Started local name server framework.
[wine] / dlls / richedit / reader.c
1 /*
2  * - Need to document error code meanings.
3  * - Need to do something with \* on destinations.
4  * - Make the parameter a long?
5  *
6  * reader.c - RTF file reader.  Release 1.10.
7  *
8  * ASCII 10 (\n) and 13 (\r) are ignored and silently discarded.
9  * Nulls are also discarded.
10  * (although the read hook will still get a look at them.)
11  *
12  * "\:" is not a ":", it's a control symbol.  But some versions of
13  * Word seem to write "\:" for ":".  This reader treats "\:" as a
14  * plain text ":"
15  *
16  * 19 Mar 93
17  * - Add hack to skip "{\*\keycode ... }" group in stylesheet.
18  * This is probably the wrong thing to do, but it's simple.
19  * 13 Jul 93
20  * - Add THINK C awareness to malloc() declaration.  Necessary so
21  * compiler knows the malloc argument is 4 bytes.  Ugh.
22  * 07 Sep 93
23  * - Text characters are mapped onto standard codes, which are placed
24  * in rtfMinor.
25  * - Eliminated use of index() function.
26  * 05 Mar 94
27  * - Added zillions of new symbols (those defined in RTF spec 1.2).
28  * 14 Mar 94
29  * - Public functions RTFMsg() and RTFPanic() now take variable arguments.
30  * This means RTFPanic() now is used in place of what was formerly the
31  * internal function Error().
32  * - 8-bit characters are now legal, so they're not converted to \'xx
33  * hex char representation now.
34  * 01 Apr 94
35  * - Added public variables rtfLineNum and rtfLinePos.
36  * - #include string.h or strings.h, avoiding strncmp() problem where
37  * last argument is treated as zero when prototype isn't available.
38  * 04 Apr 94
39  * - Treat style numbers 222 and 0 properly as "no style" and "normal".
40  *
41  * Author: Paul DuBois  dubois@primate.wisc.edu
42  *
43  * This software may be redistributed without restriction and used for
44  * any purpose whatsoever.
45  */
46
47 # ifndef STRING_H
48 # define STRING_H <string.h>
49 # endif
50
51 # include       <stdio.h>
52 # include       <ctype.h>
53 # include       STRING_H
54 # ifdef STDARG
55 # include       <stdarg.h>
56 # else
57 # ifdef VARARGS
58 # include       <varargs.h>
59 # endif /* VARARGS */
60 # endif /* STDARG */
61
62 # define        rtfInternal
63 # include       "rtf.h"
64 # undef         rtfInternal
65
66 /*
67  *  include hard coded charsets
68  */
69  
70 #include "ansi_gen.h"
71 #include "ansi_sym.h"
72 #include "text_map.h"
73
74 #include <stdlib.h>
75 #include "charlist.h"
76 #include "windows.h"
77
78 extern HANDLE RICHED32_hHeap;
79
80 /*
81  * Return pointer to new element of type t, or NULL
82  * if no memory available.
83  */
84
85 # define        New(t)  ((t *) RTFAlloc ((int) sizeof (t)))
86
87 /* maximum number of character values representable in a byte */
88
89 # define        charSetSize             256
90
91 /* charset stack size */
92
93 # define        maxCSStack              10
94
95 #ifndef THINK_C
96 extern char     *malloc ();
97 #else
98 extern void     *malloc(size_t);
99 #endif
100
101 static int      _RTFGetChar();
102 static void     _RTFGetToken ();
103 static void     _RTFGetToken2 ();
104 static int      GetChar ();
105 static void     ReadFontTbl ();
106 static void     ReadColorTbl ();
107 static void     ReadStyleSheet ();
108 static void     ReadInfoGroup ();
109 static void     ReadPictGroup ();
110 static void     ReadObjGroup ();
111 static void     LookupInit ();
112 static void     Lookup ();
113 static int      Hash ();
114
115 static void     CharSetInit ();
116 static void     ReadCharSetMaps ();
117
118
119 /*
120  * Public variables (listed in rtf.h)
121  */
122
123 int     rtfClass;
124 int     rtfMajor;
125 int     rtfMinor;
126 int     rtfParam;
127 char    *rtfTextBuf = (char *) NULL;
128 int     rtfTextLen;
129
130 long    rtfLineNum;
131 int     rtfLinePos;
132
133
134 /*
135  * Private stuff
136  */
137
138 static int      pushedChar;     /* pushback char if read too far */
139
140 static int      pushedClass;    /* pushed token info for RTFUngetToken() */
141 static int      pushedMajor;
142 static int      pushedMinor;
143 static int      pushedParam;
144 static char     *pushedTextBuf = (char *) NULL;
145
146 static int      prevChar;
147 static int      bumpLine;
148
149 static RTFFont  *fontList = (RTFFont *) NULL;   /* these lists MUST be */
150 static RTFColor *colorList = (RTFColor *) NULL; /* initialized to NULL */
151 static RTFStyle *styleList = (RTFStyle *) NULL;
152
153 static char     *inputName = (char *) NULL;
154 static char     *outputName = (char *) NULL;
155
156 static EDITSTREAM editstream;
157 static CHARLIST inputCharList = {0, NULL, NULL};
158
159 /*
160  * This array is used to map standard character names onto their numeric codes.
161  * The position of the name within the array is the code.
162  * stdcharnames.h is generated in the ../h directory.
163  */
164
165 static char     *stdCharName[] =
166 {
167 # include       "stdcharnames.h"
168         (char *) NULL
169 };
170
171
172 /*
173  * These arrays are used to map RTF input character values onto the standard
174  * character names represented by the values.  Input character values are
175  * used as indices into the arrays to produce standard character codes.
176  */
177
178
179 static char     *genCharSetFile = (char *) NULL;
180 static int      genCharCode[charSetSize];       /* general */
181 static int      haveGenCharSet = 0;
182
183 static char     *symCharSetFile = (char *) NULL;
184 static int      symCharCode[charSetSize];       /* symbol */
185 static int      haveSymCharSet = 0;
186
187 static int      curCharSet = rtfCSGeneral;
188 static int      *curCharCode = genCharCode;
189
190 /*
191  * By default, the reader is configured to handle charset mapping invisibly,
192  * including reading the charset files and switching charset maps as necessary
193  * for Symbol font.
194  */
195
196 static int      autoCharSetFlags;
197
198 /*
199  * Stack for keeping track of charset map on group begin/end.  This is
200  * necessary because group termination reverts the font to the previous
201  * value, which may implicitly change it.
202  */
203
204 static int      csStack[maxCSStack];
205 static int      csTop = 0;
206
207 /*
208  * Get a char from the charlist. The charlist is used to store characters
209  * from the editstream.
210  * 
211  */
212
213 int 
214 _RTFGetChar()
215 {
216     char myChar;
217     if(CHARLIST_GetNbItems(&inputCharList) == 0)
218     {
219         char buff[10];
220         long pcb;
221         editstream.pfnCallback(editstream.dwCookie, buff, 1, &pcb);
222         if(pcb == 0)
223            return EOF;
224         else
225            CHARLIST_Enqueue(&inputCharList, buff[0]);
226     }
227     myChar = CHARLIST_Dequeue(&inputCharList);
228     return (int) myChar;
229 }
230
231 void
232 RTFSetEditStream(EDITSTREAM *es)
233 {
234     editstream.dwCookie = es->dwCookie;
235     editstream.dwError  = es->dwError;
236     editstream.pfnCallback = es->pfnCallback;
237 }
238
239 /*
240  * Initialize the reader.  This may be called multiple times,
241  * to read multiple files.  The only thing not reset is the input
242  * stream; that must be done with RTFSetStream().
243  */
244
245 void
246 RTFInit ()
247 {
248 int     i;
249 RTFColor        *cp;
250 RTFFont         *fp;
251 RTFStyle        *sp;
252 RTFStyleElt     *eltList, *ep;
253
254         if (rtfTextBuf == (char *) NULL)        /* initialize the text buffers */
255         {
256                 rtfTextBuf = RTFAlloc (rtfBufSiz);
257                 pushedTextBuf = RTFAlloc (rtfBufSiz);
258                 if (rtfTextBuf == (char *) NULL
259                         || pushedTextBuf == (char *) NULL)
260                         RTFPanic ("Cannot allocate text buffers.");
261                 rtfTextBuf[0] = pushedTextBuf[0] = '\0';
262         }
263
264         RTFFree (inputName);
265         RTFFree (outputName);
266         inputName = outputName = (char *) NULL;
267                         
268         /* initialize lookup table */
269         LookupInit ();
270
271         for (i = 0; i < rtfMaxClass; i++)
272                 RTFSetClassCallback (i, (RTFFuncPtr) NULL);
273         for (i = 0; i < rtfMaxDestination; i++)
274                 RTFSetDestinationCallback (i, (RTFFuncPtr) NULL);
275
276         /* install built-in destination readers */
277         RTFSetDestinationCallback (rtfFontTbl, ReadFontTbl);
278         RTFSetDestinationCallback (rtfColorTbl, ReadColorTbl);
279         RTFSetDestinationCallback (rtfStyleSheet, ReadStyleSheet);
280         RTFSetDestinationCallback (rtfInfo, ReadInfoGroup);
281         RTFSetDestinationCallback (rtfPict, ReadPictGroup);
282         RTFSetDestinationCallback (rtfObject, ReadObjGroup);
283
284
285         RTFSetReadHook ((RTFFuncPtr) NULL);
286
287         /* dump old lists if necessary */
288
289         while (fontList != (RTFFont *) NULL)
290         {
291                 fp = fontList->rtfNextFont;
292                 RTFFree (fontList->rtfFName);
293                 RTFFree ((char *) fontList);
294                 fontList = fp;
295         }
296         while (colorList != (RTFColor *) NULL)
297         {
298                 cp = colorList->rtfNextColor;
299                 RTFFree ((char *) colorList);
300                 colorList = cp;
301         }
302         while (styleList != (RTFStyle *) NULL)
303         {
304                 sp = styleList->rtfNextStyle;
305                 eltList = styleList->rtfSSEList;
306                 while (eltList != (RTFStyleElt *) NULL)
307                 {
308                         ep = eltList->rtfNextSE;
309                         RTFFree (eltList->rtfSEText);
310                         RTFFree ((char *) eltList);
311                         eltList = ep;
312                 }
313                 RTFFree (styleList->rtfSName);
314                 RTFFree ((char *) styleList);
315                 styleList = sp;
316         }
317
318         rtfClass = -1;
319         pushedClass = -1;
320         pushedChar = EOF;
321
322         rtfLineNum = 0;
323         rtfLinePos = 0;
324         prevChar = EOF;
325         bumpLine = 0;
326
327         CharSetInit ();
328         csTop = 0;
329 }
330
331 /*
332  * Set or get the input or output file name.  These are never guaranteed
333  * to be accurate, only insofar as the calling program makes them so.
334  */
335
336 void
337 RTFSetInputName (name)
338 char    *name;
339 {
340         if ((inputName = RTFStrSave (name)) == (char *) NULL)
341                 RTFPanic ("RTFSetInputName: out of memory");
342 }
343
344
345 char *
346 RTFGetInputName ()
347 {
348         return (inputName);
349 }
350
351
352 void
353 RTFSetOutputName (name)
354 char    *name;
355 {
356         if ((outputName = RTFStrSave (name)) == (char *) NULL)
357                 RTFPanic ("RTFSetOutputName: out of memory");
358 }
359
360
361 char *
362 RTFGetOutputName ()
363 {
364         return (outputName);
365 }
366
367
368
369 /* ---------------------------------------------------------------------- */
370
371 /*
372  * Callback table manipulation routines
373  */
374
375
376 /*
377  * Install or return a writer callback for a token class
378  */
379
380
381 static RTFFuncPtr       ccb[rtfMaxClass];               /* class callbacks */
382
383
384 void
385 RTFSetClassCallback (class, callback)
386 int             class;
387 RTFFuncPtr      callback;
388 {
389         if (class >= 0 && class < rtfMaxClass)
390                 ccb[class] = callback;
391 }
392
393
394 RTFFuncPtr
395 RTFGetClassCallback (class)
396 int     class;
397 {
398         if (class >= 0 && class < rtfMaxClass)
399                 return (ccb[class]);
400         return ((RTFFuncPtr) NULL);
401 }
402
403
404 /*
405  * Install or return a writer callback for a destination type
406  */
407
408 static RTFFuncPtr       dcb[rtfMaxDestination]; /* destination callbacks */
409
410
411 void
412 RTFSetDestinationCallback (dest, callback)
413 int             dest;
414 RTFFuncPtr      callback;
415 {
416         if (dest >= 0 && dest < rtfMaxDestination)
417                 dcb[dest] = callback;
418 }
419
420
421 RTFFuncPtr
422 RTFGetDestinationCallback (dest)
423 int     dest;
424 {
425         if (dest >= 0 && dest < rtfMaxDestination)
426                 return (dcb[dest]);
427         return ((RTFFuncPtr) NULL);
428 }
429
430
431 /* ---------------------------------------------------------------------- */
432
433 /*
434  * Token reading routines
435  */
436
437
438 /*
439  * Read the input stream, invoking the writer's callbacks
440  * where appropriate.
441  */
442
443 void
444 RTFRead ()
445 {
446         while (RTFGetToken () != rtfEOF)
447                 RTFRouteToken ();
448 }
449
450
451 /*
452  * Route a token.  If it's a destination for which a reader is
453  * installed, process the destination internally, otherwise
454  * pass the token to the writer's class callback.
455  */
456
457 void
458 RTFRouteToken ()
459 {
460 RTFFuncPtr      p;
461
462         if (rtfClass < 0 || rtfClass >= rtfMaxClass)    /* watchdog */
463         {
464                 RTFPanic ("Unknown class %d: %s (reader malfunction)",
465                                                         rtfClass, rtfTextBuf);
466         }
467         if (RTFCheckCM (rtfControl, rtfDestination))
468         {
469                 /* invoke destination-specific callback if there is one */
470                 if ((p = RTFGetDestinationCallback (rtfMinor))
471                                                         != (RTFFuncPtr) NULL)
472                 {
473                         (*p) ();
474                         return;
475                 }
476         }
477         /* invoke class callback if there is one */
478         if ((p = RTFGetClassCallback (rtfClass)) != (RTFFuncPtr) NULL)
479                 (*p) ();
480 }
481
482
483 /*
484  * Skip to the end of the current group.  When this returns,
485  * writers that maintain a state stack may want to call their
486  * state unstacker; global vars will still be set to the group's
487  * closing brace.
488  */
489
490 void
491 RTFSkipGroup ()
492 {
493 int     level = 1;
494
495         while (RTFGetToken () != rtfEOF)
496         {
497                 if (rtfClass == rtfGroup)
498                 {
499                         if (rtfMajor == rtfBeginGroup)
500                                 ++level;
501                         else if (rtfMajor == rtfEndGroup)
502                         {
503                                 if (--level < 1)
504                                         break;  /* end of initial group */
505                         }
506                 }
507         }
508 }
509
510
511 /*
512  * Read one token.  Call the read hook if there is one.  The
513  * token class is the return value.  Returns rtfEOF when there
514  * are no more tokens.
515  */
516
517 int
518 RTFGetToken ()
519 {
520 RTFFuncPtr      p;
521
522         for (;;)
523         {
524                 _RTFGetToken ();
525                 if ((p = RTFGetReadHook ()) != (RTFFuncPtr) NULL)
526                         (*p) ();        /* give read hook a look at token */
527
528                 /* Silently discard newlines, carriage returns, nulls.  */
529                 if (!(rtfClass == rtfText
530                         && (rtfMajor == '\n' || rtfMajor == '\r'
531                                                 || rtfMajor == '\0')))
532                         break;
533         }
534         return (rtfClass);
535 }
536
537
538 /*
539  * Install or return a token reader hook.
540  */
541
542 static RTFFuncPtr       readHook;
543
544
545 void
546 RTFSetReadHook (f)
547 RTFFuncPtr      f;
548 {
549         readHook = f;
550 }
551
552
553 RTFFuncPtr
554 RTFGetReadHook ()
555 {
556         return (readHook);
557 }
558
559
560 void
561 RTFUngetToken ()
562 {
563         if (pushedClass >= 0)   /* there's already an ungotten token */
564                 RTFPanic ("cannot unget two tokens");
565         if (rtfClass < 0)
566                 RTFPanic ("no token to unget");
567         pushedClass = rtfClass;
568         pushedMajor = rtfMajor;
569         pushedMinor = rtfMinor;
570         pushedParam = rtfParam;
571         (void) strcpy (pushedTextBuf, rtfTextBuf);
572 }
573
574
575 int
576 RTFPeekToken ()
577 {
578         _RTFGetToken ();
579         RTFUngetToken ();
580         return (rtfClass);
581 }
582
583
584 static void
585 _RTFGetToken ()
586 {
587 RTFFont *fp;
588
589         /* first check for pushed token from RTFUngetToken() */
590
591         if (pushedClass >= 0)
592         {
593                 rtfClass = pushedClass;
594                 rtfMajor = pushedMajor;
595                 rtfMinor = pushedMinor;
596                 rtfParam = pushedParam;
597                 (void) strcpy (rtfTextBuf, pushedTextBuf);
598                 rtfTextLen = strlen (rtfTextBuf);
599                 pushedClass = -1;
600                 return;
601         }
602
603         /*
604          * Beyond this point, no token is ever seen twice, which is
605          * important, e.g., for making sure no "}" pops the font stack twice.
606          */
607
608         _RTFGetToken2 ();
609         if (rtfClass == rtfText)        /* map RTF char to standard code */
610                 rtfMinor = RTFMapChar (rtfMajor);
611
612         /*
613          * If auto-charset stuff is activated, see if anything needs doing,
614          * like reading the charset maps or switching between them.
615          */
616
617         if (autoCharSetFlags == 0)
618                 return;
619
620         if ((autoCharSetFlags & rtfReadCharSet)
621                 && RTFCheckCM (rtfControl, rtfCharSet))
622         {
623                 ReadCharSetMaps ();
624         }
625         else if ((autoCharSetFlags & rtfSwitchCharSet)
626                 && RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
627         {
628                 if ((fp = RTFGetFont (rtfParam)) != (RTFFont *) NULL)
629                 {
630                         if (strncmp (fp->rtfFName, "Symbol", 6) == 0)
631                                 curCharSet = rtfCSSymbol;
632                         else
633                                 curCharSet = rtfCSGeneral;
634                         RTFSetCharSet (curCharSet);
635                 }
636         }
637         else if ((autoCharSetFlags & rtfSwitchCharSet) && rtfClass == rtfGroup)
638         {
639                 switch (rtfMajor)
640                 {
641                 case rtfBeginGroup:
642                         if (csTop >= maxCSStack)
643                                 RTFPanic ("_RTFGetToken: stack overflow");
644                         csStack[csTop++] = curCharSet;
645                         break;
646                 case rtfEndGroup:
647                         if (csTop <= 0)
648                                 RTFPanic ("_RTFGetToken: stack underflow");
649                         curCharSet = csStack[--csTop];
650                         RTFSetCharSet (curCharSet);
651                         break;
652                 }
653         }
654 }
655
656
657 /* this shouldn't be called anywhere but from _RTFGetToken() */
658
659 static void
660 _RTFGetToken2 ()
661 {
662 int     sign;
663 int     c;
664
665         /* initialize token vars */
666
667         rtfClass = rtfUnknown;
668         rtfParam = rtfNoParam;
669         rtfTextBuf[rtfTextLen = 0] = '\0';
670
671         /* get first character, which may be a pushback from previous token */
672
673         if (pushedChar != EOF)
674         {
675                 c = pushedChar;
676                 rtfTextBuf[rtfTextLen++] = c;
677                 rtfTextBuf[rtfTextLen] = '\0';
678                 pushedChar = EOF;
679         }
680         else if ((c = GetChar ()) == EOF)
681         {
682                 rtfClass = rtfEOF;
683                 return;
684         }
685
686         if (c == '{')
687         {
688                 rtfClass = rtfGroup;
689                 rtfMajor = rtfBeginGroup;
690                 return;
691         }
692         if (c == '}')
693         {
694                 rtfClass = rtfGroup;
695                 rtfMajor = rtfEndGroup;
696                 return;
697         }
698         if (c != '\\')
699         {
700                 /*
701                  * Two possibilities here:
702                  * 1) ASCII 9, effectively like \tab control symbol
703                  * 2) literal text char
704                  */
705                 if (c == '\t')                  /* ASCII 9 */
706                 {
707                         rtfClass = rtfControl;
708                         rtfMajor = rtfSpecialChar;
709                         rtfMinor = rtfTab;
710                 }
711                 else
712                 {
713                         rtfClass = rtfText;
714                         rtfMajor = c;
715                 }
716                 return;
717         }
718         if ((c = GetChar ()) == EOF)
719         {
720                 /* early eof, whoops (class is rtfUnknown) */
721                 return;
722         }
723         if (!isalpha (c))
724         {
725                 /*
726                  * Three possibilities here:
727                  * 1) hex encoded text char, e.g., \'d5, \'d3
728                  * 2) special escaped text char, e.g., \{, \}
729                  * 3) control symbol, e.g., \_, \-, \|, \<10>
730                  */
731                 if (c == '\'')                          /* hex char */
732                 {
733                 int     c2;
734
735                         if ((c = GetChar ()) != EOF && (c2 = GetChar ()) != EOF)
736                         {
737                                 /* should do isxdigit check! */
738                                 rtfClass = rtfText;
739                                 rtfMajor = RTFCharToHex (c) * 16
740                                                 + RTFCharToHex (c2);
741                                 return;
742                         }
743                         /* early eof, whoops (class is rtfUnknown) */
744                         return;
745                 }
746
747                 /* escaped char */
748                 /*if (index (":{}\\", c) != (char *) NULL)*/ /* escaped char */
749                 if (c == ':' || c == '{' || c == '}' || c == '\\')
750                 {
751                         rtfClass = rtfText;
752                         rtfMajor = c;
753                         return;
754                 }
755
756                 /* control symbol */
757                 Lookup (rtfTextBuf);    /* sets class, major, minor */
758                 return;
759         }
760         /* control word */
761         while (isalpha (c))
762         {
763                 if ((c = GetChar ()) == EOF)
764                         break;
765         }
766
767         /*
768          * At this point, the control word is all collected, so the
769          * major/minor numbers are determined before the parameter
770          * (if any) is scanned.  There will be one too many characters
771          * in the buffer, though, so fix up before and restore after
772          * looking up.
773          */
774
775         if (c != EOF)
776                 rtfTextBuf[rtfTextLen-1] = '\0';
777         Lookup (rtfTextBuf);    /* sets class, major, minor */
778         if (c != EOF)
779                 rtfTextBuf[rtfTextLen-1] = c;
780
781         /*
782          * Should be looking at first digit of parameter if there
783          * is one, unless it's negative.  In that case, next char
784          * is '-', so need to gobble next char, and remember sign.
785          */
786
787         sign = 1;
788         if (c == '-')
789         {
790                 sign = -1;
791                 c = GetChar ();
792         }
793         if (c != EOF && isdigit (c))
794         {
795                 rtfParam = 0;
796                 while (isdigit (c))     /* gobble parameter */
797                 {
798                         rtfParam = rtfParam * 10 + c - '0';
799                         if ((c = GetChar ()) == EOF)
800                                 break;
801                 }
802                 rtfParam *= sign;
803         }
804         /*
805          * If control symbol delimiter was a blank, gobble it.
806          * Otherwise the character is first char of next token, so
807          * push it back for next call.  In either case, delete the
808          * delimiter from the token buffer.
809          */
810         if (c != EOF)
811         {
812                 if (c != ' ')
813                         pushedChar = c;
814                 rtfTextBuf[--rtfTextLen] = '\0';
815         }
816 }
817
818
819 /*
820  * Read the next character from the input.  This handles setting the
821  * current line and position-within-line variables.  Those variable are
822  * set correctly whether lines end with CR, LF, or CRLF (the last being
823  * the tricky case).
824  *
825  * bumpLine indicates whether the line number should be incremented on
826  * the *next* input character.
827  */
828
829  
830 static int
831 GetChar ()
832 {
833 int     c;
834 int     oldBumpLine;
835
836         if ((c = _RTFGetChar()) != EOF)
837         {
838                 rtfTextBuf[rtfTextLen++] = c;
839                 rtfTextBuf[rtfTextLen] = '\0';
840         }
841         if (prevChar == EOF)
842                 bumpLine = 1;
843         oldBumpLine = bumpLine; /* non-zero if prev char was line ending */
844         bumpLine = 0;
845         if (c == '\r')
846                 bumpLine = 1;
847         else if (c == '\n')
848         {
849                 bumpLine = 1;
850                 if (prevChar == '\r')           /* oops, previous \r wasn't */
851                         oldBumpLine = 0;        /* really a line ending */
852         }
853         ++rtfLinePos;
854         if (oldBumpLine)        /* were we supposed to increment the */
855         {                       /* line count on this char? */
856                 ++rtfLineNum;
857                 rtfLinePos = 1;
858         }
859         prevChar = c;
860         return (c);
861 }
862
863
864 /*
865  * Synthesize a token by setting the global variables to the
866  * values supplied.  Typically this is followed with a call
867  * to RTFRouteToken().
868  *
869  * If a param value other than rtfNoParam is passed, it becomes
870  * part of the token text.
871  */
872
873 void
874 RTFSetToken (class, major, minor, param, text)
875 int     class, major, minor, param;
876 char    *text;
877 {
878         rtfClass = class;
879         rtfMajor = major;
880         rtfMinor = minor;
881         rtfParam = param;
882         if (param == rtfNoParam)
883                 (void) strcpy (rtfTextBuf, text);
884         else
885                 sprintf (rtfTextBuf, "%s%d", text, param);
886         rtfTextLen = strlen (rtfTextBuf);
887 }
888
889
890 /* ---------------------------------------------------------------------- */
891
892 /*
893  * Routines to handle mapping of RTF character sets
894  * onto standard characters.
895  *
896  * RTFStdCharCode(name) given char name, produce numeric code
897  * RTFStdCharName(code) given char code, return name
898  * RTFMapChar(c)        map input (RTF) char code to std code
899  * RTFSetCharSet(id)    select given charset map
900  * RTFGetCharSet()      get current charset map
901  *
902  * See ../h/README for more information about charset names and codes.
903  */
904
905
906 /*
907  * Initialize charset stuff.
908  */
909
910 static void
911 CharSetInit ()
912 {
913         autoCharSetFlags = (rtfReadCharSet | rtfSwitchCharSet);
914         RTFFree (genCharSetFile);
915         genCharSetFile = (char *) NULL;
916         haveGenCharSet = 0;
917         RTFFree (symCharSetFile);
918         symCharSetFile = (char *) NULL;
919         haveSymCharSet = 0;
920         curCharSet = rtfCSGeneral;
921         curCharCode = genCharCode;
922 }
923
924
925 /*
926  * Specify the name of a file to be read when auto-charset-file reading is
927  * done.
928  */
929
930 void
931 RTFSetCharSetMap (name, csId)
932 char    *name;
933 int     csId;
934 {
935         if ((name = RTFStrSave (name)) == (char *) NULL)        /* make copy */
936                 RTFPanic ("RTFSetCharSetMap: out of memory");
937         switch (csId)
938         {
939         case rtfCSGeneral:
940                 RTFFree (genCharSetFile);       /* free any previous value */
941                 genCharSetFile = name;
942                 break;
943         case rtfCSSymbol:
944                 RTFFree (symCharSetFile);       /* free any previous value */
945                 symCharSetFile = name;
946                 break;
947         }
948 }
949
950
951 /*
952  * Do auto-charset-file reading.
953  * will always use the ansi charset no mater what the value  
954  * of the rtfTextBuf is.
955  *
956  * TODO: add support for other charset in the future.
957  * 
958  */
959
960 static void
961 ReadCharSetMaps ()
962 {
963 char    buf[rtfBufSiz];
964
965         if (genCharSetFile != (char *) NULL)
966                 (void) strcpy (buf, genCharSetFile);
967         else
968                 sprintf (buf, "%s-gen", &rtfTextBuf[1]);
969         if (RTFReadCharSetMap (rtfCSGeneral) == 0)
970                 RTFPanic ("ReadCharSetMaps: Cannot read charset map %s", buf);
971         if (symCharSetFile != (char *) NULL)
972             (void) strcpy (buf, symCharSetFile);
973         else
974                 sprintf (buf, "%s-sym", &rtfTextBuf[1]);
975         if (RTFReadCharSetMap (rtfCSSymbol) == 0)
976                 RTFPanic ("ReadCharSetMaps: Cannot read charset map %s", buf);
977 }
978
979
980
981 /*
982  * Convert a CaracterSetMap (caracter_name, caracter) into 
983  * this form : array[caracter_ident] = caracter;
984  */
985
986 int
987 RTFReadCharSetMap (csId)
988 int     csId;
989 {
990         int     *stdCodeArray;
991         int i;
992         switch (csId)
993         {
994         default:
995                 return (0);     /* illegal charset id */
996         case rtfCSGeneral:
997         
998                 haveGenCharSet = 1;
999                 stdCodeArray = genCharCode;
1000                 for (i = 0; i < charSetSize; i++)
1001                 {
1002                     stdCodeArray[i] = rtfSC_nothing;
1003                 }
1004
1005                 for ( i = 0 ; i< sizeof(ansi_gen)/(sizeof(int));i+=2)
1006                 {
1007                     stdCodeArray[ ansi_gen[i+1] ] = ansi_gen[i];
1008                 }
1009                 break;
1010                 
1011         case rtfCSSymbol:
1012
1013                 haveSymCharSet = 1;
1014                 stdCodeArray = symCharCode;
1015                 for (i = 0; i < charSetSize; i++)
1016                 {
1017                     stdCodeArray[i] = rtfSC_nothing;
1018                 }
1019
1020                 for ( i = 0 ; i< sizeof(ansi_sym)/(sizeof(int));i+=2)
1021                 {
1022                     stdCodeArray[ ansi_sym[i+1] ] = ansi_sym[i];
1023                 }               
1024                 break;
1025         }
1026
1027         return (1);
1028 }
1029
1030
1031 /*
1032  * Given a standard character name (a string), find its code (a number).
1033  * Return -1 if name is unknown.
1034  */
1035
1036 int
1037 RTFStdCharCode (name)
1038 char    *name;
1039 {
1040 int     i;
1041
1042         for (i = 0; i < rtfSC_MaxChar; i++)
1043         {
1044                 if (strcmp (name, stdCharName[i]) == 0)
1045                         return (i);
1046         }
1047         return (-1);
1048 }
1049
1050
1051 /*
1052  * Given a standard character code (a number), find its name (a string).
1053  * Return NULL if code is unknown.
1054  */
1055
1056 char *
1057 RTFStdCharName (code)
1058 int     code;
1059 {
1060         if (code < 0 || code >= rtfSC_MaxChar)
1061                 return ((char *) NULL);
1062         return (stdCharName[code]);
1063 }
1064
1065
1066 /*
1067  * Given an RTF input character code, find standard character code.
1068  * The translator should read the appropriate charset maps when it finds a
1069  * charset control.  However, the file might not contain one.  In this
1070  * case, no map will be available.  When the first attempt is made to
1071  * map a character under these circumstances, RTFMapChar() assumes ANSI
1072  * and reads the map as necessary.
1073  */
1074
1075 int
1076 RTFMapChar (c)
1077 int     c;
1078 {
1079         switch (curCharSet)
1080         {
1081         case rtfCSGeneral:
1082                 if (!haveGenCharSet)
1083                 {
1084                         if (RTFReadCharSetMap (rtfCSGeneral) == 0)
1085                                 RTFPanic ("RTFMapChar: cannot read ansi-gen");
1086                 }
1087                 break;
1088         case rtfCSSymbol:
1089                 if (!haveSymCharSet)
1090                 {
1091                         if (RTFReadCharSetMap (rtfCSSymbol) == 0)
1092                                 RTFPanic ("RTFMapChar: cannot read ansi-sym");
1093                 }
1094                 break;
1095         }
1096         if (c < 0 || c >= charSetSize)
1097                 return (rtfSC_nothing);
1098         return (curCharCode[c]);
1099 }
1100
1101
1102 /*
1103  * Set the current character set.  If csId is illegal, uses general charset.
1104  */
1105
1106 void
1107 RTFSetCharSet (csId)
1108 int     csId;
1109 {
1110         switch (csId)
1111         {
1112         default:                /* use general if csId unknown */
1113         case rtfCSGeneral:
1114                 curCharCode = genCharCode;
1115                 curCharSet = csId;
1116                 break;
1117         case rtfCSSymbol:
1118                 curCharCode = symCharCode;
1119                 curCharSet = csId;
1120                 break;
1121         }
1122 }
1123
1124
1125 int
1126 RTFGetCharSet ()
1127 {
1128         return (curCharSet);
1129 }
1130
1131
1132 /* ---------------------------------------------------------------------- */
1133
1134 /*
1135  * Special destination readers.  They gobble the destination so the
1136  * writer doesn't have to deal with them.  That's wrong for any
1137  * translator that wants to process any of these itself.  In that
1138  * case, these readers should be overridden by installing a different
1139  * destination callback.
1140  *
1141  * NOTE: The last token read by each of these reader will be the
1142  * destination's terminating '}', which will then be the current token.
1143  * That '}' token is passed to RTFRouteToken() - the writer has already
1144  * seen the '{' that began the destination group, and may have pushed a
1145  * state; it also needs to know at the end of the group that a state
1146  * should be popped.
1147  *
1148  * It's important that rtf.h and the control token lookup table list
1149  * as many symbols as possible, because these destination readers
1150  * unfortunately make strict assumptions about the input they expect,
1151  * and a token of class rtfUnknown will throw them off easily.
1152  */
1153
1154
1155 /*
1156  * Read { \fonttbl ... } destination.  Old font tables don't have
1157  * braces around each table entry; try to adjust for that.
1158  */
1159
1160 static void
1161 ReadFontTbl ()
1162 {
1163 RTFFont *fp = NULL;
1164 char    buf[rtfBufSiz], *bp;
1165 int     old = -1;
1166 char    *fn = "ReadFontTbl";
1167
1168         for (;;)
1169         {
1170                 (void) RTFGetToken ();
1171                 if (RTFCheckCM (rtfGroup, rtfEndGroup))
1172                         break;
1173                 if (old < 0)            /* first entry - determine tbl type */
1174                 {
1175                         if (RTFCheckCMM (rtfControl, rtfCharAttr, rtfFontNum))
1176                                 old = 1;        /* no brace */
1177                         else if (RTFCheckCM (rtfGroup, rtfBeginGroup))
1178                                 old = 0;        /* brace */
1179                         else                    /* can't tell! */
1180                                 RTFPanic ("%s: Cannot determine format", fn);
1181                 }
1182                 if (old == 0)           /* need to find "{" here */
1183                 {
1184                         if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
1185                                 RTFPanic ("%s: missing \"{\"", fn);
1186                         (void) RTFGetToken ();  /* yes, skip to next token */
1187                 }
1188                 if ((fp = New (RTFFont)) == (RTFFont *) NULL)
1189                         RTFPanic ("%s: cannot allocate font entry", fn);
1190
1191                 fp->rtfNextFont = fontList;
1192                 fontList = fp;
1193
1194                 fp->rtfFName = (char *) NULL;
1195                 fp->rtfFAltName = (char *) NULL;
1196                 fp->rtfFNum = -1;
1197                 fp->rtfFFamily = 0;
1198                 fp->rtfFCharSet = 0;
1199                 fp->rtfFPitch = 0;
1200                 fp->rtfFType = 0;
1201                 fp->rtfFCodePage = 0;
1202
1203                 while (rtfClass != rtfEOF 
1204                        && !RTFCheckCM (rtfText, ';')
1205                        && !RTFCheckCM (rtfGroup, rtfEndGroup))
1206                 {
1207                         if (rtfClass == rtfControl)
1208                         {
1209                                 switch (rtfMajor)
1210                                 {
1211                                 default:
1212                                         /* ignore token but announce it */
1213                                         RTFMsg ("%s: unknown token \"%s\"\n",
1214                                                         fn, rtfTextBuf);
1215                                 case rtfFontFamily:
1216                                         fp->rtfFFamily = rtfMinor;
1217                                         break;
1218                                 case rtfCharAttr:
1219                                         switch (rtfMinor)
1220                                         {
1221                                         default:
1222                                                 break;  /* ignore unknown? */
1223                                         case rtfFontNum:
1224                                                 fp->rtfFNum = rtfParam;
1225                                                 break;
1226                                         }
1227                                         break;
1228                                 case rtfFontAttr:
1229                                         switch (rtfMinor)
1230                                         {
1231                                         default:
1232                                                 break;  /* ignore unknown? */
1233                                         case rtfFontCharSet:
1234                                                 fp->rtfFCharSet = rtfParam;
1235                                                 break;
1236                                         case rtfFontPitch:
1237                                                 fp->rtfFPitch = rtfParam;
1238                                                 break;
1239                                         case rtfFontCodePage:
1240                                                 fp->rtfFCodePage = rtfParam;
1241                                                 break;
1242                                         case rtfFTypeNil:
1243                                         case rtfFTypeTrueType:
1244                                                 fp->rtfFType = rtfParam;
1245                                                 break;
1246                                         }
1247                                         break;
1248                                 }
1249                         }
1250                         else if (RTFCheckCM (rtfGroup, rtfBeginGroup))  /* dest */
1251                         {
1252                                 RTFSkipGroup ();        /* ignore for now */
1253                         }
1254                         else if (rtfClass == rtfText)   /* font name */
1255                         {
1256                                 bp = buf;
1257                                 while (rtfClass != rtfEOF
1258                                         && !RTFCheckCM (rtfText, ';')
1259                                         && !RTFCheckCM (rtfGroup, rtfEndGroup))
1260                                 {
1261                                         *bp++ = rtfMajor;
1262                                         (void) RTFGetToken ();
1263                                 }
1264                                 
1265                                 /* FIX: in some cases the <fontinfo> isn't finished with a semi-column */
1266                                 if(RTFCheckCM (rtfGroup, rtfEndGroup))
1267                                 {
1268                                   RTFUngetToken ();
1269                                 }                               
1270                                 *bp = '\0';
1271                                 fp->rtfFName = RTFStrSave (buf);
1272                                 if (fp->rtfFName == (char *) NULL)
1273                                         RTFPanic ("%s: cannot allocate font name", fn);
1274                                 /* already have next token; don't read one */
1275                                 /* at bottom of loop */
1276                                 continue;
1277                         }
1278                         else
1279                         {
1280                                 /* ignore token but announce it */
1281                                 RTFMsg ("%s: unknown token \"%s\"\n",
1282                                                         fn, rtfTextBuf);
1283                         }
1284                         (void) RTFGetToken ();
1285                 }
1286                 if (old == 0)   /* need to see "}" here */
1287                 {
1288                         (void) RTFGetToken ();
1289                         if (!RTFCheckCM (rtfGroup, rtfEndGroup))
1290                                 RTFPanic ("%s: missing \"}\"", fn);
1291                 }
1292         }
1293         if (fp->rtfFNum == -1)
1294                 RTFPanic ("%s: missing font number", fn);
1295 /*
1296  * Could check other pieces of structure here, too, I suppose.
1297  */
1298         RTFRouteToken ();       /* feed "}" back to router */
1299 }
1300
1301
1302 /*
1303  * The color table entries have color values of -1 if
1304  * the default color should be used for the entry (only
1305  * a semi-colon is given in the definition, no color values).
1306  * There will be a problem if a partial entry (1 or 2 but
1307  * not 3 color values) is given.  The possibility is ignored
1308  * here.
1309  */
1310
1311 static void
1312 ReadColorTbl ()
1313 {
1314 RTFColor        *cp;
1315 int             cnum = 0;
1316 char            *fn = "ReadColorTbl";
1317
1318         for (;;)
1319         {
1320                 (void) RTFGetToken ();
1321                 if (RTFCheckCM (rtfGroup, rtfEndGroup))
1322                         break;
1323                 if ((cp = New (RTFColor)) == (RTFColor *) NULL)
1324                         RTFPanic ("%s: cannot allocate color entry", fn);
1325                 cp->rtfCNum = cnum++;
1326                 cp->rtfCRed = cp->rtfCGreen = cp->rtfCBlue = -1;
1327                 cp->rtfNextColor = colorList;
1328                 colorList = cp;
1329                 while (RTFCheckCM (rtfControl, rtfColorName))
1330                 {
1331                         switch (rtfMinor)
1332                         {
1333                         case rtfRed:    cp->rtfCRed = rtfParam; break;
1334                         case rtfGreen:  cp->rtfCGreen = rtfParam; break;
1335                         case rtfBlue:   cp->rtfCBlue = rtfParam; break;
1336                         }
1337                         RTFGetToken ();
1338                 }
1339                 if (!RTFCheckCM (rtfText, (int) ';'))
1340                         RTFPanic ("%s: malformed entry", fn);
1341         }
1342         RTFRouteToken ();       /* feed "}" back to router */
1343 }
1344
1345
1346 /*
1347  * The "Normal" style definition doesn't contain any style number,
1348  * all others do.  Normal style is given style rtfNormalStyleNum.
1349  */
1350
1351 static void
1352 ReadStyleSheet ()
1353 {
1354 RTFStyle        *sp;
1355 RTFStyleElt     *sep, *sepLast;
1356 char            buf[rtfBufSiz], *bp;
1357 char            *fn = "ReadStyleSheet";
1358
1359         for (;;)
1360         {
1361                 (void) RTFGetToken ();
1362                 if (RTFCheckCM (rtfGroup, rtfEndGroup))
1363                         break;
1364                 if ((sp = New (RTFStyle)) == (RTFStyle *) NULL)
1365                         RTFPanic ("%s: cannot allocate stylesheet entry", fn);
1366                 sp->rtfSName = (char *) NULL;
1367                 sp->rtfSNum = -1;
1368                 sp->rtfSType = rtfParStyle;
1369                 sp->rtfSAdditive = 0;
1370                 sp->rtfSBasedOn = rtfNoStyleNum;
1371                 sp->rtfSNextPar = -1;
1372                 sp->rtfSSEList = sepLast = (RTFStyleElt *) NULL;
1373                 sp->rtfNextStyle = styleList;
1374                 sp->rtfExpanding = 0;
1375                 styleList = sp;
1376                 if (!RTFCheckCM (rtfGroup, rtfBeginGroup))
1377                         RTFPanic ("%s: missing \"{\"", fn);
1378                 for (;;)
1379                 {
1380                         (void) RTFGetToken ();
1381                         if (rtfClass == rtfEOF
1382                                 || RTFCheckCM (rtfText, ';'))
1383                                 break;
1384                         if (rtfClass == rtfControl)
1385                         {
1386                                 if (RTFCheckMM (rtfSpecialChar, rtfOptDest))
1387                                         continue;       /* ignore "\*" */
1388                                 if (RTFCheckMM (rtfParAttr, rtfStyleNum))
1389                                 {
1390                                         sp->rtfSNum = rtfParam;
1391                                         sp->rtfSType = rtfParStyle;
1392                                         continue;
1393                                 }
1394                                 if (RTFCheckMM (rtfCharAttr, rtfCharStyleNum))
1395                                 {
1396                                         sp->rtfSNum = rtfParam;
1397                                         sp->rtfSType = rtfCharStyle;
1398                                         continue;
1399                                 }
1400                                 if (RTFCheckMM (rtfSectAttr, rtfSectStyleNum))
1401                                 {
1402                                         sp->rtfSNum = rtfParam;
1403                                         sp->rtfSType = rtfSectStyle;
1404                                         continue;
1405                                 }
1406                                 if (RTFCheckMM (rtfStyleAttr, rtfBasedOn))
1407                                 {
1408                                         sp->rtfSBasedOn = rtfParam;
1409                                         continue;
1410                                 }
1411                                 if (RTFCheckMM (rtfStyleAttr, rtfAdditive))
1412                                 {
1413                                         sp->rtfSAdditive = 1;
1414                                         continue;
1415                                 }
1416                                 if (RTFCheckMM (rtfStyleAttr, rtfNext))
1417                                 {
1418                                         sp->rtfSNextPar = rtfParam;
1419                                         continue;
1420                                 }
1421                                 if ((sep = New (RTFStyleElt)) == (RTFStyleElt *) NULL)
1422                                         RTFPanic ("%s: cannot allocate style element", fn);
1423                                 sep->rtfSEClass = rtfClass;
1424                                 sep->rtfSEMajor = rtfMajor;
1425                                 sep->rtfSEMinor = rtfMinor;
1426                                 sep->rtfSEParam = rtfParam;
1427                                 if ((sep->rtfSEText = RTFStrSave (rtfTextBuf))
1428                                                                 == (char *) NULL)
1429                                         RTFPanic ("%s: cannot allocate style element text", fn);
1430                                 if (sepLast == (RTFStyleElt *) NULL)
1431                                         sp->rtfSSEList = sep;   /* first element */
1432                                 else                            /* add to end */
1433                                         sepLast->rtfNextSE = sep;
1434                                 sep->rtfNextSE = (RTFStyleElt *) NULL;
1435                                 sepLast = sep;
1436                         }
1437                         else if (RTFCheckCM (rtfGroup, rtfBeginGroup))
1438                         {
1439                                 /*
1440                                  * This passes over "{\*\keycode ... }, among
1441                                  * other things. A temporary (perhaps) hack.
1442                                  */
1443                                 RTFSkipGroup ();
1444                                 continue;
1445                         }
1446                         else if (rtfClass == rtfText)   /* style name */
1447                         {
1448                                 bp = buf;
1449                                 while (rtfClass == rtfText)
1450                                 {
1451                                         if (rtfMajor == ';')
1452                                         {
1453                                                 /* put back for "for" loop */
1454                                                 (void) RTFUngetToken ();
1455                                                 break;
1456                                         }
1457                                         *bp++ = rtfMajor;
1458                                         (void) RTFGetToken ();
1459                                 }
1460                                 *bp = '\0';
1461                                 if ((sp->rtfSName = RTFStrSave (buf)) == (char *) NULL)
1462                                         RTFPanic ("%s: cannot allocate style name", fn);
1463                         }
1464                         else            /* unrecognized */
1465                         {
1466                                 /* ignore token but announce it */
1467                                 RTFMsg ("%s: unknown token \"%s\"\n",
1468                                                         fn, rtfTextBuf);
1469                         }
1470                 }
1471                 (void) RTFGetToken ();
1472                 if (!RTFCheckCM (rtfGroup, rtfEndGroup))
1473                         RTFPanic ("%s: missing \"}\"", fn);
1474
1475                 /*
1476                  * Check over the style structure.  A name is a must.
1477                  * If no style number was specified, check whether it's the
1478                  * Normal style (in which case it's given style number
1479                  * rtfNormalStyleNum).  Note that some "normal" style names
1480                  * just begin with "Normal" and can have other stuff following,
1481                  * e.g., "Normal,Times 10 point".  Ugh.
1482                  *
1483                  * Some German RTF writers use "Standard" instead of "Normal".
1484                  */
1485                 if (sp->rtfSName == (char *) NULL)
1486                         RTFPanic ("%s: missing style name", fn);
1487                 if (sp->rtfSNum < 0)
1488                 {
1489                         if (strncmp (buf, "Normal", 6) != 0
1490                                 && strncmp (buf, "Standard", 8) != 0)
1491                                 RTFPanic ("%s: missing style number", fn);
1492                         sp->rtfSNum = rtfNormalStyleNum;
1493                 }
1494                 if (sp->rtfSNextPar == -1)      /* if \snext not given, */
1495                         sp->rtfSNextPar = sp->rtfSNum;  /* next is itself */
1496         }
1497         RTFRouteToken ();       /* feed "}" back to router */
1498 }
1499
1500
1501 static void
1502 ReadInfoGroup ()
1503 {
1504         RTFSkipGroup ();
1505         RTFRouteToken ();       /* feed "}" back to router */
1506 }
1507
1508
1509 static void
1510 ReadPictGroup ()
1511 {
1512         RTFSkipGroup ();
1513         RTFRouteToken ();       /* feed "}" back to router */
1514 }
1515
1516
1517 static void
1518 ReadObjGroup ()
1519 {
1520         RTFSkipGroup ();
1521         RTFRouteToken ();       /* feed "}" back to router */
1522 }
1523
1524
1525 /* ---------------------------------------------------------------------- */
1526
1527 /*
1528  * Routines to return pieces of stylesheet, or font or color tables.
1529  * References to style 0 are mapped onto the Normal style.
1530  */
1531
1532
1533 RTFStyle *
1534 RTFGetStyle (num)
1535 int     num;
1536 {
1537 RTFStyle        *s;
1538
1539         if (num == -1)
1540                 return (styleList);
1541         for (s = styleList; s != (RTFStyle *) NULL; s = s->rtfNextStyle)
1542         {
1543                 if (s->rtfSNum == num)
1544                         break;
1545         }
1546         return (s);             /* NULL if not found */
1547 }
1548
1549
1550 RTFFont *
1551 RTFGetFont (num)
1552 int     num;
1553 {
1554 RTFFont *f;
1555
1556         if (num == -1)
1557                 return (fontList);
1558         for (f = fontList; f != (RTFFont *) NULL; f = f->rtfNextFont)
1559         {
1560                 if (f->rtfFNum == num)
1561                         break;
1562         }
1563         return (f);             /* NULL if not found */
1564 }
1565
1566
1567 RTFColor *
1568 RTFGetColor (num)
1569 int     num;
1570 {
1571 RTFColor        *c;
1572
1573         if (num == -1)
1574                 return (colorList);
1575         for (c = colorList; c != (RTFColor *) NULL; c = c->rtfNextColor)
1576         {
1577                 if (c->rtfCNum == num)
1578                         break;
1579         }
1580         return (c);             /* NULL if not found */
1581 }
1582
1583
1584 /* ---------------------------------------------------------------------- */
1585
1586
1587 /*
1588  * Expand style n, if there is such a style.
1589  */
1590
1591 void
1592 RTFExpandStyle (n)
1593 int     n;
1594 {
1595 RTFStyle        *s;
1596 RTFStyleElt     *se;
1597
1598         if (n == -1 || (s = RTFGetStyle (n)) == (RTFStyle *) NULL)
1599                 return;
1600         if (s->rtfExpanding != 0)
1601                 RTFPanic ("Style expansion loop, style %d", n);
1602         s->rtfExpanding = 1;    /* set expansion flag for loop detection */
1603         /*
1604          * Expand "based-on" style (unless it's the same as the current
1605          * style -- Normal style usually gives itself as its own based-on
1606          * style).  Based-on style expansion is done by synthesizing
1607          * the token that the writer needs to see in order to trigger
1608          * another style expansion, and feeding to token back through
1609          * the router so the writer sees it.
1610          */
1611         if (n != s->rtfSBasedOn)
1612         {
1613                 RTFSetToken (rtfControl, rtfParAttr, rtfStyleNum,
1614                                                         s->rtfSBasedOn, "\\s");
1615                 RTFRouteToken ();
1616         }
1617         /*
1618          * Now route the tokens unique to this style.  RTFSetToken()
1619          * isn't used because it would add the param value to the end
1620          * of the token text, which already has it in.
1621          */
1622         for (se = s->rtfSSEList; se != (RTFStyleElt *) NULL; se = se->rtfNextSE)
1623         {
1624                 rtfClass = se->rtfSEClass;
1625                 rtfMajor = se->rtfSEMajor;
1626                 rtfMinor = se->rtfSEMinor;
1627                 rtfParam = se->rtfSEParam;
1628                 (void) strcpy (rtfTextBuf, se->rtfSEText);
1629                 rtfTextLen = strlen (rtfTextBuf);
1630                 RTFRouteToken ();
1631         }
1632         s->rtfExpanding = 0;    /* done - clear expansion flag */
1633 }
1634
1635
1636 /* ---------------------------------------------------------------------- */
1637
1638 /*
1639  * Control symbol lookup routines
1640  */
1641
1642
1643 typedef struct RTFKey   RTFKey;
1644
1645 struct RTFKey
1646 {
1647         int     rtfKMajor;      /* major number */
1648         int     rtfKMinor;      /* minor number */
1649         char    *rtfKStr;       /* symbol name */
1650         int     rtfKHash;       /* symbol name hash value */
1651 };
1652
1653 /*
1654  * A minor number of -1 means the token has no minor number
1655  * (all valid minor numbers are >= 0).
1656  */
1657
1658 static RTFKey   rtfKey[] =
1659 {
1660         /*
1661          * Special characters
1662          */
1663
1664         { rtfSpecialChar,       rtfIIntVersion,         "vern",         0 },
1665         { rtfSpecialChar,       rtfICreateTime,         "creatim",      0 },
1666         { rtfSpecialChar,       rtfIRevisionTime,       "revtim",       0 },
1667         { rtfSpecialChar,       rtfIPrintTime,          "printim",      0 },
1668         { rtfSpecialChar,       rtfIBackupTime,         "buptim",       0 },
1669         { rtfSpecialChar,       rtfIEditTime,           "edmins",       0 },
1670         { rtfSpecialChar,       rtfIYear,               "yr",           0 },
1671         { rtfSpecialChar,       rtfIMonth,              "mo",           0 },
1672         { rtfSpecialChar,       rtfIDay,                "dy",           0 },
1673         { rtfSpecialChar,       rtfIHour,               "hr",           0 },
1674         { rtfSpecialChar,       rtfIMinute,             "min",          0 },
1675         { rtfSpecialChar,       rtfISecond,             "sec",          0 },
1676         { rtfSpecialChar,       rtfINPages,             "nofpages",     0 },
1677         { rtfSpecialChar,       rtfINWords,             "nofwords",     0 },
1678         { rtfSpecialChar,       rtfINChars,             "nofchars",     0 },
1679         { rtfSpecialChar,       rtfIIntID,              "id",           0 },
1680
1681         { rtfSpecialChar,       rtfCurHeadDate,         "chdate",       0 },
1682         { rtfSpecialChar,       rtfCurHeadDateLong,     "chdpl",        0 },
1683         { rtfSpecialChar,       rtfCurHeadDateAbbrev,   "chdpa",        0 },
1684         { rtfSpecialChar,       rtfCurHeadTime,         "chtime",       0 },
1685         { rtfSpecialChar,       rtfCurHeadPage,         "chpgn",        0 },
1686         { rtfSpecialChar,       rtfSectNum,             "sectnum",      0 },
1687         { rtfSpecialChar,       rtfCurFNote,            "chftn",        0 },
1688         { rtfSpecialChar,       rtfCurAnnotRef,         "chatn",        0 },
1689         { rtfSpecialChar,       rtfFNoteSep,            "chftnsep",     0 },
1690         { rtfSpecialChar,       rtfFNoteCont,           "chftnsepc",    0 },
1691         { rtfSpecialChar,       rtfCell,                "cell",         0 },
1692         { rtfSpecialChar,       rtfRow,                 "row",          0 },
1693         { rtfSpecialChar,       rtfPar,                 "par",          0 },
1694         /* newline and carriage return are synonyms for */
1695         /* \par when they are preceded by a \ character */
1696         { rtfSpecialChar,       rtfPar,                 "\n",           0 },
1697         { rtfSpecialChar,       rtfPar,                 "\r",           0 },
1698         { rtfSpecialChar,       rtfSect,                "sect",         0 },
1699         { rtfSpecialChar,       rtfPage,                "page",         0 },
1700         { rtfSpecialChar,       rtfColumn,              "column",       0 },
1701         { rtfSpecialChar,       rtfLine,                "line",         0 },
1702         { rtfSpecialChar,       rtfSoftPage,            "softpage",     0 },
1703         { rtfSpecialChar,       rtfSoftColumn,          "softcol",      0 },
1704         { rtfSpecialChar,       rtfSoftLine,            "softline",     0 },
1705         { rtfSpecialChar,       rtfSoftLineHt,          "softlheight",  0 },
1706         { rtfSpecialChar,       rtfTab,                 "tab",          0 },
1707         { rtfSpecialChar,       rtfEmDash,              "emdash",       0 },
1708         { rtfSpecialChar,       rtfEnDash,              "endash",       0 },
1709         { rtfSpecialChar,       rtfEmSpace,             "emspace",      0 },
1710         { rtfSpecialChar,       rtfEnSpace,             "enspace",      0 },
1711         { rtfSpecialChar,       rtfBullet,              "bullet",       0 },
1712         { rtfSpecialChar,       rtfLQuote,              "lquote",       0 },
1713         { rtfSpecialChar,       rtfRQuote,              "rquote",       0 },
1714         { rtfSpecialChar,       rtfLDblQuote,           "ldblquote",    0 },
1715         { rtfSpecialChar,       rtfRDblQuote,           "rdblquote",    0 },
1716         { rtfSpecialChar,       rtfFormula,             "|",            0 },
1717         { rtfSpecialChar,       rtfNoBrkSpace,          "~",            0 },
1718         { rtfSpecialChar,       rtfNoReqHyphen,         "-",            0 },
1719         { rtfSpecialChar,       rtfNoBrkHyphen,         "_",            0 },
1720         { rtfSpecialChar,       rtfOptDest,             "*",            0 },
1721         { rtfSpecialChar,       rtfLTRMark,             "ltrmark",      0 },
1722         { rtfSpecialChar,       rtfRTLMark,             "rtlmark",      0 },
1723         { rtfSpecialChar,       rtfNoWidthJoiner,       "zwj",          0 },
1724         { rtfSpecialChar,       rtfNoWidthNonJoiner,    "zwnj",         0 },
1725         /* is this valid? */
1726         { rtfSpecialChar,       rtfCurHeadPict,         "chpict",       0 },
1727
1728         /*
1729          * Character formatting attributes
1730          */
1731
1732         { rtfCharAttr,  rtfPlain,               "plain",        0 },
1733         { rtfCharAttr,  rtfBold,                "b",            0 },
1734         { rtfCharAttr,  rtfAllCaps,             "caps",         0 },
1735         { rtfCharAttr,  rtfDeleted,             "deleted",      0 },
1736         { rtfCharAttr,  rtfSubScript,           "dn",           0 },
1737         { rtfCharAttr,  rtfSubScrShrink,        "sub",          0 },
1738         { rtfCharAttr,  rtfNoSuperSub,          "nosupersub",   0 },
1739         { rtfCharAttr,  rtfExpand,              "expnd",        0 },
1740         { rtfCharAttr,  rtfExpandTwips,         "expndtw",      0 },
1741         { rtfCharAttr,  rtfKerning,             "kerning",      0 },
1742         { rtfCharAttr,  rtfFontNum,             "f",            0 },
1743         { rtfCharAttr,  rtfFontSize,            "fs",           0 },
1744         { rtfCharAttr,  rtfItalic,              "i",            0 },
1745         { rtfCharAttr,  rtfOutline,             "outl",         0 },
1746         { rtfCharAttr,  rtfRevised,             "revised",      0 },
1747         { rtfCharAttr,  rtfRevAuthor,           "revauth",      0 },
1748         { rtfCharAttr,  rtfRevDTTM,             "revdttm",      0 },
1749         { rtfCharAttr,  rtfSmallCaps,           "scaps",        0 },
1750         { rtfCharAttr,  rtfShadow,              "shad",         0 },
1751         { rtfCharAttr,  rtfStrikeThru,          "strike",       0 },
1752         { rtfCharAttr,  rtfUnderline,           "ul",           0 },
1753         { rtfCharAttr,  rtfDotUnderline,        "uld",          0 },
1754         { rtfCharAttr,  rtfDbUnderline,         "uldb",         0 },
1755         { rtfCharAttr,  rtfNoUnderline,         "ulnone",       0 },
1756         { rtfCharAttr,  rtfWordUnderline,       "ulw",          0 },
1757         { rtfCharAttr,  rtfSuperScript,         "up",           0 },
1758         { rtfCharAttr,  rtfSuperScrShrink,      "super",        0 },
1759         { rtfCharAttr,  rtfInvisible,           "v",            0 },
1760         { rtfCharAttr,  rtfForeColor,           "cf",           0 },
1761         { rtfCharAttr,  rtfBackColor,           "cb",           0 },
1762         { rtfCharAttr,  rtfRTLChar,             "rtlch",        0 },
1763         { rtfCharAttr,  rtfLTRChar,             "ltrch",        0 },
1764         { rtfCharAttr,  rtfCharStyleNum,        "cs",           0 },
1765         { rtfCharAttr,  rtfCharCharSet,         "cchs",         0 },
1766         { rtfCharAttr,  rtfLanguage,            "lang",         0 },
1767         /* this has disappeared from spec 1.2 */
1768         { rtfCharAttr,  rtfGray,                "gray",         0 },
1769
1770         /*
1771          * Paragraph formatting attributes
1772          */
1773
1774         { rtfParAttr,   rtfParDef,              "pard",         0 },
1775         { rtfParAttr,   rtfStyleNum,            "s",            0 },
1776         { rtfParAttr,   rtfHyphenate,           "hyphpar",      0 },
1777         { rtfParAttr,   rtfInTable,             "intbl",        0 },
1778         { rtfParAttr,   rtfKeep,                "keep",         0 },
1779         { rtfParAttr,   rtfNoWidowControl,      "nowidctlpar",  0 },
1780         { rtfParAttr,   rtfKeepNext,            "keepn",        0 },
1781         { rtfParAttr,   rtfOutlineLevel,        "level",        0 },
1782         { rtfParAttr,   rtfNoLineNum,           "noline",       0 },
1783         { rtfParAttr,   rtfPBBefore,            "pagebb",       0 },
1784         { rtfParAttr,   rtfSideBySide,          "sbys",         0 },
1785         { rtfParAttr,   rtfQuadLeft,            "ql",           0 },
1786         { rtfParAttr,   rtfQuadRight,           "qr",           0 },
1787         { rtfParAttr,   rtfQuadJust,            "qj",           0 },
1788         { rtfParAttr,   rtfQuadCenter,          "qc",           0 },
1789         { rtfParAttr,   rtfFirstIndent,         "fi",           0 },
1790         { rtfParAttr,   rtfLeftIndent,          "li",           0 },
1791         { rtfParAttr,   rtfRightIndent,         "ri",           0 },
1792         { rtfParAttr,   rtfSpaceBefore,         "sb",           0 },
1793         { rtfParAttr,   rtfSpaceAfter,          "sa",           0 },
1794         { rtfParAttr,   rtfSpaceBetween,        "sl",           0 },
1795         { rtfParAttr,   rtfSpaceMultiply,       "slmult",       0 },
1796
1797         { rtfParAttr,   rtfSubDocument,         "subdocument",  0 },
1798
1799         { rtfParAttr,   rtfRTLPar,              "rtlpar",       0 },
1800         { rtfParAttr,   rtfLTRPar,              "ltrpar",       0 },
1801
1802         { rtfParAttr,   rtfTabPos,              "tx",           0 },
1803         /*
1804          * FrameMaker writes \tql (to mean left-justified tab, apparently)
1805          * although it's not in the spec.  It's also redundant, since lj
1806          * tabs are the default.
1807          */
1808         { rtfParAttr,   rtfTabLeft,             "tql",          0 },
1809         { rtfParAttr,   rtfTabRight,            "tqr",          0 },
1810         { rtfParAttr,   rtfTabCenter,           "tqc",          0 },
1811         { rtfParAttr,   rtfTabDecimal,          "tqdec",        0 },
1812         { rtfParAttr,   rtfTabBar,              "tb",           0 },
1813         { rtfParAttr,   rtfLeaderDot,           "tldot",        0 },
1814         { rtfParAttr,   rtfLeaderHyphen,        "tlhyph",       0 },
1815         { rtfParAttr,   rtfLeaderUnder,         "tlul",         0 },
1816         { rtfParAttr,   rtfLeaderThick,         "tlth",         0 },
1817         { rtfParAttr,   rtfLeaderEqual,         "tleq",         0 },
1818
1819         { rtfParAttr,   rtfParLevel,            "pnlvl",        0 },
1820         { rtfParAttr,   rtfParBullet,           "pnlvlblt",     0 },
1821         { rtfParAttr,   rtfParSimple,           "pnlvlbody",    0 },
1822         { rtfParAttr,   rtfParNumCont,          "pnlvlcont",    0 },
1823         { rtfParAttr,   rtfParNumOnce,          "pnnumonce",    0 },
1824         { rtfParAttr,   rtfParNumAcross,        "pnacross",     0 },
1825         { rtfParAttr,   rtfParHangIndent,       "pnhang",       0 },
1826         { rtfParAttr,   rtfParNumRestart,       "pnrestart",    0 },
1827         { rtfParAttr,   rtfParNumCardinal,      "pncard",       0 },
1828         { rtfParAttr,   rtfParNumDecimal,       "pndec",        0 },
1829         { rtfParAttr,   rtfParNumULetter,       "pnucltr",      0 },
1830         { rtfParAttr,   rtfParNumURoman,        "pnucrm",       0 },
1831         { rtfParAttr,   rtfParNumLLetter,       "pnlcltr",      0 },
1832         { rtfParAttr,   rtfParNumLRoman,        "pnlcrm",       0 },
1833         { rtfParAttr,   rtfParNumOrdinal,       "pnord",        0 },
1834         { rtfParAttr,   rtfParNumOrdinalText,   "pnordt",       0 },
1835         { rtfParAttr,   rtfParNumBold,          "pnb",          0 },
1836         { rtfParAttr,   rtfParNumItalic,        "pni",          0 },
1837         { rtfParAttr,   rtfParNumAllCaps,       "pncaps",       0 },
1838         { rtfParAttr,   rtfParNumSmallCaps,     "pnscaps",      0 },
1839         { rtfParAttr,   rtfParNumUnder,         "pnul",         0 },
1840         { rtfParAttr,   rtfParNumDotUnder,      "pnuld",        0 },
1841         { rtfParAttr,   rtfParNumDbUnder,       "pnuldb",       0 },
1842         { rtfParAttr,   rtfParNumNoUnder,       "pnulnone",     0 },
1843         { rtfParAttr,   rtfParNumWordUnder,     "pnulw",        0 },
1844         { rtfParAttr,   rtfParNumStrikethru,    "pnstrike",     0 },
1845         { rtfParAttr,   rtfParNumForeColor,     "pncf",         0 },
1846         { rtfParAttr,   rtfParNumFont,          "pnf",          0 },
1847         { rtfParAttr,   rtfParNumFontSize,      "pnfs",         0 },
1848         { rtfParAttr,   rtfParNumIndent,        "pnindent",     0 },
1849         { rtfParAttr,   rtfParNumSpacing,       "pnsp",         0 },
1850         { rtfParAttr,   rtfParNumInclPrev,      "pnprev",       0 },
1851         { rtfParAttr,   rtfParNumCenter,        "pnqc",         0 },
1852         { rtfParAttr,   rtfParNumLeft,          "pnql",         0 },
1853         { rtfParAttr,   rtfParNumRight,         "pnqr",         0 },
1854         { rtfParAttr,   rtfParNumStartAt,       "pnstart",      0 },
1855
1856         { rtfParAttr,   rtfBorderTop,           "brdrt",        0 },
1857         { rtfParAttr,   rtfBorderBottom,        "brdrb",        0 },
1858         { rtfParAttr,   rtfBorderLeft,          "brdrl",        0 },
1859         { rtfParAttr,   rtfBorderRight,         "brdrr",        0 },
1860         { rtfParAttr,   rtfBorderBetween,       "brdrbtw",      0 },
1861         { rtfParAttr,   rtfBorderBar,           "brdrbar",      0 },
1862         { rtfParAttr,   rtfBorderBox,           "box",          0 },
1863         { rtfParAttr,   rtfBorderSingle,        "brdrs",        0 },
1864         { rtfParAttr,   rtfBorderThick,         "brdrth",       0 },
1865         { rtfParAttr,   rtfBorderShadow,        "brdrsh",       0 },
1866         { rtfParAttr,   rtfBorderDouble,        "brdrdb",       0 },
1867         { rtfParAttr,   rtfBorderDot,           "brdrdot",      0 },
1868         { rtfParAttr,   rtfBorderDot,           "brdrdash",     0 },
1869         { rtfParAttr,   rtfBorderHair,          "brdrhair",     0 },
1870         { rtfParAttr,   rtfBorderWidth,         "brdrw",        0 },
1871         { rtfParAttr,   rtfBorderColor,         "brdrcf",       0 },
1872         { rtfParAttr,   rtfBorderSpace,         "brsp",         0 },
1873
1874         { rtfParAttr,   rtfShading,             "shading",      0 },
1875         { rtfParAttr,   rtfBgPatH,              "bghoriz",      0 },
1876         { rtfParAttr,   rtfBgPatV,              "bgvert",       0 },
1877         { rtfParAttr,   rtfFwdDiagBgPat,        "bgfdiag",      0 },
1878         { rtfParAttr,   rtfBwdDiagBgPat,        "bgbdiag",      0 },
1879         { rtfParAttr,   rtfHatchBgPat,          "bgcross",      0 },
1880         { rtfParAttr,   rtfDiagHatchBgPat,      "bgdcross",     0 },
1881         { rtfParAttr,   rtfDarkBgPatH,          "bgdkhoriz",    0 },
1882         { rtfParAttr,   rtfDarkBgPatV,          "bgdkvert",     0 },
1883         { rtfParAttr,   rtfFwdDarkBgPat,        "bgdkfdiag",    0 },
1884         { rtfParAttr,   rtfBwdDarkBgPat,        "bgdkbdiag",    0 },
1885         { rtfParAttr,   rtfDarkHatchBgPat,      "bgdkcross",    0 },
1886         { rtfParAttr,   rtfDarkDiagHatchBgPat,  "bgdkdcross",   0 },
1887         { rtfParAttr,   rtfBgPatLineColor,      "cfpat",        0 },
1888         { rtfParAttr,   rtfBgPatColor,          "cbpat",        0 },
1889
1890         /*
1891          * Section formatting attributes
1892          */
1893
1894         { rtfSectAttr,  rtfSectDef,             "sectd",        0 },
1895         { rtfSectAttr,  rtfENoteHere,           "endnhere",     0 },
1896         { rtfSectAttr,  rtfPrtBinFirst,         "binfsxn",      0 },
1897         { rtfSectAttr,  rtfPrtBin,              "binsxn",       0 },
1898         { rtfSectAttr,  rtfSectStyleNum,        "ds",           0 },
1899
1900         { rtfSectAttr,  rtfNoBreak,             "sbknone",      0 },
1901         { rtfSectAttr,  rtfColBreak,            "sbkcol",       0 },
1902         { rtfSectAttr,  rtfPageBreak,           "sbkpage",      0 },
1903         { rtfSectAttr,  rtfEvenBreak,           "sbkeven",      0 },
1904         { rtfSectAttr,  rtfOddBreak,            "sbkodd",       0 },
1905
1906         { rtfSectAttr,  rtfColumns,             "cols",         0 },
1907         { rtfSectAttr,  rtfColumnSpace,         "colsx",        0 },
1908         { rtfSectAttr,  rtfColumnNumber,        "colno",        0 },
1909         { rtfSectAttr,  rtfColumnSpRight,       "colsr",        0 },
1910         { rtfSectAttr,  rtfColumnWidth,         "colw",         0 },
1911         { rtfSectAttr,  rtfColumnLine,          "linebetcol",   0 },
1912
1913         { rtfSectAttr,  rtfLineModulus,         "linemod",      0 },
1914         { rtfSectAttr,  rtfLineDist,            "linex",        0 },
1915         { rtfSectAttr,  rtfLineStarts,          "linestarts",   0 },
1916         { rtfSectAttr,  rtfLineRestart,         "linerestart",  0 },
1917         { rtfSectAttr,  rtfLineRestartPg,       "lineppage",    0 },
1918         { rtfSectAttr,  rtfLineCont,            "linecont",     0 },
1919
1920         { rtfSectAttr,  rtfSectPageWid,         "pgwsxn",       0 },
1921         { rtfSectAttr,  rtfSectPageHt,          "pghsxn",       0 },
1922         { rtfSectAttr,  rtfSectMarginLeft,      "marglsxn",     0 },
1923         { rtfSectAttr,  rtfSectMarginRight,     "margrsxn",     0 },
1924         { rtfSectAttr,  rtfSectMarginTop,       "margtsxn",     0 },
1925         { rtfSectAttr,  rtfSectMarginBottom,    "margbsxn",     0 },
1926         { rtfSectAttr,  rtfSectMarginGutter,    "guttersxn",    0 },
1927         { rtfSectAttr,  rtfSectLandscape,       "lndscpsxn",    0 },
1928         { rtfSectAttr,  rtfTitleSpecial,        "titlepg",      0 },
1929         { rtfSectAttr,  rtfHeaderY,             "headery",      0 },
1930         { rtfSectAttr,  rtfFooterY,             "footery",      0 },
1931
1932         { rtfSectAttr,  rtfPageStarts,          "pgnstarts",    0 },
1933         { rtfSectAttr,  rtfPageCont,            "pgncont",      0 },
1934         { rtfSectAttr,  rtfPageRestart,         "pgnrestart",   0 },
1935         { rtfSectAttr,  rtfPageNumRight,        "pgnx",         0 },
1936         { rtfSectAttr,  rtfPageNumTop,          "pgny",         0 },
1937         { rtfSectAttr,  rtfPageDecimal,         "pgndec",       0 },
1938         { rtfSectAttr,  rtfPageURoman,          "pgnucrm",      0 },
1939         { rtfSectAttr,  rtfPageLRoman,          "pgnlcrm",      0 },
1940         { rtfSectAttr,  rtfPageULetter,         "pgnucltr",     0 },
1941         { rtfSectAttr,  rtfPageLLetter,         "pgnlcltr",     0 },
1942         { rtfSectAttr,  rtfPageNumHyphSep,      "pgnhnsh",      0 },
1943         { rtfSectAttr,  rtfPageNumSpaceSep,     "pgnhnsp",      0 },
1944         { rtfSectAttr,  rtfPageNumColonSep,     "pgnhnsc",      0 },
1945         { rtfSectAttr,  rtfPageNumEmdashSep,    "pgnhnsm",      0 },
1946         { rtfSectAttr,  rtfPageNumEndashSep,    "pgnhnsn",      0 },
1947
1948         { rtfSectAttr,  rtfTopVAlign,           "vertalt",      0 },
1949         /* misspelled as "vertal" in specification 1.0 */
1950         { rtfSectAttr,  rtfBottomVAlign,        "vertalb",      0 },
1951         { rtfSectAttr,  rtfCenterVAlign,        "vertalc",      0 },
1952         { rtfSectAttr,  rtfJustVAlign,          "vertalj",      0 },
1953
1954         { rtfSectAttr,  rtfRTLSect,             "rtlsect",      0 },
1955         { rtfSectAttr,  rtfLTRSect,             "ltrsect",      0 },
1956
1957         /* I've seen these in an old spec, but not in real files... */
1958         /*rtfSectAttr,  rtfNoBreak,             "nobreak",      0,*/
1959         /*rtfSectAttr,  rtfColBreak,            "colbreak",     0,*/
1960         /*rtfSectAttr,  rtfPageBreak,           "pagebreak",    0,*/
1961         /*rtfSectAttr,  rtfEvenBreak,           "evenbreak",    0,*/
1962         /*rtfSectAttr,  rtfOddBreak,            "oddbreak",     0,*/
1963
1964         /*
1965          * Document formatting attributes
1966          */
1967
1968         { rtfDocAttr,   rtfDefTab,              "deftab",       0 },
1969         { rtfDocAttr,   rtfHyphHotZone,         "hyphhotz",     0 },
1970         { rtfDocAttr,   rtfHyphConsecLines,     "hyphconsec",   0 },
1971         { rtfDocAttr,   rtfHyphCaps,            "hyphcaps",     0 },
1972         { rtfDocAttr,   rtfHyphAuto,            "hyphauto",     0 },
1973         { rtfDocAttr,   rtfLineStart,           "linestart",    0 },
1974         { rtfDocAttr,   rtfFracWidth,           "fracwidth",    0 },
1975         /* \makeback was given in old version of spec, it's now */
1976         /* listed as \makebackup */
1977         { rtfDocAttr,   rtfMakeBackup,          "makeback",     0 },
1978         { rtfDocAttr,   rtfMakeBackup,          "makebackup",   0 },
1979         { rtfDocAttr,   rtfRTFDefault,          "defformat",    0 },
1980         { rtfDocAttr,   rtfPSOverlay,           "psover",       0 },
1981         { rtfDocAttr,   rtfDocTemplate,         "doctemp",      0 },
1982         { rtfDocAttr,   rtfDefLanguage,         "deflang",      0 },
1983
1984         { rtfDocAttr,   rtfFENoteType,          "fet",          0 },
1985         { rtfDocAttr,   rtfFNoteEndSect,        "endnotes",     0 },
1986         { rtfDocAttr,   rtfFNoteEndDoc,         "enddoc",       0 },
1987         { rtfDocAttr,   rtfFNoteText,           "ftntj",        0 },
1988         { rtfDocAttr,   rtfFNoteBottom,         "ftnbj",        0 },
1989         { rtfDocAttr,   rtfENoteEndSect,        "aendnotes",    0 },
1990         { rtfDocAttr,   rtfENoteEndDoc,         "aenddoc",      0 },
1991         { rtfDocAttr,   rtfENoteText,           "aftntj",       0 },
1992         { rtfDocAttr,   rtfENoteBottom,         "aftnbj",       0 },
1993         { rtfDocAttr,   rtfFNoteStart,          "ftnstart",     0 },
1994         { rtfDocAttr,   rtfENoteStart,          "aftnstart",    0 },
1995         { rtfDocAttr,   rtfFNoteRestartPage,    "ftnrstpg",     0 },
1996         { rtfDocAttr,   rtfFNoteRestart,        "ftnrestart",   0 },
1997         { rtfDocAttr,   rtfFNoteRestartCont,    "ftnrstcont",   0 },
1998         { rtfDocAttr,   rtfENoteRestart,        "aftnrestart",  0 },
1999         { rtfDocAttr,   rtfENoteRestartCont,    "aftnrstcont",  0 },
2000         { rtfDocAttr,   rtfFNoteNumArabic,      "ftnnar",       0 },
2001         { rtfDocAttr,   rtfFNoteNumLLetter,     "ftnnalc",      0 },
2002         { rtfDocAttr,   rtfFNoteNumULetter,     "ftnnauc",      0 },
2003         { rtfDocAttr,   rtfFNoteNumLRoman,      "ftnnrlc",      0 },
2004         { rtfDocAttr,   rtfFNoteNumURoman,      "ftnnruc",      0 },
2005         { rtfDocAttr,   rtfFNoteNumChicago,     "ftnnchi",      0 },
2006         { rtfDocAttr,   rtfENoteNumArabic,      "aftnnar",      0 },
2007         { rtfDocAttr,   rtfENoteNumLLetter,     "aftnnalc",     0 },
2008         { rtfDocAttr,   rtfENoteNumULetter,     "aftnnauc",     0 },
2009         { rtfDocAttr,   rtfENoteNumLRoman,      "aftnnrlc",     0 },
2010         { rtfDocAttr,   rtfENoteNumURoman,      "aftnnruc",     0 },
2011         { rtfDocAttr,   rtfENoteNumChicago,     "aftnnchi",     0 },
2012
2013         { rtfDocAttr,   rtfPaperWidth,          "paperw",       0 },
2014         { rtfDocAttr,   rtfPaperHeight,         "paperh",       0 },
2015         { rtfDocAttr,   rtfPaperSize,           "psz",          0 },
2016         { rtfDocAttr,   rtfLeftMargin,          "margl",        0 },
2017         { rtfDocAttr,   rtfRightMargin,         "margr",        0 },
2018         { rtfDocAttr,   rtfTopMargin,           "margt",        0 },
2019         { rtfDocAttr,   rtfBottomMargin,        "margb",        0 },
2020         { rtfDocAttr,   rtfFacingPage,          "facingp",      0 },
2021         { rtfDocAttr,   rtfGutterWid,           "gutter",       0 },
2022         { rtfDocAttr,   rtfMirrorMargin,        "margmirror",   0 },
2023         { rtfDocAttr,   rtfLandscape,           "landscape",    0 },
2024         { rtfDocAttr,   rtfPageStart,           "pgnstart",     0 },
2025         { rtfDocAttr,   rtfWidowCtrl,           "widowctrl",    0 },
2026
2027         { rtfDocAttr,   rtfLinkStyles,          "linkstyles",   0 },
2028
2029         { rtfDocAttr,   rtfNoAutoTabIndent,     "notabind",     0 },
2030         { rtfDocAttr,   rtfWrapSpaces,          "wraptrsp",     0 },
2031         { rtfDocAttr,   rtfPrintColorsBlack,    "prcolbl",      0 },
2032         { rtfDocAttr,   rtfNoExtraSpaceRL,      "noextrasprl",  0 },
2033         { rtfDocAttr,   rtfNoColumnBalance,     "nocolbal",     0 },
2034         { rtfDocAttr,   rtfCvtMailMergeQuote,   "cvmme",        0 },
2035         { rtfDocAttr,   rtfSuppressTopSpace,    "sprstsp",      0 },
2036         { rtfDocAttr,   rtfSuppressPreParSpace, "sprsspbf",     0 },
2037         { rtfDocAttr,   rtfCombineTblBorders,   "otblrul",      0 },
2038         { rtfDocAttr,   rtfTranspMetafiles,     "transmf",      0 },
2039         { rtfDocAttr,   rtfSwapBorders,         "swpbdr",       0 },
2040         { rtfDocAttr,   rtfShowHardBreaks,      "brkfrm",       0 },
2041
2042         { rtfDocAttr,   rtfFormProtected,       "formprot",     0 },
2043         { rtfDocAttr,   rtfAllProtected,        "allprot",      0 },
2044         { rtfDocAttr,   rtfFormShading,         "formshade",    0 },
2045         { rtfDocAttr,   rtfFormDisplay,         "formdisp",     0 },
2046         { rtfDocAttr,   rtfPrintData,           "printdata",    0 },
2047
2048         { rtfDocAttr,   rtfRevProtected,        "revprot",      0 },
2049         { rtfDocAttr,   rtfRevisions,           "revisions",    0 },
2050         { rtfDocAttr,   rtfRevDisplay,          "revprop",      0 },
2051         { rtfDocAttr,   rtfRevBar,              "revbar",       0 },
2052
2053         { rtfDocAttr,   rtfAnnotProtected,      "annotprot",    0 },
2054
2055         { rtfDocAttr,   rtfRTLDoc,              "rtldoc",       0 },
2056         { rtfDocAttr,   rtfLTRDoc,              "ltrdoc",       0 },
2057
2058         /*
2059          * Style attributes
2060          */
2061
2062         { rtfStyleAttr, rtfAdditive,            "additive",     0 },
2063         { rtfStyleAttr, rtfBasedOn,             "sbasedon",     0 },
2064         { rtfStyleAttr, rtfNext,                "snext",        0 },
2065
2066         /*
2067          * Picture attributes
2068          */
2069
2070         { rtfPictAttr,  rtfMacQD,               "macpict",      0 },
2071         { rtfPictAttr,  rtfPMMetafile,          "pmmetafile",   0 },
2072         { rtfPictAttr,  rtfWinMetafile,         "wmetafile",    0 },
2073         { rtfPictAttr,  rtfDevIndBitmap,        "dibitmap",     0 },
2074         { rtfPictAttr,  rtfWinBitmap,           "wbitmap",      0 },
2075         { rtfPictAttr,  rtfPixelBits,           "wbmbitspixel", 0 },
2076         { rtfPictAttr,  rtfBitmapPlanes,        "wbmplanes",    0 },
2077         { rtfPictAttr,  rtfBitmapWid,           "wbmwidthbytes", 0 },
2078
2079         { rtfPictAttr,  rtfPicWid,              "picw",         0 },
2080         { rtfPictAttr,  rtfPicHt,               "pich",         0 },
2081         { rtfPictAttr,  rtfPicGoalWid,          "picwgoal",     0 },
2082         { rtfPictAttr,  rtfPicGoalHt,           "pichgoal",     0 },
2083         /* these two aren't in the spec, but some writers emit them */
2084         { rtfPictAttr,  rtfPicGoalWid,          "picwGoal",     0 },
2085         { rtfPictAttr,  rtfPicGoalHt,           "pichGoal",     0 },
2086         { rtfPictAttr,  rtfPicScaleX,           "picscalex",    0 },
2087         { rtfPictAttr,  rtfPicScaleY,           "picscaley",    0 },
2088         { rtfPictAttr,  rtfPicScaled,           "picscaled",    0 },
2089         { rtfPictAttr,  rtfPicCropTop,          "piccropt",     0 },
2090         { rtfPictAttr,  rtfPicCropBottom,       "piccropb",     0 },
2091         { rtfPictAttr,  rtfPicCropLeft,         "piccropl",     0 },
2092         { rtfPictAttr,  rtfPicCropRight,        "piccropr",     0 },
2093
2094         { rtfPictAttr,  rtfPicMFHasBitmap,      "picbmp",       0 },
2095         { rtfPictAttr,  rtfPicMFBitsPerPixel,   "picbpp",       0 },
2096
2097         { rtfPictAttr,  rtfPicBinary,           "bin",          0 },
2098
2099         /*
2100          * NeXT graphic attributes
2101          */
2102
2103         { rtfNeXTGrAttr,        rtfNeXTGWidth,          "width",        0 },
2104         { rtfNeXTGrAttr,        rtfNeXTGHeight,         "height",       0 },
2105
2106         /*
2107          * Destinations
2108          */
2109
2110         { rtfDestination,       rtfFontTbl,             "fonttbl",      0 },
2111         { rtfDestination,       rtfFontAltName,         "falt",         0 },
2112         { rtfDestination,       rtfEmbeddedFont,        "fonteb",       0 },
2113         { rtfDestination,       rtfFontFile,            "fontfile",     0 },
2114         { rtfDestination,       rtfFileTbl,             "filetbl",      0 },
2115         { rtfDestination,       rtfFileInfo,            "file",         0 },
2116         { rtfDestination,       rtfColorTbl,            "colortbl",     0 },
2117         { rtfDestination,       rtfStyleSheet,          "stylesheet",   0 },
2118         { rtfDestination,       rtfKeyCode,             "keycode",      0 },
2119         { rtfDestination,       rtfRevisionTbl,         "revtbl",       0 },
2120         { rtfDestination,       rtfInfo,                "info",         0 },
2121         { rtfDestination,       rtfITitle,              "title",        0 },
2122         { rtfDestination,       rtfISubject,            "subject",      0 },
2123         { rtfDestination,       rtfIAuthor,             "author",       0 },
2124         { rtfDestination,       rtfIOperator,           "operator",     0 },
2125         { rtfDestination,       rtfIKeywords,           "keywords",     0 },
2126         { rtfDestination,       rtfIComment,            "comment",      0 },
2127         { rtfDestination,       rtfIVersion,            "version",      0 },
2128         { rtfDestination,       rtfIDoccomm,            "doccomm",      0 },
2129         /* \verscomm may not exist -- was seen in earlier spec version */
2130         { rtfDestination,       rtfIVerscomm,           "verscomm",     0 },
2131         { rtfDestination,       rtfNextFile,            "nextfile",     0 },
2132         { rtfDestination,       rtfTemplate,            "template",     0 },
2133         { rtfDestination,       rtfFNSep,               "ftnsep",       0 },
2134         { rtfDestination,       rtfFNContSep,           "ftnsepc",      0 },
2135         { rtfDestination,       rtfFNContNotice,        "ftncn",        0 },
2136         { rtfDestination,       rtfENSep,               "aftnsep",      0 },
2137         { rtfDestination,       rtfENContSep,           "aftnsepc",     0 },
2138         { rtfDestination,       rtfENContNotice,        "aftncn",       0 },
2139         { rtfDestination,       rtfPageNumLevel,        "pgnhn",        0 },
2140         { rtfDestination,       rtfParNumLevelStyle,    "pnseclvl",     0 },
2141         { rtfDestination,       rtfHeader,              "header",       0 },
2142         { rtfDestination,       rtfFooter,              "footer",       0 },
2143         { rtfDestination,       rtfHeaderLeft,          "headerl",      0 },
2144         { rtfDestination,       rtfHeaderRight,         "headerr",      0 },
2145         { rtfDestination,       rtfHeaderFirst,         "headerf",      0 },
2146         { rtfDestination,       rtfFooterLeft,          "footerl",      0 },
2147         { rtfDestination,       rtfFooterRight,         "footerr",      0 },
2148         { rtfDestination,       rtfFooterFirst,         "footerf",      0 },
2149         { rtfDestination,       rtfParNumText,          "pntext",       0 },
2150         { rtfDestination,       rtfParNumbering,        "pn",           0 },
2151         { rtfDestination,       rtfParNumTextAfter,     "pntexta",      0 },
2152         { rtfDestination,       rtfParNumTextBefore,    "pntextb",      0 },
2153         { rtfDestination,       rtfBookmarkStart,       "bkmkstart",    0 },
2154         { rtfDestination,       rtfBookmarkEnd,         "bkmkend",      0 },
2155         { rtfDestination,       rtfPict,                "pict",         0 },
2156         { rtfDestination,       rtfObject,              "object",       0 },
2157         { rtfDestination,       rtfObjClass,            "objclass",     0 },
2158         { rtfDestination,       rtfObjName,             "objname",      0 },
2159         { rtfObjAttr,   rtfObjTime,             "objtime",      0 },
2160         { rtfDestination,       rtfObjData,             "objdata",      0 },
2161         { rtfDestination,       rtfObjAlias,            "objalias",     0 },
2162         { rtfDestination,       rtfObjSection,          "objsect",      0 },
2163         /* objitem and objtopic aren't documented in the spec! */
2164         { rtfDestination,       rtfObjItem,             "objitem",      0 },
2165         { rtfDestination,       rtfObjTopic,            "objtopic",     0 },
2166         { rtfDestination,       rtfObjResult,           "result",       0 },
2167         { rtfDestination,       rtfDrawObject,          "do",           0 },
2168         { rtfDestination,       rtfFootnote,            "footnote",     0 },
2169         { rtfDestination,       rtfAnnotRefStart,       "atrfstart",    0 },
2170         { rtfDestination,       rtfAnnotRefEnd,         "atrfend",      0 },
2171         { rtfDestination,       rtfAnnotID,             "atnid",        0 },
2172         { rtfDestination,       rtfAnnotAuthor,         "atnauthor",    0 },
2173         { rtfDestination,       rtfAnnotation,          "annotation",   0 },
2174         { rtfDestination,       rtfAnnotRef,            "atnref",       0 },
2175         { rtfDestination,       rtfAnnotTime,           "atntime",      0 },
2176         { rtfDestination,       rtfAnnotIcon,           "atnicn",       0 },
2177         { rtfDestination,       rtfField,               "field",        0 },
2178         { rtfDestination,       rtfFieldInst,           "fldinst",      0 },
2179         { rtfDestination,       rtfFieldResult,         "fldrslt",      0 },
2180         { rtfDestination,       rtfDataField,           "datafield",    0 },
2181         { rtfDestination,       rtfIndex,               "xe",           0 },
2182         { rtfDestination,       rtfIndexText,           "txe",          0 },
2183         { rtfDestination,       rtfIndexRange,          "rxe",          0 },
2184         { rtfDestination,       rtfTOC,                 "tc",           0 },
2185         { rtfDestination,       rtfNeXTGraphic,         "NeXTGraphic",  0 },
2186
2187         /*
2188          * Font families
2189          */
2190
2191         { rtfFontFamily,        rtfFFNil,               "fnil",         0 },
2192         { rtfFontFamily,        rtfFFRoman,             "froman",       0 },
2193         { rtfFontFamily,        rtfFFSwiss,             "fswiss",       0 },
2194         { rtfFontFamily,        rtfFFModern,            "fmodern",      0 },
2195         { rtfFontFamily,        rtfFFScript,            "fscript",      0 },
2196         { rtfFontFamily,        rtfFFDecor,             "fdecor",       0 },
2197         { rtfFontFamily,        rtfFFTech,              "ftech",        0 },
2198         { rtfFontFamily,        rtfFFBidirectional,     "fbidi",        0 },
2199
2200         /*
2201          * Font attributes
2202          */
2203
2204         { rtfFontAttr,  rtfFontCharSet,         "fcharset",     0 },
2205         { rtfFontAttr,  rtfFontPitch,           "fprq",         0 },
2206         { rtfFontAttr,  rtfFontCodePage,        "cpg",          0 },
2207         { rtfFontAttr,  rtfFTypeNil,            "ftnil",        0 },
2208         { rtfFontAttr,  rtfFTypeTrueType,       "fttruetype",   0 },
2209
2210         /*
2211          * File table attributes
2212          */
2213
2214         { rtfFileAttr,  rtfFileNum,             "fid",          0 },
2215         { rtfFileAttr,  rtfFileRelPath,         "frelative",    0 },
2216         { rtfFileAttr,  rtfFileOSNum,           "fosnum",       0 },
2217
2218         /*
2219          * File sources
2220          */
2221
2222         { rtfFileSource,        rtfSrcMacintosh,        "fvalidmac",    0 },
2223         { rtfFileSource,        rtfSrcDOS,              "fvaliddos",    0 },
2224         { rtfFileSource,        rtfSrcNTFS,             "fvalidntfs",   0 },
2225         { rtfFileSource,        rtfSrcHPFS,             "fvalidhpfs",   0 },
2226         { rtfFileSource,        rtfSrcNetwork,          "fnetwork",     0 },
2227
2228         /*
2229          * Color names
2230          */
2231
2232         { rtfColorName, rtfRed,                 "red",          0 },
2233         { rtfColorName, rtfGreen,               "green",        0 },
2234         { rtfColorName, rtfBlue,                "blue",         0 },
2235
2236         /*
2237          * Charset names
2238          */
2239
2240         { rtfCharSet,   rtfMacCharSet,          "mac",          0 },
2241         { rtfCharSet,   rtfAnsiCharSet,         "ansi",         0 },
2242         { rtfCharSet,   rtfPcCharSet,           "pc",           0 },
2243         { rtfCharSet,   rtfPcaCharSet,          "pca",          0 },
2244
2245         /*
2246          * Table attributes
2247          */
2248
2249         { rtfTblAttr,   rtfRowDef,              "trowd",        0 },
2250         { rtfTblAttr,   rtfRowGapH,             "trgaph",       0 },
2251         { rtfTblAttr,   rtfCellPos,             "cellx",        0 },
2252         { rtfTblAttr,   rtfMergeRngFirst,       "clmgf",        0 },
2253         { rtfTblAttr,   rtfMergePrevious,       "clmrg",        0 },
2254
2255         { rtfTblAttr,   rtfRowLeft,             "trql",         0 },
2256         { rtfTblAttr,   rtfRowRight,            "trqr",         0 },
2257         { rtfTblAttr,   rtfRowCenter,           "trqc",         0 },
2258         { rtfTblAttr,   rtfRowLeftEdge,         "trleft",       0 },
2259         { rtfTblAttr,   rtfRowHt,               "trrh",         0 },
2260         { rtfTblAttr,   rtfRowHeader,           "trhdr",        0 },
2261         { rtfTblAttr,   rtfRowKeep,             "trkeep",       0 },
2262
2263         { rtfTblAttr,   rtfRTLRow,              "rtlrow",       0 },
2264         { rtfTblAttr,   rtfLTRRow,              "ltrrow",       0 },
2265
2266         { rtfTblAttr,   rtfRowBordTop,          "trbrdrt",      0 },
2267         { rtfTblAttr,   rtfRowBordLeft,         "trbrdrl",      0 },
2268         { rtfTblAttr,   rtfRowBordBottom,       "trbrdrb",      0 },
2269         { rtfTblAttr,   rtfRowBordRight,        "trbrdrr",      0 },
2270         { rtfTblAttr,   rtfRowBordHoriz,        "trbrdrh",      0 },
2271         { rtfTblAttr,   rtfRowBordVert,         "trbrdrv",      0 },
2272
2273         { rtfTblAttr,   rtfCellBordBottom,      "clbrdrb",      0 },
2274         { rtfTblAttr,   rtfCellBordTop,         "clbrdrt",      0 },
2275         { rtfTblAttr,   rtfCellBordLeft,        "clbrdrl",      0 },
2276         { rtfTblAttr,   rtfCellBordRight,       "clbrdrr",      0 },
2277
2278         { rtfTblAttr,   rtfCellShading,         "clshdng",      0 },
2279         { rtfTblAttr,   rtfCellBgPatH,          "clbghoriz",    0 },
2280         { rtfTblAttr,   rtfCellBgPatV,          "clbgvert",     0 },
2281         { rtfTblAttr,   rtfCellFwdDiagBgPat,    "clbgfdiag",    0 },
2282         { rtfTblAttr,   rtfCellBwdDiagBgPat,    "clbgbdiag",    0 },
2283         { rtfTblAttr,   rtfCellHatchBgPat,      "clbgcross",    0 },
2284         { rtfTblAttr,   rtfCellDiagHatchBgPat,  "clbgdcross",   0 },
2285         /*
2286          * The spec lists "clbgdkhor", but the corresponding non-cell
2287          * control is "bgdkhoriz".  At any rate Macintosh Word seems
2288          * to accept both "clbgdkhor" and "clbgdkhoriz".
2289          */
2290         { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhoriz",  0 },
2291         { rtfTblAttr,   rtfCellDarkBgPatH,      "clbgdkhor",    0 },
2292         { rtfTblAttr,   rtfCellDarkBgPatV,      "clbgdkvert",   0 },
2293         { rtfTblAttr,   rtfCellFwdDarkBgPat,    "clbgdkfdiag",  0 },
2294         { rtfTblAttr,   rtfCellBwdDarkBgPat,    "clbgdkbdiag",  0 },
2295         { rtfTblAttr,   rtfCellDarkHatchBgPat,  "clbgdkcross",  0 },
2296         { rtfTblAttr,   rtfCellDarkDiagHatchBgPat, "clbgdkdcross",      0 },
2297         { rtfTblAttr,   rtfCellBgPatLineColor, "clcfpat",       0 },
2298         { rtfTblAttr,   rtfCellBgPatColor,      "clcbpat",      0 },
2299
2300         /*
2301          * Field attributes
2302          */
2303
2304         { rtfFieldAttr, rtfFieldDirty,          "flddirty",     0 },
2305         { rtfFieldAttr, rtfFieldEdited,         "fldedit",      0 },
2306         { rtfFieldAttr, rtfFieldLocked,         "fldlock",      0 },
2307         { rtfFieldAttr, rtfFieldPrivate,        "fldpriv",      0 },
2308         { rtfFieldAttr, rtfFieldAlt,            "fldalt",       0 },
2309
2310         /*
2311          * Positioning attributes
2312          */
2313
2314         { rtfPosAttr,   rtfAbsWid,              "absw",         0 },
2315         { rtfPosAttr,   rtfAbsHt,               "absh",         0 },
2316
2317         { rtfPosAttr,   rtfRPosMargH,           "phmrg",        0 },
2318         { rtfPosAttr,   rtfRPosPageH,           "phpg",         0 },
2319         { rtfPosAttr,   rtfRPosColH,            "phcol",        0 },
2320         { rtfPosAttr,   rtfPosX,                "posx",         0 },
2321         { rtfPosAttr,   rtfPosNegX,             "posnegx",      0 },
2322         { rtfPosAttr,   rtfPosXCenter,          "posxc",        0 },
2323         { rtfPosAttr,   rtfPosXInside,          "posxi",        0 },
2324         { rtfPosAttr,   rtfPosXOutSide,         "posxo",        0 },
2325         { rtfPosAttr,   rtfPosXRight,           "posxr",        0 },
2326         { rtfPosAttr,   rtfPosXLeft,            "posxl",        0 },
2327
2328         { rtfPosAttr,   rtfRPosMargV,           "pvmrg",        0 },
2329         { rtfPosAttr,   rtfRPosPageV,           "pvpg",         0 },
2330         { rtfPosAttr,   rtfRPosParaV,           "pvpara",       0 },
2331         { rtfPosAttr,   rtfPosY,                "posy",         0 },
2332         { rtfPosAttr,   rtfPosNegY,             "posnegy",      0 },
2333         { rtfPosAttr,   rtfPosYInline,          "posyil",       0 },
2334         { rtfPosAttr,   rtfPosYTop,             "posyt",        0 },
2335         { rtfPosAttr,   rtfPosYCenter,          "posyc",        0 },
2336         { rtfPosAttr,   rtfPosYBottom,          "posyb",        0 },
2337
2338         { rtfPosAttr,   rtfNoWrap,              "nowrap",       0 },
2339         { rtfPosAttr,   rtfDistFromTextAll,     "dxfrtext",     0 },
2340         { rtfPosAttr,   rtfDistFromTextX,       "dfrmtxtx",     0 },
2341         { rtfPosAttr,   rtfDistFromTextY,       "dfrmtxty",     0 },
2342         /* \dyfrtext no longer exists in spec 1.2, apparently */
2343         /* replaced by \dfrmtextx and \dfrmtexty. */
2344         { rtfPosAttr,   rtfTextDistY,           "dyfrtext",     0 },
2345
2346         { rtfPosAttr,   rtfDropCapLines,        "dropcapli",    0 },
2347         { rtfPosAttr,   rtfDropCapType,         "dropcapt",     0 },
2348
2349         /*
2350          * Object controls
2351          */
2352
2353         { rtfObjAttr,   rtfObjEmb,              "objemb",       0 },
2354         { rtfObjAttr,   rtfObjLink,             "objlink",      0 },
2355         { rtfObjAttr,   rtfObjAutoLink,         "objautlink",   0 },
2356         { rtfObjAttr,   rtfObjSubscriber,       "objsub",       0 },
2357         { rtfObjAttr,   rtfObjPublisher,        "objpub",       0 },
2358         { rtfObjAttr,   rtfObjICEmb,            "objicemb",     0 },
2359
2360         { rtfObjAttr,   rtfObjLinkSelf,         "linkself",     0 },
2361         { rtfObjAttr,   rtfObjLock,             "objupdate",    0 },
2362         { rtfObjAttr,   rtfObjUpdate,           "objlock",      0 },
2363
2364         { rtfObjAttr,   rtfObjHt,               "objh",         0 },
2365         { rtfObjAttr,   rtfObjWid,              "objw",         0 },
2366         { rtfObjAttr,   rtfObjSetSize,          "objsetsize",   0 },
2367         { rtfObjAttr,   rtfObjAlign,            "objalign",     0 },
2368         { rtfObjAttr,   rtfObjTransposeY,       "objtransy",    0 },
2369         { rtfObjAttr,   rtfObjCropTop,          "objcropt",     0 },
2370         { rtfObjAttr,   rtfObjCropBottom,       "objcropb",     0 },
2371         { rtfObjAttr,   rtfObjCropLeft,         "objcropl",     0 },
2372         { rtfObjAttr,   rtfObjCropRight,        "objcropr",     0 },
2373         { rtfObjAttr,   rtfObjScaleX,           "objscalex",    0 },
2374         { rtfObjAttr,   rtfObjScaleY,           "objscaley",    0 },
2375
2376         { rtfObjAttr,   rtfObjResRTF,           "rsltrtf",      0 },
2377         { rtfObjAttr,   rtfObjResPict,          "rsltpict",     0 },
2378         { rtfObjAttr,   rtfObjResBitmap,        "rsltbmp",      0 },
2379         { rtfObjAttr,   rtfObjResText,          "rslttxt",      0 },
2380         { rtfObjAttr,   rtfObjResMerge,         "rsltmerge",    0 },
2381
2382         { rtfObjAttr,   rtfObjBookmarkPubObj,   "bkmkpub",      0 },
2383         { rtfObjAttr,   rtfObjPubAutoUpdate,    "pubauto",      0 },
2384
2385         /*
2386          * Associated character formatting attributes
2387          */
2388
2389         { rtfACharAttr, rtfACBold,              "ab",           0 },
2390         { rtfACharAttr, rtfACAllCaps,           "caps",         0 },
2391         { rtfACharAttr, rtfACForeColor,         "acf",          0 },
2392         { rtfACharAttr, rtfACSubScript,         "adn",          0 },
2393         { rtfACharAttr, rtfACExpand,            "aexpnd",       0 },
2394         { rtfACharAttr, rtfACFontNum,           "af",           0 },
2395         { rtfACharAttr, rtfACFontSize,          "afs",          0 },
2396         { rtfACharAttr, rtfACItalic,            "ai",           0 },
2397         { rtfACharAttr, rtfACLanguage,          "alang",        0 },
2398         { rtfACharAttr, rtfACOutline,           "aoutl",        0 },
2399         { rtfACharAttr, rtfACSmallCaps,         "ascaps",       0 },
2400         { rtfACharAttr, rtfACShadow,            "ashad",        0 },
2401         { rtfACharAttr, rtfACStrikeThru,        "astrike",      0 },
2402         { rtfACharAttr, rtfACUnderline,         "aul",          0 },
2403         { rtfACharAttr, rtfACDotUnderline,      "auld",         0 },
2404         { rtfACharAttr, rtfACDbUnderline,       "auldb",        0 },
2405         { rtfACharAttr, rtfACNoUnderline,       "aulnone",      0 },
2406         { rtfACharAttr, rtfACWordUnderline,     "aulw",         0 },
2407         { rtfACharAttr, rtfACSuperScript,       "aup",          0 },
2408
2409         /*
2410          * Footnote attributes
2411          */
2412
2413         { rtfFNoteAttr, rtfFNAlt,               "ftnalt",       0 },
2414
2415         /*
2416          * Key code attributes
2417          */
2418
2419         { rtfKeyCodeAttr,       rtfAltKey,              "alt",          0 },
2420         { rtfKeyCodeAttr,       rtfShiftKey,            "shift",        0 },
2421         { rtfKeyCodeAttr,       rtfControlKey,          "ctrl",         0 },
2422         { rtfKeyCodeAttr,       rtfFunctionKey,         "fn",           0 },
2423
2424         /*
2425          * Bookmark attributes
2426          */
2427
2428         { rtfBookmarkAttr, rtfBookmarkFirstCol, "bkmkcolf",     0 },
2429         { rtfBookmarkAttr, rtfBookmarkLastCol,  "bkmkcoll",     0 },
2430
2431         /*
2432          * Index entry attributes
2433          */
2434
2435         { rtfIndexAttr, rtfIndexNumber,         "xef",          0 },
2436         { rtfIndexAttr, rtfIndexBold,           "bxe",          0 },
2437         { rtfIndexAttr, rtfIndexItalic,         "ixe",          0 },
2438
2439         /*
2440          * Table of contents attributes
2441          */
2442
2443         { rtfTOCAttr,   rtfTOCType,             "tcf",          0 },
2444         { rtfTOCAttr,   rtfTOCLevel,            "tcl",          0 },
2445
2446         /*
2447          * Drawing object attributes
2448          */
2449
2450         { rtfDrawAttr,  rtfDrawLock,            "dolock",       0 },
2451         { rtfDrawAttr,  rtfDrawPageRelX,        "doxpage",      0 },
2452         { rtfDrawAttr,  rtfDrawColumnRelX,      "dobxcolumn",   0 },
2453         { rtfDrawAttr,  rtfDrawMarginRelX,      "dobxmargin",   0 },
2454         { rtfDrawAttr,  rtfDrawPageRelY,        "dobypage",     0 },
2455         { rtfDrawAttr,  rtfDrawColumnRelY,      "dobycolumn",   0 },
2456         { rtfDrawAttr,  rtfDrawMarginRelY,      "dobymargin",   0 },
2457         { rtfDrawAttr,  rtfDrawHeight,          "dobhgt",       0 },
2458
2459         { rtfDrawAttr,  rtfDrawBeginGroup,      "dpgroup",      0 },
2460         { rtfDrawAttr,  rtfDrawGroupCount,      "dpcount",      0 },
2461         { rtfDrawAttr,  rtfDrawEndGroup,        "dpendgroup",   0 },
2462         { rtfDrawAttr,  rtfDrawArc,             "dparc",        0 },
2463         { rtfDrawAttr,  rtfDrawCallout,         "dpcallout",    0 },
2464         { rtfDrawAttr,  rtfDrawEllipse,         "dpellipse",    0 },
2465         { rtfDrawAttr,  rtfDrawLine,            "dpline",       0 },
2466         { rtfDrawAttr,  rtfDrawPolygon,         "dppolygon",    0 },
2467         { rtfDrawAttr,  rtfDrawPolyLine,        "dppolyline",   0 },
2468         { rtfDrawAttr,  rtfDrawRect,            "dprect",       0 },
2469         { rtfDrawAttr,  rtfDrawTextBox,         "dptxbx",       0 },
2470
2471         { rtfDrawAttr,  rtfDrawOffsetX,         "dpx",          0 },
2472         { rtfDrawAttr,  rtfDrawSizeX,           "dpxsize",      0 },
2473         { rtfDrawAttr,  rtfDrawOffsetY,         "dpy",          0 },
2474         { rtfDrawAttr,  rtfDrawSizeY,           "dpysize",      0 },
2475
2476         { rtfDrawAttr,  rtfCOAngle,             "dpcoa",        0 },
2477         { rtfDrawAttr,  rtfCOAccentBar,         "dpcoaccent",   0 },
2478         { rtfDrawAttr,  rtfCOBestFit,           "dpcobestfit",  0 },
2479         { rtfDrawAttr,  rtfCOBorder,            "dpcoborder",   0 },
2480         { rtfDrawAttr,  rtfCOAttachAbsDist,     "dpcodabs",     0 },
2481         { rtfDrawAttr,  rtfCOAttachBottom,      "dpcodbottom",  0 },
2482         { rtfDrawAttr,  rtfCOAttachCenter,      "dpcodcenter",  0 },
2483         { rtfDrawAttr,  rtfCOAttachTop,         "dpcodtop",     0 },
2484         { rtfDrawAttr,  rtfCOLength,            "dpcolength",   0 },
2485         { rtfDrawAttr,  rtfCONegXQuadrant,      "dpcominusx",   0 },
2486         { rtfDrawAttr,  rtfCONegYQuadrant,      "dpcominusy",   0 },
2487         { rtfDrawAttr,  rtfCOOffset,            "dpcooffset",   0 },
2488         { rtfDrawAttr,  rtfCOAttachSmart,       "dpcosmarta",   0 },
2489         { rtfDrawAttr,  rtfCODoubleLine,        "dpcotdouble",  0 },
2490         { rtfDrawAttr,  rtfCORightAngle,        "dpcotright",   0 },
2491         { rtfDrawAttr,  rtfCOSingleLine,        "dpcotsingle",  0 },
2492         { rtfDrawAttr,  rtfCOTripleLine,        "dpcottriple",  0 },
2493
2494         { rtfDrawAttr,  rtfDrawTextBoxMargin,   "dptxbxmar",    0 },
2495         { rtfDrawAttr,  rtfDrawTextBoxText,     "dptxbxtext",   0 },
2496         { rtfDrawAttr,  rtfDrawRoundRect,       "dproundr",     0 },
2497
2498         { rtfDrawAttr,  rtfDrawPointX,          "dpptx",        0 },
2499         { rtfDrawAttr,  rtfDrawPointY,          "dppty",        0 },
2500         { rtfDrawAttr,  rtfDrawPolyCount,       "dppolycount",  0 },
2501
2502         { rtfDrawAttr,  rtfDrawArcFlipX,        "dparcflipx",   0 },
2503         { rtfDrawAttr,  rtfDrawArcFlipY,        "dparcflipy",   0 },
2504
2505         { rtfDrawAttr,  rtfDrawLineBlue,        "dplinecob",    0 },
2506         { rtfDrawAttr,  rtfDrawLineGreen,       "dplinecog",    0 },
2507         { rtfDrawAttr,  rtfDrawLineRed,         "dplinecor",    0 },
2508         { rtfDrawAttr,  rtfDrawLinePalette,     "dplinepal",    0 },
2509         { rtfDrawAttr,  rtfDrawLineDashDot,     "dplinedado",   0 },
2510         { rtfDrawAttr,  rtfDrawLineDashDotDot,  "dplinedadodo", 0 },
2511         { rtfDrawAttr,  rtfDrawLineDash,        "dplinedash",   0 },
2512         { rtfDrawAttr,  rtfDrawLineDot,         "dplinedot",    0 },
2513         { rtfDrawAttr,  rtfDrawLineGray,        "dplinegray",   0 },
2514         { rtfDrawAttr,  rtfDrawLineHollow,      "dplinehollow", 0 },
2515         { rtfDrawAttr,  rtfDrawLineSolid,       "dplinesolid",  0 },
2516         { rtfDrawAttr,  rtfDrawLineWidth,       "dplinew",      0 },
2517
2518         { rtfDrawAttr,  rtfDrawHollowEndArrow,  "dpaendhol",    0 },
2519         { rtfDrawAttr,  rtfDrawEndArrowLength,  "dpaendl",      0 },
2520         { rtfDrawAttr,  rtfDrawSolidEndArrow,   "dpaendsol",    0 },
2521         { rtfDrawAttr,  rtfDrawEndArrowWidth,   "dpaendw",      0 },
2522         { rtfDrawAttr,  rtfDrawHollowStartArrow,"dpastarthol",  0 },
2523         { rtfDrawAttr,  rtfDrawStartArrowLength,"dpastartl",    0 },
2524         { rtfDrawAttr,  rtfDrawSolidStartArrow, "dpastartsol",  0 },
2525         { rtfDrawAttr,  rtfDrawStartArrowWidth, "dpastartw",    0 },
2526
2527         { rtfDrawAttr,  rtfDrawBgFillBlue,      "dpfillbgcb",   0 },
2528         { rtfDrawAttr,  rtfDrawBgFillGreen,     "dpfillbgcg",   0 },
2529         { rtfDrawAttr,  rtfDrawBgFillRed,       "dpfillbgcr",   0 },
2530         { rtfDrawAttr,  rtfDrawBgFillPalette,   "dpfillbgpal",  0 },
2531         { rtfDrawAttr,  rtfDrawBgFillGray,      "dpfillbggray", 0 },
2532         { rtfDrawAttr,  rtfDrawFgFillBlue,      "dpfillfgcb",   0 },
2533         { rtfDrawAttr,  rtfDrawFgFillGreen,     "dpfillfgcg",   0 },
2534         { rtfDrawAttr,  rtfDrawFgFillRed,       "dpfillfgcr",   0 },
2535         { rtfDrawAttr,  rtfDrawFgFillPalette,   "dpfillfgpal",  0 },
2536         { rtfDrawAttr,  rtfDrawFgFillGray,      "dpfillfggray", 0 },
2537         { rtfDrawAttr,  rtfDrawFillPatIndex,    "dpfillpat",    0 },
2538
2539         { rtfDrawAttr,  rtfDrawShadow,          "dpshadow",     0 },
2540         { rtfDrawAttr,  rtfDrawShadowXOffset,   "dpshadx",      0 },
2541         { rtfDrawAttr,  rtfDrawShadowYOffset,   "dpshady",      0 },
2542
2543         { rtfVersion,   -1,                     "rtf",          0 },
2544         { rtfDefFont,   -1,                     "deff",         0 },
2545
2546         { 0,            -1,                     (char *) NULL,  0 }
2547 };
2548
2549
2550 /*
2551  * Initialize lookup table hash values.  Only need to do this once.
2552  */
2553
2554 static void
2555 LookupInit ()
2556 {
2557 static int      inited = 0;
2558 RTFKey  *rp;
2559
2560         if (inited == 0)
2561         {
2562                 for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
2563                         rp->rtfKHash = Hash (rp->rtfKStr);
2564                 ++inited;
2565         }
2566 }
2567
2568
2569 /*
2570  * Determine major and minor number of control token.  If it's
2571  * not found, the class turns into rtfUnknown.
2572  */
2573
2574 static void
2575 Lookup (s)
2576 char    *s;
2577 {
2578 RTFKey  *rp;
2579 int     hash;
2580
2581         ++s;                    /* skip over the leading \ character */
2582         hash = Hash (s);
2583         for (rp = rtfKey; rp->rtfKStr != (char *) NULL; rp++)
2584         {
2585                 if (hash == rp->rtfKHash && strcmp (s, rp->rtfKStr) == 0)
2586                 {
2587                         rtfClass = rtfControl;
2588                         rtfMajor = rp->rtfKMajor;
2589                         rtfMinor = rp->rtfKMinor;
2590                         return;
2591                 }
2592         }
2593         rtfClass = rtfUnknown;
2594 }
2595
2596
2597 /*
2598  * Compute hash value of symbol
2599  */
2600
2601 static int
2602 Hash (s)
2603 char    *s;
2604 {
2605 char    c;
2606 int     val = 0;
2607
2608         while ((c = *s++) != '\0')
2609                 val += (int) c;
2610         return (val);
2611 }
2612
2613
2614 /* ---------------------------------------------------------------------- */
2615
2616 /*
2617  * Memory allocation routines
2618  */
2619
2620
2621 /*
2622  * Return pointer to block of size bytes, or NULL if there's
2623  * not enough memory available.
2624  *
2625  * This is called through RTFAlloc(), a define which coerces the
2626  * argument to int.  This avoids the persistent problem of allocation
2627  * failing under THINK C when a long is passed.
2628  */
2629
2630 char *
2631 _RTFAlloc (size)
2632 int     size;
2633 {
2634         return HeapAlloc(RICHED32_hHeap, 0, size);
2635 }
2636
2637
2638 /*
2639  * Saves a string on the heap and returns a pointer to it.
2640  */
2641
2642
2643 char *
2644 RTFStrSave (s)
2645 char    *s;
2646 {
2647 char    *p;
2648
2649         if ((p = RTFAlloc ((int) (strlen (s) + 1))) == (char *) NULL)
2650                 return ((char *) NULL);
2651         return (strcpy (p, s));
2652 }
2653
2654
2655 void
2656 RTFFree (p)
2657 char    *p;
2658 {
2659         if (p != (char *) NULL)
2660                 HeapFree(RICHED32_hHeap, 0, p);
2661 }
2662
2663
2664 /* ---------------------------------------------------------------------- */
2665
2666
2667 /*
2668  * Token comparison routines
2669  */
2670
2671 int
2672 RTFCheckCM (class, major)
2673 int     class, major;
2674 {
2675         return (rtfClass == class && rtfMajor == major);
2676 }
2677
2678
2679 int
2680 RTFCheckCMM (class, major, minor)
2681 int     class, major, minor;
2682 {
2683         return (rtfClass == class && rtfMajor == major && rtfMinor == minor);
2684 }
2685
2686
2687 int
2688 RTFCheckMM (major, minor)
2689 int     major, minor;
2690 {
2691         return (rtfMajor == major && rtfMinor == minor);
2692 }
2693
2694
2695 /* ---------------------------------------------------------------------- */
2696
2697
2698 int
2699 RTFCharToHex (c)
2700 char    c;
2701 {
2702         if (isupper (c))
2703                 c = tolower (c);
2704         if (isdigit (c))
2705                 return (c - '0');       /* '0'..'9' */
2706         return (c - 'a' + 10);          /* 'a'..'f' */
2707 }
2708
2709
2710 int
2711 RTFHexToChar (i)
2712 int     i;
2713 {
2714         if (i < 10)
2715                 return (i + '0');
2716         return (i - 10 + 'a');
2717 }
2718
2719
2720 /* ---------------------------------------------------------------------- */
2721
2722 /*
2723  * RTFReadOutputMap() -- Read output translation map
2724  */
2725
2726 /*
2727  * Read in an array describing the relation between the standard character set
2728  * and an RTF translator's corresponding output sequences.  Each line consists
2729  * of a standard character name and the output sequence for that character.
2730  *
2731  * outMap is an array of strings into which the sequences should be placed.
2732  * It should be declared like this in the calling program:
2733  *
2734  *      char *outMap[rtfSC_MaxChar];
2735  *
2736  * reinit should be non-zero if outMap should be initialized 
2737  * zero otherwise.
2738  *
2739  */
2740
2741 int
2742 RTFReadOutputMap (outMap, reinit)
2743 char    *outMap[];
2744 int     reinit;
2745 {
2746     int  i;
2747     int  stdCode;
2748     char *name, *seq;
2749
2750     if (reinit)
2751     {
2752         for (i = 0; i < rtfSC_MaxChar; i++)
2753         {
2754             outMap[i] = (char *) NULL;
2755         }
2756     }
2757
2758     for (i=0 ;i< sizeof(text_map)/sizeof(char*); i+=2)
2759     {
2760         name = text_map[i];
2761         seq  = text_map[i+1];
2762         stdCode = RTFStdCharCode( name );
2763         outMap[stdCode] = seq;
2764     }
2765
2766     return (1);
2767 }
2768
2769 /* ---------------------------------------------------------------------- */
2770
2771 /*
2772  * Open a library file.
2773  */
2774
2775
2776 static FILE     *(*libFileOpen) () = NULL;
2777
2778
2779
2780 void
2781 RTFSetOpenLibFileProc (proc)
2782 FILE    *(*proc) ();
2783 {
2784     libFileOpen = proc;
2785 }
2786
2787
2788 FILE *
2789 RTFOpenLibFile (file, mode)
2790 char    *file;
2791 char    *mode;
2792 {
2793         if (libFileOpen == NULL)
2794                 return ((FILE *) NULL);
2795         return ((*libFileOpen) (file, mode));
2796 }
2797
2798
2799 /* ---------------------------------------------------------------------- */
2800
2801 /*
2802  * Print message.  Default is to send message to stderr
2803  * but this may be overridden with RTFSetMsgProc().
2804  *
2805  * Message should include linefeeds as necessary.  If the default
2806  * function is overridden, the overriding function may want to
2807  * map linefeeds to another line ending character or sequence if
2808  * the host system doesn't use linefeeds.
2809  */
2810
2811
2812 static void
2813 DefaultMsgProc (s)
2814 char    *s;
2815 {
2816         fprintf (stderr, "%s", s);
2817 }
2818
2819
2820 static RTFFuncPtr       msgProc = DefaultMsgProc;
2821
2822
2823 void
2824 RTFSetMsgProc (proc)
2825 RTFFuncPtr      proc;
2826 {
2827         msgProc = proc;
2828 }
2829
2830
2831 # ifdef STDARG
2832
2833 /*
2834  * This version is for systems with stdarg
2835  */
2836
2837 void
2838 RTFMsg (char *fmt, ...)
2839 {
2840 char    buf[rtfBufSiz];
2841
2842         va_list args;
2843         va_start (args,fmt);
2844         vsprintf (buf, fmt, args);
2845         va_end (args);
2846         (*msgProc) (buf);
2847 }
2848
2849 # else /* !STDARG */
2850
2851 # ifdef VARARGS
2852
2853
2854 /*
2855  * This version is for systems that have varargs.
2856  */
2857
2858 void
2859 RTFMsg (va_alist)
2860 va_dcl
2861 {
2862 va_list args;
2863 char    *fmt;
2864 char    buf[rtfBufSiz];
2865
2866         va_start (args);
2867         fmt = va_arg (args, char *);
2868         vsprintf (buf, fmt, args);
2869         va_end (args);
2870         (*msgProc) (buf);
2871 }
2872
2873 # else  /* !VARARGS */
2874
2875 /*
2876  * This version is for systems that don't have varargs.
2877  */
2878
2879 void
2880 RTFMsg (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
2881 char    *fmt;
2882 char    *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
2883 {
2884 char    buf[rtfBufSiz];
2885
2886         sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
2887         (*msgProc) (buf);
2888 }
2889
2890 # endif /* !VARARGS */
2891 # endif /* !STDARG */
2892
2893
2894 /* ---------------------------------------------------------------------- */
2895
2896
2897 /*
2898  * Process termination.  Print error message and exit.  Also prints
2899  * current token, and current input line number and position within
2900  * line if any input has been read from the current file.  (No input
2901  * has been read if prevChar is EOF).
2902  */
2903
2904 static void
2905 DefaultPanicProc (s)
2906 char    *s;
2907 {
2908         fprintf (stderr, "%s", s);
2909         /*exit (1);*/
2910 }
2911
2912
2913 static RTFFuncPtr       panicProc = DefaultPanicProc;
2914
2915
2916 void
2917 RTFSetPanicProc (proc)
2918 RTFFuncPtr      proc;
2919 {
2920         panicProc = proc;
2921 }
2922
2923
2924 # ifdef STDARG
2925
2926 /*
2927  * This version is for systems with stdarg
2928  */
2929
2930 void
2931 RTFPanic (char *fmt, ...)
2932 {
2933 char    buf[rtfBufSiz];
2934
2935         va_list args;
2936         va_start (args,fmt);
2937         vsprintf (buf, fmt, args);
2938         va_end (args);
2939         (void) strcat (buf, "\n");
2940         if (prevChar != EOF && rtfTextBuf != (char *) NULL)
2941         {
2942                 sprintf (buf + strlen (buf),
2943                         "Last token read was \"%s\" near line %ld, position %d.\n",
2944                         rtfTextBuf, rtfLineNum, rtfLinePos);
2945         }
2946         (*panicProc) (buf);
2947 }
2948
2949 # else /* !STDARG */
2950
2951 # ifdef VARARGS
2952
2953
2954 /*
2955  * This version is for systems that have varargs.
2956  */
2957
2958 void
2959 RTFPanic (va_alist)
2960 va_dcl
2961 {
2962 va_list args;
2963 char    *fmt;
2964 char    buf[rtfBufSiz];
2965
2966         va_start (args);
2967         fmt = va_arg (args, char *);
2968         vsprintf (buf, fmt, args);
2969         va_end (args);
2970         (void) strcat (buf, "\n");
2971         if (prevChar != EOF && rtfTextBuf != (char *) NULL)
2972         {
2973                 sprintf (buf + strlen (buf),
2974                         "Last token read was \"%s\" near line %ld, position %d.\n",
2975                         rtfTextBuf, rtfLineNum, rtfLinePos);
2976         }
2977         (*panicProc) (buf);
2978 }
2979
2980 # else  /* !VARARGS */
2981
2982 /*
2983  * This version is for systems that don't have varargs.
2984  */
2985
2986 void
2987 RTFPanic (fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
2988 char    *fmt;
2989 char    *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
2990 {
2991 char    buf[rtfBufSiz];
2992
2993         sprintf (buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
2994         (void) strcat (buf, "\n");
2995         if (prevChar != EOF && rtfTextBuf != (char *) NULL)
2996         {
2997                 sprintf (buf + strlen (buf),
2998                         "Last token read was \"%s\" near line %ld, position %d.\n",
2999                         rtfTextBuf, rtfLineNum, rtfLinePos);
3000         }
3001         (*panicProc) (buf);
3002 }
3003
3004 # endif /* !VARARGS */
3005 # endif /* !STDARG */