1 /************************************************************************/
2 /*									*/
3 /*  Manage fields.							*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docBufConfig.h"
8 
9 #   include	<stdlib.h>
10 #   include	<string.h>
11 #   include	<stdio.h>
12 
13 #   include	<appDebugon.h>
14 
15 #   include	"docBuf.h"
16 #   include	"docTreeNode.h"
17 #   include	"docField.h"
18 #   include	<docTreeType.h>
19 #   include	<docTextParticule.h>
20 #   include	<docBookmarkField.h>
21 #   include	"docParaString.h"
22 #   include	"docParaParticules.h"
23 #   include	"docNodeTree.h"
24 
25 /************************************************************************/
26 /*									*/
27 /*  Find the inner most field for a particular position.		*/
28 /*									*/
29 /************************************************************************/
30 
docFindFieldForPosition(BufferDocument * bd,const DocumentPosition * dp)31 DocumentField * docFindFieldForPosition(
32 				BufferDocument *		bd,
33 				const DocumentPosition *	dp )
34     {
35     EditPosition	ep;
36     DocumentTree *	dt;
37     BufferItem *	bodySectBi;
38     const int		lastOne= 0;
39 
40     docSetEditPosition( &ep, dp );
41 
42     if  ( docGetTreeOfNode( &dt, &bodySectBi, bd, dp->dpNode ) )
43 	{ LDEB(1); return (DocumentField *)0;	}
44 
45     return docFindChildField( &(dt->dtRootFields), &ep, lastOne );
46     }
47 
48 /************************************************************************/
49 /*									*/
50 /*  Find a field of a certain type that holds a position.		*/
51 /*									*/
52 /************************************************************************/
53 
docFindTypedFieldForPosition(BufferDocument * bd,const DocumentPosition * dp,int kind,int lastOne)54 DocumentField * docFindTypedFieldForPosition(
55 				BufferDocument *		bd,
56 				const DocumentPosition *	dp,
57 				int				kind,
58 				int				lastOne )
59     {
60     EditPosition	ep;
61     DocumentTree *	dt;
62     DocumentField *	dfInner;
63 
64     docSetEditPosition( &ep, dp );
65 
66     if  ( docGetTreeOfNode( &dt, (BufferItem **)0, bd, dp->dpNode ) )
67 	{ LDEB(1); return (DocumentField *)0;	}
68 
69     dfInner= docFindChildField( &(dt->dtRootFields), &ep, lastOne );
70 
71     while( dfInner && docEditPositionInField( dfInner, &ep ) )
72 	{
73 	DocumentField *	df= dfInner;
74 
75 	while( df )
76 	    {
77 	    if  ( df->dfKind == kind || kind == -1 )
78 		{ return df;	}
79 
80 	    df= df->dfParent;
81 	    }
82 
83 	dfInner= docGetNextField( &(dt->dtRootFields), dfInner );
84 	}
85 
86     return (DocumentField *)0;
87     }
88 
docFindTypedFieldInSelection(struct BufferDocument * bd,const struct DocumentSelection * ds,int kind,int lastOne)89 DocumentField * docFindTypedFieldInSelection(
90 			    struct BufferDocument *		bd,
91 			    const struct DocumentSelection *	ds,
92 			    int					kind,
93 			    int					lastOne )
94     {
95     EditRange		er;
96     DocumentTree *	dt;
97 
98     docSetEditRange( &er, ds );
99 
100     if  ( docGetRootOfSelectionScope( &dt, (BufferItem **)0,
101 					    bd, &(ds->dsSelectionScope) ) )
102 	{ LDEB(1); return (DocumentField *)0;	}
103 
104     return docFindFieldInRange( &er, &(dt->dtRootFields), lastOne, kind );
105     }
106 
107 /************************************************************************/
108 /*									*/
109 /*  Suggest a bookmark name that matches the text in a selection.	*/
110 /*									*/
111 /************************************************************************/
112 
docSuggestNewBookmarkName(MemoryBuffer * markName,const BufferDocument * bd,const DocumentSelection * ds)113 int docSuggestNewBookmarkName(	MemoryBuffer *			markName,
114 				const BufferDocument *		bd,
115 				const DocumentSelection *	ds )
116     {
117     int			rval= 0;
118     const BufferItem *	paraBi= ds->dsHead.dpNode;
119     int			stroff= ds->dsHead.dpStroff;
120 
121     if  ( paraBi )
122 	{
123 	const char *	s= (const char *)docParaString( paraBi, stroff );
124 	int		stroffTail;
125 
126 	if  ( paraBi == ds->dsTail.dpNode )
127 	    { stroffTail= ds->dsTail.dpStroff;	}
128 	else{ stroffTail= docParaStrlen( paraBi );	}
129 
130 	if  ( docBookmarkFromText( markName, s, stroffTail- stroff ) )
131 	    { LDEB(1); return -1;	}
132 
133 	if  ( docMakeBookmarkUnique( bd, markName ) )
134 	    { LDEB(1); return -1;	}
135 
136 	rval= 1;
137 	}
138 
139     return rval;
140     }
141 
142 /************************************************************************/
143 
docMakeBookmarkUnique(const BufferDocument * bd,MemoryBuffer * markName)144 int docMakeBookmarkUnique(	const BufferDocument *	bd,
145 				MemoryBuffer *		markName )
146     {
147     DocumentField *	df;
148     const DocumentFieldList *	dfl= &(bd->bdFieldList);
149 
150     if  ( docFindBookmarkField( &df, dfl, markName ) >= 0 )
151 	{
152 	int		i;
153 	char		scratch[6+1];
154 	int		offset= docBookmarkSuffixIndex( markName, 6 );
155 
156 	for ( i= 0; i < 1000000; i++ )
157 	    {
158 	    sprintf( scratch, "%06d", i );
159 	    utilMemoryBufferReplaceBytes( markName,
160 						offset, markName->mbSize,
161 						(unsigned char *)scratch, 6 );
162 
163 	    if  ( docFindBookmarkField( &df, dfl, markName ) < 0 )
164 		{ return 0;	}
165 	    }
166 
167 	LDEB(i); return -1;
168 	}
169 
170     return 0;
171     }
172 
173 /************************************************************************/
174 /*									*/
175 /*  Derive field kind from field instructions.				*/
176 /*									*/
177 /************************************************************************/
178 
docFieldKindFromInstructions(const DocumentField * df)179 int docFieldKindFromInstructions(	const DocumentField *	df )
180     {
181     const FieldInstructions *	fi= &(df->dfInstructions);
182 
183     char *			s;
184     char *			p;
185     int				n;
186     int				i;
187 
188     const FieldKindInformation *	fki;
189 
190     if  ( fi->fiComponentCount < 1 )
191 	{ LDEB(fi->fiComponentCount); return -1;	}
192 
193     s= (char *) fi->fiComponents[0].icBuffer.mbBytes;
194     n= fi->fiComponents[0].icBuffer.mbSize;
195     /* Cope with OpenOffice that inserts backslashes before the instructions */
196     while( n > 0 && *s == '\\' )
197 	{ n--; s++;	}
198 
199     i= 0; p= s;
200     while( i < n && isalpha( *p ) )
201 	{
202 	if  ( islower( *p ) )
203 	    { *p= toupper( *p );	}
204 	i++; p++;
205 	}
206 
207     if  ( DOC_FieldKindCount != DOCfk_COUNT )
208 	{ LLDEB(DOC_FieldKindCount,DOCfk_COUNT); return -1;	}
209 
210     /* LSDEB(p-s,(char *)s); */
211 
212     fki= DOC_FieldKinds;
213     for ( i= 0; i < DOC_FieldKindCount; fki++, i++ )
214 	{
215 	if  ( ! fki->fkiIsFieldInRtf )
216 	    { continue;	}
217 
218 	if  ( ! strncmp( s, fki->fkiLabel, p- s )	&&
219 	      ! fki->fkiLabel[p- s]			)
220 	    { return i;	}
221 	}
222 
223     return -1;
224     }
225 
226 /************************************************************************/
227 /*									*/
228 /*  Shift fields in an edit operation.					*/
229 /*  NOTE that we depend on the paragraph number only for shifting the	*/
230 /*  section number: Only the body has more than one section and there	*/
231 /*  is a colose relationship in that case.				*/
232 /*									*/
233 /*  1)	For (BODY) fields that span sections, the section number is	*/
234 /*	that of the head position of the field.				*/
235 /*									*/
236 /************************************************************************/
237 
docShiftFieldStart(DocumentField * df,int sectFrom,int paraFrom,int stroffFrom,int sectShift,int paraShift,int stroffShift)238 static void docShiftFieldStart(		DocumentField *		df,
239 					int			sectFrom,
240 					int			paraFrom,
241 					int			stroffFrom,
242 					int			sectShift,
243 					int			paraShift,
244 					int			stroffShift )
245     {
246     /*  earlier paragraph  */
247     if  ( df->dfHeadPosition.epParaNr < paraFrom )
248 	{ return;	}
249 
250     /*  later paragraph  */
251     if  ( df->dfHeadPosition.epParaNr > paraFrom )
252 	{
253 	df->dfHeadPosition.epParaNr += paraShift;
254 	/*  1  */
255 	if  ( df->dfSelectionScope.ssTreeType == DOCinBODY )
256 	    { df->dfSelectionScope.ssSectNr += sectShift;	}
257 
258 	return;
259 	}
260 
261     /* Same paragraph */
262     if  ( df->dfHeadPosition.epStroff < stroffFrom )
263 	{ return;	}
264     if  ( df->dfHeadPosition.epStroff > stroffFrom )
265 	{
266 	df->dfHeadPosition.epParaNr += paraShift;
267 	df->dfHeadPosition.epStroff += stroffShift;
268 	/*  1  */
269 	if  ( df->dfSelectionScope.ssTreeType == DOCinBODY )
270 	    { df->dfSelectionScope.ssSectNr += sectShift;	}
271 
272 	return;
273 	}
274 
275     return;
276     }
277 
docShiftFieldEnd(DocumentField * df,int sectFrom,int paraFrom,int stroffFrom,int sectShift,int paraShift,int stroffShift)278 static void docShiftFieldEnd(		DocumentField *		df,
279 					int			sectFrom,
280 					int			paraFrom,
281 					int			stroffFrom,
282 					int			sectShift,
283 					int			paraShift,
284 					int			stroffShift )
285     {
286     /*  earlier paragraph  */
287     if  ( df->dfTailPosition.epParaNr < paraFrom )
288 	{ return;	}
289 
290     /*  later paragraph  */
291     if  ( df->dfTailPosition.epParaNr > paraFrom )
292 	{
293 	df->dfTailPosition.epParaNr += paraShift;
294 	/*  1
295 	if  ( df->dfSelectionScope.ssTreeType == DOCinBODY )
296 	    { df->dfSelectionScope.ssSectNr += sectShift;	}
297 	*/
298 
299 	return;
300 	}
301 
302     /* Same paragraph */
303     if  ( df->dfTailPosition.epStroff < stroffFrom )
304 	{ return;	}
305     if  ( df->dfTailPosition.epStroff > stroffFrom )
306 	{
307 	df->dfTailPosition.epParaNr += paraShift;
308 	df->dfTailPosition.epStroff += stroffShift;
309 	/*  1
310 	if  ( df->dfSelectionScope.ssTreeType == DOCinBODY )
311 	    { df->dfSelectionScope.ssSectNr += sectShift;	}
312 	*/
313 
314 	return;
315 	}
316 
317     return;
318     }
319 
320 /************************************************************************/
321 /*									*/
322 /*  Shift fields.							*/
323 /*									*/
324 /************************************************************************/
325 
docShiftChildFieldReferences(const ChildFields * cf,int sectFrom,int paraFrom,int stroffFrom,int sectShift,int paraShift,int stroffShift)326 static void docShiftChildFieldReferences(
327 					const ChildFields *	cf,
328 					int			sectFrom,
329 					int			paraFrom,
330 					int			stroffFrom,
331 					int			sectShift,
332 					int			paraShift,
333 					int			stroffShift )
334     {
335     int			l;
336     int			r;
337     int			m;
338 
339     DocumentField *	df;
340 
341     if  ( cf->cfChildCount == 0 )
342 	{ return;	}
343 
344     l= 0; r= cf->cfChildCount; m= ( l+ r )/ 2;
345     while( l < m )
346 	{
347 	df= cf->cfChildren[m];
348 
349 	if  ( df->dfTailPosition.epParaNr < paraFrom )
350 	    { l= m;	}
351 	else{ r= m;	}
352 
353 	m= ( l+ r )/ 2;
354 	}
355 
356     df= cf->cfChildren[m];
357     if  ( df->dfTailPosition.epParaNr < paraFrom )
358 	{ m++;	}
359 
360     for ( m= m; m < cf->cfChildCount; m++ )
361 	{
362 	DocumentField *	dfc= cf->cfChildren[m];
363 
364 	if  ( dfc->dfFieldNumber < 0 )
365 	    { LDEB(dfc->dfFieldNumber); continue;	}
366 
367 	if  ( dfc->dfSelectionScope.ssTreeType == DOCinBODY		&&
368 	      dfc->dfSelectionScope.ssOwnerSectNr >= 0			&&
369 	      dfc->dfSelectionScope.ssOwnerSectNr > sectFrom		)
370 	    { dfc->dfSelectionScope.ssOwnerSectNr += sectShift;		}
371 
372 	docShiftFieldStart( dfc, sectFrom, paraFrom, stroffFrom,
373 					sectShift, paraShift, stroffShift );
374 	docShiftFieldEnd( dfc, sectFrom, paraFrom, stroffFrom,
375 					sectShift, paraShift, stroffShift );
376 
377 	if  ( dfc->dfChildFields.cfChildCount > 0 )
378 	    {
379 	    docShiftChildFieldReferences( &(dfc->dfChildFields),
380 					sectFrom, paraFrom, stroffFrom,
381 					sectShift, paraShift, stroffShift );
382 	    }
383 	}
384 
385     return;
386     }
387 
docShiftFieldReferences(DocumentTree * dt,int sectFrom,int paraFrom,int stroffFrom,int sectShift,int paraShift,int stroffShift)388 int docShiftFieldReferences(		DocumentTree *		dt,
389 					int			sectFrom,
390 					int			paraFrom,
391 					int			stroffFrom,
392 					int			sectShift,
393 					int			paraShift,
394 					int			stroffShift )
395     {
396     /*
397     appDebug( "docShiftFieldReferences( %s,"
398 		" para:%d+%d, stroff:%d+%d )\n",
399 	    docTreeTypeStr( dt->dtRoot?dt->dtRoot->biTreeType:-1 ),
400 	    paraFrom, paraShift, stroffFrom, stroffShift );
401     */
402 
403     /*  1  */
404     if  ( paraFrom < 1 )
405 	{ LDEB(paraFrom); return -1;	}
406 
407     docShiftChildFieldReferences( &(dt->dtRootFields),
408 					sectFrom, paraFrom, stroffFrom,
409 					sectShift, paraShift, stroffShift );
410     return 0;
411     }
412 
413 /************************************************************************/
414 /*									*/
415 /*  Delete all fields that completely fall inside a range in the	*/
416 /*  document.								*/
417 /*									*/
418 /************************************************************************/
419 
docDeleteFieldChildren(int * pUpdateFlags,BufferDocument * bd,DocumentField * dfp)420 static void docDeleteFieldChildren(	int *			pUpdateFlags,
421 					BufferDocument *	bd,
422 					DocumentField *		dfp )
423     {
424     if  ( dfp->dfKind == DOCfkLISTTEXT )
425 	{ (*pUpdateFlags) |= FIELDdoLISTTEXT;	}
426     if  ( dfp->dfKind == DOCfkSEQ )
427 	{ (*pUpdateFlags) |= FIELDdoSEQ;	}
428     if  ( docFieldHasNote( dfp->dfKind ) && dfp->dfNoteIndex >= 0 )
429 	{ (*pUpdateFlags) |= FIELDdoCHFTN;	}
430 
431     docDeleteChildFields( pUpdateFlags, bd, &(dfp->dfChildFields) );
432     return;
433     }
434 
docDeleteChildFields(int * pUpdateFlags,BufferDocument * bd,ChildFields * cf)435 void docDeleteChildFields(	int *			pUpdateFlags,
436 				BufferDocument *	bd,
437 				ChildFields *		cf )
438     {
439     int		i;
440 
441     for ( i= 0; i < cf->cfChildCount; i++ )
442 	{
443 	DocumentField *	dfc= cf->cfChildren[i];
444 
445 	docDeleteFieldChildren( pUpdateFlags, bd, dfc );
446 	docDeleteFieldFromDocument( bd, dfc );
447 	}
448 
449     docCleanChildFields( cf );
450     docInitChildFields( cf );
451     }
452 
453 /************************************************************************/
454 /*									*/
455 /*  Delete a field from a document and remove all references.		*/
456 /*									*/
457 /*  NOTE The shortcut that optimizes a lot of superfluous calls.	*/
458 /*									*/
459 /************************************************************************/
460 
docDeleteFieldFromParent(DocumentTree * dt,DocumentField * df)461 int docDeleteFieldFromParent(	DocumentTree *			dt,
462 				DocumentField *			df )
463     {
464     ChildFields *	cf;
465 
466     if  ( df->dfParent )
467 	{ cf= &(df->dfParent->dfChildFields);	}
468     else{ cf= &(dt->dtRootFields);		}
469 
470     if  ( df->dfChildFields.cfChildCount == 0	&&
471 	  cf->cfChildCount == 1			)
472 	{ cf->cfChildCount--;	}
473     else{
474 	if  ( docDeleteChildField( cf, df ) )
475 	    {
476 	    SDEB(docTreeTypeStr(df->dfSelectionScope.ssTreeType));
477 	    XDEB(df->dfParent);
478 	    return -1;
479 	    }
480 	}
481 
482     df->dfNumberInParent= -1;
483 
484     return 0;
485     }
486 
487 /************************************************************************/
488 /*									*/
489 /*  Delete all fields that overlap a range.				*/
490 /*									*/
491 /************************************************************************/
492 
docDeleteFieldRange(int * pUpdateFlags,BufferDocument * bd,const EditRange * er,ChildFields * rootFields,DocumentField * dfLeft,DocumentField * dfRight)493 int docDeleteFieldRange(	int *			pUpdateFlags,
494 				BufferDocument *	bd,
495 				const EditRange *	er,
496 				ChildFields *		rootFields,
497 				DocumentField *		dfLeft,
498 				DocumentField *		dfRight )
499     {
500     int			rval= 0;
501     int			i;
502 
503     int			count= rootFields->cfChildCount;
504     DocumentField **	fields= (DocumentField **)0;
505 
506     if  ( rootFields->cfChildCount == 0 )
507 	{ goto ready;	}
508 
509     fields= (DocumentField **)malloc( count* sizeof(DocumentField *) );
510     if  ( ! fields )
511 	{ LXDEB(count,fields); rval= -1; goto ready;	}
512 
513     for ( i= 0; i < count; i++ )
514 	{ fields[i]= rootFields->cfChildren[i];	}
515 
516     /*  1  */
517     for ( i= 0; i < count; i++ )
518 	{
519 	DocumentField *		df= fields[i];
520 	int			bcm;
521 	int			ecm;
522 
523 	if  ( docCompareEditPositions( &(df->dfTailPosition),
524 						    &(er->erHead) ) <= 0 )
525 	    { continue;	}
526 
527 	if  ( docCompareEditPositions( &(df->dfHeadPosition),
528 						    &(er->erTail) ) >= 0 )
529 	    { break;	}
530 
531 	bcm= docCompareEditPositions( &(df->dfHeadPosition), &(er->erHead) );
532 	ecm= docCompareEditPositions( &(df->dfTailPosition), &(er->erTail) );
533 
534 	if  ( bcm < 0 || ecm > 0 )
535 	    {
536 	    docDeleteFieldRange( pUpdateFlags, bd, er,
537 						    &(df->dfChildFields),
538 						    dfLeft, dfRight );
539 	    }
540 	else{
541 	    if  ( df->dfKind == DOCfkLISTTEXT )
542 		{ (*pUpdateFlags) |= FIELDdoLISTTEXT;	}
543 	    if  ( df->dfKind == DOCfkSEQ )
544 		{ (*pUpdateFlags) |= FIELDdoSEQ;	}
545 	    if  ( docFieldHasNote( df->dfKind ) && df->dfNoteIndex >= 0 )
546 		{ (*pUpdateFlags) |= FIELDdoCHFTN;	}
547 
548 	    docDeleteFieldChildren( pUpdateFlags, bd, df );
549 	    docDeleteChildField( rootFields, df );
550 	    docDeleteFieldFromDocument( bd, df );
551 	    }
552 	}
553 
554   ready:
555 
556     if  ( fields )
557 	{ free( fields );	}
558 
559     return rval;
560     }
561 
562 /************************************************************************/
563 /*									*/
564 /*  Insert the special field at the head of a numbered paragraph.	*/
565 /*  (buller), or of a foot/endnote.					*/
566 /*									*/
567 /*  0)  Insert a text particule at the head of the paragraph as a	*/
568 /*	temporary field value.						*/
569 /*  1)  Allocate a field.						*/
570 /*  2)  Insert start particule.						*/
571 /*  3)  Insert end particule.						*/
572 /*  4)  Make sure there is at least one particule after the field.	*/
573 /*									*/
574 /************************************************************************/
575 
docInsertParaHeadField(DocumentField ** pDfHead,DocumentSelection * dsInsideHead,DocumentSelection * dsAroundHead,int * pHeadPart,int * pTailPart,BufferItem * paraBi,BufferDocument * bd,DocumentTree * dt,int fieldKind,int textAttrNr)576 int docInsertParaHeadField(	DocumentField **	pDfHead,
577 				DocumentSelection *	dsInsideHead,
578 				DocumentSelection *	dsAroundHead,
579 				int *			pHeadPart,
580 				int *			pTailPart,
581 				BufferItem *		paraBi,
582 				BufferDocument *	bd,
583 				DocumentTree *		dt,
584 				int			fieldKind,
585 				int			textAttrNr )
586     {
587     DocumentField *		df;
588     TextParticule *		tpText;
589     int				stroffShift= 0;
590     int				head= 0;
591     const int			stroffHead= 0;
592     int				wasEmpty= ( docParaStrlen( paraBi ) == 0 );
593     DocumentFieldList *		dfl= &(bd->bdFieldList);
594 
595     DocumentSelection		dsField;
596 
597     while( head+ 1 < paraBi->biParaParticuleCount			&&
598 	   paraBi->biParaParticules[head+ 1].tpStroff == stroffHead	&&
599 	   paraBi->biParaParticules[head+ 1].tpKind == DOCkindFIELDHEAD &&
600 	   docGetFieldKindByNumber( dfl,
601 	     paraBi->biParaParticules[head+ 1].tpObjectNumber==DOCfkBOOKMARK ) )
602 	{ head++;	}
603 
604     /*  4  */
605     if  ( docParaStringReplace( &stroffShift, paraBi,
606 			    stroffHead, stroffHead, (const char *)"?", 1 ) )
607 	{ LDEB(docParaStrlen(paraBi)); return -1; }
608 
609     if  ( paraBi->biParaParticuleCount > 0 && wasEmpty )
610 	{
611 	tpText= paraBi->biParaParticules;
612 	if  ( tpText->tpKind != DOCkindSPAN )
613 	    { SDEB(docKindStr(tpText->tpKind)); return -1;	}
614 
615 	tpText->tpStrlen= 1;
616 
617 	if  ( docShiftParticuleOffsets( bd, paraBi, head+ 1,
618 				paraBi->biParaParticuleCount, stroffShift ) )
619 	    { LDEB(stroffShift); }
620 	}
621     else{
622 	tpText= docInsertTextParticule( paraBi, head,
623 			    stroffHead, 1, DOCkindSPAN, textAttrNr );
624 	if  ( ! tpText )
625 	    { LXDEB(paraBi->biParaParticuleCount,tpText); return -1; }
626 
627 	if  ( docShiftParticuleOffsets( bd, paraBi, head+ 1,
628 				paraBi->biParaParticuleCount, stroffShift ) )
629 	    { LDEB(stroffShift); }
630 	}
631 
632     docSetParaSelection( &dsField, paraBi, 1, stroffHead, stroffShift );
633 
634     /*  2,3  */
635     df= docMakeField( bd, dt, &dsField, head, head+ 1, textAttrNr, textAttrNr );
636     if  ( ! df )
637 	{ XDEB(df); return -1;	}
638 
639     df->dfKind= fieldKind;
640 
641     /*  4  */
642     if  ( paraBi->biParaParticuleCount == head+ 3 )
643 	{
644 	tpText= docInsertTextParticule( paraBi, head+ 3,
645 					docParaStrlen( paraBi ), 0,
646 					DOCkindSPAN, textAttrNr );
647 	if  ( ! tpText )
648 	    { LXDEB(paraBi->biParaParticuleCount,tpText); return -1; }
649 	}
650 
651     if  ( docDelimitFieldInDoc( dsInsideHead, dsAroundHead,
652 					    pHeadPart, pTailPart, bd, df ) )
653 	{ LDEB(1); return -1; }
654 
655     *pDfHead= df;
656     return 0;
657     }
658 
docMakeField(BufferDocument * bd,DocumentTree * dt,const DocumentSelection * dsInput,int part0,int part1,int attr0,int attr1)659 DocumentField * docMakeField(	BufferDocument *		bd,
660 				DocumentTree *			dt,
661 				const DocumentSelection *	dsInput,
662 				int				part0,
663 				int				part1,
664 				int				attr0,
665 				int				attr1 )
666     {
667     int			paraNr0= docNumberOfParagraph( dsInput->dsHead.dpNode );
668     int			paraNr1;
669     const BufferItem *	sectBi0;
670 
671     DocumentField *	rval= (DocumentField *)0;
672     DocumentField *	df;
673     int			singleParagraph= 0;
674 
675     int			stroff0;
676     int			stroff1;
677 
678     df= docClaimField( &(bd->bdFieldList) );
679     if  ( ! df )
680 	{ XDEB(df); goto ready;	}
681     df->dfKind= DOCfkUNKNOWN;
682 
683     sectBi0= docGetSectNode( dsInput->dsHead.dpNode );
684     if  ( ! sectBi0 )
685 	{ XDEB(sectBi0); goto ready;	}
686 
687     if  ( dsInput->dsTail.dpNode == dsInput->dsHead.dpNode )
688 	{ singleParagraph= 1; paraNr1= paraNr0;	}
689     else{
690 	const BufferItem *	sectBi1;
691 
692 	singleParagraph= 0;
693 	paraNr1= docNumberOfParagraph( dsInput->dsTail.dpNode );
694 
695 	sectBi1= docGetSectNode( dsInput->dsTail.dpNode );
696 	if  ( ! sectBi1 )
697 	    { XDEB(sectBi1); goto ready;	}
698 
699 	if  ( sectBi1 != sectBi0 )
700 	    { XXDEB(sectBi0,sectBi1); goto ready;	}
701 	}
702 
703     {
704     TextParticule *	tp;
705 
706     tp= docMakeSpecialParticule( dsInput->dsTail.dpNode, part1,
707 		    dsInput->dsTail.dpStroff, DOCkindFIELDTAIL, attr1 );
708     if  ( ! tp )
709 	{ XDEB(tp); goto ready;	}
710     tp->tpObjectNumber= df->dfFieldNumber;
711     stroff1= tp->tpStroff;
712 
713     docShiftParticuleOffsets( bd, dsInput->dsTail.dpNode, part1+ 1,
714 		dsInput->dsTail.dpNode->biParaParticuleCount, tp->tpStrlen );
715     }
716 
717     {
718     TextParticule *	tp;
719 
720     tp= docMakeSpecialParticule( dsInput->dsHead.dpNode, part0,
721 		    dsInput->dsHead.dpStroff, DOCkindFIELDHEAD, attr0 );
722     if  ( ! tp )
723 	{ XDEB(tp); goto ready;	}
724     tp->tpObjectNumber= df->dfFieldNumber;
725     stroff0= tp->tpStroff;
726 
727     docShiftParticuleOffsets( bd, dsInput->dsHead.dpNode, part0+ 1,
728 		dsInput->dsHead.dpNode->biParaParticuleCount, tp->tpStrlen );
729 
730     if  ( singleParagraph )
731 	{ stroff1 += tp->tpStrlen;	}
732     }
733 
734     df->dfSelectionScope= sectBi0->biSectSelectionScope;
735     df->dfHeadPosition.epParaNr= paraNr0;
736     df->dfHeadPosition.epStroff= stroff0;
737     df->dfTailPosition.epParaNr= paraNr1;
738     df->dfTailPosition.epStroff= stroff1;
739 
740     if  ( docInsertFieldInTree( &(dt->dtRootFields), df ) )
741 	{ LDEB(1); goto ready;	}
742 
743     rval= df; df= (DocumentField *)0; /* steal */
744 
745   ready:
746 
747     if  ( df )
748 	{ docDeleteFieldFromList( &(bd->bdFieldList), df );	}
749 
750     return rval;
751     }
752 
753 /************************************************************************/
754 /*									*/
755 /*  Find the special field at the head of a paragraph in a list.	*/
756 /*									*/
757 /************************************************************************/
758 
docParaHeadFieldKind(const BufferItem * paraBi,const BufferDocument * bd)759 int docParaHeadFieldKind(	const BufferItem *	paraBi,
760 				const BufferDocument *	bd )
761     {
762     int		fieldKind= -1;
763 
764     if  ( paraBi->biTreeType == DOCinFOOTNOTE	||
765 	  paraBi->biTreeType == DOCinENDNOTE	)
766 	{
767 	BufferItem *		bi= docGetSectNode( paraBi->biParent );
768 	if  ( ! bi )
769 	    { XDEB(bi); return -1;		}
770 	else{
771 	    DocumentPosition	dp;
772 
773 	    if  ( docHeadPosition( &dp, bi ) )
774 		{ LDEB(1); return -1;	}
775 
776 	    if  ( dp.dpNode == paraBi )
777 		{ fieldKind= DOCfkCHFTN;	}
778 	    }
779 	}
780 
781     if  ( paraBi->biParaListOverride > 0 )
782 	{ fieldKind= DOCfkLISTTEXT;	}
783 
784     return fieldKind;
785     }
786 
787