1 /************************************************************************/
2 /*									*/
3 /*  Trace modifications to a document.					*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docEditConfig.h"
8 
9 #   include	<stdio.h>
10 #   include	<ctype.h>
11 #   include	<string.h>
12 
13 #   include	<appDebugon.h>
14 
15 #   include	<sioFd.h>
16 #   include	<utilMD5.h>
17 
18 #   include	"docRtfTrace.h"
19 #   include	"docEditCommand.h"
20 
21 #   include	<docRtfTraceImpl.h>
22 #   include	<docRtfWriterImpl.h>
23 #   include	<docRtfFlags.h>
24 #   include	<docRtfTags.h>
25 #   include	<docTreeType.h>
26 
27 /************************************************************************/
28 /*									*/
29 /*  Save contents.							*/
30 /*									*/
31 /************************************************************************/
32 
docRtfTraceContents(RtfWriter * rw,const char * tag,const DocumentSelection * ds)33 static int docRtfTraceContents(	RtfWriter *			rw,
34 				const char *			tag,
35 				const DocumentSelection *	ds )
36     {
37     int			rval= 0;
38 
39     int			saveContents= 0;
40 
41     if  ( ! docIsIBarSelection( ds )			||
42 	  ( rw->rwSaveFlags & RTFflagSAVE_SOMETHING )	)
43 	{ saveContents= 1;	}
44 
45     if  ( saveContents )
46 	{
47 	docRtfWriteNextLine( rw );
48 	docRtfWriteDestinationBegin( rw, tag );
49 
50 #	if 0
51 	Why?
52 	{
53 	PropertyMask	dpSaveMask;
54 
55 	if  ( docRtfDocPropMask( &dpSaveMask,
56 					&(rw->rwDocument->bdProperties) ) )
57 	    { LDEB(1); rval= -1; goto ready;	}
58 
59 	if  ( docRtfSaveDocumentProperties( rw, &dpSaveMask,
60 					&(rw->rwDocument->bdProperties) ) )
61 	    { LDEB(1); rval= -1; goto ready;	}
62 	}
63 #	endif
64 
65 	if  ( ds )
66 	    {
67 	    docRtfWriteDestinationBegin( rw, RTFtag__SelOpen );
68 	    docRtfWriteDestinationEnd( rw );
69 	    }
70 
71 	docRtfWriteSwitchToPlain( rw );
72 	docCleanParagraphProperties( &(rw->rwcParagraphProperties) );
73 	docInitParagraphProperties( &(rw->rwcParagraphProperties) );
74 
75 	if  ( docRtfWriteSelection( rw, ds ) )
76 	    { LDEB(1); rval= -1; goto ready;	}
77 
78 	docRtfWriteNextLine( rw );
79 	docRtfWriteDestinationEnd( rw );
80 	}
81 
82   ready:
83 
84     return rval;
85     }
86 
87 /************************************************************************/
88 /*									*/
89 /*  Save the new properties of a property update.			*/
90 /*									*/
91 /************************************************************************/
92 
docRtfTraceNewProperties(EditOperation * eo,const PropertyMask * taSetMask,const TextAttribute * taSet,const PropertyMask * ppSetMask,const ParagraphProperties * ppSet,const PropertyMask * cpSetMask,const CellProperties * cpSet,const PropertyMask * rpSetMask,const RowProperties * rpSet,const PropertyMask * spSetMask,const SectionProperties * spSet,const PropertyMask * dpSetMask,const DocumentProperties * dpSet)93 int docRtfTraceNewProperties(	EditOperation *			eo,
94 				const PropertyMask *		taSetMask,
95 				const TextAttribute *		taSet,
96 
97 				const PropertyMask *		ppSetMask,
98 				const ParagraphProperties *	ppSet,
99 
100 				const PropertyMask *		cpSetMask,
101 				const CellProperties *		cpSet,
102 
103 				const PropertyMask *		rpSetMask,
104 				const RowProperties *		rpSet,
105 
106 				const PropertyMask *		spSetMask,
107 				const SectionProperties *	spSet,
108 
109 				const PropertyMask *		dpSetMask,
110 				const DocumentProperties *	dpSet )
111     {
112     RtfWriter *	rw= eo->eoTraceWriter;
113 
114     if  ( taSetMask && utilPropMaskIsEmpty( taSetMask ) )
115 	{ taSetMask= (const PropertyMask *)0;	}
116     if  ( ppSetMask && utilPropMaskIsEmpty( ppSetMask ) )
117 	{ ppSetMask= (const PropertyMask *)0;	}
118     if  ( cpSetMask && utilPropMaskIsEmpty( cpSetMask ) )
119 	{ cpSetMask= (const PropertyMask *)0;	}
120     if  ( rpSetMask && utilPropMaskIsEmpty( rpSetMask ) )
121 	{ rpSetMask= (const PropertyMask *)0;	}
122     if  ( spSetMask && utilPropMaskIsEmpty( spSetMask ) )
123 	{ spSetMask= (const PropertyMask *)0;	}
124     if  ( dpSetMask && utilPropMaskIsEmpty( dpSetMask ) )
125 	{ dpSetMask= (const PropertyMask *)0;	}
126 
127     docRtfWriteNextLine( rw );
128     docRtfWriteDestinationBegin( rw, RTFtag_NPR );
129 
130     if  ( dpSetMask )
131 	{ docRtfSaveDocumentProperties( rw, -1, dpSetMask, dpSet );	}
132     if  ( spSetMask )
133 	{ docRtfSaveSectionProperties( rw, spSetMask, spSet );		}
134     if  ( rpSetMask )
135 	{
136 	const int	col0= -1, col1= -1;
137 
138 	docRtfSaveRowProperties( rw, rpSetMask, rpSet, col0, col1 );
139 	}
140     if  ( cpSetMask )
141 	{
142 	const int	shiftLeft= 0;
143 
144 	docRtfSaveCellProperties( rw, cpSetMask, cpSet, shiftLeft );
145 	}
146 
147     docRtfWriteTag( rw, RTFtag_pard );
148 
149     if  ( ppSetMask )
150 	{ docRtfSaveParagraphProperties( rw, ppSetMask, ppSet );	}
151 
152     docRtfWriteTag( rw, RTFtag_plain );
153 
154     if  ( taSetMask )
155 	{ docRtfSaveTextAttribute( rw, taSetMask, taSet );		}
156 
157     /* NO: just the properties docRtfWriteTag( rw, RTFtag_par ); */
158     docRtfWriteNextLine( rw );
159 
160     docRtfWriteDestinationEnd( rw );
161     return 0;
162     }
163 
164 /************************************************************************/
165 /*									*/
166 /*  Keep track of image properties.					*/
167 /*									*/
168 /************************************************************************/
169 
docRtfTraceImageProperties(EditOperation * eo,const char * tag,const PropertyMask * pipSetMask,const PictureProperties * pipSet)170 static int docRtfTraceImageProperties(
171 				EditOperation *			eo,
172 				const char *			tag,
173 				const PropertyMask *		pipSetMask,
174 				const PictureProperties *	pipSet )
175     {
176     RtfWriter *	rw= eo->eoTraceWriter;
177 
178     docRtfWriteNextLine( rw );
179     docRtfWriteDestinationBegin( rw, tag );
180     docRtfWriteDestinationBegin( rw, RTFtag_pict );
181 
182     if  ( docRtfSavePictureTags( rw, pipSetMask, pipSet ) )
183 	{ LDEB(1); return -1;	}
184 
185     docRtfWriteDestinationEnd( rw );
186     docRtfWriteDestinationEnd( rw );
187     return 0;
188     }
189 
docRtfTraceOldImageProperties(EditOperation * eo,const PropertyMask * pipSetMask,const PictureProperties * pipSet)190 int docRtfTraceOldImageProperties(
191 				EditOperation *			eo,
192 				const PropertyMask *		pipSetMask,
193 				const PictureProperties *	pipSet )
194     {
195     return docRtfTraceImageProperties( eo, RTFtag_OTX,
196 							pipSetMask, pipSet );
197     }
198 
docRtfTraceNewImageProperties(EditOperation * eo,const PropertyMask * pipSetMask,const PictureProperties * pipSet)199 int docRtfTraceNewImageProperties(
200 				EditOperation *			eo,
201 				const PropertyMask *		pipSetMask,
202 				const PictureProperties *	pipSet )
203     {
204     return docRtfTraceImageProperties( eo, RTFtag_NTX,
205 							pipSetMask, pipSet );
206     }
207 
docRtfTraceList(EditOperation * eo,const char * tag,const DocumentList * dl)208 static int docRtfTraceList(	EditOperation *		eo,
209 				const char *		tag,
210 				const DocumentList *	dl )
211     {
212     RtfWriter *	rw= eo->eoTraceWriter;
213 
214     docRtfWriteNextLine( rw );
215     docRtfWriteDestinationBegin( rw, tag );
216 
217     if  ( docRtfWriteListProps( rw, dl ) )
218 	{ LDEB(1); return -1;	}
219 
220     docRtfWriteDestinationEnd( rw );
221     return 0;
222     }
223 
docRtfTraceOldList(EditOperation * eo,const DocumentList * dl)224 int docRtfTraceOldList(		EditOperation *			eo,
225 				const DocumentList *		dl )
226     {
227     return docRtfTraceList( eo, RTFtag_OTX, dl );
228     }
229 
docRtfTraceNewList(EditOperation * eo,const DocumentList * dl)230 int docRtfTraceNewList(		EditOperation *			eo,
231 				const DocumentList *		dl )
232     {
233     return docRtfTraceList( eo, RTFtag_NTX, dl );
234     }
235 
236 /************************************************************************/
237 /*									*/
238 /*  Keep track of note properties.					*/
239 /*									*/
240 /************************************************************************/
241 
docRtfTraceNoteProperties(EditOperation * eo,const char * textTag,const PropertyMask * npSetMask,const NoteProperties * npSet)242 static int docRtfTraceNoteProperties(
243 				EditOperation *			eo,
244 				const char *			textTag,
245 				const PropertyMask *		npSetMask,
246 				const NoteProperties *		npSet )
247     {
248     RtfWriter *	rw= eo->eoTraceWriter;
249 
250     docRtfWriteNextLine( rw );
251     docRtfWriteDestinationBegin( rw, textTag );
252 
253     if  ( npSet->npAutoNumber )
254 	{ docRtfWriteTag( rw, "chftn" );	}
255     else{
256 	docRtfWriteFontEncodedString( rw,
257 				(const char *)npSet->npFixedText.mbBytes,
258 				npSet->npFixedText.mbSize );
259 	}
260 
261     if  ( PROPmaskISSET( npSetMask, NOTEpropAUTO_NUMBER ) )
262 	{
263 	docRtfWriteFlagTag( rw, "FtnAuto", npSet->npAutoNumber );
264 	}
265 
266     docRtfWriteDestinationBegin( rw, RTFtag_footnote );
267 
268     if  ( PROPmaskISSET( npSetMask, NOTEpropTREE_TYPE ) )
269 	{
270 	docRtfWriteAltTag( rw, "ftnalt", "NoFtnalt",
271 					npSet->npTreeType == DOCinENDNOTE );
272 	}
273 
274     docRtfWriteFontEncodedString( rw, "?", 1 );
275 
276     docRtfWriteDestinationEnd( rw );
277     docRtfWriteDestinationEnd( rw );
278 
279     return 0;
280     }
281 
docRtfTraceOldNoteProperties(EditOperation * eo,const PropertyMask * npSetMask,const NoteProperties * npSet)282 int docRtfTraceOldNoteProperties(
283 				EditOperation *			eo,
284 				const PropertyMask *		npSetMask,
285 				const NoteProperties *		npSet )
286     {
287     return docRtfTraceNoteProperties( eo, RTFtag_OTX,
288 							npSetMask, npSet );
289     }
290 
docRtfTraceNewNoteProperties(EditOperation * eo,const PropertyMask * npSetMask,const NoteProperties * npSet)291 int docRtfTraceNewNoteProperties(
292 				EditOperation *			eo,
293 				const PropertyMask *		npSetMask,
294 				const NoteProperties *		npSet )
295     {
296     return docRtfTraceNoteProperties( eo, RTFtag_NTX,
297 							npSetMask, npSet );
298     }
299 
300 /************************************************************************/
301 /*									*/
302 /*  Save the old data before a modification.				*/
303 /*									*/
304 /************************************************************************/
305 
docRtfTraceOldContentsLow(const EditOperation * eo,const DocumentSelection * ds,unsigned int flags)306 int docRtfTraceOldContentsLow(	const EditOperation *		eo,
307 				const DocumentSelection *	ds,
308 				unsigned int			flags )
309     {
310     int			rval= 0;
311 
312     const char *	tag= RTFtag_OTX;
313 
314     RtfWriter *		rw= eo->eoTraceWriter;
315     int			savedFlags= rw->rwSaveFlags;
316 
317     rw->rwSaveFlags |= ( flags | RTFflagUNENCODED );
318 
319     rval= docRtfTraceContents( rw, tag, ds );
320 
321     rw->rwSaveFlags= savedFlags;
322 
323     return rval;
324     }
325 
326 /************************************************************************/
327 /*									*/
328 /*  Save the old data before a modification.				*/
329 /*									*/
330 /************************************************************************/
331 
docRtfTraceOldContents(DocumentSelection * ds,const EditOperation * eo,int level,unsigned int flags)332 int docRtfTraceOldContents(	DocumentSelection *		ds,
333 				const EditOperation *		eo,
334 				int				level,
335 				unsigned int			flags )
336     {
337     const int		direction= 0;
338 
339     docEditOperationGetSelection( ds, eo );
340 
341     switch( level )
342 	{
343 	case DOClevSPAN:
344 	    return docRtfTraceOldContentsLow( eo, ds, flags );
345 	    break;
346 	case DOClevPARA:
347 	    docSelectWholeParagraph( ds, direction );
348 	    return docRtfTraceOldContentsLow( eo, ds, flags );
349 	    break;
350 
351 	case DOClevCELL:
352 	    docSelectWholeCell( ds, direction, 0 );
353 	    return docRtfTraceOldContentsLow( eo, ds, flags );
354 	    break;
355 	case DOClevCOLUMN:
356 	    docSelectWholeCell( ds, direction, 1 );
357 	    return docRtfTraceOldContentsLow( eo, ds, flags );
358 	    break;
359 	case DOClevROW:
360 	    docSelectRow( ds, direction, 1 );
361 	    return docRtfTraceOldContentsLow( eo, ds, flags );
362 	    break;
363 	case DOClevTABLE:
364 	    docSelectWholeTable( ds );
365 	    return docRtfTraceOldContentsLow( eo, ds, flags );
366 	    break;
367 
368 	case DOClevSECT:
369 	    docSelectWholeSection( ds, direction );
370 	    return docRtfTraceOldContentsLow( eo, ds, flags );
371 	    break;
372 	default:
373 	    LDEB(level); return -1;
374 	}
375     }
376 
docRtfTraceOldProperties(DocumentSelection * ds,EditOperation * eo,int level,const PropertyMask * taSetMask,const PropertyMask * ppSetMask,const PropertyMask * cpSetMask,const PropertyMask * rpSetMask,const PropertyMask * spSetMask,const PropertyMask * dpSetMask)377 int docRtfTraceOldProperties(	DocumentSelection *		ds,
378 				EditOperation *			eo,
379 				int				level,
380 				const PropertyMask *		taSetMask,
381 				const PropertyMask *		ppSetMask,
382 				const PropertyMask *		cpSetMask,
383 				const PropertyMask *		rpSetMask,
384 				const PropertyMask *		spSetMask,
385 				const PropertyMask *		dpSetMask )
386     {
387     RtfWriter *	rw= eo->eoTraceWriter;
388 
389     int		flags= RTFflagSAVE_SOMETHING;
390 
391     if  ( taSetMask && utilPropMaskIsEmpty( taSetMask ) )
392 	{ taSetMask= (const PropertyMask *)0;	}
393     if  ( ppSetMask && utilPropMaskIsEmpty( ppSetMask ) )
394 	{ ppSetMask= (const PropertyMask *)0;	}
395     if  ( cpSetMask && utilPropMaskIsEmpty( cpSetMask ) )
396 	{ cpSetMask= (const PropertyMask *)0;	}
397     if  ( rpSetMask && utilPropMaskIsEmpty( rpSetMask ) )
398 	{ rpSetMask= (const PropertyMask *)0;	}
399     if  ( spSetMask && utilPropMaskIsEmpty( spSetMask ) )
400 	{ spSetMask= (const PropertyMask *)0;	}
401     if  ( dpSetMask && utilPropMaskIsEmpty( dpSetMask ) )
402 	{ dpSetMask= (const PropertyMask *)0;	}
403 
404     if  ( taSetMask )
405 	{ flags |= RTFflagSAVE_SOMETHING;	}
406     else{
407 	flags |= RTFflagOMIT_TEXT;
408 
409 	if  ( ! ppSetMask )
410 	    {
411 	    flags |= RTFflagOMIT_PARAS;
412 	    }
413 	}
414 
415     if  ( cpSetMask || rpSetMask )
416 	{ flags |= RTFflagEMIT_CELL;	}
417 
418     rw->rwPpExtraMask= ppSetMask;
419     rw->rwCpExtraMask= cpSetMask;
420     rw->rwRpExtraMask= rpSetMask;
421     rw->rwSpExtraMask= spSetMask;
422 
423     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_PRL, level );
424 
425     if  ( docRtfTraceOldContents( ds, eo, level, flags ) )
426 	{ LDEB(1); return -1;	}
427 
428     rw->rwPpExtraMask= (const PropertyMask *)0;
429     rw->rwCpExtraMask= (const PropertyMask *)0;
430     rw->rwRpExtraMask= (const PropertyMask *)0;
431     rw->rwSpExtraMask= (const PropertyMask *)0;
432 
433     return 0;
434     }
435 
docRtfTraceHeaderFooter(EditOperation * eo,const DocumentTree * dt)436 int docRtfTraceHeaderFooter(	EditOperation *			eo,
437 				const DocumentTree *		dt )
438     {
439     RtfWriter *	rw= eo->eoTraceWriter;
440 
441     docRtfWriteNextLine( rw );
442     docRtfWriteDestinationBegin( rw, RTFtag_OTX );
443 
444     if  ( dt->dtPageSelectedUpon >= 0 )
445 	{
446 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OPG,
447 						    dt->dtPageSelectedUpon );
448 	if  ( dt->dtColumnSelectedIn >= 0 )
449 	    {
450 	    docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OCO,
451 						    dt->dtColumnSelectedIn );
452 	    }
453 	}
454 
455     if  ( docRtfSaveHeaderFooter( rw, dt ) )
456 	{ LDEB(1); return -1;	}
457 
458     docRtfWriteTag( rw, RTFtag_pard );
459     docRtfWriteTag( rw, RTFtag_plain );
460     docRtfWriteTag( rw, RTFtag_par );
461     docRtfWriteNextLine( rw );
462 
463     docRtfWriteDestinationEnd( rw );
464 
465     return 0;
466     }
467 
468 /************************************************************************/
469 /*									*/
470 /*  Save the new data after a modification.				*/
471 /*									*/
472 /************************************************************************/
473 
docRtfTraceNewContents(EditOperation * eo,int posWhere)474 int docRtfTraceNewContents(	EditOperation *			eo,
475 				int				posWhere )
476     {
477     int			rval= 0;
478     EditRange *		er= &(eo->eoAffectedRange);
479     DocumentSelection	ds;
480 
481     RtfWriter *		rw= eo->eoTraceWriter;
482     int			savedFlags= rw->rwSaveFlags;
483 
484     docSelectionForEditPositionsInTree( &ds, eo->eoTree,
485 						&(er->erHead), &(er->erTail) );
486 
487     rw->rwSaveFlags |= RTFflagUNENCODED;
488 
489     if  ( docRtfTraceContents( eo->eoTraceWriter, RTFtag_NTX, &ds ) )
490 	{ LDEB(1); rval= -1; goto ready;	}
491 
492     docRtfTraceNewPosition( eo, (const SelectionScope *)0, posWhere );
493 
494   ready:
495 
496     rw->rwSaveFlags= savedFlags;
497 
498     return rval;
499     }
500 
501 /************************************************************************/
502 /*									*/
503 /*  The tags that indicate where the selection was placed after the	*/
504 /*  modification.							*/
505 /*									*/
506 /************************************************************************/
507 
508 static const char * const DOCrtfSEL_TAGS[]=
509     {
510     RTFtag_SEH,
511     RTFtag_SEN,
512     RTFtag_SAL,
513     RTFtag_SET,
514     RTFtag_SEB,
515     RTFtag_SEA
516     };
517 
518 static const int DOCrtfSEL_TAG_COUNT= sizeof(DOCrtfSEL_TAGS)/sizeof(char *);
519 
520 /************************************************************************/
521 /*									*/
522 /*  Trace the position at the end of the exit operation.		*/
523 /*  If we switch tree (header,footer,note,body) rememer so.		*/
524 /*									*/
525 /************************************************************************/
526 
docRtfTraceNewPosition(EditOperation * eo,const SelectionScope * ssNew,int posWhere)527 int docRtfTraceNewPosition(	EditOperation *			eo,
528 				const SelectionScope *		ssNew,
529 				int				posWhere )
530     {
531     EditRange *		er= &(eo->eoAffectedRange);
532 
533     if  ( ssNew )
534 	{
535 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NTT,
536 							ssNew->ssTreeType );
537 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NSN,
538 							ssNew->ssSectNr );
539 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NOSN,
540 							ssNew->ssOwnerSectNr );
541 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NON,
542 							ssNew->ssOwnerNumber );
543 	}
544 
545     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NHP, er->erHead.epParaNr );
546     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NHS, er->erHead.epStroff );
547     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NTP, er->erTail.epParaNr );
548     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_NTS, er->erTail.epStroff );
549 
550     if  ( posWhere >= 0 && posWhere < DOCrtfSEL_TAG_COUNT )
551 	{ docRtfWriteTag( eo->eoTraceWriter, DOCrtfSEL_TAGS[posWhere] ); }
552     else{ LLDEB(posWhere,DOCrtfSEL_TAG_COUNT);				}
553 
554     return 0;
555     }
556 
557 /************************************************************************/
558 /*									*/
559 /*  Start a trace item.							*/
560 /*  1)  Remember the operation.						*/
561 /*  2)  Remember the selection scope: In what tree was the selection?	*/
562 /*  3)  Remember the selection.						*/
563 /*									*/
564 /************************************************************************/
565 
docTraceStartStepLow(EditOperation * eo,EditTrace * et,int command,int fieldKind)566 static int docTraceStartStepLow( EditOperation *		eo,
567 				EditTrace *			et,
568 				int				command,
569 				int				fieldKind )
570     {
571     int			flags= RTFflagUNENCODED;
572     const char *	tag= docRtfGetTraceTag( command );
573 
574     if  ( ! tag )
575 	{ LXDEB(command,tag); return -1;	}
576 
577     docInitTraceStep( &(et->etThisStep) );
578     et->etThisStep.tsCommand= command;
579     et->etThisStep.tsFieldKind= fieldKind;
580     et->etThisStep.tsTraceOffset= 0;
581 
582     et->etCount= et->etIndex;
583 
584     if  ( et->etIndex > 0 )
585 	{
586 	const TraceStep *	ts;
587 
588 	ts= (const TraceStep *)utilPagedListGetItemByNumber(
589 				    &(et->etTraceSteps), et->etIndex- 1 );
590 	if  ( ! ts )
591 	    { LXDEB(et->etIndex,ts); return -1;	}
592 
593 	et->etThisStep.tsTraceOffset= ts->tsTraceOffset+ ts->tsByteCount;
594 	}
595 
596     eo->eoTraceStream= sioOutFdOpenAt( et->etTraceFileHandle,
597 						et->etThisStep.tsTraceOffset );
598     if  ( ! eo->eoTraceStream )
599 	{ XDEB(eo->eoTraceStream); return -1;	}
600     eo->eoTraceWriter= docRtfOpenWriter( eo->eoTraceStream,
601 						    eo->eoDocument, flags );
602     if  ( ! eo->eoTraceWriter )
603 	{ XDEB(eo->eoTraceWriter); return -1;	}
604 
605     /*  1  */
606     docRtfWriteDestinationBegin( eo->eoTraceWriter, tag );
607 
608     return 0;
609     }
610 
docTraceStartStep(EditOperation * eo,EditTrace * et,int command,int fieldKind)611 int docTraceStartStep(	EditOperation *			eo,
612 			EditTrace *			et,
613 			int				command,
614 			int				fieldKind )
615     {
616     if  ( docTraceStartStepLow( eo, et, command, fieldKind ) )
617 	{ LDEB(command); return -1;	}
618 
619     /*  2  */
620     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OTT,
621 					eo->eoSelectionScope.ssTreeType );
622     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OSN,
623 					eo->eoSelectionScope.ssSectNr );
624     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OOSN,
625 					eo->eoSelectionScope.ssOwnerSectNr );
626     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OON,
627 					eo->eoSelectionScope.ssOwnerNumber );
628 
629     /*  3  */
630     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OHP,
631 					eo->eoSelectedRange.erHead.epParaNr );
632     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OHS,
633 					eo->eoSelectedRange.erHead.epStroff );
634     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OTP,
635 					eo->eoSelectedRange.erTail.epParaNr );
636     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OTS,
637 					eo->eoSelectedRange.erTail.epStroff );
638 
639     if  ( eo->eoCol0 >= 0 )
640 	{
641 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OHC, eo->eoCol0 );
642 	}
643 
644     if  ( eo->eoCol1 >= 0 )
645 	{
646 	docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_OTC, eo->eoCol1 );
647 	}
648 
649     return 0;
650     }
651 
docTraceStartReplace(DocumentSelection * dsTraced,EditOperation * eo,EditTrace * et,int command,int level,unsigned int flags)652 int docTraceStartReplace(	DocumentSelection *		dsTraced,
653 				EditOperation *			eo,
654 				EditTrace *			et,
655 				int				command,
656 				int				level,
657 				unsigned int			flags )
658     {
659     if  ( docTraceStartStep( eo, et, command, -1 ) )
660 	{ LDEB(1); return -1;	}
661 
662     if  ( docRtfTraceOldContents( dsTraced, eo, level, flags ) )
663 	{ LDEB(1); return -1;	}
664 
665     return 0;
666     }
667 
668 /************************************************************************/
669 /*									*/
670 /*  Extend a replace.							*/
671 /*									*/
672 /*  Replacements start with a regular replace step. If the user		*/
673 /*  continues to type at the end of the replacement, the replace is	*/
674 /*  extended. As long as the user types 'the same word', the extent is	*/
675 /*  replaced with an extent that holds the whole extent.		*/
676 /*									*/
677 /************************************************************************/
678 
docTraceExtendReplace(EditOperation * eo,EditTrace * et,int command,int level,unsigned int flags)679 int docTraceExtendReplace(	EditOperation *			eo,
680 				EditTrace *			et,
681 				int				command,
682 				int				level,
683 				unsigned int			flags )
684     {
685     int			rval= 0;
686     const TraceStep *	ts;
687 
688     const int		fieldKind= -1;
689 
690     if  ( et->etIndex < 1 )
691 	{ LDEB(et->etIndex); return -1;		}
692 
693     ts= (const TraceStep *)utilPagedListGetItemByNumber(
694 				    &(et->etTraceSteps), et->etIndex- 1 );
695     if  ( ! ts )
696 	{ LXDEB(et->etIndex,ts); return -1;	}
697 
698     switch( ts->tsCommand )
699 	{
700 	case EDITcmdREPLACE:
701 	    break;
702 
703 	case EDITcmdEXTEND_REPLACE:
704 	    if  ( et->etIndex < 2 )
705 		{ LLDEB(ts->tsCommand,et->etIndex); return -1;	}
706 	    et->etIndex--;
707 	    break;
708 
709 	default:
710 	    LLDEB(command,ts->tsCommand); return -1;
711 	}
712 
713     if  ( docTraceStartStepLow( eo, et, command, fieldKind ) )
714 	{ LDEB(1); return -1;	}
715 
716     return rval;
717     }
718 
719 /************************************************************************/
720 /*									*/
721 /*  Remember the old/new field instructions of a field.			*/
722 /*									*/
723 /************************************************************************/
724 
docRtfTraceFieldImpl(EditOperation * eo,const DocumentField * df,const char * tag)725 static int docRtfTraceFieldImpl(	EditOperation *			eo,
726 					const DocumentField *		df,
727 					const char *			tag )
728     {
729     RtfWriter *	rw= 	eo->eoTraceWriter;
730 
731     DocumentSelection	dsInsideField;
732     DocumentSelection	dsAroundField;
733 
734     int			headPart;
735     int			tailPart;
736 
737     if  ( docDelimitFieldInDoc( &dsInsideField, &dsAroundField,
738 				&headPart, &tailPart, eo->eoDocument, df ) )
739 	{ LDEB(1); return -1; }
740 
741     docRtfWriteNextLine( rw );
742     docRtfWriteDestinationBegin( rw, tag );
743 
744     docRtfWriteTag( rw, RTFtag_pard );
745     docRtfWriteTag( rw, RTFtag_plain );
746     docRtfSaveFieldHead( rw, dsAroundField.dsHead.dpNode, headPart );
747     docRtfWriteRawBytes( rw, " ", 1 );
748     docRtfSaveFieldTail( rw, dsAroundField.dsTail.dpNode, tailPart );
749     docRtfWriteTag( rw, RTFtag_par );
750 
751     docRtfWriteDestinationEnd( rw );
752 
753     return 0;
754     }
755 
docRtfTraceFieldKind(EditOperation * eo,int kind)756 int docRtfTraceFieldKind(	EditOperation *			eo,
757 				int				kind )
758 
759     {
760     docRtfWriteArgTag( eo->eoTraceWriter, RTFtag_FLK, kind );
761     return 0;
762     }
763 
docRtfTraceOldField(EditOperation * eo,const DocumentField * df)764 int docRtfTraceOldField(	EditOperation *			eo,
765 				const DocumentField *		df )
766 
767     {
768     docRtfTraceFieldKind( eo, df->dfKind );
769 
770     return docRtfTraceFieldImpl( eo, df, RTFtag_OTX );
771     }
772 
docRtfTraceNewField(EditOperation * eo,const DocumentField * df)773 int docRtfTraceNewField(	EditOperation *			eo,
774 				const DocumentField *		df )
775     { return docRtfTraceFieldImpl( eo, df, RTFtag_NTX );	}
776 
777 /************************************************************************/
778 /*									*/
779 /*  Finish a trace step.						*/
780 /*									*/
781 /************************************************************************/
782 
docRtfTraceCloseTrace(EditOperation * eo,EditTrace * et)783 int docRtfTraceCloseTrace(	EditOperation *			eo,
784 				EditTrace *			et )
785     {
786     TraceStep *	ts= (TraceStep *)0;
787 
788     docRtfWriteDestinationEnd( eo->eoTraceWriter );
789     docRtfWriteNextLine( eo->eoTraceWriter );
790 
791     docRtfCloseWriter( eo->eoTraceWriter );
792     eo->eoTraceWriter= (RtfWriter *)0;
793 
794     et->etThisStep.tsByteCount= sioOutGetBytesWritten( eo->eoTraceStream );
795 
796     sioOutClose( eo->eoTraceStream );
797     eo->eoTraceStream= (SimpleOutputStream *)0;
798 
799     ts= utilPagedListClaimItem( &(et->etTraceSteps), et->etIndex );
800     if  ( ! ts )
801 	{ LXDEB(et->etIndex,ts); return -1;	}
802     et->etIndex++;
803     et->etCount++;
804 
805     *ts= et->etThisStep;
806 
807     utilPagedListSetSize( &(et->etTraceSteps), et->etCount );
808 
809     return 0;
810     }
811 
812 /************************************************************************/
813 /*									*/
814 /*  Start a trace: Store the digest and the current date and time.	*/
815 /*									*/
816 /************************************************************************/
817 
docRtfTraceVersion(int command,const MemoryBuffer * filename,const char * digest64,const struct tm * revtim,EditTrace * et)818 int docRtfTraceVersion(		int			command,
819 				const MemoryBuffer *	filename,
820 				const char *		digest64,
821 				const struct tm *	revtim,
822 				EditTrace *		et )
823     {
824     int			rval= 0;
825 
826     EditOperation	eo;
827     RtfWriter *		rw;
828 
829     const int		fieldKind= -1;
830     const int		addSemicolon= 0;
831 
832     docInitEditOperation( &eo );
833 
834     if  ( docTraceStartStepLow( &eo, et, command, fieldKind ) )
835 	{ LDEB(command); rval= -1; goto ready;	}
836 
837     rw= eo.eoTraceWriter;
838 
839     /*  HACK: Must go to the props.. not the document */
840     docRtfWriteDestinationBegin( rw, RTFtag_NPR );
841 
842     docRtfSaveDate( rw, RTFtag_revtim, revtim );
843 
844     if  ( digest64 )
845 	{
846 	docRtfWriteDocEncodedStringDestination( rw, RTFtag__generator,
847 				digest64, strlen(digest64), addSemicolon );
848 	}
849 
850     if  ( filename && ! utilMemoryBufferIsEmpty( filename ) )
851 	{
852 	const char *	fn= utilMemoryBufferGetString( filename );
853 
854 	docRtfWriteDocEncodedStringDestination( rw, RTFtag_hlinkbase,
855 				fn, strlen(fn), addSemicolon );
856 	}
857 
858     docRtfWriteDestinationEnd( rw );
859 
860     if  ( docRtfTraceCloseTrace( &eo, et ) )
861 	{ LDEB(command); rval= -1; goto ready;	}
862 
863   ready:
864 
865     docCleanEditOperation( &eo );
866 
867     return rval;
868     }
869 
870