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