/*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 = PRDESUB1.C
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS   : prde_SetUpPrinterStateData
 *               prde_InitialisePrinterStateData
 *               prde_ProcessPrinterStateData
 *               prde_GetCodePageList
 *               prde_GetIniDfltFontInfo
 *               prde_GetDriverDataDfltFontInfo
 *               prde_ProcessDefaultFont
 *               prde_GetFontInfo
 *               prde_CalcAttrCodePageFonts
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES       : Winthorn Functional Specification
 *               Device Driver Interface Specification
 *               Printer Device Driver Design
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define INCL_32                         /* Convert to C/SET2                  */
#define INCL_DOSPROCESS                 /* Convert to C/SET2                  */
#define INCL_DOSRESOURCES
#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_WINPOINTERS
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2                  */
#undef INCL_DOSRESOURCES
#undef INCL_DOSSEMAPHORES
#undef INCL_GREALL
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS
#undef INCL_SHLERRORS
#undef INCL_DOSPROCESS
#undef INCL_WINSHELLDATA
#undef INCL_WINPOINTERS

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

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

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

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

#include <prdmtypt.h>

#include <pmerr.h>

#include <prdaextf.h>
#include <prdeextf.h>
#include <prdgextf.h>
#include <prdtextf.h>
#include <prduextf.h>

extern lpPrtDataEntry       PrinterStateData;
extern lpGlobalCard         GlobalCardData;
extern lpDCTEntryType       DCT [];
extern lpDVTCPSource        DVTCodePageCaps [];
extern lplpFontCPListType   DVTFontCPList [];

extern BYTE                 UStoNLS238X [];       /*                        */
extern BYTE                 NLStoUS238X [];       /*                        */
extern BYTE                 UStoNLS239X [];       /*                        */
extern BYTE                 NLStoUS239X [];       /*                        */

extern USHORT                 DRIVER_TYPE;        /*                        */

/****************************************************************************
 *
 * FUNCTION NAME = prde_SetUpPrinterStateData
 *
 * DESCRIPTION   =
 *
 *             The printer state data records things such as what cards the
 *             printer has or what fonts have been downloaded that it's helpful
 *             to remember from one print job to the next. We may remember old
 *             values if we've got the same printer name and printer type.
 *
 *             The state data is kept as a chain of entries, one for each
 *             PrinterName that has been printed on so far in this session.
 *
 *             We look through the entries to find one for our printer, if
 *             possible; if the printer type has changed since the last job
 *             then we re-initialise.
 *
 *             Recap on what StartPtr points to: it points to the info just
 *             after all the forms in PrinterIniInfo, that is to say to
 *             SourceData, CardIndices, SlotIndices, ShipData, CardData,
 *             DownFontData, CodePageData, MetricsPath and DfltFontInfo.
 *             These are of the lengths specified in the header, except that
 *             CardIndices has length depending on NumberOwnedCards, ShipData
 *             has length depending on ShippedCardCount and SlotIndices has
 *             constant length.
 *
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 lpDMSettings      pDMSettings     Device mode settings
 *                 pDMDriverStruc    DriverData      Driver Data
 *                 PBYTE             StartPtr        Pointer to font info in
 *                                                   PrinterIniInfo.
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


ULONG prde_SetUpPrinterStateData ( lpPDBI         PDBInstance, /*            */
                                   lpDMSettings   pDMSettings, /*            */
                                   pDMDriverStruc DriverData,  /*            */
                                   PBYTE          StartPtr )   /*            */

