diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 18:52:35 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 18:52:35 (GMT) |
commit | 9ef925b353e71b6b8abd23b59ca1adef488e3a3b (patch) | |
tree | 8d0d428ac62291f834ea8927bfa82c115ff1689d /ast/memory.c | |
parent | 0b1addf5643c828955a6add53f2a4f7a7a813e41 (diff) | |
download | blt-9ef925b353e71b6b8abd23b59ca1adef488e3a3b.zip blt-9ef925b353e71b6b8abd23b59ca1adef488e3a3b.tar.gz blt-9ef925b353e71b6b8abd23b59ca1adef488e3a3b.tar.bz2 |
upgrade ast 8.7.1
Diffstat (limited to 'ast/memory.c')
-rw-r--r-- | ast/memory.c | 5876 |
1 files changed, 0 insertions, 5876 deletions
diff --git a/ast/memory.c b/ast/memory.c deleted file mode 100644 index 2d45317..0000000 --- a/ast/memory.c +++ /dev/null @@ -1,5876 +0,0 @@ -/* -* Name: -* memory.c - -* Purpose: -* Implement memory allocation/deallocation functions. - -* Description: -* This file implements the Memory module which is used for -* allocating and freeing memory in the AST library. For a -* description of the module and its interface, see the .h file of -* the same name. - -* Note, it is assumed that malloc, free and realloc are thread-safe. - -* Copyright: -* Copyright (C) 1997-2006 Council for the Central Laboratory of the -* Research Councils -* Copyright (C) 2009-2010 Science & Technology Facilities Council. -* All Rights Reserved. - -* Licence: -* This program is free software: you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, either -* version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General -* License along with this program. If not, see -* <http://www.gnu.org/licenses/>. - -* Authors: -* RFWS: R.F. Warren-Smith (Starlink) -* DSB: D.S. Berry (Starlink) - -* History: -* 2-JAN-1996 (RFWS): -* Original version. -* 26-JAN-1996 (RFWS): -* Removed trailing underscores from static functions and -* changed to use new error function interfaces. -* 20-JUN-1996 (RFWS): -* Added astString. -* 15-JUL-1996 (RFWS): -* Make IsDynamic execute under error conditions to avoid memory -* leaks in such situations. -* 11-SEP-1996 (RFWS): -* Added astStringArray (original written by DSB). -* 18-MAR-1998 (RFWS): -* Added notes about these functions being available for writing -* foreign language and graphics interfaces, etc. -* 29-JAN-2002 (DSB): -* Added astChrLen and astSscanf. -* 15-FEB-2002 (DSB): -* Removed use of non-ANSI vsscanf from astSscanf. -* 15-NOV-2002 (DSB): -* Moved ChrMatch from SkyFrame (etc) to here. Included stdio.h and -* ctype.h. -* 10-FEB-2003 (DSB): -* Added facilities for detecting and tracing memory leaks. These -* are only included if AST is compiled with the -DDEBUG flag. -* 3-MAR-2004 (DSB): -* Modified astSscanf to avoid use of uninitialised values -* corresponding to "%n" fields in the format string. -* 26-JAN-2004 (DSB): -* Modified astRealloc to clarify the nature of the returned pointer -* (which is not a "Memory *"). Also correct issuing and deissuing -* of pointers in DEBUG code within astRealloc. -* 16-FEB-2006 (DSB): -* Convert Magic from a function to a macro for extra speed. -* 21-FEB-2006 (DSB): -* Convert IsDynamic from a function to a macro for extra speed. -* 23-FEB-2006 (DSB): -* Added the caching system for allocated but unused memory blocks, -* controlled by AST tuning parameter MemoryCaching. -* 2-MAR-2006 (DSB): -* Added astFlushMemory, and renamed the memory debugging functions. -* These are now conditionally compiled if the MEM_DEBUG macros is -* defined (set by configuring AST with the --with-memdebug option). -* Also modified them to take into account MemoryCaching. -* 24-MAY-2006 (DSB): -* Ensure that pointers to memory returned by this module are all -* aligned on 8 byte boundaries. This fixes problems with ualigned -* memory access that could cause bus errors on Solaris. -* 26-MAY-2006 (DSB): -* Cast (void *) pointers to (char *) before doing arithmetic on -* them (changes supplied by Micah Johnson). -* 4-DEC-2006 (DSB): -* Fix bug in astMalloc that caused a non-null pointer to be -* returned on error. -* 4-JAN-2007 (DSB): -* Move definition of astCLASS macro so that it comes before the -* inclusion of the AST include files (which test for astCLASS). -* 27-JUN-2007 (DSB): -* Added astIsDynamic. -* 24-OCT-2007 (DSB): -* Zero the size of memory blocks stored in the Cache so that an -* error will be reported if an attempt is made to free a memory -* block that has already been freed. -* 25-OCT-2007 (DSB): -* Added astRemoveLeadingBlanks. -* 28-FEB-2008 (DSB): -* Added astChrSub. -* 17-MAR-2008 (DSB): -* Added "{nnn}" quantifier to astChrSub. -* 27-MAR-2008 (DSB): -* Added astChrSplitRE, and re-structured regexp functions. -* 18-NOV-2008 (DSB): -* In astFlushMemory, do not release permanent memory blocks as -* they may still be needed. -* 9-FEB-2009 (DSB): -* Added astChr2Double. -* 25-JUN-2009 (DSB): -* Fix handling of escape characters in astSplitC. -* 19-MAY-2010 (DSB): -* - Added astStringCase. -* - Changed access from protected to public for commonly used -* functions. -* 26-MAY-2010 (DSB): -* Added astCalloc. -* 18-AUG-2010 (DSB): -* Added astMemoryStats -* 19-AUG-2010 (DSB): -* Added astMemoryWarning -* 8-OCT-2010 (DSB): -* Modify memory allocation to use "calloc" directly, rather than -* using "malloc+memset". -* 12-APR-2011 (DSB): -* Fix regular expression problem where a ".*" template field failed to -* match a null string if it occurred before a closing parenthesis at -* the end of the template. -* 26-MAY-2011 (DSB): -* - Changed API for astCalloc to match RTL (i.e. remove "init"). -* - Changed astChr2Double to check for strigs like "2.", which -* some sscanfs fail to read as a floating point value. -* 27-MAY-2011 (DSB): -* Added astFreeDouble to free a dynamically allocated array of -* pointers to other dynamically allocated arrays. -* 21-JUN-2011 (DSB): -* Added astCheckMemory - an alternative to astFlushMemory that does -* not free any memory. -* 21-NOV-2011 (DSB): -* Correct matchend value returned by astChrSplitRE. -* 6-JAN-2014 (DSB): -* Optimise access to cache to avoid valgrind warnings. -* 16-JAN-2014 (DSB): -* Dump details of all active memory blocks if the total memory allocation -* specified by astMemoryWarning is exceeded. -* 23-SEP-2014 (DSB): -* Modify astAppendString to allow printf conversion specifications to -* be included in the appended string. -* 20-OCT-2014 (DSB): -* Revert the change to astAppendString made on 23-SEP-2014 as it is -* insecure. Instead add new function astAppendStringf. -* 26-MAR-2015 (DSB): -* Added astChrTrunc. -* 17-MAR-2017 (DSB): -* Remove unnecessary checks that supplied size_t argument values -* are not less than zero - size_t is unsigned and so is never negative. -*/ - -/* Configuration results. */ -/* ---------------------- */ -#if HAVE_CONFIG_H -#include <config.h> -#endif - -/* Module Macros. */ -/* ============== */ -/* Define the astCLASS macro (even although this is not a class - implementation) to obtain access to the protected error handling - functions. */ -#define astCLASS memory - -/* The maximum number of fields within a format string allowed by astSscanf. */ -#define VMAXFLD 20 - -/* The maximum number of nested astBeginPM/astEndPM contexts. */ -#define PM_STACK_MAXSIZE 20 - -/* Select the appropriate memory management functions. These will be the - system's malloc, calloc, free and realloc unless AST was configured with - the "--with-starmem" option, in which case they will be the starmem - malloc, calloc, free and realloc. */ -#ifdef HAVE_STAR_MEM_H -# include <star/mem.h> -# define MALLOC starMalloc -# define CALLOC starCalloc -# define FREE starFree -# define REALLOC starRealloc -#else -# define MALLOC malloc -# define CALLOC calloc -# define FREE free -# define REALLOC realloc -#endif - - -#ifdef MEM_DEBUG -#define ISSUED "issued" -#define FREED "freed" -#endif - -/* Include files. */ -/* ============== */ -/* Interface definitions. */ -/* ---------------------- */ -#include "error.h" /* Error reporting facilities */ -#include "globals.h" /* Thread-specific global data */ -#include "memory.h" /* Interface to this module */ -#include "pointset.h" /* For AST__BAD */ - -#ifdef MEM_DEBUG -#include "object.h" /* For astMakePointer */ -#endif - -/* Error code definitions. */ -/* ----------------------- */ -#include "ast_err.h" /* AST error codes */ - -/* C header files. */ -/* --------------- */ -#include <ctype.h> -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <limits.h> - -#ifdef THREAD_SAFE -#include <pthread.h> -#endif - -#ifdef MEM_PROFILE -#include <sys/times.h> -#endif - -/* Function Macros. */ -/* =============== */ -/* These are defined as macros rather than functions to avoid the - overhead of a function call since they are called extremely frequently. */ - -/* -* Name: -* IS_DYNAMIC - -* Purpose: -* Test whether a memory region has been dynamically allocated. - -* Type: -* Private macro - -* Synopsis: -* #include "memory.h" -* IS_DYNAMIC( ptr, dynamic ) - -* Description: -* This macro takes a pointer to a region of memory and tests if -* the memory has previously been dynamically allocated using other -* functions from this module. It does this by checking for the -* presence of a "magic" number in the header which precedes the -* allocated memory. If the magic number is not present (or the -* pointer is invalid for any other reason), an error is reported -* and the global error status is set. -* -* The result of the test is written to the variable specified by "res". - -* Parameters: -* ptr -* Pointer to the start (as known to the external user) of the -* dynamically allocated memory. -* dynamic -* Name of an "int" variable to recieve the result of the test. -* If the memory was allocated dynamically, a value of 1 is -* stored in this variable. Otherwise, zero is stored and an error -* results. - -* Notes: -* - A NULL pointer value produces an error report from this -* function, although other functions may wish to regard a NULL -* pointer as valid. -* - This function attempts to execute even if the global error -* status is set, although no further error report will be made if -* the memory is not dynamically allocated under these -* circumstances. -* - The test performed by this function is not 100% secure as the -* "magic" value could occur by accident (although this is -* unlikely). It is mainly intended to provide security against -* programming errors, including accidental corruption of the -* memory header and attempts to allocate the same region of memory -* more than once. -*/ - -#define IS_DYNAMIC(ptr,dynamic) \ -\ -/* Initialise. */ \ - dynamic = 0; \ -\ -/* Check that a NULL pointer has not been supplied and report an error \ - if it has (but not if the global status is already set). */ \ - if ( !ptr ) { \ - if ( astOK ) { \ - astError( AST__PTRIN, "Invalid NULL pointer (address %p).", status, ptr ); \ - } \ -\ -/* If OK, derive a pointer to the memory header that precedes the \ - allocated region of memory. */ \ - } else { \ - Memory *isdynmem; /* Pointer to memory header */ \ - isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); \ -\ -/* Check if the "magic number" in the header is valid and report an \ - error if it is not (but not if the global status is already \ - set). */ \ - if ( isdynmem->magic != MAGIC( isdynmem, isdynmem->size ) ) { \ - if ( astOK ) { \ - astError( AST__PTRIN, \ - "Invalid pointer or corrupted memory at address %p.", status, \ - ptr ); \ - } \ -\ -/* Note if the magic number is OK. */ \ - } else { \ - dynamic = 1; \ - } \ - } - - - -/* -* Name: -* MAGIC - -* Purpose: -* Generate a "magic number". - -* Type: -* Private macro. - -* Synopsis: -* #include "memory.h" -* unsigned long MAGIC( void *ptr, size_t size ) - -* Description: -* This macro generates a "magic number" which is a function of -* a memory address and an object size. This number may be stored -* in a region of dynamically allocated memory to allow it to be -* recognised as dynamically allocated by other routines, and also -* to provide security against memory leaks, etc. - -* Parameters: -* ptr -* The memory pointer. -* size -* The object size. - -* Returned Value: -* The function returns the magic number. - -* Notes: -* This function does not perform error checking. -*/ - -/* Form the bit-wise exclusive OR between the memory address and the - object size, then add 1 and invert the bits. Return the result as - an unsigned long integer. */ -#define MAGIC(ptr,size) \ - ( ~( ( ( (unsigned long) ptr ) ^ ( (unsigned long) size ) ) + \ - ( (unsigned long) 1 ) ) ) - -/* A macro that returns the size of the a Memory structure padded to a - multiple of 8 bytes. */ -#define SIZEOF_MEMORY \ - ( ( sizeof_memory != 0 ) ? sizeof_memory : SizeOfMemory( status ) ) - - -/* Type Definitions. */ -/* ================= */ - -#ifdef MEM_PROFILE - -/* Structure used to record the time spent between matching calls to - astStartTimer and astStopTimer. */ -typedef struct AstTimer { - int id; /* Unique integer identifier for timer */ - clock_t e0; /* Absolute elapsed time at timer start */ - clock_t u0; /* Absolute user time at timer start */ - clock_t s0; /* Absolute system time at timer start */ - clock_t et; /* Cumulative elapsed time within timer */ - clock_t ut; /* Cumulative user time within timer */ - clock_t st; /* Cumulative system time within timer */ - int nentry; /* Number of entries into the timer */ - const char *name; /* An identifying label for the timer */ - const char *file; /* Name of source file where timer was started */ - int line; /* Source file line no. where timer was started */ - struct AstTimer *parent; /* The parent enclosing timer */ - int nchild; /* Number of child timers */ - struct AstTimer **children;/* Timers that count time within this timer */ -} AstTimer; - -#endif - -/* Module Variables. */ -/* ================= */ - -/* Extra stuff for profiling (can only be used in single threaded - environments). */ -#ifdef MEM_PROFILE -static AstTimer *Current_Timer = NULL; -static int Enable_Timers = 0; -static int Timer_Count = 0; -#endif - -/* Extra stuff for debugging of memory management (tracking of leaks - etc). */ -#ifdef MEM_DEBUG - -/* The identifier for the memory block which is to be tracked. */ -static int Watched_ID = -1; - -/* The next integer to use to identify an active memory block pointer. */ -static int Next_ID = -1; - -/* Indicates if future memory allocations are permanent (i.e. will not - usually be freed explicitly by AST). */ -static int Perm_Mem = 0; - -/* A "first in, last out" stack of Perm_Mem values used by nested - astBeginPM/astEndPM contexts. */ -static int PM_Stack[ PM_STACK_MAXSIZE ]; - -/* The number of values currently in the PM_Stack array. */ -static int PM_Stack_Size = 0; - -/* A pointer to a double linked list holding pointers to currently active - memory blocks (i.e. memory blocks for which a pointer has been issued - but not yet freed). This does not include the memory blocks in the - Cache array (these are not considered to be active). */ -static Memory *Active_List = NULL; - -/* Should a new ID be issued each time a cached memory block is returned - by astMalloc? Otherwise, the same ID value is used throughout the - life of a memory block. */ -static int Keep_ID = 0; - -/* Suppress all memory use reports except for issuing and freeing? */ -static int Quiet_Use = 0; - -/* Report the ID of every cached block when the cache is emptied? */ -static int List_Cache = 0; - -/* Memory allocation at which to issue a warning. */ -static size_t Warn_Usage = 0; - -/* Current memory allocated by AST. */ -static size_t Current_Usage = 0; - -/* Peak memory allocated by AST. */ -static size_t Peak_Usage = 0; - -#ifdef THREAD_SAFE -static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; -#define LOCK_DEBUG_MUTEX pthread_mutex_lock( &mutex2 ); -#define UNLOCK_DEBUG_MUTEX pthread_mutex_unlock( &mutex2 ); -#else -#define LOCK_DEBUG_MUTEX -#define UNLOCK_DEBUG_MUTEX -#endif - -#endif - -/* Define macros for accessing all items of thread-safe global data - used by this module. */ -#ifdef THREAD_SAFE - -#define sizeof_memory astGLOBAL(Memory,Sizeof_Memory) -#define cache astGLOBAL(Memory,Cache) -#define cache_init astGLOBAL(Memory,Cache_Init) -#define use_cache astGLOBAL(Memory,Use_Cache) - -/* Define the initial values for the global data for this module. */ -#define GLOBAL_inits \ - globals->Sizeof_Memory = 0; \ - globals->Cache_Init = 0; \ - globals->Use_Cache = 0; \ - -/* Create the global initialisation function. */ -astMAKE_INITGLOBALS(Memory) - -/* If thread safety is not needed, declare globals at static variables. */ -/* -------------------------------------------------------------------- */ -#else - -/* The size of a Memory header structure, padded to a multiple of 8 - bytes. This value is initialised by the SizeOfMemory function, and - should be accessed using the SIZEOF_MEMORY macro. */ -static size_t sizeof_memory = 0; - -/* A cache of allocated but currently unused memory block. This cache is - maintained in order to avoid the overhead of continual calls to malloc to - allocate small blocks of memory. The vast majority of memory blocks - allocated by AST are under 200 bytes in size. Each element in this array - stores a pointer to the header for a free (i.e. allocated but currently - unused) memory block. The size of the memory block (not including the - Memory header) will equal the index at which the pointer is stored within - "cache". Each free memory block contains (in its Memory header) a pointer - to the header for another free memory block of the same size (or a NULL - pointer if there are no other free memory blocks of the same size). */ -static Memory *cache[ MXCSIZE + 1 ]; - -/* Has the "cache" array been initialised? */ -static int cache_init = 0; - -/* Should the cache be used? */ -static int use_cache = 0; - -#endif - -/* Prototypes for Private Functions. */ -/* ================================= */ -static size_t SizeOfMemory( int * ); -static char *CheckTempStart( const char *, const char *, const char *, char *, int *, int *, int *, int *, int *, int *, int *, int * ); -static char *ChrMatcher( const char *, const char *, const char *, const char *, const char *[], int, int, int, char ***, int *, const char **, int * ); -static char *ChrSuber( const char *, const char *, const char *[], int, int, char ***, int *, const char **, int * ); - -#ifdef MEM_DEBUG -static void Issue( Memory *, int * ); -static void DeIssue( Memory *, int * ); -#endif - -#ifdef MEM_PROFILE -static AstTimer *ReportTimer( AstTimer *, int, AstTimer **, int *, int * ); -static int CompareTimers( const void *, const void * ); -static int CompareTimers2( const void *, const void * ); -#endif - -/* Function implementations. */ -/* ========================= */ -char *astAppendString_( char *str1, int *nc, const char *str2, int *status ) { -/* -*++ -* Name: -* astAppendString - -* Purpose: -* Append a string to another string which grows dynamically. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char *astAppendString( char *str1, int *nc, const char *str2 ) - -* Description: -* This function appends one string to another dynamically -* allocated string, extending the dynamic string as necessary to -* accommodate the new characters (plus the final null). - -* Parameters: -* str1 -* Pointer to the null-terminated dynamic string, whose memory -* has been allocated using an AST memory allocation function. -* If no space has yet been allocated for this string, a NULL -* pointer may be given and fresh space will be allocated by this -* function. -* nc -* Pointer to an integer containing the number of characters in -* the dynamic string (excluding the final null). This is used -* to save repeated searching of this string to determine its -* length and it defines the point where the new string will be -* appended. Its value is updated by this function to include -* the extra characters appended. -* -* If "str1" is NULL, the initial value supplied for "*nc" will -* be ignored and zero will be used. -* str2 -* Pointer to a constant null-terminated string, a copy of which -* is to be appended to "str1". - -* Returned Value: -* astAppendString() -* A possibly new pointer to the dynamic string with the new string -* appended (its location in memory may have to change if it has to -* be extended, in which case the original memory is automatically -* freed by this function). When the string is no longer required, -* its memory should be freed using astFree. - -* Notes: -* - If this function is invoked with the global error status set -* or if it should fail for any reason, then the returned pointer -* will be equal to "str1" and the dynamic string contents will be -* unchanged. -*-- -*/ - - -/* Local Variables: */ - char *result; /* Pointer value to return */ - int len; /* Length of new string */ - -/* Initialise. */ - result = str1; - -/* If the first string pointer is NULL, also initialise the character - count to zero. */ - if ( !str1 ) *nc = 0; - -/* Check the global error status. */ - if ( !astOK || !str2 ) return result; - -/* Calculate the total string length once the two strings have been - concatenated. */ - len = *nc + (int) strlen( str2 ); - -/* Extend the first (dynamic) string to the required length, including - a final null. Save the resulting pointer, which will be - returned. */ - result = astGrow( str1, len + 1, sizeof( char ) ); - -/* If OK, append the second string and update the total character - count. */ - if ( astOK ) { - (void) strcpy( result + *nc, str2 ); - *nc = len; - } - -/* Return the result pointer. */ - return result; -} - -char *astAppendStringf_( char *str1, int *nc, const char *str2, ... ) { -/* -*++ -* Name: -* astAppendStringf - -* Purpose: -* Append a string to another string, allowing printf format specifiers. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char *astAppendStringf( char *str1, int *nc, const char *str2, ... ) - -* Description: -* This function appends one string to another dynamically -* allocated string, extending the dynamic string as necessary to -* accommodate the new characters (plus the final null). It is the -* same as astAppendString, except that the "str2" string ay include -* printf format specifiers. - -* Parameters: -* str1 -* Pointer to the null-terminated dynamic string, whose memory -* has been allocated using an AST memory allocation function. -* If no space has yet been allocated for this string, a NULL -* pointer may be given and fresh space will be allocated by this -* function. -* nc -* Pointer to an integer containing the number of characters in -* the dynamic string (excluding the final null). This is used -* to save repeated searching of this string to determine its -* length and it defines the point where the new string will be -* appended. Its value is updated by this function to include -* the extra characters appended. -* -* If "str1" is NULL, the initial value supplied for "*nc" will -* be ignored and zero will be used. -* str2 -* Pointer to a constant null-terminated string, a copy of which -* is to be appended to "str1". It may contain format -* specifications such as used with the C "printf" family of -* functions. -* ... -* Additional optional arguments (as used by e.g. "printf") -* which specify values which are to be substituted into the "str2" -* string in place of any format specifications. - -* Returned Value: -* astAppendString() -* A possibly new pointer to the dynamic string with the new string -* appended (its location in memory may have to change if it has to -* be extended, in which case the original memory is automatically -* freed by this function). When the string is no longer required, -* its memory should be freed using astFree. - -* Notes: -* - If this function is invoked with the global error status set -* or if it should fail for any reason, then the returned pointer -* will be equal to "str1" and the dynamic string contents will be -* unchanged. -*-- -*/ - -/* Local Variables: */ - char *pbuf; /* Pointer to buffer for expanded "str2" */ - char *result; /* Pointer value to return */ - char buf[1000]; /* A large buffer for the expanded "str2" */ - int *status; /* Pointer to inherited status variable */ - int buf_size; /* Size of buffer for expanded "str2" */ - int len; /* Length of new string */ - int nexp; /* Number of characters written to "pbuf". */ - va_list args; /* Variable argument list pointer */ - -/* Initialise. */ - result = str1; - -/* If the first string pointer is NULL, also initialise the character - count to zero. */ - if( !str1 ) *nc = 0; - -/* Get a pointer to the integer holding the inherited status value. This - function cannot have a "status" argument like most other functions - because of the variable argument list. */ - status = astGetStatusPtr; - -/* Check the global error status. */ - if ( !astOK || !str2 ) return result; - -/* If available use vsnprintf to determine the amount of memory needed to - hold the expanded version of "str2". Then allocate the required memory. */ -#if HAVE_VSNPRINTF - va_start( args, str2 ); - buf_size = vsnprintf( buf, sizeof( buf ), str2, args ) + 1; - va_end( args ); - pbuf = astMalloc( buf_size ); - -/* Otherwise, all we can do is use a big buffer and hope for the best. */ -#else - buf_size = sizeof( buf ); - pbuf = buf; -#endif - -/* Expand any conversion specifications in "str2". */ - va_start( args, str2 ); - nexp = vsprintf( pbuf, str2, args ); - va_end( args ); - -/* Check that the result buffer did not overflow (should only be - possible if vsnprintf is not available). If it did, memory may - have been corrupted. Report the error and abort. */ - if( nexp >= buf_size ) { - if( astOK ) astError( AST__ATSER, "astAppendString: Internal buffer " - "overflow while appending a string - the " - "result exceeds %d characters.", status, - buf_size - 1 ); - } - -/* Calculate the total string length once the two strings have been - concatenated. */ - len = *nc + nexp; - -/* Extend the first (dynamic) string to the required length, including - a final null. Save the resulting pointer, which will be - returned. */ - result = astGrow( str1, len + 1, sizeof( char ) ); - -/* If OK, append the second string and update the total character - count. */ - if ( astOK ) { - (void) strcpy( result + *nc, pbuf ); - *nc = len; - } - -/* If required, free the buffer holding the expanded version of "str2". */ -#if HAVE_VSNPRINTF - pbuf = astFree( pbuf ); -#endif - -/* Return the result pointer. */ - return result; -} - -int astBrackets_( const char *text, size_t start, size_t end, - char opchar, char clchar, int strip, - size_t *openat, size_t *closeat, char **before, - char **in, char **after, int *status ){ -/* -*++ -* Name: -* astBrackets - -* Purpose: -* Identify a bracketed sub-string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* int astBrackets( const char *text, size_t start, size_t end, -* char opchar, char clchar, int strip, -* size_t *openat, size_t *closeat, char **before, -* char **in, char **after ) - -* Description: -* This function searches a specified section of the supplied text -* string for the first sub-string that is delimited by opening and -* closing brackets. If found, the positions of the opening and closing -* brackets are returned. Optionally, null-terminated copies of the -* strings, before, in and after the brackets can be returned. The -* characters to be used as the opening and closing brackets can be -* specified. - -* Parameters: -* text -* The text string to be seached. -* start -* The zero-based index of the first character to be checked within -* "text". The whole string is used if "start" is greater than "end". -* end -* The zero-based index of the last character to be checked within -* "text". The whole string is used if "start" is greater than "end". -* The last character is used if "end" is greater than the length -* of the string. -* opchar -* The character to be used as the opening bracket (e.g. '['). -* clchar -* The character to be used as the closing bracket (e.g. ']'). -* strip -* If non-zero, leading and trailing spaces are removed from the -* returned "before", "in" and "after" strings. -* openat -* Returned holding the zero-based index of the opening bracket. -* Ignored if NULL. -* closeat -* Returned holding the zero-based index of the closing bracket. -* Ignored if NULL. -* before -* Address at which to return a pointer to a null-terminated copy -* of the string that came before the opening bracket. This will be -* a null string "" if the opening bracket is the first character -* in the search. The returned pointer should be freed using astFree -* when no longer needed. Ignored if "before" is NULL. -* in -* Address at which to return a pointer to a null-terminated copy -* of the string that came between the opening and closing bracket. -* This will be a null string "" if the bracket was empty. The -* returned pointer should be freed using astFree when no longer -* needed. Ignored if "in" is NULL. -* after -* Address at which to return a pointer to a null-terminated copy -* of the string that came after the opening bracket. This will be -* a null string "" if the closing bracket is the last character -* in the search. The returned pointer should be freed using astFree -* when no longer needed. Ignored if "after" is NULL. - -* Returned Value: -* astBrackets() -* A value of 1 is returned if a correctly bracketed sub-string was -* found. A value of 0 is returned if no bracketed sub-string was -* found. A value of -1 is returned if too many closing brackets -* were found. A value of -2 is returned if too many opening -* brackets were found. - -* Notes: -* - Any nested brackets within a top-level bracketed sub-string are -* skipped. Any inbalance in brackets is indicated by the function -* return value. -* - If no bracketed sub-string is found, all the returned pointers -* will be NULL, "closeat" will be 0 and "openat" will be 1. -*-- -*/ -/* Local Variables: */ - int result; - size_t nc; - size_t nct; - size_t opat; - size_t clat; - int depth; - const char *p; - const char *pend; - -/* Initialise. */ - result = 0; - if( openat ) *openat = 1; - if( closeat ) *closeat = 0; - if( before ) *before = NULL; - if( in ) *in = NULL; - if( after ) *after = NULL; - -/* Check the global error status. Also check a text string was supplied. */ - if ( !astOK || !text ) return result; - -/* Get the total length of the supplied string, including any trailing blanks - but excluding the terminating null. */ - nct = strlen( text ); - -/* Get the actual start and end positions to use. */ - if( start > end ) { - start = 0; - end = nct - 1; - } else if( end >= nct ) { - end = nct - 1; - } - -/* Check there is some text to search. */ - if( start <= end ) { - -/* Initialise the indices of the opening and closing brackets to indicate - that no brackets have yet been found ( opat > clat). */ - opat = 1; - clat = 0; - -/* Initialise the current depth of nesting within brackets. */ - depth = 0; - -/* Loop through all characters in the section of the string to be - searched. */ - p = text + start - 1; - pend = text + end; - while( ++p <= pend ) { - -/* If this is an opening bracket, increment the nesting depth. If it is - the first opening bracket (original depth zero), record its position. */ - if( *p == opchar ) { - if( depth++ == 0 ) opat = p - text; - -/* If this is a closing bracket, record its position and decrement the - nesting depth. If the depth reaches zero, break out of the loop. If - a closing bracket is found before any opening bracket, the depth will - go negative, so check for this too. */ - } else if( *p == clchar ) { - clat = p - text; - if( --depth <= 0 ) break; - } - } - -/* If the final depth is positive, we have to0 many opening brackets. - So return -2. */ - if( depth > 0 ) { - result = -2; - -/* If the final is negative, we found a closing bracket before finding an - opening bracket, so return -1. */ - } else if( depth < 0 ) { - result = -1; - -/* If brackets were balanced correctly, check we actually found some - brackets. If so, return 1. */ - } else if( opat <= clat ) { - result = 1; - -/* Return the index of the opening and closing brackets. */ - if( openat ) *openat = opat; - if( closeat ) *closeat = clat; - -/* If required, extract the string that occurs before the opening bracket, - and terminate it. */ - if( before ) { - nc = opat; - *before = astStore( NULL, text, nc + 1 ); - (*before)[ nc ] = 0; - -/* If required, strip trailing and leading spaces. */ - if( strip ) { - astChrTrunc( *before ); - astRemoveLeadingBlanks( *before ); - } - } - -/* If required, extract the string that occurs within the brackets, - and terminate it. Strip spaces if required. */ - if( in ) { - nc = clat - opat - 1; - *in = astStore( NULL, text + opat + 1, nc + 1 ); - (*in)[ nc ] = 0; - - if( strip ) { - astChrTrunc( *in ); - astRemoveLeadingBlanks( *in ); - } - } - -/* If required, extract the string that occurs after the brackets, - and terminate it. Strip spaces if required. */ - if( after ) { - nc = nct - clat - 1; - *after = astStore( NULL, text + clat + 1, nc + 1 ); - (*after)[ nc ] = 0; - - if( strip ) { - astChrTrunc( *after ); - astRemoveLeadingBlanks( *after ); - } - } - } - } - -/* Return the result. */ - return result; -} - -void *astCalloc_( size_t nmemb, size_t size, int *status ) { -/* -*++ -* Name: -* astCalloc - -* Purpose: -* Allocate and initialise memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astCalloc( size_t nmemb, size_t size ) - -* Description: -* This function allocates memory in a similar manner to the -* standard C "calloc" function, but with improved security -* (against memory leaks, etc.) and with error reporting. It also -* fills the allocated memory with zeros. -* -* Like astMalloc, it allows zero-sized memory allocation -* (without error), resulting in a NULL returned pointer value. - -* Parameters: -* nmemb -* The number of array elements for which memory is to be allocated. -* size -* The size of each array element, in bytes. - -* Returned Value: -* astCalloc() -* If successful, the function returns a pointer to the start of -* the allocated memory region. If the size allocated is zero, this -* will be a NULL pointer. - -* Notes: -* - A pointer value of NULL is returned if this function is -* invoked with the global error status set or if it fails for any -* reason. -*-- -*/ -/* Local Variables: */ - void *result; /* Returned pointer */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Attempt to allocate and initialise the required amount of memory. */ - result = astMallocInit( nmemb*size ); - -/* If the above call failed due to failure of the system malloc function, - issue an extra error giving the number of elements and element size. */ - if( astStatus == AST__NOMEM ) { - astError( AST__NOMEM, "(%lu elements, each of %lu bytes).", status, - (unsigned long) nmemb, (unsigned long) size ); - } - -/* Return the result. */ - return result; -} - -static char *CheckTempStart( const char *template, const char *temp, - const char *pattern, - char *allowed, int *ntemp, int *allow, - int *min_nc, int *max_nc, int *start_sub, - int *end_sub, int *greedy, int *status ){ -/* -* Name: -* CheckTempStart - -* Purpose: -* Examine the leading field in an astChrSub template. - -* Type: -* Private function. - -* Synopsis: -* char *CheckTempStart( const char *template, const char *temp, -* const char *pattern, -* char *allowed, int *ntemp, int *allow, -* int *min_nc, int *max_nc, int *start_sub, -* int *end_sub, int *greedy, int *status ) - -* Description: -* This function returns inforation about the leading field in a -* template string supplied to astChrSub. - -* Parameters: -* template -* The full template string (used for error messages). -* temp -* Pointer to the next character to read from the template string. -* pattern -* Pointer to the user supplied pattern string (only used in error -* messages). -* allowed -* Pointer to a buffer in which to store a string of characters -* that the leading temeplate field will match. A NULL pointer may -* be supplied in which case new memory will be allocated. The -* supplied memory is expanded as necessary, and a pointer to it is -* returned as the function value. -* ntemp -* Address of an int in which to return the number of characters -* consumed from the start of "temp". -* allow -* Address of an int in which to return a flag which is non-zero if -* the returned string contains characters that are allowed in the -* test field, or zero if the returned string contains characters that -* are disallowed in the test field. -* min_nc -* Address of an int in which to return the minimum number of -* test characters that must belong to the returned set of -* allowed characters. -* max_nc -* Address of an int in which to return the maximum number of -* test characters that must belong to the returned set of -* allowed characters. -* start_sub -* Address of an int in which to return a flag which is non-zero if -* the leading template field indicates the start of a field to be -* substituted. In this case the supplied "allowed" pointer is -* returned without change as the function value, "Min_nc" is -* returned as zero, and max_nc is returned as zero. -* end_sub -* Address of an int in which to return a flag which is non-zero if -* the leading template field indicates the end of a field to be -* substituted. In this case the supplied "allowed" pointer is -* returned without change as the function value, "Min_nc" is -* returned as zero, and limit is returned as zero. -* greedy -* Address of an int in which to return a flag which is non-zero if -* the template starts with a greedy quantifier. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* Pointer to a (possibly newly allocated) memory area holding a -* string of characters that the leading temeplate field will match. -* This string should be released using astFree when no longer needed. -* If a NULL pointyer is returned, then all characters are allowed -* (or disallowed if "*allow" is zero). - -* Notes: -* - The returned value is also stored in the module variable -* sizeof_memory. -*/ - -/* Local Variables: */ - char *result; - const char *start; - const char *end; - -/* Initialise. */ - result = allowed; - *ntemp = 0; - *allow = 1; - *min_nc = 0; - *max_nc = 0; - *start_sub = 0; - *end_sub = 0; - *greedy = 1; - -/* Check global status */ - if( !astOK ) return result; - -/* If the next character is an opening parenthesis, this marks the start - of a substitution field. */ - if( *temp == '(' ) { - *start_sub = 1; - *ntemp = 1; - -/* If the next character is an closing parenthesis, this marks the end - of a substitution field. */ - } else if( *temp == ')' ) { - *end_sub = 1; - *ntemp = 1; - -/* If the next character is an opening bracket, this marks the start of a - field of allowed or disallowed characters. */ - } else { - if( *temp == '[' ) { - -/* If the first character in the brackets is "^" this is a field of - disallowed characters, otherwise they are allowed. */ - if( temp[ 1 ] == '^' ) { - *allow = 0; - start = temp + 2; - } else { - start = temp + 1; - } - -/* Get a pointer to the closing bracket. */ - end = strchr( temp, ']' ); - -/* Copy the intervening string into the returned string. */ - if( end ) { - result = astStore( allowed, start, end - start + 1 ); - if( result ) result[ end - start ] = 0; - -/* Report an error if no closing bracket was found. */ - } else { - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "missing ']'.", status, pattern ); - } - -/* Indicate how many template characters have been used. */ - *ntemp = end - temp + 1; - -/* A single dot matches any character. */ - } else if( *temp == '.' ) { - result = astFree( result ); - *ntemp = 1; - -/* Now deal with escape sequences. */ - } else if( *temp == '\\' ) { - -/* Digits... */ - if( temp[ 1 ] == 'd' || temp[ 1 ] == 'D' ) { - result = astStore( allowed, "0123456789", 11 ); - result[ 10 ] = 0; - if( temp[ 1 ] == 'D' ) *allow = 0; - -/* White space... */ - } else if( temp[ 1 ] == 's' || temp[ 1 ] == 'S' ) { - result = astStore( allowed, " \n\r", 5 ); - result[ 4 ] = 0; - if( temp[ 1 ] == 'S' ) *allow = 0; - -/* Word characters... */ - } else if( temp[ 1 ] == 'w' || temp[ 1 ] == 'W' ) { - result = astStore( allowed, "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_", - 64 ); - result[ 63 ] = 0; - if( temp[ 1 ] == 'W' ) *allow = 0; - -/* Any other character is treated literally. */ - } else { - result = astStore( allowed, temp + 1, 2 ); - result[ 1 ] = 0; - } - -/* Set number of template characters consumed. */ - *ntemp = 2; - -/* Everything else must be matched literally. */ - } else { - - if( *temp == '*' || *temp == '?' || *temp == '+' ){ - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "field starts with '%c'.", status, pattern, temp[ *ntemp ] ); - } else { - result = astStore( allowed, temp, 2 ); - result[ 1 ] = 0; - *ntemp = 1; - } - - } - -/* Now see if there is any quantifier. */ - if( temp[ *ntemp ] == '*' ) { - *min_nc = 0; - *max_nc = INT_MAX; - (*ntemp)++; - if( temp[ *ntemp ] == '?' ){ - *greedy = 0; - (*ntemp)++; - } - - } else if( temp[ *ntemp ] == '+' ) { - *min_nc = 1; - *max_nc = INT_MAX; - (*ntemp)++; - if( temp[ *ntemp ] == '?' ){ - *greedy = 0; - (*ntemp)++; - } - - } else if( temp[ *ntemp ] == '?' ) { - *min_nc = 0; - *max_nc = 1; - (*ntemp)++; - - } else { - -/* See if the remaining string starts with "{nnn}". If so, extract the - "nnn" and use it as the minimum and maximum field length. */ - if( temp[ *ntemp ] == '{' ) { - - start = temp + *ntemp + 1; - while( isdigit( (int) *start ) ) { - *min_nc = 10*( *min_nc ) + (int )( ( *start ) - '0' ); - start++; - } - - if( *start == '}' ) { - *max_nc = *min_nc; - *ntemp = start - temp + 1; - } else { - start = NULL; - } - - } else { - start = NULL; - } - -/* If the remaining string does not start with "{nnn}", use a minimum and - maximum field length of 1. */ - if( !start ) { - *min_nc = 1; - *max_nc = 1; - } - } - } - -/* Return the string of allowed characters. */ - return result; -} - -double astChr2Double_( const char *str, int *status ) { -/* -*++ -* Name: -* astChr2Double - -* Purpose: -* read a double value from a string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* double astChr2Double( const char *str ) - -* Description: -* This function reads a double from the supplied null-terminated string, -* ignoring leading and trailing white space. AST__BAD is ereturned -* without error if the string is not a numerical value. - -* Parameters: -* str -* Pointer to the string. - -* Returned Value: -* astChr2Double() -* The double value, or AST__BAD. - -* Notes: -* - A value of AST__BAD is returned if this function is invoked with -* the global error status set or if it should fail for any reason. -*-- -*/ - -/* Local Variables: */ - double result; /* The returned value */ - int ival; /* Integer value read from string */ - int len; /* Length of supplied string */ - int nc; /* Number of characters read from the string */ - -/* Check the global error status and supplied pointer. */ - if ( !astOK || !str ) return AST__BAD; - -/* Save the length of the supplied string. */ - len = strlen( str ); - -/* Use scanf to read the floating point value. This fails if either 1) the - string does not begin with a numerical value (in which case astSscanf - returns zero), or 2) there are non-white characters following the - numerical value (in which case "nc" - the number of characters read from - the string - is less than the length of the string). */ - if ( nc = 0, - ( 1 != astSscanf( str, " %lg %n", &result, &nc ) ) || ( nc < len ) ) { - result = AST__BAD; - } - -/* If the above failed, try again allowing the string to be an integer - followed by a dot (e.g. "1."). Some implementations of sscanf do not - consider this to be a floating point value. */ - if( 1 || result == AST__BAD ) { - if ( nc = 0, - ( 1 == astSscanf( str, " %d. %n", &ival, &nc ) ) && ( nc >= len ) ) { - result = ival; - } - } - -/* Return the result. */ - return result; -} - -void astChrCase_( const char *in, char *out, int upper, int blen, int *status ) { -/* -*++ -* Name: -* astChrCase - -* Purpose: -* Convert a string to upper or lower case. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astChrCase( const char *in, char *out, int upper, int blen, int *status ) - -* Description: -* This function converts a supplied string to upper or lower case, -* storing the result in a supplied buffer. The astStringCase function -* is similar, but stores the result in a dynamically allocated buffer. - -* Parameters: -* in -* Pointer to the null terminated string to be converted. If this -* is NULL, the supplied contents of the "out" string are used as -* the input string. -* out -* Pointer to the buffer to receive the converted string. The -* length of this buffer is given by "blen". If NULL is supplied -* for "in", then the supplied contents of "out" are converted and -* written back into "out" over-writing the supplied contents. -* upper -* If non-zero, the string is converted to upper case. Otherwise it -* is converted to lower case. -* blen -* The length of the output buffer. Ignored if "in" is NULL. No -* more than "blen - 1" characters will be copied from "in" to -* "out", and a terminating null character will then be added. - -*-- -*/ - -/* Local Variables: */ - const char *pin; - char *pout; - int i; - -/* Check the global error status. */ - if ( !astOK ) return; - -/* The simple case of over-writing the supplied string. */ - if( ! in ) { - pout = out - 1; - while( *(++pout) ) *pout = toupper( (int) *pout ); - -/* If a separate output buffer has been supplied... */ - } else { - -/* Initialise pointers to the input and output buffers. */ - pin = in; - pout = out; - -/* Copy the string character by character, converting the case in the - process. Start counting from 1, not 0, in order to ensure that we are - left with room for a terminating null. */ - for( i = 1; i < blen && *pin; i++ ) { - *(pout++) = toupper( (int) *(pin++) ); - } - -/* Terminate the returned string. */ - *pout = 0; - } -} - -void astChrClean_( char *text ) { -/* -*++ -* Name: -* astChrClean - -* Purpose: -* Replace unprintable characters in a string with spaces. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astChrClean( char *text ) - -* Description: -* This function replaces all unprintable characters in the given -* string with spaces. It is assumed that the string contains only -* ASCII characters. - -* Parameters: -* text -* Pointer to the null terminated string to be modified. - -*-- -*/ - -/* Local Variables: */ - char *pr; - - if( !text ) return; - - pr = text - 1; - while( *(++pr) ) { - if( *pr < ' ' || *pr > '~' ) *pr = ' '; - } -} - -int astChrMatch_( const char *str1, const char *str2, int *status ) { -/* -*++ -* Name: -* astChrMatch - -* Purpose: -* Case insensitive string comparison. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* int astChrMatch( const char *str1, const char *str2 ) - -* Description: -* This function compares two null terminated strings for equality, -* discounting differences in case and any trailing white space in either -* string. - -* Parameters: -* str1 -* Pointer to the first string. -* str2 -* Pointer to the second string. - -* Returned Value: -* astChrMatch() -* Non-zero if the two strings match, otherwise zero. - -* Notes: -* - A value of zero is returned if this function is invoked with the -* global error status set or if it should fail for any reason. -*-- -*/ - -/* Local Variables: */ - int match; /* Strings match? */ - -/* Check the global error status. */ - if ( !astOK ) return 0; - -/* Initialise. */ - match = 1; - -/* Loop to compare characters in the two strings until a mis-match occurs or - we reach the end of the longer string. */ - while ( match && ( *str1 || *str2 ) ) { - -/* Two characters match if (a) we are at the end of one string and the other - string contains white space or (b) both strings contain the same character - when converted to lower case. */ - match = ( !*str1 && isspace( *str2 ) ) || - ( !*str2 && isspace( *str1 ) ) || - ( tolower( *str1 ) == tolower( *str2 ) ); - -/* Step through each string a character at a time until its end is reached. */ - if ( *str1 ) str1++; - if ( *str2 ) str2++; - } - -/* Return the result. */ - return match; -} - -int astChrMatchN_( const char *str1, const char *str2, size_t n, int *status ) { -/* -*++ -* Name: -* astChrMatchN - -* Purpose: -* Case insensitive string comparison of at most N characters - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* int astChrMatchN( const char *str1, const char *str2, size_t n ) - -* Description: -* This function compares two null terminated strings for equality, -* discounting differences in case and any trailing white space in either -* string. No more than "n" characters are compared. - -* Parameters: -* str1 -* Pointer to the first string. -* str2 -* Pointer to the second string. -* n -* Maximum number of characters to compare. - -* Returned Value: -* astChrMatchN() -* Non-zero if the two strings match, otherwise zero. - -* Notes: -* - A value of zero is returned if this function is invoked with the -* global error status set or if it should fail for any reason. -*-- -*/ - -/* Local Variables: */ - int match; /* Strings match? */ - int nc; /* Number of characters compared so far */ - -/* Check the global error status. */ - if ( !astOK ) return 0; - -/* Initialise. */ - match = 1; - -/* So far we have compared zero characters */ - nc = 0; - -/* Loop to compare characters in the two strings until a mis-match occurs or - we reach the end of the longer string, or we reach the specified - maximum number of characters. */ - while ( match && ( *str1 || *str2 ) && nc++ < n ) { - -/* Two characters match if (a) we are at the end of one string and the other - string contains white space or (b) both strings contain the same character - when converted to lower case. */ - match = ( !*str1 && isspace( *str2 ) ) || - ( !*str2 && isspace( *str1 ) ) || - ( tolower( *str1 ) == tolower( *str2 ) ); - -/* Step through each string a character at a time until its end is reached. */ - if ( *str1 ) str1++; - if ( *str2 ) str2++; - } - -/* Return the result. */ - return match; -} - -void astChrRemoveBlanks_( char *text ) { -/* -*++ -* Name: -* astChrRemoveBlanks - -* Purpose: -* Remove all spaces from a string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astChrClean( char *text ) - -* Description: -* This function removes all spaces form the supplied string by moving -* non-space characters to the left. The string is terminated to -* remove any trailing spaces. - -* Parameters: -* text -* Pointer to the null terminated string to be modified. - -*-- -*/ - -/* Local Variables: */ - char *pr; - char *pw; - - if( !text ) return; - - pw = text; - pr = text - 1; - while( *(++pr) ) { - if( *pr != ' ' ) *(pw++) = *pr; - } - *pw = 0; -} - -char **astChrSplit_( const char *str, int *n, int *status ) { -/* -*++ -* Name: -* astChrSplit - -* Purpose: -* Extract words from a supplied string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char **astChrSplit( const char *str, int *n ) - -* Description: -* This function extracts all space-separated words form the supplied -* string and returns them in an array of dynamically allocated strings. - -* Parameters: -* str -* Pointer to the string to be split. -* n -* Address of an int in which to return the number of words returned. - -* Returned Value: -* astChrSplit() -* A pointer to a dynamically allocated array containing "*n" elements. -* Each element is a pointer to a dynamically allocated character -* string containing a word extracted from the supplied string. Each -* of these words will have no leading or trailing white space. - -* Notes: -* - A NULL pointer is returned if this function is invoked with the -* global error status set or if it should fail for any reason, or if -* the supplied string contains no words. -*-- -*/ - -/* Local Variables: */ - char **result; - char *w; - const char *p; - const char *ws; - int first; - int state; - int wl; - -/* Check the global error status. */ - if ( !astOK ) return NULL; - -/* Initialise. */ - result = NULL; - ws = NULL; - *n = 0; - -/* State 0 is "looking for the next non-white character which marks the - start of the next word". State 1 is "looking for the next white character - which marks the end of the current word". */ - state = 0; - -/* Loop through all characters in the supplied string, including the - terminating null. */ - p = str - 1; - first = 1; - while( *(p++) || first ) { - first = 0; - -/* If this is the terminating null or a space, and we are currently looking - for the end of a word, allocate memory for the new word, copy the text - in, terminate it, extend the returned array by one element, and store - the new word in it. */ - if( !*p || isspace( *p ) ) { - if( state == 1 ) { - wl = p - ws; - w = astMalloc( wl + 1 ); - if( w ) { - strncpy( w, ws, wl ); - w[ wl ] = 0; - result = astGrow( result, *n + 1, sizeof( char * ) ); - if( result ) result[ (*n)++ ] = w; - } - state = 0; - } - -/* If this is non-blank character, and we are currently looking for the - start of a word, note the address of the start of the word, and - indicate that we are now looking for the end of a word. */ - } else { - if( state == 0 ) { - state = 1; - ws = p; - } - } - } - -/* Return the result. */ - return result; -} - -char **astChrSplitC_( const char *str, char c, int *n, int *status ) { -/* -*++ -* Name: -* astChrSplitC - -* Purpose: -* Split a string using a specified character delimiter. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char **astChrSplitC( const char *str, char c, int *n ) - -* Description: -* This function extracts all sub-strings separated by a given -* character from the supplied string and returns them in an array -* of dynamically allocated strings. The delimiter character itself -* is not included in the returned strings. -* -* Delimiter characters that are preceded by "\" are not used as -* delimiters but are included in the returned word instead (without -* the "\"). - -* Parameters: -* str -* Pointer to the string to be split. -* c -* The delimiter character. -* n -* Address of an int in which to return the number of words returned. - -* Returned Value: -* astChrSplitC() -* A pointer to a dynamically allocated array containing "*n" elements. -* Each element is a pointer to a dynamically allocated character -* string containing a word extracted from the supplied string. - -* Notes: -* - A NULL pointer is returned if this function is invoked with the -* global error status set or if it should fail for any reason, or if -* the supplied string contains no words. -*-- -*/ - -/* Local Variables: */ - char **result; - char *word; - const char *p; - int escaped; - int wordlen; - -/* Initialise returned values. */ - *n = 0; - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* More initialisations. */ - word = NULL; - wordlen = 0; - escaped = 0; - -/* Loop through all characters in the supplied string, including the - terminating null. */ - p = str; - while( *p ) { - -/* Is this a delimiter character? */ - if( *p == c ) { - -/* If it is escaped, it does not mark the end of a word. Put it into the - current output buffer instead, overwriting the escape character that - preceded it. */ - if( escaped ) { - word[ wordlen - 1 ] = c; - -/* The next character is not escaped. */ - escaped = 0; - -/* If the delimiter is not escaped, terminate the current word and store - a pointer to it in the returned array. */ - } else { - result = astGrow( result, *n + 1, sizeof( char * ) ); - word = astGrow( word, wordlen + 1, 1 ); - if( result && word ) { - word[ wordlen ] = 0; - result[ (*n)++ ] = word; - wordlen = 0; - word = NULL; - } - } - -/* If this is not a delimitier character, store it in the returned word. */ - } else { - word = astGrow( word, wordlen + 1, 1 ); - if( word ) word[ wordlen++ ] = *p; - -/* If the current character was escaped, indicate that the next character - is not escaped. */ - if( escaped ) { - escaped = 0; - -/* If this character is a unescaped backslash, set a flag indicating that the - next character is escaped. */ - } else if( *p == '\\' ){ - escaped = 1; - } - } - -/* Move on to the next character. */ - p++; - } - -/* Store the text following the final delimitier. */ - result = astGrow( result, *n + 1, sizeof( char * ) ); - word = astGrow( word, wordlen + 1, 1 ); - if( result && word ) { - word[ wordlen ] = 0; - result[ (*n)++ ] = word; - } - -/* Return the result. */ - return result; -} - -char **astChrSplitRE_( const char *str, const char *regexp, int *n, - const char **matchend, int *status ) { -/* -*++ -* Name: -* astChrSplitRE - -* Purpose: -* Extract sub-strings matching a specified regular expression. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char **astChrSplitRE( const char *str, const char *regexp, int *n, -* const char **matchend ) - -* Description: -* This function compares the supplied string with the supplied -* regular expression. If they match, each section of the test string -* that corresponds to a parenthesised sub-string in the regular -* expression is copied and stored in the returned array. - -* Parameters: -* str -* Pointer to the string to be split. -* regexp -* The regular expression. See "Template Syntax:" in the astChrSub -* prologue. Note, this function differs from astChrSub in that any -* equals signs (=) in the regular expression are treated literally. -* n -* Address of an int in which to return the number of sub-strings -* returned. -* matchend -* A pointer to a location at which to return a pointer to the -* character that follows the last character within the supplied test -* string that matched any parenthesises sub-section of "regexp". A -* NULL pointer is returned if no matches were found. A NULL pointer -* may be supplied if the location of the last matching character is -* not needed. - -* Returned Value: -* astChrSplitRE() -* A pointer to a dynamically allocated array containing "*n" elements. -* Each element is a pointer to a dynamically allocated character -* string containing a sub-string extracted from the supplied string. -* The array itself, and the strings within it, should all be freed -* using astFree when no longer needed. - -* Notes: -* - If a parenthesised sub-string in the regular expression is matched -* by more than one sub-string within the test string, then only the -* first is returned. To return multiple matches, the regular -* expression should include multiple copies of the parenthesised -* sub-string (for instance, separated by ".+?" if the intervening -* string is immaterial). -* - A NULL pointer is returned if this function is invoked with the -* global error status set or if it should fail for any reason, or if -* the supplied string contains no words. -*-- -*/ - -/* Local Variables: */ - char **result; - char *temp; - int i; - -/* Initialise returned values. */ - *n = 0; - result = NULL; - -/* Check global status */ - if( !astOK ) return result; - -/* Call ChrSuber to do the work, saving the matching parts of the test - string. */ - temp = ChrSuber( str, regexp, NULL, 0, 1, &result, n, matchend, status ); - if( temp ) { - temp = astFree( temp ); - -/* Free all results if no match was found. */ - } else if( result ) { - for( i = 0; i < *n; i++ ) result[ i ] = astFree( result[ i ] ); - result = astFree( result ); - *n = 0; - } - -/* Return the result */ - return result; -} - -char *ChrSuber( const char *test, const char *pattern, const char *subs[], - int nsub, int ignore_equals, char ***parts, int *npart, - const char **matchend, int *status ){ -/* -* Name: -* ChrSuber - -* Purpose: -* Performs substitutions on a supplied string. - -* Type: -* Private function. - -* Synopsis: -* #include "memory.h" -* char *ChrSuber( const char *test, const char *pattern, -* const char *subs[], int nsub, int ignore_equals, -* char ***parts, int *npart, const char **matchend, -* int *status ) - -* Description: -* This function performs the work for astChrSub and astChrSplitRE. - -* Parameters: -* test -* The string to be tested. -* pattern -* The template string. See "Template Syntax:" in the astChrSub - prologue. -* subs -* An array of strings that are to replace the sections of the test -* string that match each parenthesised sub-string in "pattern". The -* first element of "subs" replaces the part of the test string that -* matches the first parenthesised sub-string in the template, etc. -* -* If "nsub" is zero, then the "subs" pointer is ignored. In this -* case, and if parameter "ignore_equals" is zero, substitution strings -* may be specified by appended them to the end of the "pattern" string, -* separated by "=" characters -* nsub -* The number of substitution strings supplied in array "subs". -* ignore_equals -* If non-zero, any equals signs in the supplied pattern are -* treated literally, rather than being used to split the template -* from any substitution strigs. -* parts -* Address of a location at which to return a pointer to an array -* of character string pointers. The strings are the sub-sections -* of "test" that matched the parenthesised sub-sections of -* "template". The array will have "*npart" elements. Ignored if NULL. -* npart -* Address of a location at which to return the length of the -* "parts" array. Ignored if "parts" is NULL. -* matchend -* A pointer to a location at which to return a pointer to the -* character that follows the last character within the supplied test -* string that matched any parenthesises sub-section of "regexp". A -* NULL pointer is returned if no matches were found. A NULL pointer -* may be supplied if the location of the last matching character is -* not needed. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* A pointer to a dynamically allocated string holding the result -* of the substitutions, or NULL if the test string does not match -* the template string. This string should be freed using astFree -* when no longer needed. If no substituions are specified then a -* copy of the test string is returned if it matches the template. - -* Notes: -* - A NULL pointer is returned if this function is invoked with the -* global error status set or if it should fail for any reason, or if -* the supplied test string does not match the template. - -*/ - -/* Local Variables: */ - char **sections; - char **temps; - char *cptr; - char *result; - char *temp; - char *template; - int i; - int nsec; - int ntemp; - size_t tlen; - -/* Initialise */ - result = NULL; - if( parts ) *npart = 0; - -/* Check global status */ - if( !astOK ) return result; - -/* If required, split the total "pattern" string into sections, using - (unescaped) "=" characters as the delimiter. The first section is the - actual template, and each subsequent section (if any) holds a - substitution string. */ - if( ! ignore_equals ) { - sections = astChrSplitC( pattern, '=', &nsec ); - -/* If equals signs are being treated literally, just take a copy of the - supplied pattern. */ - } else { - cptr = astStore( NULL, pattern, strlen( pattern ) + 1 ); - sections = &cptr; - nsec = 1; - } - - if( sections ) { - -/* If the caller did not provide any substitution strings, use the ones - appended to the end of the pattern string (if any). */ - if( nsub == 0 ) { - subs = (void *) ( sections + 1 ); - nsub = nsec - 1; - } - -/* Split the template section into sub-sections, using (unescaped) "|" - characters as the delimiter. Each sub-section is an alternate pattern - matching template. */ - temps = astChrSplitC( sections[ 0 ], '|', &ntemp ); - - } else { - temps = 0; - ntemp = 0; - } - -/* Loop round each template until all templates have been checked or a - match occurs.. */ - for( i = 0; i < ntemp && !result; i++ ) { - temp = temps[ i ]; - tlen = strlen( temp ); - -/* If the template starts with "^" or "(^", remove the "^" character. - Otherwise insert ".*?" at the start. Allocate three extra characters - in case we later need to add ".*?" to the end of the string. */ - if( temp[ 0 ] == '^' ) { - template = astMalloc( tlen + 3 ); - if( template ) { - strcpy( template, temp + 1 ); - tlen--; - } - - } else if( temp[ 0 ] == '(' && temp[ 1 ] == '^') { - template = astMalloc( tlen + 3 ); - if( template ) { - template[ 0 ] = '('; - strcpy( template + 1, temp + 2 ); - tlen--; - } - - } else { - template = astMalloc( tlen + 7 ); - if( template ) { - template[ 0 ] = '.'; - template[ 1 ] = '*'; - template[ 2 ] = '?'; - strcpy( template + 3, temp ); - tlen += 3; - } - } - -/* If the pattern ends with "$" or "$)", remove the "$" character. Otherwise - insert ".*?" at the end. */ - if( template[ tlen - 1 ] == '$' ) { - tlen--; - - } else if( template[ tlen - 2 ] == '$' && template[ tlen - 1 ] == ')' ) { - template[ tlen - 2 ] = ')'; - tlen--; - - } else { - template[ tlen ] = '.'; - template[ tlen + 1 ] = '*'; - template[ tlen + 2 ] = '?'; - tlen += 3; - } - -/* Ensure the string is terminated */ - template[ tlen ] = 0; - -/* See if the test string matches the current template. */ - result = ChrMatcher( test, test + strlen( test ), template, pattern, - subs, nsub, 0, 1, parts, npart, matchend, status ); - -/* Free resources. */ - template = astFree( template ); - } - - if( temps ) { - for( i = 0; i < ntemp; i++ ) temps[ i ] = astFree( temps[ i ] ); - temps = astFree( temps ); - } - - if( sections ) { - for( i = 0; i < nsec; i++ ) sections[ i ] = astFree( sections[ i ] ); - if( ! ignore_equals ) sections = astFree( sections ); - } - -/* Return a NULL pointer if an error has occurred. */ - if( !astOK ) result = astFree( result ); - -/* Return the result */ - return result; -} - -char *astChrSub_( const char *test, const char *pattern, const char *subs[], - int nsub, int *status ){ -/* -*++ -* Name: -c astChrSub -f AST_CHRSUB - -* Purpose: -* Performs substitutions on a supplied string. - -* Type: -* Public function. - -* Synopsis: -c #include "memory.h" -c char *astChrSub( const char *test, const char *pattern, -c const char *subs[], int nsub ) -f MATCH = AST_CHRSUB( TEST, PATTERN, RESULT, STATUS ) - -* Description: -* This function checks a supplied test string to see if it matches a -* supplied template. If it does, specified sub-sections of the test -* string may optionally be replaced by supplied substitution strings. -* The resulting string is returned. - -* Parameters: -c test -f TEST = CHARACTER * ( * ) (Given) -* The string to be tested. -* pattern -f PATTERN = CHARACTER * ( * ) (Given) -* The template string. See "Template Syntax:" below. -* subs -* An array of strings that are to replace the sections of the test -* string that match each parenthesised sub-string in "pattern". The -* first element of "subs" replaces the part of the test string that -* matches the first parenthesised sub-string in the template, etc. -* -* If "nsub" is zero, then the "subs" pointer is ignored. In this -* case, substitution strings may be specified by appended them to -* the end of the "pattern" string, separated by "=" characters. -* Note, if you need to include a literal "=" character in the -* pattern, precede it by an escape "\" character. -* nsub -* The number of substitution strings supplied in array "subs". -f RESULT = CHARACTER * ( * ) (Returned) -f Returned holding the result of the substitutions. If the test -f string does not match the template, then a blank string is -f returned. - -* Returned Value: -c astChrSub() -c A pointer to a dynamically allocated string holding the result -c of the substitutions, or NULL if the test string does not match -c the template string. This string should be freed using astFree -c when no longer needed. If no substituions are specified then a -c copy of the test string is returned if it matches the template. -f AST_CHRSUB = LOGICAL -f .TRUE. if the test string matched the supplied template, and -f .FALSE. otherwise. - -* Template Syntax: -* The template syntax is a minimal form of regular expression, The -* quantifiers allowed are "*", "?", "+", "{n}", "*?" and "+?" (the -* last two are non-greedy - they match the minimum length possible -* that still gives an overall match to the template). The only -* constraints allowed are "^" and "$". The following atoms are allowed: -* -* - [chars]: Matches any of the specified characters. -* -* - [^chars]: Matches anything but the specified characters. -* -* - .: Matches any single character. -* -* - x: Matches the character x so long as x has no other significance. -* -* - \x: Always matches the character x (except for [dDsSwW]). -* -* - \d: Matches a single digit. -* -* - \D: Matches anything but a single digit. -* -* - \w: Matches any alphanumeric character, and "_". -* -* - \W: Matches anything but alphanumeric characters, and "_". -* -* - \s: Matches white space. -* -* - \S: Matches anything but white space. -* -* Note, minus signs ("-") within brackets have no special significance, -* so ranges of characters must be specified explicitly. -* -* Multiple template strings can be concatenated, using the "|" -* character to separate them. The test string is compared against -* each one in turn until a match is found. -* -c Parentheses are used within each template to identify sub-strings -c that are to be replaced by the strings supplied in "sub". -c -c If "nsub" is supplied as zero, then substitution strings may be -c specified by appended them to the end of the "pattern" string, -c separated by "=" characters. If "nsub" is not zero, then any -c substitution strings appended to the end of "pattern" are ignored. -f -f Parentheses are used within each template to identify sub-strings -f that are to be replaced by new strings. The new strings are -f specified by appended them to the end of the "pattern" string, -f separated by "=" characters. -* -c Each element of "subs" -f Each new string -* may contain a reference to a token of the -* form "$1", "$2", etc. The "$1" token will be replaced by the part -* of the test string that matched the first parenthesised sub-string -* in "pattern". The "$2" token will be replaced by the part of the -* test string that matched the second parenthesised sub-string in -* "pattern", etc. -* - -c Notes: -c - A NULL pointer is returned if this function is invoked with the -c global error status set or if it should fail for any reason, or if -c the supplied test string does not match the template. - -*-- -*/ - -/* Call ChrSuber to do the work, without saving the matching parts of the - test string. */ - return ChrSuber( test, pattern, subs, nsub, 0, NULL, NULL, NULL, status ); -} - -void astChrTrunc_( char *text, int *status ){ -/* -*++ -* Name: -* astChrTrunc - -* Purpose: -* Terminate a string to exclude trailing spaces. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astChrTrunc( char *text ) - -* Description: -* This function pokes a null character into the supplied string to -* remove any trailing spaces. - -* Parameters: -* text -* The string to be truncated. - -*-- -*/ - if( !text ) return; - text[ astChrLen( text ) ] = 0; -} - -void astFandl_( const char *text, size_t start, size_t end, - size_t *f, size_t *l, int *status ){ -/* -*++ -* Name: -* astFandl - -* Purpose: -* Identify the used section of a string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astFandl_( const char *text, size_t start, size_t end, -* size_t *f, size_t *l ) - -* Description: -* This function searches a specified section of the supplied text -* for non-space characters, returning the indices of the first and -* last. - -* Parameters: -* text -* The text string to be seached. -* start -* The zero-based index of the first character to be checked within -* "text". The whole string is used if "start" is greater than "end". -* end -* The zero-based index of the last character to be checked within -* "text". The whole string is used if "start" is greater than "end". -* The last character is used if "end" is greater than the length -* of the string. -* f -* Returned holding the zero-based index of the first non-space -* character. Ignored if NULL. -* l -* Returned holding the zero-based index of the last non-space -* character. Ignored if NULL. - -* Notes: -* - "f" is returned greater than "l" if the specified section of the -* string is entirely blank. -*-- -*/ -/* Local Variables: */ - size_t nct; - const char *pstart; - const char *pend; - -/* Initialise. */ - if( f ) *f = 1; - if( l ) *l = 0; - -/* Check the global error status. Also check a text string was supplied. */ - if ( !astOK || !text ) return; - -/* Get the total length of the supplied string, including any trailing blanks - but excluding the terminating null. */ - nct = strlen( text ); - -/* Get the actual start and end positions to use. */ - if( start > end ) { - start = 0; - end = nct - 1; - } else if( end >= nct ) { - end = nct - 1; - } - -/* Check there is some text to search. */ - if( start <= end ) { - -/* If we want the position of the first non-space... */ - if( f ) { - -/* Move forward through all the characters in the substring to be searched. - Break when the first non-space is found. */ - pend = text + end; - pstart = text + start - 1; - while( ++pstart <= pend ){ - if( *pstart != ' ' ) { - *f = pstart - text; - break; - } - } - } - -/* If we want the position of the last non-space... */ - if( l ) { - -/* Move backwards through all the characters in the substring to be - searched. Break when the first non-space is found. */ - pend = text + end + 1; - pstart = text + start; - while( --pend >= pstart ) { - if( *pend != ' ' ) { - *l = pend - text; - break; - } - } - } - } -} - -void *astFree_( void *ptr, int *status ) { -/* -*++ -* Name: -* astFree - -* Purpose: -* Free previously allocated memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astFree( void *ptr ) - -* Description: -* This function frees memory that has previouly been dynamically -* allocated using one of the AST memory function. - -* Parameters: -* ptr -* Pointer to previously allocated memory. An error will result -* if the memory has not previously been allocated by another -* function in this module. However, a NULL pointer value is -* accepted (without error) as indicating that no memory has yet -* been allocated, so that no action is required. - -* Returned Value: -* astFree() -* Always returns a NULL pointer. - -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - Memory *mem; /* Pointer to memory header */ - int isdynamic; /* Is the memory dynamically allocated? */ - size_t size; /* The usable size of the memory block */ - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* If the incoming pointer is NULL, do nothing. Otherwise, check if it - points at dynamically allocated memory (IsDynamic sets the global - error status if it does not). */ - if( ptr ) { - IS_DYNAMIC( ptr, isdynamic ); - } else { - isdynamic = 0; - } - if ( isdynamic ) { - -/* If OK, obtain a pointer to the memory header. */ - mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); - -#ifdef MEM_DEBUG - DeIssue( mem, status ); -#endif - -/* If the memory block is small enough, and the cache is being used, put it - into the cache rather than freeing it, so that it can be reused. */ - size = mem->size; - if( use_cache && size <= MXCSIZE ) { - mem->next = cache[ size ]; - cache[ size ] = mem; - -/* Set the size to zero to indicate that the memory block has been freed. - The size of the block is implied by the Cache element it is stored in. */ - mem->size = (size_t) 0; - -/* Simply free other memory blocks, clearing the "magic number" and size - values it contains. This helps prevent accidental re-use of the memory. */ - } else { - mem->magic = (unsigned long) 0; - mem->size = (size_t) 0; - -/* Free the allocated memory. */ - FREE( mem ); - } - } - -/* Always return a NULL pointer. */ - return NULL; - -} - -void *astFreeDouble_( void *ptr, int *status ) { -/* -*++ -* Name: -* astFreeDouble - -* Purpose: -* Free previously double allocated memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astFreeDouble( void *ptr ) - -* Description: -* This function frees memory that has previouly been dynamically -* allocated using one of the AST memory function. It assumes that -* the supplied pointer is a pointer to an array of pointers. Each -* of these pointers is first freed, and then the supplied pointer -* is freed. -* -* Note, this routine should not be used with arrays allocated -* by astGrow since astGrow over-allocates and so there may be -* non-initialised pointers at the end of the array. - -* Parameters: -* ptr -* Pointer to previously allocated memory. An error will result -* if the memory has not previously been allocated by another -* function in this module. However, a NULL pointer value is -* accepted (without error) as indicating that no memory has yet -* been allocated, so that no action is required. - -* Returned Value: -* astFreeDouble() -* Always returns a NULL pointer. - -*-- -*/ - -/* Local Variables: */ - int iptr; /* Index of sub-pointer */ - int nptr; /* Number of sub-pointers */ - size_t size; /* The usable size of the memory block */ - void **ptrs; /* Pointer to array of pointers */ - -/* Check a pointer was supplied. */ - if( ! ptr ) return NULL; - -/* Get the size of the memory area. */ - size = astSizeOf( ptr ); - -/* Get the number of points this amount of memory could hold. */ - nptr = size/sizeof( void * ); - -/* Report an error if the size is not an integer multiple of an address - size. */ - if( nptr*sizeof( void * ) != size ) { - astError( AST__MEMIN, "Invalid attempt to free double allocated " - "memory: the supplied memory size (%lu bytes) is not " - "an integer multiple of %lu.", status, size, - sizeof( void * ) ); - - } else { - -/* Free each sub-pointer. */ - ptrs = (void **) ptr; - for( iptr = 0; iptr < nptr; iptr++ ) { - ptrs[ iptr ] = astFree( ptrs[ iptr ] ); - } - -/* Free the supplied pointer. */ - ptr = astFree( ptr ); - } - -/* Always return a NULL pointer. */ - return NULL; -} - -void *astGrow_( void *ptr, int n, size_t size, int *status ) { -/* -*++ -* Name: -* astGrow - -* Purpose: -* Allocate memory for an adjustable array. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astGrow( void *ptr, int n, size_t size ) - -* Description: -* This function allocates memory in which to store an array of -* data whose eventual size is unknown. It should be invoked -* whenever a new array size is determined and will appropriately -* increase the amount of memory allocated when necessary. In -* general, it will over-allocate in anticipation of future growth -* so that the amount of memory does not need adjusting on every -* invocation. - -* Parameters: -* ptr -* Pointer to previously allocated memory (or NULL if none has -* yet been allocated). -* n -* Number of array elements to be stored (may be zero). -* size -* The size of each array element. - -* Returned Value: -* astGrow() -* If the memory was allocated successfully, a pointer to the start -* of the possibly new memory region is returned (this may be the -* same as the original pointer). - -* Notes: -* - When new memory is allocated, the existing contents are preserved. -* - This function does not free memory once it is allocated, so -* the size allocated grows to accommodate the maximum size of the -* array (or "high water mark"). Other memory handling routines may -* be used to free the memory (or alter its size) if necessary. -* - If this function is invoked with the global error status set, -* or if it fails for any reason, the original pointer value is -* returned and the memory contents are unchanged. -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - int isdynamic; /* Is the memory dynamically allocated? */ - Memory *mem; /* Pointer to memory header */ - size_t newsize; /* New size to allocate */ - void *new; /* Result pointer */ - -/* Check the global error status. */ - if ( !astOK ) return ptr; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Initialise. */ - new = ptr; - -/* Calculate the total size of memory needed. */ - size *= (size_t) n; - -/* If no memory has yet been allocated, allocate exactly the amount - required. */ - if ( !ptr ) { - new = astMalloc( size ); - -/* Otherwise, check that the incoming pointer identifies previously - allocated memory. */ - } else { - IS_DYNAMIC( ptr, isdynamic ); - if ( isdynamic ) { - -/* Obtain a pointer to the memory header and check if the new size - exceeds that already allocated. */ - mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); - if ( mem->size < size ) { - -/* If so, calculate a possible new size by doubling the old - size. Increase this further if necessary. */ - newsize = mem->size * ( (size_t) 2 ); - if ( size > newsize ) newsize = size; - -/* Re-allocate the memory. */ - new = astRealloc( ptr, newsize ); - } - } - } - -/* Return the result. */ - return new; -} - -int astIsDynamic_( const void *ptr, int *status ) { -/* -*++ -* Name: -* astIsDynamic - -* Purpose: -* Returns a flag indicating if memory was allocated dynamically. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* int astIsDynamic( const void *ptr ) - -* Description: -* This function takes a pointer to a region of memory and tests if -* the memory has previously been dynamically allocated using other -* functions from this module. It does this by checking for the -* presence of a "magic" number in the header which precedes the -* allocated memory. If the magic number is not present (or the -* pointer is invalid for any other reason), zero is returned. -* Otherwise 1 is returned. - -* Parameters: -* ptr -* Pointer to test. - -* Returned Value: -* astIsDynamic() -* Non-zero if the memory was allocated dynamically. Zero is returned -* if the supplied pointer is NULL. - -* Notes: -* - A value of zero is returned if this function is invoked with -* the global error status set, or if it fails for any reason. -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - Memory *isdynmem; /* Pointer to memory header */ \ - -/* Check the global error status and the supplied pointer. */ - if ( !astOK || ! ptr ) return 0; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Derive a pointer to the memory header that precedes the - supplied region of memory. */ - isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); - -/* Check if the "magic number" in the header is valid, returning non-zero - if it is. */ - return ( isdynmem->magic == MAGIC( isdynmem, isdynmem->size ) ); -} - -void *astMalloc_( size_t size, int init, int *status ) { -/* -*++ -* Name: -* astMalloc - -* Purpose: -* Allocate memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astMalloc( size_t size ) - -* Description: -* This function allocates memory in a similar manner to the -* standard C "malloc" function, but with improved security -* (against memory leaks, etc.) and with error reporting. It also -* allows zero-sized memory allocation (without error), resulting -* in a NULL returned pointer value. - -* Parameters: -* size -* The size of the memory region required (may be zero). - -* Returned Value: -* astMalloc() -* If successful, the function returns a pointer to the start of -* the allocated memory region. If the size allocated is zero, this -* will be a NULL pointer. - -* Notes: -* - A pointer value of NULL is returned if this function is -* invoked with the global error status set or if it fails for any -* reason. -*-- - -* astMallocInit: -* - This function can be invoked using either the public astMalloc -* macro documented above, or the private astMallocInit macro. -* astMallocInit has the same interface as astMalloc, but calls calloc -* rather than malloc so that the allocated memory is filled with zeros. -* Ideally, we should use an extra layer in the calling heirarchy to -* remove the hidden "init" argument in the astMalloc_ interface, but -* astMalloc is time-critical in many situations and so it is included -* as a "hidden" argument. - -*/ - -/* Local Constants: */ -#define ERRBUF_LEN 80 - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ - char *errstat; /* Pointer to system error message */ - Memory *mem; /* Pointer to space allocated by malloc */ - void *result; /* Returned pointer */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* If the size is greater than zero, either get a previously - allocated memory block from the cache, or attempt to use malloc - to allocate the memory, including space for the header structure. */ - if ( size > (size_t ) 0 ) { - -/* If the cache is being used and a cached memory block of the required size - is available, remove it from the cache array and use it. */ - mem = ( use_cache && size <= MXCSIZE ) ? cache[ size ] : NULL; - if( mem ) { - cache[ size ] = mem->next; - mem->next = NULL; - mem->size = (size_t) size; - -/* Initialise the memory (but not the header) if required. */ - if( init ) (void) memset( (char *) mem + SIZEOF_MEMORY, 0, size ); - -/* Otherwise, allocate a new memory block using "malloc" or "calloc". */ - } else { - if( init ) { - mem = CALLOC( 1, SIZEOF_MEMORY + size ); - } else { - mem = MALLOC( SIZEOF_MEMORY + size ); - } - -/* Report an error if malloc failed. */ - if ( !mem ) { - -#if HAVE_STRERROR_R - strerror_r( errno, errbuf, ERRBUF_LEN ); - errstat = errbuf; -#else - errstat = strerror( errno ); -#endif - astError( AST__NOMEM, "malloc: %s", status, errstat ); - astError( AST__NOMEM, "Failed to allocate %lu bytes of memory.", status, - (unsigned long) size ); - -/* If successful, set the "magic number" in the header and also store - the size. */ - } else { - mem->magic = MAGIC( mem, size ); - mem->size = size; - mem->next = NULL; - -#ifdef MEM_DEBUG - mem->id = -1; - mem->prev = NULL; -#endif - - } - } - -/* Do nothing more if no memory is being returned. */ - if( mem ) { - -#ifdef MEM_DEBUG - Issue( mem, status ); -#endif - -/* Increment the memory pointer to the start of the region of - allocated memory to be used by the caller.*/ - result = mem; - result = (char *) result + SIZEOF_MEMORY; - } - } - -/* Return the result. */ - return result; -} -#undef ERRBUF_LEN - -static char *ChrMatcher( const char *test, const char *end, const char *template, - const char *pattern, const char *subs[], int nsub, - int ignore, int expdoll, char ***mres, int *mlen, - const char **matchend, int *status ){ -/* -* Name: -* ChrMatcher - -* Purpose: -* Performs substitutions on a supplied string. - -* Type: -* Private function. - -* Synopsis: -* #include "memory.h" -* char *ChrMatcher( const char *test, const char *end, const char *template, -* const char *pattern, const char *subs[], int nsub, -* int ignore, int expdoll, char ***mres, int *mlen, -* const char **matchend, int *status ) - -* Description: -* This function is performs most of the work for astChrSub. - -* Parameters: -* test -* The string to be tested. -* end -* Pointer to the terminating null character at the end of "test". -* template -* The template string. See astChrSub for details. -* pattern -* The user supplied "pattern" string (only used for error messages). -* subs -* An array of strings holding the values that are to be substituted -* into each parenthesised substring in "test". -* nsub -* The length of the subs arrays. -* ignore -* If non-zero, then no substitutions are performed, and any -* inbalance in parentheses is ignored. -* expdoll -* If non-zero, then any "$1", "$2", etc, tokens in the -* substitution fields will be repalced by the corresponding fields -* in the test string. -* mres -* Address of a location at which to return a pointer to an array -* of character string pointers. The strings are the sub-sections -* of "test" that matched the parenthesised sub-sections of -* "template". The array will have "*m" elements. Ignored if NULL. -* mlen -* Address of a location at which to return the length of the -* returned "mres" array. Ignored if "mres" is NULL. -* matchend -* A pointer to a location at which to return a pointer to the -* character that follows the last character within the supplied test -* string that matched any parenthesises sub-section of "regexp". A -* NULL pointer is returned if no matches were found. A NULL pointer -* may be supplied if the location of the last matching character is -* not needed. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* A pointer to a dynamically allocated string holding the result of the -* substitutions, or NULL if the test string does not match the template -* string. This string should be freed using astFree when no longer -* needed. - -* Notes: -* - A NULL pointer is returned if this function is invoked with the -* global error status set or if it should fail for any reason, or if -* the supplied test string does not match the template. -*/ - -/* Local Variables: */ - char **matches; - char **newsubs; - char **parts; - char *allowed; - char *r; - char *result; - char *sres; - char *stest; - char stemp[10]; - const char *aaa; - const char *aa; - const char *a; - const char *b; - int allow; - int dollar; - int end_sub; - int greedy; - int i; - int in_sub; - int ipart; - int match; - int matchlen; - int max_na; - int min_na; - int na; - int nb; - int nmatch; - int npart; - int partlen; - int reslen; - int start_sub; - size_t stl; - -/* Initialisation. */ - if( mres ) *mlen = 0; - aaa = NULL; - if( matchend ) *matchend = NULL; - -/* Check the global error status. */ - if( !astOK ) return NULL; - -/* more initialisation. */ - result = NULL; - allowed = NULL; - -/* Get memory for a set of pointers to copies of the test sub-strings that - fall between the sub-strings being replaced. */ - parts = astMalloc( sizeof( char *)*(size_t) ( nsub + 1 ) ); - -/* Get memory for a set of pointers to copies of the test sub-strings that - match the parenthesised sub-strings in the template. */ - matches = astMalloc( sizeof( char *)*(size_t) nsub ); - -/* Initialise pointers to the next test and template characters to read. */ - a = test; - b = template; - -/* Initialise the pointer to the start of the previous test character */ - aa = test; - -/* Assume the test string matches the template. */ - match = 1; - -/* The template pointer is not currently in a substitution field. */ - in_sub = 0; - -/* Initialise the number of substitution fields found so far. */ - npart = 0; - nmatch = 0; - -/* Loop until we have reached the end of either the test or template - string. We break out of the loop early if we find that the test string - does not match the template string. */ - while( match && *a && *b ) { - -/* Examine the string at the start of the template string. This returns a - string of allowed (or disallowed) characters that the next test character - can match, the number of template characters consumed, the minimum number - of test characters that must match the allowed character set, and a flag - indicating if the number of matching test characters can exceed the - minimum number or must be exactly equal to the minimum number. */ - allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, - &min_na, &max_na, &start_sub, &end_sub, - &greedy, status ); - if( !astOK ) break; - -/* Increment the the pointer to the next template character. */ - b += nb; - -/* If the leading field in the template indicates the start of a - substitution field, record the test string up to the current point. */ - if( start_sub ){ - -/* Do nothing if we are ignoring substitutions. */ - if( ! ignore ){ - -/* Store a pointer to the first test character that matches the - substitution template. */ - aaa = a; - -/* Report an error and abort if we are already inside a substitution - field */ - if( in_sub ) { - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "missing ')'.", status, pattern ); - break; - } - -/* Indicate that we are now in a substitution field. */ - in_sub = 1; - -/* If possible, store a copy of the test string that started at the end - of the previous substitution field and ends at the current point. - First ensure the "parts" array is large enough since the string may - contain more than "nsub" parenthesised sub-strings. */ - parts = astGrow( parts, npart + 1, sizeof( char * ) ); - if( parts ) { - partlen = ( a - aa ); - parts[ npart ] = astStore( NULL, aa, partlen + 1 ); - if( parts[ npart ] ) { - parts[ npart ][ partlen ] = 0; - npart++; - } - } - } - -/* If the leading field in the template indicates the end of a - substitution field, initialise the start of the next part of the test - string. */ - } else if( end_sub ){ - -/* Do nothing if we are ignoring substitutions. */ - if( ! ignore ){ - -/* Report an error and abort if we are not currently in a substitution - field. */ - if( ! in_sub ) { - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "missing '('.", status, pattern ); - break; - } - -/* We are no longer in a substitution field. */ - in_sub = 0; - -/* If possible, store a copy of the test string that matched the - substitution template. */ - matches = astGrow( matches, nmatch + 1, sizeof( char * ) ); - if( matches ) { - matchlen = ( a - aaa ); - matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 ); - if( matches[ nmatch ] ) { - matches[ nmatch ][ matchlen ] = 0; - nmatch++; - if( matchend ) *matchend = a; - } - } - -/* Record the start of the next test string part. */ - aa = a; - } - -/* Otherwise, find how many characters at the front of the test string - match the leading field in the template. Find the number of leading - characters in the test string that are contained in the set of - characters allowed by the leading field in the template. */ - } else { - if( !allowed ) { - na = strlen( a ); - - } else if( allow ) { - na = strspn( a, allowed ); - - } else { - na = strcspn( a, allowed ); - } - -/* Check that the minmum number of matching characters is available. */ - if( na < min_na ){ - match = 0; - break; - } - -/* Dont match more characters than are needed. */ - if( na > max_na ) na = max_na; - -/* We cannot match more characters than are available. */ - if( na < max_na ) max_na = na; - -/* If we have exhausted the template, match the maximum number of - characters. */ - if( ! *b ) { - na = max_na; - -/* If we still have a match, we may choose to use fewer than the max - allowed number of test characters in order to allow the next template - field to be matched. Don't need to do this if we have reached the end - of the template. */ - } else if( max_na > min_na ) { - match = 0; - -/* If a greedy quantifier was used, try using a decreasing number of test - characters, starting at the maximum allowed and decreasing down to the - minimum, until a number is found which allows the rest of the string - to be matched. */ - if( greedy ) { - for( na = max_na; na >= min_na; na-- ) { - r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0, - NULL, NULL, NULL, status ); - if( r ) { - match = 1; - r = astFree( r ); - break; - } - } - -/* If a non-greedy quantifier was used, try using an increasing number of - test characters, starting at the minimum allowed and increasing up to - the maximum, until a number is found which allows the rest of the string - to be matched. */ - } else { - for( na = min_na; na <= max_na; na++ ) { - r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0, - NULL, NULL, NULL, status ); - if( r ) { - match = 1; - r = astFree( r ); - break; - } - } - } - } - -/* Increment the the pointer to the next test character. */ - a += na; - if( a > end ) a = end; - } - } - -/* If the test string is finished but the template string is not, see if - the next part of the template string will match a null test string. - But ignore the ends of substitution fields. */ - if( !*a && *b && match ) { - while( *b && *b != ')' ) { - allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, - &min_na, &max_na, &start_sub, &end_sub, - &greedy, status ); - b += nb; - allowed = astFree( allowed ); - - if( min_na > 0 ) { - match = 0; - break; - } - } - } - -/* If the next character in the template is a closing parenthesis, then - we are finishing a substitution field. */ - if( match && *b == ')' ) { - -/*Check we are not ignoring substitutions. */ - if( ! ignore ){ - -/* Report an error and abort if we are not currently in a substitution - field. */ - if( ! in_sub ) { - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "missing '('.", status, pattern ); - } - -/* We are no longer in a substitution field. */ - in_sub = 0; - -/* If possible, store a copy of the test string that matched the - substitution field. */ - matches = astGrow( matches, nmatch + 1, sizeof( char * ) ); - if( matches ) { - matchlen = ( a - aaa ); - matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 ); - if( matches[ nmatch ] ) { - matches[ nmatch ][ matchlen ] = 0; - nmatch++; - if( matchend ) *matchend = a; - } - } - - aa = a; - } - b++; - } - -/* If the test string is finished but the template string is not, see if - the rest of the template string will match a null test string. */ - if( !*a && *b && match ) { - - while( *b ) { - allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow, - &min_na, &max_na, &start_sub, &end_sub, - &greedy, status ); - b += nb; - allowed = astFree( allowed ); - - if( min_na > 0 ) { - match = 0; - break; - } - } - - } - -/* No match if either string was not used completely. */ - if( *a || *b ) match = 0; - -/* Report an error if we are still inside a substitution field */ - if( match && in_sub && !ignore ) { - astError( AST__BADSUB, "Invalid pattern matching template \"%s\": " - "missing ')'.", status, pattern ); - match = 0; - } - -/* If we have a match, construct the returned string. */ - if( match && parts ) { - -/* Store the test string following the final substitution field. */ - parts = astGrow( parts, npart + 1, sizeof( char * ) ); - if( parts ) { - partlen = ( a - aa ); - parts[ npart ] = astStore( NULL, aa, partlen + 1 ); - if( parts[ npart ] ) { - parts[ npart ][ partlen ] = 0; - npart++; - } - } - -/* If required, expand $1, $2, etc within the replacement strings. */ - if( expdoll) { - newsubs = astMalloc( sizeof( char * )*nsub ); - if( newsubs ) { - for( i = 0; i < nsub; i++ ) { - stl = strlen( subs[ i ] ); - stest = astStore( NULL, subs[ i ], stl + 1 ); - for( dollar = 1; dollar <= nsub; dollar++ ) { - sprintf( stemp, ".*($%d).*", dollar ); - sres = ChrMatcher( stest, stest + stl, stemp, stemp, - (void *) ( matches + dollar - 1 ), - 1, 0, 0, NULL, NULL, NULL, status ); - if( sres ) { - (void) astFree( stest ); - stest = sres; - } - } - newsubs[ i ] = stest; - } - } - - } else { - newsubs = (char **) subs; - } - -/* Concatenate the sub-strings to form the final string. */ - reslen = 0; - for( ipart = 0; ipart < npart - 1; ipart++ ) { - result = astAppendString( result, &reslen, parts[ ipart ] ); - if( ipart < nsub ) { - result = astAppendString( result, &reslen, newsubs[ ipart ] ); - } else { - result = astAppendString( result, &reslen, matches[ ipart ] ); - } - } - result = astAppendString( result, &reslen, parts[ ipart ] ); - -/* Free resources. */ - if( newsubs && newsubs != (char **) subs ) { - for( i = 0; i < nsub; i++ ) { - newsubs[ i ] = astFree( newsubs[ i ] ); - } - newsubs = astFree( newsubs ); - } - } - - allowed = astFree( allowed ); - for( ipart = 0; ipart < npart; ipart++ ) { - parts[ ipart ] = astFree( parts[ ipart ] ); - } - parts = astFree( parts ); - -/* If required, return the array holding the test sub-strings that - matched the parenthesised template sub-strings, together with - the length of the array. Otherwise, free the memory holding these - strings. */ - if( mres ) { - *mres = matches; - *mlen = nmatch; - - } else if( matches ) { - for( i = 0; i < nmatch; i++ ) { - matches[ i ] = astFree( matches[ i ] ); - } - matches = astFree( matches ); - - } - -/* Return the result. */ - return result; -} - -int astMemCaching_( int newval, int *status ){ -/* -*++ -* Name: -* astMemCaching - -* Purpose: -* Controls whether allocated but unused memory is cached in this module. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* int astMemCaching( int newval ) - -* Description: -* This function sets a flag indicating if allocated but unused memory -* should be cached or not. It also returns the original value of the -* flag. -* -* If caching is switched on or off as a result of this call, then the -* current contents of the cache are discarded. -* -* Note, each thread has a separate cache. Calling this function -* affects only the currently executing thread. - -* Parameters: -* newval -* The new value for the MemoryCaching tuning parameter (see -* astTune in objectc.c). If AST__TUNULL is supplied, the current -* value is left unchanged. - -* Returned Value: -* astMemCaching() -* The original value of the MemoryCaching tuning parameter. - -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS - int i; - int result; - Memory *mem; - -#ifdef MEM_DEBUG - int id_list_size; - int *id_list; -#endif - -/* Check the global error status. */ - if ( !astOK ) return 0; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Store the original value of the tuning parameter. */ - result = use_cache; - -/* If a new value is to be set. */ - if( newval != AST__TUNULL ) { - -/* If the cache has been initialised, empty it. */ - if( cache_init ) { - -/* If we are listing the ID of every memory block in the cache, count the - number of blocks in the cache and then allocate an array to store the ID - values in. This is done so that we can sort them before displaying them. */ -#ifdef MEM_DEBUG - if( List_Cache ) { - Memory *next; - - id_list_size = 0; - for( i = 0; i <= MXCSIZE; i++ ) { - next = cache[ i ]; - while( next ) { - id_list_size++; - next = next->next; - } - } - - id_list = MALLOC( sizeof(int)*id_list_size ); - if( !id_list ) { - astError( AST__INTER, "astMemCaching: Cannot allocate %lu " - "bytes of memory", status, (unsigned long)(sizeof(int)*id_list_size) ); - } - - id_list_size = 0; - - } else { - id_list = NULL; - } -#endif - - for( i = 0; i <= MXCSIZE; i++ ) { - while( cache[ i ] ) { - mem = cache[ i ]; - cache[ i ] = mem->next; - mem->size = (size_t) i; - -#ifdef MEM_DEBUG - if( id_list ) { - id_list[ id_list_size++ ] = mem->id; - } -#endif - - FREE( mem ); - } - } - -/* If we are displaying the IDs of memory blocks still in the cache, sort - them using a bubblesort algorithm, then display them. */ -#ifdef MEM_DEBUG - if( id_list ) { - - if( id_list_size == 0 ) { - printf( "Emptying the AST memory cache - (the cache is " - "already empty)\n" ); - - } else { - int sorted, j, t; - - sorted = 0; - for( j = id_list_size - 2; !sorted && j >= 0; j-- ) { - sorted = 1; - for( i = 0; i <= j; i++ ) { - if( id_list[ i ] > id_list[ i + 1 ] ) { - sorted = 0; - t = id_list[ i ]; - id_list[ i ] = id_list[ i + 1 ]; - id_list[ i + 1 ] = t; - } - } - } - - printf( "Emptying the AST memory cache - freeing the " - "following memory blocks: "); - for( i = 0; i < id_list_size; i++ ) printf( "%d ", id_list[ i ] ); - printf( "\n" ); - - } - } -#endif - -/* Otherwise, initialise the cache array to hold a NULL pointer at every - element. */ - } else { - for( i = 0; i <= MXCSIZE; i++ ) cache[ i ] = NULL; - cache_init = 1; - } - -/* Store the new value. */ - use_cache = newval; - - } - -/* Return the original value. */ - return result; -} - -void *astRealloc_( void *ptr, size_t size, int *status ) { -/* -*++ -* Name: -* astRealloc - -* Purpose: -* Change the size of a dynamically allocated region of memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astRealloc( void *ptr, size_t size ) - -* Description: -* This function changes the size of a dynamically allocated region -* of memory, preserving its contents up to the minimum of the old -* and new sizes. This may involve copying the contents to a new -* location, so a new pointer is returned (and the old memory freed -* if necessary). -* -* This function is similar to the standard C "realloc" function -* except that it provides better security against programming -* errors and also supports the allocation of zero-size memory -* regions (indicated by a NULL pointer). - -* Parameters: -* ptr -* Pointer to previously allocated memory (or NULL if the -* previous size of the allocated memory was zero). -* size -* New size required for the memory region. This may be zero, in -* which case a NULL pointer is returned (no error results). It -* should not be negative. - -* Returned Value: -* astRealloc() -* If the memory was reallocated successfully, a pointer to the -* start of the new memory region is returned (this may be the same -* as the original pointer). If size was given as zero, a NULL -* pointer is returned. - -* Notes: -* - If this function is invoked with the error status set, or if -* it fails for any reason, the original pointer value is returned -* and the memory contents are unchanged. Note that this behaviour -* differs from that of the standard C "realloc" function which -* returns NULL if it fails. -*-- -*/ - -/* Local Constants: */ -#define ERRBUF_LEN 80 - -/* Local Variables: */ - astDECLARE_GLOBALS - char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ - char *errstat; /* Pointer to system error message */ - int isdynamic; /* Was memory allocated dynamically? */ - void *result; /* Returned pointer */ - Memory *mem; /* Pointer to memory header */ - -/* Check the global error status. */ - if ( !astOK ) return ptr; - -/* Initialise. */ - result = ptr; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* If a NULL pointer was supplied, use astMalloc to allocate some new - memory. */ - if ( !ptr ) { - result = astMalloc( size ); - -/* Otherwise, check that the pointer supplied points at memory - allocated by a function in this module (IsDynamic sets the global - error status if it does not). */ - } else { - IS_DYNAMIC( ptr, isdynamic ); - if ( isdynamic ) { - -/* Obtain a pointer to the memory header. */ - mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); - -/* If the new size is zero, free the old memory and set a NULL return - pointer value. */ - if ( size == (size_t) 0 ) { - astFree( ptr ); - result = NULL; - -/* Otherwise, reallocate the memory. */ - } else { - -/* If the cache is being used, for small memory blocks, do the equivalent of - mem = REALLOC( mem, SIZEOF_MEMORY + size ); - - using astMalloc, astFree and memcpy explicitly in order to ensure - that the memory blocks are cached. */ - if( use_cache && ( mem->size <= MXCSIZE || size <= MXCSIZE ) ) { - result = astMalloc( size ); - if( result ) { - if( mem->size < size ) { - memcpy( result, ptr, mem->size ); - } else { - memcpy( result, ptr, size ); - } - astFree( ptr ); - - } else { - result = ptr; - } - -/* For other memory blocks simply use realloc. */ - } else { - -#ifdef MEM_DEBUG - DeIssue( mem, status ); -#endif - - mem = REALLOC( mem, SIZEOF_MEMORY + size ); - -/* If this failed, report an error and return the original pointer - value. */ - if ( !mem ) { -#if HAVE_STRERROR_R - strerror_r( errno, errbuf, ERRBUF_LEN ); - errstat = errbuf; -#else - errstat = strerror( errno ); -#endif - astError( AST__NOMEM, "realloc: %s", status, errstat ); - astError( AST__NOMEM, "Failed to reallocate a block of " - "memory to %ld bytes.", status, (long) size ); - -/* If successful, set the new "magic" value and size in the memory - header and obtain a pointer to the start of the region of memory to - be used by the caller. */ - } else { - mem->magic = MAGIC( mem, size ); - mem->size = size; - mem->next = NULL; -#ifdef MEM_DEBUG - mem->id = -1; - mem->prev = NULL; - Issue( mem, status ); -#endif - result = mem; - result = (char *) result + SIZEOF_MEMORY; - } - } - } - } - } - -/* Return the result. */ - return result; -} -#undef ERRBUF_LEN - -void astRemoveLeadingBlanks_( char *string, int *status ) { -/* -*++ -* Name: -* astRemoveLeadingBlanks - -* Purpose: -* Remove any leading white space from a string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void astRemoveLeadingBlanks( char *string ) - -* Description: -* This function moves characters in the supplied string to the left -* in order to remove any leading white space. - -* Parameters: -* string -* Pointer to the string. - -*-- -*/ - -/* Local Variables: */ - char *c, *d; - -/* Check a string has been supplied. */ - if( string ){ - -/* Get a pointer to the first non-white character in the string. */ - c = string; - while( *c && isspace( *c ) ) c++; - -/* Do nothing more if there are no leading spaces. */ - if( c > string ) { - -/* Copy all characters (excluding the trailing null) to the left to - over-write the leading spaces. */ - d = string; - while( *c ) *(d++) = *(c++); - -/* Terminate the returned string. */ - *d = 0; - } - } -} - -size_t astSizeOf_( const void *ptr, int *status ) { -/* -*++ -* Name: -* astSizeOf - -* Purpose: -* Determine the size of a dynamically allocated region of memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* size_t astSizeOf( const void *ptr ) - -* Description: -* This function returns the size of a region of dynamically -* allocated memory. - -* Parameters: -* ptr -* Pointer to dynamically allocated memory (or NULL if the size -* of the allocated memory was zero). - -* Returned Value: -* astSizeOf() -* The allocated size. This will be zero if a NULL pointer was -* supplied (no error will result). - -* Notes: -* - A value of zero is returned if this function is invoked with -* the global error status set, or if it fails for any reason. -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - int isdynamic; /* Was the memory allocated dynamically? */ - size_t size; /* Memory size */ - -/* Check the global error status. */ - if ( !astOK ) return (size_t) 0; - -/* Initialise. */ - size = (size_t) 0; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Check if a non-NULL valid pointer has been given. If so, extract - the memory size from the header which precedes it. */ - if ( ptr ){ - IS_DYNAMIC( ptr, isdynamic ); - if( isdynamic ) size = ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size; - } - -/* Return the result. */ - return size; -} - -static size_t SizeOfMemory( int *status ){ -/* -* Name: -* SizeOfMemory - -* Purpose: -* Returns the size of a Memory structure, padded to an 8 byte -* boundary. - -* Type: -* Private function. - -* Synopsis: -* size_t SizeOfMemory( int *status ) - -* Description: -* This function returns the size of a Memory structure used to -* store header information about any block of memory allocated by this -* module. The returned value may be larger than the actual size of -* the Memory structure in order to ensure that the pointer returned by -* astMalloc etc points to an 8 byte boundary. Failure to do this can -* result in some operating systems having problems. E.g Solaris -* requires this alignment if the returned pointer is going to be used to -* store doubles. - -* Parameters: -* status -* Pointer to the inherited status variable. - -* Returned Value: -* The size to use for a Memory structure. - -* Notes: -* - The returned value is also stored in the module variable -* sizeof_memory. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Get the basic size of a Memory structure. */ - sizeof_memory = sizeof( Memory ); - -/* Now increase the returned value to ensure it is a multiple of 8. Mask - off all but the last 3 bits, xor with 0x7 to get the remainder, add 1 - to make it a multiple of 8 bytes. */ - sizeof_memory += ((sizeof_memory & 0x7) ? ((sizeof_memory & 0x7) ^ 0x7) + 1 : 0); - -/* Return the value */ - return sizeof_memory; - -} - -size_t astTSizeOf_( const void *ptr, int *status ) { -/* -*+ -* Name: -* astTSizeOf - -* Purpose: -* Determine the total size of a dynamically allocated region of memory. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* size_t astTSizeOf( const void *ptr ) - -* Description: -* This function returns the size of a region of dynamically -* allocated memory, including the extra memory used to store -* the header information for the memory block (size and magic number). - -* Parameters: -* ptr -* Pointer to dynamically allocated memory (or NULL if the size -* of the allocated memory was zero). - -* Returned Value: -* The allocated size. This will be zero if a NULL pointer was -* supplied (no error will result). - -* Notes: -* - A value of zero is returned if this function is invoked with -* the global error status set, or if it fails for any reason. -* - This function is documented as protected because it should not -* be invoked by external code. However, it is available via the -* external C interface so that it may be used when writing (e.g.) -* foreign language or graphics interfaces. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - int isdynamic; /* Was the memory allocated dynamically? */ - size_t size; /* Memory size */ - -/* Check the global error status. */ - if ( !astOK ) return (size_t) 0; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Initialise. */ - size = (size_t) 0; - -/* Check if a non-NULL valid pointer has been given. If so, extract - the memory size from the header which precedes it. */ - if ( ptr ){ - IS_DYNAMIC( ptr, isdynamic ); - if( isdynamic ) size = SIZEOF_MEMORY + - ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size; - } - -/* Return the result. */ - return size; -} - -void *astStore_( void *ptr, const void *data, size_t size, int *status ) { -/* -*++ -* Name: -* astStore - -* Purpose: -* Store data in dynamically allocated memory. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* void *astStore( void *ptr, const void *data, size_t size ) - -* Description: -* This function stores data in dynamically allocated memory, -* allocating the memory (or adjusting the size of previously -* allocated memory) to match the amount of data to be stored. - -* Parameters: -* ptr -* Pointer to previously allocated memory (or NULL if none has -* yet been allocated). -* data -* Pointer to the start of the data to be stored. This may be -* given as NULL if there are no data, in which case it will be -* ignored and this function behaves like astRealloc, preserving -* the existing memory contents. -* size -* The total size of the data to be stored and/or the size of -* memory to be allocated. This may be zero, in which case the -* data parameter is ignored, any previously-allocated memory is -* freed and a NULL pointer is returned. - -* Returned Value: -* astStore() -* If the data were stored successfully, a pointer to the start of -* the possibly new memory region is returned (this may be the same -* as the original pointer). If size was given as zero, a NULL -* pointer is returned. - -* Notes: -* - This is a convenience function for use when storing data of -* arbitrary size in memory which is to be allocated -* dynamically. It is appropriate when the size of the data will -* not change frequently because the size of the memory region will -* be adjusted to fit the data on every invocation. -* - If this function is invoked with the error status set, or if -* it fails for any reason, the original pointer value is returned -* and the memory contents are unchanged. -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - int valid; /* Is the memory pointer usable? */ - void *new; /* Pointer to returned memory */ - -/* Check the global error status. */ - if ( !astOK ) return ptr; - -/* If needed, get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Initialise. */ - new = ptr; - -/* If the new size is zero, use astRealloc to free any previously - allocated memory. Also re-allocate the memory if the data pointer - is NULL (in which case we want to preserve its contents). */ - if ( ( size == (size_t) 0 ) || !data ) { - new = astRealloc( ptr, size ); - -/* In other cases, we do not want to preserve any memory - contents. Check if the incoming memory pointer is valid (IsDynamic - sets the global error status if it is not). */ - } else { - if ( !ptr ){ - valid = 1; - } else { - IS_DYNAMIC( ptr, valid ); - } - if( valid ) { - -/* Allocate the new memory. If successful, free the old memory (if - necessary) and copy the data into it. */ - new = astMalloc( size ); - if ( astOK ) { - if ( ptr ) ptr = astFree( ptr ); - (void) memcpy( new, data, size ); - -/* If memory allocation failed, do not free the old memory but return - a pointer to it. */ - } else { - new = ptr; - } - } - } - -/* Return the result. */ - return new; -} - -char *astString_( const char *chars, int nchars, int *status ) { -/* -*++ -* Name: -* astString - -* Purpose: -* Create a C string from an array of characters. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char *astString( const char *chars, int nchars ) - -* Description: -* This function allocates memory to hold a C string and fills the -* string with the sequence of characters supplied. It then -* terminates the string with a null character and returns a -* pointer to its start. The memory used for the string may later -* be de-allocated using astFree. -* -* This function is intended for constructing null terminated C -* strings from arrays of characters which are not null terminated, -* such as when importing a character argument from a Fortran 77 -* program. - -* Parameters: -* chars -* Pointer to the array of characters to be used to fill the string. -* nchars -* The number of characters in the array (zero or more). - -* Returned Value: -* astString() -* If successful, the function returns a pointer to the start of -* the allocated string. If the number of characters is zero, a -* zero-length string is still allocated and a pointer to it is -* returned. - -* Notes: -* - A pointer value of NULL is returned if this function is -* invoked with the global error status set or if it fails for any -* reason. -*-- -*/ - -/* Local Variables: */ - char *result; /* Pointer value to return */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Check that the number of characters in the string is valid and - report an error if it is not. */ - if ( nchars < 0 ) { - astError( AST__NCHIN, "astString: Invalid attempt to allocate a string " - "with %d characters.", status, nchars); - -/* Allocate memory to hold the string. */ - } else { - result = (char *) astMalloc( (size_t) ( nchars + 1 ) ); - -/* If successful, copy the characters into the string. */ - if ( astOK && result ) { - (void) memcpy( result, chars, (size_t) nchars ); - -/* Terminate the string. */ - result[ nchars ] = '\0'; - } - } - -/* Return the result. */ - return result; -} - -char **astStringArray_( const char *chars, int nel, int len, int *status ) { -/* -*++ -* Name: -* astStringArray - -* Purpose: -* Create an array of C strings from an array of characters. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char **astStringArray( const char *chars, int nel, int len ) - -* Description: -* This function turns an array of fixed-length character data into -* a dynamicllay allocated array of null-terminated C strings with -* an index array that may be used to access them. -* -* The array of character data supplied is assumed to hold "nel" -* adjacent fixed-length strings (without terminating nulls), each -* of length "len" characters. This function allocates memory and -* creates a null-terminated copy of each of these strings. It also -* creates an array of "nel" pointers which point at the start of -* each of these new strings. A pointer to this index array is -* returned. -* -* The memory used is allocated in a single block and should later -* be de-allocated using astFree. -s -* Parameters: -* chars -* Pointer to the array of input characters. The number of characters -* in this array should be at least equal to (nel * len). -* nel -* The number of fixed-length strings in the input character -* array. This may be zero but should not be negative. -* len -* The number of characters in each fixed-length input -* string. This may be zero but should not be negative. - -* Returned Value: -* astStringArray() -* A pointer to the start of the index array, which contains "nel" -* pointers pointing at the start of each null-terminated output -* string. -* -* The returned pointer should be passed to astFree to de-allocate -* the memory used when it is no longer required. This will free -* both the index array and the memory used by the strings it -* points at. - -* Notes: -* - A NULL pointer will also be returned if the value of "nel" is -* zero, in which case no memory is allocated. -* - A pointer value of NULL will also be returned if this function -* is invoked with the global error status set or if it fails for -* any reason. -*-- -*/ - -/* Local Variables: */ - char **result; /* Result pointer to return */ - char *out_str; /* Pointer to start of next output string */ - const char *in_str; /* Pointer to start of next input string */ - int i; /* Loop counter for array elements */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Check that the array size is valid and report an error if it is - not. */ - if ( nel < 0 ) { - astError( AST__NELIN, - "astStringArray: Invalid attempt to allocate an array of " - "%d strings.", status, nel ); - -/* If the string length will be used, check that it is valid and - report an error if it is not. */ - } else if ( ( nel > 0 ) && ( len < 0 ) ) { - astError( AST__NCHIN, - "astStringArray: Invalid attempt to allocate an " - "array of strings with %d characters in each.", status, len ); - -/* Allocate memory to hold the array of string pointers plus the - string data (with terminating nulls). */ - } else { - result = astMalloc( sizeof( char * ) * (size_t) nel + - (size_t) ( nel * ( len + 1 ) ) ); - -/* If successful, initialise pointers to the start of the current - input and output strings. */ - if( astOK ){ - in_str = chars; - out_str = (char *) ( result + nel ); - -/* Loop to copy each string. */ - for ( i = 0; i < nel; i++ ) { - (void) memcpy( out_str, in_str, (size_t) len ); - -/* Terminate the output string. */ - out_str[ len ] = '\0'; - -/* Store a pointer to the start of the output string in the array of - character pointers. */ - result[ i ] = out_str; - -/* Increment the pointers to the start of the next string. */ - out_str += len + 1; - in_str += len; - } - } - } - -/* Return the result. */ - return result; -} - -char *astStringCase_( const char *string, int upper, int *status ) { -/* -*++ -* Name: -* astStringCase - -* Purpose: -* Convert a string to upper or lower case. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* char *astStringCase( const char string, int upper ) - -* Description: -* This function converts a supplied string to upper or lower case, -* storing the result in dynamically allocated memory. The astChrCase -* function is similar, but stores the result in a supplied buffer. - -* Parameters: -* string -* Pointer to the null terminated string to be converted. -* upper -* If non-zero, the string is converted to upper case. Otherwise it -* is converted to lower case. - -* Returned Value: -* astStringCase() -* If successful, the function returns a pointer to the start of -* the allocated string. The returned memory should be freed using -* astFree when no longer needed. - -* Notes: -* - A pointer value of NULL is returned if this function is -* invoked with the global error status set or if it fails for any -* reason. -*-- -*/ - -/* Local Variables: */ - char *pout; /* Pointer to next output character */ - char *result; /* Pointer value to return */ - const char *pin; /* Pointer to next input character */ - int i; /* Character index */ - int len; /* String length */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Get the length of the supplied string, excluding the trailing null. */ - len = strlen( string ); - -/* Allocate memory to hold the converted string, plus terminating null. */ - result = (char *) astMalloc( (size_t) ( len + 1 ) ); - -/* If successful, copy the characters into the string, converting each - one to the requested case. */ - if ( result ) { - pin = string; - pout = result; - - if( upper ) { - for( i = 0; i < len; i++ ) { - *(pout++) = toupper( (int) *(pin++) ); - } - - } else { - - for( i = 0; i < len; i++ ) { - *(pout++) = tolower( (int) *(pin++) ); - } - } - -/* Terminate the string. */ - *pout = '\0'; - } - -/* Return the result. */ - return result; -} - -size_t astChrLen_( const char *string, int *status ) { -/* -*++ -* Name: -* astChrLen - -* Purpose: -* Determine the used length of a string. - -* Type: -* Public function. - -* Synopsis: -* #include "memory.h" -* size_t astChrLen( const char *string ) - -* Description: -* This function returns the used length of a string. This excludes any -* trailing white space or non-printable characters (such as the -* trailing null character). - -* Parameters: -* string -* Pointer to the string. - -* Returned Value: -* astChrLen() -* The number of characters in the supplied string, not including the -* trailing newline, and any trailing white-spaces or non-printable -* characters. - -*-- -*/ - -/* Local Variables: */ - const char *c; /* Pointer to the next character to check */ - size_t ret; /* The returned string length */ - -/* Initialise the returned string length. */ - ret = 0; - -/* Check a string has been supplied. */ - if( string ){ - -/* Check each character in turn, starting with the last one. */ - ret = strlen( string ); - c = string + ret - 1; - while( ret ){ - if( isprint( (int) *c ) && !isspace( (int) *c ) ) break; - c--; - ret--; - } - } - -/* Return the answer. */ - return ret; - -} - -int astSscanf_( const char *str, const char *fmt, ...) { -/* -*+ -* Name: -* astSscanf - -* Purpose: -* A wrapper for the ANSI sscanf function. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* int astSscanf( const char *str, const char *fmt, ...) - -* Description: -* This function is a direct plug-in replacement for sscanf. It ensures ANSI -* behaviour is available on all platforms, including those (such as -* MacOS) on which have the native sscanf function exhibits non-ANSI -* behaviour. - -* Parameters: -* str -* Pointer to the string to be scanned. -* fmt -* Pointer to the format string which defines the fields to be -* looked for within "str". -* ... -* Pointers to locations at which to return the value of each -* succesfuly converted field, in the order specified in "fmt". - -* Returned Value: -* The number of fields which were succesfully read from "str". -*- -*/ - -/* Local Variables: */ - char *c; /* Pointer to the next character to check */ - char *newfor; /* Pointer to modified format string */ - const char *d; /* Pointer to the next character to check */ - int *status; /* Pointer to inherited status value */ - int iptr; /* Index into ptr array */ - int lfor; /* No. of characters in format string */ - int lstr; /* No. of characters in scanned string */ - int nc; /* No. of characters read from str */ - int nfld; /* No. of counted field specifiers found so far */ - int nptr; /* Np. of pointers stored */ - int ret; /* The returned number of conversions */ - va_list args; /* Variable argument list pointer */ - void *fptr; /* The next supplied pointer */ - void *ptr[ VMAXFLD ]; /* Array of supplied pointers */ - -/* Initialise the variable argument list pointer. */ - va_start( args, fmt ); - -/* Get a pointer to the integer holding the inherited status value. */ - status = astGetStatusPtr; - -/* Initialise the returned string length. */ - ret = 0; - -/* Check a string and format have been supplied. */ - if( str && fmt ){ - -/* Go through the format string, counting the number of field specifiers which - will return a value, and storing the corresponding points in the ptr - array. */ - nptr = 0; - c = (char *) fmt; - while( *c ) { - -/* Field specifiers are marked by a % sign. */ - if( *c == '%' ) { - -/* Look at the character following the % sign. Quit if the end of the string - has been reached. */ - c++; - if( *c ) { - -/* If the % sign is followed by a "*" or another "%", then there will be no - corresponding pointer in the variable argument list "args". Ignore such - field specifiers. */ - if( *c != '*' && *c != '%' ) { - -/* If possible store the corresponding pointer from the variable argument - list supplied to this function. Report an error if there are too many. */ - if ( nptr < VMAXFLD ) { - ptr[ nptr++ ] = va_arg( args, void *); - -/* If the current field specifier is "%n" the corresponding pointer - should be a pointer to an integer. We initialise the integer to zero. - We need to do this because sscanf does not include "%n" values in the - returned count of succesful conversions, and so there is no sure way - of knowing whether a value has been stored for a "%n" field, and so - whether it is safe to use it as an index into the supplied. */ - if( *c == 'n' ) *( (int *) ptr[ nptr - 1 ] ) = 0; - - } else { - astError( AST__INTER, "astSscanf: Format string " - "'%s' contains more than %d fields " - "(AST internal programming error).", status, - fmt, VMAXFLD ); - break; - } - } - -/* Move on the first character following the field specifier. */ - c++; - } - -/* If this is not the start of a field specifier, pass on. */ - } else { - c++; - } - } - -/* Fill any unused pointers with NULL. */ - for( iptr = nptr; iptr < VMAXFLD; iptr++ ) ptr[iptr] = NULL; - -/* Get the length of the string to be scanned. */ - lstr = strlen( str ); - -/* Get the length of the format string excluding any trailing white space. */ - lfor = astChrLen( fmt ); - -/* Bill Joye reports that MacOS sscanf fails to return the correct number of - characters read (using a %n conversion) if there is a space before the - %n. So check for this. Does the format string contain " %n"? */ - c = strstr( fmt, " %n" ); - if( c && astOK ) { - -/* Take a copy of the supplied format string (excluding any trailing spaces). */ - newfor = (char *) astStore( NULL, (void *) fmt, (size_t) lfor + 1 ); - if( newfor ) { - -/* Ensure the string is terminated (in case the supplied format string - has any trailing spaces). */ - newfor[ lfor ] = 0; - -/* Remove all spaces from before any %n. */ - c = strstr( (const char *) newfor, " %n" ); - while( c ) { - while( *(c++) ) *( c - 1 ) = *c; - c = strstr( newfor, " %n" ); - } - -/* Use the native sscanf with the modified format string. Note, we cannot - use vsscanf because it is not ANSI C. Instead, we list the pointers - explicitly. */ - ret = sscanf( str, newfor, ptr[0], ptr[1], ptr[2], ptr[3], - ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], - ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], - ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] ); - -/* Now look through the original format string for conversions specifiers. - If any %n conversions are found which are preceded by a space, then - correct the returned character counts to include any spaces following the - corresponding point in the scanned string. */ - nfld = 0; - iptr = 0; - c = (char *) fmt; - while( *c ) { - -/* Field specifiers are marked by a % sign. */ - if( *c == '%' ) { - -/* Look at the character following the % sign. Quit if the end of the string - has been reached. */ - c++; - if( *c ) { - -/* If the % sign is followed by a "*" or another "%", then there will be no - corresponding pointer in the variable argument list "args". Ignore such - field specifiers. */ - if( *c != '*' && *c != '%' ) { - -/* Get the supplied pointer corresponding to this field specifier. */ - fptr = ptr[ iptr++ ]; - -/* Increment the number of matched fields required. "%n" specifiers are not - included in the value returned by sscanf so skip over them. */ - if( *c != 'n' ) { - nfld++; - -/* If the % sign is followed by a "n", and was preceded by a space, we - may need to correct the returned character count. */ - } else if( c > fmt + 1 && *(c-2) == ' ' ) { - -/* Do not correct the returned value if sscanf did not get as far as this - field specifier before an error occurred. */ - if( ret >= nfld ) { - -/* Get the original character count produced by sscanf. */ - nc = *( (int *) fptr ); - -/* For each space in "str" which follows, increment the returned count by - one (so long as the original count is not zero or more than the length - of the string - this is not foolproof, but I can't think of a better - check - all uses of %n in AST initialize the supplied count to zero - before calling sscanf so a value fo zero is a safe (ish) bet that the - supplied string doesn't match the supplied format). */ - if( nc > 0 && nc < lstr ) { - d = str + nc; - while( *(d++) == ' ' ) nc++; - *( (int *) fptr ) = nc; - } - } - } - } - -/* Move on the first character following the field specifier. */ - c++; - } - -/* If this is not the start of a field specifier, pass on. */ - } else { - c++; - } - } - -/* Release the temporary copy of the format string. */ - newfor = (char *) astFree( (void *) newfor ); - } - -/* If the format string should not trigger any known problems, use sscanf - directly. */ - } else if( astOK ) { - ret = sscanf( str, fmt, ptr[0], ptr[1], ptr[2], ptr[3], - ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], - ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], - ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] ); - } - } - -/* Tidy up the argument pointer. */ - va_end( args ); - -/* Return the answer. */ - return ret; - -} - - -/* The next functions are used only when memory debugging is - switched on via the MEM_DEBUG macro. They can be used for locating - memory leaks, etc. */ -#ifdef MEM_DEBUG - -void astActiveMemory_( const char *label ) { -/* -*+ -* Name: -* astActiveMemory - -* Purpose: -* Display a list of any currently active AST memory pointers. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astActiveMemory( const char *label ) - -* Description: -* This function displays a list of the identifiers for all currently -* active AST memory chunks. The list is written to standard output -* using "printf", preceded by the supplied text. - -* Parameters: -* label -* A textual label to display before the memody id values (may be -* NULL). - -* Notes: -* - This function attempts to execute even if an error has occurred. -* - Memory blocks which are not usually freed are not reported. Such -* blocks are typically used by AST to hold internal state information. -*- -*/ - - Memory *next; - - if( label ) printf("%s: ", label ); - next = Active_List; - if( next ) { - while( next ) { - if( !next->perm ) { - printf( "%d(%s:%d) ", next->id, next->file, next->line ); - } - next = next->next; - } - } else { - printf("There are currently no active AST memory blocks."); - } - printf("\n"); - -} - -void astWatchMemory_( int id ) { -/* -*+ -* Name: -* astWatchMemory - -* Purpose: -* Indicate uses of the memory block with the specified identifier -* should be reported. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astWatchMemory( int id ) - -* Description: -* This function forces astMemoryAlarm to be invoked when key -* operations are performed on a specified memory block. These key -* operations include; allocation, freeing, copying and cloning of -* Objects, etc. -* -* astMemoryAlarm reports a message when called identifying the memory -* block and the action performed on it. When using a debugger, these -* events can be trapped and investigated by setting a debugger -* breakpoint in astMemoryAlarm_. - -* Parameters: -* id -* The identifier of the memory block which is to be watched. - -* Notes: -* - This function attempts to execute even if an error has occurred. -*- -*/ - Watched_ID = id; -} - -int astMemoryId_( const void *ptr, int *status ){ -/* -*+ -* Name: -* astMemoryId - -* Purpose: -* Return the integer identifier for a memory block. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* int astMemoryId( const void *ptr ) - -* Description: -* This function returns the integer identifier associated with a -* memory block allocated by function sin this module. - -* Parameters: -* ptr -* The pointer (a genuine C pointer, not an encoded object -* identifier). - -* Returned Value: -* The integer identifier. A value of -1 is returned if "ptr" is NULL. - -*- -*/ - astDECLARE_GLOBALS - astGET_GLOBALS(NULL); - return ptr ? ((Memory *)(ptr-SIZEOF_MEMORY))->id : -1; -} - -void *astMemoryPtr_( int id ){ -/* -*+ -* Name: -* astMemoryPtr - -* Purpose: -* Return a pointer to the memory block with a given identifier. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void *astMemoryPtr( int id ) - -* Description: -* This function returns a pointer to the memory block with a given -* identifier. NULL is returned if the given identifier is not active. - -* Parameters: -* id -* The identifier for an active memory block. - -* Returned Value: -* The pointer to the memory block. NULL is returned if no active memory -* with the given ID can be found. Note, this is always a genuine C -* pointer (even for public Object pointers). - -*- -*/ - Memory *next; - void *ret; - - ret = NULL; - next = Active_List; - while( next ) { - if( next->id == id ) { - ret = next + 1; - break; - } - } - - return ret; -} - -void astMemoryAlarm_( const char *verb ){ -/* -*+ -* Name: -* astMemoryAlarm - -* Purpose: -* Called when a watched memory ID is used. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void astMemoryAlarm( const char *verb ) - -* Description: -* This function is called when a watched memory ID is used. See -* astWatchMemory. - -* Parameters: -* verb -* Text to include in message. -*- -*/ - - printf( "astMemoryAlarm: Memory id %d has been %s.\n", Watched_ID, verb ); -} - -void astMemoryStats_( int reset, size_t *peak, size_t *current, int *status ) { -/* -*+ -* Name: -* astMemoryStats - -* Purpose: -* Return the current and peak AST memory usage. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astMemoryStats( int reset, size_t *peak, size_t *current ) - -* Description: -* This function returns the current amount of memory allocated -* using AST memory management functions, and the peak amount of -* simultaneously allocated memory since the last time the peak value -* was reset. - -* Parameters: -* reset -* If non-zero, the peak value is reset to the current usage -* upon return. -* peak -* Address at which to return the peak memory usage since the last -* reset, in bytes. -* current -* Address at which to return the current memory usage, in bytes. - -*- -*/ - - LOCK_DEBUG_MUTEX; - - if( peak ) *peak = Peak_Usage; - if( current ) *current = Current_Usage; - if( reset ) Peak_Usage = Current_Usage; - - UNLOCK_DEBUG_MUTEX; -} - -void astMemoryWarning_( size_t threshold, int *status ) { -/* -*+ -* Name: -* astMemoryWarning - -* Purpose: -* Issues a warning memory goes over a specified threshold. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astMemoryWarning( size_t threshold ) - -* Description: -* This function prints a warning message to standard output if the -* AST memory usage exceeds the specified threshold. - -* Parameters: -* threshold -* The memory allocation, in bytes, at which a warning should be issued, -* Supply zero to suppress warnings. - -* Notes: -* - This function is used to reset the threshold to zero when the first -* warning is issued in order to prevent a flood of warnings appearing. -* Therefore, setting a debugger breakpoint in this function -* ("astMemoryWarning_" - do not forget the trailing underscore) -* allows you to locate the point at which memory allocation first -* exceeds the threshold. - -*- -*/ - - LOCK_DEBUG_MUTEX; - - Warn_Usage = threshold; - - UNLOCK_DEBUG_MUTEX; -} - -void astMemoryUse_( const void *ptr, const char *verb, int *status ){ -/* -*+ -* Name: -* astMemoryUse - -* Purpose: -* Called to report the use of a memory block pointer. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void astMemoryUse( void *ptr, const char *verb ) - -* Description: -* If the supplied memory block is being watched, astMemoryAlarm is -* called to report the use of the pointer. The reported text includes -* the supplied "verb". A memory block can be watched by calling -* astWatchMemory. - -* Parameters: -* ptr -* A pointer to the memory block being used. The pointer must have -* been returned by one of the AST memory management functions (e.g. -* astMalloc, astRealloc, etc). -* verb -* A verb indicating what is being done to the pointer. -*- -*/ - - astDECLARE_GLOBALS - astGET_GLOBALS(NULL); - - if( ptr && astMemoryId( ptr ) == Watched_ID ) { - if( !Quiet_Use || !strcmp( verb, ISSUED ) || - !strcmp( verb, FREED ) ) { - astMemoryAlarm( verb ); - } - } -} - -int astMemoryTune_( const char *name, int value, int *status ){ -/* -*+ -* Name: -* astMemoryTune - -* Purpose: -* Set a tuning parameter for the memory debugging functions. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* int astMemoryTune( const char *name, int value ) - -* Description: -* There are a few tuning parameters which control the behaviour of -* the memory debugging functions. This function allows these tuning -* parameters to be queried or set. - -* Parameters: -* name -* The name of the tuning parameter to query or set. Valid names are: -* -* "Keep_ID": A boolean flag indicating if a new ID should be issued -* for a cached memory block each time it is returned by astMalloc? -* Otherwise, the same ID value is used throughtout the life of a -* memory block. Default is zero (false). -* -* "List_Cache": A boolean flag which if non-zero (true) causes the -* ID of every memory block in the cache to be reported when the -* cache is emptied by astFlushMemory. -* -* "Quiet_Use": A boolean flag controlling the number of reports issued -* when a memory block is being watched (see astWatchMemory). If -* non-zero (true), then the only events which are reported are the -* issuing of a memory block pointer by astMalloc or astRealloc,and -* the freeing (or caching) of a memory block by astFree. If Quiet_Use -* is zero (the default), then additional reports are made for -* memory blocks used to hold AST Objects whenever the Object is -* copied, cloned, or checked. -* value -* The new value for the tuning parameter. If AST__TUNULL is -* supplied, the original value is left unchanged. - -* Returned Value: -* The original value of the tuning parameter. - -*- -*/ - - int result = AST__TUNULL; - - if( name ) { - - if( astChrMatch( name, "Keep_ID" ) ) { - result = Keep_ID; - if( value != AST__TUNULL ) Keep_ID = value; - - } else if( astChrMatch( name, "Quiet_Use" ) ) { - result = Quiet_Use; - if( value != AST__TUNULL ) Quiet_Use = value; - - } else if( astChrMatch( name, "List_Cache" ) ) { - result = List_Cache; - if( value != AST__TUNULL ) List_Cache = value; - - } else if( astOK ) { - astError( AST__TUNAM, "astMemoryTune: Unknown AST memory tuning " - "parameter specified \"%s\".", status, name ); - } - } - - return result; -} - -void astBeginPM_( int *status ) { -/* -*+ -* Name: -* astBeginPM - -* Purpose: -* Start a block of permanent memory allocations. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astBeginPM - -* Description: -* This function indicates that all memory allocations made by calls -* to other functions in this module (e.g. astMalloc), up to the -* astEndPM call which matches the astBeginPM call, will not usually -* be freed explicitly. Matching astBeginPM/astEndPM calls should be -* used to enclose all code which allocates memory which is never -* freed explitly by AST. Such memory allocations may be freed if -* required, using the astFlushMemory function (but note this should -* only be done once all use of AST by an application has finished). -* -* Matching pairs of astBeginPM/astEndPM calls can be nested up to a -* maximum depth of 20. - -*- -*/ - - LOCK_DEBUG_MUTEX; - -/* The global Perm_Mem flag indicates whether or not subsequent memory - management functions in this module should store pointers to allocated - blocks in the PM_List array. Push the current value of this flag - onto a stack, and set the value to 1. */ - if( PM_Stack_Size >= PM_STACK_MAXSIZE ){ - if( astOK ) { - astError( AST__INTER, "astBeginPM: Maximum stack size has been " - "exceeded (internal AST programming error)." , status); - } - - } else { - PM_Stack[ PM_Stack_Size++ ] = Perm_Mem; - Perm_Mem = 1; - } - UNLOCK_DEBUG_MUTEX; -} - -void astEndPM_( int *status ) { -/* -*+ -* Name: -* astEndPM - -* Purpose: -* End a block of permanent memory allocations. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astEndPM - -* Description: -* This function indicates the end of the block of permanent memory -* allocations started by the matching call to astBeginPM. See -* astBeginPM for further details. - -*- -*/ - - LOCK_DEBUG_MUTEX; - -/* The global Perm_Mem flag indicates whether or not subsequent memory - management functions in this module should store pointers to allocated - blocks in the PM_List array. Pop the value from the top of this stack. */ - if( PM_Stack_Size == 0 ){ - if( astOK ) { - astError( AST__INTER, "astEndPM: astEndPM called without " - "matching astBeginPM (internal AST programming error)." , status); - } - - } else { - Perm_Mem = PM_Stack[ --PM_Stack_Size ]; - } - - UNLOCK_DEBUG_MUTEX; -} - -void astFlushMemory_( int leak, int *status ) { -/* -*+ -* Name: -* astFlushMemory - -* Purpose: -* Free all permanent and cached memory blocks. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astFlushMemory( int leak ); - -* Description: -* This function should only be called once all use of AST by an -* application has finished. It frees any allocated but currently -* unused memory stored in an internal cache of unused memory -* pointers. (Note, it does not free any memory used permanently to -* store internal AST state information). -* -* It is not normally necessary to call this function since the memory -* will be freed anyway by the operating system when the application -* terminates. However, it can be called if required in order to -* stop memory management tools such as valgrind from reporting that -* the memory has not been freed at the end of an application. -* -* In addition, if "leak" is non-zero this function will also report -* an error if any active AST memory pointers remain which have not -* been freed (other than pointers for the cached and permanent -* memory described above). Leakage of active memory blocks can be -* investigated using astActiveMemory and astWatchMemory. - -* Parameters: -* leak -* Should an error be reported if any non-permanent memory blocks -* are found to be active? - -*- -*/ - -/* Local Variables: */ - Memory *next; - int nact; - int istat; - -/* Empty the cache. */ - astMemCaching( astMemCaching( AST__TUNULL ) ); - -/* Free and count all non-permanent memory blocks. */ - nact = 0; - next = Active_List; - while( Active_List ) { - next = Active_List->next; - if( !Active_List->perm ) { - nact++; - FREE( Active_List ); - } - Active_List = next; - } - -/* Report an error if any active pointers remained. if an error has - already occurred, use the existing status value. */ - if( nact && leak ){ - - if( astOK ) { - istat = AST__INTER; - } else { - istat = astStatus; - } - astError( istat, "astFlushMemory: %d AST memory blocks have not " - "been released (programming error).", status, nact ); - - } else { - printf("astFlushMemory: All AST memory blocks were released correctly.\n" ); - } -} - -void astCheckMemory_( int *status ) { -/* -*+ -* Name: -* astCheckMemory - -* Purpose: -* Check that all AST memory blocks have been released. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* astCheckMemory - -* Description: -* This macro reports an error if any active AST memory pointers -* remain which have not been freed (other than pointers for cached -* and "permanently allocated" memory). Leakage of active memory blocks -* can be investigated using astActiveMemory and astWatchMemory. -*- -*/ - -/* Local Variables: */ - Memory *next; - int nact; - int istat; - -/* Empty the cache. */ - astMemCaching( astMemCaching( AST__TUNULL ) ); - -/* Count all non-permanent memory blocks. */ - nact = 0; - next = Active_List; - while( Active_List ) { - next = Active_List->next; - if( !Active_List->perm ) nact++; - Active_List = next; - } - -/* Report an error if any active pointers remained. If an error has - already occurred, use the existing status value. */ - if( nact ){ - - if( astOK ) { - istat = AST__INTER; - } else { - istat = astStatus; - } - astError( istat, "astCheckMemory: %d AST memory blocks have not " - "been released (programming error).", status, nact ); - - } else { - printf("astCheckMemory: All AST memory blocks were released correctly.\n" ); - } -} - -static void Issue( Memory *mem, int *status ) { -/* -* Name: -* Issue - -* Purpose: -* Indicate that a pointer to a memory block has been issued. - -* Type: -* Private function. - -* Synopsis: -* #include "memory.h" -* void Issue( Memory *mem, int *status ); - -* Description: -* Initialises the extra debug items in the Memory header, and adds the -* Memory structure to the list of active memory blocks. - -* Parameters: -* mem -* Pointer to the Memory structure. -* status -* Pointer to the inherited status value. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS - -/* Return if no pointer was supplied. */ - if( !mem ) return; - - LOCK_DEBUG_MUTEX; - astGET_GLOBALS(NULL); - -/* Store a unique identifier for this pointer. Unless global Keep_ID is - non-zero, a new identifier is used each time the pointer becomes active - (i.e. each time it is remove from the cache or malloced). */ - if( !Keep_ID || mem->id < 0 ) mem->id = ++Next_ID; - -/* Record the file name and line number where it was issued. */ - if( AST__GLOBALS && AST__GLOBALS->Error.Current_File ) { - strncpy( mem->file, AST__GLOBALS->Error.Current_File, sizeof(mem->file) ); - mem->file[ sizeof(mem->file) - 1 ] = 0; - mem->line = AST__GLOBALS->Error.Current_Line; - } else { - mem->file[ 0 ] = 0; - mem->line = 0; - } - -/* Indicate if this is a permanent memory block (i.e. it will usually not - be freed by AST). */ - mem->perm = Perm_Mem; - -/* Add it to the double linked list of active pointers. */ - mem->next = Active_List; - mem->prev = NULL; - if( Active_List ) Active_List->prev = mem; - Active_List = mem; - -/* Report that the pointer is being issued. */ - astMemoryUse( (void *) mem + SIZEOF_MEMORY, ISSUED ); - -/* Update the current and peak memory usage. */ - Current_Usage += mem->size + SIZEOF_MEMORY; - if( Current_Usage > Peak_Usage ) Peak_Usage = Current_Usage; - -/* If the current allocation is above the threshold set using - astMemoryWarning, issue a warning message, and then reset the threshold - to zero to prevent further warnings being issued, and to allow a - debugger breakpoint to be set. */ - if( Current_Usage > Warn_Usage && - Warn_Usage > 0 ) { - printf( "Warning - AST memory allocation has exceeded %ld bytes - " - "dumping catalogue of active memory blocks to file 'memory.dump'\n", - Warn_Usage ); - -/* Create a file holding the details of all currently active memory blocks. It can be - examined using topcat. */ - FILE *fd = fopen( "memory.dump", "w" ); - if( fd ) { - Memory *next; - - fprintf( fd, "# id size perm file line\n"); - next = Active_List; - if( next ) { - while( next ) { - if( !next->perm ) { - fprintf( fd, "%d %zu %d %s %d\n", next->id, next->size, - next->perm, next->file, next->line ); - } - next = next->next; - } - } - - fclose(fd ); - } - - Warn_Usage = 0; - } - - UNLOCK_DEBUG_MUTEX; -} - -static void DeIssue( Memory *mem, int *status ) { -/* -* Name: -* DeIssue - -* Purpose: -* Indicate that a pointer to a memory block has been freed. - -* Type: -* Private function. - -* Synopsis: -* #include "memory.h" -* void DeIssue( Memeory *mem, int *status ); - -* Description: -* Initialises the extra debug items in the Memory header, and adds the -* Memory structure to the list of active memory blocks. - -* Parameters: -* mem -* Pointer to the Memory structure. -* status -* Pointer to the inherited status value. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS - Memory *next; - Memory *prev; - -/* Return if no pointer was supplied. */ - if( !mem ) return; - - LOCK_DEBUG_MUTEX; - astGET_GLOBALS(NULL); - -/* Report that the pointer is being freed. */ - astMemoryUse( (void *) mem + SIZEOF_MEMORY, FREED ); - -/* Remove the block from the double linked list of active pointers. */ - next = mem->next; - prev = mem->prev; - if( prev ) prev->next = next; - if( next ) next->prev = prev; - if( mem == Active_List ) Active_List = next; - mem->next = NULL; - mem->prev = NULL; - -/* Update the current memory usage. */ - Current_Usage -= mem->size + SIZEOF_MEMORY; - - UNLOCK_DEBUG_MUTEX; -} - - -#endif - - - - - - -/* The next functions are used only when profiling AST application. */ -#ifdef MEM_PROFILE - - -void astStartTimer_( const char *file, int line, const char *name, int *status ) { -/* -*+ -* Name: -* astStartTimer - -* Purpose: -* Measure the time spent until the corresponding call to astStopTimer. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void astStartTimer( const char *name ); - -* Description: -* This function looks for a timer with the specified name within the -* current parent timer. If no timer with the given name is found, a -* new timer is created and initialised to zero. The current absolute -* time (elapsed, user and system) is recorded in the timer. The new -* timer then becomes the current timer. - -* Parameters: -* name -* A label for the timer. This should be unique within the -* enclosing parent timer. - -* Notes: -* - This function should only be used in a single-threaded environment. -* - This function returns without action if timers are currently -* disabled (see astEnableTimers). - -*- -*/ - -/* Local Variables: */ - int n, found, i; - AstTimer *t; - struct tms buf; - -/* Check inherited status. Also return if timers are currently disabled. */ - if( !Enable_Timers || *status != 0 ) return; - -/* See if a timer with the given name exists in the list of child timers - within the current timer. */ - found = 0; - if( Current_Timer ) { - for( i = 0; i < Current_Timer->nchild; i++ ) { - t = Current_Timer->children[ i ]; - if( !strcmp( t->name, name ) ) { - found = 1; - break; - } - } - } - -/* If not, create and initialise one now, and add it into the list of - children within the current timer. */ - if( !found ) { - t = astMalloc( sizeof( AstTimer ) ); - t->id = Timer_Count++; - t->et = 0; - t->ut = 0; - t->st = 0; - t->nentry = 0; - t->name = name; - t->file = file; - t->line = line; - t->parent = Current_Timer; - t->nchild = 0; - t->children = NULL; - - if( Current_Timer ) { - n = (Current_Timer->nchild)++; - Current_Timer->children = astGrow( Current_Timer->children, - sizeof( AstTimer *), - Current_Timer->nchild ); - Current_Timer->children[ n ] = t; - } - } - -/* Record the current absolute times (elapsed, user and system) within - the new timer. */ - t->e0 = times(&buf); - t->u0 = buf.tms_utime; - t->s0 = buf.tms_stime; - -/* Increment the number of entries into the timer. */ - (t->nentry)++; - -/* Use the new timer as the current timer until the corresponding call to - astStopTimer. */ - Current_Timer = t; -} - -void astEnableTimers_( int enable, int *status ) { -/* -*+ -* Name: -* astEnableTimers - -* Purpose: -* Set a global flag indicating if the use of AST timers is enabled. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void astStartTimer( int enable ); - -* Description: -* This function sets a global flag that enables otr disables the user -* of AST Timers. If timers are disabled, the astStartTimer and -* astStopTimer functions will return without action. - -* Parameters: -* enable -* If non-zero, timers will be used. - -* Notes: -* - This function should only be used in a single-threaded environment. - -*- -*/ - Enable_Timers = enable; -} - -void astStopTimer_( int *status ) { -/* -*+ -* Name: -* astStopTimer - -* Purpose: -* Record the time spent since the corresponding call to astStartTimer. - -* Type: -* Protected function. - -* Synopsis: -* #include "memory.h" -* void astStopTimer; - -* Description: -* This function obtains the time increments since the corresponding -* call to astStartTimer, and adds these increments onto the total -* times stored in the current timer. It then changes the current -* timer to be the parent timer associated the current timer on entry. -* -* If the current timer on entry has no parent (i.e. is a top level -* timer), the times spent in the top-level timer, and all its -* descendent timers, are displayed. - -* Notes: -* - This function should only be used in a single-threaded environment. -* - This function returns without action if timers are currently -* disabled (see astEnableTimers). - -*- -*/ - -/* Local Variables: */ - AstTimer *flat; - AstTimer *t; - int i; - int nflat; - struct tms buf; - -/* Check inherited status. Also return if timers are currently disabled. */ - if( !Enable_Timers || !Current_Timer || *status != 0 ) return; - -/* Get the current absolute times, and thus find the elapsed times since the - corresponding call to astStartTimer. Use these elapsed times to increment - the total times spent in the timer. */ - Current_Timer->et += ( times(&buf) - Current_Timer->e0 ); - Current_Timer->st += ( buf.tms_stime - Current_Timer->s0 ); - Current_Timer->ut += ( buf.tms_utime - Current_Timer->u0 ); - -/* If this is a top level timer, display the times spent in the current - timer, and in all its descendent timers. This also frees the memory - used by the timers. */ - if( !Current_Timer->parent ) { - flat = NULL; - nflat = 0; - Current_Timer = ReportTimer( Current_Timer, 0, &flat, &nflat, status ); - -/* Sort and display the flat list of timers, then free the memory used by - the flat list. */ - qsort( flat, nflat, sizeof( AstTimer), CompareTimers2 ); - printf("\n\n"); - t = flat; - for( i = 0; i < nflat; i++,t++ ) { - printf( "%s (%s:%d): ", t->name, t->file, t->line ); - printf( "elapsed=%ld ", (long int) t->et ); -/* - printf( "system=%ld ", (long int) t->st ); - printf( "user=%ld ", (long int) t->ut ); -*/ - printf( "calls=%d ", t->nentry ); - printf("\n"); - } - flat = astFree( flat ); - -/* If this is not a top level timer, restore the parent timer as the - curent timer. */ - } else { - Current_Timer = Current_Timer->parent; - } -} - -static AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat, - int *nflat, int *status ) { -/* -* Name: -* ReportTimer - -* Purpose: -* Free and report the times spent in a given timer, and all descendents. - -* Type: -* Private function. - -* Synopsis: -* #include "memory.h" -* AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat, -* int *nflat, int *status ) - -* Description: -* This routines reports to standard output the times spent in the -* supplied timer. It then calls itself recursively to report the times -* spent in each of the child timers of the supplied timer. -* -* It also frees the memory used to hold the supplied timer. - -* Parameters: -* t -* Pointer to the AstTimer structure. -* ind -* The number of spaces of indentation to display before the timer -* details. -* flat -* Address of a pointer to the start of an array of AstTimers. The -* number of elements in this array is given by "*nflat". Each -* Timer in this array holds the accumulated total for all entries -* into a given timer, from all parent contexts. -* nflat -* Address of an int holding the current length of the "*flat" array. -* status -* Pointer to the inherited status value. -*/ - -/* Local Variables: */ - int found; - int i; - AstTimer *ft; - AstTimer *parent; - -/* Check inherited status */ - if( *status != 0 ) return NULL; - -/* Display a single line of text containing the times stored in the supplied - timer, preceded by the requested number of spaces. */ - for( i = 0; i < ind; i++ ) printf(" "); - printf( "%s (%s:%d): ", t->name, t->file, t->line ); - - printf( "id=%d ", t->id ); - printf( "elapsed=%ld ", (long int) t->et ); -/* - printf( "system=%ld ", (long int) t->st ); - printf( "user=%ld ", (long int) t->ut ); -*/ - printf( "calls=%d ", t->nentry ); - -/* If there are any children, end the line with an opening bvrace. */ - if( t->nchild ) printf("{"); - printf("\n"); - -/* If there is more than one child, sort them into descending order of - elapsed time usage. */ - if( t->nchild > 1 ) qsort( t->children, t->nchild, sizeof( AstTimer * ), - CompareTimers ); - -/* Increment the indentation and call this function recursively to - display and free each child timer. */ - ind += 3; - for( i = 0; i < t->nchild; i++ ) { - (t->children)[ i ] = ReportTimer( (t->children)[ i ], ind, flat, - nflat, status ); - } - -/* Delimit the children by displaying a closing brace. */ - if( t->nchild ) { - for( i = 0; i < ind - 3; i++ ) printf(" "); - printf("}\n"); - } - -/* See if this timer is contained within itself at a higher level. */ - parent = t->parent; - while( parent && ( parent->line != t->line || - strcmp( parent->file, t->file ) ) ) { - parent = parent->parent; - } - -/* If not, search for a timer in the "flat" array of timers that has the same - source file and line number. */ - if( !parent ) { - found = 0; - ft = *flat; - for( i = 0; i < *nflat; i++, ft++ ) { - if( ft->line == t->line && - !strcmp( ft->file, t->file ) ) { - found = 1; - break; - } - } - -/* If not found, add a new timer to the end of the "flat" array and - initialise it. */ - if( !found ) { - i = (*nflat)++; - *flat = astGrow( *flat, *nflat, sizeof( AstTimer ) ); - ft = (*flat) + i; - ft->id = 0; - ft->et = t->et; - ft->ut = t->ut; - ft->st = t->st; - ft->nentry = t->nentry; - ft->name = t->name; - ft->file = t->file; - ft->line = t->line; - ft->parent = NULL; - ft->nchild = 0; - ft->children = NULL; - - -/* If found, increment the properites to include the supplied timer. */ - } else { - ft->et += t->et; - ft->ut += t->ut; - ft->st += t->st; - ft->nentry += t->nentry; - } - } - -/* Free the memory used by the supplied timer. */ - t->children = astFree( t->children ); - return astFree( t ); -} - - -static int CompareTimers( const void *a, const void *b ){ - return ((*((AstTimer **) b ))->et) - ((*((AstTimer **) a ))->et); -} - -static int CompareTimers2( const void *a, const void *b ){ - return (((AstTimer *) b )->et) - (((AstTimer *) a )->et); -} - -#endif |