/*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 = PRDQHCC
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdq_QueryHardcopyCaps
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define INCL_32                        /* CON3201 */
#define INCL_DOSPROCESS                /* CON3201 */
#define INCL_DOSSEMAPHORES
#define INCL_GREALL
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_SPL
#define INCL_WINSHELLDATA
#define INCL_GPIERRORS
#define INCL_DEV
#define INCL_WINPOINTERS
#define INCL_DOSPROCESS                 /* CON3201 */
#include <os2.h>
#undef INCL_DOSSEMAPHORES
#undef INCL_GREALL
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_SPL
#undef INCL_WINSHELLDATA
#undef INCL_GPIERRORS
#undef INCL_DEV
#undef INCL_WINPOINTERS

#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                         /* CON3201 */

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

#define NO_SYS
#define INCL_HELP
#define ENCON_INCL
#define MOCON_INCL
#define QUCON_INCL
#define PRDMTYPE_INCL
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef PRDMTYPE_INCL
#undef NO_SYS
#undef INCL_HELP
#undef ENCON_INCL
#undef MOCON_INCL
#undef QUCON_INCL


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

USHORT  prdz_EnterDriver(lpDCI);

extern HMODULE  prdd_ModHandle;

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdq_QueryHardcopyCaps                                 */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   See "OS/2 Technical Reference: I/O Subsytems and Device Drivers" */
/*                                                                    */
/*   hanDC           DcH;                                             */
/*   ULONG           Start;                                           */
/*   ULONG           Count;                                           */
/*   lpFormInfo      PtrFormInfo;                                     */
/*   lpDCI           DCIData;                                         */
/*   ULONG           FunN;                                            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function returns information about the hardcopy             */
/*   capabilities of the printer.  It can return two types of         */
/*   information:  if Count = 0 then it returns the number of         */
/*   currently defined forms for the printer; Otherwise, it returns   */
/*   information about the forms specified by Start and Count.  The   */
/*   function checks the PDBInstance->pStartPtr for information about */
/*   the current printer and returns an err if it cannot find an entry*/
/*   for the current printer.  Otherwise, it obtains the information  */
/*   about the forms specified by Start and Count and converts this   */
/*   data to the format (ie lengths in millimetres and pels) it is    */
/*   required to return them in.                                      */
/*                                                                    */
/**********************************************************************/
/* CON3201
ULONG _loadds prdq_QueryHardcopyCaps ( DcH,
                                                  Start,
                                                  Count,
                                                  PtrFormInfo,
                                                  DCIData,
                                                  FunN )

hanDC           DcH;
LONG            Start;
LONG            Count;
PHCINFO         PtrFormInfo;
lpDCI           DCIData;
ULONG           FunN;
                      */

ULONG  prdq_QueryHardcopyCaps (hanDC           DcH,
                               LONG            Start,
                               LONG            Count,
                               PHCINFO         PtrFormInfo,
                               lpDCI           DCIData,
                               ULONG           FunN)

