/*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 = PRDPSUBR
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdp_PrintSimple
 *             prdp_PrintMemory
 *             prdp_AddString
 *             prdp_PrintMoveDown
 *             prdp_AddHorizMoveString
 *             prdp_NeedSpacesForMove
 *             prdp_OutlineFontSizeString
 *             prdp_IntToAsciiDecimal
 *
 * 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_DOSMODULEMGR
#include <os2.h>
#undef INCL_DOSPROCESS              /* CON3201 */
#undef INCL_DOSMODULEMGR
#undef INCL_DOSSEMAPHORES
#undef INCL_GREALL
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_SPL
#undef INCL_WINSHELLDATA

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

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

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

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

#include <prdncone.h>
#include <prdeextf.h>
#include <prdgextf.h>
#include <prdpextf.h>
#include <prdyextf.h>
#include <prdnextf.h>
#include <prdtextf.h>
#include <prduextf.h>

extern ESTEntryType     EST[];
extern PCHAR            OS2_INI_VERSION;
extern ULONG            prdd_Zeroes[];


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_PrintSimple                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   lpDCI           DCIData;      Pointer to DC Instance data        */
/*   USHORT          CommandSrc;   which command table to use         */
/*   USHORT          Command;      Index into a command table         */
/*   PBYTE           lpParams;     Pointer to any parameters which    */
/*                                 need to be included in the         */
/*                                 command sequence                   */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function accesses uses the DCT to access the EST or the     */
/*   EST directly to send issue escape sequences. It uses the PDB     */
/*   instance data scratch pad, therefore commands in the EST must    */
/*   be no longer than DCT_MAX_SIMPLE                                 */
/*                                                                    */
/**********************************************************************/
/*CON3201
USHORT pascal prdp_PrintSimple ( DCIData,
                               CommandSrc,
                               Command,
                               lpParams )

lpDCI           DCIData;
USHORT          CommandSrc;
USHORT          Command;
PBYTE           lpParams;
                         */

USHORT prdp_PrintSimple (lpDCI           DCIData,
                         USHORT          CommandSrc,
                         USHORT          Command,
                         PBYTE           lpParams)

{
#define TFUNC "prdp_PrintSmple"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    lpPDBI      PDBInst;       /* Pointer to the PDB Instance data    */
    USHORT      return_value;  /* ERROR_NEG,ERR_ABORT,ERR_PURGE      */
    USHORT      BytesWritten;  /* number of bytes prtwritten          */
    ULONG       Index;         /* index into EST for escape string    */
    USHORT      SrcLen;        /* escape string length                */
    USHORT      SrcMask;       /* escape string mask                  */
    PCHAR       SrcString;     /* escape string                       */
    PCHAR       lpString;      /* local pointer to scratch pad        */
    USHORT      ParamBits;     /* Used to examine ParamMask           */

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

    /******************************************************************/
    /* Set up pointers to the PDB Instance data from the DC           */
    /* Instance data and to the DCT for this printer.                 */
    /******************************************************************/
    PDBInst = DCIData->DCIPdbInstance;

    /******************************************************************/
    /* Need to output escape codes if DC is                           */
    /*  - DIRECT (STD or RAW) .. write to printer                     */
    /*  - QUEUED (RAW only) .... write to spooler                     */
    /* Otherwise just return OK.                                      */
    /******************************************************************/
    if ( (DCIData->Flags & DIRECT) ||
         (DCIData->Flags & QUEUED_RAW) )
    {
        /**************************************************************/
        /* Command can be an index into the printer DCT, which gives  */
        /* an index into the EST, or a direct index into the EST.     */
        /**************************************************************/
        if (CommandSrc == USE_PRINTER_TABLE)
        {
            Index = PDBInst->PrinterData->lpDCT[Command];

            /**********************************************************/
            /* If this entry is not used then just return OK.         */
            /**********************************************************/
            if (Index == (ULONG)((USHORT)EST_NOT_USED)) /* CON3203 */
            {
                return ( OK );
            }

        }
        else
        {
            Index = Command;
        }

        TRACE6(TFUNC, "EST Index", &Index, 1);

        /**************************************************************/
        /* Get the information about the escape sequences from the    */
        /* global Escape Sequence Table. Only acess array if index is */
        /* in range of course and if it isn't then output an error.   */
        /**************************************************************/
        if ((Index >= 0) && (Index <= EST_NUMBER_ENTRIES))
        {
            SrcString = EST[Index].EscapeSeq;
            SrcLen    = EST[Index].EscapeSeqLen;
            SrcMask   = EST[Index].ParamMask;
        }
        else
        {
            OutputPrompt("Invalid EST Index in PRINT SIMPLE");
            return ( ERROR_NEG );
        }


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

        /**************************************************************/
        /* Firewall to ensure that we don't GP trap when anybody adds */
        /* new escape sequences that are too big for the scratch pad  */
        /**************************************************************/
        if (SrcLen > DCT_MAX_SIMPLE)
        {
            OutputPrompt("EST length greater than scratch pad size");
            return (ERROR_NEG);
        }

        /**************************************************************/
        /* Copy the string into the scratch pad                       */
        /**************************************************************/
        prdu_memcpy( (PBYTE) PDBInst->PDBScratch,
                     (PBYTE) SrcString,
                     (USHORT)SrcLen );

        /**************************************************************/
        /* Update the escape sequence with any supplied parameters.   */
        /* Starting from the least significant bit and while there    */
        /* are still parameters to insert in the control sequence     */
        /* (SrcMask!=0) check if the next position in the sequence    */
        /* requires a parameter and if it does reset the              */
        /* corresponding bit in ParamMask and insert the parameter)   */
        /* into the sequence.                                         */
        /**************************************************************/
        for ( ParamBits = 1,lpString = PDBInst->PDBScratch;
              SrcMask != 0;
              ParamBits += ParamBits, lpString++ )
        {
            if ( (SrcMask & ParamBits) != 0 )
            {
                SrcMask &= ~ParamBits;
                *lpString = *lpParams;
                lpParams++;
            }
        }

        /**************************************************************/
        /* Now write the data.                                        */
        /**************************************************************/
        if (DCIData->Flags & DIRECT)
        {
            /**********************************************************/
            /* Keep trying to write the string to the DOS device (the */
            /* printer) until we succeed or we give up trying.        */
            /**********************************************************/
            return_value = prdn_PrtWrite( DCIData,
                                          PDBInst->PDBScratch,
                                          SrcLen,
                                          PDBInst,
                                          BytesWritten );

            if (return_value != OK)
            {
                /******************************************************/
                /* ERR_ABORT or ERR_PURGE                             */
                /******************************************************/
                return ( return_value );
            }
        }
        else
        {
            /**********************************************************/
            /* Output string to spooler file.                         */
            /**********************************************************/
            if ( SplQmWrite ( (HSPL)DCIData->DCISplHandle,
                              (ULONG)SrcLen,
                              PDBInst->PDBScratch) != OK )
            {
                return ( ERROR_NEG );
            }
        }
    }
    /* .. if (DIRECT or QUEUED RAW) ................................. */

    TRACE8(TFUNC, "Exit OK", FNULL, 0);
    return ( OK );

}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_PrintMemory                                       */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PBYTE       pMemory;      Pointer to buffer to be output         */
/*   USHORT      MemoryIndex;  Number of characters to be output      */
/*   lpDCI       DCIData;      Pointer to DC INstance data            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function prints the current contents of the buffer          */
/*   described by pMemory and MemoryIndex.                            */
/*                                                                    */
/**********************************************************************/
/*
USHORT pascal prdp_PrintMemory ( pMemory,
                                 MemoryIndex,
                                 DCIData )

PBYTE       pMemory;
USHORT      MemoryIndex;
lpDCI       DCIData;
                     */

