Mercurial > hg > minc-tools
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( ¤t, (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( ¤t, (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 +}