summaryrefslogtreecommitdiff
path: root/support/RTF-1_06a1/reader.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/RTF-1_06a1/reader.c
Initial commit
Diffstat (limited to 'support/RTF-1_06a1/reader.c')
-rw-r--r--support/RTF-1_06a1/reader.c1380
1 files changed, 1380 insertions, 0 deletions
diff --git a/support/RTF-1_06a1/reader.c b/support/RTF-1_06a1/reader.c
new file mode 100644
index 0000000000..c3ed341bf5
--- /dev/null
+++ b/support/RTF-1_06a1/reader.c
@@ -0,0 +1,1380 @@
+/*
+ reader.c - RTF file reader. Distribution 1.06.
+
+ ASCII 10 (\n) and 13 (\r) are ignored and silently discarded.
+ (The read hook will still get a look at them.)
+
+ "\:" is not a ":", it's a control symbol. But some versions of
+ Word seem to write "\:" for ":". This reader treats "\:" as a
+ plain text ":"
+
+ This reader needs to catch \cf and \cb in the color table
+ reader? (Doesn't yet.)
+*/
+
+# include <stdio.h>
+# include <ctype.h>
+# include "rtf.h"
+
+
+/*
+ Return pointer to new element of type t, or NULL
+*/
+
+# define New(t) ((t *) RTFAlloc (sizeof (t)))
+
+
+extern char *index ();
+extern char *malloc ();
+extern char *strcpy ();
+
+
+/*
+ Public variables (listed in rtf.h)
+*/
+
+char rtfTextBuf[rtfBufSiz];
+int rtfTextLen;
+int rtfClass;
+int rtfMajor;
+int rtfMinor;
+int rtfParam;
+
+
+/*
+ Private stuff
+*/
+
+
+static RTFFont *fontList = NULL; /* these lists MUST be */
+static RTFColor *colorList = NULL; /* initialized to NULL */
+static RTFStyle *styleList = NULL;
+
+
+static FILE *rtffp = stdin;
+
+static int pushback = EOF;
+
+
+static void _RTFGetToken ();
+static int GetChar ();
+static int HexVal ();
+static void ReadFontTbl ();
+static void ReadColorTbl ();
+static void ReadStyleSheet ();
+static void ReadInfoGroup ();
+static void ReadPictGroup ();
+static void LookupInit ();
+static void Lookup ();
+static int Hash ();
+
+
+/*
+ Initialize the reader. This may be called multiple times.
+ The only thing not reset is the input stream.
+*/
+
+void RTFInit ()
+{
+int i;
+RTFColor *cp;
+RTFFont *fp;
+RTFStyle *sp;
+RTFStyleElt *eltList, *ep;
+
+ /* initialize lookup table */
+ LookupInit ();
+
+ for (i = 0; i < rtfMaxClass; i++)
+ RTFSetClassCallback (i, NULL);
+ for (i = 0; i < rtfMaxDestination; i++)
+ RTFSetDestinationCallback (i, NULL);
+
+ /* install built-in destination readers */
+ RTFSetDestinationCallback (rtfFontTbl, ReadFontTbl);
+ RTFSetDestinationCallback (rtfColorTbl, ReadColorTbl);
+ RTFSetDestinationCallback (rtfStyleSheet, ReadStyleSheet);
+ RTFSetDestinationCallback (rtfInfo, ReadInfoGroup);
+ RTFSetDestinationCallback (rtfPict, ReadPictGroup);
+
+ RTFSetReadHook (NULL);
+
+ /* dump old lists if necessary */
+
+ while (fontList != NULL)
+ {
+ fp = fontList->rtfNextFont;
+ RTFFree (fontList->rtfFName);
+ RTFFree ((char *) fontList);
+ fontList = fp;
+ }
+ while (colorList != NULL)
+ {
+ cp = colorList->rtfNextColor;
+ RTFFree ((char *) colorList);
+ colorList = cp;
+ }
+ while (styleList != NULL)
+ {
+ sp = styleList->rtfNextStyle;
+ eltList = styleList->rtfSSEList;
+ while (eltList != NULL)
+ {
+ ep = eltList->rtfNextSE;
+ RTFFree (eltList->rtfSEText);
+ RTFFree ((char *) eltList);
+ eltList = ep;
+ }
+ RTFFree (styleList->rtfSName);
+ RTFFree ((char *) styleList);
+ styleList = sp;
+ }
+
+ pushback = EOF;
+}
+
+
+/*
+ Set the reader's input stream to the given stream. Can
+ be used to redirect other than to the default (stdin).
+*/
+
+void RTFSetStream (stream)
+FILE *stream;
+{
+ rtffp = stream;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Callback table manipulation routines
+*/
+
+
+/*
+ Install or return a writer callback for a token class
+*/
+
+static void (*ccb[rtfMaxClass]) (); /* class callbacks */
+
+void RTFSetClassCallback (class, callback)
+int class;
+void (*callback) ();
+{
+ if (class >= 0 && class < rtfMaxClass)
+ ccb[class] = callback;
+}
+
+
+void (*RTFGetClassCallback (class)) ()
+int class;
+{
+ if (class >= 0 && class < rtfMaxClass)
+ return (ccb[class]);
+ return (NULL);
+}
+
+
+/*
+ Install or return a writer callback for a destination type
+*/
+
+static void (*dcb[rtfMaxDestination]) (); /* destination callbacks */
+
+void RTFSetDestinationCallback (dest, callback)
+int dest;
+void (*callback) ();
+{
+ if (dest >= 0 && dest < rtfMaxDestination)
+ dcb[dest] = callback;
+}
+
+
+void (*RTFGetDestinationCallback (dest)) ()
+int dest;
+{
+ if (dest >= 0 && dest < rtfMaxDestination)
+ return (dcb[dest]);
+ return (NULL);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Token reading routines
+*/
+
+
+/*
+ Read the input stream, invoking the writer's callbacks
+ where appropriate.
+*/
+
+void RTFRead ()
+{
+ while (RTFGetToken () != rtfEOF)
+ RTFRouteToken ();
+}
+
+
+/*
+ Route a token. If it's a destination for which a reader is
+ installed, process the destination internally, otherwise
+ pass the token to the writer's class callback.
+*/
+
+void RTFRouteToken ()
+{
+void (*p) ();
+
+ if (rtfClass < 0 || rtfClass >= rtfMaxClass) /* watchdog */
+ {
+ fprintf (stderr, "Unknown class %d: %s", rtfClass, rtfTextBuf);
+ fprintf (stderr, " (reader malfunction)\n");
+ return;
+ }
+ if (RTFCheckCM (rtfControl, rtfDestination))
+ {
+ /* invoke destination-specific callback if there is one */
+ if ((p = RTFGetDestinationCallback (rtfMinor)) != NULL)
+ {
+ (*p) ();
+ return;
+ }
+ }
+ /* invoke class callback if there is one */
+ if ((p = RTFGetClassCallback (rtfClass)) != NULL)
+ (*p) ();
+}
+
+
+/*
+ Skip to the end of the current group. When this returns,
+ writers that maintain a state stack may want to call their
+ state unstacker; global vars will still be set to the group's
+ closing brace.
+*/
+
+void RTFSkipGroup ()
+{
+int level = 1;
+
+ while (RTFGetToken () != rtfEOF)
+ {
+ if (rtfClass == rtfGroup)
+ {
+ if (rtfMajor == rtfBeginGroup)
+ ++level;
+ else if (rtfMajor == rtfEndGroup)
+ {
+ if (--level < 1)
+ break; /* end of initial group */
+ }
+ }
+ }
+}
+
+
+/*
+ Read one token. Call the read hook if there is one. The
+ token class is the return value. Returns rtfEOF when there
+ are no more tokens.
+*/
+
+int RTFGetToken ()
+{
+void (*p) ();
+
+ for (;;)
+ {
+ _RTFGetToken ();
+ if ((p = RTFGetReadHook ()) != NULL)
+ (*p) (); /* give read hook a look at token */
+
+ /* Silently discard newlines and carriage returns. */
+ if (!(rtfClass == rtfText
+ && (rtfMajor == '\n' || rtfMajor == '\r')))
+ break;
+ }
+ return (rtfClass);
+}
+
+
+/*
+ Install or return a token reader hook.
+*/
+
+static void (*readHook) ();
+
+void RTFSetReadHook (f)
+void (*f) ();
+{
+ readHook = f;
+}
+
+
+void (*RTFGetReadHook ()) ()
+{
+ return (readHook);
+}
+
+
+static void _RTFGetToken ()
+{
+int sign;
+int c;
+
+ /* initialize token vars */
+
+ rtfClass = rtfUnknown;
+ rtfParam = 0;
+ rtfTextBuf[rtfTextLen = 0] = '\0';
+
+ /* get first character, which may be a pushback from previous token */
+
+ if (pushback != EOF)
+ {
+ c = pushback;
+ rtfTextBuf[rtfTextLen] = c;
+ rtfTextBuf[++rtfTextLen] = '\0';
+ pushback = EOF;
+ }
+ else if ((c = GetChar ()) == EOF)
+ {
+ rtfClass = rtfEOF;
+ return;
+ }
+
+ if (c == '{')
+ {
+ rtfClass = rtfGroup;
+ rtfMajor = rtfBeginGroup;
+ return;
+ }
+ if (c == '}')
+ {
+ rtfClass = rtfGroup;
+ rtfMajor = rtfEndGroup;
+ return;
+ }
+ if (c != '\\')
+ {
+ /*
+ Two possibilities here:
+ 1) ASCII 9, effectively like \tab control symbol
+ 2) literal text char
+ */
+ if (c == '\t') /* ASCII 9 */
+ {
+ rtfClass = rtfControl;
+ rtfMajor = rtfTab;
+ }
+ else
+ {
+ rtfClass = rtfText;
+ rtfMajor = c;
+ }
+ return;
+ }
+ if ((c = GetChar ()) == EOF)
+ {
+ /* early eof, whoops (class is rtfUnknown) */
+ return;
+ }
+ if (!isalpha (c))
+ {
+ /*
+ Three possibilities here:
+ 1) hex encoded text char, e.g., \'d5, \'d3
+ 2) special escaped text char, e.g., \{, \}
+ 3) control symbol, e.g., \_, \-, \|, \<10>
+ */
+ if (c == '\'') /* hex char */
+ {
+ int c2;
+
+ if ((c = GetChar ()) != EOF && (c2 = GetChar ()) != EOF)
+ {
+ /* should do isxdigit check! */
+ rtfClass = rtfText;
+ rtfMajor = HexVal (c) * 16 + HexVal (c2);
+ return;
+ }
+ /* early eof, whoops (class is rtfUnknown) */
+ return;
+ }
+
+ if (index (":{}\\", c) != NULL) /* escaped char */
+ {
+ rtfClass = rtfText;
+ rtfMajor = c;
+ return;
+ }
+
+ /* control symbol */
+ Lookup (rtfTextBuf); /* sets class, major, minor */
+ return;
+ }
+ /* control word */
+ while (isalpha (c))
+ {
+ if ((c = GetChar ()) == EOF)
+ break;
+ }
+
+ /*
+ At this point, the control word is all collected, so the
+ major/minor numbers are determined before the parameter
+ (if any) is scanned. There will be one too many characters
+ in the buffer, though, so fix up before and restore after
+ looking up.
+ */
+
+ if (c != EOF)
+ rtfTextBuf[rtfTextLen-1] = '\0';
+ Lookup (rtfTextBuf); /* sets class, major, minor */
+ if (c != EOF)
+ rtfTextBuf[rtfTextLen-1] = c;
+
+ /*
+ Should be looking at first digit of parameter if there
+ is one, unless it's negative. In that case, next char
+ is '-', so need to gobble next char, and remember sign.
+ */
+
+ sign = 1;
+ if (c == '-')
+ {
+ sign = -1;
+ c = GetChar ();
+ }
+ if (c != EOF)
+ {
+ while (isdigit (c)) /* gobble parameter */
+ {
+ rtfParam = rtfParam * 10 + c - '0';
+ if ((c = GetChar ()) == EOF)
+ break;
+ }
+ rtfParam *= sign;
+ }
+ /*
+ If control symbol delimiter was a blank, gobble it.
+ Otherwise the character is first char of next token, so
+ push it back for next call. In either case, delete the
+ delimiter from the token buffer.
+ */
+ if (c != EOF)
+ {
+ if (c != ' ')
+ pushback = c;
+ rtfTextBuf[--rtfTextLen] = '\0';
+ }
+ return;
+}
+
+
+/*
+ Distributions up through 1.04 assumed high bit could be set in
+ RTF file characters. Beginning with 1.05, that's not true, but
+ still check and die if such a character is found.
+*/
+
+static int GetChar ()
+{
+int c;
+
+ if ((c = getc (rtffp)) != EOF)
+ {
+ if (c & 0x80)
+ {
+ fprintf (stderr, "Char with high bit set (%#x) found\n", c);
+ exit (1);
+ }
+ rtfTextBuf[rtfTextLen] = c;
+ rtfTextBuf[++rtfTextLen] = '\0';
+ }
+ return (c);
+}
+
+
+static int HexVal (c)
+char c;
+{
+ if (isupper (c))
+ c = tolower (c);
+ if (isdigit (c))
+ return (c - '0'); /* '0'..'9' */
+ return (c - 'a' + 10); /* 'a'..'f' */
+}
+
+
+/*
+ Synthesize a token by setting the global variables to the
+ values supplied. Typically this is followed with a call
+ to RTFRouteToken().
+
+ If param is non-negative, it becomes part of the token text.
+*/
+
+void RTFSetToken (class, major, minor, param, text)
+int class, major, minor, param;
+char *text;
+{
+ rtfClass = class;
+ rtfMajor = major;
+ rtfMinor = minor;
+ rtfParam = param;
+ if (param >= 0)
+ sprintf (rtfTextBuf, "%s%d", text, param);
+ else
+ strcpy (rtfTextBuf, text);
+ rtfTextLen = strlen (rtfTextBuf);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Special destination readers. They gobble the destination so the
+ writer doesn't have to deal with them. That's wrong for any
+ translator that wants to process any of these itself. In that
+ case, these readers should be overridden by installing a different
+ destination callback.
+
+ The last token read by each of these reader will be the destination's
+ terminating '}', which will then be the current token. That token
+ is passed to RTFRouteToken() - the writer had already seen the '{'
+ that began the destination grou, and may have pushed a state; it also
+ needs to know at the end of the group that a state should be popped.
+
+ It's important that rtf.h and the control token lookup table list
+ as many symbols as possible, because these readers unfortunately
+ make strict assumptions about the input they expect, and a token
+ of class rtfUnknown will throw them off easily.
+*/
+
+
+/*
+ Read { \fonttbl ... } destination. Old font tables don't have
+ braces around each table entry; try to adjust for that.
+*/
+
+static void ReadFontTbl ()
+{
+RTFFont *fp;
+char buf[rtfBufSiz], *bp;
+int old = -1;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if (old < 0) /* first entry - determine tbl type */
+ {
+ if (RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
+ old = 1; /* no brace */
+ else if (RTFCheckCM (rtfGroup, rtfBeginGroup))
+ old = 0; /* brace */
+ else
+ { /* can't tell! */
+ fprintf (stderr, "Bad font table-1\n");
+ exit (1);
+ }
+ }
+ if (old == 0) /* need to find "{" here */
+ {
+ if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
+ {
+ fprintf (stderr, "Bad font table-2\n");
+ exit (1);
+ }
+ (void) RTFGetToken (); /* yes, skip to next token */
+ }
+ if ((fp = New (RTFFont)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate font entry\n");
+ exit (1);
+ }
+ fp->rtfNextFont = fontList;
+ fontList = fp;
+ if (!RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
+ {
+ fprintf (stderr, "Bad font table-3\n");
+ exit (1);
+ }
+ fp->rtfFNum = rtfParam;
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfControl, rtfFontFamily))
+ {
+ fprintf (stderr, "Bad font table-4\n");
+ exit (1);
+ }
+ fp->rtfFFamily = rtfMinor;
+ bp = buf;
+ while (RTFGetToken () == rtfText)
+ {
+ if (rtfMajor == ';')
+ break;
+ *bp++ = rtfMajor;
+ }
+ *bp = '\0';
+ if ((fp->rtfFName = RTFStrSave (buf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate font name\n");
+ exit (1);
+ }
+ if (old == 0) /* need to see "}" here */
+ {
+ (void) RTFGetToken ();
+ if (!RTFCheckCM (rtfGroup, rtfEndGroup))
+ {
+ fprintf (stderr, "Bad font table-5\n");
+ exit (1);
+ }
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/*
+ The color table entries have color values of -1 if
+ the default color should be used for the entry (only
+ a semi-colon is given in the definition, no color values).
+ There will be a problem if a partial entry (1 or 2 but
+ not 3 color values) is given. The possibility is ignored
+ here.
+*/
+
+static void ReadColorTbl ()
+{
+RTFColor *cp;
+int cnum = 0;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if ((cp = New (RTFColor)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate color entry\n");
+ exit (1);
+ }
+ cp->rtfCNum = cnum++;
+ cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
+ cp->rtfNextColor = colorList;
+ colorList = cp;
+ for (;;)
+ {
+ if (!RTFCheckCM (rtfControl, rtfColorName))
+ break;
+ switch (rtfMinor)
+ {
+ case rtfRed: cp->rtfCRed = rtfParam; break;
+ case rtfGreen: cp->rtfCGreen = rtfParam; break;
+ case rtfBlue: cp->rtfCBlue = rtfParam; break;
+ }
+ RTFGetToken ();
+ }
+ if (!RTFCheckCM (rtfText, (int) ';'))
+ {
+ fprintf (stderr, "Bad color table\n");
+ exit (1);
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/*
+ The "Normal" style definition doesn't contain any style number
+ (why?), all others do. Normal style is given style 0.
+*/
+
+static void ReadStyleSheet ()
+{
+RTFStyle *sp;
+RTFStyleElt *sep, *sepLast;
+char buf[rtfBufSiz], *bp;
+
+ for (;;)
+ {
+ (void) RTFGetToken ();
+ if (RTFCheckCM (rtfGroup, rtfEndGroup))
+ break;
+ if ((sp = New (RTFStyle)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style entry\n");
+ exit (1);
+ }
+ sp->rtfSNum = -1;
+ sp->rtfSBasedOn = rtfBasedOnNone;
+ sp->rtfSNextPar = -1;
+ sp->rtfSSEList = sepLast = NULL;
+ sp->rtfNextStyle = styleList;
+ sp->rtfExpanding = 0;
+ styleList = sp;
+ if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
+ {
+ fprintf (stderr, "Bad stylesheet-1\n");
+ exit (1);
+ }
+ while (RTFGetToken () == rtfControl)
+ {
+ if (RTFCheckMM (rtfParAttr, rtfStyleNum))
+ {
+ sp->rtfSNum = rtfParam;
+ continue;
+ }
+ if (RTFCheckMM (rtfStyleAttr, rtfBasedOn))
+ {
+ sp->rtfSBasedOn = rtfParam;
+ continue;
+ }
+ if (RTFCheckMM (rtfStyleAttr, rtfNext))
+ {
+ sp->rtfSNextPar = rtfParam;
+ continue;
+ }
+ if ((sep = New (RTFStyleElt)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style element\n");
+ exit (1);
+ }
+ sep->rtfSEClass = rtfClass;
+ sep->rtfSEMajor = rtfMajor;
+ sep->rtfSEMinor = rtfMinor;
+ sep->rtfSEParam = rtfParam;
+ if ((sep->rtfSEText = RTFStrSave (rtfTextBuf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style element\n");
+ exit (1);
+ }
+ if (sepLast == NULL) /* first style element */
+ sp->rtfSSEList = sep;
+ else /* add to end */
+ sepLast->rtfNextSE = sep;
+ sep->rtfNextSE = NULL;
+ sepLast = sep;
+ }
+ if (sp->rtfSNextPar == -1) /* \snext not given */
+ sp->rtfSNextPar = sp->rtfSNum; /* next is itself */
+ if (rtfClass != rtfText)
+ {
+ fprintf (stderr, "Bad stylesheet-2\n");
+ exit (1);
+ }
+ bp = buf;
+ while (rtfClass == rtfText)
+ {
+ if (rtfMajor == ';')
+ {
+ (void) RTFGetToken ();
+ break;
+ }
+ *bp++ = rtfMajor;
+ (void) RTFGetToken ();
+ }
+ *bp = '\0';
+ if (sp->rtfSNum < 0) /* no style number was specified */
+ { /* (only legal for Normal style) */
+ if (strcmp (buf, "Normal") != 0)
+ {
+ fprintf (stderr, "Bad stylesheet-3\n");
+ exit (1);
+ }
+ sp->rtfSNum = 0;
+ }
+ if ((sp->rtfSName = RTFStrSave (buf)) == NULL)
+ {
+ fprintf (stderr, "Can't allocate style name\n");
+ exit (1);
+ }
+ if (!RTFCheckCM (rtfGroup, rtfEndGroup))
+ {
+ fprintf (stderr, "Bad stylesheet-4\n");
+ exit (1);
+ }
+ }
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+static void ReadInfoGroup ()
+{
+ RTFSkipGroup ();
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+static void ReadPictGroup ()
+{
+ RTFSkipGroup ();
+ RTFRouteToken (); /* feed "}" back to router */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Routines to return pieces of stylesheet, or font or color tables
+*/
+
+
+RTFStyle *RTFGetStyle (num)
+int num;
+{
+RTFStyle *s;
+
+ if (num == -1)
+ return (styleList);
+ for (s = styleList; s != NULL; s = s->rtfNextStyle)
+ {
+ if (s->rtfSNum == num)
+ break;
+ }
+ return (s); /* NULL if not found */
+}
+
+
+RTFFont *RTFGetFont (num)
+int num;
+{
+RTFFont *f;
+
+ if (num == -1)
+ return (fontList);
+ for (f = fontList; f != NULL; f = f->rtfNextFont)
+ {
+ if (f->rtfFNum == num)
+ break;
+ }
+ return (f); /* NULL if not found */
+}
+
+
+RTFColor *RTFGetColor (num)
+int num;
+{
+RTFColor *c;
+
+ if (num == -1)
+ return (colorList);
+ for (c = colorList; c != NULL; c = c->rtfNextColor)
+ {
+ if (c->rtfCNum == num)
+ break;
+ }
+ return (c); /* NULL if not found */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ Expand style n, if there is such a style.
+*/
+
+void RTFExpandStyle (n)
+int n;
+{
+RTFStyle *s;
+RTFStyleElt *se;
+
+ if (n == -1 || (s = RTFGetStyle (n)) == NULL)
+ return;
+ if (s->rtfExpanding != 0)
+ {
+ fprintf (stderr, "Style expansion loop, style %d\n", n);
+ exit (1);
+ }
+ s->rtfExpanding = 1; /* set expansion flag for loop detection */
+ /*
+ Expand "based-on" style. This is done by synthesizing
+ the token that the writer needs to see in order to trigger
+ another style expansion, and feeding to token back through
+ the router so the writer sees it.
+ */
+ RTFSetToken (rtfControl, rtfParAttr, rtfStyleNum, s->rtfSBasedOn, "\\s");
+ RTFRouteToken ();
+ /*
+ Now route the tokens unique to this style
+ */
+ for (se = s->rtfSSEList; se != NULL; se = se->rtfNextSE)
+ {
+ rtfClass = se->rtfSEClass;
+ rtfMajor = se->rtfSEMajor;
+ rtfMinor = se->rtfSEMinor;
+ rtfParam = se->rtfSEParam;
+ strcpy (rtfTextBuf, se->rtfSEText);
+ rtfTextLen = strlen (rtfTextBuf);
+ RTFRouteToken ();
+ }
+ s->rtfExpanding = 0; /* done - clear expansion flag */
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Control symbol lookup routines
+*/
+
+
+typedef struct RTFKey RTFKey;
+
+struct RTFKey
+{
+ int rtfKMajor; /* major number */
+ int rtfKMinor; /* minor number */
+ char *rtfKStr; /* symbol name */
+ int rtfKHash; /* symbol name hash value */
+};
+
+/*
+ A minor number of -1 means the token has no minor number
+ (all valid minor numbers are >= 0).
+*/
+
+static RTFKey rtfKey[] =
+{
+ rtfSpecialChar, rtfCurHeadPict, "chpict", 0, /* ?? */
+
+ rtfSpecialChar, rtfCurHeadDate, "chdate", 0,
+ rtfSpecialChar, rtfCurHeadTime, "chtime", 0,
+ rtfSpecialChar, rtfCurHeadPage, "chpgn", 0,
+ rtfSpecialChar, rtfCurFNote, "chftn", 0,
+ rtfSpecialChar, rtfCurAnnotRef, "chatn", 0,
+ rtfSpecialChar, rtfFNoteSep, "chftnsep", 0,
+ rtfSpecialChar, rtfFNoteCont, "chftnsepc", 0,
+ rtfSpecialChar, rtfFormula, "|", 0,
+ rtfSpecialChar, rtfNoBrkSpace, "~", 0,
+ rtfSpecialChar, rtfNoReqHyphen, "-", 0,
+ rtfSpecialChar, rtfNoBrkHyphen, "_", 0,
+ rtfSpecialChar, rtfCell, "cell", 0,
+ rtfSpecialChar, rtfRow, "row", 0,
+ rtfSpecialChar, rtfPar, "par", 0,
+ rtfSpecialChar, rtfPar, "\n", 0,
+ rtfSpecialChar, rtfPar, "\r", 0,
+ rtfSpecialChar, rtfSect, "sect", 0,
+ rtfSpecialChar, rtfPage, "page", 0,
+ rtfSpecialChar, rtfColumn, "column", 0,
+ rtfSpecialChar, rtfLine, "line", 0,
+ rtfSpecialChar, rtfTab, "tab", 0,
+ rtfSpecialChar, rtfOptDest, "*", 0,
+ rtfSpecialChar, rtfIIntVersion, "vern", 0,
+ rtfSpecialChar, rtfICreateTime, "creatim", 0,
+ rtfSpecialChar, rtfIRevisionTime, "revtim", 0,
+ rtfSpecialChar, rtfIPrintTime, "printim", 0,
+ rtfSpecialChar, rtfIBackupTime, "buptim", 0,
+ rtfSpecialChar, rtfIEditTime, "edmins", 0,
+ rtfSpecialChar, rtfIYear, "yr", 0,
+ rtfSpecialChar, rtfIMonth, "mo", 0,
+ rtfSpecialChar, rtfIDay, "dy", 0,
+ rtfSpecialChar, rtfIHour, "hr", 0,
+ rtfSpecialChar, rtfIMinute, "min", 0,
+ rtfSpecialChar, rtfINPages, "nofpages", 0,
+ rtfSpecialChar, rtfINWords, "nofwords", 0,
+ rtfSpecialChar, rtfINChars, "nofchars", 0,
+ rtfSpecialChar, rtfIIntID, "id", 0,
+
+ rtfCharAttr, rtfPlain, "plain", 0,
+ rtfCharAttr, rtfBold, "b", 0,
+ rtfCharAttr, rtfItalic, "i", 0,
+ rtfCharAttr, rtfStrikeThru, "strike", 0,
+ rtfCharAttr, rtfOutline, "outl", 0,
+ rtfCharAttr, rtfShadow, "shad", 0,
+ rtfCharAttr, rtfSmallCaps, "scaps", 0,
+ rtfCharAttr, rtfAllCaps, "caps", 0,
+ rtfCharAttr, rtfInvisible, "v", 0,
+ rtfCharAttr, rtfFontNum, "f", 0,
+ rtfCharAttr, rtfFontSize, "fs", 0,
+ rtfCharAttr, rtfExpand, "expnd", 0,
+ rtfCharAttr, rtfUnderline, "ul", 0,
+ rtfCharAttr, rtfWUnderline, "ulw", 0,
+ rtfCharAttr, rtfDUnderline, "uld", 0,
+ rtfCharAttr, rtfDbUnderline, "uldb", 0,
+ rtfCharAttr, rtfNoUnderline, "ulnone", 0,
+ rtfCharAttr, rtfSuperScript, "up", 0,
+ rtfCharAttr, rtfSubScript, "dn", 0,
+ rtfCharAttr, rtfRevised, "revised", 0,
+ rtfCharAttr, rtfForeColor, "cf", 0,
+ rtfCharAttr, rtfBackColor, "cb", 0,
+
+ rtfParAttr, rtfParDef, "pard", 0,
+ rtfParAttr, rtfStyleNum, "s", 0,
+ rtfParAttr, rtfQuadLeft, "ql", 0,
+ rtfParAttr, rtfQuadRight, "qr", 0,
+ rtfParAttr, rtfQuadJust, "qj", 0,
+ rtfParAttr, rtfQuadCenter, "qc", 0,
+ rtfParAttr, rtfFirstIndent, "fi", 0,
+ rtfParAttr, rtfLeftIndent, "li", 0,
+ rtfParAttr, rtfRightIndent, "ri", 0,
+ rtfParAttr, rtfSpaceBefore, "sb", 0,
+ rtfParAttr, rtfSpaceAfter, "sa", 0,
+ rtfParAttr, rtfSpaceBetween, "sl", 0,
+ rtfParAttr, rtfInTable, "intbl", 0,
+ rtfParAttr, rtfKeep, "keep", 0,
+ rtfParAttr, rtfKeepNext, "keepn", 0,
+ rtfParAttr, rtfSideBySide, "sbys", 0,
+ rtfParAttr, rtfPBBefore, "pagebb", 0,
+ rtfParAttr, rtfNoLineNum, "noline", 0,
+ rtfParAttr, rtfTabPos, "tx", 0,
+ rtfParAttr, rtfTabRight, "tqr", 0,
+ rtfParAttr, rtfTabCenter, "tqc", 0,
+ rtfParAttr, rtfTabDecimal, "tqdec", 0,
+ rtfParAttr, rtfTabBar, "tb", 0,
+ rtfParAttr, rtfBorderTop, "brdrt", 0,
+ rtfParAttr, rtfBorderBottom, "brdrb", 0,
+ rtfParAttr, rtfBorderLeft, "brdrl", 0,
+ rtfParAttr, rtfBorderRight, "brdrr", 0,
+ rtfParAttr, rtfBorderBar, "bar", 0,
+ rtfParAttr, rtfBorderBox, "box", 0,
+ rtfParAttr, rtfBorderBetween, "brdrbtw", 0,
+ rtfParAttr, rtfBorderSingle, "brdrs", 0,
+ rtfParAttr, rtfBorderThick, "brdrth", 0,
+ rtfParAttr, rtfBorderShadow, "brdrsh", 0,
+ rtfParAttr, rtfBorderDouble, "brdrdb", 0,
+ rtfParAttr, rtfBorderDot, "brdrdot", 0,
+ rtfParAttr, rtfBorderHair, "brdrhair", 0,
+ rtfParAttr, rtfLeaderDot, "tldot", 0,
+ rtfParAttr, rtfLeaderHyphen, "tlhyph", 0,
+ rtfParAttr, rtfLeaderUnder, "tlul", 0,
+ rtfParAttr, rtfLeaderThick, "tlth", 0,
+ rtfParAttr, rtfBorderSpace, "brsp", 0,
+
+ rtfSectAttr, rtfSectDef, "sectd", 0,
+ /*rtfSectAttr, rtfNoBreak, "nobreak", 0,
+ rtfSectAttr, rtfColBreak, "colbreak", 0,
+ rtfSectAttr, rtfPageBreak, "pagebreak", 0,
+ rtfSectAttr, rtfEvenBreak, "evenbreak", 0,
+ rtfSectAttr, rtfOddBreak, "oddbreak", 0,*/
+ rtfSectAttr, rtfNoBreak, "sbknone", 0,
+ rtfSectAttr, rtfColBreak, "sbkcol", 0,
+ rtfSectAttr, rtfPageBreak, "sbkpage", 0,
+ rtfSectAttr, rtfEvenBreak, "sbkeven", 0,
+ rtfSectAttr, rtfOddBreak, "sbkodd", 0,
+ rtfSectAttr, rtfPageCont, "pgncont", 0,
+ rtfSectAttr, rtfPageStarts, "pgnstarts", 0,
+ rtfSectAttr, rtfPageRestart, "pgnrestart", 0,
+ rtfSectAttr, rtfPageDecimal, "pgndec", 0,
+ rtfSectAttr, rtfPageURoman, "pgnucrm", 0,
+ rtfSectAttr, rtfPageLRoman, "pgnlcrm", 0,
+ rtfSectAttr, rtfPageULetter, "pgnucltr", 0,
+ rtfSectAttr, rtfPageLLetter, "pgnlcltr", 0,
+ rtfSectAttr, rtfPageNumLeft, "pgnx", 0,
+ rtfSectAttr, rtfPageNumTop, "pgny", 0,
+ rtfSectAttr, rtfHeaderY, "headery", 0,
+ rtfSectAttr, rtfFooterY, "footery", 0,
+ rtfSectAttr, rtfLineModulus, "linemod", 0,
+ rtfSectAttr, rtfLineDist, "linex", 0,
+ rtfSectAttr, rtfLineStarts, "linestarts", 0,
+ rtfSectAttr, rtfLineRestart, "linerestart", 0,
+ rtfSectAttr, rtfLineRestartPg, "lineppage", 0,
+ rtfSectAttr, rtfLineCont, "linecont", 0,
+ rtfSectAttr, rtfTopVAlign, "vertalt", 0,
+ rtfSectAttr, rtfBottomVAlign, "vertal", 0,
+ rtfSectAttr, rtfCenterVAlign, "vertalc", 0,
+ rtfSectAttr, rtfJustVAlign, "vertalj", 0,
+ rtfSectAttr, rtfColumns, "cols", 0,
+ rtfSectAttr, rtfColumnSpace, "colsx", 0,
+ rtfSectAttr, rtfColumnLine, "linebetcol", 0,
+ rtfSectAttr, rtfENoteHere, "endnhere", 0,
+ rtfSectAttr, rtfTitleSpecial, "titlepg", 0,
+
+ rtfDocAttr, rtfPaperWidth, "paperw", 0,
+ rtfDocAttr, rtfPaperHeight, "paperh", 0,
+ rtfDocAttr, rtfLeftMargin, "margl", 0,
+ rtfDocAttr, rtfRightMargin, "margr", 0,
+ rtfDocAttr, rtfTopMargin, "margt", 0,
+ rtfDocAttr, rtfBottomMargin, "margb", 0,
+ rtfDocAttr, rtfFacingPage, "facingp", 0,
+ rtfDocAttr, rtfGutterWid, "gutter", 0,
+ rtfDocAttr, rtfDefTab, "deftab", 0,
+ rtfDocAttr, rtfWidowCtrl, "widowctrl", 0,
+ rtfDocAttr, rtfHyphHotZone, "hyphhotz", 0,
+ rtfDocAttr, rtfFNoteEndSect, "endnotes", 0,
+ rtfDocAttr, rtfFNoteEndDoc, "enddoc", 0,
+ rtfDocAttr, rtfFNoteBottom, "ftnbj", 0,
+ rtfDocAttr, rtfFNoteText, "ftntj", 0,
+ rtfDocAttr, rtfFNoteStart, "ftnstart", 0,
+ rtfDocAttr, rtfFNoteRestart, "ftnrestart", 0,
+ rtfDocAttr, rtfPageStart, "pgnstart", 0,
+ rtfDocAttr, rtfLineStart, "linestart", 0,
+ rtfDocAttr, rtfLandscape, "landscape", 0,
+ rtfDocAttr, rtfFracWidth, "fracwidth", 0,
+ rtfDocAttr, rtfNextFile, "nextfile", 0,
+ rtfDocAttr, rtfTemplate, "template", 0,
+ rtfDocAttr, rtfMakeBackup, "makeback", 0,
+ rtfDocAttr, rtfRTFDefault, "defformat", 0,
+ rtfDocAttr, rtfRevisions, "revisions", 0,
+ rtfDocAttr, rtfMirrorMargin, "margmirror", 0,
+ rtfDocAttr, rtfRevDisplay, "revprop", 0,
+ rtfDocAttr, rtfRevBar, "revbar", 0,
+
+ rtfStyleAttr, rtfBasedOn, "sbasedon", 0,
+ rtfStyleAttr, rtfNext, "snext", 0,
+
+ rtfPictAttr, rtfMacQD, "macpict", 0,
+ rtfPictAttr, rtfWinMetafile, "wmetafile", 0,
+ rtfPictAttr, rtfWinBitmap, "wbitmap", 0,
+ rtfPictAttr, rtfPicWid, "picw", 0,
+ rtfPictAttr, rtfPicHt, "pich", 0,
+ rtfPictAttr, rtfPicGoalWid, "picwgoal", 0,
+ rtfPictAttr, rtfPicGoalWid, "picwGoal", 0,
+ rtfPictAttr, rtfPicGoalHt, "pichgoal", 0,
+ rtfPictAttr, rtfPicGoalHt, "pichGoal", 0,
+ rtfPictAttr, rtfPicScaleX, "picscalex", 0,
+ rtfPictAttr, rtfPicScaleY, "picscaley", 0,
+ rtfPictAttr, rtfPicScaled, "picscaled", 0,
+ rtfPictAttr, rtfPicCropTop, "piccropt", 0,
+ rtfPictAttr, rtfPicCropBottom, "piccropb", 0,
+ rtfPictAttr, rtfPicCropLeft, "piccropl", 0,
+ rtfPictAttr, rtfPicCropRight, "piccropr", 0,
+ rtfPictAttr, rtfPixelBits, "wbmbitspixel", 0,
+ rtfPictAttr, rtfBitmapPlanes, "wbmplanes", 0,
+ rtfPictAttr, rtfBitmapWid, "wbmwidthbytes", 0,
+ rtfPictAttr, rtfPicBinary, "bin", 0,
+
+ rtfDestination, rtfPict, "pict", 0,
+ rtfDestination, rtfFootnote, "footnote", 0,
+ rtfDestination, rtfHeader, "header", 0,
+ rtfDestination, rtfHeaderLeft, "headerl", 0,
+ rtfDestination, rtfHeaderRight, "headerr", 0,
+ rtfDestination, rtfHeaderFirst, "headerf", 0,
+ rtfDestination, rtfFooter, "footer", 0,
+ rtfDestination, rtfFooterLeft, "footerl", 0,
+ rtfDestination, rtfFooterRight, "footerr", 0,
+ rtfDestination, rtfFooterFirst, "footerf", 0,
+ rtfDestination, rtfFNSep, "ftnsep", 0,
+ rtfDestination, rtfFNContSep, "ftnsepc", 0,
+ rtfDestination, rtfFNContNotice, "ftncn", 0,
+ rtfDestination, rtfInfo, "info", 0,
+ rtfDestination, rtfStyleSheet, "stylesheet", 0,
+ rtfDestination, rtfFontTbl, "fonttbl", 0,
+ rtfDestination, rtfColorTbl, "colortbl", 0,
+ rtfDestination, rtfAnnotation, "annotation", 0,
+ rtfDestination, rtfAnnotID, "atnid", 0,
+ rtfDestination, rtfField, "field", 0,
+ rtfDestination, rtfFieldInst, "fldinst", 0,
+ rtfDestination, rtfFieldResult, "fldrslt", 0,
+ rtfDestination, rtfIndex, "xe", 0,
+ rtfDestination, rtfIndexBold, "bxe", 0,
+ rtfDestination, rtfIndexItalic, "ixe", 0,
+ rtfDestination, rtfIndexText, "txe", 0,
+ rtfDestination, rtfIndexRange, "rxe", 0,
+ rtfDestination, rtfTOC, "tc", 0,
+ rtfDestination, rtfBookmarkStart, "bkmkstart", 0,
+ rtfDestination, rtfBookmarkEnd, "bkmkend", 0,
+ rtfDestination, rtfITitle, "title", 0,
+ rtfDestination, rtfISubject, "subject", 0,
+ rtfDestination, rtfIAuthor, "author", 0,
+ rtfDestination, rtfIOperator, "operator", 0,
+ rtfDestination, rtfIKeywords, "keywords", 0,
+ rtfDestination, rtfIComment, "comment", 0,
+ rtfDestination, rtfIVersion, "version", 0,
+ rtfDestination, rtfIDoccomm, "doccomm", 0,
+
+ rtfTOCAttr, rtfTOCType, "tcf", 0,
+ rtfTOCAttr, rtfTOCLevel, "tcl", 0,
+
+ rtfFontFamily, rtfFFNil, "fnil", 0,
+ rtfFontFamily, rtfFFRoman, "froman", 0,
+ rtfFontFamily, rtfFFSwiss, "fswiss", 0,
+ rtfFontFamily, rtfFFModern, "fmodern", 0,
+ rtfFontFamily, rtfFFScript, "fscript", 0,
+ rtfFontFamily, rtfFFDecor, "fdecor", 0,
+ rtfFontFamily, rtfFFTech, "ftech", 0,
+
+ rtfColorName, rtfRed, "red", 0,
+ rtfColorName, rtfGreen, "green", 0,
+ rtfColorName, rtfBlue, "blue", 0,
+
+ rtfCharSet, rtfMacCharSet, "mac", 0,
+ rtfCharSet, rtfAnsiCharSet, "ansi", 0,
+ rtfCharSet, rtfPcCharSet, "pc", 0,
+ rtfCharSet, rtfPcaCharSet, "pca", 0,
+
+ rtfTblAttr, rtfCellBordBottom, "clbrdrb", 0,
+ rtfTblAttr, rtfCellBordTop, "clbrdrt", 0,
+ rtfTblAttr, rtfCellBordLeft, "clbrdrl", 0,
+ rtfTblAttr, rtfCellBordRight, "clbrdrr", 0,
+ rtfTblAttr, rtfRowDef, "trowd", 0,
+ rtfTblAttr, rtfRowLeft, "trql", 0,
+ rtfTblAttr, rtfRowRight, "trqr", 0,
+ rtfTblAttr, rtfRowCenter, "trqc", 0,
+ rtfTblAttr, rtfRowGapH, "trgaph", 0,
+ rtfTblAttr, rtfRowHt, "trrh", 0,
+ rtfTblAttr, rtfRowLeftEdge, "trleft", 0,
+ rtfTblAttr, rtfCellPos, "cellx", 0,
+ rtfTblAttr, rtfMergeRngFirst, "clmgf", 0,
+ rtfTblAttr, rtfMergePrevious, "clmrg", 0,
+
+ rtfFieldAttr, rtfFieldDirty, "flddirty", 0,
+ rtfFieldAttr, rtfFieldEdited, "fldedit", 0,
+ rtfFieldAttr, rtfFieldLocked, "fldlock", 0,
+ rtfFieldAttr, rtfFieldPrivate, "fldpriv", 0,
+
+ rtfPosAttr, rtfPosX, "posx", 0,
+ rtfPosAttr, rtfPosXCenter, "posxc", 0,
+ rtfPosAttr, rtfPosXInside, "posxi", 0,
+ rtfPosAttr, rtfPosXLeft, "posxl", 0,
+ rtfPosAttr, rtfPosXOutSide, "posxo", 0,
+ rtfPosAttr, rtfPosXRight, "posxr", 0,
+ rtfPosAttr, rtfPosY, "posy", 0,
+ rtfPosAttr, rtfPosYInline, "posyil", 0,
+ rtfPosAttr, rtfPosYTop, "posyt", 0,
+ rtfPosAttr, rtfPosYCenter, "posyc", 0,
+ rtfPosAttr, rtfPosYBottom, "posyb", 0,
+ rtfPosAttr, rtfAbsWid, "absw", 0,
+ rtfPosAttr, rtfTextDist, "dxfrtext", 0,
+ rtfPosAttr, rtfRPosMargV, "pvmrg", 0,
+ rtfPosAttr, rtfRPosPageV, "pvpg", 0,
+ rtfPosAttr, rtfRPosMargH, "phmrg", 0,
+ rtfPosAttr, rtfRPosPageH, "phpg", 0,
+ rtfPosAttr, rtfRPosColH, "phcol", 0,
+
+ rtfVersion, -1, "rtf", 0,
+ rtfDefFont, -1, "deff", 0,
+
+ 0, -1, NULL, 0
+};
+
+
+/*
+ Initialize lookup table hash values
+*/
+
+static void LookupInit ()
+{
+static int inited = 0;
+RTFKey *rp;
+
+ if (inited == 0)
+ {
+ for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
+ rp->rtfKHash = Hash (rp->rtfKStr);
+ ++inited;
+ }
+}
+
+
+/*
+ Determine major and minor number of control token. If it's
+ not found, the class turns into rtfUnknown.
+*/
+
+static void Lookup (s)
+char *s;
+{
+RTFKey *rp;
+int hash;
+
+ ++s; /* skip over the leading \ character */
+ hash = Hash (s);
+ for (rp = rtfKey; rp->rtfKStr != NULL; rp++)
+ {
+ if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
+ {
+ rtfClass = rtfControl;
+ rtfMajor = rp->rtfKMajor;
+ rtfMinor = rp->rtfKMinor;
+ return;
+ }
+ }
+ rtfClass = rtfUnknown;
+}
+
+
+/*
+ Compute hash value of symbol
+*/
+
+static int Hash (s)
+char *s;
+{
+char c;
+int val = 0;
+
+ while ((c = *s++) != '\0')
+ val += (int) c;
+ return (val);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+/*
+ Memory allocation routines
+*/
+
+
+/*
+ Return pointer to block of size bytes, or NULL if there's
+ not enough memory available.
+*/
+
+char *RTFAlloc (size)
+int size;
+{
+ return (malloc (size));
+}
+
+
+/*
+ Saves a string on the heap and returns a pointer to it.
+*/
+
+
+char *RTFStrSave (s)
+char *s;
+{
+char *p;
+
+ if ((p = RTFAlloc (strlen (s) + 1)) == NULL)
+ return (NULL);
+ return (strcpy (p, s));
+}
+
+
+void RTFFree (p)
+char *p;
+{
+ if (p != NULL)
+ free (p);
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+
+/*
+ Token comparison routines
+*/
+
+int RTFCheckCM (class, major)
+int class, major;
+{
+ return (rtfClass == class && rtfMajor == major);
+}
+
+
+int RTFCheckCMM (class, major, minor)
+int class, major, minor;
+{
+ return (rtfClass == class && rtfMajor == major && rtfMinor == minor);
+}
+
+
+int RTFCheckMM (major, minor)
+int major, minor;
+{
+ return (rtfMajor == major && rtfMinor == minor);
+}