1 /************************************************************************/
2 /*									*/
3 /*  Evaluate fields+ the list of kinds of fields.			*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docBufConfig.h"
8 
9 #   include	<string.h>
10 
11 #   include	<appDebugon.h>
12 
13 #   include	"docBuf.h"
14 #   include	"docNotes.h"
15 #   include	"docField.h"
16 #   include	"docParaString.h"
17 #   include	"docEvalField.h"
18 #   include	"docParaParticules.h"
19 #   include	"docDebug.h"
20 #   include	<docTreeType.h>
21 #   include	<docDocumentNote.h>
22 #   include	"docTreeScanner.h"
23 #   include	"docDebug.h"
24 #   include	"docRecalculateFields.h"
25 
26 /************************************************************************/
27 /*									*/
28 /*  Manage fields.							*/
29 /*									*/
30 /************************************************************************/
31 
docInitRecalculateFields(RecalculateFields * rf)32 void docInitRecalculateFields(   RecalculateFields *     rf )
33     {
34     rf->rfDocument= (BufferDocument *)0;
35     rf->rfTree= (DocumentTree *)0;
36     rf->rfSelectedTree= (DocumentTree *)0;
37     rf->rfMergeValueTree= (void *)0;
38     rf->rfCloseObject= (DOC_CLOSE_OBJECT)0;
39     rf->rfFieldsUpdated= 0;
40     rf->rfUpdateFlags= 0;
41 
42     rf->rfBodySectNode= (const BufferItem *)0;
43     rf->rfBodySectPage= -1;
44 
45     docInitEditPosition( &(rf->rfSelHead) );
46     docInitEditPosition( &(rf->rfSelTail) );
47 
48     rf->rfFieldDataProvider= (FieldDataProvider)0;
49     rf->rfInstanceStreamProvider= (InstanceStreamProvider)0;
50     rf->rfMergeThrough= (void *)0;
51 
52     return;
53     }
54 
55 /************************************************************************/
56 /*									*/
57 /*  Replace the previous contents of a field with new contents.		*/
58 /*									*/
59 /************************************************************************/
60 
docFieldReplaceContents(int * pStroff,int * pStroffShift,int * pTextAttrNr,BufferItem * paraNode,int part,int partCount,int stroffShift,const char * addedString,int addedStrlen,const RecalculateFields * rf)61 int docFieldReplaceContents(
62 			int *				pStroff,
63 			int *				pStroffShift,
64 			int *				pTextAttrNr,
65 			BufferItem *			paraNode,
66 			int				part,
67 			int				partCount,
68 			int				stroffShift,
69 			const char *			addedString,
70 			int				addedStrlen,
71 			const RecalculateFields *	rf )
72     {
73     int			i;
74     TextParticule *	tp= paraNode->biParaParticules+ part;
75 
76     int			textAttributeNumber= tp[1].tpTextAttrNr;
77     int			past= tp[1+partCount].tpStroff+ stroffShift;
78     int			stroff= tp[1].tpStroff+ stroffShift;
79 
80     int			d= 0;
81 
82     if  ( docParaStringReplace( &d, paraNode, stroff, past,
83 					    addedString, addedStrlen ) )
84 	{ LDEB(addedStrlen); return -1;	}
85 
86     if  ( partCount > 0 )
87 	{
88 	tp= paraNode->biParaParticules+ part+ 1;
89 	for ( i= 0; i < partCount; tp++, i++ )
90 	    {
91 	    if  ( rf->rfCloseObject )
92 		{ (*rf->rfCloseObject)( rf->rfDocument, tp );	}
93 	    docCleanParticuleObject( rf->rfDocument, tp );
94 	    }
95 
96 	docDeleteParticules( paraNode, part+ 1, partCount );
97 	}
98 
99     *pStroff= stroff;
100     *pStroffShift= d;
101     *pTextAttrNr= textAttributeNumber;
102     return 0;
103     }
104 
105 /************************************************************************/
106 
docRecalculateFieldParticulesFromString(int * pCalculated,int * pPartShift,int * pStroffShift,BufferItem * paraNode,int part,int partCount,const MemoryBuffer * mbResult,const RecalculateFields * rf)107 int docRecalculateFieldParticulesFromString(
108 				int *				pCalculated,
109 				int *				pPartShift,
110 				int *				pStroffShift,
111 				BufferItem *			paraNode,
112 				int				part,
113 				int				partCount,
114 				const MemoryBuffer *		mbResult,
115 				const RecalculateFields *	rf )
116     {
117     int					d;
118 
119     TextParticule *			tp= paraNode->biParaParticules+ part;
120     int					textAttributeNumber;
121 
122     int					past;
123     int					stroff;
124     int					partsMade;
125 
126     int					i;
127 
128     if  ( tp[1].tpStrlen == mbResult->mbSize				&&
129 	  ! memcmp( docParaString( paraNode, tp[1].tpStroff+ *pStroffShift ),
130 				    mbResult->mbBytes, mbResult->mbSize ) )
131 	{
132 	*pCalculated= 0;
133 	*pPartShift= 0;
134 	/* NO! *pStroffShift= 0; */
135 	return 0;
136 	}
137 
138     textAttributeNumber= tp[1].tpTextAttrNr;
139     past= tp[1+partCount].tpStroff+ *pStroffShift;
140     stroff= tp[1].tpStroff+ *pStroffShift;
141 
142     if  ( docParaStringReplace( &d, paraNode, stroff, past,
143 				(char *)mbResult->mbBytes, mbResult->mbSize ) )
144 	{ LDEB(mbResult->mbSize); return -1;	}
145 
146     tp= paraNode->biParaParticules+ part+ 1;
147     for ( i= 0; i < partCount; tp++, i++ )
148 	{
149 	if  ( rf->rfCloseObject )
150 	    { (*rf->rfCloseObject)( rf->rfDocument, tp ); }
151 
152 	docCleanParticuleObject( rf->rfDocument, tp );
153 	}
154 
155     partsMade= docRedivideStringInParticules( paraNode, stroff,
156 				    mbResult->mbSize,
157 				    part+ 1, partCount, textAttributeNumber );
158     if  ( partsMade < partCount )
159 	{
160 	docDeleteParticules( paraNode,
161 				part+ 1+ partsMade, partCount- partsMade );
162 	}
163 
164     *pCalculated= 1;
165     *pPartShift= partsMade- partCount;
166     *pStroffShift += d;
167 
168     return 0;
169     }
170 
171 /************************************************************************/
172 /*									*/
173 /*  Substitute an individual text field in a paragraph.			*/
174 /*									*/
175 /*  NOTE: This routine is not recursive. Nested fields are handeled	*/
176 /*	by the caller.							*/
177 /*									*/
178 /************************************************************************/
179 
docRecalculateParaStringTextParticules(int * pCalculated,int * pPartShift,int * pStroffShift,BufferItem * paraNode,int part,int partCount,DocumentField * df,const RecalculateFields * rf)180 int docRecalculateParaStringTextParticules(
181 				int *				pCalculated,
182 				int *				pPartShift,
183 				int *				pStroffShift,
184 				BufferItem *			paraNode,
185 				int				part,
186 				int				partCount,
187 				DocumentField *			df,
188 				const RecalculateFields *	rf )
189     {
190     int					rval= 0;
191     MemoryBuffer			mbResult;
192     int					calculated= 0;
193 
194     const FieldKindInformation *	fki= DOC_FieldKinds+ df->dfKind;
195 
196     utilInitMemoryBuffer( &mbResult );
197 
198     if  ( (*fki->fkiCalculateTextString)( &calculated, &mbResult, df, rf ) )
199 	{ SDEB(fki->fkiLabel); rval= -1; goto ready;	}
200 
201     if  ( ! calculated )
202 	{
203 	*pCalculated= 0;
204 	*pPartShift= 0;
205 	/* NO! *pStroffShift= 0; */
206 	goto ready;
207 	}
208 
209     if  ( docRecalculateFieldParticulesFromString(
210 				    pCalculated, pPartShift, pStroffShift,
211 				    paraNode, part, partCount, &mbResult, rf ) )
212 	{ LDEB(1); rval= -1; goto ready;	}
213 
214   ready:
215 
216     utilCleanMemoryBuffer( &mbResult );
217 
218     return rval;
219     }
220 
221 /************************************************************************/
222 /*									*/
223 /*  Substitute the text fields in a paragraph.				*/
224 /*									*/
225 /*  1)  For all fields in range...					*/
226 /*	NOTE that the end of the range may have been shifted by the	*/
227 /*	calculation of field results.					*/
228 /*  2)  Shift this particule by what previous calculations have changed	*/
229 /*	in size.							*/
230 /*  3)  Not the beginning of a field.. Irrelevant.			*/
231 /*  4)  Retrieve the field. Do some sanity checks: Only text level	*/
232 /*	fields are evaluated here.					*/
233 /*  5)  Count the number of particules currently in the field.		*/
234 /*  6)  When the field is to be recalculated.. do so.			*/
235 /*	NOTE that this may shift both the array of particules and the	*/
236 /*	paragraph text.							*/
237 /*	Otherwise just shift the offsets of the particules inside the	*/
238 /*	field.								*/
239 /*  7)  When there is sufficient space inside the field to contain	*/
240 /*	yet another one.. go into recursion.				*/
241 /*	NOTE that this may shift both the array of particules and the	*/
242 /*	paragraph text.							*/
243 /*  8)  Shift the end particule of the field.				*/
244 /*  9)  Set the current position in the loop to the end particule. The	*/
245 /*	loop increment will move to the particule after the field.	*/
246 /*									*/
247 /************************************************************************/
248 
docRecalculateParaTextFields(RecalculateFields * rf,int * pPartShift,int * pStroffShift,BufferItem * paraNode,int part,int partUpto)249 static int docRecalculateParaTextFields(
250 				RecalculateFields *	rf,
251 				int *			pPartShift,
252 				int *			pStroffShift,
253 				BufferItem *		paraNode,
254 				int			part,
255 				int			partUpto )
256     {
257     BufferDocument *	bd= rf->rfDocument;
258     int			fieldsUpdated= 0;
259     int			paraNr= -1;
260 
261     /*  1  */
262     for ( part= part; part < partUpto+ *pPartShift; part++ )
263 	{
264 	TextParticule *			tp= paraNode->biParaParticules+ part;
265 
266 	DocumentField *			df;
267 	const FieldKindInformation *	fki;
268 
269 	int				tailPart;
270 	int				partCount;
271 	int				closed;
272 	int				stroffTail;
273 
274 	/*  2  */
275 	if  ( docShiftParticuleOffsets( rf->rfDocument, paraNode, part, part+ 1,
276 							    *pStroffShift ) )
277 	    { LDEB(*pStroffShift);	}
278 
279 	/*  3  */
280 	if  ( tp->tpKind != DOCkindFIELDHEAD )
281 	    { continue;	}
282 
283 	if  ( paraNr <= 0					&&
284 	      ( rf->rfSelHead.epParaNr > 0	||
285 	        rf->rfSelTail.epParaNr > 0	)	)
286 	    { paraNr= docNumberOfParagraph( paraNode );	}
287 
288 	/*  4  */
289 	df= docGetFieldByNumber( &(bd->bdFieldList), tp->tpObjectNumber );
290 	if  ( ! df )
291 	    {
292 	    LXDEB(tp->tpObjectNumber,df);
293 	    docListNode(0,paraNode,0);
294 	    docListFieldTree(rf->rfDocument,rf->rfTree);
295 	    continue;
296 	    }
297 	if  ( df->dfKind >= DOC_FieldKindCount )
298 	    { LLDEB(df->dfKind,DOC_FieldKindCount); continue;	}
299 
300 	fki= DOC_FieldKinds+ df->dfKind;
301 
302 	/*  5  */
303 	partCount= docCountParticulesInField( paraNode, &closed, part,
304 						    partUpto+ *pPartShift );
305 	if  ( partCount < 0 )
306 	    { SLDEB(docFieldKindStr(df->dfKind),partCount); continue;	}
307 	tailPart= part+ 1+ partCount;
308 	if  ( tailPart < paraNode->biParaParticuleCount )
309 	    { stroffTail= tp[1+partCount].tpStroff;	}
310 	else{ stroffTail= docParaStrlen( paraNode );	}
311 
312 	/*  6  */
313 	if  ( closed						&&
314 	      fki->fkiLevel == DOClevSPAN			&&
315 	      ( fki->fkiCalculateWhen & rf->rfUpdateFlags )	&&
316 	      fki->fkiCalculateTextParticules			)
317 	    {
318 	    int			partShift= 0;
319 	    int			calculated= 0;
320 	    int			oldStroffShift= *pStroffShift;
321 
322 	    if  ( (*fki->fkiCalculateTextParticules)( &calculated,
323 					&partShift, pStroffShift,
324 					paraNode, part, partCount, df, rf ) )
325 		{ LDEB(1); return -1;	}
326 
327 	    if  ( calculated )
328 		{
329 		int	stroffShift= *pStroffShift- oldStroffShift;
330 
331 		if  ( rf->rfTree == rf->rfSelectedTree )
332 		    {
333 		    docAdjustEditPositionOffsetB( &(rf->rfSelHead),
334 					paraNr, stroffTail, stroffShift );
335 		    docAdjustEditPositionOffsetE( &(rf->rfSelTail),
336 					paraNr, stroffTail, stroffShift );
337 		    }
338 
339 		fieldsUpdated++; rf->rfFieldsUpdated++;
340 		}
341 	    else{
342 		if  ( docShiftParticuleOffsets( rf->rfDocument, paraNode,
343 					part+ 1, tailPart, *pStroffShift ) )
344 		    { LDEB(*pStroffShift);	}
345 		}
346 
347 	    tailPart += partShift;
348 	    *pPartShift += partShift;
349 	    }
350 	else{
351 	    if  ( docShiftParticuleOffsets( rf->rfDocument, paraNode,
352 					part+ 1, tailPart, *pStroffShift ) )
353 		{ LDEB(*pStroffShift);	}
354 	    }
355 
356 	/*  7  */
357 	if  ( tailPart- part >= 2 )
358 	    {
359 	    int			partShift= 0;
360 	    int			stroffShift= 0;
361 
362 	    if  ( docRecalculateParaTextFields( rf,
363 		    &partShift, &stroffShift, paraNode, part+ 1, tailPart ) )
364 		{ LDEB(1); return -1;	}
365 
366 	    tailPart += partShift;
367 	    *pPartShift += partShift;
368 	    *pStroffShift += stroffShift;
369 	    }
370 
371 	/*  8   */
372 	if  ( closed )
373 	    {
374 	    tp= paraNode->biParaParticules+ tailPart;
375 	    if  ( tp->tpKind != DOCkindFIELDTAIL )
376 		{ LDEB(tp->tpKind);	}
377 
378 	    tp->tpStroff += *pStroffShift;
379 	    df->dfTailPosition.epStroff= tp->tpStroff;
380 	    }
381 
382 	/*  9  */
383 	part= tailPart;
384 	}
385 
386     if  ( fieldsUpdated )
387 	{ docInvalidateParagraphLayout( paraNode );	}
388 
389     return 0;
390     }
391 
392 /************************************************************************/
393 /*									*/
394 /*  Substitute the text fields in a document tree.			*/
395 /*									*/
396 /*  1)	Unexpected recursion?						*/
397 /*									*/
398 /************************************************************************/
399 
docRecalculateTextLevelFieldsInDocumentTree(RecalculateFields * rf,DocumentTree * dt,const BufferItem * bodySectNode,int page)400 int docRecalculateTextLevelFieldsInDocumentTree(
401 					RecalculateFields *	rf,
402 					DocumentTree *		dt,
403 					const BufferItem *	bodySectNode,
404 					int			page )
405     {
406     int			rval= 0;
407     int			ret;
408     int			saveFieldsUpdated= rf->rfFieldsUpdated;
409     DocumentTree *	saveTree= rf->rfTree;
410     const BufferItem *	saveBodySectNode= rf->rfBodySectNode;
411     int			saveBodySectPage= rf->rfBodySectPage;
412 
413     if  ( ! dt->dtRoot )
414 	{ return 0;	}
415 
416     if  ( dt->dtRoot->biTreeType != DOCinBODY			&&
417           ( ! bodySectNode				||
418             bodySectNode->biTreeType != DOCinBODY	)	)
419 	{ XDEB(rf->rfBodySectNode); return -1;	}
420 
421     rf->rfBodySectNode= bodySectNode;
422     rf->rfBodySectPage= page;
423 
424     rf->rfFieldsUpdated= 0;
425     rf->rfTree= dt;
426 
427     ret= docRecalculateTextLevelFields( rf, dt->dtRoot );
428     if  ( ret )
429 	{ LDEB(ret); rval= -1;	}
430 
431     if  ( rf->rfFieldsUpdated > 0 )
432 	{ docInvalidateTreeLayout( dt );	}
433 
434     rf->rfFieldsUpdated += saveFieldsUpdated;
435 
436     rf->rfTree= saveTree;
437     rf->rfBodySectNode= saveBodySectNode;
438     rf->rfBodySectPage= saveBodySectPage;
439 
440     return rval;
441     }
442 
docRecalculateTextLevelFieldsInSeparators(RecalculateFields * rf,const BufferItem * bodySectNode)443 static int docRecalculateTextLevelFieldsInSeparators(
444 					RecalculateFields *	rf,
445 					const BufferItem *	bodySectNode )
446     {
447     const int		page= -1;
448     BufferDocument *	bd= rf->rfDocument;
449 
450     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
451 			    &(bd->bdEiFtnsep), bodySectNode, page )	)
452 	{ LDEB(1); return -1;	}
453 
454     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
455 			    &(bd->bdEiFtnsepc), bodySectNode, page )	)
456 	{ LDEB(1); return -1;	}
457 
458     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
459 			    &(bd->bdEiFtncn), bodySectNode, page )	)
460 	{ LDEB(1); return -1;	}
461 
462     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
463 			    &(bd->bdEiAftnsep), bodySectNode, page )	)
464 	{ LDEB(1); return -1;	}
465 
466     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
467 			    &(bd->bdEiAftnsepc), bodySectNode, page )	)
468 	{ LDEB(1); return -1;	}
469 
470     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
471 			    &(bd->bdEiAftncn), bodySectNode, page )	)
472 	{ LDEB(1); return -1;	}
473 
474     return 0;
475     }
476 
docRecalculateTextLevelFieldsInSectHdFt(RecalculateFields * rf,const BufferItem * bodySectNode)477 static int docRecalculateTextLevelFieldsInSectHdFt(
478 					RecalculateFields *	rf,
479 					const BufferItem *	bodySectNode )
480     {
481     const int			page= -1;
482     SectHeadersFooters *	shf= bodySectNode->biSectHeadersFooters;
483 
484     rf->rfBodySectNode= bodySectNode;
485 
486     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
487 			&(shf->shfFirstPageHeader), bodySectNode, page ) )
488 	{ LDEB(1); return -1;	}
489 
490     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
491 			&(shf->shfLeftPageHeader), bodySectNode, page ) )
492 	{ LDEB(1); return -1;	}
493 
494     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
495 			&(shf->shfRightPageHeader), bodySectNode, page ) )
496 	{ LDEB(1); return -1;	}
497 
498 
499     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
500 			&(shf->shfFirstPageFooter), bodySectNode, page ) )
501 	{ LDEB(1); return -1;	}
502 
503     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
504 			&(shf->shfLeftPageFooter), bodySectNode, page ) )
505 	{ LDEB(1); return -1;	}
506 
507     if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
508 			&(shf->shfRightPageFooter), bodySectNode, page ) )
509 	{ LDEB(1); return -1;	}
510 
511     return 0;
512     }
513 
docRecalculateTextLevelFieldsInSectNotes(RecalculateFields * rf,const BufferItem * bodySectNode)514 static int docRecalculateTextLevelFieldsInSectNotes(
515 					RecalculateFields *	rf,
516 					const BufferItem *	bodySectNode )
517     {
518     BufferDocument *	bd= rf->rfDocument;
519 
520     DocumentField *	dfNote;
521     DocumentNote *	dn;
522     const int		page= -1;
523     const int		treeType= -1;
524 
525     dfNote= docGetFirstNoteOfSection( &dn, bd,
526 				bodySectNode->biNumberInParent, treeType );
527     while( dfNote )
528 	{
529 	DocumentTree *	dt= &(dn->dnDocumentTree);
530 
531 	if  ( ! dt->dtRoot )
532 	    { continue;	}
533 
534 	if  ( docRecalculateTextLevelFieldsInDocumentTree( rf,
535 						dt, bodySectNode, page ) )
536 	    { LDEB(1); return -1;	}
537 
538 	dfNote= docGetNextNoteInSection( &dn, bd,
539 			bodySectNode->biNumberInParent, dfNote, treeType );
540 	}
541 
542     return 0;
543     }
544 
docRecalculateTextLevelFieldsLeaveNode(struct BufferItem * node,const DocumentSelection * ds,const struct BufferItem * bodySectNode,void * voidrf)545 static int docRecalculateTextLevelFieldsLeaveNode(
546 				    struct BufferItem *		node,
547 				    const DocumentSelection *	ds,
548 				    const struct BufferItem *	bodySectNode,
549 				    void *			voidrf )
550     {
551     RecalculateFields *	rf= (RecalculateFields *)voidrf;
552     int			rval= 0;
553 
554     const BufferItem *	saveBodySectNode= rf->rfBodySectNode;
555 
556     switch( node->biLevel )
557 	{
558 	case DOClevBODY:
559 	    if  ( docRecalculateTextLevelFieldsInSeparators( rf,
560 						    node->biChildren[0] ) )
561 		{ LDEB(1); rval= -1; goto ready;	}
562 
563 	    break;
564 
565 	case DOClevSECT:
566 	    if  ( node->biTreeType == DOCinBODY )
567 		{
568 		SectHeadersFooters *	shf= node->biSectHeadersFooters;
569 
570 		if  ( ! shf )
571 		    { XDEB(shf); rval= -1; goto ready;	}
572 
573 		if  ( docRecalculateTextLevelFieldsInSectHdFt( rf, node ) )
574 		    { LDEB(1); rval= -1; goto ready;	}
575 
576 		if  ( docRecalculateTextLevelFieldsInSectNotes( rf, node ) )
577 		    { LDEB(1); rval= -1; goto ready;	}
578 		}
579 
580 	    break;
581 
582 	case DOClevPARA:
583 
584 	    {
585 	    int		partShift= 0;
586 	    int		stroffShift= 0;
587 
588 	    if  ( docRecalculateParaTextFields( rf, &partShift, &stroffShift,
589 					node, 0, node->biParaParticuleCount ) )
590 		{ LDEB(1); rval= -1; goto ready;	}
591 	    }
592 
593 	    break;
594 
595 	default:
596 	    break;
597 	}
598 
599   ready:
600 
601     rf->rfBodySectNode= saveBodySectNode;
602 
603     return rval;
604     }
605 
docRecalculateTextLevelFields(RecalculateFields * rf,BufferItem * node)606 int docRecalculateTextLevelFields(	RecalculateFields *	rf,
607 					BufferItem *		node )
608     {
609     const int		flags= 0;
610 
611     if  ( docScanTreeNode( rf->rfDocument, node,
612 		    (NodeVisitor)0, docRecalculateTextLevelFieldsLeaveNode,
613 		    flags, (void *)rf ) )
614 	{ LDEB(1); return -1;	}
615 
616     return 0;
617     }
618