USHORT prdp_PrintMemory (PBYTE       pMemory,
                         USHORT      MemoryIndex,
                         lpDCI       DCIData)

{
#define TFUNC "prdp_PrintMem"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    USHORT      Result;            /* Function call return values     */
    lpPDBI      PDBInst;           /* Pointer to the PDB Instance data*/
    USHORT      BytesWritten;      /* number of bytes prtwritten      */

    /******************************************************************/
    /* Set up PDBInst from the DC Instance data.                      */
    /******************************************************************/
    PDBInst = DCIData->DCIPdbInstance;

    /******************************************************************/
    /* If it is an Indirect DC of IBM_Q_RAW data then output the      */
    /* string to the spool file and return an error if this fails.    */
    /******************************************************************/
    if ( (DCIData->DCIDCType == OD_QUEUED) &&
         (PDBInst->PDBOutputType == IBMQRAW) )
    {
        Result = SplQmWrite ( (HSPL)DCIData->DCISplHandle,
                              (ULONG) MemoryIndex,
                              pMemory );

        TRACE4(TFUNC, "SplQmWrite Result", &Result, 1);

        if ( Result != OK )
        {
            TRACE4(TFUNC, "Spool write failed", &Result, 1);
            return (Result);
        }
    }
    else if ( DCIData->DCIDCType == OD_DIRECT )
    {
        /**************************************************************/
        /* Otherwise output the string directly to the printer.       */
        /**************************************************************/
        if ( MemoryIndex )
        {
            /**********************************************************/
            /* Only write out data if there is some data to be        */
            /* written.                                               */
            /**********************************************************/
            Result = prdn_PrtWrite( DCIData,
                                    pMemory,
                                    MemoryIndex,
                                    PDBInst,
                                    BytesWritten );

            if ( Result != OK )
                return ( Result );
        }
    }

    return (OK);

}
#undef TFUNC






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_AddString                                         */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   USHORT          LogCommand;   Command number (in DCT) or the     */
/*                                 length of the string for direct    */
/*                                 string output                      */
/*   PBYTE           lpParams;     Pointer to any parameters which    */
/*                                 need to be included in the         */
/*                                 command sequence or the string to  */
/*                                 be output for direct string output */
/*   USHORT          Option;       Option flags determine whether the */
/*                                 string to add is a command         */
/*                                 sequence or a string of characters */
/*   lpDCI           DCIData;      Pointer to DC Instance data        */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function adds a string to the buffer and outputs the buffer */
/*   when full.  It can output either command sequences (built up     */
/*   using the same method as prdp_MakeString) or simple character    */
/*   strings.                                                         */
/*                                                                    */
/**********************************************************************/
/*CON3201
USHORT pascal prdp_AddString ( Command,
                               CommandSrc,
                               lpParams,
                               pMemory,
                               pMemoryIndex,
                               MemorySize,
                               DCIData )

USHORT          Command;
USHORT          CommandSrc;
PBYTE           lpParams;
PBYTE           pMemory;
PUSHORT         pMemoryIndex;
USHORT          MemorySize;
lpDCI           DCIData;
                         */

