home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / utils / rtfprsr / rtf2trof.c < prev    next >
Text File  |  1995-05-18  |  24KB  |  1,141 lines

  1. /*
  2.     Trap positions should be flushed *before* the .ev, unfortunately,
  3.     they might not be changed until after the .ev is already out!  Agh.
  4.  
  5.     Allow these options:
  6.     -h    disable headers/footers
  7.     +h    enable headers/footers (default)
  8.  
  9.     Bottom position should be written in terms of page length, which
  10.     should be stored in a register.
  11.  
  12.     Need -me, -mm, -ms specific stuff.  Is there a way of detecting
  13.     them from within troff?
  14.  
  15.     Allow header/footer suppression?  (for cases where the code written
  16.     is just completely wrong.)
  17.  
  18.     Need to handle \titlepg.
  19.  
  20.     rtf2troff - read rtf input, write troff output
  21.  
  22.     Syntax: rtf2troff options file
  23.  
  24.     Options:
  25.     -e        echo token information
  26.     -me        write -me specific output
  27.     -mm        write -mm specific output
  28.     -ms        write -ms specific output
  29.     -s        disable strikethrough
  30.     +s        enable strikethrough (default)
  31.     -t troff    specify troff version
  32.     -u        disable underlining
  33.     +u        enable underlining (default)
  34.  
  35.     This translator was written to be used with the Primate Center's
  36.     troff-variant (xroff).  xroff dependencies are bracketed within
  37.     "if (xroff) { ... }" constructions.
  38.  
  39.     29 Jan 91    Paul DuBois    dubois@primate.wisc.edu
  40.  
  41.     29 Jan 91 V1.0. Created.
  42.     31 Jan 91 Made to work. :-)
  43.     27 Feb 91 V1.01. Updated for distribution 1.05.
  44.     28 Feb 91 V1.02. Began updating for distribution 1.06.
  45.  
  46.     --
  47.  
  48.     troff puts paragraph markers at the beginning of paragraphs,
  49.     RTF puts 'em at end; the difference is a pain.
  50.  
  51.     "Small caps" is done by \s-1 ... \s+1 and capitalizing everything
  52.     in between.
  53.  
  54.     Good underlining is hard to do in troff; each character is
  55.     underlined individually, which generates an abysmal amount of
  56.     output.  Strikethrough output is even worse.
  57.  
  58.     --
  59.  
  60.     Deficiencies are myriad.  They include, but are by no means
  61.     limited to:
  62.  
  63.     No formula support.
  64.  
  65.     Poor table support.  Tabs within cells are botched.  Tables are
  66.     always centered.  Tables often come out looking pretty ugly.
  67.  
  68.     space before, after and between don't appear to always work.
  69.  
  70.     troff has no decimal tabs; they are treated as (ugh) right justified
  71.     tabs.
  72.  
  73.     Vertical lines ("bar tabs") are unsupported.
  74.  
  75.     Poor font support (only R, I, B, not even I+B).  Font table ignored.
  76.  
  77.     Line numbering ignored, for no good reason.
  78.  
  79.     Only normal and continuous underlining are supported.
  80.  
  81.     No outline or shadow, since troff can't do that.
  82.  
  83.     All-caps, small-caps doesn't work for non-ASCII characters (> 127)
  84.     or special (mapped) characters.  (Of course, why should it?)
  85.  
  86.     Default space between lines should be "auto" - but how to do that?
  87.  
  88.     Mixing of leader characters within a paragraph is not supported.
  89.  
  90.     Is nTabs = 0 handled incorrectly?
  91.  
  92.     Mechanism for handling invisible text is inconsistent.
  93.     It's hard to do correctly...particularly as not everything
  94.     is ignored when \v is in effect, and I'm not sure exactly
  95.     what governs whether something is ignored or not.
  96. */
  97.  
  98. # include    <stdio.h>
  99. # include    <sys/types.h>
  100. # include    <ctype.h>
  101. # include    "rtf.h"
  102. # include    "rtf2troff.h"
  103.  
  104.  
  105. int    tvers = TROFF;
  106. int    mvers = noMacros;
  107.  
  108.  
  109. State        *is;        /* current internal state */
  110. DocState    *ids;        /* internal document state */
  111. SectState    *iss;        /* internal section state */
  112. ParState    *ips;        /* internal paragraph state */
  113. CharState    *ics;        /* internal character state */
  114.  
  115. State        *ws;        /* written state */
  116. DocState    *wds;        /* written document state */
  117. SectState    *wss;        /* written section state */
  118. ParState    *wps;        /* written paragraph state */
  119. CharState    *wcs;        /* written character state */
  120.  
  121.  
  122. /*
  123.     Whether internal state has been changed since written state
  124.     was last synchronized to it.  Initially true so that internal
  125.     state will be flushed when first content character is written.
  126. */
  127.  
  128. int    docStateChanged = 1;    /* document properties have changed */
  129. int    sectStateChanged = 1;    /* section properties have changed */
  130. int    parStateChanged = 1;    /* paragraph properties have changed */
  131. int    charStateChanged = 1;    /* character properties have changed */
  132.  
  133.  
  134. /*
  135.     Indirection level for escape (\) processing.  Incremented
  136.     during macro/diversion collection.
  137. */
  138.  
  139. int    indirectionLevel = 0;
  140.  
  141.  
  142. static int    haveTables = 0;    /* non-zero if any seen */
  143. static TblState    tableState;
  144. TblState    *its = &tableState;
  145. int        inTable = 0;    /* whether in table cell or not */
  146.  
  147.  
  148. /*
  149.     Default output stream
  150. */
  151.  
  152. FILE    *f = stdout;
  153.  
  154. static int    allowUnderline = 1;
  155. static int    allowStrikeThru = 1;
  156.  
  157. static char    *usage = "Usage: rtf2troff [-e] [-me|-mm|-ms] [-s|+s] [-t troff] [-u|+u] file";
  158.  
  159.  
  160. static void    TokenEcho ();
  161.  
  162. static void    Unknown ();
  163. static void    Text ();
  164. static void    Group ();
  165. static void    Control ();
  166. static void    BeginDestination ();
  167. static void    EndDestination ();
  168. static void    Destination ();
  169. static void    CharSet ();
  170. static void    SpecialChar ();
  171. static void    DocAttr ();
  172. static void    SectAttr ();
  173. static void    ParAttr ();
  174. static void    CharAttr ();
  175.  
  176.  
  177. static void    SetNextTabType ();
  178. static void    SetNextTabPos ();
  179. static void    SetTabChar ();
  180.  
  181.  
  182. int main (argc, argv)
  183. int    argc;
  184. char    **argv;
  185. {
  186. char    *troff = "troff";
  187. char    *macros = (char *) NULL;
  188.  
  189.     RTFInit ();
  190.  
  191.     /*
  192.         Process arguments.  The -t and -me|-mm|-ms arguments
  193.         must be remembered and applied *in that order* after
  194.         argument processing, or char maps may not be selected
  195.         properly.
  196.     */
  197.     --argc;
  198.     ++argv;
  199.     while (argc > 0 && **argv == '-')
  200.     {
  201.         if (strcmp ("-e", *argv) == 0)
  202.             RTFSetReadHook (TokenEcho);
  203.         else if (strcmp ("-s", *argv) == 0)
  204.             allowStrikeThru = 0;
  205.         else if (strcmp ("+s", *argv) == 0)
  206.             allowStrikeThru = 1;
  207.         else if (strcmp ("-u", *argv) == 0)
  208.             allowUnderline = 0;
  209.         else if (strcmp ("+u", *argv) == 0)
  210.             allowUnderline = 1;
  211.         else if (strcmp ("-t", *argv) == 0)
  212.         {
  213.             if (argc < 2)
  214.             {
  215.                 fprintf (stderr, "%s\n", usage);
  216.                 exit (1);
  217.             }
  218.             --argc;
  219.             ++argv;
  220.             troff = *argv;
  221.             if (strcmp (troff, "troff") == 0)
  222.                 tvers = TROFF;
  223.             else if (strcmp (troff, "xroff") == 0)
  224.                 tvers = XROFF;
  225.             else if (strcmp (troff, "pstroff") == 0)
  226.                 tvers = PSTROFF;
  227.         }
  228.         else if (strcmp ("-me", *argv) == 0)
  229.         {
  230.             macros = *argv;
  231.             mvers = meMacros;
  232.         }
  233.         else if (strcmp ("-mm", *argv) == 0)
  234.         {
  235.             macros = *argv;
  236.             mvers = mmMacros;
  237.         }
  238.         else if (strcmp ("-ms", *argv) == 0)
  239.         {
  240.             macros = *argv;
  241.             mvers = msMacros;
  242.         }
  243.         else
  244.         {
  245.             fprintf (stderr, "Unknown option: %s\n", *argv);
  246.             fprintf (stderr, "%s\n", usage);
  247.             exit (1);
  248.         }
  249.         --argc;
  250.         ++argv;
  251.     }
  252.     SelectFormatterMaps (troff);
  253.     if (macros != (char *) NULL)
  254.         SelectMacPackMaps (macros);
  255.  
  256.     /* not clever; only allows stdin or one named file to be read */
  257.  
  258.     if (argc > 0)
  259.     {
  260.         if (freopen (argv[0], "r", stdin) == (FILE *) NULL)
  261.         {
  262.             fprintf (stderr, "Can't open \"%s\"\n", argv[0]);
  263.             exit (1);
  264.         }
  265.     }
  266.  
  267.  
  268. /*
  269.     Install writer callbacks into reader and initialize state
  270.     (sets up pointers into internal state 0, and equates initial
  271.     written state to internal state).
  272. */
  273.  
  274.     RTFSetClassCallback (rtfText, Text);
  275.     RTFSetClassCallback (rtfGroup, Group);
  276.     RTFSetClassCallback (rtfControl, Control);
  277.     RTFSetClassCallback (rtfUnknown, Unknown);
  278.  
  279.     InitState ();
  280.  
  281.     /*
  282.         If macro package needs to be told special characters
  283.         might be used, do so.
  284.     */
  285.     if (mvers == meMacros)
  286.         fprintf (f, ".sc\n");
  287.     else if (mvers == msMacros)
  288.         fprintf (f, ".AM\n");
  289.  
  290.     /*
  291.         Process the input stream.  Make sure the first intoken is
  292.         a "{" so a state push will occur before anything else
  293.         (need to preserve state 0 intact for section, paragraph,
  294.         character default restoration).
  295.     */
  296.  
  297.     (void) RTFGetToken ();
  298.     if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
  299.     {
  300.         fprintf (stderr, "malformed rtf file - ");
  301.         fprintf (stderr, "does not begin with \"{\"\n");
  302.         exit (1);
  303.     }
  304.     RTFRouteToken ();    /* send "{" through router */
  305.     RTFRead ();        /* read everything else */
  306.     Flush ();
  307.  
  308.     /* some diagnostic stuff */
  309.     CheckFinalState ();
  310.  
  311.     if (haveTables)
  312.         fprintf (stderr, "Output contains tables (run through tbl)\n");
  313.  
  314.     exit (0);
  315. }
  316.  
  317.  
  318. /*
  319.     Token echo function to implement -e
  320. */
  321.  
  322. static void TokenEcho ()
  323. {
  324.     fprintf (f, "%d\t%d\t%d\t%d\t\"%s\"\n",
  325.             rtfClass, rtfMajor, rtfMinor, rtfParam, rtfTextBuf);
  326. }
  327.  
  328.  
  329.  
  330. /* ---------------------------------------------------------------------- */
  331.  
  332. /*
  333.     Token class handlers
  334. */
  335.  
  336. /*
  337.     Echo any unknown tokens.  This helps know where translator
  338.     needs to be extended.
  339. */
  340.  
  341. static void Unknown ()
  342. {
  343.     fprintf (stderr, "Unknown symbol %s\n", rtfTextBuf);
  344. }
  345.  
  346.  
  347. /*
  348.     Group operator.  Push or pop internal state level.
  349.  
  350.     Before a pop, check whether the destination needs any shutdown.
  351. */
  352.  
  353. static void Group ()
  354. {
  355.     switch (rtfMajor)
  356.     {
  357.     case rtfBeginGroup:        /* push */
  358.         PushIState ();
  359.         break;
  360.     case rtfEndGroup:        /* pop */
  361.         /* do end-of-destination procecssing, then pop state */
  362.         if (is->destination != rtfNoDestination)
  363.             EndDestination ();
  364.         PopIState ();
  365.         break;
  366.     }
  367. }
  368.  
  369.  
  370. /*
  371.     Have a text char, write it out.  Perform special char mapping
  372.     for chars > 127, do escapes for backslashes.
  373.  
  374.     For normal characters, perform to-upper processing.
  375. */
  376.  
  377. static void Text ()
  378. {
  379. char    buf[2], *p;
  380.  
  381.     if (rtfMajor > 127)        /* non-ASCII, map to troff equiv. */
  382.         p = CharMapping (rtfMajor);
  383.     else if (rtfMajor == '\\')    /* escape; escape it */
  384.         p = "\\e";
  385.     else                /* regular unmapped, unescaped char */
  386.     {
  387.         if (ics->charStyle & (styleAllCaps | styleSmallCaps))
  388.         {
  389.             /*
  390.                 OK to use islower()/toupper() because char
  391.                 is known to be <= 127
  392.             */
  393.             if (islower (rtfMajor))
  394.                 rtfMajor = toupper (rtfMajor);
  395.         }
  396.         buf[0] = rtfMajor;
  397.         buf[1] = '\0';
  398.         p = buf;
  399.     }
  400.     PutString (p);
  401. }
  402.  
  403. /*
  404.     The char sets, special chars and destinations do not involve
  405.     a state change; most other control things do.
  406. */
  407.  
  408. static void Control ()
  409. {
  410.     switch (rtfMajor)
  411.     {
  412.     case rtfCharSet:
  413.         CharSet ();
  414.         break;
  415.     case rtfSpecialChar:
  416.         SpecialChar ();
  417.         break;
  418.     case rtfDestination:
  419.         BeginDestination ();
  420.         break;
  421.     case rtfDocAttr:
  422.         DocAttr ();
  423.         break;
  424.     case rtfSectAttr:
  425.         SectAttr ();
  426.         break;
  427.     case rtfParAttr:
  428.         ParAttr ();
  429.         break;
  430.     case rtfCharAttr:
  431.         CharAttr ();
  432.         break;
  433.     case rtfTblAttr:
  434.         TblAttr ();
  435.         break;
  436.     }
  437. }
  438.  
  439.  
  440. static void CharSet ()
  441. {
  442.     SelectCharSetMaps (rtfMinor);
  443. }
  444.  
  445. /*
  446.     The hyphen and dash control things are treated as though they
  447.     were rtfText here.
  448.  
  449.     An extra level of indirection is added to the page number register.
  450. */
  451.  
  452. static void SpecialChar ()
  453. {
  454. char    buf[rtfBufSiz];
  455.  
  456.     switch (rtfMinor)
  457.     {
  458.     case rtfCurHeadPage:
  459.         PutString ("\\\\n%");    /* reference page number register */
  460.         break;
  461.     case rtfCurHeadDate:
  462.         /* unimplemented */
  463.         break;
  464.     case rtfCurHeadTime:
  465.         /* unimplemented */
  466.         break;
  467.     case rtfNoBrkSpace:
  468.         PutString ("\\ ");
  469.         break;
  470.     case rtfNoReqHyphen:
  471.         PutString ("\\%");
  472.         break;
  473.     case rtfNoBrkHyphen:
  474.         PutString ("\\-");
  475.         break;
  476.     case rtfSect:
  477.         Sect ();
  478.         break;
  479.     case rtfRow:        /* end of cell, and of row/table */
  480.         EndCell ();
  481.         EndTbl ();
  482.         break;
  483.     case rtfLine:
  484.         Par ();
  485.         break;
  486.     case rtfPar:
  487.         Par ();
  488.         break;
  489.     case rtfCell:
  490.         EndCell ();        /* end current cell */
  491.         BeginCell ();        /* begin next cell */
  492.         break;
  493.     case rtfTab:
  494.         PutString ("\t");
  495.         break;
  496.     case rtfPage:
  497.         Par ();
  498.         fprintf (f, ".bp\n");
  499.         break;
  500.     }
  501. }
  502.  
  503.  
  504. /*
  505.     Begin/End destination don't try to do anything except dump
  506.     out comments delimiting the destination.  Something "real"
  507.     should be done, but at least the comment is better than nothing.
  508.  
  509.     The switch explicitly lists those destinations for which something
  510.     intelligent should be done.  (But nothing is, yet.)  Everything
  511.     else falls under the default case and is simply skipped anonymously.
  512.     
  513.     When a destination is skipped, the "}" is fed back into the router
  514.     so the group state gets popped by Group().
  515. */
  516.  
  517. static void BeginDestination ()
  518. {
  519.     Destination (1);
  520. }
  521.  
  522.  
  523. static void EndDestination ()
  524. {
  525.     Destination (0);
  526. }
  527.  
  528.  
  529. static void Destination (startDest)
  530. int    startDest;
  531. {
  532. char    *dp = (char *) NULL;    /* destination name */
  533. char    *mp = (char *) NULL;    /* macro name */
  534. char    *rp = (char *) NULL;    /* register name */
  535. char    *sp = (char *) NULL;    /* skipped destination name */
  536. int    reset = 0;    /* need reset to defaults? */
  537.  
  538.     /* if beginning destination, set dest type */
  539.     if (startDest)
  540.         is->destination = rtfMinor;
  541.     /* switch on destination type */
  542.     switch (is->destination)
  543.     {
  544.     case rtfFootnote:
  545.         /*
  546.             Don't skip, but don't start diversion: effect is to
  547.             leave footnote text in main document body.  Incorrect,
  548.             but better than losing it.  Eventually, footnotes
  549.             should be caught in diversions.
  550.         */
  551.         dp = "footnote";
  552.         break;
  553.     case rtfHeader:
  554.         dp = "header";
  555.         mp = mHeaderAll;
  556.         rp = rHeaderAll;
  557.         ++reset;
  558.         break;
  559.     case rtfHeaderLeft:
  560.         dp = "left header";
  561.         mp = mHeaderLeft;
  562.         rp = rHeaderLeft;
  563.         ++reset;
  564.         break;
  565.     case rtfHeaderRight:
  566.         dp = "right header";
  567.         mp = mHeaderRight;
  568.         rp = rHeaderRight;
  569.         ++reset;
  570.         break;
  571.     case rtfHeaderFirst:
  572.         dp = "first page header";
  573.         mp = mHeaderFirst;
  574.         rp = rHeaderFirst;
  575.         ++reset;
  576.         break;
  577.     case rtfFooter:
  578.         dp = "footer";
  579.         mp = mFooterAll;
  580.         rp = rFooterAll;
  581.         ++reset;
  582.         break;
  583.     case rtfFooterLeft:
  584.         dp = "left footer";
  585.         mp = mFooterLeft;
  586.         rp = rFooterLeft;
  587.         ++reset;
  588.         break;
  589.     case rtfFooterRight:
  590.         dp = "right footer";
  591.         mp = mFooterRight;
  592.         rp = rFooterRight;
  593.         ++reset;
  594.         break;
  595.     case rtfFooterFirst:
  596.         dp = "first page footer";
  597.         mp = mFooterFirst;
  598.         rp = rFooterFirst;
  599.         ++reset;
  600.         break;
  601.     case rtfFNSep:
  602.         sp = "footnote separator";
  603.         break;
  604.     case rtfFNContSep:
  605.         sp = "continued footnote separator";
  606.         break;
  607.     case rtfFNContNotice:
  608.         sp = "continued footnote notice";
  609.         break;
  610.     case rtfField:            /* don't ignore, but don't capture */
  611.         dp = "field";
  612.         break;
  613.     case rtfFieldInst:        /* ignore */
  614.         sp = "field instruction";
  615.         break;
  616.     case rtfFieldResult:        /* don't ignore, but don't capture */
  617.         dp = "field result";
  618.         break;
  619.     default:
  620.         sp = rtfTextBuf;
  621.         break;
  622.     }
  623.  
  624.     if (dp != (char *) NULL && startDest)
  625.         Comment ("begin %s", dp);
  626.     if (mp != (char *) NULL)        /* begin a capture macro */
  627.     {
  628.         Flush ();
  629.         if (startDest)
  630.         {
  631.             FlushInitialState ();    /* make sure this is out */
  632.             FlushSectState ();    /* flush trap positions */
  633.             if (rp != (char *) NULL)/* set a register */
  634.                 fprintf (f, ".nr %s 1\n", rp);
  635.             BeginDiversion (mp);
  636.             if (reset)
  637.             {
  638.                 /* reset paragraph, char defaults */
  639.                 /* (fake a \pard and \plain) */
  640.                 RTFSetToken (rtfControl, rtfParAttr,
  641.                         rtfParDef, -1, "\\pard");
  642.                 RTFRouteToken ();
  643.                 RTFSetToken (rtfControl, rtfCharAttr,
  644.                         rtfPlain, -1, "\\plain");
  645.                 RTFRouteToken ();
  646.             }
  647.         }
  648.         else
  649.         {
  650.             EndDiversion ();
  651.         }
  652.     }
  653.     if (sp != (char *) NULL)    /* skip a group */
  654.     {
  655.         if (startDest)
  656.         {
  657.             Comment ("SKIPPING %s group", sp);
  658.             RTFSkipGroup ();
  659.             RTFRouteToken ();    /* feed "}" back into router */
  660.         }
  661.         else
  662.             Comment ("end skipped group");
  663.     }
  664.     if (dp != (char *) NULL && startDest == 0)
  665.         Comment ("end %s", dp);
  666. }
  667.  
  668.  
  669. static void DocAttr ()
  670. {
  671. double    inch = (double) rtfParam / (double) rtfTpi;
  672.  
  673.     switch (rtfMinor)
  674.     {
  675.     case rtfPaperWidth:
  676.         ids->pageWidth = inch;
  677.         break;
  678.     case rtfPaperHeight:
  679.         ids->pageHeight = inch;
  680.         break;
  681.     case rtfLeftMargin:
  682.         ids->leftMargin = inch;
  683.         break;
  684.     case rtfRightMargin:
  685.         ids->rightMargin = inch;
  686.         break;
  687.     case rtfTopMargin:
  688.         ids->topMargin = inch;
  689.         /* pre-emptive strike */
  690.         if (iss->headerPos >= ids->topMargin)
  691.             iss->headerPos = ids->topMargin / 2;
  692.         break;
  693.     case rtfBottomMargin:
  694.         ids->bottomMargin = inch;
  695.         if (iss->footerPos >= ids->bottomMargin)
  696.             iss->footerPos = ids->bottomMargin / 2;
  697.         break;
  698.     case rtfDefTab:
  699.         ids->tabWidth = inch;
  700.         break;
  701.     case rtfLandscape:
  702.         ids->landscape = 1;
  703.         break;
  704.     }
  705.     ++docStateChanged;
  706. }
  707.  
  708.  
  709. static void SectAttr ()
  710. {
  711. double    inch = (double) rtfParam / (double) rtfTpi;
  712.  
  713.     switch (rtfMinor)
  714.     {
  715.     case rtfSectDef:
  716.         RestoreSectDefaults ();
  717.         break;
  718.     case rtfNoBreak:
  719.     case rtfColBreak:
  720.     case rtfPageBreak:
  721.     case rtfEvenBreak:
  722.     case rtfOddBreak:
  723.         iss->breakType = rtfMinor;
  724.         break;
  725.     case rtfPageStarts:
  726.         iss->pageStart = rtfParam;
  727.         break;
  728.     case rtfPageCont:
  729.         iss->pageRestart = 0;
  730.         break;
  731.     case rtfPageRestart:
  732.         iss->pageRestart = 1;
  733.         break;
  734.     case rtfPageDecimal:
  735.         Flush ();
  736.         fprintf (f, ".af %% 1\n");
  737.         break;
  738.     case rtfPageURoman:
  739.         Flush ();
  740.         fprintf (f, ".af %% I\n");
  741.         break;
  742.     case rtfPageLRoman:
  743.         Flush ();
  744.         fprintf (f, ".af %% i\n");
  745.         break;
  746.     case rtfPageULetter:
  747.         Flush ();
  748.         fprintf (f, ".af %% A\n");
  749.         break;
  750.     case rtfPageLLetter:
  751.         Flush ();
  752.         fprintf (f, ".af %% a\n");
  753.         break;
  754.     case rtfPageNumLeft:
  755.         break;
  756.     case rtfPageNumTop:
  757.         break;
  758.     case rtfHeaderY:
  759.         iss->headerPos = inch;
  760.         if (iss->headerPos >= ids->topMargin)
  761.             iss->headerPos = ids->topMargin / 2;
  762.         break;
  763.     case rtfFooterY:
  764.         iss->footerPos = inch;
  765.         if (iss->footerPos >= ids->bottomMargin)
  766.             iss->footerPos = ids->bottomMargin / 2;
  767.         break;
  768.     case rtfLineModulus:
  769.         break;
  770.     case rtfLineDist:
  771.         break;
  772.     case rtfLineStarts:
  773.         break;
  774.     case rtfLineRestart:
  775.         break;
  776.     case rtfLineRestartPg:
  777.         break;
  778.     case rtfLineCont:
  779.         break;
  780.     case rtfTopVAlign:
  781.         break;
  782.     case rtfBottomVAlign:
  783.         break;
  784.     case rtfCenterVAlign:
  785.         break;
  786.     case rtfJustVAlign:
  787.         break;
  788.     case rtfColumns:
  789.         break;
  790.     case rtfColumnSpace:
  791.         break;
  792.     case rtfColumnLine:
  793.         break;
  794.     case rtfENoteHere:
  795.         break;
  796.     case rtfTitleSpecial:
  797.         iss->titleSpecial = 1;
  798.         break;
  799.     }
  800.     ++sectStateChanged;
  801. }
  802.  
  803.  
  804. /*
  805.     Paragraph defaults are restored by using the state 0 values,
  806.     they applying the "Normal" style (style 0).
  807.  
  808.     For the rtfStyleNum, the tab flag is reset before expanding the
  809.     style so any inherited tabs will be overridden by tabs in the
  810.     style, and reset after expansion so any tabs in the paragraph
  811.     itself will override inherited or style tabs.
  812.  
  813.     The "unimplemented" cases below are those which are currently
  814.     ignored, but for which something might be done someday, i.e.,
  815.     they're reminders.
  816. */
  817.  
  818. static void ParAttr ()
  819. {
  820. double    inch = (double) rtfParam / (double) rtfTpi;
  821.  
  822.     switch (rtfMinor)
  823.     {
  824.     case rtfParDef:
  825.         RestoreParDefaults ();
  826.         break;
  827.     case rtfStyleNum:
  828.         ips->tabFlag = 0;
  829.         RTFExpandStyle (rtfParam);
  830.         ips->tabFlag = 0;
  831.         break;
  832.     case rtfQuadLeft:
  833.     case rtfQuadRight:
  834.     case rtfQuadJust:
  835.     case rtfQuadCenter:
  836.         ips->justification = rtfMinor;
  837.         break;
  838.     case rtfFirstIndent:
  839.         ips->firstIndent = inch;
  840.         break;
  841.     case rtfLeftIndent:
  842.         ips->leftIndent = inch;
  843.         break;
  844.     case rtfRightIndent:
  845.         ips->rightIndent = inch;
  846.         break;
  847.     case rtfSpaceBefore:
  848.         ips->spaceBefore = inch;
  849.         break;
  850.     case rtfSpaceAfter:
  851.         ips->spaceAfter = inch;
  852.         break;
  853.     case rtfSpaceBetween:
  854.         ips->spaceBetween = inch;
  855.         break;
  856.     case rtfInTable:
  857.         haveTables = 1;
  858.         /*
  859.             If first cell of row, set temp indent to left edge
  860.             of table.  (Actually, this is done incorrectly; tables
  861.             are always centered.)
  862.             Subsequent cells are begun when \cell is seen.
  863.         */
  864.         if (its->tableHeader == 0)    /* first cell; need */
  865.         {                /* table prolog */
  866.             BeginTbl ();
  867.             BeginCell ();
  868.         }
  869.         break;
  870.     case rtfNoLineNum:
  871.         /* unimplemented */
  872.         break;
  873.     case rtfTabPos:
  874.         SetNextTabPos (inch);
  875.         break;
  876.     case rtfTabRight:
  877.     case rtfTabCenter:
  878.     case rtfTabDecimal:
  879.         SetNextTabType (rtfMinor);
  880.         break;
  881.     case rtfTabBar:
  882.         /* unimplemented */
  883.         break;
  884.     case rtfBorderTop:
  885.         ips->borderFlags |= borderTop;
  886.         break;
  887.     case rtfBorderBottom:
  888.         ips->borderFlags |= borderBottom;
  889.         break;
  890.     case rtfBorderLeft:
  891.         /* unimplemented */
  892.         break;
  893.     case rtfBorderRight:
  894.         /* unimplemented */
  895.         break;
  896.     case rtfBorderBar:
  897.         /* unimplemented */
  898.         break;
  899.     case rtfBorderBox:
  900.         /* unimplemented */
  901.         break;
  902.     case rtfBorderBetween:
  903.         /* unimplemented */
  904.         break;
  905.     case rtfBorderSingle:
  906.     case rtfBorderThick:
  907.     case rtfBorderShadow:
  908.     case rtfBorderDouble:
  909.     case rtfBorderDot:
  910.     case rtfBorderHair:
  911.         ips->borderType = rtfMinor;
  912.         break;
  913.     case rtfBorderSpace:
  914.         /* unimplemented */
  915.         break;
  916.     case rtfLeaderDot:
  917.     case rtfLeaderHyphen:
  918.     case rtfLeaderUnder:
  919.     case rtfLeaderThick:
  920.         SetTabChar (rtfMinor);
  921.         break;
  922.     }
  923.     ++parStateChanged;
  924. }
  925.  
  926.  
  927. /*
  928.     Several of the attributes can be turned off with param value
  929.     of zero (e.g., \b vs. \b0), but since the value of rtfParam
  930.     is 0 if no param is given, test the text of the token directly.
  931.     to find out if there's a zero at the end of it.
  932.  
  933.     \plain is like \pard but for characters, i.e, it restores all
  934.     character defaults.
  935. */
  936.  
  937. static void CharAttr ()
  938. {
  939. int    turnOn = (rtfTextBuf[rtfTextLen-1] != '0');
  940.  
  941.     switch (rtfMinor)
  942.     {
  943.     case rtfPlain:
  944.         RestoreCharDefaults ();
  945.         break;
  946.     case rtfBold:
  947.         if (turnOn)
  948.             ics->charStyle |= styleBold;
  949.         else
  950.             ics->charStyle &= ~styleBold;
  951.         break;
  952.     case rtfItalic:
  953.         if (turnOn)
  954.             ics->charStyle |= styleItalic;
  955.         else
  956.             ics->charStyle &= ~styleItalic;
  957.         break;
  958.     case rtfStrikeThru:
  959.         if (allowStrikeThru)
  960.         {
  961.             if (turnOn)
  962.                 ics->charStyle |= styleStrikeThru;
  963.             else
  964.                 ics->charStyle &= ~styleStrikeThru;
  965.         }
  966.         break;
  967.     case rtfOutline:
  968.         if (turnOn)
  969.             ics->charStyle |= styleOutline;
  970.         else
  971.             ics->charStyle &= ~styleOutline;
  972.         break;
  973.     case rtfShadow:
  974.         if (turnOn)
  975.             ics->charStyle |= styleShadow;
  976.         else
  977.             ics->charStyle &= ~styleShadow;
  978.         break;
  979.     case rtfSmallCaps:
  980.         if (turnOn)
  981.             ics->charStyle |= styleSmallCaps;
  982.         else
  983.             ics->charStyle &= ~styleSmallCaps;
  984.         break;
  985.     case rtfAllCaps:
  986.         if (turnOn)
  987.             ics->charStyle |= styleAllCaps;
  988.         else
  989.             ics->charStyle &= ~styleAllCaps;
  990.         break;
  991.     case rtfInvisible:
  992.         if (turnOn)
  993.             ics->charStyle |= styleInvisible;
  994.         else
  995.             ics->charStyle &= ~styleInvisible;
  996.         break;
  997.     case rtfFontNum:
  998.         /* unimplemented */
  999.         break;
  1000.     case rtfFontSize:
  1001.         /* sizes are in half-points, convert to whole points */
  1002.         ics->fontSize = (int) (rtfParam / 2);
  1003.         if (ics->fontSize <= 0)
  1004.             ++ics->fontSize;    /* don't play with fire */
  1005.         break;
  1006.     case rtfExpand:
  1007.         /* unimplemented */
  1008.         break;
  1009.     case rtfUnderline:
  1010.         if (allowUnderline)
  1011.         {
  1012.             if (turnOn)
  1013.                 ics->charStyle |= styleUnderline;
  1014.             else
  1015.                 ics->charStyle &= ~styleUnderline;
  1016.         }
  1017.         break;
  1018.     case rtfWUnderline:
  1019.         if (allowUnderline)
  1020.         {
  1021.             if (turnOn)
  1022.                 ics->charStyle |= styleWUnderline;
  1023.             else
  1024.                 ics->charStyle &= ~styleWUnderline;
  1025.         }
  1026.         break;
  1027.     case rtfDUnderline:
  1028.         /* unimplemented */
  1029.         break;
  1030.     case rtfDbUnderline:
  1031.         /* unimplemented */
  1032.         break;
  1033.     case rtfNoUnderline:
  1034.         ics->charStyle &= ~styleUnderline;
  1035.         ics->charStyle &= ~styleWUnderline;
  1036.         break;
  1037.     case rtfSuperScript:
  1038.         /* superscripts are in half-points, convert to points */
  1039.         ics->superScript = rtfParam / 2;
  1040.         break;
  1041.     case rtfSubScript:
  1042.         /* subscripts are in half-points, convert to points */
  1043.         ics->subScript = rtfParam / 2;
  1044.         break;
  1045.     case rtfRevised:
  1046.         /* unimplemented */
  1047.         break;
  1048.     case rtfForeColor:
  1049.         /* unimplemented */
  1050.         break;
  1051.     case rtfBackColor:
  1052.         /* unimplemented */
  1053.         break;
  1054.     }
  1055.     ++charStateChanged;
  1056. }
  1057.  
  1058.  
  1059. /* ---------------------------------------------------------------------- */
  1060.  
  1061. /*
  1062.     Tab handling routines
  1063. */
  1064.  
  1065. void InitTabSet ()
  1066. {
  1067. int    i;
  1068.  
  1069.     ips->nTabs = 0;
  1070.     /*
  1071.         Set all tabs to be left-justified; that will then be used if
  1072.         no other tab type is specified.  This is done because the
  1073.         position is specified *after* the type.
  1074.     */
  1075.     for (i = 0; i < maxTab; i++)
  1076.         ips->tabType[i] = rtfTabLeft;
  1077. }
  1078.  
  1079.  
  1080. static void SetNextTabPos (pos)
  1081. double    pos;
  1082. {
  1083.     if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
  1084.         fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
  1085.                             maxTab);
  1086.     else
  1087.     {
  1088.         /* if no tab info has been set for this state, reinit them */
  1089.         if (ips->tabFlag == 0)
  1090.         {
  1091.             InitTabSet ();
  1092.             ips->tabFlag = 1;
  1093.         }
  1094.         ips->tab[ips->nTabs++] = pos;
  1095.     }
  1096. }
  1097.  
  1098.  
  1099. /*
  1100.     Tab types are specified *before* the position to which they apply
  1101.     is given, so set the next available slot in anticipation of the
  1102.     position's being specified next.
  1103. */
  1104.  
  1105. static void SetNextTabType (type)
  1106. int    type;
  1107. {
  1108.     if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
  1109.         fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
  1110.                             maxTab);
  1111.     else
  1112.     {
  1113.         /* if no tab info has been set for this state, reinit them */
  1114.         if (ips->tabFlag == 0)
  1115.         {
  1116.             InitTabSet ();
  1117.             ips->tabFlag = 1;
  1118.         }
  1119.         ips->tabType[ips->nTabs] = type;
  1120.     }
  1121. }
  1122.  
  1123.  
  1124. static void SetTabChar (leader)
  1125. int    leader;
  1126. {
  1127.     if (ips->tabFlag != 0 && ips->nTabs >= maxTab)
  1128.         fprintf (stderr, "maximum tabstop count (%d) exceeded\n",
  1129.                             maxTab);
  1130.     else
  1131.     {
  1132.         /* if no tab info has been set for this state, reinit them */
  1133.         if (ips->tabFlag == 0)
  1134.         {
  1135.             InitTabSet ();
  1136.             ips->tabFlag = 1;
  1137.         }
  1138.         ips->tabChar = rtfMinor;
  1139.     }
  1140. }
  1141.