git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
209 lines
7.3 KiB
C++
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);
|
|
}
|
|
|