USHORT prdp_AddString (USHORT          Command,
                       USHORT          CommandSrc,
                       PBYTE           lpParams,
                       PBYTE           pMemory,
                       PUSHORT         pMemoryIndex,
                       USHORT          MemorySize,
                       lpDCI           DCIData)

{
#define TFUNC "prdp_AddString"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    USHORT        Result;       /* ERR_ABORT, ERR_PURGE               */
    lpPDBI        PDBInst;      /* Pointer to the PDB Instance data   */
                                /* Change Index to LONG, could be neg */
    LONG          Index;        /* index into EST from DCT            */
    PCHAR         SrcString;    /* string to be written               */
    USHORT        SrcLen;       /* length of the string to be written */
    USHORT        SrcMask;      /* mask for inserting parameters      */
    USHORT        ParamBits;    /* ... into a control sequence        */

    TRACE4(TFUNC, "Entry", FNULL, 0);
    TRACE4(TFUNC, "Command", &Command, 1);
    TRACE4(TFUNC, "CommandSrc", &CommandSrc, 1);

    /******************************************************************/
    /* get hold of the string to be output                            */
    /******************************************************************/
    if ( CommandSrc == USE_PRINTER_TABLE )
    {
        /**************************************************************/
        /* In this it comes via the printer command table to the EST  */
        /**************************************************************/
        PDBInst   = DCIData->DCIPdbInstance;
        Index     = PDBInst->PrinterData->lpDCT[Command];
        /**************************************************************/
        /* If this entry is not used then just return OK.             */
        /**************************************************************/
        if (Index == (USHORT)EST_NOT_USED) /* CON3203 */
        {
            return ( OK );
        }

        if ((Index >= 0) && (Index <= EST_NUMBER_ENTRIES))
        {
            SrcString = EST[Index].EscapeSeq;
            SrcLen    = EST[Index].EscapeSeqLen;
            SrcMask   = EST[Index].ParamMask;
        }
        else
        {
            OutputPrompt("Invalid EST Index in ADD STRING");
            return ( ERROR_NEG );
        }
    }

    else if ( CommandSrc == USE_GLOBAL_TABLE )
    {
        /**************************************************************/
        /* In this it comes from the EST directly                     */
        /**************************************************************/
        Index = Command;

        if ((Index >= 0) && (Index <= EST_NUMBER_ENTRIES))
        {
            SrcString = EST[Index].EscapeSeq;
            SrcLen    = EST[Index].EscapeSeqLen;
            SrcMask   = EST[Index].ParamMask;
        }
        else
        {
            OutputPrompt("Invalid EST Index in ADD STRING");
            return ( ERROR_NEG );
        }
    }
    else
    {
        /**************************************************************/
        /* In this case it is supplied on the call, there can be no   */
        /* byte replacement                                           */
        /**************************************************************/
        SrcString = lpParams;
        SrcLen    = Command;
        SrcMask   = 0;
    }

    TRACE4(TFUNC, "SrcString", SrcString, 3);
    TRACE4(TFUNC, "SrcLen", &SrcLen, 1);

    /******************************************************************/
    /* If the buffer is too full to accomodate the new string then    */
    /* output it.                                                     */
    /******************************************************************/
    if ( *pMemoryIndex + SrcLen > MemorySize )
    {
        TRACE4(TFUNC, "Buffer full", FNULL, 0);

        if ( (Result = prdp_PrintMemory ( pMemory,
                                          *pMemoryIndex,
                                          DCIData) ) != OK )
        {
            return (Result);
        }

        *pMemoryIndex  = 0;
    }

    /******************************************************************/
    /* Add the string to the buffer as long as it is at least one     */
    /* character long.                                                */
    /******************************************************************/
    if ( SrcLen )
    {
        pMemory += *pMemoryIndex;

        prdu_memcpy( (PBYTE)pMemory, (PBYTE)SrcString, (USHORT)SrcLen);
    }

    /******************************************************************/
    /* Parse the string if there are any bytes to be replaced.        */
    /******************************************************************/
    if ( SrcMask )
    {
        for ( ParamBits = 1;
              SrcMask != 0;
              ParamBits += ParamBits, pMemory++ )
        {
            /**********************************************************/
            /* Loop for each bit updating if the bit is set           */
            /**********************************************************/
            if ( SrcMask & ParamBits )
            {
                SrcMask &= ~ParamBits;
                *pMemory = *lpParams;
                lpParams++;
            }
        }
    }

    /******************************************************************/
    /* Update MemoryIndex to include String;                          */
    /******************************************************************/
    *pMemoryIndex += SrcLen;

    TRACE4(TFUNC, "MemoryIndex", pMemoryIndex, 1);
    TRACE4(TFUNC, "Exit", FNULL, 0);

    return (OK);
}
#undef TFUNC

/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_PrintMoveDown                                     */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PUSHORT      pHeadPos;    Pointer to the current head position   */
/*                             on the vertical axis (returns as new   */
/*                             head position on the vertical axis)    */
/*   PUSHORT      pHeadErr;    Pointer to the error in the current    */
/*                             head position (due to printer          */
/*                             resolution being different to DC       */
/*                             resolution)                            */
/*   USHORT       Target;      Required new head position on the      */
/*                             vertical axis                          */
/*   lpDCI        DCIData;     Pointer to DC Instance data            */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function moves the printer head to as close to the Target   */
/*   position as possible taking account of the current error in head */
/*   position and calculating the new error in head position.  Exact  */
/*   positioning of the head may not be possible due to limitations   */
/*   on the printers vertical resolution.                             */
/*                                                                    */
/**********************************************************************/
/*CON3201
USHORT prdp_PrintMoveDown (pHeadPos,
                         pHeadErr,
                         Target,
                         pMemory,
                         pMemoryIndex,
                         MemorySize,
                         DCIData)

PUSHORT      pHeadPos;
PUSHORT      pHeadErr;
USHORT       Target;
PBYTE        pMemory;
PUSHORT      pMemoryIndex;
USHORT       MemorySize;
lpDCI        DCIData;
                           */

