/*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 = PRDESUBR
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prde_ReadIniFile
 *             prde_ExhangeDispatch
 *             prde_Termination
 *             prde_ReadHeaderData
 *             prde_GetValFromText
 *             prde_FindFormNumber
 *             prde_FindReqdTray
 *             prde_ProcessPPMTrayInfo
 *             prde_SetUpPPMFormInfo
 *             prde_StringsAreEqual
 *             prde_GetResources
 *             prde_OpenSpooler
 *             prde_OpenPort
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_GREALL
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#define INCL_SHLERRORS
#define INCL_DOSPROCESS
#define INCL_WINSHELLDATA
#define INCL_DOSMODULEMGR
#define INCL_WINPOINTERS
#define INCL_SPL
#define INCL_DOSMISC
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_SPL
#undef INCL_DOSSEMAPHORES
#undef INCL_GREALL
#undef INCL_DOSMODULEMGR
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS
#undef INCL_SHLERRORS
#undef INCL_DOSPROCESS
#undef INCL_WINSHELLDATA
#undef INCL_WINPOINTERS
#undef INCL_DOSMISC

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELSERVER
#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELSERVER
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdconse.h>
#include <prddcone.h>
#include <prdecone.h>
#include <prdmcone.h>
#include <prdpcone.h>

#define ENCON_INCL
#define MOCON_INCL
#define PRCON_INCL
#define PRDMTYPE_INCL
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef ENCON_INCL
#undef MOCON_INCL
#undef PRCON_INCL
#undef PRDMTYPE_INCL

#include <prdeextf.h>
#include <prdgextf.h>
#include <prdyextf.h>
#include <prduextf.h>
#include <prdmextf.h>

extern DeviceSemTable       lpDevSemTable;
extern DeviceSemTableEntry  DevSemQueuedDCTable;

/* extern USHORT               PMVersion; CON3201 - No longer needed */

extern char                 szIBMQSTD[];
extern char                 szIBMQESC[];
extern char                 szIBMQRAW[];

extern char                 szBoldString[];
extern char                 szDWideString[];
extern char                 szDHighString[];
extern char                 szQualityString1[];
extern char                 szQualityString2[];
extern char                 szQualityString3[];
extern char                 szQualityString2a[];

extern HMODULE              prdd_ModHandle;
extern PCHAR                DriverNameString;
extern USHORT               DRIVER_TYPE;

/**********************************************************************/
/* Set up access to external semaphores.                              */
/**********************************************************************/
/*
extern FSRSEM               RAMSemaphoreTable[];              CON3201 */
extern HMTX                 MutexSemTable[];               /* CON3201 */



/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_ReadIniFile                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PFNL       PRDAddress;            Address of function to replace */
/*                                     entry with                     */
/*   ULONG      EngineFunctionNumber;  Function number to be replaced */
/*   ULONG far *DispatchTable;         Pointer to dispatch table      */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function reads an entry in the os2.ini file and returns     */
/*   a pointer to a buffer containing the data. If the pointer is     */
/*   NULL no entry was found; if it is -1 an error occurred.          */
/*   The calling function is responsible for freeing memory           */
/*   allocated for the data, if the function succeeds                 */
/*                                                                    */
/**********************************************************************/
#if 0
PBYTE pascal far prde_ReadIniFile( DriverName,
                                   Key )

PSZ      DriverName;
PSZ      Key;
#endif

PBYTE prde_ReadIniFile( PSZ DriverName,                    /* CON3201 */
                        PSZ Key )                          /* CON3201 */

{
#define TFUNC "prde_ReadIniFle"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    USHORT   Result;
    PBYTE    Buffer;
 /* USHORT   Size; */
    ULONG    Size;                                         /* CON3201 */
    PFN       pPrfQueryProfSz;
    PFN       pPrfQueryProfData;
    HMODULE   ModuleHandle;
    USHORT    DosResult;
    BOOL      ModuleOK;

    TRACE4(TFUNC, "Key", Key, 3);

    /* CON3201 : don't need the following logic                      */
#if 0
    ModuleOK = DosLoadModule( FNULL, 0, "PMSHAPI", &ModuleHandle);
    TRACE4(TFUNC, "Prf LoadMod Res", &ModuleOK, 1);

 /* if ( prdu_strcmp( (void far *)Key,           */
 /*              (void far *)"PM_SPOOLER_DD" ) ) */
    if ( prdu_strcmp( (void *)Key,                         /* CON3201 */
                 (void *)"PM_SPOOLER_DD" ) )               /* CON3201 */
    {
        /* Key is not PM_SPOOLER_DD: use OS2.INI                      */
        if ( WinQueryProfileSize(hab, Key, DriverName, &Size) )
        {
            LOGERR( TFUNC, "inv device name",
                    FNULL, 0, PMERR_INV_DEVICE_NAME );
            return((PBYTE)ERROR_NEG);
        }
    }
    else
    {
        if ( ModuleOK == DOS_OK )
        {
            /**********************************************************/
            /* Now try and get the address of Prf..                   */
            /**********************************************************/
            DosResult = DosGetProcAddr( ModuleHandle,
                                        "PRFQUERYPROFILESIZE",
                                        &pPrfQueryProfSz);
            TRACE4(TFUNC, "DosGetProcAddr Res", &DosResult, 1);
            if (DosResult == DOS_OK)
            {
                /******************************************************/
                /* 1.2: Can now make the call                         */
                /******************************************************/
                if ( !pPrfQueryProfSz( HINI_SYSTEMPROFILE,
                                       Key,
                                       DriverName,
                                       (PULONG)&Size) )
#endif
                if ( !PrfQueryProfileSize( HINI_SYSTEMPROFILE, /*CON3201*/
                                           Key,                /*CON3201*/
                                           DriverName,         /*CON3201*/
                                           &Size) )            /*CON3201*/
                 {
                     LOGERR(TFUNC,"inv device name",
                            FNULL,0,PMERR_INV_DEVICE_NAME);
                     return((PBYTE)ERROR_NEG);
                 }
    /* CON3201 : don't need the following logic                      */
#if 0
            }
            else
            {
                if ( WinQueryProfileSize(hab, Key, DriverName, &Size) )
                {
                    LOGERR( TFUNC, "inv device name",
                          FNULL, 0, PMERR_INV_DEVICE_NAME );
                    return((PBYTE)ERROR_NEG);
                }
            }
        }
        else
        {
            DosBeep(470,70);
        }
    }
#endif

 /* TRACE4(TFUNC, "Ini size", &Size, 1); */
    TRACE4(TFUNC, "Ini size", (PUSHORT)&Size, 1);          /* CON3201 */

    if (Size)
    {
        /**************************************************************/
        /* There is an entry for this driver in the OS2.INI file -    */
        /* allocate a segment for data from OS2.INI file.             */
        /* Allow to put version number there if it is not already     */
        /* there. We need this for prdm_Dialog routine. PD00143       */
        /**************************************************************/
     /* if ( (Result = SSALLOCSEG (Size + 4, &SELECTOROF(Buffer), 0)) */
        if ( (Result = SafeSSALLOCMEM (&Buffer, (Size + 4), 0)) /* CON3201 */
                                                             != DOS_OK )
        {
         /* LOGDOSERR(TFUNC, "SSALLOCSEG Fail", &Result, 1, Result); */
            LOGDOSERR(TFUNC, "SSALLOCMEM Fail", &Result, 1, Result);/*CON3201*/
            return((PBYTE)ERROR_NEG);
        }

     /* OFFSETOF(Buffer) = 0;                                 CON3201 */

        /**************************************************************/
        /* Read the OS2.INI data into the buffer.                     */
        /**************************************************************/

     /* CON3201 : don't need the following logic                      */
#if 0
     /* if ( prdu_strcmp( (void far *)Key,           */
     /*              (void far *)"PM_SPOOLER_DD" ) ) */
        if ( prdu_strcmp( (void *)Key,                     /* CON3201 */
                     (void *)"PM_SPOOLER_DD" ) )           /* CON3201 */
        {
            /* Key is not PM_SPOOLER_DD: use OS2.INI                  */
            if ( WinQueryProfileData( hab,
                                      Key,
                                      DriverName,
                                      (PVOID)Buffer,
                                      (PUSHORT)&Size) != OK )
            {
                TRACE4(TFUNC, "Error reading file", FNULL, 0);
             /* SSFREESEG(SELECTOROF(Buffer)); */
                SSFREEMEM(Buffer);                         /* CON3201 */
                return((PBYTE)ERROR_NEG);
            }
        }
        else
        {
            if ( ModuleOK == DOS_OK )
            {
                /******************************************************/
                /* Now try and get the address of Prf..               */
                /******************************************************/
                DosResult = DosGetProcAddr( ModuleHandle,
                                            "PRFQUERYPROFILEDATA",
                                            &pPrfQueryProfData);
                TRACE4(TFUNC, "DosGetProcAddr Res", &DosResult, 1);
                if (DosResult == DOS_OK)
                {
                    /**************************************************/
                    /* Can now make the call                          */
                    /**************************************************/
                    if ( pPrfQueryProfData( HINI_SYSTEMPROFILE,
                                          Key,
                                          DriverName,
                                          (PVOID)Buffer,
                                          (PULONG)&Size) != OK )
#endif
                    if ( !PrfQueryProfileData( HINI_SYSTEMPROFILE,/*CON3201*/
                                          Key,                    /*CON3201*/
                                          DriverName,             /*CON3201*/
                                          (PVOID)Buffer,          /*CON3201*/
                                          &Size) )                /*CON3201*/
                    {
                        TRACE4(TFUNC, "Error reading file", FNULL, 0);
                     /* SSFREESEG(SELECTOROF(Buffer)); */
                        SSFREEMEM(Buffer);                 /* CON3201 */
                        return((PBYTE)ERROR_NEG);
                    }
     /* CON3201 : don't need the following logic                      */
#if 0
                }
                else
                {
                    if ( WinQueryProfileData( hab,
                                              Key,
                                              DriverName,
                                              (PVOID)Buffer,
                                              (PUSHORT)&Size) != OK )
                    {
                        TRACE4(TFUNC, "Error reading file", FNULL, 0);
                     /* SSFREESEG(SELECTOROF(Buffer)); */
                        SSFREEMEM(Buffer);                 /* CON3201 */
                        return((PBYTE)ERROR_NEG);
                    }
                }
            }
            else
            {
                DosBeep(470,70);
            }
        }
#endif
        return(Buffer);
    }

    if ( !DriverName )
        TRACE4(TFUNC, "Buffer", Buffer, (Size+3)/4);

    return(FNULL);

}