{
#define TFUNC "prdq_QryHardCps"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    lpPDBI       PDBInstance;      /* Pointer to PDB data             */
    USHORT       NoOfFormsReturned;/* The number of forms to be       */
                                   /* returned                        */
    USHORT       NumberOfForms;    /* The number of forms held in     */
                                   /* OS2.INI for this printer        */
    USHORT       FormNo;           /* The current form number (this   */
                                   /* is enumerated from zero)        */
    USHORT       FormCount;        /* Loop control variable           */
    ULONG        ConvFactNum;      /* Multiplier ...                  */
    ULONG        ConvFactDenom;    /*  ... and divisor for conversion */
                                   /* to the required units (mm)      */
    ULONG        ConvFactRound;    /* PD00015 : inch to mm rounding   */
    PBYTE        dp;               /* Pointer for accessing Buffer    */
    PBYTE        pSource, pWork;   /* Working pointers                */
    PBYTE        pEntryStart;      /* Pointer to start of INI entry   */
                                   /* for a printer                   */
    ULONG        ResWidth;         /* Horizontal resolution           */
    ULONG        ResDepth;         /* Vertical resolution             */
    PBYTE        FormPtr;
    PBYTE        pFormData;        /* Start of forms data             */
    lpDDTType    pDDT;             /* Pointer to DDT in PDB           */
    USHORT       i, j;             /* Loop variables                  */
    USHORT       TrayNo;           /*                ........         */
    LONG         Swap;             /* Swap variable for landscape     */
    ULONG        LeftClip;         /* Left and right clip values for  */
    ULONG        RightClip;        /* ..a non-default form read from  */
    ULONG        BottomClip;       /* ..OS2.INI in inches.            */
    ULONG        TopClip;          /*                                 */
    BYTE         DecimalPoint[3];  /* Character used as decimal point */
    PBYTE        pSourceData;      /* Ini form source information     */
    USHORT       NumberManualForms;/* Number manual forms for source  */
    USHORT       MaxFormsReturned; /* Maximum forms that can return   */
    USHORT       DefaultFormNumber;
    PHCINFO      HoldPtrFormInfo;  /* Points to returned form data    */
    USHORT       SourceIndex;      /* Current source index            */
    USHORT       AddedFeed;        /* Whether env. feed installed     */
                                   /* printer                         */
    lpDVTSourceList   pSourceInfo; /* Current source config.          */
    lpDVTSourceTray   pTrayInfo;   /* Tray list for the curr.         */
                                   /* source configuration            */
    DMSettingsType    DMSettings;  /* Device mode settings            */
    ULONG       TopMargin;         /* TopMargin correction for 4224   */
                                   /* printers (in hundredths of      */
                                   /* inches)                         */
    ULONG       TopMarginMm;       /* TopMargin converted to tenths   */
                                   /* of millimetres                  */
    ULONG       RawPageDepth;      /* Depth of page in hundredths of  */
                                   /* inches                          */
    ULONG       RawPageDepthMm;    /* RawPageDepth converted to tenths*/
                                   /* of millimetres                  */
    BOOL        UseSources;        /* Flag to indicate that HCAPS_CUR */
                                   /* RENT will indicate forms in     */
                                   /* sources.                        */
    USHORT      IniVersionType;    /* Says whether .ini entry is in   */
                                   /* current or old format, or       */
                                   /* unusable.                       */


    /******************************************************************/
    /* Trace arguments                                                */
    /******************************************************************/
    TRACE8(TFUNC, "DcH", &DcH, 1);
    TRACE8(TFUNC, "Start", &Start, 1);
    TRACE8(TFUNC, "Count", &Count, 1);
    TRACE8(TFUNC, "PtrFormInfo", PtrFormInfo, 1);
    TRACE8(TFUNC, "DCIData", &DCIData, 1);

    /******************************************************************/
    /* Validation                                                     */
    /******************************************************************/
    if ( !prdz_EnterDriver(DCIData) )
        return(ERROR_NEG);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,56)