USHORT prdp_PrintMoveDown (PUSHORT      pHeadPos,
                           PUSHORT      pHeadErr,
                           USHORT       Target,
                           PBYTE        pMemory,
                           PUSHORT      pMemoryIndex,
                           USHORT       MemorySize,
                           lpDCI        DCIData)

{
#define TFUNC "prdp_PrntMveDwn"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    USHORT        Result;
    USHORT        Length;      /* The amount we move the print head   */
    USHORT        HeadMove;    /* The amount we move the print head   */
                               /* in each step                        */
    ULONG         Work;        /* Intermediate value in calculation   */
                               /* of length                           */
    lpDDTType     pDDT;        /* Pointer to DDT                      */

    TRACE4(TFUNC, "Head Pos", pHeadPos, 1);
    TRACE4(TFUNC, "Target", &Target, 1);
    TRACE4(TFUNC, "Head Error", pHeadErr, 1);

    /******************************************************************/
    /* If the HeadPos is < the Target head position then there is     */
    /* nothing for us to do so exit (HeadPos and Target are measured  */
    /* from the bottom of the sheet of paper so moving the printer    */
    /* head down the paper increases HeadPos)                         */
    /******************************************************************/
    if ((int)*pHeadPos <= (int)Target)
        return(OK);

    /******************************************************************/
    /* Set up the pDDT                                                */
    /******************************************************************/
    pDDT = &DCIData->DCIPdbInstance->DDT;

    /******************************************************************/
    /* The difference between Target and HeadPos is multiplied by     */
    /* the printers vertical units before adding it to the HeadErr as */
    /* this is the format the HeadErr is stored in.                   */
    /******************************************************************/
    Work = (ULONG)(*pHeadPos - Target) *
           (ULONG)pDDT->DDTRasterMode->VerticalUnits +
           (ULONG)*pHeadErr;

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

    /******************************************************************/
    /* Work is then divided by the printer's vertical resolution. Note*/
    /* that this gives us an overall factor of vertical units of      */
    /* movement divided by vertical resolution which we multiply the  */
    /* distance we want to move by (this distance being in units of   */
    /* the printers vertical resolution) to get the movement in terms */
    /* of the printers vertical units of movement. (hopefully!)       */
    /******************************************************************/
    Length = (USHORT)((ULONG)Work /
                    (ULONG)pDDT->DDTRasterMode->ResDepth);

    TRACE4(TFUNC, "Length", &Length, 1);

    /******************************************************************/
    /* Set the HeadPos to the Target and calculate the error which    */
    /* is Work mod ResDepth. ??? code change                          */
    /******************************************************************/
    *pHeadPos = Target;
    *pHeadErr = (USHORT)((ULONG)Work - (ULONG)Length *
                       (ULONG)pDDT->DDTRasterMode->ResDepth);

    TRACE4(TFUNC, "New Head Pos", pHeadPos, 1);
    TRACE4(TFUNC, "New Head Error", pHeadErr, 1);

    /******************************************************************/
    /* Move the printer head the desired distance allowing for the    */
    /* maximum movement in a single step.                             */
    /******************************************************************/
    while (Length)
    {
        HeadMove = min (Length, pDDT->DDTRasterMode->MaxVerticalMove);
        Length -= HeadMove;

        TRACE4(TFUNC, "Move Head", &HeadMove, 1);

        if ( (Result = prdp_AddString (
                             EST_VARIABLE_LINE_FEED,
                             USE_GLOBAL_TABLE,
                             (PBYTE)&HeadMove,
                             pMemory,
                             (PUSHORT)pMemoryIndex,
                             MemorySize,
                             DCIData )) != OK)
        {
            return (Result);
        }
    }


    TRACE4(TFUNC, "Return OK", FNULL, 0);
    return(OK);
}
#undef TFUNC



/*CON3201
USHORT pascal prdp_AddHorizMoveString ( ReqdPosX,
                                        CurrPosX,
                                        pMemory,
                                        pMemoryIndex,
                                        MemorySize,
                                        DCIData )

SHORT           ReqdPosX;
SHORT           CurrPosX;
PBYTE           pMemory;
PUSHORT         pMemoryIndex;
USHORT          MemorySize;
lpDCI           DCIData;
                          */

USHORT prdp_AddHorizMoveString (SHORT           ReqdPosX,
                                SHORT           CurrPosX,
                                PBYTE           pMemory,
                                PUSHORT         pMemoryIndex,
                                USHORT          MemorySize,
                                lpDCI           DCIData)

