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