campo-sirio/xi/xitree.c
alex ebabab8c26 This commit was generated by cvs2svn to compensate for changes in r5761,
which included commits to RCS files with non-trunk default branches.

git-svn-id: svn://10.65.10.50/trunk@5762 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-12-17 12:57:49 +00:00

507 lines
11 KiB
C
Executable File

/*******************************************************************************
* Copyright 1991-1996 by ORCA Software, Inc. *
* *
* All rights reserved. May not be reproduced or distributed, in printed or *
* electronic form, without permission of ORCA Software, Inc. May not be *
* distributed as object code, separately or linked with other object modules, *
* without permission. *
*******************************************************************************/
/* ERROR CODES 20201-20201 */
#define XI_INTERNAL
#include "xi.h"
#include "xiheap.h"
#include "xiutils.h"
#define PADCHAR ((char)0x8e)
#define MAGIC 0xe8
/*
constants to define for more debugging
PAD - pad allocations with N bytes of magic and check magic number when
xi_tree_check_sanity is called
FENCE - call xi_tree_check_sanity on every Nth xi_tree_* call
PREPAD - put an extra N bytes between the node struct and the data.
This padding is never checked.
sample usage:
#define PAD 20
#define FENCE 10
#define PREPAD 10
*/
/*
#define PAD 100
#define FENCE 1
*/
typedef struct _tree_node
{
struct _tree_node *parent;
struct _tree_node *sibling;
struct _tree_node *child;
#ifdef TREEDEBUG
int line;
char *file;
int magic; /* for sanity checks */
int size;
#ifdef PREPAD
char prepad[PREPAD];
#endif
#endif
} TREE_NODE;
/* This code automatically determines the proper size for TREE_NODE so that
the data following it is always correctly aligned. */
static struct
{
TREE_NODE node;
double data;
} dummy_header;
#define SIZEOF_TREE_NODE ((int)( (char*)&dummy_header.data - (char*)&dummy_header.node ))
#ifdef TREEDEBUG
#undef xi_tree_malloc
#undef xi_tree_realloc
#define xi_tree_malloc_body xi_tree_malloc_d
#define xi_tree_realloc_body xi_tree_realloc_d
#define xi_tree_malloc_stub xi_tree_malloc
#define xi_tree_realloc_stub xi_tree_realloc
#else
#define xi_tree_malloc_body xi_tree_malloc
#define xi_tree_realloc_body xi_tree_realloc
#define xi_tree_malloc_stub xi_tree_malloc_d
#define xi_tree_realloc_stub xi_tree_realloc_d
#endif
#define VOIDPTR_TO_TREEPTR(p) ((TREE_NODE *)((long)(p) - SIZEOF_TREE_NODE))
#define TREEPTR_TO_VOIDPTR(t) ((void *)((long)(t) + SIZEOF_TREE_NODE))
#define DBGTAB 3
static TREE_NODE topnode =
{
NULL, &topnode, NULL
#ifdef TREEDEBUG
,0, "TOPNODE", MAGIC, 0
#endif
};
static TREE_NODE *top = &topnode;
#ifdef TREEDEBUG
#ifdef FENCE
static int fence_count;
#endif
static int node_count = 1; /* start with just top node */
#endif
static void
dflt_error_fcn( void )
{
NOREF( dummy_header.data );
XinError( 20201, XinSeverityFatal, 0L );
}
static void ( *error_fcn ) ( void ) = dflt_error_fcn;
#ifdef TREEDEBUG
void xi_tree_check_fence( void );
void
xi_tree_check_fence( void )
{
#ifdef FENCE
static int fence_count;
fence_count++;
if ( fence_count % FENCE == 0 )
xi_tree_check_sanity( "FENCE CHECK" );
#endif
}
static void
adjust_size( size_t * size )
{
NOREF( size );
#ifdef PAD
*size += PAD;
#endif
}
static void
validate_node( void *p )
{
if ( p != NULL && VOIDPTR_TO_TREEPTR( p )->magic != MAGIC )
XinDialogFatal( "Bad tree node detected: file %s, line %d",
VOIDPTR_TO_TREEPTR( p )->file, VOIDPTR_TO_TREEPTR( p )->line );
}
#endif
static void
remove_from_siblings_and_parent( TREE_NODE * remove_t )
{
TREE_NODE *tp;
/* remove from sibling list */
tp = remove_t;
while ( tp->sibling != remove_t )
tp = tp->sibling;
tp->sibling = remove_t->sibling;
/* adjust parent pointers */
if ( remove_t->parent->child == remove_t )
{
remove_t->parent->child = ( ( remove_t->sibling == remove_t ) ?
NULL : remove_t->sibling );
}
}
static void
xi_tree_free_internal( TREE_NODE * remove_t, BOOLEAN toplevel )
{
TREE_NODE *tp;
TREE_NODE *nexttp;
if ( toplevel )
{
remove_from_siblings_and_parent( remove_t );
remove_t->sibling = NULL;
}
/* free all child nodes */
tp = remove_t->child;
if ( tp != NULL )
do
{
/* store next pointer before nuking node */
nexttp = tp->sibling;
xi_tree_free_internal( tp, FALSE );
tp = nexttp;
} while ( tp != remove_t->child );
/* free underlying heap manager memory */
#ifdef TREEDEBUG
heap_free( remove_t->file );
node_count--;
#endif
heap_free( remove_t );
}
void
xi_tree_reparent( void *p, void *parent )
{
TREE_NODE *tn;
#ifdef TREEDEBUG
xi_tree_check_fence( );
validate_node( p );
#endif
remove_from_siblings_and_parent( VOIDPTR_TO_TREEPTR( p ) );
tn = VOIDPTR_TO_TREEPTR( p );
if ( parent == NULL )
parent = TREEPTR_TO_VOIDPTR( top );
tn->parent = VOIDPTR_TO_TREEPTR( parent );
if ( tn->parent->child == NULL )
{
tn->parent->child = tn;
tn->sibling = tn;
}
else
{
/* insert tn in the sibling list */
tn->sibling = tn->parent->child->sibling;
tn->parent->child->sibling = tn;
}
}
void
xi_tree_free( void *p )
{
#ifdef TREEDEBUG
xi_tree_check_fence( );
validate_node( p );
#endif
xi_tree_free_internal( VOIDPTR_TO_TREEPTR( p ), TRUE );
}
void *
xi_tree_get_parent( void *p )
{
TREE_NODE *parent;
#ifdef TREEDEBUG
validate_node( p );
#endif
parent = VOIDPTR_TO_TREEPTR( p )->parent;
return ( ( parent == top ) ? NULL : TREEPTR_TO_VOIDPTR( parent ) );
}
void *
xi_tree_malloc_body( size_t size, void *parent
#ifdef TREEDEBUG
,int line, char *file
#endif
)
{
TREE_NODE *tn;
#ifdef TREEDEBUG
size_t orig_size = size;
xi_tree_check_fence( );
validate_node( parent );
adjust_size( &size );
#endif
tn = ( TREE_NODE * ) heap_malloc( size + SIZEOF_TREE_NODE );
if ( !tn )
{
( *error_fcn ) ( );
return NULL;
}
#ifdef TREEDEBUG
memset( ( char * ) tn + SIZEOF_TREE_NODE + orig_size,
PADCHAR, ( long ) ( size - orig_size ) );
tn->file = ( char * ) heap_malloc( strlen( file ) + 1 );
if ( !tn->file )
{
( *error_fcn ) ( );
return NULL;
}
strcpy( tn->file, file );
tn->line = line;
tn->magic = MAGIC;
tn->size = size;
node_count++;
#endif
tn->child = NULL;
tn->sibling = tn;
if ( parent == NULL )
parent = TREEPTR_TO_VOIDPTR( top );
tn->parent = VOIDPTR_TO_TREEPTR( parent );
if ( tn->parent->child == NULL )
tn->parent->child = tn;
else
{
/* insert tn in the sibling list */
tn->sibling = tn->parent->child->sibling;
tn->parent->child->sibling = tn;
}
return ( TREEPTR_TO_VOIDPTR( tn ) );
}
void *
xi_tree_realloc_body( void *p, size_t size
#ifdef TREEDEBUG
,int line, char *file
#endif
)
{
TREE_NODE *old_t;
TREE_NODE *new_t;
TREE_NODE *tp;
#ifdef TREEDEBUG
size_t orig_size = size;
xi_tree_check_fence( );
adjust_size( &size );
#endif
old_t = VOIDPTR_TO_TREEPTR( p );
#ifdef TREEDEBUG
validate_node( p );
#endif
new_t = ( TREE_NODE * ) heap_realloc( old_t, ( size + SIZEOF_TREE_NODE ) );
#ifdef TREEDEBUG
if ( !new_t )
{
( *error_fcn ) ( );
return NULL;
}
memset( ( char * ) new_t + SIZEOF_TREE_NODE + orig_size,
PADCHAR, ( long ) ( size - orig_size ) );
new_t->line = line;
new_t->size = size;
heap_free( new_t->file );
new_t->file = ( char * ) heap_malloc( strlen( file ) + 1 );
if ( !new_t->file )
{
( *error_fcn ) ( );
return NULL;
}
strcpy( new_t->file, file );
#endif
if ( new_t != old_t )
{
/* change parent pointer */
if ( new_t->parent->child == old_t )
new_t->parent->child = new_t;
/* change sibling pointers */
for ( tp = new_t; tp->sibling != old_t; tp = tp->sibling )
;
tp->sibling = new_t;
/* change children pointers */
tp = new_t->child;
if ( tp != NULL )
do
{
tp->parent = new_t;
tp = tp->sibling;
} while ( tp != new_t->child );
}
return ( TREEPTR_TO_VOIDPTR( new_t ) )
;
}
static void
xi_tree_dbg_internal( TREE_NODE * tn, int level )
{
char buf[150];
char *s;
TREE_NODE *tn2;
int i,
l;
if ( tn == NULL )
return;
/* print tab indent indicating level */
s = buf;
for ( l = level; l; l-- )
{
for ( i = 0; i < DBGTAB; i++ )
*s++ = ' ';
}
#ifdef TREEDEBUG
sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx, file=%s, line=%d",
( long ) ( tn ), ( long ) ( tn->parent ), ( long ) ( tn->sibling ),
( long ) ( tn->child ), tn->file, tn->line );
#else
sprintf( s, "node %08lx: par=%08lx, sib=%08lx, ch=%08lx",
( long ) tn, ( long ) ( tn->parent ), ( long ) ( tn->sibling ),
( long ) ( tn->child ) );
#endif
xi_dbg( buf );
tn2 = tn->child;
if ( tn2 != NULL )
do
{
xi_tree_dbg_internal( tn2, level + 1 );
tn2 = tn2->sibling;
} while ( tn2 != tn->child );
}
void
xi_tree_dbg( char *title )
{
char buf[100];
sprintf( buf, "TREE MEMORY DEBUG TRACE (%s)", title );
xi_dbg( buf );
xi_dbg( "=======================" );
xi_tree_dbg_internal( top, 0 );
heap_dbg( title );
xi_tree_check_sanity( title );
}
static void
xi_tree_check_sanity_internal( TREE_NODE * tn, char *title,
int *count )
{
TREE_NODE *tn2;
#ifdef TREEDEBUG
#ifdef PAD
int i;
/* check pad bytes for node */
if ( tn != &topnode )
for ( i = tn->size - PAD; i < tn->size; i++ )
if ( *( ( char * ) tn + SIZEOF_TREE_NODE + i ) != PADCHAR )
XinDialogFatal( "xi_tree_node padding corrupted: node=%08lx, file=%s, line=%d",
( long ) ( tn ), tn->file, tn->line );
#endif
#endif
/* check that all children point to this node */
tn2 = tn->child;
( *count )++;
if ( tn2 != NULL )
do
{
if ( tn2->parent != tn )
XinDialogFatal( "memory check %s: tree node %08lx has bad parent",
title, ( long ) ( tn2 ) );
xi_tree_check_sanity_internal( tn2, title, count );
tn2 = tn2->sibling;
} while ( tn2 != tn->child );
}
void
xi_tree_check_sanity( char *title )
{
int count = 0;
xi_tree_check_sanity_internal( top, title, &count );
#ifdef TREEDEBUG
if ( count != node_count )
XinDialogFatal( "tree sanity check failed: tree count=%d, allocation count=%d",
count, node_count );
#endif
}
#ifdef TREEDEBUG
void *xi_tree_malloc_stub( size_t size, void *parent );
void *
xi_tree_malloc_stub( size_t size, void *parent )
{
return ( xi_tree_malloc_body( size, parent, 0, "(unknown)" ) );
}
void *xi_tree_realloc_stub( void *p, size_t size );
void *
xi_tree_realloc_stub( void *p, size_t size )
{
return ( xi_tree_realloc_body( p, size, 0, "(unknown)" ) );
}
#else
void *
xi_tree_malloc_stub( size_t size, void *parent,
int line, char *file );
void *
xi_tree_malloc_stub( size_t size, void *parent,
int line, char *file )
{
NOREF( line );
NOREF( file );
return ( xi_tree_malloc_body( size, parent ) );
}
void *
xi_tree_realloc_stub( void *p, size_t size,
int line, char *file );
void *
xi_tree_realloc_stub( void *p, size_t size,
int line, char *file )
{
NOREF( line );
NOREF( file );
return ( xi_tree_realloc_body( p, size ) );
}
#endif
void
xi_tree_reg_error_fcn( void ( *fcn ) ( void ) )
{
error_fcn = fcn;
}