{
#define TFUNC "prdp_AddHorMovS"

    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    lpDDTType         pDDT;
    lpPDBI            PDBInst;
    USHORT            PrinterType;
    lpFontDataType    pFontData;
    BOOL              MoveRight;
    SHORT             NoOfFontPels;
    SHORT             NoOfRoughMoves;
    SHORT             NoOfFineMoves;
    SHORT             Remainder1;                      /*  PD00484   */
    SHORT             Remainder2;                      /*  PD00484   */
    SHORT             NoOfBytes;
    SHORT             CommandCount;
    USHORT            i;
    USHORT            Result;
    USHORT            MoveCommand;   /* The current logical command   */


    /******************************************************************/
    /* Check for trivial case.                                        */
    /******************************************************************/
    if ( CurrPosX == ReqdPosX )
        return (OK);

    /******************************************************************/
    /* Set up local pointers.                                         */
    /******************************************************************/
    PDBInst     = DCIData->DCIPdbInstance;
    PrinterType = PDBInst->PrinterData->PrinterType;
    pDDT        = &PDBInst->DDT;
    pFontData   = &DCIData->DCIFontData;

    /******************************************************************/
    /* Handle special case needed since the printers cannot use a     */
    /* move (e.g. backspace) which goes beyond the left margin.       */
    /*                                                                */
    /* If the printer head needs to move left to a position within    */
    /* one move (e.g. a space at 10 c.p.i.) of the left margin then   */
    /* because of the above restriction we cannot use the "normal"    */
    /* method below.  Therefore do a carriage return and              */
    /* reset the current x co-ord to 0.                               */
    /*                                                                */
    /* Spaces are always used at 10 cpi.  All the calculations and x  */
    /* coords (including the parameters ReqdPosX and CurrPosX) are    */
    /* in font coords - these are the same as the highest resolution  */
    /* available on the printer.                                      */
    /******************************************************************/
    if ( (ReqdPosX < CurrPosX) &&
         (ReqdPosX < pDDT->DDTRasterMode->HorzRoughFPelsL) )
    {
        if ( (Result = prdp_AddString(
                             EST_CARRIAGE_RETURN,
                             USE_GLOBAL_TABLE,
                             FNULL,
                             pMemory,
                             pMemoryIndex,
                             MemorySize,
                             DCIData )) != OK )
        {
            return (Result);
        }

        /**************************************************************/
        /* Using the XOffset here is correct even for landscape mode  */
        /* - see code which initiates this value.  Using CONV_X_VALUE */
        /* in landscape mode is also OK since the printers which have */
        /* device fonts in landscape mode have square resolutions     */
        /* only.                                                      */
        /**************************************************************/
        CurrPosX =
                - prdt_XformFontValue( PDBInst->FormXOffset,
                                       DEVICE_TO_FONT | CONV_X_VALUE,
                                       pFontData );

        /**********************************************************************/
        /*  PD00547: Reset the remainder.                                     */
        /**********************************************************************/
        DCIData->Remainder = 0;

        /**************************************************************/
        /* If the required x co-ord is also at the left margin then   */
        /* there is no more to do.                                    */
        /**************************************************************/
        if ( ReqdPosX == CurrPosX )
            return (OK);
    }


    /******************************************************************/
    /* Routine varies depending on direction we need to go.           */
    /******************************************************************/
    MoveRight = (ReqdPosX > CurrPosX);

    /******************************************************************/
    /* Calculate NoOfFontPels (i.e. pels in font coords) that the     */
    /* printer needs to make - this is an absolute value (i.e. its    */
    /* always positive.                                               */
    /******************************************************************/
    if ( MoveRight )
        NoOfFontPels = ReqdPosX - CurrPosX;
    else
        NoOfFontPels = CurrPosX - ReqdPosX;

    /******************************************************************/
    /* The methods used for the horizontal moves are as follows:      */
    /*                                                                */
    /*   DDT_MOVE_NO_STEP .. use spaces and backspaces                */
    /*       first to get near and then output raster graphics (all   */
    /*       background colour) to get the fine adjustment.           */
    /*                                                                */
    /*   DDT_MOVE_STEP_RIGHT_RAST .. use backspaces to move left or   */
    /*       use Esd d to move right (in units of 1/120") and then    */
    /*       use raster output (used on 23XX printers)                */
    /*                                                                */
    /*   DDT_MOVE_STEP_RIGHT .. use backspaces to move left and then  */
    /*       use Esc d to fine adjust or                              */
    /*       use Esd d to move right (in units of 1/120")             */
    /*                                                                */
    /*   DDT_MOVE_STEP_BOTH .. use Esc d/e to move right/left in      */
    /*       units of 1/120" and then use raster output (used on Q    */
    /*       drivers).                                                */
    /*                                                                */
    /*   DDT_MOVE_ABS_SCP .. use Set Cursor Position command - this   */
    /*       is done elsewhere and we should not be in this routine   */
    /*       if this is the method used.                              */
    /*                                                                */
    /* WARNING .. if these methods are changed, or added to, then     */
    /* prdp_NeedSpacesForMove must be altered to match.               */
    /******************************************************************/

    /******************************************************************/
    /* Work out the number of rough and fine moves to use - these     */
    /* are absolute values (i.e. they are always positive).  Note     */
    /* that the rounding is always down, not half rounding.  This is  */
    /* OK currently (18/10/90 SP) since HorzFineFPels is always 1.    */
    /******************************************************************/
    if ( MoveRight )
    {
        MoveCommand = DCT_ROUGH_MOVE_RIGHT;

        NoOfRoughMoves =
           (NoOfFontPels / pDDT->DDTRasterMode->HorzRoughFPelsR);

        NoOfFineMoves  =
           (NoOfFontPels -
               (NoOfRoughMoves * pDDT->DDTRasterMode->HorzRoughFPelsR)) /
                                        pDDT->DDTRasterMode->HorzFineFPels;

        /**********************************************************************/
        /* PD00547: Keep track of the leftover pels and add in an extra move  */
        /* every time we build up to one.                                     */
        /**********************************************************************/
        if ( (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT) ||
             ( (pDDT->DDTDriverType == DDT_IBM42XX_DRV) &&
               ( (PrinterType == IBM_4224_MONO) ||
                 (PrinterType == IBM_4224_COLOR) ) ) )
        {
            Remainder1 =
               (NoOfFontPels -
                  (NoOfRoughMoves * pDDT->DDTRasterMode->HorzRoughFPelsR)) %
                                           pDDT->DDTRasterMode->HorzFineFPels;

            Remainder2 = DCIData->Remainder + Remainder1;

            /******************************************************************/
            /*  Issue an extra rough move if we've got enough errors          */
            /*  accumulated.  (Rough move because for 24 wire printers        */
            /*  rough and fine moves are the same.)                           */
            /*                                                                */
            /*  PD00578: Issue an extra fine move for the 4224s. (Fine move   */
            /*  because rough moves are bigger that fine for these printers.) */
            /******************************************************************/
            if (Remainder2 >= pDDT->DDTRasterMode->HorzFineFPels)
            {
                if ( (pDDT->DDTDriverType == DDT_IBM42XX_DRV) &&
                     ( (PrinterType == IBM_4224_MONO) ||
                       (PrinterType == IBM_4224_COLOR) ) )
                    NoOfFineMoves++;
                else
                    NoOfRoughMoves++;

                DCIData->Remainder =
                     Remainder2 - pDDT->DDTRasterMode->HorzFineFPels;
            }
            else
            {
                DCIData->Remainder = Remainder2;
            }

        }
    }
    else
    {
        MoveCommand = DCT_ROUGH_MOVE_LEFT;

        NoOfRoughMoves = 1 +
           ((NoOfFontPels - 1)/ pDDT->DDTRasterMode->HorzRoughFPelsL);

        NoOfFineMoves  =
           ((NoOfRoughMoves * pDDT->DDTRasterMode->HorzRoughFPelsL) -
                                                         NoOfFontPels) /
                                        pDDT->DDTRasterMode->HorzFineFPels;


        /**********************************************************************/
        /* PD00547: Keep track of the leftover pels and add in an extra move  */
        /* every time we build up to one.                                     */
        /*                                                                    */
        /* PD00578 : Need to do it for the 4224s as well as 24 wire printers. */
        /**********************************************************************/
        if ( (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT) ||
             ( (pDDT->DDTDriverType == DDT_IBM42XX_DRV) &&
               ( (PrinterType == IBM_4224_MONO) ||
                 (PrinterType == IBM_4224_COLOR) ) ) )
        {
            Remainder1 =
               ((NoOfRoughMoves * pDDT->DDTRasterMode->HorzRoughFPelsL) -
                                                             NoOfFontPels) %
                                            pDDT->DDTRasterMode->HorzFineFPels;

            Remainder2 = DCIData->Remainder + Remainder1;

            /******************************************************************/
            /*  Issue an extra fine move if we've got enough errors           */
            /*  accumulated.                                                  */
            /******************************************************************/
            if (Remainder2 >= pDDT->DDTRasterMode->HorzFineFPels)
            {
                NoOfFineMoves++;
                DCIData->Remainder =
                    Remainder2 - pDDT->DDTRasterMode->HorzFineFPels;
            }
            else
            {
                DCIData->Remainder = Remainder2;
            }

        } /* ...if (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT) ... */
    }

    /******************************************************************/
    /* Add the the rough moves to the buffer - these will be either   */
    /* spaces/backspaces or Esc d/e commands.                         */
    /*                                                                */
    /* PD00484 : Add in check for new horizontal move type            */
    /******************************************************************/
    if ( NoOfRoughMoves != 0 )
    {
        if ( (pDDT->DDTHorizMoveType & DDT_MOVE_NO_STEP) ||
             ((pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT) &&
                                                         (!MoveRight)) ||
             ((pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT_RAST) &&
                                                         (!MoveRight)) )
        {
            /**********************************************************/
            /* Spaces or backspaces...                                */
            /**********************************************************/
            for ( i = 0; i < NoOfRoughMoves; i++ )
            {
                if ( (Result = prdp_AddString( MoveCommand,
                                     USE_PRINTER_TABLE,
                                     FNULL,
                                     pMemory,
                                     pMemoryIndex,
                                     MemorySize,
                                     DCIData )) != OK )
                {
                    return (Result);
                }
            }
        }
        else
        {
            if ( (Result = prdp_AddString( MoveCommand,
                                 USE_PRINTER_TABLE,
                                 (PBYTE)&NoOfRoughMoves,
                                 pMemory,
                                 pMemoryIndex,
                                 MemorySize,
                                 DCIData )) != OK )
            {
                return (Result);
            }
        }
    }

    if  ( NoOfFineMoves != 0 )
    {
       /***********************************************************************/
       /*  PD00484 : For 24 wire Pro's no adjustment to number of fine moves  */
       /*  is needed as we aren't doing raster graphics, so just add the      */
       /*  command.                                                           */
       /***********************************************************************/
        if (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT)
        {
            if ( (Result = prdp_AddString( DCT_FINE_MOVE_RIGHT,
                                           USE_PRINTER_TABLE,
                                           (PBYTE)&NoOfFineMoves,
                                           pMemory,
                                           pMemoryIndex,
                                           MemorySize,
                                           DCIData )) != OK )
            {
                return (Result);
            }
        }
        else
        {
            /******************************************************************/
            /*If we are moving right with raster output we need to add the    */
            /*vertical strips of background colour. Send out the expect raster*/
            /*command followed by a series of background bytes.               */
            /******************************************************************/
            /**************************************************************/
            /* The number of backgound bytes to send out will depend on   */
            /* VertLinePelsHiRes - i.e. the number of wires printer head  */
            /* uses (8 or 24).  The values for the low and high count     */
            /* bytes given to the raster output command will depend on    */
            /* the precise escape sequence used (Esc Z or Esc [ g).       */
            /*                                                            */
            /* WARNING: If the raster commands we use are changed the     */
            /* setting up of CommandCount will need to change to match.   */
            /**************************************************************/
            NoOfBytes = NoOfFineMoves *
                               (pDDT->DDTRasterMode->VertLinePelsHiRes / 8);

            CommandCount = NoOfBytes;

            if ( pDDT->DDTRasterMode->VertLinePelsHiRes == 24 )
                CommandCount += 1;                      /*  i.e. Esc [ g  */

            if ( (Result = prdp_AddString(
                                 DCT_FINE_MOVE_RIGHT,
                                 USE_PRINTER_TABLE,
                                 (PBYTE)&CommandCount,
                                 pMemory,
                                 pMemoryIndex,
                                 MemorySize,
                                 DCIData )) != OK )
            {
                return (Result);
            }

            /**************************************************************/
            /* Now send out the background colour.                        */
            /**************************************************************/
            if ( *pMemoryIndex + NoOfBytes > MemorySize )
            {
                if ( (Result = prdp_PrintMemory ( pMemory,
                                                  *pMemoryIndex,
                                                  DCIData) ) != OK )
                    return (Result);

                *pMemoryIndex  = 0;
            }

            prdu_memcpy( (PBYTE) (pMemory + *pMemoryIndex),
                         (PBYTE) prdd_Zeroes,
                         NoOfBytes );

            *pMemoryIndex += NoOfBytes;
        }
    }

    return (OK);
}
#undef TFUNC


