/************************************************************/
/* Windows Write, Copyright 1985-1992 Microsoft Corporation */
/************************************************************/

/*--- Module not really used, just the idea behind FORMAT.ASM ---*/


#define NOCLIPBOARD
#define NOGDICAPMASKS
#define NOCTLMGR
#define NOVIRTUALKEYCODES
#define NOWINMESSAGES
#define NOWINSTYLES
#define NOKEYSTATE
#define NOSYSCOMMANDS
#define NORASTEROPS
#define NOSHOWWINDOW
#define NOCLIPBOARD
#define NOWINSTYLES
#define NOSYSMETRICS
#define NOMENUS
#define NOATOM
#define NOCREATESTRUCT
#define NODRAWTEXT
#define NOMB
#define NOMEMMGR
#define NOMETAFILE
#define NOWH
#define NOWINOFFSETS
#define NOWNDCLASS
#include <windows.h>
/* #include "wwsmall.h" */

#include "mw.h"
#include "cmddefs.h"
#include "fmtdefs.h"
#include "propdefs.h"
#include "ch.h"
#include "docdefs.h"
#include "ffdefs.h"
#include "filedefs.h"
#include "fkpdefs.h"
#include "dispdefs.h"
#include "scrndefs.h"
#include "macro.h"
#include "debug.h"
#include "fontdefs.h"
#include "str.h"
#include "wwdefs.h"
#ifdef DBCS
#include "dbcs.h"
#endif

#ifdef DFLI
#define Dfli(x) x  /* Enable debug-format-line info */
#else
#define Dfli(x)
#endif

#ifdef CASHMERE
#define                 cchSmcapMax     16
#endif /* CASHMERE */

static int              ichpFormat;

#ifdef CASHMERE
static CHAR             mptlcch[] = " .-_";
#endif /* CASHMERE */

extern int              docHelp;
extern struct FLI       vfli;
extern struct CHP       (**vhgchpFormat)[];
extern int              ichpMacFormat;
extern struct CHP       vchpAbs;
extern struct PAP       vpapAbs;
extern struct SEP       vsepAbs;
extern struct SEP       vsepPage;
extern struct CHP       vchpNormal;
extern struct DOD       (**hpdocdod)[];
extern typeCP           vcpLimSectCache;
extern typeCP           vcpFirstParaCache;
extern typeCP           vcpLimParaCache;
extern typeCP           vcpFetch;
extern int              vichFetch;
extern int              vccpFetch;
extern CHAR             *vpchFetch;
extern int              vcchFetch;
extern int              vftc;
extern int              ypSubSuper;
extern int              ypSubSuperPr;
extern HDC              vhMDC;
extern HDC              vhDCPrinter;
extern int              dxpLogInch;
extern int              dypLogInch;
extern int              dxaPrPage;
extern int              dyaPrPage;
extern int              dxpPrPage;
extern int              dypPrPage;
extern int              dypMax;
extern struct FMI       vfmiScreen, vfmiPrint;
extern int              vfOutOfMemory;
extern CHAR             vchDecimal;  /* "decimal point" character */
extern int              vzaTabDflt;  /* width of default tab */
#ifdef CASHMERE
extern int              vfVisiMode;
#endif /* CASHMERE */