#undef TFUNC




/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_ExchangeDispatch                                  */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PFNL       PRDAddress;            Address of function to replace */
/*                                     entry with                     */
/*   ULONG      EngineFunctionNumber;  Function number to be replaced */
/*   ULONG far *DispatchTable;         Pointer to dispatch table      */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function substitutes the supplied function address in the   */
/*   dispatch table and returns the original contents of the entry in */
/*   the dispatch table for the function specified by                 */
/*   EngineFunctionNumber.                                            */
/*                                                                    */
/**********************************************************************/
#if 0
PFNL pascal far prde_ExchangeDispatch( PRDAddress,
                                       EngineFunctionNumber,
                                       DispatchTable )

PFNL       PRDAddress;
ULONG      EngineFunctionNumber;
ULONG far *DispatchTable;
#endif

PFNL prde_ExchangeDispatch( PFNL   PRDAddress,             /* CON3201 */
                            ULONG  EngineFunctionNumber,   /* CON3201 */
                            ULONG *DispatchTable )         /* CON3201 */

{
#define TFUNC "prde_ExDispatch"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    ULONG         EngineAddress; /* Original contents of the dispatch */
                                 /* table for this entry              */
 /* ULONG far    *p_Disp_Entry;     Pointer to entry in the dispatch  */
                                                           /* CON3201 */
    ULONG        *p_Disp_Entry;  /* Pointer to entry in the dispatch  */
                                 /* table                             */


    /******************************************************************/
    /* Set up p_Disp_Entry by using EngineFunctionNumber as an offset */
    /* to DispatchTable.                                              */
    /******************************************************************/
    p_Disp_Entry = ((DispatchTable) +
                    (EngineFunctionNumber & 0xFFL));

    /******************************************************************/
    /* Fetch the address of the engine function.                      */
    /******************************************************************/
    EngineAddress = *p_Disp_Entry;

    /******************************************************************/
    /* Substitute our address and return the engine address.          */
    /******************************************************************/
 /* (PFNL)*p_Disp_Entry = PRDAddress; */
    *p_Disp_Entry = (ULONG)PRDAddress;                     /* CON3201 */
    return((PFNL)EngineAddress);

}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_Termination                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   USHORT  Reason;   Reason for termination                         */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function is called by the DOS when a process is terminated. */
/*   It allows the printer driver to free any semaphores owned by     */
/*   that process.                                                    */
/*                                                                    */
/**********************************************************************/
#if 0
void pascal far prde_Termination ( Reason )

USHORT  Reason;
#endif

void prde_Termination ( USHORT Reason )                    /* CON3201 */

{
#define TFUNC "prde_Termination"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
 /* PFSRSEM              lpRAMSemaphoreTable;     Pointer to our      */
                                               /* semaphore table     */
    PHMTX                lpMutexSemTable;                  /* CON3201 */

    /******************************************************************/
    /* Search the RAM Semaphore table for any semaphores owned by     */
    /* the terminating process. If any exist then clear them down     */
    /* as many times as necessary                                     */
    /******************************************************************/
#if 0
    for ( lpRAMSemaphoreTable = RAMSemaphoreTable;
          lpRAMSemaphoreTable < (PFSRSEM)(RAMSemaphoreTable +
                                          RAM_SEMAPHORE_TABLE_SIZE);
          lpRAMSemaphoreTable++ )
    {
           FSRSemExit(lpRAMSemaphoreTable);
    }
#endif
    for ( lpMutexSemTable = MutexSemTable;                 /* CON3201 */
          lpMutexSemTable < (PHMTX)(MutexSemTable +        /* CON3201 */
                             MUTEX_SEMAPHORE_TABLE_SIZE);  /* CON3201 */
          lpMutexSemTable++ )                              /* CON3201 */
    {
           DosCloseMutexSem(*lpMutexSemTable);             /* CON3201 */
    }

    /******************************************************************/
    /* Close the Trace File.                                          */
    /******************************************************************/
    CloseTraceFile;

    /******************************************************************/
    /* Signal DosExit termination function complete to DOS            */
    /******************************************************************/
    (void)DosExitList(EXLST_EXIT, FNULL);

}
#undef TFUNC



/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_ReadHeaderData                                    */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDMSettings  pDMSettings   Address settings are read into       */
/*   PBYTE         pSource       Address of INI buffer                */
/*   USHORT        IniVersionType     says whether version is         */
/*                                    current or previous type        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function reads the fixed length header data from            */
/*   the INI entry for the given printer to DMSettings.               */
/*                                                                    */
/*   It can cope with reading old-type Pro and Q ini entries. Old     */
/*   type 4019 entries shouldn't get to here.                         */
/**********************************************************************/
#if 0
void pascal far prde_ReadHeaderData( pDMSettings,
                                     pSource,
                                     IniVersionType )

lpDMSettings    pDMSettings;
PBYTE           pSource;
USHORT          IniVersionType;
#endif

void prde_ReadHeaderData( lpDMSettings pDMSettings,        /* CON3201 */
                          PBYTE        pSource,            /* CON3201 */
                          USHORT       IniVersionType )    /* CON3201 */

