changeset 49:c131e9d2d965

Initial revision
author david <david>
date Wed, 16 Dec 1992 11:29:51 +0000
parents 7037bb9bca7c
children 74341ea7b209
files volume_io/Prog_utils/alloc.c volume_io/Prog_utils/alloc_check.c volume_io/Prog_utils/files.c volume_io/Prog_utils/time.c
diffstat 4 files changed, 3112 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/volume_io/Prog_utils/alloc.c
@@ -0,0 +1,221 @@
+#include  <def_mni.h>
+
+#ifdef sgi
+typedef  size_t    alloc_int;
+typedef  void      *alloc_ptr;
+#else
+typedef  unsigned  alloc_int;
+typedef  char      *alloc_ptr;
+#endif
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : alloc_memory
+@INPUT      : n_bytes
+@OUTPUT     : ptr
+@RETURNS    : Status
+@DESCRIPTION: Allocates the specified number of bytes.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  alloc_memory( ptr, n_bytes )
+    void   **ptr;
+    int    n_bytes;
+{
+    void       abort_if_allowed();
+    void       record_alloc();
+    Status     status;
+
+    status = OK;
+
+    if( n_bytes > 0 )
+    {
+        *ptr = (void *) malloc( (alloc_int) n_bytes );
+
+        if( *ptr == (void *) 0 )
+        {
+            (void) printf( "alloc_memory: out of memory, %d bytes.\n",
+                           n_bytes );
+            status = OUT_OF_MEMORY;
+            abort_if_allowed();
+        }
+    }
+    else
+        *ptr = (void *) 0;
+
+    record_alloc( n_bytes );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : realloc_memory
+@INPUT      : ptr
+            : n_bytes
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Reallocates the ptr.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  realloc_memory( ptr, n_bytes )
+    void   **ptr;
+    int    n_bytes;
+{
+    void       abort_if_allowed();
+    Status     status;
+    Status     free_memory();
+    void       record_realloc();
+
+    status = OK;
+
+    if( n_bytes > 0 )
+    {
+        *ptr = (void *) realloc( (alloc_ptr) *ptr, (alloc_int) n_bytes );
+
+        if( *ptr == (void *) 0 )
+        {
+            (void) printf( "realloc_memory: out of memory, %d bytes.\n",
+                           n_bytes );
+            status = OUT_OF_MEMORY;
+            abort_if_allowed();
+        }
+    }
+
+    record_realloc( n_bytes );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : free_memory
+@INPUT      : ptr
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Frees the pointer, and sets it to NIL.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  free_memory( ptr )
+    void   **ptr;
+{
+    void  record_free();
+
+    record_free();
+
+    if( *ptr != (void *) 0 )
+    {
+#ifdef sgi
+        free( *ptr );
+#else
+        free( (char *) *ptr );
+#endif
+        *ptr = (void *) 0;
+    }
+
+    return( OK );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : abort_if_allowed
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Checks if the user wants to abort.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  abort_if_allowed()
+{
+    char  ch;
+
+    if( !ENV_EXISTS( "NO_ABORT" ) )
+    {
+        (void) printf( "Do you wish to abort (y/n): " );
+        do
+        {
+            ch = getchar();
+        }
+        while( ch != 'y' && ch != 'n' );
+
+        while( getchar() != '\n' )
+        {
+        }
+
+        if( ch == 'y' )
+        {
+            abort();
+        }
+    }
+}
+
+#include  <stdio.h>
+
+private  FILE  *file;
+
+private  Boolean  writing_alloc_debug()
+{
+    static   Boolean   first = TRUE;
+    static   Boolean   writing = FALSE;
+    char               *filename;
+
+    if( first )
+    {
+        first = FALSE;
+        filename = getenv( "ALLOC_OUTPUT_FILE" );
+
+        if( filename != (char *) 0 )
+        {
+            file = fopen( filename, "w" );
+
+            if( file != (FILE *) 0 )
+                writing = TRUE;
+        }
+    }
+
+    return( writing );
+}
+
+private  void  record_alloc( n_bytes )
+    int   n_bytes;
+{
+    if( writing_alloc_debug() )
+    {
+        (void) fprintf( file, "ALLOC   %20d\n", n_bytes );
+        (void) fflush( file );
+    }
+}
+
+private  void  record_realloc( n_bytes )
+    int   n_bytes;
+{
+    if( writing_alloc_debug() )
+    {
+        (void) fprintf( file, "REALLOC %20d\n", n_bytes );
+        (void) fflush( file );
+    }
+}
+
+private  void  record_free()
+{
+    if( writing_alloc_debug() )
+    {
+        (void) fprintf( file, "FREE\n" );
+        (void) fflush( file );
+    }
+}
new file mode 100644
--- /dev/null
+++ b/volume_io/Prog_utils/alloc_check.c
@@ -0,0 +1,981 @@
+
+#include  <def_string.h>
+#include  <def_mni.h>
+#include  <def_files.h>
+#include  <stdlib.h>
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : alloc_check.c
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Maintains a skiplist structure to list all memory allocated,
+            : and check for errors such as freeing a pointer twice or
+            : overlapping allocations.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+#define  MAX_SKIP_LEVELS   50
+#define  SKIP_P            0.5
+
+#define  MEMORY_DIFFERENCE  1000000
+
+static    void     update_total_memory();
+static    int      get_random_level();
+static    Real     get_random_0_to_1();
+static    void     output_entry();
+static    Real     current_seconds();
+static    void     get_date();
+void               abort_if_allowed();
+
+typedef  struct skip_struct
+{
+    void                    *ptr;
+    int                     n_bytes;
+    char                    *source_file;
+    int                     line_number;
+    Real                    time_of_alloc;
+    struct  skip_struct     *forward[1];
+} skip_struct;
+
+typedef  struct
+{
+    int            next_memory_threshold;
+    int            total_memory_allocated;
+    skip_struct    *header;
+    int            level;
+} alloc_struct;
+
+typedef  struct
+{
+    skip_struct   *update[MAX_SKIP_LEVELS];
+} update_struct;
+
+#ifdef sgi
+typedef  size_t    alloc_int;
+typedef  void      *alloc_ptr;
+#else
+typedef  unsigned  alloc_int;
+typedef  char      *alloc_ptr;
+#endif
+
+#define  ALLOC_SKIP_STRUCT( ptr, n_level )                                    \
+     (ptr) = (skip_struct *) malloc( (alloc_int)                              \
+                 (sizeof(skip_struct)+((n_level)-1) * sizeof(skip_struct *)) );
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : initialize_alloc_list
+@INPUT      : alloc_list
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Initializes the allocation list to empty.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private   void  initialize_alloc_list( alloc_list )
+    alloc_struct  *alloc_list;
+{
+    int   i;
+
+    alloc_list->next_memory_threshold = MEMORY_DIFFERENCE;
+    alloc_list->total_memory_allocated = 0;
+
+    ALLOC_SKIP_STRUCT( alloc_list->header, MAX_SKIP_LEVELS );
+    alloc_list->level = 1;
+
+    for_less( i, 0, MAX_SKIP_LEVELS )
+        alloc_list->header->forward[i] = (skip_struct *) 0;
+}
+
+private  void  check_initialized_alloc_list( alloc_list )
+    alloc_struct  *alloc_list;
+{
+    static   Boolean  first = TRUE;
+
+    if( first )
+    {
+        first = FALSE;
+        initialize_alloc_list( alloc_list );
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : find_pointer_position
+@INPUT      : alloc_list
+            : ptr
+@OUTPUT     : update
+@RETURNS    : TRUE if found
+@DESCRIPTION: Searches the alloc_list for the given ptr, and sets the update
+            : struct so that it can provide an insert.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Boolean  find_pointer_position( alloc_list, ptr, update )
+    alloc_struct    *alloc_list;
+    void            *ptr;
+    update_struct   *update;
+{
+    int           i;
+    skip_struct   *x;
+    Boolean       found;
+
+    x = alloc_list->header;
+
+    for( i = alloc_list->level-1;  i >= 0;  --i )
+    {
+        while( x->forward[i] != (skip_struct *) 0 && x->forward[i]->ptr < ptr )
+        {
+            x = x->forward[i];
+        }
+        update->update[i] = x;
+    }
+
+    x = update->update[0]->forward[0];
+
+    found = (x != (skip_struct *) 0) && (x->ptr == ptr);
+
+    return( found );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : insert_ptr_in_alloc_list
+@INPUT      : alloc_list
+            : update           - the set of pointers indicating where to insert
+            : ptr              }
+            : n_bytes          }}
+            : source_file      }}} these are recorded in the list
+            : line_number      }}
+            : time_of_alloc    }
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Records the allocated pointer in the allocation list.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private   void  insert_ptr_in_alloc_list( alloc_list, update, ptr, n_bytes,
+                                          source_file, line_number,
+                                          time_of_alloc )
+    alloc_struct   *alloc_list;
+    update_struct  *update;
+    void           *ptr;
+    int            n_bytes;
+    char           source_file[];
+    int            line_number;
+    Real           time_of_alloc;
+{
+    int           i, new_level;
+    skip_struct   *x;
+
+    new_level = get_random_level();
+
+    if( new_level > alloc_list->level )
+    {
+        for( i = alloc_list->level;  i < new_level;  ++i )
+            update->update[i] = alloc_list->header;
+
+        alloc_list->level = new_level;
+    }
+
+    ALLOC_SKIP_STRUCT( x, new_level );
+
+    x->ptr = ptr;
+    x->n_bytes = n_bytes;
+    x->source_file = source_file;
+    x->line_number = line_number;
+    x->time_of_alloc = time_of_alloc;
+    update_total_memory( alloc_list, n_bytes );
+
+    for( i = 0;  i < new_level;  ++i )
+    {
+        x->forward[i] = update->update[i]->forward[i];
+        update->update[i]->forward[i] = x;
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : check_overlap
+@INPUT      : update
+            : ptr
+            : n_bytes
+@OUTPUT     : entry
+@RETURNS    : TRUE if an overlap
+@DESCRIPTION: Checks the new ptr to see if it overlaps with the previous and
+            : following memory allocations in the list, and returns the result.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Boolean  check_overlap( update, ptr, n_bytes, entry )
+    update_struct   *update;
+    void            *ptr;
+    int             n_bytes;
+    skip_struct     **entry;
+{
+    Boolean      overlap;
+
+    overlap = FALSE;
+
+    *entry = update->update[0];
+
+    if( *entry != (skip_struct *) 0 )
+    {
+        if( (void *) ((char *) (*entry)->ptr + (*entry)->n_bytes) > ptr )
+             overlap = TRUE;
+        else
+        {
+            (*entry) = (*entry)->forward[0];
+            if( *entry != (skip_struct *) 0 &&
+                (void *) ((char*)ptr + n_bytes) > (*entry)->ptr )
+                overlap = TRUE;
+        }
+    }
+
+    return( overlap );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : remove_ptr_from_alloc_list
+@INPUT      : alloc_list
+            : ptr
+@OUTPUT     : source_file
+            : line_number
+            : time_of_alloc
+@RETURNS    : TRUE if it existed
+@DESCRIPTION: Finds and deletes the entry in the skip list associated with
+            : ptr, and returns the information associated with the entry
+            : (source_file, line_number, time_of_alloc).
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private   Boolean  remove_ptr_from_alloc_list( alloc_list, ptr, source_file,
+                                           line_number, time_of_alloc )
+    alloc_struct   *alloc_list;
+    void           *ptr;
+    char           *source_file[];
+    int            *line_number;
+    Real           *time_of_alloc;
+{
+    int           i;
+    Boolean       found;
+    skip_struct   *x;
+    update_struct update;
+
+    found = find_pointer_position( alloc_list, ptr, &update );
+
+    if( found )
+    {
+        x = update.update[0]->forward[0];
+
+        *source_file = x->source_file;
+        *line_number = x->line_number;
+        *time_of_alloc = x->time_of_alloc;
+
+        update_total_memory( alloc_list, -x->n_bytes );
+
+        for( i = 0;  i < alloc_list->level;  ++i )
+        {
+            if( update.update[i]->forward[i] != x )
+                break;
+            update.update[i]->forward[i] = x->forward[i];
+        }
+
+        free( (alloc_ptr) x );
+
+        while( alloc_list->level > 1 &&
+               alloc_list->header->forward[alloc_list->level-1] ==
+                    (skip_struct *) 0 )
+        {
+            --alloc_list->level;
+        }
+    }
+
+    return( found );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_random_level
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : a random level between 1 and MAX_LEVELS
+@DESCRIPTION: Determines a random level with exponential probability of higher
+            : levels.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  int  get_random_level()
+{
+    int    level;
+    Real   get_random_0_to_1();
+
+    level = 1;
+
+    while( get_random_0_to_1() < SKIP_P && level < MAX_SKIP_LEVELS )
+        ++level;
+
+    return( level );
+}
+
+#ifdef  NOT_NEEDED
+private   void  delete_alloc_list( alloc_list )
+    alloc_struct  *alloc_list;
+
+{
+    skip_struct   *ptr, *deleting;
+
+    ptr = alloc_list->header;
+
+    while( ptr != (skip_struct *) 0 )
+    {
+        deleting = ptr;
+        ptr = ptr->forward[0];
+        free( (void *) deleting );
+    }
+}
+#endif
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_alloc_list
+@INPUT      : file
+            : alloc_list
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Outputs the list of allocated memory to the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  output_alloc_list( file, alloc_list )
+    FILE          *file;
+    alloc_struct  *alloc_list;
+{
+    skip_struct  *ptr;
+
+    ptr = alloc_list->header->forward[0];
+
+    while( ptr != (skip_struct *) 0 )
+    {
+        output_entry( file, ptr );
+        ptr = ptr->forward[0];
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : update_total_memory
+@INPUT      : alloc_list
+            : n_bytes
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Adds n_bytes to the size of memory recorded.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  update_total_memory( alloc_list, n_bytes )
+    alloc_struct  *alloc_list;
+    int           n_bytes;
+{
+    alloc_list->total_memory_allocated += n_bytes;
+
+    if( size_display_enabled() &&
+        alloc_list->total_memory_allocated >
+        alloc_list->next_memory_threshold )
+    {
+        alloc_list->next_memory_threshold = MEMORY_DIFFERENCE *
+                (alloc_list->total_memory_allocated / MEMORY_DIFFERENCE + 1);
+        (void) printf( "Memory allocated =%5.1f Megabytes\n",
+                       (Real) alloc_list->total_memory_allocated / 1000000.0 );
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : print_source_location
+@INPUT      : source_file
+            : line_number
+            : time_of_alloc
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Prints the information about a particular allocation.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  print_source_location( source_file, line_number,
+                                      time_of_alloc )
+    char   source_file[];
+    int    line_number;
+    Real   time_of_alloc;
+{
+    (void) printf( "%s:%d\t%g seconds", source_file, line_number,
+                   time_of_alloc );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_entry
+@INPUT      : file
+            : entry
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Outputs the information about an allocation entry to the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  output_entry( file, entry )
+    FILE          *file;
+    skip_struct   *entry;
+{
+    (void) fprintf( file, "%s:%d\t%g seconds\n",
+                    entry->source_file,
+                    entry->line_number,
+                    entry->time_of_alloc );
+}
+
+/*  
+--------------------------------------------------------------------------
+    Routines that are to be called from outside this file
+--------------------------------------------------------------------------
+*/
+
+private   alloc_struct   alloc_list;
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_total_memory_alloced
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : int  - the number of bytes allocated
+@DESCRIPTION: Returns the total amount of memory allocated by the program,
+            : not counting that used by the skip list.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  int  get_total_memory_alloced()
+{
+    return( alloc_list.total_memory_allocated );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : alloc_checking_enabled
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : TRUE if alloc checking is turned on
+@DESCRIPTION: Checks an environment variable to see if alloc checking is
+            : not disabled.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Boolean  alloc_checking_enabled()
+{
+#ifdef NO_DEBUG_ALLOC
+    return( FALSE );
+#else
+    static  Boolean  first = TRUE;
+    static  Boolean  enabled;
+
+    if( first )
+    {
+        enabled = !ENV_EXISTS( "NO_DEBUG_ALLOC" );
+        first = FALSE;
+    }
+
+    return( enabled );
+#endif
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : size_display_enabled
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : TRUE if size displaying is turned on
+@DESCRIPTION: Checks an environment variable to see if memory size display
+            : is disabled.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Boolean  size_display_enabled()
+{
+#ifdef NO_DEBUG_ALLOC
+    return( FALSE );
+#else
+    static  Boolean  first = TRUE;
+    static  Boolean  enabled;
+
+    if( first )
+    {
+        enabled = ENV_EXISTS( "ALLOC_SIZE" );
+        first = FALSE;
+    }
+
+    return( enabled );
+#endif
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : record_ptr
+@INPUT      : ptr
+            : n_bytes
+            : source_file
+            : line_number
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Records the information about a single allocation in the list.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  record_ptr( ptr, n_bytes, source_file, line_number )
+    void   *ptr;
+    int    n_bytes;
+    char   source_file[];
+    int    line_number;
+{
+    Real           current_time;
+    update_struct  update_ptrs;
+    void           check_initialized_alloc_list();
+    skip_struct    *entry;
+
+    if( alloc_checking_enabled() )
+    {
+        current_time = current_seconds();
+
+        check_initialized_alloc_list( &alloc_list );
+
+        if( n_bytes <= 0 )
+        {
+            print_source_location( source_file, line_number, current_time );
+            (void) printf( ": Alloc called with zero size.\n" );
+            abort_if_allowed();
+        }
+        else if( ptr == (void *) 0 )
+        {
+            print_source_location( source_file, line_number, current_time );
+            (void) printf( ": Alloc returned a NIL pointer.\n" );
+            abort_if_allowed();
+        }
+        else
+        {
+            (void) find_pointer_position( &alloc_list, ptr, &update_ptrs );
+
+            if( check_overlap( &update_ptrs, ptr, n_bytes, &entry ) )
+            {
+                print_source_location( source_file, line_number, current_time );
+                (void) printf(
+                 ": Alloc returned a pointer overlapping an existing block:\n"
+                 );
+                print_source_location( entry->source_file, entry->line_number,
+                                       entry->time_of_alloc );
+                (void) printf( "\n" );
+                abort_if_allowed();
+            }
+            else
+                insert_ptr_in_alloc_list( &alloc_list,
+                           &update_ptrs, ptr, n_bytes,
+                           source_file, line_number, current_time );
+        }
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : change_ptr
+@INPUT      : old_ptr
+            : new_ptr
+            : n_bytes
+            : source_file
+            : line_number
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Changes the information (mainly the n_bytes) associated with a
+            : given pointer.  This function is called from the def_alloc
+            : macros after a realloc().
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  change_ptr( old_ptr, new_ptr, n_bytes, source_file, line_number )
+    void   *old_ptr;
+    void   *new_ptr;
+    int    n_bytes;
+    char   source_file[];
+    int    line_number;
+{
+    char           *orig_source;
+    int            orig_line;
+    Real           time_of_alloc;
+    skip_struct    *entry;
+    update_struct  update_ptrs;
+
+    if( alloc_checking_enabled() )
+    {
+        check_initialized_alloc_list( &alloc_list );
+
+        if( n_bytes <= 0 )
+        {
+            print_source_location( source_file, line_number,
+                                   current_seconds() );
+            (void) printf( ": Realloc called with zero size.\n" );
+            abort_if_allowed();
+        }
+        else if( !remove_ptr_from_alloc_list( &alloc_list, old_ptr,
+                      &orig_source, &orig_line, &time_of_alloc ) )
+        {
+            print_source_location( source_file, line_number,
+                                   current_seconds() );
+            (void) printf(
+                     ": Tried to realloc a pointer not already alloced.\n");
+            abort_if_allowed();
+        }
+        else
+        {
+            (void) find_pointer_position( &alloc_list, new_ptr, &update_ptrs );
+
+            if( check_overlap( &update_ptrs, new_ptr, n_bytes, &entry ) )
+            {
+                print_source_location( source_file, line_number,
+                                       current_seconds());
+                (void) printf(
+               ": Realloc returned a pointer overlapping an existing block:\n");
+                print_source_location( entry->source_file, entry->line_number,
+                                       entry->time_of_alloc );
+                (void) printf( "\n" );
+                abort_if_allowed();
+            }
+            else
+                insert_ptr_in_alloc_list( &alloc_list,
+                       &update_ptrs, new_ptr, n_bytes,
+                       orig_source, orig_line, time_of_alloc );
+        }
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : unrecord_ptr
+@INPUT      : ptr
+            : source_file
+            : line_number
+@OUTPUT     : 
+@RETURNS    : TRUE if ptr was in list
+@DESCRIPTION: Removes the entry for the given ptr from the list.  Called by
+            : the macros during a FREE.  Returns TRUE if the pointer was
+            : in the list.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Boolean  unrecord_ptr( ptr, source_file, line_number )
+    void   *ptr;
+    char   source_file[];
+    int    line_number;
+{
+    Boolean  was_previously_alloced;
+    char     *orig_source;
+    int      orig_line;
+    Real     time_of_alloc;
+
+    was_previously_alloced = TRUE;
+
+    if( alloc_checking_enabled() )
+    {
+        check_initialized_alloc_list( &alloc_list );
+
+        if( ptr == (void *) 0 )
+        {
+            print_source_location( source_file, line_number,
+                                   current_seconds() );
+            (void) printf( ": Tried to free a NIL pointer.\n" );
+            abort_if_allowed();
+            was_previously_alloced = FALSE;
+        }
+        else if( !remove_ptr_from_alloc_list( &alloc_list, ptr, &orig_source,
+                                              &orig_line, &time_of_alloc ) )
+        {
+            print_source_location( source_file, line_number,
+                                   current_seconds() );
+            (void) printf( ": Tried to free a pointer not alloced.\n" );
+            abort_if_allowed();
+            was_previously_alloced = FALSE;
+        }
+    }
+
+    return( was_previously_alloced );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_alloc_to_file
+@INPUT      : filename
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Outputs a list of all memory allocated to the given file.  Usually
+            : done at the end of the program to see if there is any memory that
+            : was orphaned.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  output_alloc_to_file( filename )
+    char   filename[];
+{
+    FILE     *file;
+    void     output_alloc_list();
+    String   date_str;
+
+    if( alloc_checking_enabled() )
+    {
+        check_initialized_alloc_list( &alloc_list );
+
+        if( filename != (char *) 0 && filename[0] != (char) 0 )
+            file = fopen( filename, "w" );
+        else
+            file = stdout;
+
+        if( file != (FILE *) 0 )
+        {
+            get_date( date_str );
+
+            (void) fprintf( file, "Alloc table at %s\n", date_str );
+
+            output_alloc_list( file, &alloc_list );
+
+            if( file != stdout )
+                (void) fclose( file );
+        }
+    }
+}
+
+#include  <sys/time.h>
+#include  <def_string.h>
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_date
+@INPUT      : 
+@OUTPUT     : date_str
+@RETURNS    : 
+@DESCRIPTION: Fills in the date into the string.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  get_date( date_str )
+    char  date_str[];
+{
+    time_t           clock_time;
+    struct  tm       *time_tm;
+    char             *str;
+#ifndef sgi
+    time_t time();
+#endif
+
+    (void) time( &clock_time );
+
+    time_tm = localtime( &clock_time );
+
+    str = asctime( time_tm );
+
+    (void) strcpy( date_str, str );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : current_seconds
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : Real
+@DESCRIPTION: Returns the number of seconds since the first call to this.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Real  current_seconds()
+{
+    static  Boolean          first_call = TRUE;
+    static  struct  timeval  first;
+    struct  timeval          current;
+    Real                     secs;
+
+    if( first_call )
+    {
+        first_call = FALSE;
+        (void) gettimeofday( &first, (struct timezone *) 0 );
+        secs = 0.0;
+    }
+    else
+    {
+        (void) gettimeofday( &current, (struct timezone *) 0 );
+        secs = (double) current.tv_sec - (double) first.tv_sec +
+               1.0e-6 * (double) (current.tv_usec - first.tv_usec);
+    }
+
+    return( secs );
+}
+
+#include  <def_math.h>
+
+#define  MAX_RAND  2147483648.0
+
+private  Boolean  initialized = FALSE;
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : set_random_seed
+@INPUT      : seed
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Initializes the random number generation.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  set_random_seed( seed )
+    int   seed;
+{
+#ifdef sgi
+    (void) srandom( (unsigned int) seed );
+#else
+    int  srandom();
+    (void) srandom( seed );
+#endif
+
+    initialized = TRUE;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : check_initialized
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Checks if the random number generator initialized.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  void  check_initialized()
+{
+    struct   timeval   t;
+    int                seed;
+
+    if( !initialized )
+    {
+        (void) gettimeofday( &t, (struct timezone *) 0 );
+
+        seed = (int) t.tv_usec;
+
+        set_random_seed( seed );
+    }
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_random
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : int
+@DESCRIPTION: Gets a random integer.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  int  get_random()
+{
+    check_initialized();
+
+#ifdef sgi
+    return( random() );
+#else
+    {
+        long   random();
+
+        return( (int) random() );
+    }
+#endif
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_random_0_to_1
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : Real
+@DESCRIPTION: Returns a random number between 0 and 1.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Real  get_random_0_to_1()
+{
+    return( (Real) get_random() / MAX_RAND );
+}
new file mode 100644
--- /dev/null
+++ b/volume_io/Prog_utils/files.c
@@ -0,0 +1,1722 @@
+
+#include  <def_mni.h>
+#include  <def_files.h>
+#include  <def_alloc.h>
+#include  <def_string.h>
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : file_exists
+@INPUT      : filename
+@OUTPUT     : 
+@RETURNS    : TRUE or FALSE if file exists
+@DESCRIPTION: Checks if the file of the given name exists
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Boolean  file_exists( filename )
+    char        filename[];
+{
+    Boolean  exists;
+    FILE     *file;
+
+    file = fopen( filename, "r" );
+
+    if( file != (FILE *) 0 )
+    {
+        (void) fclose( file );
+        exists = TRUE;
+    }
+    else
+        exists = FALSE;
+
+    return( exists );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : remove_file
+@INPUT      : filename
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Deletes the given file.
+@METHOD     : Makes a system call to perform a UNIX "rm"
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  remove_file( filename )
+    char  filename[];
+{
+    String  command;
+
+    (void) sprintf( command, "rm -f %s", filename );
+
+    (void) system( command );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : open_file
+@INPUT      : filename
+            : io_type        READ_FILE or WRITE_FILE
+            : file_format    ASCII_FORMAT or BINARY_FORMAT
+@OUTPUT     : file
+@RETURNS    : 
+@DESCRIPTION: Opens the given filename for ascii or binary input or output.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  open_file( filename, io_type, file_format, file )
+    char               filename[];
+    IO_types           io_type;
+    File_formats       file_format;
+    FILE               **file;
+{
+    Status   status;
+    String   access_str;
+
+    switch( io_type )
+    {
+    case APPEND_FILE:   (void) strcpy( access_str, "a" );  break;
+
+    case WRITE_FILE:    (void) strcpy( access_str, "w" );  break;
+
+    case READ_FILE:
+    default:            (void) strcpy( access_str, "r" );  break;
+    }
+
+    if( file_format == BINARY_FORMAT )
+        (void) strcat( access_str, "b" );
+
+    *file = fopen( filename, access_str );
+
+    if( *file != (FILE *) 0 )
+    {
+        status = OK;
+    }
+    else
+    {
+        PRINT_ERROR( "Could not open file \"" );
+        PRINT_ERROR( filename );
+        PRINT_ERROR( "\".\n" );
+        *file = (FILE *) 0;
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : open_file_with_default_suffix
+@INPUT      : filename
+            : default_suffix  - e.g. ".obj"
+            : io_type        READ_FILE or WRITE_FILE
+            : file_format    ASCII_FORMAT or BINARY_FORMAT
+@OUTPUT     : file
+@RETURNS    : 
+@DESCRIPTION: Opens the given filename for ascii or binary input or output.
+            : On output, if the file has no suffix, it adds the default suffix.
+            : On input, if the file does not exist as given, then it tries to
+            : find the file with the default_suffix.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  open_file_with_default_suffix( filename, default_suffix,
+                                               io_type, file_format, file )
+    char               filename[];
+    char               default_suffix[];
+    IO_types           io_type;
+    File_formats       file_format;
+    FILE               **file;
+{
+    Boolean  suffix_added;
+    String   used_filename;
+
+    if( io_type == READ_FILE )
+    {
+        suffix_added = FALSE;
+
+        if( !file_exists(filename) && has_no_extension( filename ) )
+        {
+            (void) sprintf( used_filename, "%s.%s", filename, default_suffix );
+            if( file_exists( used_filename ) )
+                suffix_added = TRUE;
+        }
+
+        if( !suffix_added )
+            (void) strcpy( used_filename, filename );
+    }
+    else if( has_no_extension( filename ) )
+        (void) sprintf( used_filename, "%s.%s", filename, default_suffix );
+    else
+        (void) strcpy( used_filename, filename );
+
+    return( open_file( used_filename, io_type, file_format, file ) );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : has_no_extension
+@INPUT      : filename
+@OUTPUT     : 
+@RETURNS    : TRUE if there is no . extension
+@DESCRIPTION: Checks if there is an extension on the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+private  Boolean  has_no_extension( filename )
+    char   filename[];
+{
+    char  *str;
+
+    /* skip possible .. at beginning */
+
+    str = filename;
+    while( *str == '.' ) ++str;
+
+    return( strchr( str, '.' ) == (char *) 0 );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : set_file_position
+@INPUT      : file
+            : byte_position
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Sets the file position to the given offset from the start.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  set_file_position( file, byte_position )
+    FILE     *file;
+    long     byte_position;
+{
+    Status   status;
+
+    if( fseek( file, byte_position, 0 ) == 0 )
+    {
+        status = OK;
+    }
+    else
+    {
+        PRINT_ERROR( "Error setting the file position.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : close_file
+@INPUT      : file
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Closes the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  close_file( file )
+    FILE     *file;     
+{
+    (void) fclose( file );
+
+    return( OK );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : extract_directory
+@INPUT      : filename
+@OUTPUT     : directory
+@RETURNS    : 
+@DESCRIPTION: Extracts the directory from the filename by copying the string
+            : from the beginning up to the last '/'.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  extract_directory( filename, directory )
+    char    filename[];
+    char    directory[];
+{
+    int   slash_index;
+
+    slash_index = strlen(filename) - 1;
+
+    while( slash_index > 0 && filename[slash_index] != '/' )
+    {
+        --slash_index;
+    }
+
+    if( slash_index < 0 )
+    {
+        slash_index = 0;
+    }
+
+    (void) strncpy( directory, filename, slash_index );
+
+    directory[slash_index] = (char) 0;
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_absolute_filename
+@INPUT      : filename
+            : directory
+@OUTPUT     : abs_filename
+@RETURNS    : 
+@DESCRIPTION: Given a filename and a default directory, determines the correct
+            : filename by checking if the filename is a relative or absolute
+            : pathname, and prepending the directory, if the former.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  get_absolute_filename( filename, directory, abs_filename )
+    char    filename[];
+    char    directory[];
+    char    abs_filename[];
+{
+    String  save_filename;
+
+    /* in case abs_filename and filename are same variable */
+
+    (void) strcpy( save_filename, filename );
+
+    /* if the directory is non-null and the filename is not already
+       absolute (begins with '/'), then prefix the directory to the filename */
+
+    if( directory != (char *) 0 && strlen( directory ) > 0 &&
+        filename[0] != '/' )
+    {
+        (void) strcpy( abs_filename, directory );
+        (void) strcat( abs_filename, "/" );
+    }
+    else
+    {
+        abs_filename[0] = (char) 0;
+    }
+
+    (void) strcat( abs_filename, save_filename );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : strip_off_directories
+@INPUT      : filename
+@OUTPUT     : no_dirs
+@RETURNS    : 
+@DESCRIPTION: Strips off the directories from filename putting the result in
+            : no_dirs.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  strip_off_directories( filename, no_dirs )
+    char    filename[];
+    char    no_dirs[];
+{
+    int    i;
+
+    i = strlen( filename ) - 1;
+
+    while( i >= 0 && filename[i] != '/' )
+    {
+        --i;
+    }
+
+    (void) strcpy( no_dirs, &filename[i+1] );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : flush_file
+@INPUT      : file
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Flushes the output buffer for the given file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  flush_file( file )
+    FILE     *file;
+{
+    Status   status;
+
+    if( fflush( file ) == 0 )
+    {
+        status = OK;
+    }
+    else
+    {
+        PRINT_ERROR( "Error flushing file.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_character
+@INPUT      : file
+@OUTPUT     : ch
+@RETURNS    : Status
+@DESCRIPTION: Inputs one character from the file, returning ERROR if eof.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_character( file, ch )
+    FILE  *file;
+    char   *ch;
+{
+    Status   status;
+    int      c;
+
+    c = fgetc( file );
+
+    if( c == EOF )
+    {
+        status = ERROR;
+    }
+    else
+    {
+        *ch = c;
+        status = OK;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : unget_character
+@INPUT      : file
+@OUTPUT     : ch
+@RETURNS    : Status
+@DESCRIPTION: Ungets one character back to the file, returning status.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  unget_character( file, ch )
+    FILE  *file;
+    char  ch;
+{
+    Status   status;
+    int      c;
+
+    c = ungetc( ch, file );
+
+    if( c == EOF )
+        status = ERROR;
+    else
+        status = OK;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_nonwhite_character
+@INPUT      : file
+@OUTPUT     : ch
+@RETURNS    : Status
+@DESCRIPTION: Inputs the next nonwhite (tab, space, newline) character.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_nonwhite_character( file, ch )
+    FILE   *file;
+    char   *ch;
+{
+    Status   status;
+
+    do
+    {
+        status = input_character( file, ch );
+    }
+    while( status == OK && (*ch == ' ' || *ch == '\t' || *ch == '\n') );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_character
+@INPUT      : file
+            : ch
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs the character to the file, returning the status.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_character( file, ch )
+    FILE   *file;
+    char   ch;
+{
+    Status   status;
+
+    if( fputc( ch, file ) != ch )
+    {
+        status = ERROR;
+    }
+    else
+    {
+        status = OK;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : skip_input_until
+@INPUT      : file
+            : search_char
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Skips characters in the file, up to and including the first match
+            : of the search_char;
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status   skip_input_until( file, search_char )
+    FILE   *file;
+    char   search_char;
+{
+    Status   status;
+    char     ch;
+
+    status = OK;
+
+    do
+    {
+        status = input_character( file, &ch );
+    }
+    while( status == OK && ch != search_char );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_string
+@INPUT      : file
+            : str
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs the string to the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_string( file, str )
+    FILE  *file;
+    char  str[];
+{
+    Status   status;
+
+    if( fprintf( file, "%s", str ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting string.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_string
+@INPUT      : file
+            : str
+            : string_length         - size of string storage
+            : termination_char
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Inputs a string from the file.  First it skips white space, then
+            : inputs all characters until the termination_char is found.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_string( file, str, string_length, termination_char )
+    FILE  *file;
+    char  str[];
+    int   string_length;
+    char  termination_char;
+{
+    int     i;
+    char    ch;
+    Status  status;
+
+    status = input_nonwhite_character( file, &ch );
+
+    i = 0;
+
+    while( status == OK && ch != termination_char && ch != '\n' )
+    {
+        str[i] = ch;
+        ++i;
+
+        if( i >= string_length - 1 )
+        {
+            PRINT_ERROR( "Input string too long.\n" );
+            status = ERROR;
+        }
+        else
+        {
+            status = input_character( file, &ch );
+        }
+    }
+
+    if( ch == '\n' )
+        (void) ungetc( ch, file );
+
+    str[i] = (char) 0;
+    
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_quoted_string
+@INPUT      : file
+            : str
+            : str_length    - size of string storage
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Skips to the next nonwhitespace character, checks if it is a
+            : quotation mark, then reads characters into the string until the
+            : next quotation mark.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_quoted_string( file, str, str_length )
+    FILE            *file;
+    char            str[];
+    int             str_length;
+{
+    int      i;
+    char     ch;
+    Status   status;
+    Status   input_nonwhite_character();
+    Status   input_character();
+
+    status = input_nonwhite_character( file, &ch );
+
+    if( status == OK && ch != '"' )
+        status = ERROR;
+
+    if( status == OK )
+        status = input_character( file, &ch );
+
+    i = 0;
+
+    while( status == OK && ch != '"' && i < str_length-1 )
+    {
+        str[i] = ch;
+        ++i;
+        status = input_character( file, &ch );
+    }
+
+    if( status == OK && ch == '\n' )
+        (void) ungetc( ch, file );
+
+    str[i] = (char) 0;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_quoted_string
+@INPUT      : file
+            : str
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs the given string, with quotation marks around it.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_quoted_string( file, str )
+    FILE            *file;
+    char            str[];
+{
+    Status   status;
+
+    if( fprintf( file, " \"%s\"", str ) > 0 )
+        status = OK;
+    else
+        status = ERROR;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_binary_data
+@INPUT      : file
+            : element_size       size of each element
+            : n                  number of elements
+@OUTPUT     : data               array of elements to input
+@RETURNS    : Status
+@DESCRIPTION: Inputs the data in binary format.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_binary_data( file, data, element_size, n )
+    FILE            *file;
+    VOID            *data;
+    size_t          element_size;
+    int             n;
+{
+    Status   status;
+    int      n_done;
+
+    status = OK;
+
+    n_done = fread( data, element_size, n, file );
+    if( n_done != n )
+    {
+#ifdef ERROR_MESSAGES
+        PRINT_ERROR( "Error inputting binary data.\n" );
+        PRINT( "     (%d out of %d items of size %d).\n", n_done, n,
+               (int) element_size );
+#endif
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_binary_data
+@INPUT      : file
+            : data               array of elements to output
+            : element_size       size of each element
+            : n                  number of elements
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs the data in binary format.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_binary_data( file, data, element_size, n )
+    FILE            *file;
+    VOID            *data;
+    size_t          element_size;
+    int             n;
+{
+    Status   status;
+    int      n_done;
+
+    status = OK;
+
+    n_done = fwrite( data, element_size, n, file );
+    if( n_done != n )
+    {
+        PRINT_ERROR( "Error outputting binary data.\n" );
+        PRINT( "     (%d out of %d items of size %d).\n", n_done, n,
+               (int) element_size );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_newline
+@INPUT      : file
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Skips to after the next newline in the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_newline( file )
+    FILE            *file;
+{
+    Status   status;
+    Status   skip_input_until();
+
+    status = skip_input_until( file, '\n' );
+
+    if( status == END_OF_FILE )
+    {
+        PRINT_ERROR( "Error inputting newline.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_newline
+@INPUT      : file
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs a newline to the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_newline( file )
+    FILE            *file;
+{
+    Status   status;
+
+    if( fprintf( file, "\n" ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting newline.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_line
+@INPUT      : line         - string to input to
+            : str_length   - storage allocated to the string
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Inputs all characters upto the next newline.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_line( file, line, str_length )
+    FILE    *file;
+    char    line[];
+    int     str_length;
+{
+    Status   status;
+    int      i;
+    char     ch;
+
+    i = 0;
+
+    status = input_character( file, &ch );
+
+    while( status == OK && ch != '\n' && i < str_length-1 )
+    {
+        line[i] = ch;
+        ++i;
+
+        status = input_character( file, &ch );
+    }
+
+    line[i] = (char) 0;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_boolean
+@INPUT      : file
+@OUTPUT     : b
+@RETURNS    : Status
+@DESCRIPTION: Inputs a Boolean value from a file, by looking for an 'f' or 't'.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_boolean( file, b )
+    FILE            *file;
+    Boolean         *b;
+{
+    Status   status;
+    char     ch;
+    Status   input_nonwhite_character();
+
+    status = input_nonwhite_character( file, &ch );
+
+    if( status == OK )
+    {
+        if( ch == 'f' || ch == 'F' )
+            *b = FALSE;
+        else if( ch == 't' || ch == 'T' )
+            *b = TRUE;
+        else
+            status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_boolean
+@INPUT      : file
+            : b
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Outputs a T or F to the file.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_boolean( file, b )
+    FILE            *file;
+    Boolean         b;
+{
+    Status   status;
+    char     *str;
+
+    status = OK;
+
+    if( b )
+        str = "T";
+    else
+        str = "F";
+
+    if( fprintf( file, " %s", str ) > 0 )
+    {
+        PRINT_ERROR( "Error outputting Boolean.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_short
+@INPUT      : file
+@OUTPUT     : s
+@RETURNS    : Status
+@DESCRIPTION: Inputs an ascii short.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_short( file, s )
+    FILE            *file;
+    short           *s;
+{
+    Status   status;
+
+    if( fscanf( file, "%hd", s ) == 1 )
+        status = OK;
+    else
+        status = ERROR;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_short
+@INPUT      : file
+            : s
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Outputs an ascii short.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_short( file, s )
+    FILE            *file;
+    short           s;
+{
+    Status   status;
+
+    if( fprintf( file, " %d", s ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting short.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_int
+@INPUT      : file
+@OUTPUT     : i
+@RETURNS    : Status
+@DESCRIPTION: Inputs an ascii integer.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_int( file, i )
+    FILE            *file;
+    int             *i;
+{
+    Status   status;
+
+    if( fscanf( file, "%d", i ) == 1 )
+        status = OK;
+    else
+        status = ERROR;
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_int
+@INPUT      : file
+            : i
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Outputs an ascii integer.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_int( file, i )
+    FILE            *file;
+    int             i;
+{
+    Status   status;
+
+    if( fprintf( file, " %d", i ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting int.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_real
+@INPUT      : file
+@OUTPUT     : r
+@RETURNS    : Status
+@DESCRIPTION: Inputs an ascii real value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_real( file, r )
+    FILE            *file;
+    Real            *r;
+{
+    Status   status;
+
+    if( fscanf( file, "%f", r ) == 1 )
+        status = OK;
+    else
+    {
+#ifdef ERROR_MESSAGES
+        PRINT_ERROR( "Error inputting float.\n" );
+#endif
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_real
+@INPUT      : file
+            : i
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Outputs an ascii real value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_real( file, r )
+    FILE            *file;
+    Real            r;
+{
+    Status   status;
+
+    if( fprintf( file, " %g", r ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting float.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : input_double
+@INPUT      : file
+@OUTPUT     : d
+@RETURNS    : Status
+@DESCRIPTION: Inputs an ascii double.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  input_double( file, d )
+    FILE            *file;
+    double          *d;
+{
+    Status   status;
+
+    if( fscanf( file, "%lf", d ) == 1 )
+        status = OK;
+    else
+    {
+#ifdef ERROR_MESSAGES
+        PRINT_ERROR( "Error inputting double.\n" );
+#endif
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : output_double
+@INPUT      : file
+            : d
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Outputs an ascii double value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  output_double( file, d )
+    FILE            *file;
+    double          d;
+{
+    Status   status;
+
+    if( fprintf( file, " %g", d ) > 0 )
+        status = OK;
+    else
+    {
+        PRINT_ERROR( "Error outputting double.\n" );
+        status = ERROR;
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_binary_data
+@INPUT      : file
+            : io_flag
+            : data
+            : element_size
+            : n
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs binary data, depending on io_flag.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_binary_data( file, io_flag, data, element_size, n )
+    FILE            *file;
+    IO_types        io_flag;
+    VOID            *data;
+    size_t          element_size;
+    int             n;
+{
+    Status   status;
+
+    if( io_flag == READ_FILE )
+        status = input_binary_data( file, data, element_size, n );
+    else
+        status = output_binary_data( file, data, element_size, n );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_newline
+@INPUT      : file
+            : io_flag
+            : data
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary newline char, as appropriate.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_newline( file, io_flag, format )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = OK;
+        else
+            status = output_newline( file );
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_quoted_string
+@INPUT      : file
+            : io_flag
+            : format
+            : str
+            : str_length
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary quoted string.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_quoted_string( file, io_flag, format, str, str_length )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    char            str[];
+    int             str_length;
+{
+    int      length;
+    Status   status;
+    Status   io_int();
+    Status   input_character();
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_quoted_string( file, str, str_length );
+        else
+            status = output_quoted_string( file, str );
+    }
+    else
+    {
+        if( io_flag == WRITE_FILE )
+            length = strlen( str );
+
+        status = io_int( file, io_flag, format, &length );
+
+        if( io_flag == READ_FILE && length >= str_length )
+        {
+            PRINT( "String too large: " );
+            status = ERROR;
+        }
+
+        if( status == OK )
+        {
+            status = io_binary_data( file, io_flag, (VOID *) str,
+                                     sizeof(str[0]), length );
+        }
+
+        str[length] = (char) 0;
+    }
+
+    if( status != OK )
+    {
+        PRINT_ERROR( "Error in quoted string in file.\n" );
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_boolean
+@INPUT      : file
+            : io_flag
+            : format
+            : b              boolean value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary boolean value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_boolean( file, io_flag, format, b )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    Boolean         *b;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_boolean( file, b );
+        else
+            status = output_boolean( file, *b );
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) b, sizeof(*b), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_short
+@INPUT      : file
+            : io_flag
+            : format
+            : short_int              short value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary short value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_short( file, io_flag, format, short_int )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    short           *short_int;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_short( file, short_int );
+        else
+            status = output_short( file, *short_int );
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) short_int,
+                                 sizeof(*short_int), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_unsigned_char
+@INPUT      : file
+            : io_flag
+            : format
+            : c              unsigned char value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary unsigned char.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_unsigned_char( file, io_flag, format, c )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    unsigned  char  *c;
+{
+    int      i;
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+        {
+            if( fscanf( file, "%d", &i ) == 1 )
+                *c = i;
+            else
+            {
+                PRINT_ERROR( "Error inputting unsigned char.\n" );
+                status = ERROR;
+            }
+        }
+        else
+        {
+            if( fprintf( file, "%d", (int) *c ) != 1 )
+            {
+                PRINT_ERROR( "Error outputting unsigned char.\n" );
+                status = ERROR;
+            }
+        }
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) c, sizeof(*c), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_int
+@INPUT      : file
+            : io_flag
+            : format
+            : i              integer value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary integer value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_int( file, io_flag, format, i )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    int             *i;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_int( file, i );
+        else
+            status = output_int( file, *i );
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) i, sizeof(*i), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_real
+@INPUT      : file
+            : io_flag
+            : format
+            : r              real value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary real value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_real( file, io_flag, format, r )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    Real            *r;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_real( file, r );
+        else
+            status = output_real( file, *r );
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) r, sizeof(*r), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_double
+@INPUT      : file
+            : io_flag
+            : format
+            : d              double value
+@OUTPUT     :
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs an ascii or binary double value.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_double( file, io_flag, format, d )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    double          *d;
+{
+    Status   status;
+
+    status = OK;
+
+    if( format == ASCII_FORMAT )
+    {
+        if( io_flag == READ_FILE )
+            status = input_double( file, d );
+        else
+            status = output_double( file, *d );
+    }
+    else
+        status = io_binary_data( file, io_flag, (VOID *) d, sizeof(*d), 1 );
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_ints
+@INPUT      : file
+            : io_flag
+            : format
+            : n               number of ints
+            : ints            array of ints
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs a list of ascii or binary integers.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_ints( file, io_flag, format, n, ints )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    int             n;
+    int             *ints[];
+{
+    Status   status;
+    int      i;
+#define      INTS_PER_LINE   8
+
+    status = OK;
+
+    if( io_flag == READ_FILE )
+    {
+        ALLOC( status, *ints, n );
+    }
+
+    if( status == OK )
+    {
+        if( format == ASCII_FORMAT )
+        {
+            for_less( i, 0, n )
+            {
+                status = io_int( file, io_flag, format, &(*ints)[i] );
+
+                if( status == OK )
+                {
+                    if( i == n - 1 || (i+1) % INTS_PER_LINE == 0 )
+                    {
+                        status = io_newline( file, io_flag, format );
+                    }
+                }
+
+                if( status == ERROR )
+                {
+                    break;
+                }
+            }
+        }
+        else
+        {
+            status = io_binary_data( file, io_flag, (VOID *) *ints,
+                                     sizeof((*ints)[0]), n );
+        }
+    }
+
+    return( status );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : io_unsigned_chars
+@INPUT      : file
+            : io_flag
+            : format
+            : n               number of unsigned chars
+            : unsigned_chars  array of unsigned chars
+@OUTPUT     : 
+@RETURNS    : Status
+@DESCRIPTION: Inputs or outputs a list of ascii or binary unsigned chars.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Status  io_unsigned_chars( file, io_flag, format, n, unsigned_chars )
+    FILE            *file;
+    IO_types        io_flag;
+    File_formats    format;
+    int             n;
+    unsigned char   *unsigned_chars[];
+{
+    Status   status;
+    int      i;
+
+    status = OK;
+
+    if( io_flag == READ_FILE )
+        ALLOC( status, *unsigned_chars, n );
+
+    if( status == OK )
+    {
+        if( format == ASCII_FORMAT )
+        {
+            for_less( i, 0, n )
+            {
+                status = io_unsigned_char( file, io_flag, format,
+                                           &(*unsigned_chars)[i] );
+
+                if( status == OK )
+                {
+                    if( i == n - 1 || (i+1) % INTS_PER_LINE == 0 )
+                        status = io_newline( file, io_flag, format );
+                }
+
+                if( status == ERROR )
+                    break;
+            }
+        }
+        else
+        {
+            status = io_binary_data( file, io_flag, (VOID *) (*unsigned_chars),
+                                     sizeof((*unsigned_chars)[0]), n );
+        }
+    }
+
+    return( status );
+}
new file mode 100644
--- /dev/null
+++ b/volume_io/Prog_utils/time.c
@@ -0,0 +1,188 @@
+#include  <sys/types.h>
+#include  <sys/times.h>
+#include  <sys/time.h>
+#include  <sys/param.h>
+#include  <limits.h>
+#include  <def_mni.h>
+#include  <def_string.h>
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : current_cpu_seconds
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : # seconds
+@DESCRIPTION: Returns the number of cpu seconds used by the program to date.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Real  current_cpu_seconds()
+{
+    struct  tms  buffer;
+    Real         cpu_time;
+
+    (void) times( &buffer );
+
+    cpu_time = (Real) buffer.tms_utime / (Real) HZ;
+
+    return( cpu_time );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : current_realtime_seconds
+@INPUT      : 
+@OUTPUT     : 
+@RETURNS    : # seconds
+@DESCRIPTION: Returns the number of seconds since the first invocation of this
+            : function.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  Real  current_realtime_seconds()
+{
+    static  Boolean          first_call = TRUE;
+    static  struct  timeval  first;
+    struct  timeval          current;
+    Real                     secs;
+
+    if( first_call )
+    {
+        first_call = FALSE;
+        (void) gettimeofday( &first, (struct timezone *) 0 );
+        secs = 0.0;
+    }
+    else
+    {
+        (void) gettimeofday( &current, (struct timezone *) 0 );
+        secs = (double) current.tv_sec - (double) first.tv_sec +
+               1.0e-6 * (double) (current.tv_usec - first.tv_usec);
+    }
+
+    return( secs );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : format_time
+@INPUT      : format
+            : seconds
+@OUTPUT     : str
+@RETURNS    : 
+@DESCRIPTION: Decides what time unit to use and displays the seconds value
+            : in str, using format.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  format_time( str, format, seconds )
+    char   str[];
+    char   format[];
+    Real   seconds;
+{
+    int     i;
+    static  char   *units[] = { "us", "ms", "sec", "min", "hrs",
+                                "days", "years"
+                              };
+    static  Real   scale[] = { 1000.0, 1000.0, 60.0, 60.0, 24.0, 365.0 };
+    Boolean  negative;
+
+    negative = seconds < 0.0;
+    if( negative )  seconds = -seconds;
+
+    seconds *= 1.0e6;
+
+    for_less( i, 0, SIZEOF_STATIC_ARRAY(units)-1 )
+    {
+        if( seconds > 2.0 * scale[i] )
+        {
+            seconds /= scale[i];
+        }
+        else
+        {
+            break;
+        }
+    }
+
+    seconds = (int) (10.0 * seconds + 0.5) / 10.0;
+
+    if( negative )  seconds = -seconds;
+
+    (void) sprintf( str, format, seconds, units[i] );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : print_time
+@INPUT      : format
+            : seconds
+@OUTPUT     : 
+@RETURNS    : 
+@DESCRIPTION: Prints out the time in suitable units.
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  print_time( format, seconds )
+    char   format[];
+    Real   seconds;
+{
+    String  str;
+
+    format_time( str, format, seconds );
+
+    (void) printf( "%s", str );
+}
+
+/* ----------------------------- MNI Header -----------------------------------
+@NAME       : get_clock_time
+@INPUT      : 
+@OUTPUT     : time_str
+@RETURNS    : 
+@DESCRIPTION: Stores the current time of day in the "time_str".
+@METHOD     : 
+@GLOBALS    : 
+@CALLS      : 
+@CREATED    :                      David MacDonald
+@MODIFIED   : 
+---------------------------------------------------------------------------- */
+
+public  void  get_clock_time( time_str )
+    char  time_str[];
+{
+    time_t           clock_time;
+    struct  tm       *time_tm;
+    char             *str;
+#ifndef sgi
+    time_t   time();
+#endif
+
+    (void) time( &clock_time );
+
+    time_tm = localtime( &clock_time );
+
+    str = asctime( time_tm );
+
+    (void) strcpy( time_str, str );
+}
+
+public  void  sleep_program( seconds )
+    Real   seconds;
+{
+#ifdef sgi
+    long  ticks;
+
+    ticks = (long) ROUND( seconds * CLK_TCK );
+    sginap( ticks );
+#endif
+}