update for HEAD-2003091401
[reactos.git] / lib / richedit / text-writer.c
1 /*
2  * text-writer -- RTF-to-text translation writer code.
3  *
4  * Read RTF input, write text of document (text extraction).
5  *
6  * Wrapper must call WriterInit() once before processing any files,
7  * then set up input and call BeginFile() for each input file.
8  *
9  * This installs callbacks for the text and control token classes.
10  * The control class is necessary so that special characters such as
11  * \par, \tab, \sect, etc.  can be converted.
12  *
13  * It's problematic what to do with text in headers and footers, and
14  * what to do about tables.
15  *
16  * This really is quite a stupid program, for instance, it could keep
17  * track of the current leader character and dump that out when a tab
18  * is encountered.
19  *
20  * 04 Feb 91    Paul DuBois     dubois@primate.wisc.edu
21  *
22  * This software may be redistributed without restriction and used for
23  * any purpose whatsoever.
24  *
25  * 04 Feb 91
26  * -Created.
27  * 27 Feb 91
28  * - Updated for distribution 1.05.
29  * 13 Jul 93
30  * - Updated to compile under THINK C 6.0.
31  * 31 Aug 93
32  * - Added Mike Sendall's entries for Macintosh char map.
33  * 07 Sep 93
34  * - Uses charset map and output sequence map for character translation.
35  * 11 Mar 94
36  * - Updated for 1.10 distribution.
37  */
38
39 #include <stdio.h>
40
41 #include "rtf.h"
42 #include "rtf2text.h"
43 #include "charlist.h"
44 #include "debug.h"
45
46 #if 0
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
50 #else
51   #define TRACE DPRINT
52   #define WARN DPRINT
53   #define FIXME DPRINT
54 #endif
55
56 static void     TextClass ();
57 static void     ControlClass ();
58 static void     Destination ();
59 static void     SpecialChar ();
60 static void     PutStdChar ();
61 static void     PutLitChar ();
62 static void     PutLitStr ();
63
64 static char     *outMap[rtfSC_MaxChar];
65
66 static CHARLIST charlist = {0, NULL, NULL};
67
68 int RTFToBuffer(char* pBuffer, int nBufferSize);
69 int RTFToBuffer(char* pBuffer, int nBufferSize)
70 {
71
72    /* check if the buffer is big enough to hold all characters  */
73    /* we require one more for the '\0'                          */
74
75    TRACE("\n");
76
77    if(nBufferSize < charlist.nCount + 1) {
78         return charlist.nCount + CHARLIST_CountChar(&charlist, '\n') + 1;
79    }
80
81    while(charlist.nCount)
82    {
83        *pBuffer = CHARLIST_Dequeue(&charlist);
84        if(*pBuffer=='\n')
85        {
86          *pBuffer = '\r';
87          pBuffer++;
88          *pBuffer = '\n';
89        }
90        pBuffer++;
91    }
92    *pBuffer = '\0';
93
94    return 0;
95 }
96
97
98 /*
99  * Initialize the writer.
100  */
101
102 void
103 WriterInit ()
104 {
105         RTFReadOutputMap (outMap,1);
106 }
107
108
109 int
110 BeginFile ()
111 {
112         /* install class callbacks */
113
114         RTFSetClassCallback (rtfText, TextClass);
115         RTFSetClassCallback (rtfControl, ControlClass);
116
117         return (1);
118 }
119
120
121 /*
122  * Write out a character.  rtfMajor contains the input character, rtfMinor
123  * contains the corresponding standard character code.
124  *
125  * If the input character isn't in the charset map, try to print some
126  * representation of it.
127  */
128
129 static void
130 TextClass ()
131 {
132 char    buf[rtfBufSiz];
133
134         TRACE("\n");
135
136         if (rtfFormat == SF_TEXT)
137                 PutLitChar (rtfMajor);
138         else if (rtfMinor != rtfSC_nothing)
139                 PutStdChar (rtfMinor);
140         else
141         {
142                 if (rtfMajor < 128)     /* in ASCII range */
143                         sprintf (buf, "[[%c]]", rtfMajor);
144                 else
145                         sprintf (buf, "[[\\'%02x]]", rtfMajor);
146                 PutLitStr (buf);
147         }
148 }
149
150
151 static void
152 ControlClass ()
153 {
154         TRACE("\n");
155         switch (rtfMajor)
156         {
157         case rtfDestination:
158                 Destination ();
159                 break;
160         case rtfSpecialChar:
161                 SpecialChar ();
162                 break;
163         }
164 }
165
166
167 /*
168  * This function notices destinations that should be ignored
169  * and skips to their ends.  This keeps, for instance, picture
170  * data from being considered as plain text.
171  */
172
173 static void
174 Destination ()
175 {
176
177         TRACE("\n");
178
179         switch (rtfMinor)
180         {
181         case rtfPict:
182         case rtfFNContSep:
183         case rtfFNContNotice:
184         case rtfInfo:
185         case rtfIndexRange:
186         case rtfITitle:
187         case rtfISubject:
188         case rtfIAuthor:
189         case rtfIOperator:
190         case rtfIKeywords:
191         case rtfIComment:
192         case rtfIVersion:
193         case rtfIDoccomm:
194                 RTFSkipGroup ();
195                 break;
196         }
197 }
198
199
200 /*
201  * The reason these use the rtfSC_xxx thingies instead of just writing
202  * out ' ', '-', '"', etc., is so that the mapping for these characters
203  * can be controlled by the text-map file.
204  */
205
206 void SpecialChar ()
207 {
208
209         TRACE("\n");
210
211         switch (rtfMinor)
212         {
213         case rtfPage:
214         case rtfSect:
215         case rtfRow:
216         case rtfLine:
217         case rtfPar:
218                 PutLitChar ('\n');
219                 break;
220         case rtfCell:
221                 PutStdChar (rtfSC_space);       /* make sure cells are separated */
222                 break;
223         case rtfNoBrkSpace:
224                 PutStdChar (rtfSC_nobrkspace);
225                 break;
226         case rtfTab:
227                 PutLitChar ('\t');
228                 break;
229         case rtfNoBrkHyphen:
230                 PutStdChar (rtfSC_nobrkhyphen);
231                 break;
232         case rtfBullet:
233                 PutStdChar (rtfSC_bullet);
234                 break;
235         case rtfEmDash:
236                 PutStdChar (rtfSC_emdash);
237                 break;
238         case rtfEnDash:
239                 PutStdChar (rtfSC_endash);
240                 break;
241         case rtfLQuote:
242                 PutStdChar (rtfSC_quoteleft);
243                 break;
244         case rtfRQuote:
245                 PutStdChar (rtfSC_quoteright);
246                 break;
247         case rtfLDblQuote:
248                 PutStdChar (rtfSC_quotedblleft);
249                 break;
250         case rtfRDblQuote:
251                 PutStdChar (rtfSC_quotedblright);
252                 break;
253         }
254 }
255
256
257 /*
258  * Eventually this should keep track of the destination of the
259  * current state and only write text when in the initial state.
260  *
261  * If the output sequence is unspecified in the output map, write
262  * the character's standard name instead.  This makes map deficiencies
263  * obvious and provides incentive to fix it. :-)
264  */
265
266 void PutStdChar (int stdCode)
267 {
268
269   char  *oStr = (char *) NULL;
270   char  buf[rtfBufSiz];
271
272 /*      if (stdCode == rtfSC_nothing)
273                 RTFPanic ("Unknown character code, logic error\n");
274 */
275         TRACE("\n");
276
277         oStr = outMap[stdCode];
278         if (oStr == (char *) NULL)      /* no output sequence in map */
279         {
280                 sprintf (buf, "[[%s]]", RTFStdCharName (stdCode));
281                 oStr = buf;
282         }
283         PutLitStr (oStr);
284 }
285
286
287 void PutLitChar (int c)
288 {
289         CHARLIST_Enqueue(&charlist, (char) c);
290         /* fputc (c, ostream); */
291 }
292
293
294 static void PutLitStr (char     *s)
295 {
296         for(;*s;s++)
297         {
298           CHARLIST_Enqueue(&charlist, *s);
299         }
300         /* fputs (s, ostream); */
301 }