{
#define TFUNC "prde_ReadHeaderData"

    /******************************************************************/
    /* Read the printer type code.                                    */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->PrinterType,
                           PRINTER_TYPE_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the total size of the entry for this printer.             */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->INIEntrySize,
                           NO_DATA_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the orientation.                                          */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->Orientation,
                           ORIENTATION_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the resolution.                                           */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->Resolution,
                           RESOLUTION_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the form feed state.                                      */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->FFSet,
                           FORM_FEED_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the default spool file type.                              */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->DefaultSpoolIndex,
                           SPOOL_INDEX_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the Pel Addressable font type.                            */
    /******************************************************************/
    pDMSettings->PelAddrFontType = *pSource++ - '0';

    TRACE6(TFUNC, "PelAddrFontType", &pDMSettings->PelAddrFontType, 1);

    /******************************************************************/
    /* Read the index of the current Source configuration.            */
    /* This is an index into the DVTSourceList in the printer's DDT.  */
    /* See comment in prde_WriteHeaderData for further details.       */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->SourceIndex,
                           NO_INFO_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the Envelope Feed type.                                   */
    /******************************************************************/
    pDMSettings->AddedFeed = *pSource++ - '0';

    /******************************************************************/
    /* Read the current form number.                                  */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->SelectedForm,
                           NO_FORM_CNT_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the number of forms.                                      */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->NumberOfForms,
                           NO_FORM_CNT_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the number of avaiable cards.                             */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->NumberAvailCards,
                           NO_FONT_CNT_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the number of owned cards.                                */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->NumberOwnedCards,
                           NO_FONT_CNT_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the number of shipped cards.                              */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->ShippedCardCount,
                           NO_INFO_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the number of download fonts.                             */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->NumberOfDownFonts,
                           NO_FONT_CNT_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the flag indicating download code page memory available.  */
    /******************************************************************/
    pDMSettings->DownCPMemAvail = *pSource++ - '0';

    /******************************************************************/
    /* Read the number of added code pages.                           */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->NoOfAddedCPs,
                           NO_CODE_PAGE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the index of the initial code page.                       */
    /*   -1 : no code page is selected as initial                     */
    /*   >0 : InitCodePage is as index into the DVTCodePageCaps array.*/
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->InitCodePage,
                           NO_CODE_PAGE_DIGITS,
                           pSource );

    pDMSettings->InitCodePage--;

    /******************************************************************/
    /* Write the reload type for the initial code page.               */
    /******************************************************************/
    pDMSettings->InitCPReloadType = *pSource++ - '0';

    /**************************************************************/
    /* New .ini fields are present. Read them.                    */
    /**************************************************************/
    /**************************************************************/
    /* Memory option for the 4019 family                          */
    /**************************************************************/
    prdm_ReadWordFromText( pDMSettings->MemoryOption,
                           NO_MEM_OPT_DIGITS,
                           pSource );

    /**************************************************************/
    /* Resident font set: entry level or full set (might be needed*/
    /* on Heritage E).                                            */
    /**************************************************************/
    pDMSettings->ResFontSet = *pSource++ - '0';

    /**************************************************************/
    /* Simplex or duplex on those printers that support this      */
    /* option.                                                    */
    /* 4019Heritage has the enabled option too.                   */
    /**************************************************************/
    pDMSettings->SimDup = *pSource++ - '0';
    pDMSettings->DuplexEnabled =
                 (pDMSettings->SimDup & DUPLEX_FLAG) ? TRUE : FALSE;
    pDMSettings->SimDup &= ~DUPLEX_FLAG;

    /**************************************************************/
    /* Default source.                                            */
    /**************************************************************/
    prdm_ReadWordFromText( pDMSettings->DefaultSource,
                           NO_DEF_SOURCE_DIGITS,
                           pSource );

    /**************************************************************/
    /* Band compression.                                          */
    /**************************************************************/
    pDMSettings->BandCompression = *pSource++ - '0';

    /**************************************************************/
    /* Down load system fonts.                                    */
    /**************************************************************/
    pDMSettings->DownSysFonts = *pSource++ - '0';

    /**************************************************************/
    /* PD00136 : Disable Outline Fonts                            */
    /**************************************************************/
    pDMSettings->DisableOutlineFonts = *pSource++ - '0';

    /******************************************************************/
    /* DIAL/NILE : Get the machine type.                              */
    /******************************************************************/
    pDMSettings->MachineType = *pSource++ - '0';

    /******************************************************************/
    /* Read the default outline font point size     PD00137           */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->DfltFontPointSz,
                           NO_POINTSIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Get the default Printer Patterns for 4019   PD00769           */
    /******************************************************************/
    pDMSettings->PrinterPatterns = *pSource++ - '0';

    /**************************************************************/
    /* There are some unused bytes reserved for future expansion. */
    /**************************************************************/
    pSource += PADDING_LENGTH;
    pDMSettings->NotUsed = 0;


    /******************************************************************/
    /* Read the size of the source form data.                         */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->SourceDataSize,
                           NO_DATA_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the length of the default metrics path.                   */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->MetricsPathLength,
                           PATHNAME_SIZE_LENGTH,
                           pSource );

    /******************************************************************/
    /* Read the size of the card data.                                */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->CardDataSize,
                           NO_DATA_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the size of the download font data.                       */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->DownFontDataSize,
                           NO_DATA_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the size of the code page data.                           */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->CodePageDataSize,
                           NO_DATA_SIZE_DIGITS,
                           pSource );

    /******************************************************************/
    /* Read the size of the default font info.                        */
    /******************************************************************/
    prdm_ReadWordFromText( pDMSettings->DfltFontInfoSize,
                           NO_INFO_SIZE_DIGITS,
                           pSource );

}
#undef TFUNC



/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_GetValFromText                                    */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PBYTE far *Data;  Points to the start of the text string to be   */
/*                   + converted to a value.  Returns updated to      */
/*                     position after number.                         */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   Converts a number in text in the OS2.INI entry (ie '125') into   */
/*   a value.                                                         */
/*                                                                    */
/**********************************************************************/
#if 0
USHORT pascal prde_GetValFromText( Data )

PBYTE far *Data;
#endif

USHORT prde_GetValFromText( PBYTE *Data )                  /* CON3201 */

{
#define TFUNC "prde_GetValFromText"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    PBYTE  dp = *Data;    /* Pointer for stepping through string      */
    USHORT Val;           /* Variable to build up the value in        */

    int  DecPlaces;       /* This is -1 if we haven't found a decimal */
                          /* place, 0 if we have, and > 0 for a count */
                          /* of the decimal places read               */

    DecPlaces = -1;

    /******************************************************************/
    /* The number is terminated by a space.                           */
    /******************************************************************/
    for ( Val = 0; *dp != ' '; dp++ )
    {
        /**************************************************************/
        /* ALT_POINT represents a '.' but we construct the value      */
        /* as a whole number so just skip it.                         */
        /**************************************************************/
        if ( *dp != ALT_POINT )
        {
           /***********************************************************/
           /* Only do next statement if DecPlaces                     */
           /* less than maximum number of decimal places allowed      */
           /***********************************************************/
            if (DecPlaces < 2 )
            {
              /********************************************************/
              /* Incorporate the next digit.                          */
              /********************************************************/
              Val = Val * 10 + *dp - '0';
            }

           /***********************************************************/
           /* ++DecPlaces if necessary                                */
           /***********************************************************/
           if ( DecPlaces >=0 )
               DecPlaces++;
        }

       /***************************************************************/
       /* Check for finding dec pt.                                   */
       /***************************************************************/
       if( *dp == ALT_POINT )
         DecPlaces = 0;
    }

    /******************************************************************/
    /* Return Data pointing to the terminating space and return the   */
    /* Val.                                                           */
    /******************************************************************/
    *Data = dp;

    return Val;
}
#undef TFUNC





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_FindFormNumber                                    */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PBYTE            pWork           Ptr to the form name we're      */
/*                                    trying to match                 */
/*   PBYTE            pFormData       Start of form data chunk in     */
/*                                    in INI file                     */
/*   USHORT           NumberOfForms   Number of forms listed in       */
/*                                    PrinterIniInfo or in DDT        */
/*   lpDDTType        pDDT            ptr to DDT in PDB               */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/* This function is given a form name (that was read from             */
/* SpoolerParams) and tries to match it in the list of forms in       */
/* PrinterIniInfo (if found) or the default list in the DDT (if not). */
/* It returns the number of the form matched +1 if it found a match   */
/* and 0 if it didn't.                                                */
/**********************************************************************/
#if 0
USHORT pascal prde_FindFormNumber( pWork,
                                   pFormData,
                                   NumberOfForms,
                                   pDDT )

PBYTE      pWork;
PBYTE      pFormData;
USHORT     NumberOfForms;
lpDDTType  pDDT;
#endif

USHORT prde_FindFormNumber( PBYTE     pWork,               /* CON3201 */
                            PBYTE     pFormData,           /* CON3201 */
                            USHORT    NumberOfForms,       /* CON3201 */
                            lpDDTType pDDT )               /* CON3201 */