{
#define TFUNC "SetUpPrinterData"
    /*
    **  Local variables.
    */
    BOOL                 Found;            /* Used in seaching        */
    USHORT               LogErrCode;
    lpPrtDataEntry       PrinterData;      /* PrinterStateData for    */
                                           /* current printer         */
 /*
 **            
 **  lpPrtDataEntry far * lplpPrinterData;     Used to search through.
 */
    lpPrtDataEntry     * lplpPrinterData;  /* Used to search through  */
                                           /* logical printer list    */


    /*
    **  Search through list of printers to see if this is the
    **  first time this printer has been written to.
    */
    Found = FALSE;

/*
**  for( lplpPrinterData = (lpPrtDataEntry far *)&PrinterStateData;
*/
    for( lplpPrinterData = (lpPrtDataEntry *)&PrinterStateData; /*            */
        *lplpPrinterData != FNULL;
      /*
      **  lplpPrinterData = (lpPrtDataEntry far *)
      */
         lplpPrinterData = (lpPrtDataEntry *)              /*            */
                                   &((*lplpPrinterData)->PrtNextEntry) )
    {
        TRACE4(TFUNC, "List data addr.", lplpPrinterData, 1);
        TRACE4(TFUNC, "List data", (*lplpPrinterData), 4);

        if (!prdu_strcmp( (PBYTE) PDBInstance->LPName,
                          (PBYTE) (*lplpPrinterData)->LPName ) )
        {
            Found = TRUE;
            break;
        }
    }

    if ( Found )
    {
        /*
        **  We've found an entry for the printer we want.
        */
        PrinterData = *lplpPrinterData;
    }
    else
    {
        /*
        **  Add new entry to the printer state data structure
        */
        TRACE6(TFUNC, "New printer", FNULL, 0);

        if ( prdg_AllocGlobalHeapItem( sizeof(PrtDataEntryType),
                                    /*
                                    ** (PBYTE far *)&PrinterData)
                                    */
                                       (PBYTE *)&PrinterData) /*            */
                                       != OK )
        {
            TRACE4(TFUNC, "Alloc Global Heap failed", FNULL, 0);
            TRACE4(TFUNC, "printer state", NULL, 0);
            LogErrCode = PMERR_NOT_ENOUGH_MEM;
            goto LOGERR_EXIT;
        }

        /*
        **  Make sure there's no rubbish in the new entry.
        */
        (VOID) prdu_memset ( (PBYTE) PrinterData,
                             '\0',
                             sizeof(PrtDataEntryType) );

        /*
        **  Add entry to printer state list.
        */
        *lplpPrinterData = PrinterData;

        /*
        **  Copy the device name across.
        */
        prdu_strcpy( (PBYTE)PrinterData->LPName,
                     (PBYTE)PDBInstance->LPName );
    }

    /*
    **  Hang the PrinterData off the PDB.
    */
    PDBInstance->PrinterData = PrinterData;

    if ( (!Found) ||
         (PDBInstance->PrinterType != PrinterData->PrinterType) )
    {
        /*
        **  We need to initialise the PrinterData, either because it's
        **  a new entry or because the PrinterType has changed since
        **  the previous print job on that printer.
        */
        (VOID) prde_InitialisePrinterStateData( PDBInstance,
                                                pDMSettings);
    }

    /*
    **  Process PrinterStateData.
    */
    if ( prde_ProcessPrinterStateData ( PDBInstance,
                                        pDMSettings,
                                        DriverData,
                                        StartPtr ) != OK )
    {
        goto ERR_EXIT;
    }
    /*
    **             : Set flag for initial download of download fonts and reset
    **  DOWN_FONT_RELOAD flag so that download is only done on the first
    **  print job after selecting OK in printer properties.
    */
    if (PDBInstance->PrinterData->DataChange & DOWN_FONT_RELOAD) {
        PDBInstance->PrinterData->DataChange |= INITIAL_DOWN_FONT_LOAD;
        PDBInstance->PrinterData->DataChange &= ~DOWN_FONT_RELOAD;
    }

    return OK;

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

ERR_EXIT:
    return ERROR_NEG;
}
#undef TFUNC





/****************************************************************************
 *
 * FUNCTION NAME = prde_InitialisePrinterStateData
 *
 * DESCRIPTION   = This function initialises a new block of PrinterData or
 *                 re-initialises an old block that has data for the wrong
 *                 printer type.
 *
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 lpDMSettings      pDMSettings     Device mode settings
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


ULONG prde_InitialisePrinterStateData ( lpPDBI       PDBInstance,  /*            */
                                        lpDMSettings pDMSettings ) /*            */

{
    /*
    **  Local variables.
    */
    lpPrtDataEntry       PrinterData;      /* PrinterStateData        */
    USHORT               i;                /* Loop variable           */

    /*
    **  Set local ptr to PrinterStateData.
    */
    PrinterData = PDBInstance->PrinterData;

    /*
    **  Set the FIRST_DIRECT_DC flag.  This will tell us to download a
    **  dummy code page to the Pro printers the first time we hit a
    **  Direct DC - this is done to avoid offline problems on the Pro
    **  II and Pro III.
    */
    PrinterData->DataChange |= FIRST_DIRECT_DC;

    /*
    **  PrinterData either needs initialising (if not written to
    **  before) or an overhaul (new printer type).
    */
    PrinterData->PrinterType = PDBInstance->PrinterType;

    /*
    **  Get the address of the Device Command Table for this printer.
    */
    PrinterData->lpDCT = DCT[PrinterData->PrinterType];

    /*
    **  Free memory previously allocated for the download and card
    **  font data if we are doing an overhaul.
    */
    if ( PrinterData->CardData )
    {
        (VOID) prdg_FreeGlobalHeapItem(
                (PrinterData->CardFontCount * sizeof(CardFontListType)),
                (PUSHORT*)&PrinterData->CardData );
    }

    if ( PrinterData->DownFontData )
    {
        (VOID) prdg_FreeGlobalHeapItem(
                (PrinterData->DownFontCount * sizeof(DownFontListType)),
                (PUSHORT*)&PrinterData->DownFontData );
    }

    /*
    **  Set up defaults for the card and download font data.
    */
    PrinterData->CardData      = FNULL;
    PrinterData->DownFontData  = FNULL;
    PrinterData->CardFontCount = 0;
    PrinterData->DownFontCount = 0;

    /*
    **  Ensure the code page paths are initialised to FNULL.
    */
    for ( i = 0; i < NO_OF_ADDABLE_CPS + 1; i++ )
    {
        PrinterData->CPPathList[i] = FNULL;
    }

    /*
    **  Initialise the current code page number and quality (Draft or
    **  Fastfont) and also assume downloadable code page memory is not
    **  available.
    */
    PrinterData->CPCurrent  = NO_CODE_PAGE;
    PrinterData->CPQuality  = DRAFT_CODE_PAGE;
    PrinterData->CPMemAvail = DOWN_CP_MEM_NOT_AVAIL;

    /*
    **  Set the DataChange flag so that :
    **   - the font list for cards is updated
    **   - the initial code page is downloaded
    */
    PrinterData->DataChange |= (OWNED_LIST_CHANGE | CODE_PAGE_INIT_RELOAD);

    TRACE6(TFUNC, "Printer data", PrinterData, 32);
    return OK;

}
#undef TFUNC