/*CON3201
BOOL pascal prdp_NeedSpacesForMove ( NextPosX,
                                     CurrPosX,
                                     TextEntryPtr,
                                     DCIData )

SHORT           NextPosX;
SHORT           CurrPosX;
lpGTBEntry far *TextEntryPtr;
lpDCI           DCIData;
                             */

BOOL prdp_NeedSpacesForMove (SHORT           NextPosX,
                             SHORT           CurrPosX,
                             lpGTBEntry     *TextEntryPtr,
                             lpDCI           DCIData)

{
    /******************************************************************/
    /* Local Variables                                                */
    /******************************************************************/
    lpDDTType     pDDT;
    BOOL          NeedSpaces;
    USHORT        PrinterType;
    USHORT        DriverType;
    USHORT        PostDCTCmd;

    /******************************************************************/
    /* Set up initial bits and bobs - spaces are always at 10 cpi.    */
    /******************************************************************/
    pDDT = &DCIData->DCIPdbInstance->DDT;
    PrinterType = DCIData->DCIPdbInstance->PrinterType;
    DriverType = pDDT->DDTDriverType;

    /**************************************************************************/
    /*  PD00569 : Only set up PostDCTCmd for Nile/Tibers as                   */
    /*  DCIData->DCIPdbInstance->Fontlist[(*TextEntryPtr)->GTBInfo.Index      */
    /*  is not valid for card, download codepage, or download fonts.          */
    /**************************************************************************/
    if ( (DriverType == DDT_IBM42XX_DRV) &&
         (((PrinterType > IBM_4224_MONO) && (PrinterType < IBM_4226)) ||
          (PrinterType == IBM_2390_PS1) ) )
    {
        PostDCTCmd = DCIData->DCIPdbInstance->FontList[(*TextEntryPtr)->
                                        GTBInfo.Index]->PostDCTCmd;
    }

    /******************************************************************/
    /* We need to know whether spaces will be used in the move.       */
    /*                                                                */
    /* The methods used for the horizontal moves are as follows:      */
    /*                                                                */
    /*   DDT_MOVE_NO_STEP .. use spaces and backspaces                */
    /*       first to get near and then output raster graphics (all   */
    /*       background colour) to get the fine adjustment.           */
    /*                                                                */
    /*   DDT_MOVE_STEP_RIGHT_RAST .. use backspaces to move left or   */
    /*       use Esd d to move right (in units of 1/120") and then    */
    /*       use raster output (used on 23XX printers)                */
    /*                                                                */
    /*   DDT_MOVE_STEP_RIGHT .. use backspaces to move left and then  */
    /*       use Esc d to fine adjust or                              */
    /*       use Esd d to move right (in units of 1/120")             */
    /*                                                                */
    /*   DDT_MOVE_STEP_BOTH .. use Esc d/e to move right/left in      */
    /*       units of 1/120" and then use raster output (used on Q    */
    /*       drivers).                                                */
    /*                                                                */
    /*   DDT_MOVE_ABS_SCP .. use Set Cursor Position command - spaces */
    /*       are never required in this case.                         */
    /*                                                                */
    /* If the required position is within a space of the left margin  */
    /* then in fact backspaces will not used; however for the         */
    /* purposes of this function, which helps with a performance      */
    /* enhanmcement, that special case is ignored.  See               */
    /* prdp_AddHorizMoveString above for details.                     */
    /*                                                                */
    /******************************************************************/
    if ( (pDDT->DDTHorizMoveType & DDT_MOVE_ABS_SCP) ||
         (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_BOTH) )
    {
        NeedSpaces = FALSE;
    }
    else if ( (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT) ||
              (pDDT->DDTHorizMoveType & DDT_MOVE_STEP_RIGHT_RAST) ) /*PD00484*/
    {
        /**********************************************************************/
        /*  PD00537 : Activate Post DCT for Nile/Tiber                        */
        /**********************************************************************/
        if (( NextPosX >= CurrPosX ) &&
        ( !((DriverType == DDT_IBM42XX_DRV) &&
            ( ((PrinterType == IBM_NILE_9) || (PrinterType == IBM_TIBER_9)) &&
                                    ((PostDCTCmd == EST_NT_LQ) ||
                                    (PostDCTCmd == EST_SET_NT_DRAFT_HORZ_SP)))
             ||
             ( ((PrinterType == IBM_NILE_24) || (PrinterType == IBM_TIBER_24) ||
                (PrinterType == IBM_2390_PS1) ) &&
                                   (PostDCTCmd == EST_NT_LQ) )
             ||
             ( (PrinterType == IBM_EXECJET) &&
                                   (PostDCTCmd == EST_SET_FONT_GOTHIC_10) ) ) ) )
            NeedSpaces = FALSE;
        else
            NeedSpaces = TRUE;
    }
    else if ( pDDT->DDTHorizMoveType & DDT_MOVE_NO_STEP )
    {
        if ( (NextPosX >= CurrPosX) &&
             ((NextPosX - CurrPosX) < pDDT->DDTRasterMode->HorzRoughFPelsR) )
            NeedSpaces = FALSE;
        else
            NeedSpaces = TRUE;
    }

    return (NeedSpaces);

}






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_OutlineFontSizeString                             */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   PCHAR          StartPtr;       place to write to                 */
/*   FIXED          fxSize;         size to write                     */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/* For outline fonts, the Nominal Vertical and Horizontal Font Size   */
/* parameters to the FSC command (NVFS and NHFS) should be written    */
/* to the printer as ascii decimal strings of length 7 (xxxx.xx).     */
/*                                                                    */
/* This converts FIXED sizes into such a string.                      */
/**********************************************************************/
/*CON3201
VOID pascal prdp_OutlineFontSizeString( StartPtr,
                                        fxSize )

PCHAR          StartPtr;
FIXED          fxSize;
                    */