{
#define TFUNC "prde_FindFormNumber"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    PBYTE  NameStart;          /* Start of form name                  */
    USHORT NumberBytes;        /* Count of bytes to be compared       */
    USHORT i;                  /* Loop variable                       */
    BYTE   FormNameBuffer[33]; /* Buffer used to get form name from   */
                               /* resources                           */

    /******************************************************************/
    /* pWork points to the form name terminated either by a space or  */
    /* a null. Terminate it with a 1 so it has the same terminator as */
    /* the INI information.                                           */
    /******************************************************************/
    TRACE4(TFUNC, "Entry", NULL,0);

    NumberBytes = 0;
    NameStart = pWork;

    /******************************************************************/
    /* Form names can contain spaces. Look for null terminator, comma */
    /* or next key name. If find keyname then go back to previous     */
    /* space which must be a delimitor, then go back to start of      */
    /* the spaces (in case there's more than 1).                      */
    /******************************************************************/
    while (*pWork != '\0' && *pWork != '=' && *pWork != ',')
    {
        pWork++;
        NumberBytes++;
    }

    if (*pWork == '=')
    {
        while (*pWork != ' ')
        {
            pWork--;
            NumberBytes--;
        }
        while (*pWork == ' ')
        {
            pWork--;
            NumberBytes--;
        }
        NumberBytes++;
    }

    /******************************************************************/
    /* Now loop through the defined forms and check for a match       */
    /******************************************************************/
    if (pFormData)
    {
        /**************************************************************/
        /* Form data is from PrinterIniInfo.                          */
        /**************************************************************/
        pFormData += 2;

        for ( i = 0; i < NumberOfForms; i++ )
        {
            if ( !(prdu_memcmp( NameStart,
                           pFormData + i * (FORM_DATA_LENGTH + 2),
                           NumberBytes )) )
            {
                /******************************************************/
                /* Found match. Return form no. + 1.                  */
                /******************************************************/
                return( i + 1);
            }
        }

        /**************************************************************/
        /* No match found. Return.                                    */
        /**************************************************************/
        return( 0);
    }

    else      /*   PrinterIniInfo not found    */
    {
        /**************************************************************/
        /* Look through the default list of form names.               */
        /**************************************************************/
        for ( i = 0; i < NumberOfForms; i++ )
        {
            /**********************************************************/
            /* Get FormName no. i from resources.                     */
            /**********************************************************/
            (void)WinLoadString(
                           hab,
                           prdd_ModHandle,
                           pDDT->DDTDefinedForms[i].FormNameId,
                           33,
                           FormNameBuffer );

            if ( !(prdu_memcmp( NameStart,
                           FormNameBuffer,
                           NumberBytes ) ) )
            {
                /******************************************************/
                /* Found match. Return form no. + 1.                  */
                /******************************************************/
                return( i + 1);
            }
        }
        /**************************************************************/
        /* No match. Return 0.                                        */
        /**************************************************************/
        return (0);
    }
}
#undef TFUNC




/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_FindReqdTray                                      */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI           PDBInstance     PDBInstance pointer             */
/*   USHORT           PageNo          Index into PPM structure        */
/*   lpDMSettings     pDMSettings     DMSettings pointer              */
/*   PBYTE            pFormData       Start of form data chunk in     */
/*                                    in INI file                     */
/*   lpDVTSourceList  pSourceInfo     Info for current source config. */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function looks through the trays for the current source     */
/*   configuration to find the required form.                         */
/*                                                                    */
/* We look for the form using the following list of priorities:       */
/*  1. any automatic trays  (priority within these is implied         */
/*       by the order they appear in the tray list)                   */
/*  2. if not found in auto tray use manual feed if it exists         */
/*  3. if not found above use whatever is in the default tray         */
/*       (since by this stage we know there are no manual trays       */
/*        this must be an automatic tray - it will be tray # 0)       */
/**********************************************************************/
#if 0
void pascal prde_FindReqdTray( PDBInstance,
                               PageNo,
                               pDMSettings,
                               pFormData,
                               pSourceInfo )

lpPDBI           PDBInstance;
USHORT           PageNo;
lpDMSettings     pDMSettings;
PBYTE            pFormData;
lpDVTSourceList  pSourceInfo;
#endif

void prde_FindReqdTray( lpPDBI          PDBInstance,       /* CON3201 */
                        USHORT          PageNo,            /* CON3201 */
                        lpDMSettings    pDMSettings,       /* CON3201 */
                        PBYTE           pFormData,         /* CON3201 */
                        lpDVTSourceList pSourceInfo )      /* CON3201 */

{
#define TFUNC "prde_FndReqdTray"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    lpPPMInfoType    pPPMInfo;        /* Ptr to reqd PPM structure    */
    USHORT           ReqdFormNo;      /* Form we're looking for       */
    PBYTE            pSourceData;     /* Pointer for accessing        */
                                      /* source data in the INI entry */
    BYTE             SourceType;      /* Paper or envelope            */
    SHORT            ReqdTrayNo;      /* Tray associated with reqd.   */
                                      /* form                         */
    PBYTE            pWork;           /* Working pointer              */
    lpDVTSourceTray  pTrayInfo;       /* Tray list for the current    */
                                      /* source configuration         */
    USHORT           TrayNo;          /* Loop variable                */
    USHORT           AutoTrayForm;    /* Form associated with an      */
                                      /* automatic tray               */
    BOOL             ManualTrayFound; /* Flag to determine if a manual*/
                                      /* tray was found for the paper */
                                      /* type.                        */

    /******************************************************************/
    /* Pick up the PPMInfo for the correct page.                      */
    /******************************************************************/
    pPPMInfo = &PDBInstance->PPMInfo[PageNo];

    /******************************************************************/
    /* Pick up the form number we will look for and then set up a     */
    /* pointer to SourceData in PrinterIniInfo.                       */
    /******************************************************************/
    ReqdFormNo = pPPMInfo->FormNumber;

    pSourceData = pFormData +
                 (pDMSettings->NumberOfForms * (FORM_DATA_LENGTH + 2) );

    /******************************************************************/
    /* Pick the source type (paper or envelope) from the INI file     */
    /* entry - it's the first character in the string for ReqdFormNo. */
    /******************************************************************/
    SourceType = *(pFormData + (ReqdFormNo * (FORM_DATA_LENGTH + 2)));


    /******************************************************************/
    /* Set up a pointer to the tray list for the current source       */
    /* configuration.                                                 */
    /******************************************************************/
    pTrayInfo = pSourceInfo->SourceTrayList;

    /******************************************************************/
    /* First set ReqdTrayNo; if it is not reset then this will mean   */
    /* we should use the first automatic tray as per 3. above.        */
    /******************************************************************/
    ReqdTrayNo = VALUE_NOT_SET;
    ManualTrayFound = FALSE;
    /******************************************************************/
    /* Now loop through all the trays for this source configuration   */
    /* and check if the form type is correct.  If it is then remember */
    /* the number of any manual tray and look for an automatic        */
    /* tray with the correct form.                                    */
    /******************************************************************/
    for ( TrayNo = 0;
          TrayNo < pSourceInfo->NoOfLogicalTrays;
          TrayNo++, pTrayInfo++ )
    {
        /*********************************************************************/
        /*  If the source types match or this is a Envelope+ tray and        */
        /*  the form is an envelope, then look for the form.                 */
        /*  INKJET: Available forms list has both envelope and paper forms.  */
        /*  We therefore have to check for a source type of paper or envelope */
        /*  also.                                                             */
        /*********************************************************************/

        if ( (pTrayInfo->SourceType == SourceType) ||
            ( (pTrayInfo->SourceType == DDT_DEFAULT_OR_ENV_FORM) &&
              (SourceType == DDT_ENVELOPE_FORM) ) ||
            ( pTrayInfo->SourceType == (DDT_PAPER_FORM | DDT_ENVELOPE_FORM ) ) )
        {
            if ( pTrayInfo->FeedType == DDT_MANUAL_FEED )
            {
                /******************************************************/
                /* Remember the number of a manual tray - this will   */
                /* be overwritten if an automatic tray with the       */
                /* correct form is found.                             */
                /******************************************************/
                ManualTrayFound = TRUE;
                ReqdTrayNo = TrayNo;
            }
            else
            {
                pWork = pSourceData +
                         (NO_FORM_CNT_DIGITS * pTrayInfo->DMTrayUsage);

                prdm_ReadWordFromText( AutoTrayForm,
                                       NO_FORM_CNT_DIGITS,
                                       pWork );

                if ( AutoTrayForm == ReqdFormNo )
                {
                    /**************************************************/
                    /* Break out if found - this ensures automatic    */
                    /* trays take priority over manual trays.         */
                    /**************************************************/
                    ReqdTrayNo = TrayNo;
                    break;
                }
            }
        }
        /* .... if ( pTrayInfo->SourceType == SourceType ) .......... */
    }
    /* .... for ( .. TrayNo < pSourceInfo->NoOfLogicalTrays; .. ) ... */

    /******************************************************************/
    /*  Since there is no manual tray for this type like paper and    */
    /*  envelopes, must set the ReqdTrayNo to something or the form   */
    /*  is changed to letter.  Therefore, print manager will not hold */
    /*  the job and we will send it as tray 1, paper size 1.  Manual  */
    /*  envelopes was chosen since all forms in the Envelope+ tray    */
    /*  can exist in the manual envelope tray.                        */
    /******************************************************************/

    if ( ( SourceType == DDT_DEFAULT_OR_ENV_FORM ) &&
         ( ReqdTrayNo == VALUE_NOT_SET ) )    /* CON3203 */
    {
       ReqdTrayNo = TrayNo - 1;
    }

    /******************************************************************/
    /* PD00415 : Set the required tray if there are no manual trays of*/
    /* this type.  This allows print manager to give us a form        */
    /* mismatch if the default tray contains the default form and     */
    /* another form is selected in job properties.                    */
    /******************************************************************/
                                                 /* CON3203 */
    if ( ( !ManualTrayFound ) && ( ReqdTrayNo == VALUE_NOT_SET ) )
    {
       ReqdTrayNo = 0;
    }

    /******************************************************************/
    /* If we have not found a tray with the required form then        */
    /* use the form in the default tray.                              */
    /******************************************************************/
    if ( ReqdTrayNo == VALUE_NOT_SET ) /* CON3203 */
    {
        pWork = pSourceData + (NO_FORM_CNT_DIGITS *
                              pSourceInfo->SourceTrayList->DMTrayUsage);

        prdm_ReadWordFromText( ReqdFormNo,
                               NO_FORM_CNT_DIGITS,
                               pWork );

        ReqdTrayNo = 0;
        PDBInstance->PPMInfo[PageNo].FormNumber = ReqdFormNo;
    }

    /******************************************************************/
    /* Reset the tray info pointer for the selected tray and then     */
    /* set up the tray info in the PPM structure.                     */
    /******************************************************************/
    pTrayInfo  = pSourceInfo->SourceTrayList;
    pTrayInfo += ReqdTrayNo;

    /******************************************************************/
    /* Note change for Heritage: pass in the source type (paper or    */
    /* envelope) so that PPM can be set up for multi-media tray.      */
    /******************************************************************/
    prde_ProcessPPMTrayInfo( PDBInstance,
                             PageNo,
                             SourceType,
                             pTrayInfo );
    return;
}
#undef TFUNC






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_ProcessPPMTrayInfo                                */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI           PDBInstance     PDBInstance pointer             */
/*   USHORT           PageNo          Index into PPM structure        */
/*   lpDVTSourceTray  pTrayInfo       Info for reqd source tray       */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function sets up the part of PPMInfo to do with the tray -  */
/*   the fields FeedTechnique, FormControl and SourceDrawer.          */
/**********************************************************************/
#if 0
void pascal prde_ProcessPPMTrayInfo( PDBInstance,
                                     PageNo,
                                     SourceType,
                                     pTrayInfo )