/* F O R M A T  L I N E */
FormatLine(doc, cp, ichCp, cpMac, flm)
int doc;
typeCP cp;
int ichCp;
typeCP cpMac;
int flm;
    {
    /* Fills up vfli with a line of text */

    int near Justify(struct IFI *, unsigned, int);
    int near FGrowFormatHeap(void);
    int near FFirstIch(int);

    struct IFI ifi;
    struct TBD *ptbd;
    struct CHP chpLocal;
    int xpTab;

#ifdef CASHMERE
    int dypBefore;
#endif /* CASHMERE */

    int dypAscent;
    int dypDescent;
    int dypAscentMac;
    int dypDescentMac;
    unsigned xaLeft;
    unsigned xaRight;
    struct PAP *ppap;
    struct SEP *psep;
    int fFlmPrinting = flm & flmPrinting;
    int dxaFormat;
    int dyaFormat;
    int dxpFormat;
    int dypFormat;
    int ypSubSuperFormat;
    int fTruncated = false;     /* if the run was truncated */
    int ichpNRH;



#ifdef CASHMERE
    struct FNTB **hfntb;
    int fVisiMode;
#endif /* CASHMERE */

    /* Check for fli current */
    if (vfli.doc == doc && vfli.cpMin == cp && vfli.ichCpMin == ichCp &&
      vfli.flm == flm)
        {
        /* Just did this one */
        return;
        }

    Scribble(5, 'F');
    bltc(&vfli, 0, cwFLIBase);
    /* This means:
        vfli.fSplat = false;
        vfli.dcpDepend = 0;
        vfli.ichCpMac = 0;
        vfli.dypLine = 0;
        vfli.dypAfter = 0;
        vfli.dypFont = 0;
        vfli.dypBase = 0;
    */

    /* vfSplatNext = FALSE; No longer used. */

    /* Rest of format loads up cache with current data */
    vfli.doc = doc;
    vfli.cpMin = cp;
    vfli.ichCpMin = ichCp;
    vfli.flm = flm;

    if (cp > cpMac)
        {
        /* Space after the endmark.  Reset the cache because the footnotes come
        at the same cp in the footnote window */
        vfli.doc = docNil;
        vfli.cpMac = cp;
        vfli.rgdxp[0] = 0;

        /* Line after end mark is taller than screen */

#ifdef CASHMERE
        vfli.dypBase = vfli.dypFont = vfli.dypAfter = ((vfli.dypLine = dypMax)
          >> 1);
#else /* not CASHMERE */
        vfli.dypBase = vfli.dypFont = ((vfli.dypLine = dypMax) >> 1);
#endif /* not CASHMERE */

        Scribble(5, ' ');
        return;
        }

    /* Initialize run tables */
    ichpFormat = 0;

    /* Cache section and paragraph properties */

#ifdef CASHMERE
    hfntb = (**hpdocdod)[doc].hfntb;
    if (hfntb == 0 || cp < (**hfntb).rgfnd[0].cpFtn)
        {
        /* Normal text */
        CacheSect(doc, cp);
        }
    else
        {
        /* Footnote section properties come from the section of the footnote
        reference. */
        CacheSect(doc, CpRefFromFtn(doc, cp));
        }
#else /* not CASHMERE */
    CacheSect(doc, cp);
#endif /* not CASHMERE */

    psep = &vsepAbs;

    CachePara(doc, cp);
    ppap = &vpapAbs;

    /* Now we have:
        ppap    paragraph properties
        psep    division properties
    */

    if (ppap->fGraphics)
        {
        /* Format a picture paragraph in a special way (see picture.c) */
        FormatGraphics(doc, cp, ichCp, cpMac, flm);
        Scribble(5, ' ');
        return;
        }

    /* Assure we have a good memory DC for font stuff */
    ValidateMemoryDC();
    if (vhMDC == NULL || vhDCPrinter == NULL)
        {
        Scribble(5, ' ');
        return;
        }

#ifdef CASHMERE
    /* When printing, don't show visible characters */
    fVisiMode = vfVisiMode && !fFlmPrinting;
#endif /* CASHMERE */

    bltc(&ifi, 0, cwIFI);
    /* This means:
        ifi.ich = 0;
        ifi.ichPrev = 0;
        ifi.ichFetch = 0;
        ifi.cchSpace = 0;
        ifi.ichLeft = 0;
    */

    ifi.jc = jcTabLeft;
    ifi.fPrevSpace = true;

    /* Set up some variables that have different value depending on whether we
    are printing or not. */
    if (fFlmPrinting)
        {
        dxaFormat = dxaPrPage;
        dyaFormat = dyaPrPage;
        dxpFormat = dxpPrPage;
        dypFormat = dypPrPage;
        ypSubSuperFormat = ypSubSuperPr;
        }
    else
        {
        dxaFormat = dyaFormat = czaInch;
        dxpFormat = dxpLogInch;
        dypFormat = dypLogInch;
        ypSubSuperFormat = ypSubSuper;
        }

    /* Calculate line height and width measures.  Compute
        xaLeft          left indent 0 means at left margin
        xaRight         width of column measured from left margin (not from left
                        indent).
    */
    xaLeft = ppap->dxaLeft;

    /* If this is the first line of a paragraph, adjust xaLeft for the first
    line indent.  (Also, set dypBefore, since its handy.) */
    if (cp == vcpFirstParaCache)
        {
        xaLeft += ppap->dxaLeft1;

#ifdef CASHMERE
        dypBefore = MultDiv(ppap->dyaBefore, dypLogInch, czaInch);
#endif /* CASHMERE */

        }

#ifdef CASHMERE
    else
        {
        dypBefore = 0;
        }
#endif /* CASHMERE */

    /* Now, set xaRight (width measured in twips). */

#ifdef CASHMERE
    xaRight = (ppap->rhc ? vsepPage.xaMac - vsepPage.dxaGutter :
      psep->dxaText) - ppap->dxaRight;
#else /* not CASHMERE */
    xaRight = psep->dxaText - ppap->dxaRight;
#endif /* not CASHMERE */


    /* Do necessary checks on xaLeft and xaRight */
    if (xaRight > xaRightMax)
        {
        xaRight = xaRightMax;
        }
    if (xaLeft > xaRightMax)
        {
        xaLeft = xaRightMax;
        }
    if (xaLeft < 0)
        {
        xaLeft = 0;
        }
    if (xaRight < xaLeft)
        {
        xaRight = xaLeft + 1;
        }

    vfli.xpLeft = ifi.xp = ifi.xpLeft = MultDiv(xaLeft, dxpFormat, dxaFormat);
    vfli.xpMarg = ifi.xpRight = MultDiv(xaRight, dxpFormat, dxaFormat);
    ifi.xpPr = MultDiv(xaLeft, dxpPrPage, dxaPrPage);
    ifi.xpPrRight = MultDiv(xaRight, dxpPrPage, dxaPrPage);

    /* Get a pointer to the tab-stop table. */
    ptbd = ppap->rgtbd;

    /* Turn off justification. */
    SetTextJustification(fFlmPrinting ? vhDCPrinter : vhMDC, 0, 0);

    /* Initialize the line height information. */
    dypAscentMac = dypDescentMac = 0;

    /* To tell if there were any tabs */
    ifi.ichLeft = -1;

    /* Get the first run, and away we go... */
    FetchCp(doc, cp, ichCp, fcmBoth + fcmParseCaps);
    goto FirstCps;

    for ( ; ; )
        {
        int iichNew;
        int xpPrev;
        int dxp;
        int dxpPr;

        /* The number of characters to process (usually vcchFetch) */
        int cch;

        /* The number of characters in current run already used */
        int cchUsed;

        /* A pointer to the current list of characters (usually vpchFetch) */
        CHAR *pch;

#ifdef CASHMERE
        CHAR rgchSmcap[cchSmcapMax];
#endif /* CASHMERE */

        if (ifi.ichFetch == cch)
            {
            /* End of a run */
            int dich;
            BOOL fSizeChanged;

            if (ifi.ich >= ichMaxLine)
            /* End of run because of line length limit has been reached. */
                {
                goto DoBreak;
                }

            if (fTruncated)
                {
                cchUsed += cch;
                pch = vpchFetch + cchUsed;
                cch = vcchFetch - cchUsed;
                fTruncated = false;
                goto OldRun;    /* use the rest of the old run  */
                }

NullRun:
            FetchCp(docNil, cpNil, 0, fcmBoth + fcmParseCaps);
FirstCps:

            cchUsed = 0;

            /* Continue fetching runs until a run is found with a nonzero
            length. */
            if ((cch = vcchFetch) == 0)
                {
                goto NullRun;
                }

            pch = vpchFetch;
            if (vcpFetch >= cpMac || (!fFlmPrinting && *pch == chSect))
                {
#ifdef SYSENDMARK
                /* Force end mark and section mark to be in standard system
                font. */
                blt(&vchpNormal, &vchpAbs, cwCHP);
                vchpAbs.ftc = ftcSystem;
                vchpAbs.ftcXtra = 0;
                vchpAbs.hps = hpsDefault;
#else
#ifdef REVIEW
                /* The following comment is absolutely misleading!  Ftc==0
                   doesn't give you a system font.  It gives you the first
                   entry in the font table. */
#endif /* REVIEW */
                /* Force end mark and section mark to be in standard system
                font. */
                blt(&vchpNormal, &vchpAbs, cwCHP);
                vchpAbs.ftc = 0;
                vchpAbs.ftcXtra = 0;
                vchpAbs.hps = hpsDefault;
#endif /* if-else-def KANJI */
                }

#ifdef CASHMERE
            /* Adjust the size of the font for "small capitals". */
            if (vchpAbs.csm == csmSmallCaps)
                {
                vchpAbs.hps = HpsAlter(vchpAbs.hps, -1);
                }
#endif /* CASHMERE */

            /* Now we have:
                ichpFormat     index into gchp table
                vcpFetch        first cp of current run
                vfli.cpMin      first cp of line
                ifi.ich         ???
            */

           /* since LoadFont could change vchpAbs, and we don't want
              that to happen, we copy vchpAbs into vchpLocal and use
              vchpLocal in place of vchpAbs hereafter. Note that vchpAbs
              is intentionally used above for handling the endmark. */

                blt(&vchpAbs, &chpLocal, cwCHP);


            if (fFlmPrinting)
                {
                LoadFont(doc, &chpLocal, mdFontPrint);
                dypAscent = vfmiPrint.dypAscent + vfmiPrint.dypLeading;
                dypDescent = vfmiPrint.dypDescent;
                }
            else
                {
                LoadFont(doc, &chpLocal, mdFontJam);
                dypAscent = vfmiScreen.dypAscent + vfmiScreen.dypLeading;
                dypDescent = vfmiScreen.dypDescent;
                }

#ifdef ENABLE   /* BRYANL 8/27/87: New philosophy for handling
                   font selection failures is: font selection
                   ALWAYS succeeds. This prevents FormatLine
                   returns that do not advance. */
            /* Bail out if there is a memory failure. */
            if (vfOutOfMemory)
                {
                goto DoBreak;
                }
#endif  /* ENABLE */

            /* Floating line size algorithm */
            if (chpLocal.hpsPos != 0)
                {
                /* Modify font for subscript/superscript */
                if (chpLocal.hpsPos < hpsNegMin)
                    {
                    dypAscent += ypSubSuperFormat;
                    }
                else
                    {
                    dypDescent += ypSubSuperFormat;
                    }
                }

            /* Update the maximum ascent and descent of the line. */
            fSizeChanged = FALSE;
            if (dypDescentMac < dypDescent)
                {
                dypDescentMac = dypDescent;
                fSizeChanged = TRUE;
                }
            if (dypAscentMac < dypAscent)
                {
                dypAscentMac = dypAscent;
                fSizeChanged = TRUE;
                }


            if (fSizeChanged)
                {

#ifdef AUTO_SPACING
                /* This is the original Mac Word code that assumed line spacing
                of 0 in a PAP meant auto line spacing.  PC Word defaults to 1
                line invalidating this assumption. */
                if (ppap->dyaLine == 0)
                    {

#ifdef CASHMERE
                    ifi.dypLineSize = dypDescentMac + dypAscentMac + dypBefore;
#else /* not CASHMERE */
                    ifi.dypLineSize = dypDescentMac + dypAscentMac;
#endif /* not CASHMERE */

                    }
                else
                    {

#ifdef CASHMERE
                    ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
                      dyaFormat) + dypBefore, dypBefore + 1);
#else /* not CASHMERE */
                    ifi.dypLineSize = imax(MultDiv(ppap->dyaLine, dypFormat,
                      dyaFormat), 1);
#endif /* not CASHMERE */

                    }
#else /* not AUTO_SPACING */
                /* This code forces auto line spacing except in the case where
                the user specifies a line spacing greater than the auto line
                spacing. */
                    {
#ifdef CASHMERE
                    register int dypAuto = dypDescentMac + dypAscentMac +
                      dypBefore;
#else /* not CASHMERE */
                    register int dypAuto = dypDescentMac + dypAscentMac;
#endif /* not CASHMERE */

                    if (ppap->dyaLine > czaLine)
                        {

#ifdef CASHMERE
                        register int dypUser = imax(MultDiv(ppap->dyaLine,
                          dypFormat, dyaFormat) + dypBefore, dypBefore + 1);
#else /* not CASHMERE */
                        register int dypUser = imax(MultDiv(ppap->dyaLine,
                          dypFormat, dyaFormat), 1);
#endif /* not CASHMERE */

                        ifi.dypLineSize = max(dypAuto, dypUser);
                        }
                    else
                        {
                        ifi.dypLineSize = dypAuto;
                        }
                    }
#endif /* not AUTO_SPACING */

                }

OldRun:
            /* Calculate length of the run but no greater than 256 */
            iichNew = (int)(vcpFetch - vfli.cpMin);
            if (iichNew >= ichMaxLine)
                {
                iichNew = ichMaxLine - 1;
                }
            dich = iichNew - ifi.ich;

            /* Ensure that all tab and non-required hyphen characters start at
            beginning of run */
            if (ichpFormat <= 0  || dich > 0 || CchDiffer(&chpLocal,
              &(**vhgchpFormat)[ichpFormat - 1], cchCHPUsed) != 0 || *pch ==
              chTab || *pch == chNRHFile)
                {
#ifdef DFLI
                if (*pch == chNRHFile)
                    CommSz("CHNRHFILE at beginning of run");
#endif                
                if (ichpFormat != ichpMacFormat || FGrowFormatHeap())
                    {
                    register struct CHP *pchp = &(**vhgchpFormat)[ichpFormat -
                      1];

                    if (ichpFormat > 0)
                        {
                        pchp->cchRun = ifi.ich - ifi.ichPrev;
                        pchp->ichRun = ifi.ichPrev;
                        }
                    blt(&chpLocal, ++pchp, cwCHP);

#ifdef ENABLE   /* font codes */
                    pchp->ftc = vftc;
                    pchp->ftcXtra = (vftc & 0x01c0) >> 6;
                    pchp->hps = vhps;
#endif /* ENABLE */

                    pchp->cchRun = ichMaxLine;
                    if (dich <= 0)
                        {
                        pchp->ichRun = ifi.ich;
                        }
                    else
                        {
                        /* Q&D insert */
                        bltc(&vfli.rgdxp[ifi.ich], 0, dich);
                        bltbc(&vfli.rgch[ifi.ich], 0, dich);
                        pchp->ichRun = ifi.ich = iichNew;
                        }
                    ifi.ichPrev = ifi.ich;
                    ichpFormat++;
                    }
                }

            if (vcpFetch >= cpMac)
                {
                /* End of doc reached */
                if (!ifi.fPrevSpace || vcpFetch == cp)
                    {
                    vfli.ichReal = ifi.ich;
                    vfli.xpReal = ifi.xpReal = ifi.xp;
                    }
                if (!fFlmPrinting && (doc != docHelp))
                    {
                    vfli.rgch[ifi.ich] = chEMark;
                    vfli.xpReal += (vfli.rgdxp[ifi.ich++] = DxpFromCh(chEMark,
                      false));
                    }
                vfli.dypLine = ifi.dypLineSize;
                vfli.dypBase = dypDescentMac;
                vfli.dypFont = dypAscentMac + dypDescentMac;
                vfli.ichMac = vfli.ichReal = ifi.ich;
                vfli.cpMac = cpMac + 1;
                goto JustEol;   /* dcpDepend == 0 */
                }

            /* Here we have ifi.ich, cch */
            if (ifi.ich + cch > ichMaxLine)
            /* If this run would put the line over 255, truncate it and set a
            flag. */
                  {
                  cch = ichMaxLine - ifi.ich;
                  fTruncated = true;
                  }

            ifi.ichFetch = 0;

#ifdef CASHMERE
            if (chpLocal.csm != csmNormal)
                {
                int ich;
                CHAR *pchT = &rgchSmcap[0];

                /* We can handle only a run of cchSmcapMax small capital
                characters.  If the run is larger then truncate. */
                if (cch > cchSmcapMax)
                    {
                    cch = cchSmcapMax;
                    fTruncated = true;
                    }

                /* Raise the case of the characters. */
                for (ich = 0 ; ich < cch ; ich++)
                    {
                    *pchT++ = ChUpper(*pch++);
                    }
                pch = &rgchSmcap[0];
                }
#endif /* CASHMERE */

            /* Do "special" characters here */
            if (chpLocal.fSpecial)
                {
                if (!FFormatSpecials(&ifi, flm, vsepAbs.nfcPgn))
                    {
                    if (ifi.chBreak == 0)   /* No breaks in this line */
                        {
                        goto Unbroken;
                        }
                    else
                        {
                        vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
                        goto JustBreak;
                        }
                    }
                }

            continue;
            }

        /* End of new run treatment.  We are back in the "for every character"
        section. */
            {
            register int ch = pch[ifi.ichFetch++];

NormChar:

            if (ch == chSpace)
                {
                /* Speed kludge for spaces */
                ifi.xp += (vfli.rgdxp[ifi.ich] = dxp =
                    fFlmPrinting ? vfmiPrint.dxpSpace : vfmiScreen.dxpSpace);
                ifi.xpPr += (dxpPr = vfmiPrint.dxpSpace);
                vfli.rgch[ifi.ich++] = chSpace;
#ifdef DFLI                
                {
                char rgch[100];
                
                wsprintf(rgch,"  chSpace     , xp==%d/%d, xpPr==%d/%d", 
                    ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
                CommSz(rgch);
                }
#endif
                goto BreakOppr;
                }

            /* If the printer width is not in the printer width table, then get
            it. */
            if (ch < chFmiMin || ch >= chFmiMax || (dxpPr =
              vfmiPrint.mpchdxp[ch]) == dxpNil)
                {
                dxpPr = DxpFromCh(ch, TRUE);
                }

            if (fFlmPrinting)
                {
                /* If we are printing, then there is no need to bother with the
                screen width. */
                dxp = dxpPr;
                }
            else if (ch < chFmiMin || ch >= chFmiMax ||
                (dxp = vfmiScreen.mpchdxp[ch]) == dxpNil)
                    dxp = DxpFromCh(ch, FALSE);

#ifdef DBCS
            if (IsDBCSLeadByte(ch))
                {
                ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
                ifi.xpPr += dxpPr;
                vfli.rgch[ifi.ich++] = ch;
                ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
                ifi.xpPr += dxpPr;
                vfli.rgch[ifi.ich++] = pch[ifi.ichFetch++];
                }
            else
                {
                ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
                ifi.xpPr += dxpPr;
                vfli.rgch[ifi.ich++] = ch;
                }
#else
            ifi.xp += (vfli.rgdxp[ifi.ich] = dxp);
            ifi.xpPr += dxpPr;
            vfli.rgch[ifi.ich++] = ch;
#endif

             /* special case "normal characters" above hyphen */

            if (ch > chHyphen)
                goto DefaultCh;

            switch (ch)
                {

#ifdef CRLF
                case chReturn:
                    /* Undo damage */
                    ifi.ich--;
                    ifi.xp -= dxp;
                    ifi.xpPr -= dxpPr;
                    continue;
#endif /* CRLF */

                case chNRHFile:
                    /* Undo damage */
                    ifi.ich--;
                    ifi.xp -= dxp;
                    ifi.xpPr -= dxpPr;

                    ichpNRH = ichpFormat - 1;
#ifdef DFLI
                    {
                    char rgch[100];
                    
                    wsprintf(rgch,"  OptHyph: width==%d, xpPr==%d/%d\n\r", 
                        DxpFromCh(chHyphen,true), ifi.xpPr,ifi.xpPrRight);
                    CommSz(rgch);
                    }
#endif
                    if (ifi.xpPr + DxpFromCh(chHyphen, true) > ifi.xpPrRight)
                        {
                        /* Won't fit, force a break */
                        goto DoBreak;
                        }

#ifdef CASHMERE
                    else if (fVisiMode)
                        {
                        /* Treat just like a normal hyphen */
                        ch = chHyphen;
                        goto NormChar;
                        }
#endif /* CASHMERE */

                    xpPrev = ifi.xp;
                    vfli.rgch[ifi.ich] = chTab;
                    goto Tab0;

                case chSect:
                    /* Undo damage */
                    ifi.ich--;
                    ifi.xp -= dxp;
                    ifi.xpPr -= dxpPr;

                    vfli.dypFont = vfli.dypLine = (dypAscentMac + (vfli.dypBase
                      = dypDescentMac));
                    vfli.cpMac = vcpFetch + ifi.ichFetch;
                    if (FFirstIch(ifi.ich))
                        {
                        /* Beginning of line; return a splat */
                        vfli.fSplat = true;

                        if (!fFlmPrinting)
                            {

#ifdef CASHMERE
                            int chT = vfli.cpMac == vcpLimSectCache ?
                              chSectSplat : chSplat;
#else /* not CASHMERE */
                            int chT = chSplat;
#endif /* not CASHMERE */

                            int dxpCh = DxpFromCh(chT, false);

                            /* Set the width of the splat to be about 8.5" */
                            int cch = min((dxpLogInch * 17 / 2) / dxpCh,
                              ichMaxLine - 32);

                            bltbc(&vfli.rgch[ifi.ich], chT, cch);
                            bltc(&vfli.rgdxp[ifi.ich], dxpCh, cch);
                            vfli.ichMac = cch + ifi.ich;
                            vfli.xpReal = LOWORD(GetTextExtent(vhMDC,
                              (LPSTR)vfli.rgch, cch));
                            vfli.xpLeft = 0;
                            }
                        else
                            {
                            vfli.ichMac = 0;
                            }
                        goto EndFormat;
                        }

                    /* The section character is in the middle of a line, the
                    line will terminate in front of the character. */
                    /* vfSplatNext = TRUE; No longer used*/
                    vfli.cpMac += cchUsed - 1;
                    vfli.dcpDepend = 1;
                    if (!ifi.fPrevSpace)
                        {
                        ifi.cBreak = ifi.cchSpace;
                        vfli.ichReal = ifi.ich;
                        vfli.xpReal = ifi.xpReal = ifi.xp;
                        }
                    vfli.ichMac = ifi.ich;
                    vfli.dypLine = ifi.dypLineSize;
                    goto JustBreak;

                case chTab:
                    /* Undo damage */
                    ifi.ich--;
                    ifi.xp -= dxp;
                    ifi.xpPr -= dxpPr;

                    if (ifi.xpPr < ifi.xpPrRight)
                        {
                        register struct CHP *pchp;
                        unsigned xaPr;
                        unsigned xaTab;

                        if (!ifi.fPrevSpace)
                            {
                            /* Remember number of spaces to left and number of
                            real chars in line for justification */
                            ifi.cBreak = ifi.cchSpace;
                            vfli.ichReal = ifi.ich;
                            ifi.xpReal =  ifi.xp;
                            }

                        if (ifi.jc != jcTabLeft)
                            {
                            Justify(&ifi, xpTab, flm);
                            }
                        xpPrev = ifi.xp;

                        /* Now get info about this tab */
                        xaPr = MultDiv(ifi.xpPr, dxaPrPage, dxpPrPage);
                        while ((xaTab = ptbd->dxa) != 0)
                            {
                            if (xaTab > xaRight)
                                {
                                /* Don't let tabs extend past right margin. */
                                xaTab = xaRight;
                                }

                            if (xaTab >= xaPr)
                                {
                                /* Use tab stop information */

#ifdef CASHMERE
                                ifi.tlc = ptbd->tlc;
#endif /* CASHMERE */

                                ifi.jc = jcTabMin + (ptbd++)->jc;

#ifdef ENABLE /* we do the mapping in HgtbdCreate */
                                if (ifi.jc != jcTabDecimal)
                                    {
                                    ifi.jc = jcTabLeft;
                                    }
#endif
                                goto TabFound;
                                }
                            ptbd++;
                            }

                        /* Out of set tabs; go to next nth column */
                        xaTab = (xaPr / (vzaTabDflt) + 1) * (vzaTabDflt);

#ifdef CASHMERE
                        ifi.tlc = tlcWhite;
#endif /* CASHMERE */

                        ifi.jc = jcTabLeft;

TabFound:
                        xpTab = imax(MultDiv(xaTab, dxpFormat, dxaFormat),
                          ifi.xp);

                        /* Do left-justified tabs immediately */
                        if (ifi.jc == jcTabLeft)
                            {
                            ifi.xp = xpTab;
                            ifi.xpPr = MultDiv(xaTab, dxpPrPage, dxaPrPage);
                            }
                        ifi.xpLeft = ifi.xp;
                        ifi.ichLeft = ifi.ich;
                        ifi.cchSpace = 0;
                        ifi.chBreak = 0;
Tab0:
                        ifi.fPrevSpace = false;
                        vfli.ichMac = ifi.ich;
                        vfli.xpReal = ifi.xp;
                        vfli.dypLine = ifi.dypLineSize;
                        vfli.dypBase = dypDescentMac;
                        vfli.dypFont = dypAscentMac + dypDescentMac;

                        if (ifi.ichFetch != 1 && (ichpFormat != ichpMacFormat
                          || FGrowFormatHeap()))
                            {
                            /* Probably in real trouble if FGrowFormatHeap fails
                            at this point */
                            pchp = &(**vhgchpFormat)[ichpFormat - 1];
                            if (ichpFormat > 0)
                                {
                                /* Finish off previous run */
                                pchp->ichRun = ifi.ichPrev;
                                pchp->cchRun = ifi.ich - ifi.ichPrev;
                                }

                            blt(&chpLocal, ++pchp, cwCHP);
                            ichpFormat++;
                            }
                        else
                            {
                            pchp = &(**vhgchpFormat)[ichpFormat - 1];
                            }
                        pchp->ichRun = ifi.ich;
                        pchp->cchRun = ichMaxLine;

#ifdef CASHMERE
                        pchp->chLeader = mptlcch[ifi.tlc];
#endif /* CASHMERE */

                        vfli.rgdxp[ifi.ichPrev = ifi.ich++] = ifi.xp - xpPrev;

                        if (ch != chTab)
                            {
                            /* This character is a non-required hyphen. */
                            Dfli(CommSz("ch is really OptHyph "));
                            goto BreakOppr;
                            }

                        continue;
                        }
                    else
                        {
                        ch = chNBSFile;
                        goto NormChar;
                        }

                case chHyphen:
                    if (ifi.xpPr > ifi.xpPrRight)
                        {
                        goto DoBreak;
                        }

BreakOppr:
                Dfli(CommSz(" BKOPPR\n\r"));
                /*    this case never used in switch - always goto here */
                /* case chSpace:  */
                    if (ifi.ich >= ichMaxLine)
                        {
                        Dfli(CommSzNum("  Unbroken, ich>ichMaxLine\n\r"));
                        goto Unbroken;
                        }

                case chEol:
                case chNewLine:
                    ifi.chBreak = ch;
                    vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch;
                    vfli.xpReal = ifi.xp;
                    vfli.ichMac = ifi.ich;
                    vfli.dypLine = ifi.dypLineSize;
                    vfli.dypFont = dypAscentMac + (vfli.dypBase =
                      dypDescentMac);
                    Dfli(CommSzNumNum("    vfli.xpReal, ichMac ",vfli.xpReal,vfli.ichMac));


                    if (ch == chHyphen || ch == chNRHFile)
                        {
                        Dfli(CommSz("    chHyph/OptHyph catch \n\r"));
                        ifi.cBreak = ifi.cchSpace;
                        vfli.ichReal = ifi.ich;
                        vfli.xpReal = ifi.xpReal = ifi.xp;
                        }
                    else
                        {
                        if (!ifi.fPrevSpace)
                            {
                            Dfli(CommSz("!fPrevSpace \n\r"));
                            ifi.cBreak = ifi.cchSpace;
                            vfli.ichReal = ifi.ich - 1;
                            ifi.xpReal = (vfli.xpReal = ifi.xp) - dxp;
                            }
                        if (ch == chEol || ch == chNewLine)
                            {

#ifdef CASHMERE
                            if (hfntb != 0 && vfli.cpMac ==
                              (**hfntb).rgfnd[0].cpFtn)
                                {
                                /* End of footnote */
                                if (!fFlmPrinting)
                                    {
                                    vfli.rgch[ifi.ich - 1] = chEMark;
                                    vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
                                      DxpFromCh(chEMark, false)) - dxp;
                                    vfli.ichReal++;     /* show this guy */
                                    }
                                }
                            else
#endif /* CASHMERE */
                                {

#ifdef CASHMERE
                                int chT = fVisiMode ? ChVisible(ch) : chSpace;
#else /* not CASHMERE */
                                int chT = chSpace;
#endif /* not CASHMERE */

                                int dxpNew = DxpFromCh(chT, fFlmPrinting);

                                vfli.rgch[ifi.ich - 1] = chT;
                                vfli.rgdxp[ifi.ich - 1] = dxpNew;

                                vfli.xpReal += (vfli.rgdxp[ifi.ich - 1] =
                                    dxpNew) - dxp;


                                if (!ifi.fPrevSpace)
                                    {
                                    vfli.xpReal += dxpNew - dxp;
#ifdef CASHMERE
                                    vfli.ichReal =
                                         fVisiMode ? ifi.ich : ifi.ich - 1;
#else /* not CASHMERE */
                                    vfli.ichReal = ifi.ich - 1;
#endif /* not CASHMERE */
                                    }
                                }


                            if (ch == chEol)
                                {
JustEol:
                                if (fFlmPrinting)
                                    {
                                    vfli.ichMac = vfli.ichReal;
                                    }
                                if (ifi.jc != jcTabLeft)
                                    {
                                    /* Handle last tab's text */
                                    Justify(&ifi, xpTab, flm);
                                    }
                                else if ((ifi.jc = ppap->jc) != jcBoth &&
                                  ifi.jc != jcLeft)
                                    {
                                    /* Do line justification */
                                    Justify(&ifi, ifi.xpRight, flm);
                                    }
                                vfli.xpRight = ifi.xpRight;
                                goto EndFormat;
                                }
                            else
                                {
                                /* Handle a line break */
                                goto JustBreak;
                                }
                            }
                        ++ifi.cchSpace;
                        ifi.fPrevSpace = true;
                        }
                    break;

DefaultCh:

                default:

#ifdef DFLI                    
                    {
                    char rgch[100];
                    wsprintf(rgch,"  DefaultCh: %c, xp==%d/%d, xpPr==%d/%d\n\r", 
                        ch, ifi.xp, ifi.xpRight, ifi.xpPr, ifi.xpPrRight);
                    CommSz(rgch);
                    }
#endif /* ifdef DFLI */
                    
                    if (ifi.xpPr > ifi.xpPrRight)
DoBreak:
                        {
                        Dfli(CommSz("    BREAK!\n\r"));
                        if (ifi.chBreak == 0)
Unbroken:
                            {
                            /* Admit first character to the line, even if margin
                            is crossed.  First character at ifi.ich - 1 may be
                            preceded by 0 width characters. */
#ifdef DBCS
                            if (IsDBCSLeadByte(ch))
                                {
                                if (FFirstIch(ifi.ich-2) && ifi.ich<ichMaxLine)
                                    goto PChar;
                                vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-2;
                                vfli.ichReal = vfli.ichMac = ifi.ich - 2;
                                vfli.dypLine = ifi.dypLineSize;
                                vfli.dypFont = dypAscentMac + (vfli.dypBase =
                                  dypDescentMac);
                                vfli.dcpDepend = 1;
                                vfli.xpReal = ifi.xpReal = ifi.xp - (dxp * 2);
                                }
                            else
                                {
                                if (FFirstIch(ifi.ich-1) && ifi.ich<ichMaxLine)
                                    goto PChar;
                                vfli.cpMac = vcpFetch+cchUsed+ifi.ichFetch-1;
                                vfli.ichReal = vfli.ichMac = ifi.ich - 1;
                                vfli.dypLine = ifi.dypLineSize;
                                vfli.dypFont = dypAscentMac + (vfli.dypBase =
                                  dypDescentMac);
                                vfli.dcpDepend = 1;
                                vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
                                }
#else
                            if (FFirstIch(ifi.ich - 1) && ifi.ich < ichMaxLine)
                                {
                                goto PChar;
                                }
                            vfli.cpMac = vcpFetch + cchUsed + ifi.ichFetch - 1;
                            vfli.ichReal = vfli.ichMac = ifi.ich - 1;
                            vfli.dypLine = ifi.dypLineSize;
                            vfli.dypFont = dypAscentMac + (vfli.dypBase =
                              dypDescentMac);
                            vfli.dcpDepend = 1;
                            vfli.xpReal = ifi.xpReal = ifi.xp - dxp;
#endif
                            goto DoJustify;
                            }

                        vfli.dcpDepend = vcpFetch + ifi.ichFetch - vfli.cpMac;
JustBreak:
                        if (ifi.chBreak == chNRHFile)
                            {
                            /* Append a non-required hyphen to the end of the
                            line. (Replace zero length tab previously
                            inserted)  */

                            Dfli(CommSz("    Breaking line at OptHyphen\n\r"));
                            ifi.xpReal += (vfli.rgdxp[vfli.ichReal - 1] =
                              DxpFromCh(chHyphen, fFlmPrinting));
                            vfli.xpRight = vfli.xpReal = ifi.xpReal;
                            vfli.rgch[vfli.ichReal - 1] = chHyphen;
                            vfli.ichMac = vfli.ichReal;
                            if (ichpNRH < ichpFormat - 1)
                                {
                                register struct CHP *pchp =
                                  &(**vhgchpFormat)[ichpNRH];

                                pchp->cchRun++;
                                if (pchp->ichRun >= vfli.ichMac)
                                    {
                                    pchp->ichRun = vfli.ichMac - 1;
                                    }
                                }
                            }

                        if (fFlmPrinting)
                            {
                            vfli.ichMac = vfli.ichReal;
                            }
                        if (ifi.jc != jcTabLeft)
                            {
                            Justify(&ifi, xpTab, flm);
                            }
                        else
                            {
DoJustify:
                            if ((ifi.jc = ppap->jc) != jcLeft)
                                {
                                Dfli(CommSzNum("    DoJustify: xpRight ",ifi.xpRight));
                                Justify(&ifi, ifi.xpRight, flm);
                                }
                            }
                        vfli.xpRight = ifi.xpRight;
EndFormat:
                        vfli.ichLastTab = ifi.ichLeft;

#ifdef CASHMERE
                        if (vfli.cpMac == vcpLimParaCache)
                            {
                            vfli.dypAfter = vpapAbs.dyaAfter / DyaPerPixFormat;
                            vfli.dypLine += vfli.dypAfter;
                            vfli.dypBase += vfli.dypAfter;
                            }
#endif /* CASHMERE */

                        Scribble(5, ' ');
                        return;
                        }
                    else
                        {
PChar:
                        /* A printing character */
                        ifi.fPrevSpace = false;
                        }
                    break;

                }       /* Switch */
            }
        }       /* for ( ; ; ) */

    Scribble(5, ' ');
    }


