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