Implemented simple caching of client connections.
[wine] / dlls / 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 "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
47
48 static void     TextClass ();
49 static void     ControlClass ();
50 static void     Destination ();
51 static void     SpecialChar ();
52 static void     PutStdChar ();
53 static void     PutLitChar ();
54 static void     PutLitStr ();
55
56 static char     *outMap[rtfSC_MaxChar];
57
58 static CHARLIST charlist = {0, NULL, NULL};
59
60 int RTFToBuffer(char* pBuffer, int nBufferSize);
61 int RTFToBuffer(char* pBuffer, int nBufferSize)
62 {
63
64    /* check if the buffer is big enough to hold all characters  */
65    /* we require one more for the '\0'                          */
66
67    TRACE("\n");
68
69    if(nBufferSize < charlist.nCount + 1) {
70         return charlist.nCount + CHARLIST_CountChar(&charlist, '\n') + 1;
71    }
72
73    while(charlist.nCount)
74    {
75        *pBuffer = CHARLIST_Dequeue(&charlist);
76        if(*pBuffer=='\n')
77        {
78          *pBuffer = '\r';
79          pBuffer++;
80          *pBuffer = '\n';
81        }
82        pBuffer++;
83    }
84    *pBuffer = '\0';
85
86    return 0;
87 }
88
89
90 /*
91  * Initialize the writer.
92  */
93
94 void
95 WriterInit ()
96 {
97         RTFReadOutputMap (outMap,1);
98 }
99
100
101 int
102 BeginFile ()
103 {
104         /* install class callbacks */
105
106         RTFSetClassCallback (rtfText, TextClass);
107         RTFSetClassCallback (rtfControl, ControlClass);
108
109         return (1);
110 }
111
112
113 /*
114  * Write out a character.  rtfMajor contains the input character, rtfMinor
115  * contains the corresponding standard character code.
116  *
117  * If the input character isn't in the charset map, try to print some
118  * representation of it.
119  */
120
121 static void
122 TextClass ()
123 {
124 char    buf[rtfBufSiz];
125
126         TRACE("\n");
127
128         if (rtfFormat == SF_TEXT)
129                 PutLitChar (rtfMajor);
130         else if (rtfMinor != rtfSC_nothing)
131                 PutStdChar (rtfMinor);
132         else
133         {
134                 if (rtfMajor < 128)     /* in ASCII range */
135                         sprintf (buf, "[[%c]]", rtfMajor);
136                 else
137                         sprintf (buf, "[[\\'%02x]]", rtfMajor);
138                 PutLitStr (buf);
139         }
140 }
141
142
143 static void
144 ControlClass ()
145 {
146         TRACE("\n");
147         switch (rtfMajor)
148         {
149         case rtfDestination:
150                 Destination ();
151                 break;
152         case rtfSpecialChar:
153                 SpecialChar ();
154                 break;
155         }
156 }
157
158
159 /*
160  * This function notices destinations that should be ignored
161  * and skips to their ends.  This keeps, for instance, picture
162  * data from being considered as plain text.
163  */
164
165 static void
166 Destination ()
167 {
168
169         TRACE("\n");
170
171         switch (rtfMinor)
172         {
173         case rtfPict:
174         case rtfFNContSep:
175         case rtfFNContNotice:
176         case rtfInfo:
177         case rtfIndexRange:
178         case rtfITitle:
179         case rtfISubject:
180         case rtfIAuthor:
181         case rtfIOperator:
182         case rtfIKeywords:
183         case rtfIComment:
184         case rtfIVersion:
185         case rtfIDoccomm:
186                 RTFSkipGroup ();
187                 break;
188         }
189 }
190
191
192 /*
193  * The reason these use the rtfSC_xxx thingies instead of just writing
194  * out ' ', '-', '"', etc., is so that the mapping for these characters
195  * can be controlled by the text-map file.
196  */
197
198 void SpecialChar ()
199 {
200
201         TRACE("\n");
202
203         switch (rtfMinor)
204         {
205         case rtfPage:
206         case rtfSect:
207         case rtfRow:
208         case rtfLine:
209         case rtfPar:
210                 PutLitChar ('\n');
211                 break;
212         case rtfCell:
213                 PutStdChar (rtfSC_space);       /* make sure cells are separated */
214                 break;
215         case rtfNoBrkSpace:
216                 PutStdChar (rtfSC_nobrkspace);
217                 break;
218         case rtfTab:
219                 PutLitChar ('\t');
220                 break;
221         case rtfNoBrkHyphen:
222                 PutStdChar (rtfSC_nobrkhyphen);
223                 break;
224         case rtfBullet:
225                 PutStdChar (rtfSC_bullet);
226                 break;
227         case rtfEmDash:
228                 PutStdChar (rtfSC_emdash);
229                 break;
230         case rtfEnDash:
231                 PutStdChar (rtfSC_endash);
232                 break;
233         case rtfLQuote:
234                 PutStdChar (rtfSC_quoteleft);
235                 break;
236         case rtfRQuote:
237                 PutStdChar (rtfSC_quoteright);
238                 break;
239         case rtfLDblQuote:
240                 PutStdChar (rtfSC_quotedblleft);
241                 break;
242         case rtfRDblQuote:
243                 PutStdChar (rtfSC_quotedblright);
244                 break;
245         }
246 }
247
248
249 /*
250  * Eventually this should keep track of the destination of the
251  * current state and only write text when in the initial state.
252  *
253  * If the output sequence is unspecified in the output map, write
254  * the character's standard name instead.  This makes map deficiencies
255  * obvious and provides incentive to fix it. :-)
256  */
257
258 void PutStdChar (int stdCode)
259 {
260
261   char  *oStr = (char *) NULL;
262   char  buf[rtfBufSiz];
263
264 /*      if (stdCode == rtfSC_nothing)
265                 RTFPanic ("Unknown character code, logic error\n");
266 */
267         TRACE("\n");
268
269         oStr = outMap[stdCode];
270         if (oStr == (char *) NULL)      /* no output sequence in map */
271         {
272                 sprintf (buf, "[[%s]]", RTFStdCharName (stdCode));
273                 oStr = buf;
274         }
275         PutLitStr (oStr);
276 }
277
278
279 void PutLitChar (int c)
280 {
281         CHARLIST_Enqueue(&charlist, (char) c);
282         /* fputc (c, ostream); */
283 }
284
285
286 static void PutLitStr (char     *s)
287 {
288         for(;*s;s++)
289         {
290           CHARLIST_Enqueue(&charlist, *s);
291         }
292         /* fputs (s, ostream); */
293 }