home *** CD-ROM | disk | FTP | other *** search
- /*
- trf-flush.c - state and content text flushing
-
- Eventually, all output will end up being flushed through one
- or two low-level routines, which will allow better trapping
- on conditions such as initial state needing to be dumped,
- diversions needing to be started, trap positions needing to
- be flushed, etc. Maybe in 1.06a2.
- */
-
- # include <stdio.h>
- # include <sys/types.h>
- # ifdef VARARGS
- # include <varargs.h>
- # endif /* VARARGS */
- # include "rtf.h"
- # include "rtf2troff.h"
-
-
- static int initialStateFlushed = 0;
-
- static int useInLine = 0; /* non-zero for inline char state changes */
- static char inLineChgs[rtfBufSiz] = "";
-
- /*
- Whether any content text chars have been written to current
- paragraph.
- */
-
- static int inPara = 0;
- static int oLen = 0;
- static int breakOK = 0;
-
-
- static void FlushDocState ();
- static void FlushParState ();
- static void FlushCharState ();
- static void FlushSACharState ();
- static void Continuation ();
- static void CalcInLineChanges ();
- static void _PutS ();
- static char *ApplyIndirection ();
-
- static void DrawLine ();
- static char *TabTypeStr ();
- static char *JustTypeStr ();
- static void CheckVMargins ();
- static double LineLen ();
-
-
- /*
- Flush any discrepancies between state as written and current
- internal state to bring the former in sync with the latter.
-
- Virtually all formatting text is written by this operation.
-
- It's assumed here, perhaps unfortunately, that things needing
- a Flush() first won't occur in the middle of output line
- collection.
- */
-
- void FlushState ()
- {
- /* flush */
- FlushInitialState ();
- fprintf(stderr, "FlushState():");
- if (docStateChanged) {
- fprintf(stderr, "<");
- FlushDocState ();
- fprintf(stderr, ":doc flushed>");
- getchar();
- }
- /* header/footer depend on some doc properties */
- if (docStateChanged || sectStateChanged) {
- fprintf(stderr, "<");
- FlushSectState ();
- fprintf(stderr, ":sec flushed>");
- }
- /* para line length depends on some doc properties; ditto tabs */
- if (docStateChanged || parStateChanged) {
- fprintf(stderr, "<");
- FlushParState ();
- fprintf(stderr, ":para flushed>");
- }
- if (charStateChanged) {
- fprintf(stderr, "<");
- FlushCharState ();
- fprintf(stderr, ":char flushed>");
- }
-
- /* sync */
- if (docStateChanged)
- bcopy ((char *) ids, (char *) wds, (int) sizeof (DocState));
- if (sectStateChanged)
- bcopy ((char *) iss, (char *) wss, (int) sizeof (SectState));
- if (parStateChanged)
- bcopy ((char *) ips, (char *) wps, (int) sizeof (ParState));
- if (charStateChanged)
- bcopy ((char *) ics, (char *) wcs, (int) sizeof (CharState));
-
- docStateChanged = 0;
- sectStateChanged = 0;
- parStateChanged = 0;
- charStateChanged = 0;
- fprintf(stderr, "<state reset> ");
- }
-
-
- /*
- This is called at the beginning of output to write out absolute
- initial values for some important state stuff. The other
- state-writers usually write values relative to the last written
- values, so this is needed to write absolute values that the
- relative values can be relative *to*.
-
- Problem: it's important to avoid tripping the first pseudo-page
- transition, or the header for the first page will be lost. This
- occurs when non-diverted text processing occurs or when a number
- of different requests (e.g., .in) occur. Header/footer text
- processingn occurs in diversions, so that's not a problem. To
- avoid tripping the trap with requests, use things like 'in instead
- of .in. Losing a break isn't a problem since there's no content
- text to write yet.
-
- The page length is written early and header/footer traps are
- planted. These traps stay intact. At most, the footer trap
- position might be moved.
-
- Tp is non-zero if a section's title page is special.
-
- Macros Ha, Hf, Hl and Hr are defined if/when all-page, first-page,
- left-page and right-page headers are given, and the number registers
- of the same name, which initially have value zero, are set to 1.
- Similarly for footers. The register Tm defines the top margins.
- The registers Hp and Fp define the header and footer positions.
-
- HE, FO need are written to exit if there are trap loops and
- to not space too much if vertical margins are weird.
- */
-
- void FlushInitialState ()
- {
- if (initialStateFlushed)
- return;
-
- Comment ("begin initial layout setup, change as desired");
-
- /* check whether it appears landscape *should have* been selected */
- if (ids->pageHeight < ids->pageWidth && !ids->landscape)
- {
- fprintf (stderr, "Turning landscape on\n");
- ids->landscape = 1;
- }
-
- if (ids->landscape)
- {
- if (tvers == XROFF)
- fprintf (f, ".dc landscape\n");
- /* reverse page height and width? */
- }
- fprintf (f, ".pl %gi\n", ids->pageHeight);
- if (tvers == XROFF)
- {
- double pLen;
-
- /* have to tell printer the page length in 300dpi units */
- /* if not default 11in (this is orientation dependent) */
- if (ids->landscape)
- pLen = ids->pageWidth;
- else
- pLen = ids->pageHeight;
- if (pLen != 11.0)
- fprintf (f, ".dc length %d\n", (int) (pLen * 300));
- }
-
- /* abandon hope, all ye who who enter here to try to read this... */
-
- fprintf (f, ".ad %s\n", JustTypeStr (ips->justification));
- fprintf (f, ".po %gi\n", ids->leftMargin);
- fprintf (f, "'in %gi\n", ips->leftIndent); /* ' to avoid break */
- fprintf (f, ".ll %gi\n", LineLen (ids, ips));
- fprintf (f, ".ps %d\n", ics->fontSize);
- Comment ("%gi = %gp", ips->spaceBetween, ips->spaceBetween * 72);
- fprintf (f, ".vs %gi\n", ips->spaceBetween);
- fprintf (f, ".ft R\n");
-
- /* plant traps */
-
- Comment ("plant header trap");
- fprintf (f, ".nr %s %d\n", rTitlePageSpecial, iss->titleSpecial);
- fprintf (f, ".nr %s %gi\n", rTopMargin, ids->topMargin);
- fprintf (f, ".nr %s %gi\n", rHeaderPos, iss->headerPos);
- fprintf (f, ".nr %s 0\n", rHeaderAll);
- fprintf (f, ".nr %s 0\n", rHeaderFirst);
- fprintf (f, ".nr %s 0\n", rHeaderLeft);
- fprintf (f, ".nr %s 0\n", rHeaderRight);
- fprintf (f, ".de %s\n", mHeader);
- fprintf (f, ".if \\\\n(%s>=\\\\n(Bm \\{\\\n",
- rTopMargin, rBottomMargin);
- fprintf (f, ".\ttm Trap Loop Death detected...\n");
- fprintf (f, ".\tex\n");
- fprintf (f, ".\\}\n");
- fprintf (f, ".rs\n");
- fprintf (f, ".if \\\\n(%s<\\\\n(%s 'sp |\\\\n(%su\n",
- rHeaderPos, rTopMargin, rHeaderPos);
- fprintf (f, ".ev 1\n");
- /*fprintf (f, ".nf\n"); /* correct? */
- /* ugly stuff to select correct header text macro */
- fprintf (f, ".ie (\\\\n%%=1&\\\\n(%s>0&\\\\n(%s>0) .%s\n",
- rHeaderFirst, rTitlePageSpecial, mHeaderFirst);
- fprintf (f, ".el \\{\\\n");
- fprintf (f, ". ie \\\\n(%s>0 \\{\\\n", rHeaderLeft);
- fprintf (f, ". ie o .%s\n", mHeaderRight);
- fprintf (f, ". el .%s\n", mHeaderLeft);
- fprintf (f, ". \\}\n");
- fprintf (f, ". el .if \\\\n(%s>0 .%s\n", rHeaderAll, mHeaderAll);
- fprintf (f, ".\\}\n");
- /* end ugly stuff */
- fprintf (f, ".ev\n");
- fprintf (f, "'sp |\\\\n(%su\n", rTopMargin);
- fprintf (f, ".ns\n");
- fprintf (f, "..\n");
- fprintf (f, ".wh 0i %s\n", mHeader);
-
- Comment ("plant footer trap");
- fprintf (f, ".nr %s %gi\n",
- rBottomMargin, ids->pageHeight - ids->bottomMargin);
- fprintf (f, ".nr %s %gi\n",
- rFooterPos, ids->pageHeight - iss->footerPos);
- fprintf (f, ".nr %s 0\n", rFooterAll);
- fprintf (f, ".nr %s 0\n", rFooterFirst);
- fprintf (f, ".nr %s 0\n", rFooterLeft);
- fprintf (f, ".nr %s 0\n", rFooterRight);
- fprintf (f, ".de %s\n", mFooter);
- fprintf (f, ".if \\\\n(%s>\\\\n(%s 'sp |\\\\n(%su\n",
- rFooterPos, rBottomMargin, rFooterPos);
- fprintf (f, ".ev 1\n");
- /*fprintf (f, ".nf\n"); /* correct? */
- /* ugly stuff to select correct footer text macro */
- fprintf (f, ".ie (\\\\n%%=1&\\\\n(%s>0&\\\\n(%s>0) .%s\n",
- rFooterFirst, rTitlePageSpecial, mFooterFirst);
- fprintf (f, ".el \\{\\\n");
- fprintf (f, ". ie \\\\n(%s>0 \\{\\\n", rFooterLeft);
- fprintf (f, ". ie o .%s\n", mFooterRight);
- fprintf (f, ". el .%s\n", mFooterLeft);
- fprintf (f, ". \\}\n");
- fprintf (f, ". el .if \\\\n(%s>0 .%s\n", rFooterAll, mFooterAll);
- fprintf (f, ".\\}\n");
- /* end ugly stuff */
- fprintf (f, ".ev\n");
- fprintf (f, "'bp\n");
- fprintf (f, "..\n");
- fprintf (f, ".wh %gi %s\n", -ids->bottomMargin, mFooter);
-
- Comment ("end initial layout setup");
-
- /* manually sync everything that was just flushed */
- wds->bottomMargin = ids->bottomMargin;
- wds->bottomMargin = ids->bottomMargin;
- wds->landscape = ids->landscape;
- wds->leftMargin = ids->leftMargin;
- wds->leftMargin = ids->leftMargin;
- wds->pageHeight = ids->pageHeight;
- wds->pageWidth = ids->pageWidth;
- wds->rightMargin = ids->rightMargin;
- wds->topMargin = ids->topMargin;
- wss->footerPos = iss->footerPos;
- wss->headerPos = iss->headerPos;
- wss->titleSpecial = iss->titleSpecial;
- wps->justification = ips->justification;
- wps->leftIndent = ips->leftIndent;
- wps->rightIndent = ips->rightIndent;
- wps->spaceBetween = ips->spaceBetween;
- wcs->fontSize = ics->fontSize;
-
- ++initialStateFlushed;
- }
-
-
- /*
- Note that right margin is document property in RTF, but has the
- effect of changing line length, which is handled under paragraph
- property changes. Ditto for change of default tab width.
- */
-
- static void FlushDocState ()
- {
- CheckVMargins ();
- if (ids->landscape != wds->landscape)
- {
- /* note: once on, can't turn off */
- if (ids->landscape) /* it's now on */
- {
- Flush ();
- if (tvers == XROFF)
- fprintf (f, ".dc landscape\n");
- }
- }
- if (ids->pageHeight != wds->pageHeight)
- {
- Flush ();
- fprintf (f, ".pl %gi\n", ids->pageHeight);
- if (tvers == XROFF)
- {
- double pLen;
-
- /* have to tell printer the page length in 300dpi units */
- /* if not default 11in (this is orientation dependent) */
-
- if (ids->landscape)
- pLen = ids->pageWidth;
- else
- pLen = ids->pageHeight;
- if (pLen != 11.0)
- fprintf (f, ".dc length %d\n",
- (int) (pLen * 300));
- }
- }
- if (ids->leftMargin != wds->leftMargin)
- {
- Flush ();
- fprintf (f, ".po %gi\n", ids->leftMargin);
- }
- }
-
-
- /*
- If the top margin or the header or footer positions have
- changed, redefine the registers giving their sizes. If the
- bottom margin has changed, move the trap to the right spot.
- (Document and section state interact here.)
-
- This is also called when a macro is about to be diverted, so that
- the trap position isn't set within a different environment.
- (Is that necessary?)
-
- The really ugly thing here is to try and catch cases where the
- header position is set below the top margin, and especially where the
- footer position *above* the bottom margin. The latter can result
- in loops where the footer trap is invoked in a loop.
- */
-
- void FlushSectState ()
- {
- if (iss->titleSpecial != wss->titleSpecial)
- {
- Flush ();
- fprintf (f, ".nr %s %d\n",
- rTitlePageSpecial, iss->titleSpecial);
- }
- if (ids->topMargin != wds->topMargin)
- {
- Flush ();
- fprintf (f, ".nr %s %gi\n", rTopMargin, ids->topMargin);
- }
- if (iss->headerPos != wss->headerPos)
- {
- Flush ();
- fprintf (f, ".nr %s %gi\n", rHeaderPos, iss->headerPos);
- }
- if (ids->bottomMargin != wds->bottomMargin)
- {
- Flush ();
- fprintf (f, ".ch %s %gi\n", mHeader, -ids->bottomMargin);
- }
- if (iss->footerPos != wss->footerPos)
- {
- Flush ();
- fprintf (f, ".nr %s %gi\n",
- rFooterPos, ids->pageHeight - iss->footerPos);
- }
- }
-
-
- static void FlushParState ()
- {
- int tabdiff;
- int i;
-
- if (ips->justification != wps->justification)
- {
- Flush ();
- fprintf (f, ".ad %s\n", JustTypeStr (ips->justification));
- }
- if (ips->leftIndent != wps->leftIndent)
- {
- Flush ();
- fprintf (f, ".in %+gi\n", ips->leftIndent - wps->leftIndent);
- }
- /*
- troff doesn't set right indent, rather it sets
- line length (function of page width - po - rm - ri)
- */
- if (ids->pageWidth != wds->pageWidth
- || ids->leftMargin != wds->leftMargin
- || ids->rightMargin != wds->rightMargin
- || ips->rightIndent != wps->rightIndent)
- {
- Flush ();
- fprintf (f, ".ll %gi\n", LineLen (ids, ips));
- }
- if (ips->spaceBetween != wps->spaceBetween)
- {
- Flush ();
- fprintf (f, ".vs %gi\n", ips->spaceBetween);
- }
-
- /*
- Determine if tabs have changed, which they will if there
- are a different number of tab stops than previously, or any
- of the current ones are different than those last written
- out. Change of default width is a change, too.
- */
-
- tabdiff = 0;
- if (ids->tabWidth != wds->tabWidth)
- tabdiff = 1;
- else if (ips->nTabs != wps->nTabs)
- tabdiff = 1;
- else
- {
- for (i = 0; i < ips->nTabs; i++)
- {
- if (ips->tab[i] != wps->tab[i]
- || ips->tabType[i] != wps->tabType[i])
- {
- tabdiff = 1;
- break;
- }
- }
- }
- if (tabdiff)
- {
- Flush ();
- if (ips->nTabs == 0) /* use defaults */
- {
- fprintf (f, ".ta %gi", ids->tabWidth);
- for (i = 1; i < maxTab; i++)
- fprintf (f, " +%gi", ids->tabWidth);
- }
- else
- {
- fprintf (f, ".ta %gi%s", ips->tab[0],
- TabTypeStr (ips->tabType[0]));
- for (i = 1; i < ips->nTabs; i++)
- {
- fprintf (f, " +%gi%s",
- ips->tab[i] - ips->tab[i-1],
- TabTypeStr (ips->tabType[i]));
- }
- }
- fprintf (f, "\n");
- }
- if (ips->tabChar != wps->tabChar)
- {
- Flush ();
- switch (ips->tabChar)
- {
- case rtfLeaderMotion:
- fprintf (f, ".tc\n");
- break;
- case rtfLeaderDot:
- fprintf (f, ".tc .\n");
- break;
- case rtfLeaderHyphen:
- fprintf (f, ".tc -\n");
- break;
- case rtfLeaderUnder:
- case rtfLeaderThick:
- fprintf (f, ".tc _\n");
- break;
- }
- }
- }
-
-
- /*
- Flush character state. Actually, if useInLine is true, this
- just calculates the string of inline commands that should be
- generated, and those are later flushed in PutString ().
- */
-
- static void FlushCharState ()
- {
- if (useInLine)
- CalcInLineChanges ();
- else
- FlushSACharState ();
- }
-
-
- /*
- Flush character state, using standalone requests.
- If in a paragraph, generates a \c to cause stuff on current line
- to be joined to next so extraneous space won't end up in the
- output.
- */
- static void FlushSACharState ()
- {
- u_long csFontBits, wsFontBits;
- int idiff;
- double ddiff;
-
- if (ics->fontSize != wcs->fontSize) /* write font size */
- {
- Continuation ();
- idiff = ics->fontSize - wcs->fontSize;
- fprintf (f, ".ps %+d\n", idiff);
- }
- /*
- Note: super/subscripts don't always have intended effect
- in non-inline mode. Output may need hand fixing.
- */
- if (ics->superScript != wcs->superScript)
- {
- Continuation ();
- ddiff = wcs->superScript - ics->superScript;
- fprintf (f, "'sp %gp\n", ddiff);
- }
- if (ics->subScript != wcs->subScript)
- {
- Continuation ();
- ddiff = ics->subScript - wcs->subScript;
- fprintf (f, "'sp %gp\n", ddiff);
- }
- if (ics->charStyle != wcs->charStyle) /* write R, I, B */
- {
- /*
- Since troff implements plain, bold and italic by
- changing fonts, figure out whether the font needs
- to be changed. This doesn't understand simultaneous
- bold+italic (boo-hoo), and treats it as italic.
- */
- csFontBits = StyleFontBits (ics->charStyle);
- wsFontBits = StyleFontBits (wcs->charStyle);
- if (csFontBits != wsFontBits)
- {
- Continuation ();
- if (csFontBits == 0) /* neither bold or italic */
- fprintf (f, ".ft R\n");
- else if (csFontBits & styleItalic)
- fprintf (f, ".ft I\n");
- else if (csFontBits & styleBold)
- fprintf (f, ".ft B\n");
- }
-
- /* if smallcaps now on and wasn't before, turn on */
- if ((ics->charStyle & styleSmallCaps)
- && !(wcs->charStyle & styleSmallCaps))
- {
- Continuation ();
- fprintf (f, ".ps -1\n");
- }
- /* if smallcaps now off and wasn't before, turn off */
- if (!(ics->charStyle & styleSmallCaps)
- && (wcs->charStyle & styleSmallCaps))
- {
- Continuation ();
- fprintf (f, ".ps +1\n");
- }
- }
- }
-
-
- static void Continuation ()
- {
- if (oLen > 0)
- {
- if (breakOK)
- fprintf (f, "\n");
- else
- fprintf (f, "\\c\n"); /* need ApplyIndirection() ? */
- ResetParLine ();
- }
- }
-
-
- /*
- Generate a string of inline-changes, which need to be flushed with
- indirection applied.
- */
-
- static void CalcInLineChanges ()
- {
- char *picp = inLineChgs;
- int csFontBits, wsFontBits;
- int idiff;
- double ddiff;
- char c;
-
- *picp = '\0';
- if (ics->fontSize != wcs->fontSize) /* write font size */
- {
- idiff = ics->fontSize - wcs->fontSize;
- c = '+';
- if (idiff < 0)
- {
- c = '-';
- idiff *= -1;
- }
- while (idiff > 9)
- {
- sprintf (picp, "\\s%c9", c);
- picp += strlen (picp);
- idiff -= 9;
- }
- sprintf (picp, "\\s%c%d", c, idiff);
- picp += strlen (picp);
- }
- if (ics->superScript != wcs->superScript)
- {
- ddiff = wcs->superScript - ics->superScript;
- sprintf (picp, "\\v'%gp'", ddiff);
- picp += strlen (picp);
- }
- if (ics->subScript != wcs->subScript)
- {
- ddiff = ics->subScript - wcs->subScript;
- sprintf (picp, "\\v'%gp'", ddiff);
- picp += strlen (picp);
- }
- if (ics->charStyle != wcs->charStyle) /* write R, I, B */
- {
- /*
- Since troff implements plain, bold and italic by
- changing fonts, figure out whether the font needs
- to be changed. This doesn't understand simultaneous
- bold+italic (boo-hoo), and treats it as italic.
- */
- csFontBits = ics->charStyle & (styleBold | styleItalic);
- wsFontBits = wcs->charStyle & (styleBold | styleItalic);
- if (csFontBits != wsFontBits)
- {
- if (csFontBits == 0) /* neither bold or italic */
- sprintf (picp, "\\fR");
- else if (csFontBits & styleItalic)
- sprintf (picp, "\\fI");
- else if (csFontBits & styleBold)
- sprintf (picp, "\\fB");
- /* this is a NOP if no "if" was triggered above */
- picp += strlen (picp);
- }
-
- /* if smallcaps now on and wasn't before, turn on */
- if ((ics->charStyle & styleSmallCaps)
- && !(wcs->charStyle & styleSmallCaps))
- {
- sprintf (picp, "\\s-1");
- picp += strlen (picp);
- }
- /* if smallcaps now off and wasn't before, turn off */
- if (!(ics->charStyle & styleSmallCaps)
- && (wcs->charStyle & styleSmallCaps))
- {
- sprintf (picp, "\\s+1");
- picp += strlen (picp);
- }
- }
- }
-
-
- /*
- Save font, point size and vertical spacing. Called at beginning
- of table to get an idea of the values for the parameters that tbl
- will use at the beginning of each cell. FlushTblFPV() is called
- after each cell is begin, to undo this if the previous cell ends
- with some different values, so those values will carry through.
- */
-
-
- static double vs;
- static int ps;
- static u_long font;
-
-
- void SaveTblFPV ()
- {
- FlushState (); /* make sure internal state same as written */
- vs = ips->spaceBetween;
- ps = ics->fontSize;
- font = StyleFontBits (ics->charStyle);
- }
-
-
- void FlushTblFPV ()
- {
- u_long curFont;
-
- if (1 || ips->spaceBetween != vs) /* tbl will have set it to vs, */
- { /* so set it back */
- fprintf (f, ".vs %gi\n", ips->spaceBetween);
- wps->spaceBetween = ips->spaceBetween;
- }
- if (1 || ics->fontSize != ps) /* tbl will have... */
- {
- fprintf (f, ".ps %d\n", ics->fontSize);
- wcs->fontSize = ics->fontSize;
- }
- curFont = StyleFontBits (ics->charStyle);
- if (1 || curFont != font) /* tbl will have... */
- {
- if (curFont == 0)
- fprintf (f, ".ft R\n");
- else if (curFont & styleItalic)
- fprintf (f, ".ft I\n");
- else if (curFont & styleBold)
- fprintf (f, ".ft B\n");
- /* now the hard part */
- wcs->charStyle &= ~StyleFontBits (wcs->charStyle);
- wcs->charStyle |= curFont;
- }
- }
-
-
- /* ---------------------------------------------------------------------- */
-
-
- void ResetPar ()
- {
- inPara = 0;
- ResetParLine ();
- }
-
-
- void ResetParLine ()
- {
- oLen = 0;
- breakOK = 0;
- }
-
-
- /*
- Unconditional flush -- force output line and prevent next line
- from being joined to it. Also handle any bottom border and
- "extra space after paragraph" if any is needed.
- */
-
- void Par ()
- {
- FlushInitialState ();
- if (inPara)
- fprintf (f, "\n.br\n");
- else
- fprintf (f, ".sp\n");
- ResetPar ();
- if (ips->borderType != rtfNoBorderType
- && (ips->borderFlags & borderBottom) != 0)
- {
- /* draw bottom border */
- DrawLine (ips->borderType);
- }
-
- if (ips->spaceAfter != 0.0)
- fprintf (f, ".sp %gi\n", ips->spaceAfter);
-
- }
-
-
- void Sect ()
- {
- char *p = NULL;
- char buf[20];
-
- Par (); /* finish current paragraph */
- switch (iss->breakType)
- {
- case rtfNoBreak:
- break; /* nothing to do */
- case rtfColBreak:
- /* this is untested! */
- sprintf (buf, ".sp |\\n(%s\n", rBottomMargin);
- p = buf;
- break;
- case rtfPageBreak:
- p = ".bp";
- break;
- case rtfEvenBreak:
- p = ".if e .bp";
- break;
- case rtfOddBreak:
- p = ".if o .bp";
- break;
- }
- if (p != NULL)
- {
- FlushInitialState ();
- fprintf (f, "%s\n", p);
- }
- }
-
- /*
- Document content text writing routines. These should not be
- used to write out formatting text.
-
- Flush() force out any collected content text, if any
- PutString() write out a string of characters
- PutFunnyChar() map char > 127 onto troff equivalent
- */
-
-
- void Flush ()
- {
- if (inPara)
- {
- _PutS ("\n");
- ResetPar ();
- }
- }
-
-
- /*
- Dump out a piece of content text. Argument should be a string just
- as you would write it normally, assuming no levels of indirection.
-
- Does state flushing, beginning-of-paragraph processing, flushes
- pending inline changes, and writes out the string (account for levels
- of indirection).
-
- Handles underlining if continuous underlining on, or word underlining
- is on and string isn't " " or "\ ".
-
- Does *not* do:
- special char mapping (do before calling)
- to-caps mapping (ditto)
-
- */
-
- void PutString (s)
- char *s;
- {
- int doUnderlining = 0;
- int doStrikeThru = 0;
- char *p;
-
- fprintf(stderr, "\nPutString(%s) - ", s);
- if (ics->charStyle & styleInvisible) {
- fprintf(stderr, "<invisible>");
- return;
- }
-
- if (stateChanged)
- {
- useInLine = 1;
- fprintf(stderr, " --<");
- FlushState (); /* clears stateChanged */
- fprintf(stderr, " -- ");
- useInLine = 0;
- fprintf(stderr, ":stateChanged>");
-
- }
-
- /*
- It's OK to hang onto inline changes until after this if-block
- since only paragraph properties are used here; inlines only
- affect character properties.
- */
-
- if (inPara == 0) /* just beginning a paragraph */
- {
- fprintf(stderr, "<");
- if (ips->spaceBefore != 0.0)
- fprintf (f, ".sp %gi\n", ips->spaceBefore);
- if (ips->borderType != rtfNoBorderType
- && (ips->borderFlags & borderTop) != 0)
- {
- /* draw top border */
- DrawLine (ips->borderType);
- }
- if (ips->firstIndent != 0.0)
- fprintf (f, ".ti %gi\n", ips->firstIndent);
- fprintf(stderr, ":beginOfPara>");
- }
-
- if (inLineChgs[0] != '\0')
- {
- fprintf(stderr, "<");
- _PutS (ApplyIndirection (inLineChgs));
- fprintf(stderr, ":Inline Change>");
- inLineChgs[0] = '\0';
- }
-
- /* Break up long output lines. */
- if (oLen > lineBreakLen && breakOK && s[0] != ' ') {
- fprintf(stderr, "<");
- _PutS ("\n"); /* (<-- turns breakOK off) */
- fprintf(stderr, ":breaking_long_line>");
- }
-
- /*
- See if this is a natural breakpoint (single space not
- at beginning of line). If so, remember it for following
- characters, so long lines can be broken. If this is
- a breakpoint, but the previous character was too, then
- we're seeing multiple whitespace characters, and it's really
- not a breakpoint, since breaking the line would then result
- in loss of whitespace when troff joins lines back together
- (it tosses trailing whitespace; this is only safe when that
- consists of a single space).
- */
-
- if (oLen > 0 && s[0] == ' ' && s[1] == '\0')
- {
- fprintf(stderr, "<");
- if (breakOK)
- breakOK = 0; /* multiple whitespace; not OK */
- else
- breakOK = 1;
- fprintf(stderr, ":toggle_break>");
- }
-
- if (ics->charStyle & styleUnderline) {
- fprintf(stderr, "<underline>");
- ++doUnderlining;
- }
- if (ics->charStyle & styleStrikeThru) {
- fprintf(stderr, "<strike_thru>");
- ++doStrikeThru;
- }
- else if (ics->charStyle & styleWUnderline)
- {
- fprintf(stderr, "<");
- if (strcmp (s, " ") != 0 && strcmp (s, "\\ ") != 0) {
- ++doUnderlining;
- fprintf(stderr, "<underline>");
- }
- fprintf(stderr, ":Wunderline>");
- }
- if (doUnderlining || doStrikeThru)
- {
- if (oLen > 0) /* force onto own line if necessary */
- {
- p = ApplyIndirection ("\\c\n");
- _PutS (p);
- }
- /* mark horizontal position */
- p = ApplyIndirection ("\\kx");
- _PutS (p);
- }
- p = ApplyIndirection (s);
- _PutS (p);
- if (doUnderlining)
- {
- /* return to marked position, draw underline */
- p = ApplyIndirection ("\\l'|\\nxu\\(ul'");
- _PutS (p);
- }
- if (doStrikeThru)
- {
- /* return to marked position, draw strikethrough */
- p = ApplyIndirection ("\\v'-.2v'\\l'|\\nxu-'\\v'.2v'");
- _PutS (p);
- }
-
- inPara = 1;
- fprintf(stderr, "<in_Para_ungoing>\n");
- }
-
-
- /*
- Write something to current paragraph, keeping track of last char
- and number of characters written to current line. Need oLen and
- breakOK to know when to break output line for readability.
-
- When a newline is written, oLen is reset.
-
- When a non-space is written, breakOK is turned off, which handles
- cases where PutString() saw a single space and thought a natural
- break was in order, but that space ends up coming out in the middle
- of control language, such as for underlining.
- */
-
- static void _PutS (s)
- char *s;
- {
- char c;
-
- while ((c = *s++) != '\0')
- {
- fputc (c, f);
- if (c == '\n')
- ResetParLine ();
- else
- ++oLen;
- if (c != ' ')
- breakOK = 0;
- }
- }
-
-
- /*
- Process a string to apply indirection.
- Level Action
- 0 \ -> \
- 1 \ -> \\
- 2 \ -> \\\\
-
- Note: returns pointer into static buffer.
- */
-
- static char *ApplyIndirection (s)
- char *s;
- {
- static char buf[100];
- static char *p, c;
- static int slashCount, i;
-
- slashCount = 1; /* figure out how many \'s */
- for (i = 0; i < indirectionLevel; i++) /* one \ maps to */
- slashCount += slashCount;
- p = buf;
- while ((c = *s++) != '\0')
- {
- if (c != '\\')
- *p++ = c;
- else for (i = 0; i < slashCount; i++)
- *p++ = '\\';
- }
- *p = '\0';
- return (buf);
- }
-
-
- /*
- Draw horizontal line. Sets vertical size not to space down very
- much, then restores. Sets point size big for thick lines, then
- restores.
-
- Probably should take current boldface setting into account.
- */
-
- static void DrawLine (type)
- int type;
- {
- int ps;
- double vs;
- char buf[100], c;
-
- switch (type)
- {
- default:
- case rtfBorderHair:
- case rtfBorderSingle:
- ps = 10;
- vs = .1;
- c = '_';
- break;
- case rtfBorderThick:
- case rtfBorderShadow:
- ps = 36;
- vs = .3;
- c = '_';
- break;
- case rtfBorderDouble:
- ps = 5;
- vs = .3;
- c = '=';
- break;
- case rtfBorderDot:
- ps = 10;
- vs = .1;
- c = '.';
- break;
- }
- Flush ();
- if (ps != wcs->fontSize) /* change point size if necessary */
- fprintf (f, ".ps %d\n", ps);
- fprintf (f, ".vs %gi\n", vs);
- sprintf (buf, "\\l'%gi\\&%c'", LineLen (ids, ips), c);
- fprintf (f, "%s\n", ApplyIndirection (buf));
- fprintf (f, ".br\n");
- fprintf (f, ".vs\n"); /* restore */
- if (ps != wcs->fontSize) /* restore if was changed */
- fprintf (f, ".ps\n");
- }
-
-
- /* ---------------------------------------------------------------------- */
-
- /*
- Miscellaneous stuff
- */
-
-
- static char *TabTypeStr (type)
- int type;
- {
- char *p = ""; /* assume left justified (default) */
-
- switch (type)
- {
- case rtfTabDecimal: /* <- act like right tab, oh, well... */
- case rtfTabRight: p = "R"; break;
- case rtfTabCenter: p = "C"; break;
- }
- return (p);
- }
-
-
- static char *JustTypeStr (type)
- int type;
- {
- char *p = "l"; /* default if unrecognized */
-
- switch (type)
- {
- default: /* <- if unrecognized */
- case rtfQuadLeft:
- p = "l";
- break;
- case rtfQuadRight:
- p = "r";
- break;
- case rtfQuadCenter:
- p = "c";
- break;
- case rtfQuadJust:
- p = "b";
- break;
- }
- return (p);
- }
-
-
- /*
- Check vertical margins. Constraints:
-
- Top margin should not extend to or below bottom margin
- Top margin should be below header margin
- Bottom margin MUST be above top margin (or Trap Loop Death will occur)
- */
-
- static void CheckVMargins ()
- {
- if (ids->topMargin + ids->bottomMargin >= ids->pageHeight)
- {
- fprintf (stderr, "Top margin is below bottom margin. Yow!\n");
- exit (1);
- }
- }
-
-
- static double LineLen (docState, parState)
- DocState *docState;
- ParState *parState;
- {
- return (docState->pageWidth
- - (docState->leftMargin + docState->rightMargin)
- - parState->rightIndent);
- }
-
-
- /*
- Comment - dump a comment to the output. The .\" and \n at
- beginning and end are supplied automatically.
- */
-
-
- # ifdef VARARGS
-
- /*
- This version is for systems that have varargs.
- */
-
- void
- Comment (va_alist)
- va_dcl
- {
- va_list args;
- char *fmt;
-
- Flush ();
- fprintf (f, ".\\\" ");
- va_start (args);
- fmt = va_arg (args, char *);
- vfprintf (f, fmt, args);
- va_end (args);
- fprintf (f, "\n");
- }
-
- # else /* !VARARGS */
-
- /*
- This version is for systems that don't have varargs.
- */
-
- void
- Comment (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
- char *fmt;
- char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
- {
- Flush ();
- fprintf (f, ".\\\" ");
- fprintf (f, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
- fprintf (f, "\n");
- }
-
- # endif /* VARARGS */
-