#endif

    if ( (Count < 0) || ((Count > 0) && (Start < 0)) )
        goto COUNT_ERROR;

    /******************************************************************/
    /* Useful variables                                               */
    /******************************************************************/
    PDBInstance = DCIData->DCIPdbInstance;
    pDDT        = &PDBInstance->DDT;

    UseSources = ((PDBInstance->pStartPtr != NULL) &&
                  (! (PDBInstance->FormSpecifiedOnOpen )));

    /******************************************************************/
    /*  pStartPtr points to the beginning of the header data of the   */
    /*  INI information.  The segment pointed to by pStartPtr is      */
    /*  allocated and set in prdefpdb and it is deallocated in        */
    /*  prdedpdb.                                                     */
    /******************************************************************/

    if (PDBInstance->pStartPtr == NULL)
    {
        /**************************************************************/
        /* There is no configuration information for this logical     */
        /* printer so return all of the pre-defined forms             */
        /**************************************************************/
        MaxFormsReturned = pDDT->DDTNoOfDefinedForms;
        TRACE6(TFUNC, "MaxFormsReturned", &MaxFormsReturned, 1);

        /**************************************************************/
        /* If zero count return number of default defined forms.      */
        /**************************************************************/
        if ( (USHORT)Count == 0 )
        {
            TRACE6(TFUNC, "Zero Count", FNULL, 0);
            prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,D6)
#endif
            return( (ULONG)MaxFormsReturned );
        }

        TRACE6(TFUNC, "NoOfFormsReturned", &NoOfFormsReturned, 1);
    }
    else
    {
        /**************************************************************/
        /* An entry for the printer driver has been found so          */
        /* interpret the data found (see prdm_Dialog for the          */
        /* format of the entry).  We use pSource as a working         */
        /* pointer; store the position of the start of this entry.    */
        /**************************************************************/
        pEntryStart = PDBInstance->pStartPtr;

        /**************************************************************/
        /*  Calculate the ini version type so that ReadHeaderData     */
        /*  no how to handle the data that is being passed to it.     */
        /**************************************************************/

        IniVersionType = 0;
        for ( i = 0; i < 3; i++)
        {
        IniVersionType = (IniVersionType << 4) +
                         (PDBInstance->IniVersion[i] - '0');
        }
        /**************************************************************/
        /* Read DMSettings, which is needed to find the non-printable */
        /* TopMargin for 4224 printers.                               */
        /**************************************************************/
        pWork = pEntryStart;
        prde_ReadHeaderData( (lpDMSettings) &DMSettings,
                             pWork,
                             IniVersionType );

        /**************************************************************/
        /* Read in the current source index.                          */
        /**************************************************************/
        pSource = pEntryStart + OFF_SOURCE_INDEX;


        /**************************************************************/
        /* Read in the current source index.                          */
        /**************************************************************/
        prdm_ReadWordFromText( SourceIndex,
                               NO_INFO_SIZE_DIGITS,
                               pSource );

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

        /**************************************************************/
        /* Read the current form number.                              */
        /**************************************************************/
        prdm_ReadWordFromText( FormNo,
                               NO_FORM_CNT_DIGITS,
                               pSource );

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

        TRACE6(TFUNC, "NumberOfForms", &NumberOfForms, 1);

        /**************************************************************/
        /* Set up pointers to the form and source data chunks.        */
        /**************************************************************/
        pFormData   = pEntryStart + HEADER_LENGTH;
        pSourceData = pFormData + NumberOfForms * (FORM_DATA_LENGTH + 2);

        /**************************************************************/
        /* Return all the forms present in the configuration data.    */
        /**************************************************************/
        MaxFormsReturned = NumberOfForms;

        TRACE6(TFUNC, "MaxFormsReturned", &MaxFormsReturned, 1);

        /**************************************************************/
        /* If Count is zero return the number of forms available      */
        /* after freeing the memory we have allocated.                */
        /**************************************************************/
        if ( (USHORT)Count == 0 )
        {
//            (void)SSFREESEG(SELECTOROF( PDBInstance->pStartPtr ));
            prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,D6)
#endif
            return((ULONG)MaxFormsReturned);
        }

    }

    /**************************************************************/
    /* More validation                                            */
    /**************************************************************/
    if ( Start > MaxFormsReturned )
        goto COUNT_ERROR;

    /*****************************************************************/
    /* Count is non-zero so calculate the actual number of forms to  */
    /* be returned allowing for the range specified by Start and     */
    /* Count to be totally valid, partially valid or invalid.        */
    /*****************************************************************/
    if ( Start + Count <= MaxFormsReturned )
        NoOfFormsReturned = (USHORT)Count;
    else
        NoOfFormsReturned = MaxFormsReturned - (USHORT)Start;

    TRACE6(TFUNC, "NoOfFormsReturned", &NoOfFormsReturned, 1);

    /******************************************************************/
    /* Get the horizontal and vertical resolutions.                   */
    /******************************************************************/
    ResWidth = DCIData->DCIPdbInstance->DDT.DDTRasterMode->ResWidth;
    ResDepth = DCIData->DCIPdbInstance->DDT.DDTRasterMode->ResDepth;

    TRACE6(TFUNC, "ResWidth", &ResWidth, 1);
    TRACE6(TFUNC, "ResDepth", &ResDepth, 1);

    /******************************************************************/
    /* Always use full stop for decimal point in the form name on the */
    /* queue, as commas are interpreted as separators.                */
    /******************************************************************/
    *DecimalPoint = '.';

    /******************************************************************/
    /* Reference first required form with FormPtr.                    */
    /******************************************************************/
    if ( PDBInstance->pStartPtr == NULL )
        FormPtr = pDDT->DDTDefinedForms[Start].FormData;
    else
        FormPtr = pFormData + Start * (FORM_DATA_LENGTH + 2) + 2;

    HoldPtrFormInfo = PtrFormInfo;

    for ( FormCount = 0;
          FormCount < (USHORT)NoOfFormsReturned;
          PtrFormInfo++, FormCount++, FormPtr += (FORM_DATA_LENGTH + 2) )
    {
        /**************************************************************/
        /* Copy form name and append a null.                          */
        /**************************************************************/
        if ( PDBInstance->pStartPtr == NULL )
        {
            /**********************************************************/
            /* Supplying pre-defined forms                            */
            /**********************************************************/
            DefaultFormNumber = (USHORT)Start + FormCount;
            TRACE6(TFUNC, "form number", &DefaultFormNumber, 1);

            /**********************************************************/
            /* Get the name from the resource file.                   */
            /**********************************************************/
            WinLoadString(
                   hab,
                   prdd_ModHandle,
                   pDDT->DDTDefinedForms[DefaultFormNumber].FormNameId,
                   FORM_NAME_LENGTH,
              (PSZ)PtrFormInfo->szFormname );

            pSource   = pDDT->DDTDefinedForms[DefaultFormNumber].FormData;
            TopMargin = pDDT->DDTSourceList->TopMargin;

            /**********************************************************/
            /* Convert ALT_POINTS to appropriate decimal point.       */
            /**********************************************************/
            for ( dp = PtrFormInfo->szFormname; *dp != '\0'; dp++ )
            {
                if ( *dp == ALT_POINT )
                    *dp = *DecimalPoint;
            }

        }
        else
        {
            /**********************************************************/
            /* Supplying forms from OS2.INI                           */
            /**********************************************************/
            pSourceInfo  = pDDT->DDTSourceList;
            pSourceInfo += DMSettings.SourceIndex;

            /**********************************************************/
            /*  PD00355 : Make sure that the dual bin is selected     */
            /*            before incrementing the sourceindex for the */
            /*            52xx.                                       */
            /**********************************************************/

            if ( DMSettings.AddedFeed == FD_ENVELOPE )
                pSourceInfo += 1;
            else if ( DMSettings.AddedFeed == FD_MULTIMEDIA )
                pSourceInfo += 2;
            else if ( DMSettings.AddedFeed == FD_100_SHEET )
                pSourceInfo += 3;

            pSource   = (PBYTE)FormPtr;
            TopMargin = pSourceInfo->TopMargin;

            /**********************************************************/
            /* Convert ALT_POINTS to appropriate decimal point.       */
            /**********************************************************/
            for ( dp = PtrFormInfo->szFormname; *pSource != '\1'; )
            {
                *dp++ = (*pSource == ALT_POINT)
                                           ? *DecimalPoint : *pSource;
                pSource++;
            }

            *dp++ = '\0';
            pSource++;
        }

        /**************************************************************/
        /* Determine the units conversion factors.  The dimensions    */
        /* are returned in mm so we need to use conversion factors    */
        /* and also allow for the number of decimal places we store   */
        /* the values to without decimal places.                      */
        /*                                                            */
        /* Adjust for top margin on 4224 printers.  Note that         */
        /* TopMargin is in hundredths of inches.                      */
        /**************************************************************/
        if ( *pSource++ == INCHES )
        {
            /**********************************************************/
            /* For inches must convert to millimetres                 */
            /**********************************************************/
            pSource++;

            ConvFactNum   = 254;
            ConvFactDenom = 1000;
            /**********************************************************/
            /* PD00015 : Add rounding factor for inch to millimeter   */
            /* conversions.  This factor was in old 42xx and 52xx     */
            /* drivers but not in the 4019 driver.                    */
            /**********************************************************/
            ConvFactRound = ConvFactDenom / 2;

            /**********************************************************/
            /* Get the values one by one by converting the text in    */
            /* the OS2.INI entry into a number and applying the       */
            /* ConvFactNum and ConvFactDenom.                         */
            /*                                                        */
            /* Keep a copy of cy in inches/100 in RawPageDepth.       */
            /* We round to the nearest interger number of mm.         */
            /**********************************************************/

            /**********************************************************/
            /* PD00015 : Add ConvFactRound to conversion              */
            /**********************************************************/
            PtrFormInfo->cx = (LONG) ( ((ConvFactNum *
               (ULONG)prde_GetValFromText( &pSource )) + ConvFactRound) /
                                                         ConvFactDenom );

            pSource++;

            RawPageDepth = (ULONG)prde_GetValFromText( &pSource );
            /**********************************************************/
            /* PD00015 : Add ConvFactRound to conversion              */
            /**********************************************************/
            PtrFormInfo->cy = (LONG)
                    ( ((ConvFactNum * RawPageDepth) + ConvFactRound) /
                                                        ConvFactDenom );
            pSource++;

            /**********************************************************/
            /* Keep a copy of the left and right clip in inches to    */
            /* minimise rounding errors.                              */
            /**********************************************************/
            LeftClip = prde_GetValFromText( &pSource );
            pSource++;
            PtrFormInfo->xLeftClip = (LONG)
                 ( (ConvFactNum * (ULONG)LeftClip) / ConvFactDenom );

            RightClip = prde_GetValFromText( &pSource );
            pSource++;
            PtrFormInfo->xRightClip = (LONG)
                 ( (ConvFactNum * (ULONG)RightClip) / ConvFactDenom );

            if (pDDT->DDTFormFlags & DDT_VAR_BOTTOM_CLIP)
            {
               /***************************************************************/
               /*  INKJET:The Bottom Clip limit varies with the paper source. */
               /***************************************************************/
               /**********************************************************/
               /* Adjust BottomClip with the Top Margin value            */
               /**********************************************************/
               BottomClip = prde_GetValFromText( &pSource );

               if ( BottomClip < TopMargin )
                   BottomClip = TopMargin;

               pSource++;
               PtrFormInfo->yBottomClip = (LONG)
                    ( (ConvFactNum * (ULONG)BottomClip) / ConvFactDenom );

               TopClip = prde_GetValFromText( &pSource );

               pSource++;
               PtrFormInfo->yTopClip = (LONG)
                    ( (ConvFactNum * (ULONG)TopClip) / ConvFactDenom );
            }
            else
            {
               BottomClip = prde_GetValFromText( &pSource );
               pSource++;
               PtrFormInfo->yBottomClip = (LONG)
                    ( (ConvFactNum * (ULONG)BottomClip) / ConvFactDenom );

               /**********************************************************/
               /* Adjust TopClip for TopMargin                           */
               /**********************************************************/
               TopClip = prde_GetValFromText( &pSource );

               if ( TopClip > RawPageDepth - TopMargin )
                   TopClip = RawPageDepth - TopMargin;

               pSource++;
               PtrFormInfo->yTopClip = (LONG)
                    ( (ConvFactNum * (ULONG)TopClip) / ConvFactDenom );
            }

            /**********************************************************/
            /* Convert clip values to pel values. Perform same        */
            /* rounding as at enable time ie. round bottom and left   */
            /* coordinates up.                                        */
            /**********************************************************/
            PtrFormInfo->xPels = (RightClip - LeftClip) * ResWidth / 100;

            if ( pDDT->DDTInitFlags & DDT_INIT_PAGE_LENGTH )
            {
                /******************************************************/
                /* Work in 72ths of inches - as this is what printer  */
                /* physically handles.                                */
                /******************************************************/
                PtrFormInfo->yPels = (TopClip - BottomClip) * 72 / 100;
                PtrFormInfo->yPels = (PtrFormInfo->yPels * ResDepth) / 72;
            }
            else
            {
                PtrFormInfo->yPels = (TopClip - BottomClip) * ResDepth / 100;
            }
        }
        else
        {
            /***********************************************************/
            /* For millimetres just need to correct for the decimal    */
            /* place so no need to calculate a convert factor.         */
            /***********************************************************/
            pSource++;

            /**********************************************************/
            /* TopMarginMm is TopMargin converted to units of tenths  */
            /* of millimetres.                                        */
            /**********************************************************/
            TopMarginMm = (TopMargin * 254) / 100;

            /**********************************************************/
            /* Get the values one by one by converting the text in    */
            /* the OS2.INI entry into a number and applying the       */
            /* ConvFactNum and ConvFactDenom.                         */
            /**********************************************************/
            PtrFormInfo->cx = (LONG)
                   ( (ULONG)prde_GetValFromText( &pSource ) / 10);
            pSource++;

            RawPageDepthMm = (ULONG)prde_GetValFromText( &pSource );
            PtrFormInfo->cy = (LONG) ( RawPageDepthMm / 10);
            pSource++;

            LeftClip = (ULONG)prde_GetValFromText( &pSource );
            pSource++;

            RightClip = (ULONG)prde_GetValFromText( &pSource );
            pSource++;

            PtrFormInfo->xLeftClip = LeftClip / 10;

            PtrFormInfo->xRightClip = RightClip / 10;

            if (pDDT->DDTFormFlags & DDT_VAR_BOTTOM_CLIP)
            {
               /***************************************************************/
               /*  INKJET:The Bottom Clip limit varies with the paper source. */
               /***************************************************************/
               /**********************************************************/
               /* Adjust BottomClip for TopMargin                        */
               /**********************************************************/
               BottomClip = (ULONG)prde_GetValFromText( &pSource );

               if ( BottomClip < TopMarginMm )
                   BottomClip = TopMarginMm;

               PtrFormInfo->yBottomClip = BottomClip / 10;
               pSource++;

               TopClip = (ULONG)prde_GetValFromText( &pSource );
               PtrFormInfo->yTopClip = TopClip / 10;
               pSource++;

            }
            else
            {
               BottomClip = (ULONG)prde_GetValFromText( &pSource );
               PtrFormInfo->yBottomClip = BottomClip / 10;
               pSource++;

               /**********************************************************/
               /* Adjust TopClip for TopMargin                           */
               /**********************************************************/
               TopClip = (ULONG)prde_GetValFromText( &pSource );

               if ( TopClip > RawPageDepthMm - TopMarginMm )
                   TopClip = RawPageDepthMm - TopMarginMm;

               PtrFormInfo->yTopClip = TopClip / 10;
               pSource++;

            }
            /**********************************************************/
            /* Derive the width and height between the clips in pels. */
            /* Note that RasterMode is pels per inch. Treat values as */
            /* metres for convenience then divide by 1000 to put back */
            /* into the correct units                                 */
            /**********************************************************/
            PtrFormInfo->xPels = (RightClip - LeftClip) * ResWidth / 254;

            if ( pDDT->DDTInitFlags & DDT_INIT_PAGE_LENGTH )
            {
                /******************************************************/
                /* Work in 72ths of inches - as this is what printer  */
                /* physically handles.                                */
                /******************************************************/
                PtrFormInfo->yPels = (TopClip - BottomClip) * 72 / 254;
                PtrFormInfo->yPels = (PtrFormInfo->yPels * ResDepth) / 72;
            }
            else
            {
                PtrFormInfo->yPels = (TopClip - BottomClip) * ResDepth / 254;
            }

        }

        TRACE4(TFUNC, "PelWidth", &(PtrFormInfo->xPels), 1);
        TRACE4(TFUNC, "PelHeight", &(PtrFormInfo->yPels), 1);
        TRACE4(TFUNC, "FormInfo", &PtrFormInfo->xLeftClip, 6);

        /**************************************************************/
        /* Swap over if lanscape was selected.                        */
        /**************************************************************/
        if (PDBInstance->Orientation == LANDSCAPE)
        {
            Swap = PtrFormInfo->cx;
            PtrFormInfo->cx = PtrFormInfo->cy;
            PtrFormInfo->cy = Swap;

            Swap = PtrFormInfo->xPels;
            PtrFormInfo->xPels = PtrFormInfo->yPels;
            PtrFormInfo->yPels = Swap;

            Swap = PtrFormInfo->xRightClip;
            PtrFormInfo->xRightClip  = PtrFormInfo->yTopClip;
            PtrFormInfo->yTopClip    = Swap;

            Swap = PtrFormInfo->xLeftClip;
            PtrFormInfo->xLeftClip   = PtrFormInfo->yBottomClip;
            PtrFormInfo->yBottomClip = Swap;

            TRACE4(TFUNC, "Swapped FormInfo", &PtrFormInfo->xLeftClip, 6);
        }

        /**************************************************************/
        /* Reset attribute field first.                               */
        /**************************************************************/
        PtrFormInfo->flAttributes = 0x0;

        /**************************************************************/
        /* Set the attribute to show that this is a selected form.    */
        /**************************************************************/
        if (!UseSources)
        {
            /**********************************************************/
            /* HCAPS_CURRENT for all forms specified on open i.e. all */
            /* of those in PPMInfo.                                   */
            /**********************************************************/
            for (i=0; i<PDBInstance->NumberOfForms; i++ )
            {
                FormNo = PDBInstance->PPMInfo[i].FormNumber;

                if (FormNo == (USHORT)Start + FormCount)
                {
                    /**********************************************************/
                    /*  PD00738 : Only the current form will be HCAPS_CURRENT */
                    /*  depending on which page we are currently printing.    */
                    /**********************************************************/
                    if ( ((DCIData->DCIPageNumber == 1) && (i == 0)) ||
                         (PDBInstance->NumberOfForms == 1) )
                    {
                        PtrFormInfo->flAttributes |= HCAPS_CURRENT;
                    }
                    else if ( (DCIData->DCIPageNumber > 1) && (i == 1) )
                    {
                        PtrFormInfo->flAttributes |= HCAPS_CURRENT;
                    }
                }
            }
        }
    }
    /*.. for ( FormCount=0; FormCount...every form we can return......*/


    /**************************************************************************/
    /* Unless we are going to scan through the sources to find the            */
    /* current forms we have finished now.                                    */
    /*  PD00738 : Remove the prdm_LeaveDriver from this point                 */
    /*  PD00787 : Instead of not leaving the driver at all we will only check */
    /*  for no INI data before we leave.  pStartPtr is the pointer to INI data*/
    /**************************************************************************/
    if ( PDBInstance->pStartPtr == NULL )
    {
        TRACE6(TFUNC, "Exit OK", FNULL, 0);
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,D6)
#endif
        return(NoOfFormsReturned);
    }


    /******************************************************************/
    /* The printers can have variable paper sources and so can have   */
    /* multiple forms which are selectable simultaneously.  Examine   */
    /* all the source information and identify all the forms which    */
    /* are selectable.                                                */
    /* Pick up a pointer to the info for the current source config.   */
    /*  This is done as follows:                                      */
    /* - Get the pointer to the source list                           */
    /* - Adjust the pointer according to the current                  */
    /*     source index                                               */
    /* - Allow for the special case of the dual tray                  */
    /*     sources on the Qs                                          */
    /* - Allow for Laser/Heritage dual trays and multi-media tray.    */
    /******************************************************************/
    PtrFormInfo = HoldPtrFormInfo;

    pSourceInfo  = pDDT->DDTSourceList;
    pSourceInfo += SourceIndex;

    /******************************************************************/
    /*  PD00355 : Make sure that the dual bin is selected before      */
    /*            incrementing the sourceindex for the 52xx.          */
    /******************************************************************/

    if (AddedFeed == FD_ENVELOPE)
        pSourceInfo += 1;
    else if (AddedFeed == FD_MULTIMEDIA)
        pSourceInfo += 2;
    else if (AddedFeed == FD_100_SHEET)
        pSourceInfo += 3;

    TRACE6(TFUNC, "Source info", pSourceInfo, 2);

    /******************************************************************/
    /* Now loop through all the trays for this source configuration   */
    /* and record all the forms associated with a tray.               */
    /******************************************************************/
    for ( TrayNo = 0, pTrayInfo = pSourceInfo->SourceTrayList;
          TrayNo < pSourceInfo->NoOfLogicalTrays;
          TrayNo++, pTrayInfo++ )
    {
        if ( pTrayInfo->FeedType == DDT_AUTO_FEED )
        {
            /**********************************************************/
            /* Get the form associated with this tray.                */
            /**********************************************************/
            pWork = pSourceData +
                         (NO_FORM_CNT_DIGITS * pTrayInfo->DMTrayUsage);

            prdm_ReadWordFromText( FormNo,
                                   NO_FORM_CNT_DIGITS,
                                   pWork );

            TRACE6(TFUNC, "Form no", &FormNo, 1);

            /******************************************************************/
            /* Check if we have returned this form                            */
            /*  PD00738 : Change the HCAPS_CURRENT to HCAPS_SELECTABLE        */
            /******************************************************************/
            if ( (FormNo >= (USHORT)Start) &&
                 (FormNo < ((USHORT)Start + NoOfFormsReturned)) )
            {
                (PtrFormInfo[FormNo - (USHORT)Start]).flAttributes |=
                                                          HCAPS_SELECTABLE;
                if ( UseSources )
                {
                    /**********************************************************/
                    /*  If there is no driver data then we must set the       */
                    /*  default current form as the form loaded in the first  */
                    /*  automatic tray.                                       */
                    /**********************************************************/
                    (PtrFormInfo[FormNo - (USHORT)Start]).flAttributes |=
                                                              HCAPS_CURRENT;
                    UseSources = FALSE;
                }
            }
        }
        else
        {
            /**********************************************************/
            /* This is a manual tray - if manual envelope we have to  */
            /* skip over the manual paper forms to get to the manual  */
            /* envelope forms.                                        */
            /**********************************************************/
            pWork = pSourceData +
                             (NO_FORM_CNT_DIGITS * CS_MANUAL_PAPER );

            /******************************************************************/
            /* PD00243 - For Heritage, must treat manual envelope tray        */
            /*           the same as the 4019.  Heritage manual env.          */
            /*           trays type is DDT_DEFAULT_OR_ENV_FORM                */
            /* INKJET : The 4072 has a SourceType that allows both paper and  */
            /*  envelopes also.                                               */
            /******************************************************************/

            if ((pTrayInfo->SourceType == DDT_ENVELOPE_FORM) ||
                (pTrayInfo->SourceType == DDT_DEFAULT_OR_ENV_FORM) ||
                (pTrayInfo->SourceType == (DDT_PAPER_FORM | DDT_ENVELOPE_FORM)))
            {
                prdm_ReadWordFromText( NumberManualForms,
                                       NO_FORM_CNT_DIGITS,
                                       pWork );

                pWork += (NO_FORM_CNT_DIGITS * NumberManualForms);
            }

            /**********************************************************/
            /* Get the number of manual forms and for each form       */
            /* check if it is in the range of form data returned.     */
            /**********************************************************/
            prdm_ReadWordFromText( NumberManualForms,
                                   NO_FORM_CNT_DIGITS,
                                   pWork );

            for ( j = 0; j < NumberManualForms; j++ )
            {
                prdm_ReadWordFromText( FormNo,
                                       NO_FORM_CNT_DIGITS,
                                       pWork );

                TRACE6(TFUNC, "Form no", &FormNo, 1);

                /**************************************************************/
                /* Check if we have returned this form                        */
                /*  PD00738 : Change the HCAPS_CURRENT to HCAPS_SELECTABLE    */
                /**************************************************************/
                if ( (FormNo >= (USHORT)Start) &&
                     (FormNo < ((USHORT)Start + NoOfFormsReturned)) )
                {
                    (PtrFormInfo[FormNo - (USHORT)Start]).flAttributes
                                                        |= HCAPS_SELECTABLE;
                    if ( UseSources )
                    {
                        /******************************************************/
                        /*  If there is no driver data then we must set the   */
                        /*  form to the first default form.  Manual Forms are */
                        /*  always checked second so this will work for the   */
                        /*  case of a printer that only has manual form feed. */
                        /******************************************************/
                        (PtrFormInfo[FormNo - (USHORT)Start]).flAttributes |=
                                                                 HCAPS_CURRENT;
                        UseSources = FALSE;
                    }
                }
            }
            /* .... for ( j = 0; j < NumberManualForms; j++ ) ....... */
        }
        /* .... if ( pTrayInfo->FeedType != DDT_AUTO_FEED ) ..........*/
    }
    /* .... for ( .. TrayNo < pSourceInfo->NoOfLogicalTrays; .. ) ... */


    /******************************************************************/
    /* Deallocate the heap space and return the number of forms we    */
    /* have returned.                                                 */
    /******************************************************************/
//    (void)SSFREESEG(SELECTOROF( PDBInstance->pStartPtr ));
    prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,D6)
#endif
    return(NoOfFormsReturned);

COUNT_ERROR:
    prdm_LeaveDriver(DCIData);
    LOGERR(TFUNC, "Count < 0", FNULL, 0, PMERR_INV_LENGTH_OR_COUNT);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,D6)
#endif
    return(ERROR_NEG);
}
#undef TFUNC