/* J U S T I F Y */
near Justify(pifi, xpTab, flm)
struct IFI *pifi;
unsigned xpTab;
int flm;
    {
    int dxp;
    int ichT;
    int xpLeft;


    xpLeft = pifi->xpLeft;
    switch (pifi->jc)
        {
        CHAR *pch;
        unsigned *pdxp;

#ifdef CASHMERE
        case jcTabLeft:
        case jcLeft:
            return;

        case jcTabRight:
            dxp = xpTab - pifi->xpReal;
            break;

        case jcTabCenter:
            dxp = (xpTab - xpLeft) - ((pifi->xpReal - xpLeft + 1) >> 1);
            break;
#endif /* CASHMERE */

        case jcTabDecimal:
            dxp = xpTab - xpLeft;
            for (ichT = pifi->ichLeft + 1; ichT < vfli.ichReal &&
              vfli.rgch[ichT] != vchDecimal; ichT++)
                {
                dxp -= vfli.rgdxp[ichT];
                }
            break;

        case jcCenter:
            if ((dxp = xpTab - pifi->xpReal) <= 0)
                {
                return;
                }
            dxp = dxp >> 1;
            break;

        case jcRight:
            dxp = xpTab - pifi->xpReal;
            break;

        case jcBoth:
            if (pifi->cBreak == 0)
                {
                /* Ragged edge forced */
                return;
                }

            if ((dxp = xpTab - pifi->xpReal) <= 0)
                {
                /* There is nothing to do. */
                return;
                }

            pifi->xp += dxp;
            vfli.xpReal += dxp;
            vfli.dxpExtra = dxp / pifi->cBreak;

            /* Rounding becomes a non-existant issue due to brilliant
            re-thinking.
                "What a piece of work is man
                How noble in reason
                In form and movement,
                how abject and admirable..."

                        Bill "Shake" Spear [describing Sand Word] */
                {
                register CHAR *pch = &vfli.rgch[vfli.ichReal];
                register int *pdxp = &vfli.rgdxp[vfli.ichReal];
                int dxpT = dxp;
                int cBreak = pifi->cBreak;
                int cxpQuotient = (dxpT / cBreak) + 1;
                int cWideSpaces = dxpT % cBreak;

                vfli.fAdjSpace = fTrue;

                for ( ; ; )
                    {
                    /* Widen blanks */
                    --pch;
                    --pdxp;
                    if (*pch == chSpace)
                        {
                        if (cWideSpaces-- == 0)
                            {
                            int *pdxpT = pdxp + 1;

                            while (*pdxpT == 0)
                                {
                                pdxpT++;
                                }
                            vfli.ichFirstWide = pdxpT - vfli.rgdxp;
                            cxpQuotient--;
                            }
                        *pdxp += cxpQuotient;
                        if ((dxpT -= cxpQuotient) <= 0)
                            {
                            if (pifi->cBreak > 1)
                                {
                                int *pdxpT = pdxp + 1;

                                while (*pdxpT == 0)
                                    {
                                    pdxpT++;
                                    }
                                vfli.ichFirstWide = pdxpT - vfli.rgdxp;
                                }
                            return;
                            }
                        pifi->cBreak--;
                        }
                    }
                }
        }       /* Switch */

    if (dxp <= 0)
        {
        /* Nothing to do */
        return;
        }

    pifi->xp += dxp;

    if (flm & flmPrinting)
        {
        pifi->xpPr += dxp;
        }
    else
        {
        /* This statememt might introduce rounding errors in pifi->xpPr, but
        with luck, they will be small. */
        pifi->xpPr += MultDiv(MultDiv(dxp, czaInch, dxpLogInch), dxpPrPage,
          dxaPrPage);
        }

    if (pifi->ichLeft < 0)
        {
        /* Normal justification */
        vfli.xpLeft += dxp;
        }
    else
        {
        /* Tab justification */
        vfli.rgdxp[pifi->ichLeft] += dxp;
        }
    vfli.xpReal += dxp;
    }


