1 /************************************************************************/
2 /* */
3 /* Save a BufferDocument into a plain text file. */
4 /* */
5 /************************************************************************/
6
7 # include "docRtfConfig.h"
8
9 # include <stdio.h>
10 # include <ctype.h>
11
12 # include <docBuf.h>
13 # include <docNotes.h>
14 # include <docTreeNode.h>
15 # include <docNodeTree.h>
16 # include <docTreeType.h>
17 # include <docTreeScanner.h>
18 # include "docPlainReadWrite.h"
19 # include <docParaParticules.h>
20 # include <docTextParticule.h>
21 # include <docDocumentNote.h>
22 # include <sioGeneral.h>
23
24 # include <appDebugon.h>
25
26 typedef struct PlainWritingContext
27 {
28 SimpleOutputStream * pwcSos;
29 BufferDocument * pwcDocument;
30
31 int pwcFold;
32 int pwcHasOpenEnd;
33 int pwcNoteRefCount;
34 int pwcNoteDefCount;
35 } PlainWritingContext;
36
docInitPlainWritingContext(PlainWritingContext * pwc)37 static void docInitPlainWritingContext( PlainWritingContext * pwc )
38 {
39 pwc->pwcSos= (SimpleOutputStream *)0;
40 pwc->pwcDocument= (BufferDocument *)0;
41
42 pwc->pwcFold= 0;
43 pwc->pwcHasOpenEnd= 0;
44 pwc->pwcNoteRefCount= 0;
45 pwc->pwcNoteDefCount= 0;
46 }
47
docPlainSaveParaNode(PlainWritingContext * pwc,const BufferItem * paraNode,const DocumentSelection * ds)48 static int docPlainSaveParaNode( PlainWritingContext * pwc,
49 const BufferItem * paraNode,
50 const DocumentSelection * ds )
51 {
52 TextParticule * tp;
53 int pos= 0;
54 int lineCount= 0;
55
56 int part= 0;
57 int partUpto= paraNode->biParaParticuleCount;
58 int stroffFrom= -1;
59 int stroffUpto= -1;
60 int headFlags= 0;
61 int tailFlags= 0;
62 int close= 1;
63
64 BufferDocument * bd= pwc->pwcDocument;
65 SimpleOutputStream * sos= pwc->pwcSos;
66
67 const DocumentField * df;
68
69 if ( ds )
70 {
71 DocumentSelection dsPara;
72
73 if ( docIntersectSelectionWithParagraph( &dsPara,
74 &part, &partUpto,
75 &headFlags, &tailFlags,
76 paraNode, ds ) )
77 { LDEB(1); return -1; }
78
79 stroffFrom= dsPara.dsHead.dpStroff;
80 stroffUpto= dsPara.dsTail.dpStroff;
81
82 if ( ds->dsTail.dpNode == paraNode )
83 { close= ! pwc->pwcHasOpenEnd; }
84 }
85 else{
86 if ( ! docNextParagraph( (BufferItem *)paraNode ) )
87 { close= ! pwc->pwcHasOpenEnd; }
88 }
89
90 tp= paraNode->biParaParticules+ part;
91 while( part < paraNode->biParaParticuleCount )
92 {
93 TextAttribute ta;
94
95 docGetTextAttributeByNumber( &ta, bd, tp->tpTextAttrNr );
96
97 switch( tp->tpKind )
98 {
99 case DOCkindTAB:
100 if ( sioOutPutByte( '\t', sos ) < 0 )
101 { LDEB(1); return -1; }
102 pos= 8* ( pos+ 8 )/ 8;
103 break;
104
105 case DOCkindSPAN:
106 if ( pwc->pwcFold && pos > 8 && pos+ tp->tpStrlen >= 72 )
107 {
108 if ( sioOutPutByte( '\n', sos ) < 0 )
109 { LDEB(1); return -1; }
110 lineCount++; pos= 0;
111
112 if ( paraNode->biParaFirstIndentTwips < -9 &&
113 paraNode->biParaLeftIndentTwips > 9 )
114 {
115 if ( sioOutPutByte( '\t', sos ) < 0 )
116 { LDEB(1); return -1; }
117 pos= 8;
118 }
119 }
120
121 {
122 int stroff= tp->tpStroff;
123 int upto= stroffUpto;
124 const unsigned char * s;
125
126 if ( stroff < stroffFrom )
127 { stroff= stroffFrom; }
128 if ( upto < 0 )
129 { upto= tp->tpStroff+ tp->tpStrlen; }
130
131 s= docParaString( paraNode, stroff );
132 while( stroff < upto )
133 {
134 if ( sioOutPutByte( *s, sos ) < 0 )
135 { LDEB(1); return -1; }
136 s++; stroff++; pos++;
137 }
138 }
139
140 break;
141
142 case DOCkindLINEBREAK:
143 if ( sioOutPutByte( '\n', sos ) < 0 )
144 { LDEB(1); return -1; }
145 pos= 0;
146 break;
147
148 case DOCkindPAGEBREAK:
149 case DOCkindCOLUMNBREAK:
150 if ( sioOutPutByte( '\n', sos ) < 0 )
151 { LDEB(1); return -1; }
152 if ( sioOutPutByte( '\f', sos ) < 0 )
153 { LDEB(1); return -1; }
154 pos= 0;
155 break;
156
157 case DOCkindFIELDHEAD:
158 df= docGetFieldByNumber( &(bd->bdFieldList),
159 tp->tpObjectNumber );
160
161 if ( df->dfKind == DOCfkPAGEREF )
162 {
163 int count;
164 int closed;
165
166 count= docCountParticulesInField( paraNode, &closed, part,
167 paraNode->biParaParticuleCount );
168
169 count++;
170 tp += count; part += count;
171 break;
172 }
173
174 if ( df->dfKind == DOCfkCHFTN )
175 {
176 int count;
177 int closed;
178 char scratch[20+1];
179
180 count= docCountParticulesInField( paraNode, &closed, part,
181 paraNode->biParaParticuleCount );
182
183 if ( paraNode->biTreeType == DOCinBODY )
184 {
185 sprintf( scratch, "[%d]", pwc->pwcNoteRefCount+ 1 );
186 pwc->pwcNoteRefCount++;
187 }
188 else{
189 sprintf( scratch, "[%d]", pwc->pwcNoteDefCount+ 1 );
190 pwc->pwcNoteDefCount++;
191 }
192
193 sioOutPutString( scratch, sos );
194
195 tp += count; part += count;
196 }
197 break;
198
199 default:
200 LDEB(tp->tpKind);
201 /*FALLTHROUGH*/
202 case DOCkindOBJECT:
203 case DOCkindFIELDTAIL:
204 case DOCkindLTR_MARK:
205 case DOCkindRTL_MARK:
206 break;
207 }
208
209 part++; tp++;
210 }
211
212 if ( close )
213 {
214 if ( sioOutPutByte( '\n', sos ) < 0 )
215 { LDEB(1); return -1; }
216
217 lineCount++;
218 }
219
220 return 0;
221 }
222
docPlainEnterNode(BufferItem * node,const DocumentSelection * ds,const BufferItem * bodySectNode,void * voidpwc)223 static int docPlainEnterNode( BufferItem * node,
224 const DocumentSelection * ds,
225 const BufferItem * bodySectNode,
226 void * voidpwc )
227 {
228 PlainWritingContext * pwc= (PlainWritingContext *)voidpwc;
229
230 switch( node->biLevel )
231 {
232 case DOClevBODY:
233 case DOClevSECT:
234 case DOClevCELL:
235 case DOClevROW:
236 return ADVICEtsOK;
237
238 case DOClevPARA:
239 if ( docPlainSaveParaNode( pwc, node, ds ) )
240 { LDEB(1); return -1; }
241 return ADVICEtsOK;
242
243 default:
244 LDEB(node->biLevel); return -1;
245 }
246 }
247
248
docPlainSaveDocument(SimpleOutputStream * sos,BufferDocument * bd,const DocumentSelection * ds,int fold)249 int docPlainSaveDocument( SimpleOutputStream * sos,
250 BufferDocument * bd,
251 const DocumentSelection * ds,
252 int fold )
253 {
254 const int flags= 0;
255 PlainWritingContext pwc;
256
257 docInitPlainWritingContext( &pwc );
258
259 pwc.pwcFold= fold;
260 pwc.pwcHasOpenEnd= bd->bdProperties.dpHasOpenEnd;
261 pwc.pwcDocument= bd;
262 pwc.pwcSos= sos;
263
264 if ( ds )
265 { pwc.pwcHasOpenEnd= 1; }
266
267 if ( ds )
268 {
269 if ( docScanSelection( bd, ds, docPlainEnterNode,
270 (NodeVisitor)0, flags, (void *)&pwc ) < 0 )
271 { LDEB(1); return -1; }
272 }
273 else{
274 if ( docScanTree( bd, &(bd->bdBody), docPlainEnterNode,
275 (NodeVisitor)0, flags, (void *)&pwc ) < 0 )
276 { LDEB(1); return -1; }
277 }
278
279 if ( ! ds && pwc.pwcNoteRefCount > 0 )
280 {
281 DocumentField * dfNote;
282 DocumentNote * dn;
283
284 sioOutPutString( "\n-----\n\n", sos );
285
286 for ( dfNote= docGetFirstNoteOfDocument( &dn, bd, -1 );
287 dfNote;
288 dfNote= docGetNextNoteInDocument( &dn, bd, dfNote, -1 ) )
289 {
290 if ( docScanTree( bd, &(dn->dnDocumentTree), docPlainEnterNode,
291 (NodeVisitor)0, flags, (void *)&pwc ) < 0 )
292 { LDEB(1); return -1; }
293 }
294
295 if ( pwc.pwcNoteDefCount != pwc.pwcNoteRefCount )
296 { LLDEB(pwc.pwcNoteDefCount,pwc.pwcNoteRefCount); }
297 }
298
299 return 0;
300 }
301