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