/*************************************************************************** * Function: AbsorbAnyBlanks * Purpose: * Update PLINE by making it point to the first non-blank * at-or-after from but not after limit. * If they are all blank then make it point to limit * If from is non-blank then leave it alone. * Return true iff PLINE was updated. * It is legit for limit to be null (meaning end of file).*/ public static bool AbsorbAnyBlanks(ref Line from , Line limit, bool bMoveToNext ) { bool progress = false; while ( ( from != null ) && ( from.IsBlank() ) && ( from != limit ) ) { if( bMoveToNext ) from = (Line)from.GetNext(); else from = (Line)from.GetPrev(); progress = true; } return progress; }
/*************************************************************************** * Function: ExpandAnchor * Purpose: * Given an anchor point (two lines that we think should match), * try to link them, and the lines above and below them for as long * as the lines can be linked (are the same, are unlinked). * Return true if we make any links. */ public static bool ExpandAnchor(Section sec1, Line line1, Section sec2, Line line2,bool isIgnoreBlanks) { /* when a line is matched we set bChanges. If we notice some * blank lines, but do NOT link any new non-blank lines, we * do NOT set bChanges. (If we did it would cause a closed * loop as they would get noticed again next time. line_link * only returns true if it is a NEW link). * At this stage we are only interested in making links, not in * the size of the section that results (that fun comes later). * therefore trailing blanks at the end of a section are not * interesting and we don't look for them. */ bool bChanges = false; /* We handle the section limits by using a sentinel which is one * past the end of the section. (If the section ends at the end * of the list then the sentinel is null). */ Line leftend = (Line)sec1.last.GetNext(); Line rightend = (Line)sec2.last.GetNext(); /* null lines shall not match */ if ((line1 == null) || (line2 == null)) return false; /* check all lines forward until fail to link (because null, * not matching, or already linked). include the passed in anchor point since this has not * yet been linked. If blanks are ignorable then skip over any number of whole * blank lines. */ Line left = line1; Line right = line2; for(;;){ if( left.Link( right, isIgnoreBlanks ) ){ bChanges = true; left = (Line)left.GetNext(); right = (Line)right.GetNext(); if( left == leftend || right == rightend ) break; } else if( isIgnoreBlanks ){ /* even though no match, maybe an ignorable blank? */ bool moved = false; moved |= AbsorbAnyBlanks( ref left, leftend, /*bMoveToNext=*/true); moved |= AbsorbAnyBlanks( ref right, rightend,/*bMoveToNext=*/true); if( !moved ) break; /* it didn't match and we didn't move on */ if( left == leftend || right == rightend ) break; } else break; } /* check all matches going backwards from anchor point but only if it was a real anchor (could have been end-of-section/end-of-file and non-matching). */ if( line1.link == null ) return bChanges; left = (Line)line1.GetPrev(); right = (Line)line2.GetPrev(); if( left == null || right == null ) return bChanges; leftend = (Line)sec1.first.GetPrev(); rightend = (Line)sec2.first.GetPrev(); for(;;){ if( left.Link(right,isIgnoreBlanks) ){ bChanges = true; left = (Line)left.GetPrev(); right = (Line)right.GetPrev(); if( left == leftend || right == rightend ) break; } else if( isIgnoreBlanks ){ /* even though no match, maybe an ignorable blank? */ bool moved = false; moved |= AbsorbAnyBlanks( ref left, leftend, /*bMoveToNext=*/false); moved |= AbsorbAnyBlanks( ref right, rightend, /*bMoveToNext=*/false); if( !moved ) break; /* it didn't match and we didn't move on */ if( left == leftend || right == rightend ) break; } else break; } return bChanges; }