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;
 | |
| }
 |