lpPDBI           PDBInstance;
USHORT           PageNo;
BYTE             SourceType;
lpDVTSourceTray  pTrayInfo;
#endif

void prde_ProcessPPMTrayInfo( lpPDBI          PDBInstance, /* CON3201 */
                              USHORT          PageNo,      /* CON3201 */
                              BYTE            SourceType,  /* CON3201 */
                              lpDVTSourceTray pTrayInfo )  /* CON3201 */

{
#define TFUNC "prde_ProcessPPMTrayInfo"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    lpPPMInfoType    pPPMInfo;        /* Ptr to reqd PPM structure    */

    /******************************************************************/
    /* Set up a pointer to the PPM structure we need to complete.     */
    /******************************************************************/
    pPPMInfo = &PDBInstance->PPMInfo[PageNo];

    /******************************************************************/
    /* Now set up the PPM structure according to the tray info.       */
    /******************************************************************/
    if ( pTrayInfo->FeedType == DDT_MANUAL_FEED )
    {
        pPPMInfo->FeedTechnique = PFT_MANUAL;
    }
    else if ( pTrayInfo->JoinType == DDT_TRACTOR_FEED )
    {
        pPPMInfo->FeedTechnique = PFT_TRACTOR;
    }
    else
    {
        pPPMInfo->FeedTechnique = PFT_AUTOMATIC;
    }

    if (( pTrayInfo->SourceType == DDT_DEFAULT_OR_ENV_FORM ) ||
        ( pTrayInfo->SourceType == (DDT_PAPER_FORM | DDT_ENVELOPE_FORM) ) )
    {
        /**************************************************************/
        /* 4019 Heritage                                              */
        /* If paper form is required, then use FC_SHEET with tray     */
        /* number (SD) = 3.                                           */
        /* If envelope is required, use FC_ENVELOPE as for 4019 Laser.*/
        /**************************************************************/
        if (SourceType == DDT_PAPER_FORM)
        {
            pPPMInfo->FormControl = FC_SHEET;
        }
        else /* envelope */
        {
            pPPMInfo->FormControl = FC_ENVELOPE;
        }

    }
    else if ( pTrayInfo->SourceType == DDT_PAPER_FORM )
    {
        pPPMInfo->FormControl = FC_SHEET;
    }
    else
    {
        pPPMInfo->FormControl = FC_ENVELOPE;
    }

    /******************************************************************/
    /* The method below works since the automatic sheet feed paper    */
    /* are listed first (indexed from 0).                             */
    /******************************************************************/
    if ( (pPPMInfo->FeedTechnique == PFT_AUTOMATIC) &&
         (pPPMInfo->FormControl == FC_SHEET) )
    {
        /**************************************************************/
        /* Note for multi-media with paper form then use SD = 3.      */
        /* The CS_MULTIMEDIA==CS_PAPER_TRAY_3 assures this.           */
        /**************************************************************/
        pPPMInfo->SourceDrawer = (BYTE)SD_TRAY_1 +
                                              pTrayInfo->DMTrayUsage;

        /**************************************************************/
        /* The 100 sheet feed is defined as tray 4, must subtract 1   */
        /* get the right value for presentation media.                */
        /**************************************************************/

        if (pPPMInfo->SourceDrawer == 4)
        {
           pPPMInfo->SourceDrawer -= 1;
        }
    }
    else
    {
       /**************************************************************/
       /*  If it is an envelope for the envelope+ feed then the      */
       /*  SourceDrawer must be 3.                                   */
       /**************************************************************/
       /**************************************************************/
       /*  PD00243 - Make sure that the tray is envelope+ before     */
       /*            setting the value to three, since now manual    */
       /*            envelope accepts all envelope forms.            */
       /**************************************************************/

       if ( ( pTrayInfo->SourceType == DDT_DEFAULT_OR_ENV_FORM ) &&
            ( pPPMInfo->FeedTechnique == PFT_AUTOMATIC ))
          pPPMInfo->SourceDrawer = (BYTE)SD_TRAY_3;
       else
          pPPMInfo->SourceDrawer = SD_ACTIVE_VALUE;
    }
}
#undef TFUNC






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_SetUpPPMFormInfo                                  */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI           PDBInstance     PDBInstance pointer             */
/*   PBYTE            pFormData       ptr into PrinterIniInfo         */
/*   USHORT           NumberOfForms   no. listed in PrinterIniInfo    */
/*                                    or in DDT                       */
/*   USHORT           PageNo          Index into PPM structure        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function sets up the FormName and FormInfoPtr fields in     */
/* PPMInfo, if the FormNumber field is filled.                        */
/**********************************************************************/
#if 0
USHORT PASCAL prde_SetUpPPMFormInfo( PDBInstance,
                                     pFormData,
                                     NumberOfForms,
                                     PageNo )

lpPDBI           PDBInstance;
PBYTE            pFormData;
USHORT           NumberOfForms;
USHORT           PageNo;
#endif

SHORT prde_SetUpPPMFormInfo( lpPDBI PDBInstance,           /* CON3201 */
                             PBYTE  pFormData,             /* CON3201 */
                             USHORT NumberOfForms,         /* CON3201 */
                             USHORT PageNo )               /* CON3201 */

