ebabab8c26
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
507 lines
11 KiB
C
Executable File
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;
|
|
}
|