VOID prdp_OutlineFontSizeString(PCHAR          StartPtr,
                                FIXED          fxSize)

{
#define TFUNC "prdp_OutlineFontSizeString"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/

    /******************************************************************/
    /* Write the integer part.                                        */
    /******************************************************************/
    prdp_IntToAsciiDecimal ( (ULONG)HIUSHORT(fxSize),
                             4,
                             StartPtr );

    /******************************************************************/
    /* Write the decimal point.                                       */
    /******************************************************************/
    StartPtr[4] = '.';

    /******************************************************************/
    /* Write the fractional part.                                     */
    /*                                                                */
    /* LOUSHORT(fxSize) is an integer representing a number of        */
    /* 65536ths. We want an integer representing a number of 100ths,  */
    /* that gives an equivalent size. Multiply LOUSHORT(fxSize) by    */
    /* 100 and divide by 65536 to get this integer.                   */
    /******************************************************************/
    prdp_IntToAsciiDecimal ( (((ULONG)LOUSHORT(fxSize)*100L) / 0x10000),
                             2,
                             (PCHAR)&StartPtr[5] );
    return;
}
#undef TFUNC


/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdp_IntToAsciiDecimal                                 */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   LONG             Int;                 Int to convert (+ve)       */
/*   SHORT            NoDigits;            no of digits to write      */
/*   PCHAR            StartPtr;            where to write to          */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function writes a decimal ascii string, starting at         */
/* StartPtr and ending at StartPtr + NoDigits - 1, which represents   */
/* Int. There are leading 0s if necessary.                            */
/*                                                                    */
/* If Int is too big to fit, it is truncated.                         */
/**********************************************************************/
/*CON3201
VOID PASCAL prdp_IntToAsciiDecimal ( Int,
                                     NoDigits,
                                     StartPtr )

ULONG            Int;
SHORT            NoDigits;
PCHAR            StartPtr;
                             */

VOID prdp_IntToAsciiDecimal (ULONG            Int,
                             SHORT            NoDigits,
                             PCHAR            StartPtr)

{
#define TFUNC "prdp_IntToAsciiDecimal"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG               Power;          /* power of 10                */
    SHORT               i;              /* loop variable              */

    /******************************************************************/
    /* First set Power to 10 ^ NoDigits.                              */
    /******************************************************************/
    for (Power=1, i=NoDigits; i; Power *= 10, i--);

    /******************************************************************/
    /* If Int is too big, truncate it.                                */
    /******************************************************************/
    Int = Int % Power;

    /******************************************************************/
    /* Loop, writing the digits.                                      */
    /******************************************************************/
    for ( Power/=10; Power; StartPtr++, Power/=10)
    {
        *StartPtr = (CHAR)(Int/Power + '0');
        Int = Int % Power;
    }
    return;
}
#undef TFUNC