/****************************************************************************
 *
 * FUNCTION NAME = prde_ProcessPrinterStateData
 *
 * DESCRIPTION   = Do various jobs involving fonts that need doing now.
 *                 The DataChange flags in PrinterStateData tell us what
 *                 needs updating.
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 lpDMSettings      pDMSettings     Device mode settings
 *                 pDMDriverStruc    DriverData      Driver Data
 *                 PBYTE             StartPtr        Pointer to font info in
 *                                                   PrinterIniInfo.
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


ULONG prde_ProcessPrinterStateData ( lpPDBI         PDBInstance,/*            */
                                     lpDMSettings   pDMSettings,/*            */
                                     pDMDriverStruc DriverData, /*            */
                                     PBYTE          StartPtr )  /*            */

{
#define TFUNC "ProcessPrinterData"
    /*
    **  Local variables.
    */
    lpPrtDataEntry       PrinterData;      /* PrinterStateData for    */
                                           /* current printer         */
    lpDDTType            pDDT;             /* Pointer to DDT in PDB   */
    ULONG                i;                /* Loop variable           */
    PBYTE                pSourceData;      /* chunks in INI file      */
    PBYTE                pCardIndices;     /* entry for this printer  */
    PBYTE                pSlotIndices;     /*  ...                    */
    PBYTE                pShipData;        /*     ...                 */
    PBYTE                pCardData;        /*        ...              */
    PBYTE                pDownFontData;    /*           ...           */
    PBYTE                pCodePageData;    /*              ...        */
    PBYTE                pMetricsPath;     /*                 ...     */
    PBYTE                pDfltFontInfo;    /*                    ...  */
    lpCardFontListType   pCardList;        /*                    ..   */


    /*
    **  Set up local pointers to PrinterStateData and to DDT.
    */
    PrinterData = PDBInstance->PrinterData;
    pDDT        = &PDBInstance->DDT;

    /*
    **  Set up pointers to bits of PrinterIniInfo that we'll need.
    */
    if ( StartPtr )
    {
        pSourceData   = StartPtr;
        pCardIndices  = pSourceData   + pDMSettings->SourceDataSize;
        pSlotIndices  = pCardIndices  +
                      (pDMSettings->NumberOwnedCards * NO_INDEX_DIGITS);
        pShipData     = pSlotIndices  +
                               (MAX_NO_OF_CARD_SLOTS * NO_INDEX_DIGITS);
        pCardData     = pShipData     +
                        (pDMSettings->ShippedCardCount * sizeof(tCard));
        pDownFontData = pCardData     + pDMSettings->CardDataSize;
        pCodePageData = pDownFontData + pDMSettings->DownFontDataSize;
        pMetricsPath  = pCodePageData + pDMSettings->CodePageDataSize;
        pDfltFontInfo = pMetricsPath  + pDMSettings->MetricsPathLength;
    }
    else
    {
        /*
        **             : TRAP with no INI Data.
        **  If there was no INI information them ensure that if these
        **  flags are tested then the test fails legitimately rather
        **  than having an uninitialised pointer.
        */
        pSourceData   = NULL;
        pCardIndices  = NULL;
        pSlotIndices  = NULL;
        pShipData     = NULL;
        pCardData     = NULL;
        pDownFontData = NULL;
        pCodePageData = NULL;
        pMetricsPath  = NULL;
        pDfltFontInfo = NULL;

    }

    /*
    **  Get the default metrics path and terminate with a '\0'.  If
    **  the initial card metrics have not been unpacked then
    **  DMSettings.MetricsPathLength will be zero and the path stored
    **  will just be '\0' - this will act as a flag.
    */
    for ( i = 0; i < pDMSettings->MetricsPathLength; i++ )
        PrinterData->DfltMetricsPath[i] = *pMetricsPath++;

    PrinterData->DfltMetricsPath[i] = '\0';
    /*
    **  Now we deal with codepages. We throw away the previous list
    **  make a new list, and we load the metrics.
    */
    if ( prde_GetCodePageList ( PDBInstance,
                                pDMSettings,
                                pCodePageData ) != OK )
        goto ERR_EXIT;

    /*
    **  The Code Page List Change flag may have been set on by device
    **  modes; make sure it is turned off.  Note that this flag is
    **  ignored at enable time - the code page info is always updated.
    */
    PrinterData->DataChange &= ~CODE_PAGE_LIST_CHANGE;

    /*
    **  Adjust the Code Page Count.
    */
    PrinterData->CodePageCount += pDMSettings->NoOfAddedCPs;

    /*
    **  DIAL/NILE :           
    **  Calculate the number of attributed fonts in the code page.
    */
    pDDT->DDTAttrFontsInCP = prde_CalcAttrCodePageFonts( pDDT );

    /*
    **  Total number of code page fonts =
    **    No of Code Pages (inc 850) x
    **    No of Fonts (inc attributes) in each code page.
    */
    PDBInstance->TotalCodePageFonts = PrinterData->CodePageCount *
                                                 pDDT->DDTAttrFontsInCP;

    /*
    **  Load in the metrics for Code Page 850 if this is available.
    */
    if ( PrinterData->CodePageCount )
    {
        if ( prde_LoadCodePageMetrics(CP_850_INDEX, PDBInstance) != OK )
        {
            TRACE4(TFUNC, "Load CP mtrcs failed", FNULL, 0);
            goto ERR_EXIT;
        }
    }

    /*
    **  Deal with the default font. First get the information from the
    **  driver data if we can.
    */
    if ( prde_GetDriverDataDfltFontInfo( PDBInstance,
                                         DriverData,
                                         pDMSettings) != OK)
    {
        /*
        **  We couldn't use the driver data default font information
        **  so use the information from the ini file.
        */
        prde_GetIniDfltFontInfo ( PDBInstance,
                                  pDMSettings,
                                  pDfltFontInfo );
    }

    /*
    **  Now get the metrics for this font and save the default device
    **  font.
    */
    (VOID) prde_ProcessDefaultFont( PDBInstance );

    return (OK);

ERR_EXIT:
    return ERROR_NEG;
}
#undef TFUNC