{
#define TFUNC "prde_SetUpPPMFormInfo"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    lpDDTType      pDDT;              /* ptr to DDT in the PDB        */
    lpPPMInfoType  pPPMInfo;          /* Ptr to reqd PPM structure    */
    USHORT         FormNumber;        /* Form number                  */
    PBYTE          FormPtr;           /* Ptr to form dimensions       */
    PBYTE          pDest;             /* Working pointer              */
    BYTE           FormNameBuffer[33];/* Buffer used to get form name */
                                      /* from resources               */
    USHORT         LogErrCode;

    /******************************************************************/
    /* Get pointer to DDT in the PDB.                                 */
    /******************************************************************/
    pDDT = &PDBInstance->DDT;

    /******************************************************************/
    /* Set up a pointer to the PPM structure we need to complete.     */
    /******************************************************************/
    pPPMInfo = &PDBInstance->PPMInfo[PageNo];

    FormNumber = pPPMInfo->FormNumber;

    /******************************************************************/
    /* Validate the FormNumber.                                       */
    /******************************************************************/
    if ( FormNumber >= NumberOfForms )
    {
        /**************************************************************/
        /* FormNumber is invalid. Exit with an error.                 */
        /**************************************************************/
        LogErrCode = PMERR_INV_FORMS_CODE;
        goto LOGERR_EXIT;
    }

    /******************************************************************/
    /* First set up the FormName and FormId fields.                   */
    /******************************************************************/
    if ( pFormData )
    {
        /**************************************************************/
        /* If we have some PrinterIniInfo, pick up the FormId and     */
        /* get a pointer to the FormName.                             */
        /**************************************************************/
        FormPtr = pFormData + (FormNumber * (FORM_DATA_LENGTH + 2));

        FormPtr++;
        pPPMInfo->FormId = *FormPtr++;

        /**************************************************************/
        /* Put the FormName into PPMInfo - note that we change the    */
        /* decimal point character to what the spooler will expect.   */
        /**************************************************************/
        pDest = pPPMInfo->FormName;

        while ( *FormPtr != '\1' )
        {
            *pDest++ = (*FormPtr == ALT_POINT) ? (BYTE)'.' : *FormPtr;
            FormPtr++;
        }

        *pDest = '\0';

        /**************************************************************/
        /* Set FormPtr to point just after the \1 character, i.e. to  */
        /* the beginning of form dimensions.                          */
        /**************************************************************/
        FormPtr++;
    }

    else
    {
        /**************************************************************/
        /* No PrinterIniInfo - pick up the FormId from data tables    */
        /* and get the FormName resource.                             */
        /**************************************************************/
        pPPMInfo->FormId = pDDT->DDTDefinedForms[FormNumber].FormId;

        (void) WinLoadString(
                   hab,
                   prdd_ModHandle,
                   pDDT->DDTDefinedForms[FormNumber].FormNameId,
                   33,
                   FormNameBuffer );

        /**************************************************************/
        /* Store the FormName in PPMInfo.                             */
        /**************************************************************/
        FormPtr = FormNameBuffer;
        pDest = pPPMInfo->FormName;

        while ( *FormPtr )
        {
            *pDest++ = (*FormPtr == ALT_POINT) ? (BYTE)'.' : *FormPtr;
            FormPtr++;
        }

        *pDest = '\0';

        /**************************************************************/
        /* Set up pointer to form dimensions, which are in the DDT.   */
        /**************************************************************/
        FormPtr = pDDT->DDTDefinedForms[FormNumber].FormData;
    }

    /******************************************************************/
    /* Now put FormInfoPtr info PPMInfo.                              */
    /******************************************************************/
    if ( !PageNo )
    {
        /**************************************************************/
        /* First form.                                                */
        /**************************************************************/
        pPPMInfo->FormInfoPtr = FormPtr;
    }
    else
    {
        /**************************************************************/
        /* Second form.                                               */
        /* PD00064 : allocate FORM_DIMS_LENGTH plus one, as strcpyN   */
        /* adds a terminating null.                                   */
        /**************************************************************/
        if ( prdg_AllocGlobalHeapItem(
                   (USHORT)FORM_DIMS_LENGTH + 1,
                /* (PBYTE far *)&(pPPMInfo->FormInfoPtr) ) != OK ) */
                   (PBYTE *)&(pPPMInfo->FormInfoPtr) ) != OK ) /*CON3201*/
        {
            /**********************************************************/
            /* Error - set pointer to NULL.                           */
            /**********************************************************/
            pPPMInfo->FormInfoPtr = FNULL;
        }
        else
        {
            prdu_strcpyN( pPPMInfo->FormInfoPtr,
                          FormPtr,
                          FORM_DIMS_LENGTH );
        }
    }

    return OK;

LOGERR_EXIT:
    TRACE6(TFUNC, "LogErr_Exit", &LogErrCode, 1);
    LOGERR(TFUNC, "Invalid device", FNULL, 0, LogErrCode);

ERR_EXIT:
    TRACE6(TFUNC, "Err_Exit", FNULL, 0);
    return ERROR_NEG;

}
#undef TFUNC









/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_StringsAreEqual                                   */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PSZ        pszSource;                                            */
/*   PSZ        pszTarget;                                            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function compares two strings ignoring the case of the      */
/*   characters 'a' - 'z'.  It returns TRUE if the strings are the    */
/*   same; FALSE if not.                                              */
/*                                                                    */
/**********************************************************************/
#if 0
BOOL pascal far prde_StringsAreEqual( pszSource,
                                      pszTarget )

PSZ      pszSource;
PSZ      pszTarget;
#endif

BOOL prde_StringsAreEqual( PSZ pszSource,                  /* CON3201 */
                           PSZ pszTarget )                 /* CON3201 */

{
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    BYTE     Source;
    BYTE     Target;

    if ( prdu_strlen(pszSource) != prdu_strlen(pszTarget) )
        return(FALSE);

    for ( ; *pszSource; pszSource++, pszTarget++ )
    {
        Source = (BYTE)*pszSource;
        Target = (BYTE)*pszTarget;

        /**************************************************************/
        /* Force upper case letters before doing the compare.         */
        /**************************************************************/
        if ( Source >= (BYTE)'a' && Source <= (BYTE)'z' )
            Source -= (BYTE)('a' - 'A');

        if ( Target >= (BYTE)'a' && Target <= (BYTE)'z' )
            Target -= (BYTE)('a' - 'A');

        if ( Source != Target )
            return(FALSE);
    }

    return(TRUE);
}





/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_GetResources                                      */
/*                                                                    */
/*   PARAMETERS:  none                                                */
/*                                                                    */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/* This function is called from FillPDB. It gets some resources that  */
/* will be used in prdaquery. It's quicker to load them here.         */
/**********************************************************************/
#if 0
void pascal prde_GetResources()
#endif

void prde_GetResources()                                   /* CON3201 */

{
    /******************************************************************/
    /* Get the qualtiy/attributes for facenames. These are accessed   */
    /* in prdaqery (AddAttributeToFace, AddQualityToFace). Reading    */
    /* them in here provides a large performance improvement.         */
    /******************************************************************/

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_FATT_DOUBLE_WIDE,
                      30,
                      szDWideString );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_FATT_DOUBLE_HIGH,
                      30,
                      szDHighString );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_FATT_BOLD,
                      30,
                      szBoldString );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_DRAFT_PRINT,
                      30,
                      szQualityString1 );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_QUALITY_PRINT,
                      30,
                      szQualityString2 );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_ENHANCED_PRINT,
                      30,
                      szQualityString3 );

    (void) WinLoadString( hab,
                      prdd_ModHandle,
                      IDS_QUALITY_PRINT_ALT,
                      30,
                      szQualityString2a );
}



/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_SetupSplData                  PD00227             */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI             PDBInstance;                                  */
/*   FPParamsLst far   *param1;                                       */
/*                                                                    */
/*   DESCRIPTION: This function sets up the parameters and makes      */
/* the SplQmOpen call. The SpoolerParams are as passed in in param1   */
/* except that any form names included are removed and are replaced   */
/* (if FormSpecifiedOnOpen is true) by the actual form names used.    */
/**********************************************************************/
#if 0
ULONG pascal prde_SetupSplData( PDBInstance, param1 )

lpPDBI             PDBInstance;
FPParamsLst far *  param1;
#endif

ULONG prde_SetupSplData( lpPDBI       PDBInstance,         /* CON3201 */
                         FPParamsLst *param1 )             /* CON3201 */