/* F  G R O W  F O R M A T  H E A P */
int near FGrowFormatHeap()
    {
    /* Grow vhgchpFormat by 20% */
    int cchpIncr = ichpMacFormat / 5 + 1;

#ifdef WINHEAP
    if (!LocalReAlloc((HANDLE)vhgchpFormat, (ichpMacFormat + cchpIncr) * cchCHP,
      NONZEROLHND))
#else /* not WINHEAP */
    if (!FChngSizeH(vhgchpFormat, (ichpMacFormat + cchpIncr) * cwCHP, false))
#endif /* not WINHEAP */

        {
        /* Sorry, charlie */
        return false;
        }
    ichpMacFormat += cchpIncr;
    return true;
    }


/* #define DBEMG */
/* D X P  F R O M  C H */
#ifdef DBCS
/* DxpFromCh() assumes that ch passed is the first byte of a DBCS character
   if it is a part of such character. */
#endif
int DxpFromCh(ch, fPrinter)
int ch;
int fPrinter;
    {
    int               *pdxp; // changed to int (7.23.91) v-dougk
    int               dxpDummy; // changed to int (7.23.91) v-dougk

    extern int        dxpLogCh;
    extern struct FCE *vpfceScreen;

    /* If the width is not in the width table, then get it. */
    if (ch < chFmiMin)
        {
        switch (ch)
            {
        case chTab:
        case chEol:
        case chReturn:
        case chSect:
        case chNewLine:
        case chNRHFile:
            /* the width for these characters aren't really important */
	    pdxp = (CHAR *)(fPrinter ? &vfmiPrint.dxpSpace : &vfmiScreen.dxpSpace);
            break;
        default:
            pdxp = &dxpDummy;
            *pdxp = dxpNil;
            break;
            }
        }
    else if (ch >= chFmiMax)
        {
        /* outside the range we hold in our table - kludge it */
        pdxp = &dxpDummy;
        *pdxp = dxpNil;
        }
    else
        {
        /* inside our table */
        pdxp = (fPrinter ? vfmiPrint.mpchdxp : vfmiScreen.mpchdxp) + ch;
        }

#ifdef DBCS
    if (*pdxp == dxpNil && IsDBCSLeadByte(ch) )
        {
        int dxp;
#else
    if (*pdxp == dxpNil)
        {
        int dxp;
#endif

#ifdef DBCS
        struct FMI *pfmi;
        int        rgchT[cchDBCS]; // changed to int (7.23.91) v-dougk
        int        dxpT;
        int        dxpDBCS;

        pfmi = fPrinter ? (&vfmiPrint) : (&vfmiScreen);
        Assert(pfmi->bDummy == dxpNil);
        if (pfmi->dxpDBCS == dxpNil)
            {
            /* Get the width from GDI. */
            rgchT[0] = rgchT[1] = ch;
            dxpDBCS = (fPrinter ?
                            LOWORD(GetTextExtent(vhDCPrinter,
                                                 (LPSTR) rgchT, cchDBCS)) :
                            LOWORD(GetTextExtent(vhMDC,
                                                 (LPSTR) rgchT, cchDBCS)));
            /* Store in fmi, if it fits. */
            if (0 <= dxpDBCS && dxpDBCS < dxpNil)
                pfmi->dxpDBCS = (BYTE) dxpDBCS;
            return (dxpDBCS - pfmi->dxpOverhang);
            }
        else
            return (pfmi->dxpDBCS - pfmi->dxpOverhang);
        }
    else {
        int dxp;
#endif /* DBCS */
        /* get width from GDI */
        dxp = fPrinter ? LOWORD(GetTextExtent(vhDCPrinter, (LPSTR)&ch, 1)) -
          vfmiPrint.dxpOverhang : LOWORD(GetTextExtent(vhMDC, (LPSTR)&ch, 1)) -
          vfmiScreen.dxpOverhang;
#ifdef DBEMG
            CommSzNum("Get this.... ", dxp);
#endif
        //(7.24.91) v-dougk if (dxp >= 0 && dxp < dxpNil)
            {
            /* only store dxp's that fit in a byte */
            *pdxp = dxp;
            }

#ifdef DBEMG
        {
        char szT[10];
        CommSzSz("fPrinter:  ", (fPrinter ? "Printer" : "Screen"));
        if (ch == 0x0D) {
            szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
            }
        else if (ch == 0x0A) {
            szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
            }
        else if (32 <= ch && ch <= 126) {
            szT[0] = ch; szT[1] ='\0';
            }
        else if (FKanji1(ch)) {
            szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
            szT[4] = 'I'; szT[5] = '\0';
            }
        else {
            szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
            }
        CommSzSz("Character: ", szT);
        CommSzNum("Dxp:      ", (int) dxp);
        CommSzNum("OverHang: ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
        }
#endif
        return(dxp);
        }

#ifdef DBEMG
    {
    char szT[10];
    CommSzSz("fPrinter:  ", (fPrinter ? "Printer" : "Screen"));
    if (ch == 0x0D) {
        szT[0] = 'C'; szT[1] = 'R'; szT[2] = '\0';
        }
    else if (ch == 0x0A) {
        szT[0] = 'L'; szT[1] = 'F'; szT[2] = '\0';
        }
    else if (32 <= ch && ch <= 126) {
        szT[0] = ch; szT[1] ='\0';
        }
    else if (FKanji1(ch)) {
        szT[0] = 'K'; szT[1] = 'A'; szT[2] = 'N'; szT[3] = 'J';
        szT[4] = 'I'; szT[5] = '\0';
        }
    else {
        szT[0] = szT[1] = szT[2] = '-'; szT[3] = '\0';
        }
    CommSzSz("Character: ", szT);
    CommSzNum("Dxp:       ", (int) *pdxp);
    CommSzNum("OverHang:  ", (int) (fPrinter ? vfmiPrint.dxpOverhang : vfmiScreen.dxpOverhang));
    }
#endif
    return(*pdxp);
    }


/* F  F I R S T  I C H */
int near FFirstIch(ich)
int ich;
    {
    /* Returns true iff ich is 0 or preceded only by 0 width characters */
    register int ichT;
    register int *pdxp = &vfli.rgdxp[0];

    for (ichT = 0; ichT < ich; ichT++)
        {
        if (*pdxp++)
            {
            return false;
            }
        }
    return true;
    }


ValidateMemoryDC()
    {
    /* Attempt to assure that vhMDC and vhDCPrinter are valid.  If we have not
    already run out of memory, then vhDCPrinter is guaranteed, but vhMDC may
    fail due to out of memory -- it is the callers responsibility to check for
    vhMDC == NULL. */

    extern int vfOutOfMemory;
    extern HDC vhMDC;
    extern BOOL vfMonochrome;
    extern long rgbText;
    extern struct WWD *pwwdCur;

    /* If we are out of memory, then we shouldn't try to gobble it up by getting
    DC's. */
    if (!vfOutOfMemory)
        {
        if (vhMDC == NULL)
            {
            /* Create a memory DC compatible with the screen if necessary. */
            vhMDC = CreateCompatibleDC(pwwdCur->hDC);

            /* Callers are responsible for checking for vhMDC == NULL case */
            if (vhMDC != NULL)
                {
                /* Put the memory DC in transparent mode. */
                SetBkMode(vhMDC, TRANSPARENT);

                /* If the display is a monochrome device, then set the text
                color for the memory DC.  Monochrome bitmaps will not be
                converted to the foreground and background colors in this case,
                we must do the conversion. */
                if (vfMonochrome = (GetDeviceCaps(pwwdCur->hDC, NUMCOLORS) ==
                  2))
                    {
                    SetTextColor(vhMDC, rgbText);
                    }
                }
            }

        /* If the printer DC is NULL then we need to reestablish it. */
        if (vhDCPrinter == NULL)
            {
            GetPrinterDC(FALSE);
            /* GetPrinterDC has already called SetMapperFlags() on vhDCPrinter. */
            }
        }
    }