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