{
#define TFUNC "prde_SetupSplData"
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    USHORT               Result;        /* Result of functions        */
                                        /* calls                      */
    USHORT               LogErrCode;    /* Error code to be logged    */
    PBYTE                BufferPtr;     /* to store new SpoolerParams */
    PBYTE                OldBufferPtr;  /* to store old SpoolerParams */
    USHORT               BufferSize;    /* size of Buffer             */
    PDEVOPENSTRUC        pSplData;      /* Data structure passed      */
                                        /* when opening the spooler   */
    BYTE                 pszWord[100];  /* Word buffer                */
    CHAR                 Terminator;    /* parameter for subfunction  */
    USHORT               ParamsLength;
    PBYTE                ColorParams;
    PBYTE                pSource;
    BOOL                 Found = FALSE;


    /******************************************************************/
    /* Get memory for the SpoolerData      .                          */
    /******************************************************************/
    if ( prdg_AllocGlobalHeapItem( sizeof(DEVOPENSTRUC),
                                /* (PBYTE far *)&pSplData) != OK ) */
                                   (PBYTE *)&pSplData) != OK ) /*CON3201*/
    {
        TRACE6(TFUNC, "Alloc Glob Heap for Spldata failed", FNULL, 0);
        LogErrCode = PMERR_NOT_ENOUGH_MEM;
        goto LOGERR_EXIT;
    }


    /******************************************************************/
    /* Set up fields in SplData from the PDB data.                    */
    /******************************************************************/
    pSplData->pszLogAddress = PDBInstance->PDBLogAddress;
    pSplData->pszDriverName = PDBInstance->PDBDriverName;

    if ( PDBInstance->PDBOutputType == IBMQRAW )
        pSplData->pszDataType = szIBMQRAW;
    else
        pSplData->pszDataType = szIBMQSTD;

    /******************************************************************/
    /* See if we got form information from DriverData. If so we       */
    /* must set the FORM= field in the SpoolerParams to the           */
    /* corresponding form name.                                       */
    /* The PM 1.1 spooler has a     which prevents jobs from          */
    /* being released if we specify a FORM= statement in              */
    /* the SpoolerParms. Therefore only execute the following         */
    /* code if the PM version is not 1.1.  The spooler regards        */
    /* a space in the form name as a delimeter so Letter (8.5...)     */
    /* is displayed in the Job details and thought of by the          */
    /* spooler as just Letter.  Putting quotes (") around the         */
    /* form name doesnt help any.                                     */
    /*                                                                */
    /* CON3201 - Since we are not supplying a PMVersion number anymore*/
    /*           Checking the PMVersion will not be done              */
    /******************************************************************/
    pSplData->pszSpoolerParams = FNULL;
/*  if ( (PDBInstance->FormSpecifiedOnOpen) && (PMVersion > 1) )     CON3201 */
    if ( PDBInstance->FormSpecifiedOnOpen )
    {
        TRACE4(TFUNC, "Add FORM= field", FNULL, 0);

        /**************************************************************/
        /* Get the size of buffer to hold new spooler params.         */
        /**************************************************************/
        OldBufferPtr = param1->DO.pszSpoolerParams;
        TRACE4(TFUNC, "SplParm Addr", &OldBufferPtr, 1);

        if ( OldBufferPtr )
            BufferSize = prdu_strlen(OldBufferPtr) + 72;
        else
            BufferSize = 72;

        TRACE4(TFUNC, "Alloc SplParms", &Work, 1);

        /**************************************************************/
        /* Allocate memory for the Spooler Parameters                 */
        /**************************************************************/
     /* Result =  SSALLOCSEG ( BufferSize,             */
     /*                        &SELECTOROF(BufferPtr), */
     /*                        0 );                    */
        Result =  SafeSSALLOCMEM ( &BufferPtr,            /* CON3201 */
                                    BufferSize,           /* CON3201 */
                                    0 );                  /* CON3201 */
        if (Result != DOS_OK)
        {
            LogErrCode = PMERR_NOT_ENOUGH_MEM;
            goto LOGERR_EXIT;
        }

/*      OFFSETOF(BufferPtr) = 0;                               CON3201 */
        pSplData->pszSpoolerParams = BufferPtr;

        if ( OldBufferPtr )
        {
            /**********************************************************/
            /* Copy existing spooler params into the buffer. Skip     */
            /* the FORM= bit if it's there.                           */
            /**********************************************************/
            do
            {
                /******************************************************/
                /* If we've an 'F', check  the word starting there.   */
                /******************************************************/
                if (*OldBufferPtr == 'F')
                {
                    (void)prde_ReadTerminatedWordFromText(
                                                        (PBYTE)pszWord,
                                                        &Terminator,
                                                        "=",
                                                        &OldBufferPtr );

                    if (prde_StringsAreEqual ( "FORM", pszWord ))
                    {
                        /**********************************************/
                        /* Go on to the start of the next keyword, or */
                        /* to '\0' if there isn't one.                */
                        /**********************************************/
                        while (*OldBufferPtr && (*OldBufferPtr != '=') )
                            OldBufferPtr++;

                        if (*OldBufferPtr)
                        {
                            while ( *(--OldBufferPtr) != ' ');
                            OldBufferPtr++;
                        }
                    }
                }
            } while (*BufferPtr++ = *OldBufferPtr++);
            /**********************************************************/
            /* Now *BufferPtr points to one char after a null.        */
            /* Replace the null with a space.                         */
            /**********************************************************/
            *(BufferPtr - 1) = ' ';
        }

        /**************************************************************/
        /* Append the form key name to the string                     */
        /**************************************************************/
        OldBufferPtr = "FORM=";
        prdu_memcpy ( (PBYTE)BufferPtr,
                      (PBYTE)OldBufferPtr,
                      prdu_strlen(OldBufferPtr) );

        BufferPtr += prdu_strlen(OldBufferPtr);

        /**************************************************************/
        /* Now append the form name.                                  */
        /**************************************************************/
        OldBufferPtr = PDBInstance->PPMInfo[0].FormName;
        prdu_memcpy ( BufferPtr,
                      (PBYTE)OldBufferPtr,
                      prdu_strlen(OldBufferPtr) );
        BufferPtr += prdu_strlen(OldBufferPtr);

        /**************************************************************/
        /* If necessary add the second form name with a comma         */
        /* between.                                                   */
        /**************************************************************/
        if (PDBInstance->NumberOfForms == 2)
        {
            *BufferPtr++ = ',';

            OldBufferPtr = PDBInstance->PPMInfo[1].FormName;
            TRACE4(TFUNC, "Add form name", OldBufferPtr, 8);

            prdu_memcpy ( BufferPtr,
                          (PBYTE)OldBufferPtr,
                          prdu_strlen(OldBufferPtr));
            BufferPtr += prdu_strlen(OldBufferPtr);

        }
        /**************************************************************/
        /* Finish with a null.                                        */
        /**************************************************************/
        *BufferPtr++ = '\0';
    }
    else
    {
        pSource = (PBYTE)param1->DO.pszSpoolerParams;
        if (pSource)
        {
        /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pszSpoolerParams, */
                                                                   /* CON3201 */
           if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pszSpoolerParams,
                                (prdu_strlen(pSource) + 1) ) != OK)
              goto LOGERR_EXIT;
        }
    }

#ifdef TEST_TYPE_INIT
#if (TEST_TYPE_INIT == 2)
    OutputString("Spooler params: ");
    OutputString(SplData.pszSpoolerParams);
#endif
#endif
    /******************************************************************/
    /* Set up fields in SplData from the data supplied to this        */
    /* function in param1.                                            */
    /******************************************************************/
    pSplData->pdriv = FNULL;
    pSource = (PBYTE)param1->DO.pdriv;
    if (pSource)
    {
   /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pdriv, */
      if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pdriv, /*CON3201*/
                            (USHORT)param1->DO.pdriv->cb) != OK)
            goto LOGERR_EXIT;
    }

    pSplData->pszComment = FNULL;
    pSource = (PBYTE)param1->DO.pszComment;
    if (pSource)
    {
    /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pszComment, */
       if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pszComment, /*CON3201*/
                             (prdu_strlen(pSource) + 1) ) != OK)
           goto LOGERR_EXIT;
    }

    pSplData->pszQueueProcName = FNULL;
    pSource = (PBYTE)param1->DO.pszQueueProcName;
    if (pSource)
    {
    /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pszQueueProcName,*/
                                                                   /* CON3201 */
       if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pszQueueProcName,
                             (prdu_strlen(pSource) + 1) ) != OK)
           goto LOGERR_EXIT;
    }

    pSplData->pszNetworkParams = FNULL;
    pSource = (PBYTE)param1->DO.pszNetworkParams;
    if (pSource)
    {
    /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pszNetworkParams,*/
                                                                   /* CON3201 */
       if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pszNetworkParams,
                             (prdu_strlen(pSource) + 1) ) != OK)
           goto LOGERR_EXIT;
    }

    pSplData->pszQueueProcParams = FNULL;

#ifdef OMIT_FOR_WORK_AROUND
    pSource = (PBYTE)param1->DO.pszQueueProcParams;
    if (pSource)
    {
    /* if (prde_CopySplData( pSource, (PBYTE far *)&pSplData->pszQueueProcParams,*/
                                                                   /* CON3201 */
       if (prde_CopySplData( pSource, (PBYTE *)&pSplData->pszQueueProcParams,
                             (prdu_strlen(pSource) + 1) ) != OK)
           goto LOGERR_EXIT;
    }