/****************************************************************************
 *
 * FUNCTION NAME = prde_GetCodePageList
 *
 * DESCRIPTION   =
 *
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 lpDMSettings      pDMSettings     Device mode settings
 *                 PBYTE             pCodePageData   Pointer to relevant bit
 *                                                   of PrinterIniInfo
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


ULONG prde_GetCodePageList ( lpPDBI       PDBInstance,     /*            */
                             lpDMSettings pDMSettings,     /*            */
                             PBYTE        pCodePageData )  /*            */

{
#define TFUNC "GetCodePageList"

    /*
    **  Local variables.
    */
    lpPrtDataEntry       PrinterData;      /* PrinterStateData for    */
                                           /* current printer         */
    ULONG                i,j;              /* Loop variables          */
    PBYTE                pSource;          /* Working pointer         */
    PBYTE                pDest;            /* Working pointer         */
    USHORT               PathNameSize;     /* PrinterData             */
    USHORT               CodePageNo;       /* Into DVTCaps array      */
    lpDVTCPSource        CodePageCaps;     /* Code Page capabilities  */
                                           /* array for this printer  */
    USHORT               LogErrCode;

    /*
    **  Get local pointer to PrinterStateData.
    */
    PrinterData = PDBInstance->PrinterData;

    /*
    **  If the user has added code pages and then selected the not
    **  enough memory available flag the code page info is not
    **  thrown away - the code page values in DMSettings may need
    **  to be adjusted.
    **  Store the code page memory flag for use in prda_AlterCodePage.
    */
    PrinterData->CPMemAvail = pDMSettings->DownCPMemAvail;

    if ( ! (PDBInstance->DDT.DDTFontFlags & DDT_ADD_CODE_PAGE_OPTION) )
    {
        /*
        **  Printer has no code page fonts.
        */
        PrinterData->CodePageCount = 0;
        pDMSettings->NoOfAddedCPs  = 0;
        pDMSettings->InitCodePage  = NO_INDEX_SELECTED;
    }
    else
    {
        if ( (PrinterData->CPMemAvail == DOWN_CP_MEM_NOT_AVAIL ) &&
            !(PDBInstance->DDT.DDTFontFlags & DDT_DOWN_CP_MEM_SUBSET_AVAIL) )
        {
            pDMSettings->NoOfAddedCPs = 0;
            pDMSettings->InitCodePage = NO_INDEX_SELECTED;
            PrinterData->CodePageCount = 0;
        }
        else
        {
            /*
            **  If there is download area memory available then code
            **  page 850 will always be available unless it is
            **  resident.
            */
            CodePageCaps = DVTCodePageCaps[PrinterData->PrinterType];

            if ( CodePageCaps[CP_850_INDEX].CPSource == CP_RESIDENT )
                PrinterData->CodePageCount = 0;
            else
                PrinterData->CodePageCount = 1;
        }
    }

    TRACE8(TFUNC,"Code Page count", &PrinterData->CodePageCount, 1);

    /*
    **  If there is no initial code page ensure the load initial code
    **  page flag is turned off.  If there is one and the reload
    **  setting in DMSettings is to reload each job or the initial
    **  code page has changed since the last print job ensure the
    **  reload flag is on.
    */
    TRACE8( TFUNC, "CPCurrent", &(PrinterData->CPCurrent), 1 );
    TRACE8( TFUNC, "InitCodePage", &(pDMSettings->InitCodePage), 1 );

    if ( pDMSettings->InitCodePage == NO_INDEX_SELECTED )
    {
        PrinterData->DataChange &= ~CODE_PAGE_INIT_RELOAD;
    }
    else if ( ( pDMSettings->InitCPReloadType & RELOAD_EACH_JOB ) ||
                                          /* CON3203 */
              ( PrinterData->CPCurrent == NO_CODE_PAGE ) ||
              ( pDMSettings->InitCodePage != PrinterData->CPCurrent) )
    {
        PrinterData->DataChange |= CODE_PAGE_INIT_RELOAD;
    }

    TRACE8(TFUNC, "Change flag", &PrinterData->DataChange, 1);

    /*
    **  If an initial code page is to be downloaded set the variables
    **  in PrinterData correctly for this code page.  These are then
    **  picked up by the routine which does the initial downloading.
    */
    if ( PrinterData->DataChange & CODE_PAGE_INIT_RELOAD )
    {
        PrinterData->CPCurrent = pDMSettings->InitCodePage;
        PrinterData->CPQuality = DRAFT_CODE_PAGE;
    }

    /*
    **  Set up the CPJob variable which is used for a Queued Raw job
    **  (see prde_InitialiseDownFonts for comments)
    */
    if ( pDMSettings->InitCodePage != NO_INDEX_SELECTED )
    {
        PDBInstance->CPJob = pDMSettings->InitCodePage;
    }
    else
    {
        PDBInstance->CPJob = NO_CODE_PAGE;
    }

    /*
    **  Free any memory previously allocated for the pathnames.
    */
    TRACE8(TFUNC, "Free CP path mem", FNULL, 0);

    for ( i = 0; i < NO_OF_ADDABLE_CPS + 1; i++ )
    {
        if ( PrinterData->CPPathList[i] )
        {
            PathNameSize =
                      prdu_strlen( (PBYTE) PrinterData->CPPathList[i] );

            (void) prdg_FreeGlobalHeapItem( (PathNameSize + 1),
                          (PUSHORT*)&PrinterData->CPPathList[i] );

            /*
            **  Must clear the pointer - as if code pages removed
            **  there will be invalid pointers left in CPPathList,
            **  which will be 'FreeGlobal..'d next time we get here
            **  This causes the heap handling to hang.
            */
            PrinterData->CPPathList[i] = FNULL;
        }
    }

    /*
    **  Read in the new pathnames.
    */
    pSource = pCodePageData;

    TRACE8(TFUNC, "No of added CPs", &pDMSettings->NoOfAddedCPs, 1);

    for ( i = 0; i < pDMSettings->NoOfAddedCPs; i++ )
    {
        /*
        **  Read the code page index and the pathname size.
        */
        prdm_ReadWordFromText( CodePageNo,
                               NO_CODE_PAGE_DIGITS,
                               pSource );

        TRACE8(TFUNC, "CodePageNo", &CodePageNo, 1);

        prdm_ReadWordFromText( PathNameSize,
                               PATHNAME_SIZE_LENGTH,
                               pSource );

        /*
        **  Allocate memory for the pathname (including a null
        **  terminator).
        */
        if ( OK != prdg_AllocGlobalHeapItem( (PathNameSize + 1),
                                          /*
                                          **  (PBYTE far *)&pDest ) )
                                          */
                                             (PBYTE *)&pDest ) ) /*            */
        {
            TRACE8(TFUNC, "AllocGlobHeap failed",FNULL, 0);
            LogErrCode = PMERR_NOT_ENOUGH_MEM;
            goto LOGERR_EXIT;
        }

        PrinterData->CPPathList[CodePageNo - 1] = pDest;

        /*
        **  Copy the pathname across and add a terminator.
        */
        for ( j = 0; j < PathNameSize; j++ )
            *pDest++ = *pSource++;

        *pDest = '\0';

        /*
        **  Load in the metrics for this Code Page.
        */
        if ( prde_LoadCodePageMetrics( CodePageNo,
                                       PDBInstance ) != OK )
        {
            TRACE8(TFUNC, "Load CP mtrcs failed", FNULL, 0);

            /*
            **  Free memory for the path lists allocated so far.
            **  NB This is not freeing all the memory it should at
            **  this juncture.
            */
            pDest = PrinterData->CPPathList[CodePageNo - 1];
            prdg_FreeGlobalHeapItem( (PathNameSize + 1),
                                               (PUSHORT*)&pDest );
            goto ERR_EXIT;
        }
    }
    return OK;

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

ERR_EXIT:
    return ERROR_NEG;
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_GetIniDfltFontInfo
 *
 * DESCRIPTION   = This deals with the default font info from PrinterIniInfo.
 *                 Note that StartPtr points to the start of the default font
 *                 info in PrinterIniInfo.
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 lpDMSettings      pDMSettings     Device mode settings
 *                 PBYTE             StartPtr        Pointer to font info in
 *                                                   PrinterIniInfo.
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


ULONG prde_GetIniDfltFontInfo ( lpPDBI       PDBInstance,  /*            */
                                lpDMSettings pDMSettings,  /*            */
                                PBYTE        StartPtr )    /*            */

{
#define TFUNC "GetIniDfltFontInfo"
    /*
    **  Local variables.
    */
    USHORT               i;                /* Loop variable           */
    lpPrtDataEntry       PrinterData;      /* PrinterStateData        */
    lpDfltFontInfoType   pDfltFont;
    DDTType              DDT;              /*                         */

    /*
    **  Get local pointer to PrinterStateData and Default font data.
    */
    PrinterData =  PDBInstance->PrinterData;
    pDfltFont   = &PDBInstance->DfltFont;
    DDT = PDBInstance->DDT;                            /*            */

    if ( pDMSettings->DfltFontInfoSize )
    {
        prdm_ReadWordFromText( pDfltFont->Info.Type,
                               DFLTFONT_SOURCE_LEN,
                               StartPtr );

        TRACE6( TFUNC, "Dflt font source",&pDfltFont->Info.Type, 1);

#ifdef TEST_TYPE_PSD
        OutputPair("Dflt font source",
                   (ULONG)pDfltFont->Info.Type,
                   DECIMAL);
#endif
        /*
        **  Now read in the rest of the fields. Note that there is
        **  nothing else to do for FT_ENGINE case.
        */

        if ( pDfltFont->Info.Type == FT_RESIDENT ||
             pDfltFont->Info.Type == FT_CODE_PAGE )
        {
            /*
            **  This is a resident font or a font in the initial
            **  download codepage - read in the font index.
            */
            prdm_ReadWordFromText( pDfltFont->Info.Index,
                                   DFLTFONT_INDEX_LEN,
                                   StartPtr );
            /*
            **             : Add range checking on the font index.
            */
            if ( pDfltFont->Info.Index > DDT.DDTNoOfResidentFonts )
            {
               pDfltFont->Info.Index = 0;
            }


            TRACE6( TFUNC, "Dflt font index",&pDfltFont->Info.Index, 1);

#ifdef TEST_TYPE_PSD
            OutputPair("Res or CP index ",
                       (ULONG)pDfltFont->Info.Index,
                       DECIMAL);
#endif
        }

        if ( pDfltFont->Info.Type == FT_CODE_PAGE )
        {
            /*
            **  Read in the position of the codepage in the
            **  DVTCodePageList.
            */
            prdm_ReadWordFromText( pDfltFont->Info.CodePageNo,
                                   DFLTFONT_POS_IN_SRC_LEN,
                                   StartPtr );
#ifdef TEST_TYPE_PSD
            OutputPair("CP index number ",
                       (ULONG)pDfltFont->Info.CodePageNo,
                       DECIMAL);
#endif
        }

    }
    else
    {
        /*
        **            
        **  Set the default font structure to the default because
        **  is no INI file. The default is RESIDENT with index taken
        **  from DMSettings.
        */
        pDfltFont->Info.Type  = FT_RESIDENT;
        pDfltFont->Info.Index = PDBInstance->DDT.DDTDfltFontNo;
    }

#ifdef TEST_TYPE_PSD
    OutputPrompt("Return from GetIniDefaultFontInfo  ");
#endif

    return OK;
}
#undef TFUNC





/****************************************************************************
 *
 * FUNCTION NAME = prde_GetDriverDataDfltFontInfo
 *
 * DESCRIPTION   = This module try to get the default font info from the
 *                 driver data.
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *                 pDMDriverStruc    DriverData      Driver Data
 *                 lpDMSettings      pDMSettings     Printer Properties
 *                                                   Defaults
 *
 * OUTPUT        = ULONG
 *
 * RETURN-NORMAL = return OK if successful.
 *
 * RETURN-ERROR  = return ERROR if failed.
 *
 ****************************************************************************/


ULONG prde_GetDriverDataDfltFontInfo ( lpPDBI         PDBInstance, /*            */
                                       pDMDriverStruc DriverData,  /*            */
                                       lpDMSettings   pDMSettings )/*            */

{
#define TFUNC "GetDriverDataDfltFontInfo"
    /*
    **  Local variables.
    */
    USHORT               i;                /* Loop variable           */
    lpPrtDataEntry       PrinterData;      /* PrinterStateData for    */
                                           /* current printer         */
    lpDfltFontInfoType   pDfltFont;        /* Pointer to default font */
    SHORT                FontInSlot;       /* -1 :font is not in slot */
                                           /*  0 :font is in 1st slot */
                                           /*  1 :font is in 2nd slot */
    USHORT               FontIndex;
    lpCardFontListType   pCardList;
    PBYTE                pCardName;
    DDTType              DDT;                          /*            */

    /*
    **  Get local pointer to PrinterStateData and Default font data.
    */
    PrinterData =  PDBInstance->PrinterData;
    pDfltFont   = &PDBInstance->DfltFont;
    DDT = PDBInstance->DDT;                            /*            */

    /*
    **  According to the availability of the Driver Data, set up the
    **  default device font info in printer data
    */
    if ( !DriverData )
    {
        /*
        **  If the driver data is not available, return error. We will
        **  use the default font from the ini file.
        */
        return (ERROR_NEG);
    }
    else
    {
        /*
        **  If the driver data is available, set up the default font
        **  info according the type of the default font info in driver
        **  data
        */
        switch ( DriverData->Type )
        {
          case FT_ENGINE:
            /*
            **  Engine font, nothing else to do
            */
            pDfltFont->Info.Type  = FT_ENGINE;
            break;

          case FT_RESIDENT:
            /*
            **  Resident font, read in the font index.
            **
            **              : Set the default font when switching between NLS and
            **   US 23XX printers.
            */
            if (DDT.DDTFontFlags & DDT_NLS_FONTS_OPTIONAL)
            {
               if (DriverData->MachineType != 0)
               {
                  /*
                  **  If it is an 23XX printer and the machine type has changed
                  */
                  if ((pDMSettings->MachineType == US_MACHINE) &&
                      (DriverData->MachineType == NLS_MACHINE))
                  {
                     if ( ((pDMSettings->PrinterType == IBM_NILE_24) ||
                          (pDMSettings->PrinterType == IBM_TIBER_24)) )
                        pDfltFont->Info.Index = NLStoUS239X[DriverData->Index];
                     else
                        pDfltFont->Info.Index = NLStoUS238X[DriverData->Index];
                  }
                  else if ((pDMSettings->MachineType == NLS_MACHINE) &&
                           (DriverData->MachineType == US_MACHINE))
                  {
                     if ( ((pDMSettings->PrinterType == IBM_NILE_24) ||
                           (pDMSettings->PrinterType == IBM_TIBER_24)) )
                        pDfltFont->Info.Index = UStoNLS239X[DriverData->Index];
                     else
                        pDfltFont->Info.Index = UStoNLS238X[DriverData->Index];
                  }
                  else
                  {
                     /*
                     **  If the machine type has not changed
                     */
                     pDfltFont->Info.Index = DriverData->Index;
                  }
               }
               else
               {
                  /*
                  **  If there is no previous Machine Type
                  */
                  if (DriverData->Index > DDT.DDTNoOfResidentFonts)
                  {
                     pDfltFont->Info.Index = 0;
                  }
                  else
                     pDfltFont->Info.Index = DriverData->Index;
               }
            }
            else
               /*
               **  If it is not a Nile/Tiber Printer
               */
               pDfltFont->Info.Index = DriverData->Index;

            pDfltFont->Info.Type  = FT_RESIDENT;

            break;

          case FT_CODE_PAGE:
            /*
            **  Code page font,
            */
            if ( PrinterData->
                         CPPathList[DriverData->CodePageNo-1] != FNULL )
            {
                /*
                **  - if the code page is currently available, set up
                **    index and code page number
                */
                pDfltFont->Info.Type       = FT_CODE_PAGE;
                pDfltFont->Info.Index      = DriverData->Index;
                pDfltFont->Info.CodePageNo = DriverData->CodePageNo;
            }
            else
            {
                /*
                **  - if the code page is not available, reset the
                **    font to the resident font with the same index
                */
                pDfltFont->Info.Type  = FT_RESIDENT;
                pDfltFont->Info.Index = DriverData->Index;
            }
            break;

          default:
            break;
        }
    }

    return (OK);
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_ProcessDefaultFont
 *
 * DESCRIPTION   = Setup default font info and default device font info.
 *                 All fields are initialised except the code page field
 *                 which is done at EnableDC time.
 *
 * INPUT         = lpPDBI            PDBInstance     Instance Data
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


VOID prde_ProcessDefaultFont( lpPDBI PDBInstance )         /*            */
{
#define TFUNC "ProcDfltFont"
    /*
    **  Local variables.
    */
    lpPrtDataEntry       PrinterData;      /* Printer State Data     */
    lpDfltFontInfoType   DfltDeviceFont;   /* Default device font     */
    lpDfltFontInfoType   DfltFont;         /* Default font            */
    lpDDTType            pDDT;             /* Pointer to DDT in PDB   */
    lpFontInfoType       DFInfo;           /* Default font info       */
    lpFontInfoType       DDFInfo;          /* Default device font info*/
    SHORT                i;

    /*
    **  Set up pointers to variables.
    */
    PrinterData    =  PDBInstance->PrinterData;
    pDDT           = &PDBInstance->DDT;
    DfltDeviceFont = &PDBInstance->DfltDeviceFont;
    DfltFont       = &PDBInstance->DfltFont;
    DDFInfo        = &DfltDeviceFont->Info;
    DFInfo         = &DfltFont->Info;

    /*
    **  If the default font is an engine font we set up the default
    **  device font to the default default font.  The default default
    **  font index is in DDTDfltFontNo.
    */
    if (DFInfo->Type == FT_ENGINE)
    {
        /*
        **  Make the default font an engine font.
        */
        (VOID) prde_MakeDefaultFontEngine ( DfltFont );

        /*
        **  Now make the default device font the default default font
        */
        DDFInfo->Type  = FT_RESIDENT;
        DDFInfo->Index = PDBInstance->DDT.DDTDfltFontNo;
        prde_GetFontInfo( PDBInstance, DfltDeviceFont);
    }
    else
    {
        /*
        **  Default font is device so set up the default font and the
        **  default device font to the same font.  If device fonts are
        **  not available ( Printer Fonts Not Available selected or in
        **  Landscape mode), then we must set PDBInstance->FontCount
        **  to zero and set the default font to the default engine
        **  font.
        */
        prde_GetFontInfo( PDBInstance, DfltFont);

        /*
        **  Now copy the information to default device font. First the
        **  font info structure...
        */
        DDFInfo->pFont      = DFInfo->pFont;
        DDFInfo->pMultiCp   = DFInfo->pMultiCp;
        DDFInfo->Type       = DFInfo->Type;
        DDFInfo->Index      = DFInfo->Index;
        DDFInfo->Attr       = DFInfo->Attr;
        DDFInfo->CodePageNo = DFInfo->CodePageNo;

        /*
        **  Now the match number ....
        */
        DDFInfo->LCID.BaseMatchNo = DFInfo->LCID.BaseMatchNo;
        DDFInfo->LCID.EngineAttrs = DFInfo->LCID.EngineAttrs;
        DDFInfo->LCID.CPIndex     = DFInfo->LCID.CPIndex;

        /*
        **  Finally the extra fields outside of font info.
        */
        DfltDeviceFont->IndexInCard = DfltFont->IndexInCard;
        for (i = 0; i < CARD_DATA_LENGTH ; i++)
        {
            DfltDeviceFont->CardName[i] = DfltFont->CardName[i];
        }

        /*
        **  If there are no device fonts then change the default font
        **  to an engine font.
        */
        if (PDBInstance->FontCount == NO_RESIDENT_FONTS ) /* CON3203 */
        {
            /*
            **  Reset the default font to an engine font.
            */
            (VOID) prde_MakeDefaultFontEngine ( DfltFont );
        }
    }

    /*
    **             : This code moved from only being present if the
    **  default font was a device font.
    **
    **  Everything set up except the total number of fonts and a
    **  possibility that there are no device fonts.
    */
    if (PDBInstance->FontCount == NO_RESIDENT_FONTS ) /* CON3203 */
    {
        /*
        **  There are no device fonts.
        */
        PDBInstance->FontCount = 0;
    }
    else
    {
         /*
         **  Adjust FontCount to include download fonts, card fonts
         **  and code page fonts.  We only do this if device fonts are
         **  available.  If device fonts are available, FontCount
         **  already contains the number of resident fonts.
         */
         PDBInstance->FontCount +=
                (PrinterData->DownFontCount +
                 PrinterData->CardFontCount +
                 PrinterData->CodePageCount * pDDT->DDTFontsInCodePage);
    }

    return;

}
#undef TFUNC

/****************************************************************************
 *
 * FUNCTION NAME = prde_GetFontInfo
 *
 * DESCRIPTION   = Setup metrics, and match number for default font passed in.
 *
 *
 * INPUT         = lpPDBI              PDBInstance     Instance Data
 *                  lpDfltFontInfoType  DfltFontInfo   Default font to be
                                                       set up
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID prde_GetFontInfo( lpPDBI             PDBInstance,     /*            */
                       lpDfltFontInfoType DfltFontInfo )   /*            */

{
#define TFUNC "prde_GetFontInfo"

    /*
    **  Local Variables
    */
    USHORT               FontIndex;
    lpFontInfoType       FontInfo;
    lplpFontCPListType   FontCodePageList;
    lpFontCPListType     CodePageList;
    lpFontCPListType     pCodePageData;
    lpPrtDataEntry       PrinterData;
    USHORT               cpLocal;
    USHORT               CodePage;

    TRACE4(TFUNC, "GetFontInfo", FNULL, 0);

    /*
    **  Set up pointers and access the necessary data fields.
    */
    PrinterData    = PDBInstance->PrinterData;
    FontInfo       = &DfltFontInfo->Info;
    FontIndex      = FontInfo->Index;
    FontInfo->Attr = FATT_NONE;

    /*
    **  MatchNo needed for a device default font.
    */
    prdm_PutLCIDCPIndex(      FontInfo->LCID, 0xFF);
    prdm_PutLCIDEngineAttrs(  FontInfo->LCID, 0x00);
    prdm_PutLCIDFontType(     FontInfo->LCID, FontInfo->Type);
    prdm_PutLCIDFontIndex(    FontInfo->LCID, FontIndex);
    prdm_PutLCIDFontDevAttrs( FontInfo->LCID, 0x00);

    /*
    **  Set the default font info depending on the type of the
    **  default font.  Set up remaining fields (Attr and pFont) in
    **  font info.  Type and Index have been set up in prde_FillPDB
    **  (and CodePageNo if code page font).
    */
    switch ( FontInfo->Type )
    {
    case FT_RESIDENT:
        /*
        **  Resident font - metrics are in font list
        */
        FontInfo->pFont    = PDBInstance->FontList[FontIndex]->pFMFData;
        FontInfo->pMultiCp = PDBInstance->FontList[FontIndex]->pMultiCp;
        break;

    case FT_CODE_PAGE:
        /*
        **  Code page font - metrics are in font code page list.
        */
        FontCodePageList   = DVTFontCPList[PDBInstance->PrinterType];
        CodePageList       = FontCodePageList[FontIndex];
        pCodePageData      = &CodePageList[FontInfo->CodePageNo - 1];
        FontInfo->pFont    = pCodePageData->pFMFData;
        FontInfo->pMultiCp = NULL;

        /*
        **  Also put the gobal code page index into the LCID
        */
        prdm_PutLCIDGCPIndex(FontInfo->LCID, FontInfo->CodePageNo);
        break;

    }

    /*
    **  All done.
    */
    return;
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_MakeDefaultFontEngine
 *
 * DESCRIPTION   = Setup metrics, and match number for default font passed in
 *
 *
 * INPUT         = lpDfltFontInfoType  DfltFontInfo    Default font to be
 *                                                     set up
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID prde_MakeDefaultFontEngine( lpDfltFontInfoType pDfltFont ) /*            */

{
    /*
    **  Local variables.
    */
    USHORT              i;

    /*
    **  First the font info structure
    */
    pDfltFont->Info.Type       = FT_ENGINE;
    pDfltFont->Info.Index      = 0;
    pDfltFont->Info.pFont      = FNULL;
    pDfltFont->Info.pMultiCp   = FNULL;
    pDfltFont->Info.Attr       = FATT_NONE;
    pDfltFont->Info.CodePageNo = 0;

    /*
    **  Now the LCID - not significant when the default font is an
    **  engine font
    */
    LCIDTOUL(pDfltFont->Info.LCID)  = 0xFF000000;

    /*
    **  Now the final fields.
    */
    pDfltFont->IndexInCard = 0;

    for (i = 0; i < CARD_DATA_LENGTH ; i++)
    {
        pDfltFont->CardName[i] = 0;
    }

    return;
}

/****************************************************************************
 *
 * FUNCTION NAME = prde_CalcAttrCodePageFonts
 *
 * DESCRIPTION   = This module calculates the total number of attributed
 *                 fonts in a download code page.
 *
 * INPUT         = lpDDT             pDDT            Pointer to DDT
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 * NOTE: DIAL/NILE : Added function to calculate number of code page fonts
 *                                                                          
 ****************************************************************************/


USHORT prde_CalcAttrCodePageFonts( lpDDTType pDDT )
{
#define TFUNC "CalcAttrCodePageFonts"

    /*
    **  Local variables.
    */
    USHORT               i;            /* Loop variable               */
    USHORT               Count;

    /*
    **  Add up the attributes for each font in the code page.
    */
    Count = 0;
    for ( i = 0; i < pDDT->DDTFontsInCodePage; i++)
    {
       Count = Count + pDDT->DDTFontList[i]->NumAttrs;
    }

    return(Count);
}
#undef TFUNC

