Files
mars-flaim/flaim/src/gdgraft.cpp
dsandersoremutah c55dab446f Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-01-27 21:06:39 +00:00

209 lines
7.3 KiB
C++

//-------------------------------------------------------------------------
// Desc: Graft a node into a GEDCOM tree.
// Tabs: 3
//
// Copyright (c) 1990-1993,1995-2000,2003,2005-2006 Novell, Inc. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of version 2 of the GNU General Public
// License as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, contact Novell, Inc.
//
// To contact Novell about this file by physical or electronic mail,
// you may find current contact information at www.novell.com
//
// $Id: gdgraft.cpp 12307 2006-01-19 15:06:34 -0700 (Thu, 19 Jan 2006) dsanders $
//-------------------------------------------------------------------------
#include "flaimsys.h"
/*API~***********************************************************************
Name : GedChildGraft
Area : GEDCOM/LINK
Desc : Links a node or sub-tree as a child of an existing node.
*END************************************************************************/
NODE *
// A pointer to the parent node is returned.
GedChildGraft(
NODE * parent,
// [IN] Pointer to the node to which the child will be linked.
NODE * child,
// [IN] Pointer to the child node.
FLMINT nth
// [IN] Determines where the child will be linked. Use GED_FIRST
// or GED_LAST to link as the first or last child of the parent.
// Otherwise, set nth to the ordinal number of the existing
// child to which the new child should be linked. For
// example, set nth to 1 to link after the 1st existing child.
// If no children currently exist, nth may be any value.
//
// Note: The child node must not be connected to anything else.
// If the child node is already linked to another node,
// unpredictable results (such as circular trees) could occur.
)
{
NODE * lastChildNode; /* Used when child is sub-tree */
if( parent && child)
{
FLMINT level = GedNodeLevel( parent) + 1;
if( GedChild( parent)) /* Parent already has child(ren) */
{
GedSibGraft(
GedChild( parent), /* graft as sib of 1st child instead */
child,
(FLMINT)(nth == GED_FIRST /* subtacting 1 could wrap to GED_LAST */
? GED_FIRST /* don't wrap */
: nth - 1) /* graft now relative to 1st child */
);
}
else /* Parent has no children */
{
for( /* find end of child's sub-tree */
lastChildNode = child
; lastChildNode->next
; GedNodeLevelAdd( lastChildNode, level), /* adjust level of sub-tree nodes */
lastChildNode = lastChildNode->next
);
child->prior = parent;
GedNodeLevelAdd( lastChildNode, level); /* adjust last node's level */
lastChildNode->next = parent->next;
if( parent->next)
parent->next->prior = lastChildNode;
parent->next = child;
}
}
return( parent);
}
/*API~***********************************************************************
Name : GedSibGraft
Area : GEDCOM/LINK
Desc : Links a node or sub-tree as a sibling of an existing node.
DNote: GED_LAST and GED_FIRST are #define's of +/- 32k. These are practical
assumptions. Their actual value is not tested--the loop continues
for that count or until no further siblings are found. That is to say,
if there are too many siblings in the list, a true LAST or FIRST is not
reached. Since all "nth" parameters are WORD typed, other routines
would have the same problem.
*END************************************************************************/
NODE *
// A pointer to self or sib is returned depending upon which one
// occurs first in the sibling list. If sib occurs first, a
// pointer to sib is returned. Otherwise, a pointer to self is
// returned.
GedSibGraft(
NODE * self,
// [IN] Pointer to the node to which the child will be linked.
NODE * sib,
// [IN] Pointer to the node which is to be linked as a sibling.
FLMINT nth
// [IN] Determines where the sibling will be linked. Use GED_FIRST
// or GED_LAST to link as the first or last sibling of self.
// Otherwise, set nth to an ordinal number (relative to self) to
// specify which sibling that sib should be linked after. Zero
// will cause sib to be linked directly after self and a value of
// -1 will cause sib to be linked after the prior sibling.
//
// Note: The sib node must not be connected to anything else.
// If the node is already linked to another node, unpredictable
// results (such as circular trees) could occur.
)
{
NODE * lastSibNode;
NODE * returnNode;
FLMINT deltaLevel;
FLMUINT level;
FLMUINT linkAt = TRUE;
if( ! sib)
return( self);
if( ! self)
return( sib);
for( /* find end of sib's sub-tree */
level = GedNodeLevel( self),
deltaLevel = (FLMINT)(level - GedNodeLevel( sib)),
/* Compute delta to modify sib tree*/
lastSibNode = sib
; lastSibNode->next
; GedNodeLevelAdd( lastSibNode, deltaLevel), /* adjust level of sub-tree nodes */
lastSibNode = lastSibNode->next
);
GedNodeLevelAdd( lastSibNode, deltaLevel); /* adjust last node's level */
if (nth != GED_LAST ) /* Adjust nth to be zero based */
nth++; /* in order to work with algorithm */
if( nth <= 0) /* going up sibling list */
{
returnNode = sib;
while( nth) /* stop when nth is -1 */
{
if( self->prior)
{
self = self->prior;
if( GedNodeLevel( self) > level) /* nephew here */
continue; /* skip sub-tree */
else if( GedNodeLevel( self) == level) /* true sibling here */
{
nth++; /* count up to zero (nth < 0) */
continue;
}
/* else no prior siblings; at parent */
self = self->next; /* point back to first child */
}
break; /* graft as first sibling in list */
}
}
else /* going down sibling list */
{
returnNode = self;
while( nth) /* stop after nth node */
{
if( self->next)
{
self = self->next;
if( GedNodeLevel( self) > level)
continue; /* skip sub-tree */
else if( GedNodeLevel( self) == level)
{
nth--; /* count down to zero (nth > 0) */
continue;
}
/* else no following siblings */
self = self->prior; /* point back to prior node */
}
linkAt = FALSE; /* Link AFTER the self node */
break; /* graft as last sibling in list */
}
}
if( linkAt)
{
/* Link the sib tree AT the current self location - link before self */
sib->prior = self->prior;
lastSibNode->next = self;
if( self->prior)
self->prior->next = sib;
self->prior = lastSibNode;
}
else /* link AFTER */
{
/* Link the sib tree AFTER the current self location */
sib->prior = self;
lastSibNode->next = self->next;
if( self->next)
self->next->prior = lastSibNode;
self->next = sib;
}
return( returnNode);
}