#endif

    /******************************************************************/
    /* Temporary Usage : OK special coming up ( SMP 8/5/90 )          */
    /* PMPRINT adds in an extra CreateLogColorTable call using        */
    /* LCOL_CONSECRGB and a weird colour table when a Queued Std      */
    /* job comes off the queue thereby messing up the apps colour     */
    /* handling.  We can get round this by adding a COL=C to the      */
    /* QueueProcParms - its tough on the user if he wanted COL=M      */
    /* but, hey, sic biscuitus disintegrat.                           */
    /******************************************************************/
    /******************************************************************/
    /* PD00531:  The above comment NOT TRUE anymore                   */
    /*           If app sets COL then use whatever it sets it to      */
    /*           (C or M). Else use COL=C                             */
    /******************************************************************/
    ColorParams = "COL=C";
    pSource = param1->DO.pszQueueProcParams;
    if (pSource)
    {
        while ( (!Found) && (*pSource != '\0') )
        {
           if (*pSource == 'C')
           {
             if ( !prdu_strcmpN(pSource, ColorParams, 4) )
             {
                Found = TRUE;
             }
           }
           pSource++;
        }

        if (Found)
        {
          ParamsLength = prdu_strlen(param1->DO.pszQueueProcParams) + 1;
        }
        else
        {
          ParamsLength = prdu_strlen(param1->DO.pszQueueProcParams) +
                                   1 + prdu_strlen(ColorParams) + 1;
        }
    }
    else
        ParamsLength = 0 + prdu_strlen(ColorParams) + 1;


 /* Result = SSALLOCSEG ( ParamsLength ,                             */
 /*                       &SELECTOROF(pSplData->pszQueueProcParams), */
 /*                       0 );                                       */
    Result = SafeSSALLOCMEM ( &pSplData->pszQueueProcParams,    /* CON3201 */
                              ParamsLength,                     /* CON3201 */
                             0 );                               /* CON3201 */

    if ( Result != DOS_OK )
    {
        LogErrCode = PMERR_NOT_ENOUGH_MEM;
        goto LOGERR_EXIT;
    }

/*  OFFSETOF(pSplData->pszQueueProcParams) = 0;                      CON3201 */

    BufferPtr = pSplData->pszQueueProcParams;

    pSource = param1->DO.pszQueueProcParams;
    if ( pSource )
    {
        for ( ;
              *pSource;
              *BufferPtr++ = *pSource++ );

         if ( !Found )
            *BufferPtr++ = ' ';
    }

    if ( !Found )
    {
       for ( pSource = ColorParams;
             *pSource;
             *BufferPtr++ = *pSource++ );
    }

    *BufferPtr++ = '\0';

    PDBInstance->lpSplData = pSplData;

    return OK;

LOGERR_EXIT:
    TRACE6(TFUNC, "LogErr_Exit", &LogErrCode, 1);
    LOGERR(TFUNC, "Invalid device", FNULL, 0, LogErrCode);

ERR_EXIT:
    TRACE6(TFUNC, "Err_Exit", FNULL, 0);
    return ERROR_NEG;

}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_CopySplData                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PBYTE              PSource;                                      */
/*   PBYTE              PDest;                                        */
/*                                                                    */
/*   DESCRIPTION: This function copies the SpoolerData passed in      */
/*                param1 of FILLPDB call into a local copy in         */
/*                PDBInstance.                                        */
/**********************************************************************/
#if 0
ULONG pascal prde_CopySplData( pSource, ppTarget,BufferSize)

PBYTE        pSource;
PBYTE far *  ppTarget;
USHORT       BufferSize;
#endif

ULONG prde_CopySplData( PBYTE   pSource,                   /* CON3201 */
                        PBYTE  *ppTarget,                  /* CON3201 */
                        USHORT  BufferSize )               /* CON3201 */

{
#define TFUNC "prde_CopySplData"
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    USHORT               LogErrCode;    /* Error code to be logged    */
    PBYTE                pDest;


    if ( prdg_AllocGlobalHeapItem( BufferSize,
                                /* (PBYTE far *)&pDest) != OK ) */
                                   (PBYTE *)&pDest) != OK )  /*CON3201*/
    {
        TRACE6(TFUNC, "Alloc Glob Heap for Spldata failed", FNULL, 0);
        LogErrCode = PMERR_NOT_ENOUGH_MEM;
        goto LOGERR_EXIT;
    }
    prdu_memcpy( (PBYTE)pDest, (PBYTE)pSource, BufferSize);
    *ppTarget = pDest;
    return OK;

LOGERR_EXIT:
    TRACE6(TFUNC, "LogErr_Exit", &LogErrCode, 1);
    LOGERR(TFUNC, "Invalid device", FNULL, 0, LogErrCode);

ERR_EXIT:
    TRACE6(TFUNC, "Err_Exit", FNULL, 0);
    return ERROR_NEG;

}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_OpenSpooler                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI             PDBInstance;                                  */
/*                                                                    */
/*   DESCRIPTION: This function sets up the parameters and makes      */
/* the SplQmOpen call. The SpoolerParams are as passed in in          */
/* PDBInstance.                                                       */
/**********************************************************************/
#if 0
ULONG pascal prde_OpenSpooler( PDBInstance)

lpPDBI             PDBInstance;
#endif

ULONG prde_OpenSpooler( lpPDBI PDBInstance)                /* CON3201 */

{
#define TFUNC "prde_OpenSpooler"

    if ( !(PDBInstance->PDBSplHandle =
                  (ULONG)SplQmOpen("*",
                                   NO_OF_PARMS_SPLDATA,
                                    (PQMOPENDATA)PDBInstance->lpSplData)) )
    {
        return ERROR_NEG;
    }

#ifdef PORT_SEMAPHORE
    /******************************************************************/
    /* Set up the pointer to the device info                          */
    /******************************************************************/
    PDBInstance->PDBDevice = &DevSemQueuedDCTable;
#endif /* PORT_SEMAPHORE */

    return OK;
}
#undef TFUNC




/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prde_OpenPort                                          */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpPDBI             PDBInstance;                                  */
/*                                                                    */
/*   DESCRIPTION: This function doesn't really open anything; but     */
/* it does get the semaphore for the port we're writing to. We        */
/* serialise access to the ports in an attempt to stop two jobs       */
/* messing each other up (although if one of the jobs comes from      */
/* somewhere other than our driver, there's nothing we can do).       */
/* PD00636                                                            */
/**********************************************************************/
#if 0
ULONG pascal prde_OpenPort( PDBInstance )

lpPDBI             PDBInstance;
#endif

ULONG prde_OpenPort( lpPDBI PDBInstance )                  /* CON3201 */

{
#define TFUNC "prde_OpenPort"
    /******************************************************************/
    /* Local variables.                                               */
    /******************************************************************/
    ULONG                i;                /* Loop counter.           */
    DeviceSemTable       SemTable;         /* Used to loop through    */
                                           /* Device Semaphore Table  */

    /******************************************************************/
    /* Look through first NO_OF_PRINTER_DEVICES - 1 entries in the    */
    /* Semaphore Table for a match with PDBLogAddress. If no match is */
    /* found (with LPT1-9, COM1-9) then assume                        */
    /* PDBLogAddress is a file name and use the last entry in the     */
    /* Semaphore Table.                                               */
    /******************************************************************/
    TRACE4(TFUNC, "PDBLogAddress", PDBInstance->PDBLogAddress, 1);

    /**************************************************************************/
    /* PD00682 : Added if stmt to only get semaphore when PDBLogAddress is    */
    /* not NULL to prevent trap in prdu_strcmp when no port selected.         */
    /**************************************************************************/
    if ( PDBInstance->PDBLogAddress )
    {
        for ( i = 0, SemTable = lpDevSemTable;
              i < NO_OF_PRINTER_DEVICES;
              i++, SemTable++ )
        {
            if ( prdu_strcmp( SemTable->DeviceName,
                         PDBInstance->PDBLogAddress ) == 0 )
            {
                /**********************************************************/
                /* Found the right semaphore.                             */
                /**********************************************************/
                TRACE4(TFUNC, "Output to ..", SemTable->DeviceName, 1);

                PDBInstance->PDBDevice = SemTable;

                (VOID) prdg_RequestSemaphore(SemTable->ControlSemaphore, 0);

                PDBInstance->PDBPrtOpen = TRUE;

                return OK;
            }
        }
    }
    return OK;
}
#undef TFUNC
