1 /*
2 *  Name:
3 *     memory.c
4 
5 *  Purpose:
6 *     Implement memory allocation/deallocation functions.
7 
8 *  Description:
9 *     This file implements the Memory module which is used for
10 *     allocating and freeing memory in the AST library.  For a
11 *     description of the module and its interface, see the .h file of
12 *     the same name.
13 
14 *     Note, it is assumed that malloc, free and realloc are thread-safe.
15 
16 *  Copyright:
17 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
18 *     Research Councils
19 *     Copyright (C) 2009-2010 Science & Technology Facilities Council.
20 *     All Rights Reserved.
21 
22 *  Licence:
23 *     This program is free software: you can redistribute it and/or
24 *     modify it under the terms of the GNU Lesser General Public
25 *     License as published by the Free Software Foundation, either
26 *     version 3 of the License, or (at your option) any later
27 *     version.
28 *
29 *     This program is distributed in the hope that it will be useful,
30 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
31 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32 *     GNU Lesser General Public License for more details.
33 *
34 *     You should have received a copy of the GNU Lesser General
35 *     License along with this program.  If not, see
36 *     <http://www.gnu.org/licenses/>.
37 
38 *  Authors:
39 *     RFWS: R.F. Warren-Smith (Starlink)
40 *     DSB: D.S. Berry (Starlink)
41 
42 *  History:
43 *     2-JAN-1996 (RFWS):
44 *        Original version.
45 *     26-JAN-1996 (RFWS):
46 *        Removed trailing underscores from static functions and
47 *        changed to use new error function interfaces.
48 *     20-JUN-1996 (RFWS):
49 *        Added astString.
50 *     15-JUL-1996 (RFWS):
51 *        Make IsDynamic execute under error conditions to avoid memory
52 *        leaks in such situations.
53 *     11-SEP-1996 (RFWS):
54 *        Added astStringArray (original written by DSB).
55 *     18-MAR-1998 (RFWS):
56 *        Added notes about these functions being available for writing
57 *        foreign language and graphics interfaces, etc.
58 *     29-JAN-2002 (DSB):
59 *        Added astChrLen and astSscanf.
60 *     15-FEB-2002 (DSB):
61 *        Removed use of non-ANSI vsscanf from astSscanf.
62 *     15-NOV-2002 (DSB):
63 *        Moved ChrMatch from SkyFrame (etc) to here. Included stdio.h and
64 *        ctype.h.
65 *     10-FEB-2003 (DSB):
66 *        Added facilities for detecting and tracing memory leaks. These
67 *        are only included if AST is compiled with the -DDEBUG flag.
68 *     3-MAR-2004 (DSB):
69 *        Modified astSscanf to avoid use of uninitialised values
70 *        corresponding to "%n" fields in the format string.
71 *     26-JAN-2004 (DSB):
72 *        Modified astRealloc to clarify the nature of the returned pointer
73 *        (which is not a "Memory *"). Also correct issuing and deissuing
74 *        of pointers in DEBUG code within astRealloc.
75 *     16-FEB-2006 (DSB):
76 *        Convert Magic from a function to a macro for extra speed.
77 *     21-FEB-2006 (DSB):
78 *        Convert IsDynamic from a function to a macro for extra speed.
79 *     23-FEB-2006 (DSB):
80 *        Added the caching system for allocated but unused memory blocks,
81 *        controlled by AST tuning parameter MemoryCaching.
82 *     2-MAR-2006 (DSB):
83 *        Added astFlushMemory, and renamed the memory debugging functions.
84 *        These are now conditionally compiled if the MEM_DEBUG macros is
85 *        defined (set by configuring AST with the --with-memdebug option).
86 *        Also modified them to take into account MemoryCaching.
87 *     24-MAY-2006 (DSB):
88 *        Ensure that pointers to memory returned by this module are all
89 *        aligned on 8 byte boundaries. This fixes problems with ualigned
90 *        memory access that could cause bus errors on Solaris.
91 *     26-MAY-2006 (DSB):
92 *        Cast (void *) pointers to (char *) before doing arithmetic on
93 *        them (changes supplied by Micah Johnson).
94 *     4-DEC-2006 (DSB):
95 *        Fix bug in astMalloc that caused a non-null pointer to be
96 *        returned on error.
97 *     4-JAN-2007 (DSB):
98 *        Move definition of astCLASS macro so that it comes before the
99 *        inclusion of the AST include files (which test for astCLASS).
100 *     27-JUN-2007 (DSB):
101 *        Added astIsDynamic.
102 *     24-OCT-2007 (DSB):
103 *        Zero the size of memory blocks stored in the Cache so that an
104 *        error will be reported if an attempt is made to free a memory
105 *        block that has already been freed.
106 *     25-OCT-2007 (DSB):
107 *        Added astRemoveLeadingBlanks.
108 *     28-FEB-2008 (DSB):
109 *        Added astChrSub.
110 *     17-MAR-2008 (DSB):
111 *        Added "{nnn}" quantifier to astChrSub.
112 *     27-MAR-2008 (DSB):
113 *        Added astChrSplitRE, and re-structured regexp functions.
114 *     18-NOV-2008 (DSB):
115 *        In astFlushMemory, do not release permanent memory blocks as
116 *        they may still be needed.
117 *     9-FEB-2009 (DSB):
118 *        Added astChr2Double.
119 *     25-JUN-2009 (DSB):
120 *        Fix handling of escape characters in astSplitC.
121 *     19-MAY-2010 (DSB):
122 *        - Added astStringCase.
123 *        - Changed access from protected to public for commonly used
124 *        functions.
125 *     26-MAY-2010 (DSB):
126 *        Added astCalloc.
127 *     18-AUG-2010 (DSB):
128 *        Added astMemoryStats
129 *     19-AUG-2010 (DSB):
130 *        Added astMemoryWarning
131 *     8-OCT-2010 (DSB):
132 *        Modify memory allocation to use "calloc" directly, rather than
133 *        using "malloc+memset".
134 *     12-APR-2011 (DSB):
135 *        Fix regular expression problem where a ".*" template field failed to
136 *        match a null string if it occurred before a closing parenthesis at
137 *        the end of the template.
138 *     26-MAY-2011 (DSB):
139 *        - Changed API for astCalloc to match RTL (i.e. remove "init").
140 *        - Changed astChr2Double to check for strigs like "2.", which
141 *        some sscanfs fail to read as a floating point value.
142 *     27-MAY-2011 (DSB):
143 *        Added astFreeDouble to free a dynamically allocated array of
144 *        pointers to other dynamically allocated arrays.
145 *     21-JUN-2011 (DSB):
146 *        Added astCheckMemory - an alternative to astFlushMemory that does
147 *        not free any memory.
148 *     21-NOV-2011 (DSB):
149 *        Correct matchend value returned by astChrSplitRE.
150 *     6-JAN-2014 (DSB):
151 *        Optimise access to cache to avoid valgrind warnings.
152 *     16-JAN-2014 (DSB):
153 *        Dump details of all active memory blocks if the total memory allocation
154 *        specified by astMemoryWarning is exceeded.
155 */
156 
157 /* Configuration results. */
158 /* ---------------------- */
159 #if HAVE_CONFIG_H
160 #include <config.h>
161 #endif
162 
163 /* Module Macros. */
164 /* ============== */
165 /* Define the astCLASS macro (even although this is not a class
166    implementation) to obtain access to the protected error handling
167    functions. */
168 #define astCLASS memory
169 
170 /* The maximum number of fields within a format string allowed by astSscanf. */
171 #define VMAXFLD 20
172 
173 /* The maximum number of nested astBeginPM/astEndPM contexts. */
174 #define PM_STACK_MAXSIZE 20
175 
176 /* Select the appropriate memory management functions. These will be the
177    system's malloc, calloc, free and realloc unless AST was configured with
178    the "--with-starmem" option, in which case they will be the starmem
179    malloc, calloc, free and realloc. */
180 #ifdef HAVE_STAR_MEM_H
181 #  include <star/mem.h>
182 #  define MALLOC starMalloc
183 #  define CALLOC starCalloc
184 #  define FREE starFree
185 #  define REALLOC starRealloc
186 #else
187 #  define MALLOC malloc
188 #  define CALLOC calloc
189 #  define FREE free
190 #  define REALLOC realloc
191 #endif
192 
193 
194 #ifdef MEM_DEBUG
195 #define ISSUED "issued"
196 #define FREED "freed"
197 #endif
198 
199 /* Include files. */
200 /* ============== */
201 /* Interface definitions. */
202 /* ---------------------- */
203 #include "error.h"               /* Error reporting facilities */
204 #include "globals.h"             /* Thread-specific global data */
205 #include "memory.h"              /* Interface to this module */
206 #include "pointset.h"            /* For AST__BAD */
207 
208 #ifdef MEM_DEBUG
209 #include "object.h"              /* For astMakePointer */
210 #endif
211 
212 /* Error code definitions. */
213 /* ----------------------- */
214 #include "ast_err.h"             /* AST error codes */
215 
216 /* C header files. */
217 /* --------------- */
218 #include <ctype.h>
219 #include <errno.h>
220 #include <string.h>
221 #include <stdlib.h>
222 #include <stdarg.h>
223 #include <stdio.h>
224 #include <limits.h>
225 
226 #ifdef THREAD_SAFE
227 #include <pthread.h>
228 #endif
229 
230 #ifdef MEM_PROFILE
231 #include <sys/times.h>
232 #endif
233 
234 /* Function Macros. */
235 /* =============== */
236 /* These are defined as macros rather than functions to avoid the
237    overhead of a function call since they are called extremely frequently. */
238 
239 /*
240 *  Name:
241 *     IS_DYNAMIC
242 
243 *  Purpose:
244 *     Test whether a memory region has been dynamically allocated.
245 
246 *  Type:
247 *     Private macro
248 
249 *  Synopsis:
250 *     #include "memory.h"
251 *     IS_DYNAMIC( ptr, dynamic )
252 
253 *  Description:
254 *     This macro takes a pointer to a region of memory and tests if
255 *     the memory has previously been dynamically allocated using other
256 *     functions from this module. It does this by checking for the
257 *     presence of a "magic" number in the header which precedes the
258 *     allocated memory. If the magic number is not present (or the
259 *     pointer is invalid for any other reason), an error is reported
260 *     and the global error status is set.
261 *
262 *     The result of the test is written to the variable specified by "res".
263 
264 *  Parameters:
265 *     ptr
266 *        Pointer to the start (as known to the external user) of the
267 *        dynamically allocated memory.
268 *     dynamic
269 *        Name of an "int" variable to recieve the result of the test.
270 *        If the memory was allocated dynamically, a value of 1 is
271 *        stored in this variable.  Otherwise, zero is stored and an error
272 *        results.
273 
274 *  Notes:
275 *     - A NULL pointer value produces an error report from this
276 *     function, although other functions may wish to regard a NULL
277 *     pointer as valid.
278 *     - This function attempts to execute even if the global error
279 *     status is set, although no further error report will be made if
280 *     the memory is not dynamically allocated under these
281 *     circumstances.
282 *     - The test performed by this function is not 100% secure as the
283 *     "magic" value could occur by accident (although this is
284 *     unlikely). It is mainly intended to provide security against
285 *     programming errors, including accidental corruption of the
286 *     memory header and attempts to allocate the same region of memory
287 *     more than once.
288 */
289 
290 #define IS_DYNAMIC(ptr,dynamic) \
291 \
292 /* Initialise. */ \
293    dynamic = 0; \
294 \
295 /* Check that a NULL pointer has not been supplied and report an error \
296    if it has (but not if the global status is already set). */ \
297    if ( !ptr ) { \
298       if ( astOK ) { \
299          astError( AST__PTRIN, "Invalid NULL pointer (address %p).", status, ptr ); \
300       } \
301 \
302 /* If OK, derive a pointer to the memory header that precedes the \
303    allocated region of memory. */ \
304    } else { \
305       Memory *isdynmem;                /* Pointer to memory header */ \
306       isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY ); \
307 \
308 /* Check if the "magic number" in the header is valid and report an \
309    error if it is not (but not if the global status is already \
310    set). */ \
311       if ( isdynmem->magic != MAGIC( isdynmem, isdynmem->size ) ) { \
312          if ( astOK ) { \
313             astError( AST__PTRIN, \
314                       "Invalid pointer or corrupted memory at address %p.", status, \
315                       ptr ); \
316          } \
317 \
318 /* Note if the magic number is OK. */ \
319       } else { \
320          dynamic = 1; \
321       } \
322    }
323 
324 
325 
326 /*
327 *  Name:
328 *     MAGIC
329 
330 *  Purpose:
331 *     Generate a "magic number".
332 
333 *  Type:
334 *     Private macro.
335 
336 *  Synopsis:
337 *     #include "memory.h"
338 *     unsigned long MAGIC( void *ptr, size_t size )
339 
340 *  Description:
341 *     This macro generates a "magic number" which is a function of
342 *     a memory address and an object size. This number may be stored
343 *     in a region of dynamically allocated memory to allow it to be
344 *     recognised as dynamically allocated by other routines, and also
345 *     to provide security against memory leaks, etc.
346 
347 *  Parameters:
348 *     ptr
349 *        The memory pointer.
350 *     size
351 *        The object size.
352 
353 *  Returned Value:
354 *     The function returns the magic number.
355 
356 *  Notes:
357 *     This function does not perform error checking.
358 */
359 
360 /* Form the bit-wise exclusive OR between the memory address and the
361    object size, then add 1 and invert the bits. Return the result as
362    an unsigned long integer. */
363 #define MAGIC(ptr,size) \
364    ( ~( ( ( (unsigned long) ptr ) ^ ( (unsigned long) size ) ) + \
365              ( (unsigned long) 1 ) ) )
366 
367 /* A macro that returns the size of the a Memory structure padded to a
368    multiple of 8 bytes. */
369 #define SIZEOF_MEMORY \
370    ( ( sizeof_memory != 0 ) ? sizeof_memory : SizeOfMemory( status ) )
371 
372 
373 /* Type Definitions. */
374 /* ================= */
375 
376 #ifdef MEM_PROFILE
377 
378 /* Structure used to record the time spent between matching calls to
379    astStartTimer and astStopTimer. */
380 typedef struct AstTimer {
381    int id;                    /* Unique integer identifier for timer */
382    clock_t e0;                /* Absolute elapsed time at timer start */
383    clock_t u0;                /* Absolute user time at timer start */
384    clock_t s0;                /* Absolute system time at timer start */
385    clock_t et;                /* Cumulative elapsed time within timer */
386    clock_t ut;                /* Cumulative user time within timer */
387    clock_t st;                /* Cumulative system time within timer */
388    int nentry;                /* Number of entries into the timer */
389    const char *name;          /* An identifying label for the timer */
390    const char *file;          /* Name of source file where timer was started */
391    int line;                  /* Source file line no. where timer was started */
392    struct AstTimer *parent;   /* The parent enclosing timer */
393    int nchild;                /* Number of child timers */
394    struct AstTimer **children;/* Timers that count time within this timer */
395 } AstTimer;
396 
397 #endif
398 
399 /* Module Variables. */
400 /* ================= */
401 
402 /* Extra stuff for profiling (can only be used in single threaded
403    environments). */
404 #ifdef MEM_PROFILE
405 static AstTimer *Current_Timer = NULL;
406 static int Enable_Timers = 0;
407 static int Timer_Count = 0;
408 #endif
409 
410 /* Extra stuff for debugging of memory management (tracking of leaks
411    etc). */
412 #ifdef MEM_DEBUG
413 
414 /* The identifier for the memory block which is to be tracked. */
415 static int Watched_ID = -1;
416 
417 /* The next integer to use to identify an active memory block pointer. */
418 static int Next_ID = -1;
419 
420 /* Indicates if future memory allocations are permanent (i.e. will not
421    usually be freed explicitly by AST). */
422 static int Perm_Mem = 0;
423 
424 /* A "first in, last out" stack of Perm_Mem values used by nested
425    astBeginPM/astEndPM contexts. */
426 static int PM_Stack[ PM_STACK_MAXSIZE ];
427 
428 /* The number of values currently in the PM_Stack array. */
429 static int PM_Stack_Size = 0;
430 
431 /* A pointer to a double linked list holding pointers to currently active
432    memory blocks (i.e. memory blocks for which a pointer has been issued
433    but not yet freed). This does not include the memory blocks in the
434    Cache array (these are not considered to be active). */
435 static Memory *Active_List = NULL;
436 
437 /* Should a new ID be issued each time a cached memory block is returned
438    by astMalloc? Otherwise, the same ID value is used throughout the
439    life of a memory block. */
440 static int Keep_ID = 0;
441 
442 /* Suppress all memory use reports except for issuing and freeing? */
443 static int Quiet_Use = 0;
444 
445 /* Report the ID of every cached block when the cache is emptied? */
446 static int List_Cache = 0;
447 
448 /* Memory allocation at which to issue a warning. */
449 static size_t Warn_Usage = 0;
450 
451 /* Current memory allocated by AST. */
452 static size_t Current_Usage = 0;
453 
454 /* Peak memory allocated by AST. */
455 static size_t Peak_Usage = 0;
456 
457 #ifdef THREAD_SAFE
458 static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
459 #define LOCK_DEBUG_MUTEX pthread_mutex_lock( &mutex2 );
460 #define UNLOCK_DEBUG_MUTEX pthread_mutex_unlock( &mutex2 );
461 #else
462 #define LOCK_DEBUG_MUTEX
463 #define UNLOCK_DEBUG_MUTEX
464 #endif
465 
466 #endif
467 
468 /* Define macros for accessing all items of thread-safe global data
469    used by this module. */
470 #ifdef THREAD_SAFE
471 
472 #define sizeof_memory astGLOBAL(Memory,Sizeof_Memory)
473 #define cache astGLOBAL(Memory,Cache)
474 #define cache_init astGLOBAL(Memory,Cache_Init)
475 #define use_cache astGLOBAL(Memory,Use_Cache)
476 
477 /* Define the initial values for the global data for this module. */
478 #define GLOBAL_inits \
479    globals->Sizeof_Memory = 0; \
480    globals->Cache_Init = 0; \
481    globals->Use_Cache = 0; \
482 
483 /* Create the global initialisation function. */
484 astMAKE_INITGLOBALS(Memory)
485 
486 /* If thread safety is not needed, declare globals at static variables. */
487 /* -------------------------------------------------------------------- */
488 #else
489 
490 /* The size of a Memory header structure, padded to a multiple of 8
491    bytes. This value is initialised by the SizeOfMemory function, and
492    should be accessed using the SIZEOF_MEMORY macro. */
493 static size_t sizeof_memory = 0;
494 
495 /* A cache of allocated but currently unused memory block. This cache is
496    maintained in order to avoid the overhead of continual calls to malloc to
497    allocate small blocks of memory. The vast majority of memory blocks
498    allocated by AST are under 200 bytes in size. Each element in this array
499    stores a pointer to the header for a free (i.e. allocated but currently
500    unused) memory block. The size of the memory block (not including the
501    Memory header) will equal the index at which the pointer is stored within
502    "cache". Each free memory block contains (in its Memory header) a pointer
503    to the header for another free memory block of the same size (or a NULL
504    pointer if there are no other free memory blocks of the same size). */
505 static Memory *cache[ MXCSIZE + 1 ];
506 
507 /* Has the "cache" array been initialised? */
508 static int cache_init = 0;
509 
510 /* Should the cache be used? */
511 static int use_cache = 0;
512 
513 #endif
514 
515 /* Prototypes for Private Functions. */
516 /* ================================= */
517 static size_t SizeOfMemory( int * );
518 static char *CheckTempStart( const char *, const char *, const char *, char *, int *, int *, int *, int *, int *, int *, int *, int * );
519 static char *ChrMatcher( const char *, const char *, const char *, const char *, const char *[], int, int, int, char ***, int *, const char **, int * );
520 static char *ChrSuber( const char *, const char *, const char *[], int, int, char ***, int *, const char **, int * );
521 
522 #ifdef MEM_DEBUG
523 static void Issue( Memory *, int * );
524 static void DeIssue( Memory *, int * );
525 #endif
526 
527 #ifdef MEM_PROFILE
528 static AstTimer *ReportTimer( AstTimer *, int, AstTimer **, int *, int * );
529 static int CompareTimers( const void *, const void * );
530 static int CompareTimers2( const void *, const void * );
531 #endif
532 
533 /* Function implementations. */
534 /* ========================= */
astAppendString_(char * str1,int * nc,const char * str2,int * status)535 char *astAppendString_( char *str1, int *nc, const char *str2, int *status ) {
536 /*
537 *++
538 *  Name:
539 *     astAppendString
540 
541 *  Purpose:
542 *     Append a string to another string which grows dynamically.
543 
544 *  Type:
545 *     Public function.
546 
547 *  Synopsis:
548 *     #include "memory.h"
549 *     char *astAppendString( char *str1, int *nc, const char *str2 )
550 
551 *  Description:
552 *     This function appends one string to another dynamically
553 *     allocated string, extending the dynamic string as necessary to
554 *     accommodate the new characters (plus the final null).
555 
556 *  Parameters:
557 *     str1
558 *        Pointer to the null-terminated dynamic string, whose memory
559 *        has been allocated using an AST memory allocation function.
560 *        If no space has yet been allocated for this string, a NULL
561 *        pointer may be given and fresh space will be allocated by this
562 *        function.
563 *     nc
564 *        Pointer to an integer containing the number of characters in
565 *        the dynamic string (excluding the final null). This is used
566 *        to save repeated searching of this string to determine its
567 *        length and it defines the point where the new string will be
568 *        appended. Its value is updated by this function to include
569 *        the extra characters appended.
570 *
571 *        If "str1" is NULL, the initial value supplied for "*nc" will
572 *        be ignored and zero will be used.
573 *     str2
574 *        Pointer to a constant null-terminated string, a copy of which
575 *        is to be appended to "str1".
576 
577 *  Returned Value:
578 *     astAppendString()
579 *        A possibly new pointer to the dynamic string with the new string
580 *        appended (its location in memory may have to change if it has to
581 *        be extended, in which case the original memory is automatically
582 *        freed by this function). When the string is no longer required,
583 *        its memory should be freed using astFree.
584 
585 *  Notes:
586 *     - If this function is invoked with the global error status set
587 *     or if it should fail for any reason, then the returned pointer
588 *     will be equal to "str1" and the dynamic string contents will be
589 *     unchanged.
590 *--
591 */
592 
593 /* Local Variables: */
594    char *result;                 /* Pointer value to return */
595    int len;                      /* Length of new string */
596 
597 /* Initialise. */
598    result = str1;
599 
600 /* If the first string pointer is NULL, also initialise the character
601    count to zero. */
602    if ( !str1 ) *nc = 0;
603 
604 /* Check the global error status. */
605    if ( !astOK || !str2 ) return result;
606 
607 /* Calculate the total string length once the two strings have been
608    concatenated. */
609    len = *nc + (int) strlen( str2 );
610 
611 /* Extend the first (dynamic) string to the required length, including
612    a final null. Save the resulting pointer, which will be
613    returned. */
614    result = astGrow( str1, len + 1, sizeof( char ) );
615 
616 /* If OK, append the second string and update the total character
617    count. */
618    if ( astOK ) {
619       (void) strcpy( result + *nc, str2 );
620       *nc = len;
621    }
622 
623 /* Return the result pointer. */
624    return result;
625 }
626 
astCalloc_(size_t nmemb,size_t size,int * status)627 void *astCalloc_( size_t nmemb, size_t size, int *status ) {
628 /*
629 *++
630 *  Name:
631 *     astCalloc
632 
633 *  Purpose:
634 *     Allocate and initialise memory.
635 
636 *  Type:
637 *     Public function.
638 
639 *  Synopsis:
640 *     #include "memory.h"
641 *     void *astCalloc( size_t nmemb, size_t size )
642 
643 *  Description:
644 *     This function allocates memory in a similar manner to the
645 *     standard C "calloc" function, but with improved security
646 *     (against memory leaks, etc.) and with error reporting. It also
647 *     fills the allocated memory with zeros.
648 *
649 *     Like astMalloc, it allows zero-sized memory allocation
650 *     (without error), resulting in a NULL returned pointer value.
651 
652 *  Parameters:
653 *     nmemb
654 *        The number of array elements for which memory is to be allocated.
655 *     size
656 *        The size of each array element, in bytes.
657 
658 *  Returned Value:
659 *     astCalloc()
660 *        If successful, the function returns a pointer to the start of
661 *        the allocated memory region. If the size allocated is zero, this
662 *        will be a NULL pointer.
663 
664 *  Notes:
665 *     - A pointer value of NULL is returned if this function is
666 *     invoked with the global error status set or if it fails for any
667 *     reason.
668 *--
669 */
670 /* Local Variables: */
671    void *result;    /* Returned pointer */
672 
673 /* Initialise. */
674    result = NULL;
675 
676 /* Check the global error status. */
677    if ( !astOK ) return result;
678 
679 /* Attempt to allocate and initialise the required amount of memory. */
680    result = astMallocInit( nmemb*size );
681 
682 /* If the above call failed due to failure of the system malloc function,
683    issue an extra error giving the number of elements and element size. */
684    if( astStatus == AST__NOMEM ) {
685       astError( AST__NOMEM, "(%lu elements, each of %lu bytes).", status,
686                 (unsigned long) nmemb, (unsigned long) size );
687    }
688 
689 /* Return the result. */
690    return result;
691 }
692 
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)693 static char *CheckTempStart( const char *template, const char *temp,
694                              const char *pattern,
695                              char *allowed, int *ntemp, int *allow,
696                              int *min_nc, int *max_nc, int *start_sub,
697                              int *end_sub, int *greedy, int *status ){
698 /*
699 *  Name:
700 *     CheckTempStart
701 
702 *  Purpose:
703 *     Examine the leading field in an astChrSub template.
704 
705 *  Type:
706 *     Private function.
707 
708 *  Synopsis:
709 *     char *CheckTempStart( const char *template, const char *temp,
710 *                           const char *pattern,
711 *                           char *allowed, int *ntemp, int *allow,
712 *                           int *min_nc, int *max_nc, int *start_sub,
713 *                           int *end_sub, int *greedy, int *status )
714 
715 *  Description:
716 *     This function returns inforation about the leading field in a
717 *     template string supplied to astChrSub.
718 
719 *  Parameters:
720 *     template
721 *        The full template string (used for error messages).
722 *     temp
723 *        Pointer to the next character to read from the template string.
724 *     pattern
725 *        Pointer to the user supplied pattern string (only used in error
726 *        messages).
727 *     allowed
728 *        Pointer to a buffer in which to store a string of characters
729 *        that the leading temeplate field will match. A NULL pointer may
730 *        be supplied in which case new memory will be allocated. The
731 *        supplied memory is expanded as necessary, and a pointer to it is
732 *        returned as the function value.
733 *     ntemp
734 *        Address of an int in which to return the number of characters
735 *        consumed from the start of "temp".
736 *     allow
737 *        Address of an int in which to return a flag which is non-zero if
738 *        the returned string contains characters that are allowed in the
739 *        test field, or zero if the returned string contains characters that
740 *        are disallowed in the test field.
741 *     min_nc
742 *        Address of an int in which to return the minimum number of
743 *        test characters that must belong to the returned set of
744 *        allowed characters.
745 *     max_nc
746 *        Address of an int in which to return the maximum number of
747 *        test characters that must belong to the returned set of
748 *        allowed characters.
749 *     start_sub
750 *        Address of an int in which to return a flag which is non-zero if
751 *        the leading template field indicates the start of a field to be
752 *        substituted. In this case the supplied "allowed" pointer is
753 *        returned without change as the function value, "Min_nc" is
754 *        returned as zero, and max_nc is returned as zero.
755 *     end_sub
756 *        Address of an int in which to return a flag which is non-zero if
757 *        the leading template field indicates the end of a field to be
758 *        substituted. In this case the supplied "allowed" pointer is
759 *        returned without change as the function value, "Min_nc" is
760 *        returned as zero, and limit is returned as zero.
761 *     greedy
762 *        Address of an int in which to return a flag which is non-zero if
763 *        the template starts with a greedy quantifier.
764 *     status
765 *        Pointer to the inherited status variable.
766 
767 *  Returned Value:
768 *     Pointer to a (possibly newly allocated) memory area holding a
769 *     string of characters that the leading temeplate field will match.
770 *     This string should be released using astFree when no longer needed.
771 *     If a NULL pointyer is returned, then all characters are allowed
772 *     (or disallowed if "*allow" is zero).
773 
774 *  Notes:
775 *     - The returned value is also stored in the module variable
776 *     sizeof_memory.
777 */
778 
779 /* Local Variables: */
780    char *result;
781    const char *start;
782    const char *end;
783 
784 /* Initialise. */
785    result = allowed;
786    *ntemp = 0;
787    *allow = 1;
788    *min_nc = 0;
789    *max_nc = 0;
790    *start_sub = 0;
791    *end_sub = 0;
792    *greedy = 1;
793 
794 /* Check global status */
795    if( !astOK ) return result;
796 
797 /* If the next character is an opening parenthesis, this marks the start
798    of a substitution field. */
799    if( *temp == '(' ) {
800       *start_sub = 1;
801       *ntemp = 1;
802 
803 /* If the next character is an closing parenthesis, this marks the end
804    of a substitution field. */
805    } else if( *temp == ')' ) {
806       *end_sub = 1;
807       *ntemp = 1;
808 
809 /* If the next character is an opening bracket, this marks the start of a
810    field of allowed or disallowed characters. */
811    } else {
812       if( *temp == '[' ) {
813 
814 /* If the first character in the brackets is "^" this is a field of
815    disallowed characters, otherwise they are allowed. */
816          if( temp[ 1 ] == '^' ) {
817             *allow = 0;
818             start = temp + 2;
819          } else {
820             start = temp + 1;
821          }
822 
823 /* Get a pointer to the closing bracket. */
824          end = strchr( temp, ']' );
825 
826 /* Copy the intervening string into the returned string. */
827          if( end ) {
828             result = astStore( allowed, start, end - start + 1 );
829             if( result ) result[ end - start  ] = 0;
830 
831 /* Report an error if no closing bracket was found. */
832          } else {
833             astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
834                       "missing ']'.", status, pattern );
835          }
836 
837 /* Indicate how many template characters have been used. */
838          *ntemp = end - temp + 1;
839 
840 /* A single dot matches any character. */
841       } else if( *temp == '.' ) {
842          result = astFree( result );
843          *ntemp = 1;
844 
845 /* Now deal with escape sequences. */
846       } else if( *temp == '\\' ) {
847 
848 /* Digits... */
849          if( temp[ 1 ] == 'd' || temp[ 1 ] == 'D' ) {
850             result = astStore( allowed, "0123456789", 11 );
851             result[ 10 ] = 0;
852             if( temp[ 1 ] == 'D' ) *allow = 0;
853 
854 /* White space... */
855          } else if( temp[ 1 ] == 's' || temp[ 1 ] == 'S' ) {
856             result = astStore( allowed, " 	\n\r", 5 );
857             result[ 4 ] = 0;
858             if( temp[ 1 ] == 'S' ) *allow = 0;
859 
860 /* Word characters... */
861          } else if( temp[ 1 ] == 'w' || temp[ 1 ] == 'W' ) {
862             result = astStore( allowed, "abcdefghijklmnopqrstuvwxyz"
863                                "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",
864                                64 );
865             result[ 63 ] = 0;
866             if( temp[ 1 ] == 'W' ) *allow = 0;
867 
868 /* Any other character is treated literally. */
869          } else {
870             result = astStore( allowed, temp + 1, 2 );
871             result[ 1 ] = 0;
872          }
873 
874 /* Set number of template characters consumed. */
875          *ntemp = 2;
876 
877 /* Everything else must be matched literally. */
878       } else {
879 
880          if( *temp == '*' || *temp == '?' || *temp == '+' ){
881             astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
882                       "field starts with '%c'.", status, pattern, temp[ *ntemp ] );
883          } else {
884             result = astStore( allowed, temp, 2 );
885             result[ 1 ] = 0;
886             *ntemp = 1;
887          }
888 
889       }
890 
891 /* Now see if there is any quantifier. */
892       if( temp[ *ntemp ] == '*' ) {
893          *min_nc = 0;
894          *max_nc = INT_MAX;
895          (*ntemp)++;
896          if( temp[ *ntemp ] == '?' ){
897             *greedy = 0;
898             (*ntemp)++;
899          }
900 
901       } else if( temp[ *ntemp ] == '+' ) {
902          *min_nc = 1;
903          *max_nc = INT_MAX;
904          (*ntemp)++;
905          if( temp[ *ntemp ] == '?' ){
906             *greedy = 0;
907             (*ntemp)++;
908          }
909 
910       } else if( temp[ *ntemp ] == '?' ) {
911          *min_nc = 0;
912          *max_nc = 1;
913          (*ntemp)++;
914 
915       } else {
916 
917 /* See if the remaining string starts with "{nnn}". If so, extract the
918    "nnn" and use it as the minimum and maximum field length. */
919          if( temp[ *ntemp ] == '{' ) {
920 
921             start = temp + *ntemp + 1;
922             while( isdigit( (int) *start ) ) {
923                *min_nc = 10*( *min_nc ) + (int )( ( *start ) - '0' );
924                start++;
925             }
926 
927             if( *start == '}' ) {
928                *max_nc = *min_nc;
929                *ntemp = start - temp + 1;
930             } else {
931                start = NULL;
932             }
933 
934          } else {
935             start = NULL;
936          }
937 
938 /* If the remaining string does not start with "{nnn}", use a minimum and
939    maximum field length of 1. */
940          if( !start ) {
941             *min_nc = 1;
942             *max_nc = 1;
943          }
944       }
945    }
946 
947 /* Return the string of allowed characters. */
948    return result;
949 }
950 
astChr2Double_(const char * str,int * status)951 double astChr2Double_( const char *str, int *status ) {
952 /*
953 *++
954 *  Name:
955 *     astChr2Double
956 
957 *  Purpose:
958 *     read a double value from a string.
959 
960 *  Type:
961 *     Public function.
962 
963 *  Synopsis:
964 *     #include "memory.h"
965 *     double astChr2Double( const char *str )
966 
967 *  Description:
968 *     This function reads a double from the supplied null-terminated string,
969 *     ignoring leading and trailing white space. AST__BAD is ereturned
970 *     without error if the string is not a numerical value.
971 
972 *  Parameters:
973 *     str
974 *        Pointer to the string.
975 
976 *  Returned Value:
977 *     astChr2Double()
978 *       The double value, or AST__BAD.
979 
980 *  Notes:
981 *     -  A value of AST__BAD is returned if this function is invoked with
982 *     the global error status set or if it should fail for any reason.
983 *--
984 */
985 
986 /* Local Variables: */
987    double result;     /* The returned value */
988    int ival;          /* Integer value read from string */
989    int len;           /* Length of supplied string */
990    int nc;            /* Number of characters read from the string */
991 
992 /* Check the global error status and supplied pointer. */
993    if ( !astOK || !str ) return AST__BAD;
994 
995 /* Save the length of the supplied string. */
996    len = strlen( str );
997 
998 /* Use scanf to read the floating point value. This fails if either 1) the
999    string does not begin with a numerical value (in which case astSscanf
1000    returns zero), or 2) there are non-white characters following the
1001    numerical value (in which case "nc" - the number of characters read from
1002    the string - is less than the length of the string). */
1003    if ( nc = 0,
1004         ( 1 != astSscanf( str, " %lg %n", &result, &nc ) ) || ( nc < len ) ) {
1005       result = AST__BAD;
1006    }
1007 
1008 /* If the above failed, try again allowing the string to be an integer
1009    followed by a dot (e.g. "1."). Some implementations of sscanf do not
1010    consider this to be a floating point value. */
1011    if( 1 || result == AST__BAD ) {
1012       if ( nc = 0,
1013            ( 1 == astSscanf( str, " %d. %n", &ival, &nc ) ) && ( nc >= len ) ) {
1014          result = ival;
1015       }
1016    }
1017 
1018 /* Return the result. */
1019    return result;
1020 }
1021 
astChrCase_(const char * in,char * out,int upper,int blen,int * status)1022 void astChrCase_( const char *in, char *out, int upper, int blen, int *status ) {
1023 /*
1024 *++
1025 *  Name:
1026 *     astChrCase
1027 
1028 *  Purpose:
1029 *     Convert a string to upper or lower case.
1030 
1031 *  Type:
1032 *     Public function.
1033 
1034 *  Synopsis:
1035 *     #include "memory.h"
1036 *     void astChrCase( const char *in, char *out, int upper, int blen, int *status )
1037 
1038 *  Description:
1039 *     This function converts a supplied string to upper or lower case,
1040 *     storing the result in a supplied buffer. The astStringCase function
1041 *     is similar, but stores the result in a dynamically allocated buffer.
1042 
1043 *  Parameters:
1044 *     in
1045 *        Pointer to the null terminated string to be converted. If this
1046 *        is NULL, the supplied contents of the "out" string are used as
1047 *        the input string.
1048 *     out
1049 *        Pointer to the buffer to receive the converted string. The
1050 *        length of this buffer is given by "blen". If NULL is supplied
1051 *        for "in", then the supplied contents of "out" are converted and
1052 *        written back into "out" over-writing the supplied contents.
1053 *     upper
1054 *        If non-zero, the string is converted to upper case. Otherwise it
1055 *        is converted to lower case.
1056 *     blen
1057 *        The length of the output buffer. Ignored if "in" is NULL. No
1058 *        more than "blen - 1" characters will be copied from "in" to
1059 *        "out", and a terminating null character will then be added.
1060 
1061 *--
1062 */
1063 
1064 /* Local Variables: */
1065    const char *pin;
1066    char *pout;
1067    int i;
1068 
1069 /* Check the global error status. */
1070    if ( !astOK ) return;
1071 
1072 /* The simple case of over-writing the supplied string. */
1073    if( ! in ) {
1074       pout = out - 1;
1075       while( *(++pout) ) *pout = toupper( (int) *pout );
1076 
1077 /* If a separate output buffer has been supplied... */
1078    } else {
1079 
1080 /* Initialise pointers to the input and output buffers. */
1081       pin = in;
1082       pout = out;
1083 
1084 /* Copy the string character by character, converting the case in the
1085    process. Start counting from 1, not 0, in order to ensure that we are
1086    left with room for a terminating null. */
1087       for( i = 1; i < blen && *pin; i++ ) {
1088          *(pout++) = toupper( (int) *(pin++) );
1089       }
1090 
1091 /* Terminate the returned string. */
1092       *pout = 0;
1093    }
1094 }
1095 
astChrMatch_(const char * str1,const char * str2,int * status)1096 int astChrMatch_( const char *str1, const char *str2, int *status ) {
1097 /*
1098 *++
1099 *  Name:
1100 *     astChrMatch
1101 
1102 *  Purpose:
1103 *     Case insensitive string comparison.
1104 
1105 *  Type:
1106 *     Public function.
1107 
1108 *  Synopsis:
1109 *     #include "memory.h"
1110 *     int astChrMatch( const char *str1, const char *str2 )
1111 
1112 *  Description:
1113 *     This function compares two null terminated strings for equality,
1114 *     discounting differences in case and any trailing white space in either
1115 *     string.
1116 
1117 *  Parameters:
1118 *     str1
1119 *        Pointer to the first string.
1120 *     str2
1121 *        Pointer to the second string.
1122 
1123 *  Returned Value:
1124 *     astChrMatch()
1125 *        Non-zero if the two strings match, otherwise zero.
1126 
1127 *  Notes:
1128 *     -  A value of zero is returned if this function is invoked with the
1129 *     global error status set or if it should fail for any reason.
1130 *--
1131 */
1132 
1133 /* Local Variables: */
1134    int match;                    /* Strings match? */
1135 
1136 /* Check the global error status. */
1137    if ( !astOK ) return 0;
1138 
1139 /* Initialise. */
1140    match = 1;
1141 
1142 /* Loop to compare characters in the two strings until a mis-match occurs or
1143    we reach the end of the longer string. */
1144    while ( match && ( *str1 || *str2 ) ) {
1145 
1146 /* Two characters match if (a) we are at the end of one string and the other
1147    string contains white space or (b) both strings contain the same character
1148    when converted to lower case. */
1149       match = ( !*str1 && isspace( *str2 ) ) ||
1150               ( !*str2 && isspace( *str1 ) ) ||
1151               ( tolower( *str1 ) == tolower( *str2 ) );
1152 
1153 /* Step through each string a character at a time until its end is reached. */
1154       if ( *str1 ) str1++;
1155       if ( *str2 ) str2++;
1156    }
1157 
1158 /* Return the result. */
1159    return match;
1160 }
1161 
astChrMatchN_(const char * str1,const char * str2,size_t n,int * status)1162 int astChrMatchN_( const char *str1, const char *str2, size_t n, int *status ) {
1163 /*
1164 *++
1165 *  Name:
1166 *     astChrMatchN
1167 
1168 *  Purpose:
1169 *     Case insensitive string comparison of at most N characters
1170 
1171 *  Type:
1172 *     Public function.
1173 
1174 *  Synopsis:
1175 *     #include "memory.h"
1176 *     int astChrMatchN( const char *str1, const char *str2, size_t n )
1177 
1178 *  Description:
1179 *     This function compares two null terminated strings for equality,
1180 *     discounting differences in case and any trailing white space in either
1181 *     string. No more than "n" characters are compared.
1182 
1183 *  Parameters:
1184 *     str1
1185 *        Pointer to the first string.
1186 *     str2
1187 *        Pointer to the second string.
1188 *     n
1189 *        Maximum number of characters to compare.
1190 
1191 *  Returned Value:
1192 *     astChrMatchN()
1193 *        Non-zero if the two strings match, otherwise zero.
1194 
1195 *  Notes:
1196 *     -  A value of zero is returned if this function is invoked with the
1197 *     global error status set or if it should fail for any reason.
1198 *--
1199 */
1200 
1201 /* Local Variables: */
1202    int match;                    /* Strings match? */
1203    int nc;                       /* Number of characters compared so far */
1204 
1205 /* Check the global error status. */
1206    if ( !astOK ) return 0;
1207 
1208 /* Initialise. */
1209    match = 1;
1210 
1211 /* So far we have compared zero characters */
1212    nc = 0;
1213 
1214 /* Loop to compare characters in the two strings until a mis-match occurs or
1215    we reach the end of the longer string, or we reach the specified
1216    maximum number of characters. */
1217    while ( match && ( *str1 || *str2 ) && nc++ < n ) {
1218 
1219 /* Two characters match if (a) we are at the end of one string and the other
1220    string contains white space or (b) both strings contain the same character
1221    when converted to lower case. */
1222       match = ( !*str1 && isspace( *str2 ) ) ||
1223               ( !*str2 && isspace( *str1 ) ) ||
1224               ( tolower( *str1 ) == tolower( *str2 ) );
1225 
1226 /* Step through each string a character at a time until its end is reached. */
1227       if ( *str1 ) str1++;
1228       if ( *str2 ) str2++;
1229    }
1230 
1231 /* Return the result. */
1232    return match;
1233 }
1234 
astChrSplit_(const char * str,int * n,int * status)1235 char **astChrSplit_( const char *str, int *n, int *status ) {
1236 /*
1237 *++
1238 *  Name:
1239 *     astChrSplit
1240 
1241 *  Purpose:
1242 *     Extract words from a supplied string.
1243 
1244 *  Type:
1245 *     Public function.
1246 
1247 *  Synopsis:
1248 *     #include "memory.h"
1249 *     char **astChrSplit_( const char *str, int *n )
1250 
1251 *  Description:
1252 *     This function extracts all space-separated words form the supplied
1253 *     string and returns them in an array of dynamically allocated strings.
1254 
1255 *  Parameters:
1256 *     str
1257 *        Pointer to the string to be split.
1258 *     n
1259 *        Address of an int in which to return the number of words returned.
1260 
1261 *  Returned Value:
1262 *     astChrSplit()
1263 *        A pointer to a dynamically allocated array containing "*n" elements.
1264 *        Each element is a pointer to a dynamically allocated character
1265 *        string containing a word extracted from the supplied string. Each
1266 *        of these words will have no leading or trailing white space.
1267 
1268 *  Notes:
1269 *     -  A NULL pointer is returned if this function is invoked with the
1270 *     global error status set or if it should fail for any reason, or if
1271 *     the supplied string contains no words.
1272 *--
1273 */
1274 
1275 /* Local Variables: */
1276    char **result;
1277    char *w;
1278    const char *p;
1279    const char *ws;
1280    int first;
1281    int state;
1282    int wl;
1283 
1284 /* Check the global error status. */
1285    if ( !astOK ) return NULL;
1286 
1287 /* Initialise. */
1288    result = NULL;
1289    ws = NULL;
1290    *n = 0;
1291 
1292 /* State 0 is "looking for the next non-white character which marks the
1293    start of the next word". State 1 is "looking for the next white character
1294    which marks the end of the current word". */
1295    state = 0;
1296 
1297 /* Loop through all characters in the supplied string, including the
1298    terminating null. */
1299    p = str - 1;
1300    first = 1;
1301    while( *(p++) || first ) {
1302       first = 0;
1303 
1304 /* If this is the terminating null or a space, and we are currently looking
1305    for the end of a word, allocate memory for the new word, copy the text
1306    in, terminate it, extend the returned array by one element, and store
1307    the new word in it. */
1308       if( !*p || isspace( *p ) ) {
1309          if( state == 1 ) {
1310             wl = p - ws;
1311             w = astMalloc( wl + 1 );
1312             if( w ) {
1313                strncpy( w, ws, wl );
1314                w[ wl ] = 0;
1315                result = astGrow( result, *n + 1, sizeof( char * ) );
1316                if( result ) result[ (*n)++ ] = w;
1317             }
1318             state = 0;
1319          }
1320 
1321 /* If this is non-blank character, and we are currently looking for the
1322    start of a word, note the address of the start of the word, and
1323    indicate that we are now looking for the end of a word. */
1324       } else {
1325          if( state == 0 ) {
1326             state = 1;
1327             ws = p;
1328          }
1329       }
1330    }
1331 
1332 /* Return the result. */
1333    return result;
1334 }
1335 
astChrSplitC_(const char * str,char c,int * n,int * status)1336 char **astChrSplitC_( const char *str, char c, int *n, int *status ) {
1337 /*
1338 *++
1339 *  Name:
1340 *     astChrSplitC
1341 
1342 *  Purpose:
1343 *     Split a string using a specified character delimiter.
1344 
1345 *  Type:
1346 *     Public function.
1347 
1348 *  Synopsis:
1349 *     #include "memory.h"
1350 *     char **astChrSplitC( const char *str, char c, int *n )
1351 
1352 *  Description:
1353 *     This function extracts all sub-strings separated by a given
1354 *     character from the supplied string and returns them in an array
1355 *     of dynamically allocated strings. The delimiter character itself
1356 *     is not included in the returned strings.
1357 *
1358 *     Delimiter characters that are preceded by "\" are not used as
1359 *     delimiters but are included in the returned word instead (without
1360 *     the "\").
1361 
1362 *  Parameters:
1363 *     str
1364 *        Pointer to the string to be split.
1365 *     c
1366 *        The delimiter character.
1367 *     n
1368 *        Address of an int in which to return the number of words returned.
1369 
1370 *  Returned Value:
1371 *     astChrSplitC()
1372 *        A pointer to a dynamically allocated array containing "*n" elements.
1373 *        Each element is a pointer to a dynamically allocated character
1374 *        string containing a word extracted from the supplied string.
1375 
1376 *  Notes:
1377 *     -  A NULL pointer is returned if this function is invoked with the
1378 *     global error status set or if it should fail for any reason, or if
1379 *     the supplied string contains no words.
1380 *--
1381 */
1382 
1383 /* Local Variables: */
1384    char **result;
1385    char *word;
1386    const char *p;
1387    int escaped;
1388    int wordlen;
1389 
1390 /* Initialise returned values. */
1391    *n = 0;
1392    result = NULL;
1393 
1394 /* Check the global error status. */
1395    if ( !astOK ) return result;
1396 
1397 /* More initialisations. */
1398    word = NULL;
1399    wordlen = 0;
1400    escaped = 0;
1401 
1402 /* Loop through all characters in the supplied string, including the
1403    terminating null. */
1404    p = str;
1405    while( *p ) {
1406 
1407 /* Is this a delimiter character? */
1408       if( *p == c ) {
1409 
1410 /* If it is escaped, it does not mark the end of a word. Put it into the
1411    current output buffer instead, overwriting the escape character that
1412    preceded it. */
1413          if( escaped ) {
1414             word[ wordlen - 1 ] = c;
1415 
1416 /* The next character is not escaped. */
1417             escaped = 0;
1418 
1419 /* If the delimiter is not escaped, terminate the current word and store
1420    a pointer to it in the returned array. */
1421          } else {
1422             result = astGrow( result, *n + 1, sizeof( char * ) );
1423             word = astGrow( word, wordlen + 1, 1 );
1424             if( result && word ) {
1425                word[ wordlen ] = 0;
1426                result[ (*n)++ ] = word;
1427                wordlen = 0;
1428                word = NULL;
1429             }
1430          }
1431 
1432 /* If this is not a delimitier character, store it in the returned word. */
1433       } else {
1434          word = astGrow( word, wordlen + 1, 1 );
1435          if( word ) word[ wordlen++ ] = *p;
1436 
1437 /* If the current character was escaped, indicate that the next character
1438    is not escaped. */
1439          if( escaped ) {
1440             escaped = 0;
1441 
1442 /* If this character is a unescaped backslash, set a flag indicating that the
1443    next character is escaped. */
1444          } else if( *p == '\\' ){
1445             escaped = 1;
1446          }
1447       }
1448 
1449 /* Move on to the next character. */
1450       p++;
1451    }
1452 
1453 /* Store the text following the final delimitier. */
1454    result = astGrow( result, *n + 1, sizeof( char * ) );
1455    word = astGrow( word, wordlen + 1, 1 );
1456    if( result && word ) {
1457       word[ wordlen ] = 0;
1458       result[ (*n)++ ] = word;
1459    }
1460 
1461 /* Return the result. */
1462    return result;
1463 }
1464 
astChrSplitRE_(const char * str,const char * regexp,int * n,const char ** matchend,int * status)1465 char **astChrSplitRE_( const char *str, const char *regexp, int *n,
1466                        const char **matchend, int *status ) {
1467 /*
1468 *++
1469 *  Name:
1470 *     astChrSplitRE
1471 
1472 *  Purpose:
1473 *     Extract sub-strings matching a specified regular expression.
1474 
1475 *  Type:
1476 *     Public function.
1477 
1478 *  Synopsis:
1479 *     #include "memory.h"
1480 *     char **astChrSplitRE( const char *str, const char *regexp, int *n,
1481 *                           const char **matchend )
1482 
1483 *  Description:
1484 *     This function compares the supplied string with the supplied
1485 *     regular expression. If they match, each section of the test string
1486 *     that corresponds to a parenthesised sub-string in the regular
1487 *     expression is copied and stored in the returned array.
1488 
1489 *  Parameters:
1490 *     str
1491 *        Pointer to the string to be split.
1492 *     regexp
1493 *        The regular expression. See "Template Syntax:" in the astChrSub
1494 *        prologue. Note, this function differs from astChrSub in that any
1495 *        equals signs (=) in the regular expression are treated literally.
1496 *     n
1497 *        Address of an int in which to return the number of sub-strings
1498 *        returned.
1499 *     matchend
1500 *        A pointer to a location at which to return a pointer to the
1501 *        character that follows the last character within the supplied test
1502 *        string that matched any parenthesises sub-section of "regexp". A
1503 *        NULL pointer is returned if no matches were found. A NULL pointer
1504 *        may be supplied if the location of the last matching character is
1505 *        not needed.
1506 
1507 *  Returned Value:
1508 *     astChrSplitRE()
1509 *        A pointer to a dynamically allocated array containing "*n" elements.
1510 *        Each element is a pointer to a dynamically allocated character
1511 *        string containing a sub-string extracted from the supplied string.
1512 *        The array itself, and the strings within it, should all be freed
1513 *        using astFree when no longer needed.
1514 
1515 *  Notes:
1516 *     - If a parenthesised sub-string in the regular expression is matched
1517 *     by more than one sub-string within the test string, then only the
1518 *     first is returned. To return multiple matches, the regular
1519 *     expression should include multiple copies of the parenthesised
1520 *     sub-string (for instance, separated by ".+?" if the intervening
1521 *     string is immaterial).
1522 *     -  A NULL pointer is returned if this function is invoked with the
1523 *     global error status set or if it should fail for any reason, or if
1524 *     the supplied string contains no words.
1525 *--
1526 */
1527 
1528 /* Local Variables: */
1529    char **result;
1530    char *temp;
1531    int i;
1532 
1533 /* Initialise returned values. */
1534    *n = 0;
1535    result = NULL;
1536 
1537 /* Check global status */
1538    if( !astOK ) return result;
1539 
1540 /* Call ChrSuber to do the work, saving the matching parts of the test
1541    string. */
1542    temp = ChrSuber( str, regexp, NULL, 0, 1, &result, n, matchend, status );
1543    if( temp ) {
1544       temp = astFree( temp );
1545 
1546 /* Free all results if no match was found. */
1547    } else if( result ) {
1548       for( i = 0; i < *n; i++ ) result[ i ] = astFree( result[ i ] );
1549       result = astFree( result );
1550       *n = 0;
1551    }
1552 
1553 /* Return the result */
1554    return result;
1555 }
1556 
ChrSuber(const char * test,const char * pattern,const char * subs[],int nsub,int ignore_equals,char *** parts,int * npart,const char ** matchend,int * status)1557 char *ChrSuber( const char *test, const char *pattern, const char *subs[],
1558                 int nsub, int ignore_equals, char ***parts, int *npart,
1559                 const char **matchend, int *status ){
1560 /*
1561 *  Name:
1562 *     ChrSuber
1563 
1564 *  Purpose:
1565 *     Performs substitutions on a supplied string.
1566 
1567 *  Type:
1568 *     Private function.
1569 
1570 *  Synopsis:
1571 *     #include "memory.h"
1572 *     char *ChrSuber( const char *test, const char *pattern,
1573 *                     const char *subs[], int nsub, int ignore_equals,
1574 *                     char ***parts, int *npart, const char **matchend,
1575 *                     int *status )
1576 
1577 *  Description:
1578 *     This function performs the work for astChrSub and astChrSplitRE.
1579 
1580 *  Parameters:
1581 *     test
1582 *        The string to be tested.
1583 *     pattern
1584 *        The template string. See "Template Syntax:" in the astChrSub
1585          prologue.
1586 *     subs
1587 *        An array of strings that are to replace the sections of the test
1588 *        string that match each parenthesised sub-string in "pattern". The
1589 *        first element of "subs" replaces the part of the test string that
1590 *        matches the first parenthesised sub-string in the template, etc.
1591 *
1592 *        If "nsub" is zero, then the "subs" pointer is ignored. In this
1593 *        case, and if parameter "ignore_equals" is zero, substitution strings
1594 *        may be specified by appended them to the end of the "pattern" string,
1595 *        separated by "=" characters
1596 *     nsub
1597 *        The number of substitution strings supplied in array "subs".
1598 *     ignore_equals
1599 *        If non-zero, any equals signs in the supplied pattern are
1600 *        treated literally, rather than being used to split the template
1601 *        from any substitution strigs.
1602 *     parts
1603 *        Address of a location at which to return a pointer to an array
1604 *        of character string pointers. The strings are the sub-sections
1605 *        of "test" that matched the parenthesised sub-sections of
1606 *        "template". The array will have "*npart" elements. Ignored if NULL.
1607 *     npart
1608 *        Address of a location at which to return the length of the
1609 *        "parts" array. Ignored if "parts" is NULL.
1610 *     matchend
1611 *        A pointer to a location at which to return a pointer to the
1612 *        character that follows the last character within the supplied test
1613 *        string that matched any parenthesises sub-section of "regexp". A
1614 *        NULL pointer is returned if no matches were found. A NULL pointer
1615 *        may be supplied if the location of the last matching character is
1616 *        not needed.
1617 *     status
1618 *        Pointer to the inherited status variable.
1619 
1620 *  Returned Value:
1621 *     A pointer to a dynamically allocated string holding the result
1622 *     of the substitutions, or NULL if the test string does not match
1623 *     the template string. This string should be freed using astFree
1624 *     when no longer needed. If no substituions are specified then a
1625 *     copy of the test string is returned if it matches the template.
1626 
1627 *  Notes:
1628 *     -  A NULL pointer is returned if this function is invoked with the
1629 *     global error status set or if it should fail for any reason, or if
1630 *     the supplied test string does not match the template.
1631 
1632 */
1633 
1634 /* Local Variables: */
1635    char **sections;
1636    char **temps;
1637    char *cptr;
1638    char *result;
1639    char *temp;
1640    char *template;
1641    int i;
1642    int nsec;
1643    int ntemp;
1644    size_t tlen;
1645 
1646 /* Initialise */
1647    result = NULL;
1648    if( parts ) *npart = 0;
1649 
1650 /* Check global status */
1651    if( !astOK ) return result;
1652 
1653 /* If required, split the total "pattern" string into sections, using
1654    (unescaped) "=" characters as the delimiter. The first section is the
1655    actual template, and each subsequent section (if any) holds a
1656    substitution string. */
1657    if( ! ignore_equals ) {
1658       sections = astChrSplitC( pattern, '=', &nsec );
1659 
1660 /* If equals signs are being treated literally, just take a copy of the
1661    supplied pattern. */
1662    } else {
1663       cptr = astStore( NULL, pattern, strlen( pattern ) + 1 );
1664       sections = &cptr;
1665       nsec = 1;
1666    }
1667 
1668    if( sections ) {
1669 
1670 /* If the caller did not provide any substitution strings, use the ones
1671    appended to the end of the pattern string (if any). */
1672       if( nsub == 0 ) {
1673          subs = (void *) ( sections + 1 );
1674          nsub = nsec - 1;
1675       }
1676 
1677 /* Split the template section into sub-sections, using (unescaped) "|"
1678    characters as the delimiter. Each sub-section is an alternate pattern
1679    matching template. */
1680       temps = astChrSplitC( sections[ 0 ], '|', &ntemp );
1681 
1682    } else {
1683       temps = 0;
1684       ntemp = 0;
1685    }
1686 
1687 /* Loop round each template until all templates have been checked or a
1688    match occurs.. */
1689    for( i = 0; i < ntemp && !result; i++ ) {
1690       temp = temps[ i ];
1691       tlen = strlen( temp );
1692 
1693 /* If the template starts with "^" or "(^", remove the "^" character.
1694    Otherwise insert ".*?" at the start. Allocate three extra characters
1695    in case we later need to add ".*?" to the end of the string. */
1696       if( temp[ 0 ] == '^' ) {
1697          template = astMalloc( tlen + 3 );
1698          if( template ) {
1699             strcpy( template, temp + 1 );
1700             tlen--;
1701          }
1702 
1703       } else if( temp[ 0 ] == '(' && temp[ 1 ] == '^') {
1704          template = astMalloc( tlen + 3 );
1705          if( template ) {
1706             template[ 0 ] = '(';
1707             strcpy( template + 1, temp + 2 );
1708             tlen--;
1709          }
1710 
1711       } else {
1712          template = astMalloc( tlen + 7 );
1713          if( template ) {
1714             template[ 0 ] = '.';
1715             template[ 1 ] = '*';
1716             template[ 2 ] = '?';
1717             strcpy( template + 3, temp );
1718             tlen += 3;
1719          }
1720       }
1721 
1722 /* If the pattern ends with "$" or "$)", remove the "$" character. Otherwise
1723    insert ".*?" at the end. */
1724       if( template[ tlen - 1 ] == '$' ) {
1725          tlen--;
1726 
1727       } else if( template[ tlen - 2 ] == '$' && template[ tlen - 1 ] == ')' ) {
1728          template[ tlen - 2 ] = ')';
1729          tlen--;
1730 
1731       } else {
1732          template[ tlen ] = '.';
1733          template[ tlen + 1 ] = '*';
1734          template[ tlen + 2 ] = '?';
1735          tlen += 3;
1736       }
1737 
1738 /* Ensure the string is terminated */
1739       template[ tlen ] = 0;
1740 
1741 /* See if the test string matches the current template. */
1742       result = ChrMatcher( test, test + strlen( test ), template, pattern,
1743                            subs, nsub, 0, 1, parts, npart, matchend, status );
1744 
1745 /* Free resources. */
1746       template = astFree( template );
1747    }
1748 
1749    if( temps ) {
1750       for( i = 0; i < ntemp; i++ ) temps[ i ] = astFree( temps[ i ] );
1751       temps = astFree( temps );
1752    }
1753 
1754    if( sections ) {
1755       for( i = 0; i < nsec; i++ ) sections[ i ] = astFree( sections[ i ] );
1756       if( ! ignore_equals ) sections = astFree( sections );
1757    }
1758 
1759 /* Return a NULL pointer if an error has occurred. */
1760    if( !astOK ) result = astFree( result );
1761 
1762 /* Return the result */
1763    return result;
1764 }
1765 
astChrSub_(const char * test,const char * pattern,const char * subs[],int nsub,int * status)1766 char *astChrSub_( const char *test, const char *pattern, const char *subs[],
1767                   int nsub, int *status ){
1768 /*
1769 *++
1770 *  Name:
1771 c     astChrSub
1772 f     AST_CHRSUB
1773 
1774 *  Purpose:
1775 *     Performs substitutions on a supplied string.
1776 
1777 *  Type:
1778 *     Public function.
1779 
1780 *  Synopsis:
1781 c     #include "memory.h"
1782 c     char *astChrSub( const char *test, const char *pattern,
1783 c                      const char *subs[], int nsub )
1784 f     MATCH = AST_CHRSUB( TEST, PATTERN, RESULT, STATUS )
1785 
1786 *  Description:
1787 *     This function checks a supplied test string to see if it matches a
1788 *     supplied template. If it does, specified sub-sections of the test
1789 *     string may optionally be replaced by supplied substitution strings.
1790 *     The resulting string is returned.
1791 
1792 *  Parameters:
1793 c     test
1794 f     TEST = CHARACTER * ( * ) (Given)
1795 *        The string to be tested.
1796 *     pattern
1797 f     PATTERN = CHARACTER * ( * ) (Given)
1798 *        The template string. See "Template Syntax:" below.
1799 *     subs
1800 *        An array of strings that are to replace the sections of the test
1801 *        string that match each parenthesised sub-string in "pattern". The
1802 *        first element of "subs" replaces the part of the test string that
1803 *        matches the first parenthesised sub-string in the template, etc.
1804 *
1805 *        If "nsub" is zero, then the "subs" pointer is ignored. In this
1806 *        case, substitution strings may be specified by appended them to
1807 *        the end of the "pattern" string, separated by "=" characters.
1808 *        Note, if you need to include a literal "=" character in the
1809 *        pattern, precede it by an escape "\" character.
1810 *     nsub
1811 *        The number of substitution strings supplied in array "subs".
1812 f     RESULT = CHARACTER * ( * ) (Returned)
1813 f        Returned holding the result of the substitutions. If the test
1814 f        string does not match the template, then a blank string is
1815 f        returned.
1816 
1817 *  Returned Value:
1818 c     astChrSub()
1819 c        A pointer to a dynamically allocated string holding the result
1820 c        of the substitutions, or NULL if the test string does not match
1821 c        the template string. This string should be freed using astFree
1822 c        when no longer needed. If no substituions are specified then a
1823 c        copy of the test string is returned if it matches the template.
1824 f     AST_CHRSUB = LOGICAL
1825 f        .TRUE. if the test string matched the supplied template, and
1826 f        .FALSE. otherwise.
1827 
1828 *  Template Syntax:
1829 *     The template syntax is a minimal form of regular expression, The
1830 *     quantifiers allowed are "*", "?", "+", "{n}", "*?" and "+?" (the
1831 *     last two are non-greedy - they match the minimum length possible
1832 *     that still gives an overall match to the template). The only
1833 *     constraints allowed are "^" and "$". The following atoms are allowed:
1834 *
1835 *     - [chars]: Matches any of the specified characters.
1836 *
1837 *     - [^chars]: Matches anything but the specified characters.
1838 *
1839 *     - .: Matches any single character.
1840 *
1841 *     - x: Matches the character x so long as x has no other significance.
1842 *
1843 *     - \x: Always matches the character x (except for [dDsSwW]).
1844 *
1845 *     - \d: Matches a single digit.
1846 *
1847 *     - \D: Matches anything but a single digit.
1848 *
1849 *     - \w: Matches any alphanumeric character, and "_".
1850 *
1851 *     - \W: Matches anything but alphanumeric characters, and "_".
1852 *
1853 *     - \s: Matches white space.
1854 *
1855 *     - \S: Matches anything but white space.
1856 *
1857 *     Note, minus signs ("-") within brackets have no special significance,
1858 *     so ranges of characters must be specified explicitly.
1859 *
1860 *     Multiple template strings can be concatenated, using the "|"
1861 *     character to separate them. The test string is compared against
1862 *     each one in turn until a match is found.
1863 *
1864 c     Parentheses are used within each template to identify sub-strings
1865 c     that are to be replaced by the strings supplied in "sub".
1866 c
1867 c     If "nsub" is supplied as zero, then substitution strings may be
1868 c     specified by appended them to the end of the "pattern" string,
1869 c     separated by "=" characters. If "nsub" is not zero, then any
1870 c     substitution strings appended to the end of "pattern" are ignored.
1871 f
1872 f     Parentheses are used within each template to identify sub-strings
1873 f     that are to be replaced by new strings. The new strings are
1874 f     specified by appended them to the end of the "pattern" string,
1875 f     separated by "=" characters.
1876 *
1877 c     Each element of "subs"
1878 f     Each new string
1879 *     may contain a reference to a token of the
1880 *     form "$1", "$2", etc. The "$1" token will be replaced by the part
1881 *     of the test string that matched the first parenthesised sub-string
1882 *     in "pattern". The "$2" token will be replaced by the part of the
1883 *     test string that matched the second parenthesised sub-string in
1884 *     "pattern", etc.
1885 *
1886 
1887 c  Notes:
1888 c     -  A NULL pointer is returned if this function is invoked with the
1889 c     global error status set or if it should fail for any reason, or if
1890 c     the supplied test string does not match the template.
1891 
1892 *--
1893 */
1894 
1895 /* Call ChrSuber to do the work, without saving the matching parts of the
1896    test string. */
1897    return ChrSuber( test, pattern, subs, nsub, 0, NULL, NULL, NULL, status );
1898 }
1899 
astFree_(void * ptr,int * status)1900 void *astFree_( void *ptr, int *status ) {
1901 /*
1902 *++
1903 *  Name:
1904 *     astFree
1905 
1906 *  Purpose:
1907 *     Free previously allocated memory.
1908 
1909 *  Type:
1910 *     Public function.
1911 
1912 *  Synopsis:
1913 *     #include "memory.h"
1914 *     void *astFree( void *ptr )
1915 
1916 *  Description:
1917 *     This function frees memory that has previouly been dynamically
1918 *     allocated using one of the AST memory function.
1919 
1920 *  Parameters:
1921 *     ptr
1922 *        Pointer to previously allocated memory. An error will result
1923 *        if the memory has not previously been allocated by another
1924 *        function in this module. However, a NULL pointer value is
1925 *        accepted (without error) as indicating that no memory has yet
1926 *        been allocated, so that no action is required.
1927 
1928 *  Returned Value:
1929 *     astFree()
1930 *        Always returns a NULL pointer.
1931 
1932 *--
1933 */
1934 
1935 /* Local Variables: */
1936    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1937    Memory *mem;                  /* Pointer to memory header */
1938    int isdynamic;                /* Is the memory dynamically allocated? */
1939    size_t size;                  /* The usable size of the memory block */
1940 
1941 /* If needed, get a pointer to the thread specific global data structure. */
1942    astGET_GLOBALS(NULL);
1943 
1944 /* If the incoming pointer is NULL, do nothing. Otherwise, check if it
1945    points at dynamically allocated memory (IsDynamic sets the global
1946    error status if it does not). */
1947    if( ptr ) {
1948       IS_DYNAMIC( ptr, isdynamic );
1949    } else {
1950       isdynamic = 0;
1951    }
1952    if ( isdynamic ) {
1953 
1954 /* If OK, obtain a pointer to the memory header. */
1955       mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY );
1956 
1957 #ifdef MEM_DEBUG
1958       DeIssue( mem, status );
1959 #endif
1960 
1961 /* If the memory block is small enough, and the cache is being used, put it
1962    into the cache rather than freeing it, so that it can be reused. */
1963       size = mem->size;
1964       if( use_cache && size <= MXCSIZE ) {
1965          mem->next = cache[ size ];
1966          cache[ size ] = mem;
1967 
1968 /* Set the size to zero to indicate that the memory block has been freed.
1969    The size of the block is implied by the Cache element it is stored in. */
1970          mem->size = (size_t) 0;
1971 
1972 /* Simply free other memory blocks, clearing the "magic number" and size
1973    values it contains. This helps prevent accidental re-use of the memory. */
1974       } else {
1975          mem->magic = (unsigned long) 0;
1976          mem->size = (size_t) 0;
1977 
1978 /* Free the allocated memory. */
1979          FREE( mem );
1980       }
1981    }
1982 
1983 /* Always return a NULL pointer. */
1984    return NULL;
1985 
1986 }
1987 
astFreeDouble_(void * ptr,int * status)1988 void *astFreeDouble_( void *ptr, int *status ) {
1989 /*
1990 *++
1991 *  Name:
1992 *     astFreeDouble
1993 
1994 *  Purpose:
1995 *     Free previously double allocated memory.
1996 
1997 *  Type:
1998 *     Public function.
1999 
2000 *  Synopsis:
2001 *     #include "memory.h"
2002 *     void *astFreeDouble( void *ptr )
2003 
2004 *  Description:
2005 *     This function frees memory that has previouly been dynamically
2006 *     allocated using one of the AST memory function. It assumes that
2007 *     the supplied pointer is a pointer to an array of pointers. Each
2008 *     of these pointers is first freed, and then the supplied pointer
2009 *     is freed.
2010 *
2011 *     Note, this routine should not be used with arrays allocated
2012 *     by astGrow since astGrow over-allocates and so there may be
2013 *     non-initialised pointers at the end of the array.
2014 
2015 *  Parameters:
2016 *     ptr
2017 *        Pointer to previously allocated memory. An error will result
2018 *        if the memory has not previously been allocated by another
2019 *        function in this module. However, a NULL pointer value is
2020 *        accepted (without error) as indicating that no memory has yet
2021 *        been allocated, so that no action is required.
2022 
2023 *  Returned Value:
2024 *     astFreeDouble()
2025 *        Always returns a NULL pointer.
2026 
2027 *--
2028 */
2029 
2030 /* Local Variables: */
2031    int iptr;                     /* Index of sub-pointer */
2032    int nptr;                     /* Number of sub-pointers */
2033    size_t size;                  /* The usable size of the memory block */
2034    void **ptrs;                  /* Pointer to array of pointers */
2035 
2036 /* Check a pointer was supplied. */
2037    if( ! ptr ) return NULL;
2038 
2039 /* Get the size of the memory area. */
2040    size = astSizeOf( ptr );
2041 
2042 /* Get the number of points this amount of memory could hold. */
2043    nptr = size/sizeof( void * );
2044 
2045 /* Report an error if the size is not an integer multiple of an address
2046    size. */
2047    if( nptr*sizeof( void * ) != size ) {
2048       astError( AST__MEMIN, "Invalid attempt to free double allocated "
2049                 "memory: the supplied memory size (%lu bytes) is not "
2050                 "an integer multiple of %lu.", status, size,
2051                 sizeof( void * ) );
2052 
2053    } else {
2054 
2055 /* Free each sub-pointer. */
2056       ptrs = (void **) ptr;
2057       for( iptr = 0; iptr < nptr; iptr++ ) {
2058          ptrs[ iptr ] = astFree(  ptrs[ iptr ] );
2059       }
2060 
2061 /* Free the supplied pointer. */
2062       ptr = astFree( ptr );
2063    }
2064 
2065 /* Always return a NULL pointer. */
2066    return NULL;
2067 }
2068 
astGrow_(void * ptr,int n,size_t size,int * status)2069 void *astGrow_( void *ptr, int n, size_t size, int *status ) {
2070 /*
2071 *++
2072 *  Name:
2073 *     astGrow
2074 
2075 *  Purpose:
2076 *     Allocate memory for an adjustable array.
2077 
2078 *  Type:
2079 *     Public function.
2080 
2081 *  Synopsis:
2082 *     #include "memory.h"
2083 *     void *astGrow( void *ptr, int n, size_t size )
2084 
2085 *  Description:
2086 *     This function allocates memory in which to store an array of
2087 *     data whose eventual size is unknown. It should be invoked
2088 *     whenever a new array size is determined and will appropriately
2089 *     increase the amount of memory allocated when necessary. In
2090 *     general, it will over-allocate in anticipation of future growth
2091 *     so that the amount of memory does not need adjusting on every
2092 *     invocation.
2093 
2094 *  Parameters:
2095 *     ptr
2096 *        Pointer to previously allocated memory (or NULL if none has
2097 *        yet been allocated).
2098 *     n
2099 *        Number of array elements to be stored (may be zero).
2100 *     size
2101 *        The size of each array element.
2102 
2103 *  Returned Value:
2104 *     astGrow()
2105 *        If the memory was allocated successfully, a pointer to the start
2106 *        of the possibly new memory region is returned (this may be the
2107 *        same as the original pointer).
2108 
2109 *  Notes:
2110 *     - When new memory is allocated, the existing contents are preserved.
2111 *     - This function does not free memory once it is allocated, so
2112 *     the size allocated grows to accommodate the maximum size of the
2113 *     array (or "high water mark"). Other memory handling routines may
2114 *     be used to free the memory (or alter its size) if necessary.
2115 *     - If this function is invoked with the global error status set,
2116 *     or if it fails for any reason, the original pointer value is
2117 *     returned and the memory contents are unchanged.
2118 *--
2119 */
2120 
2121 /* Local Variables: */
2122    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2123    int isdynamic;                /* Is the memory dynamically allocated? */
2124    Memory *mem;                  /* Pointer to memory header */
2125    size_t newsize;               /* New size to allocate */
2126    void *new;                    /* Result pointer */
2127 
2128 /* Check the global error status. */
2129    if ( !astOK ) return ptr;
2130 
2131 /* If needed, get a pointer to the thread specific global data structure. */
2132    astGET_GLOBALS(NULL);
2133 
2134 /* Initialise. */
2135    new = ptr;
2136 
2137 /* Calculate the total size of memory needed. */
2138    size *= (size_t) n;
2139 
2140 /* If no memory has yet been allocated, allocate exactly the amount
2141    required. */
2142    if ( !ptr ) {
2143       new = astMalloc( size );
2144 
2145 /* Otherwise, check that the incoming pointer identifies previously
2146    allocated memory. */
2147    } else {
2148       IS_DYNAMIC( ptr, isdynamic );
2149       if ( isdynamic ) {
2150 
2151 /* Obtain a pointer to the memory header and check if the new size
2152    exceeds that already allocated. */
2153          mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY );
2154          if ( mem->size < size ) {
2155 
2156 /* If so, calculate a possible new size by doubling the old
2157    size. Increase this further if necessary. */
2158             newsize = mem->size * ( (size_t) 2 );
2159             if ( size > newsize ) newsize = size;
2160 
2161 /* Re-allocate the memory. */
2162             new = astRealloc( ptr, newsize );
2163          }
2164       }
2165    }
2166 
2167 /* Return the result. */
2168    return new;
2169 }
2170 
astIsDynamic_(const void * ptr,int * status)2171 int astIsDynamic_( const void *ptr, int *status ) {
2172 /*
2173 *++
2174 *  Name:
2175 *     astIsDynamic
2176 
2177 *  Purpose:
2178 *     Returns a flag indicating if memory was allocated dynamically.
2179 
2180 *  Type:
2181 *     Public function.
2182 
2183 *  Synopsis:
2184 *     #include "memory.h"
2185 *     int astIsDynamic_( const void *ptr )
2186 
2187 *  Description:
2188 *     This function takes a pointer to a region of memory and tests if
2189 *     the memory has previously been dynamically allocated using other
2190 *     functions from this module. It does this by checking for the
2191 *     presence of a "magic" number in the header which precedes the
2192 *     allocated memory. If the magic number is not present (or the
2193 *     pointer is invalid for any other reason), zero is returned.
2194 *     Otherwise 1 is returned.
2195 
2196 *  Parameters:
2197 *     ptr
2198 *        Pointer to test.
2199 
2200 *  Returned Value:
2201 *     astIsDynamic()
2202 *        Non-zero if the memory was allocated dynamically. Zero is returned
2203 *        if the supplied pointer is NULL.
2204 
2205 *  Notes:
2206 *     - A value of zero is returned if this function is invoked with
2207 *     the global error status set, or if it fails for any reason.
2208 *--
2209 */
2210 
2211 /* Local Variables: */
2212    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2213    Memory *isdynmem;               /* Pointer to memory header */ \
2214 
2215 /* Check the global error status and the supplied pointer. */
2216    if ( !astOK || ! ptr ) return 0;
2217 
2218 /* If needed, get a pointer to the thread specific global data structure. */
2219    astGET_GLOBALS(NULL);
2220 
2221 /* Derive a pointer to the memory header that precedes the
2222    supplied region of memory. */
2223    isdynmem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY );
2224 
2225 /* Check if the "magic number" in the header is valid, returning non-zero
2226    if it is. */
2227    return ( isdynmem->magic == MAGIC( isdynmem, isdynmem->size ) );
2228 }
2229 
astMalloc_(size_t size,int init,int * status)2230 void *astMalloc_( size_t size, int init, int *status ) {
2231 /*
2232 *++
2233 *  Name:
2234 *     astMalloc
2235 
2236 *  Purpose:
2237 *     Allocate memory.
2238 
2239 *  Type:
2240 *     Public function.
2241 
2242 *  Synopsis:
2243 *     #include "memory.h"
2244 *     void *astMalloc( size_t size )
2245 
2246 *  Description:
2247 *     This function allocates memory in a similar manner to the
2248 *     standard C "malloc" function, but with improved security
2249 *     (against memory leaks, etc.) and with error reporting. It also
2250 *     allows zero-sized memory allocation (without error), resulting
2251 *     in a NULL returned pointer value.
2252 
2253 *  Parameters:
2254 *     size
2255 *        The size of the memory region required (may be zero).
2256 
2257 *  Returned Value:
2258 *     astMalloc()
2259 *        If successful, the function returns a pointer to the start of
2260 *        the allocated memory region. If the size allocated is zero, this
2261 *        will be a NULL pointer.
2262 
2263 *  Notes:
2264 *     - A pointer value of NULL is returned if this function is
2265 *     invoked with the global error status set or if it fails for any
2266 *     reason.
2267 *--
2268 
2269 *  astMallocInit:
2270 *     - This function can be invoked using either the public astMalloc
2271 *     macro documented above, or the private astMallocInit macro.
2272 *     astMallocInit has the same interface as astMalloc, but calls calloc
2273 *     rather than malloc so that the allocated memory is filled with zeros.
2274 *     Ideally, we should use an extra layer in the calling heirarchy to
2275 *     remove the hidden "init" argument in the astMalloc_ interface, but
2276 *     astMalloc is time-critical in many situations and so it is included
2277 *     as a "hidden" argument.
2278 
2279 */
2280 
2281 /* Local Constants: */
2282 #define ERRBUF_LEN 80
2283 
2284 /* Local Variables: */
2285    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2286    char errbuf[ ERRBUF_LEN ];    /* Buffer for system error message */
2287    char *errstat;                /* Pointer to system error message */
2288    Memory *mem;                  /* Pointer to space allocated by malloc */
2289    void *result;                 /* Returned pointer */
2290 
2291 /* Initialise. */
2292    result = NULL;
2293 
2294 /* Check the global error status. */
2295    if ( !astOK ) return result;
2296 
2297 /* If needed, get a pointer to the thread specific global data structure. */
2298    astGET_GLOBALS(NULL);
2299 
2300 /* Check that the size requested is not negative and report an error
2301    if it is. */
2302    if ( size < (size_t) 0 ) {
2303       astError( AST__MEMIN,
2304                 "Invalid attempt to allocate %lu bytes of memory.", status,
2305                 (unsigned long) size );
2306 
2307 /* Otherwise, if the size is greater than zero, either get a previously
2308    allocated memory block from the cache, or attempt to use malloc
2309    to allocate the memory, including space for the header structure. */
2310    } else if ( size != (size_t ) 0 ) {
2311 
2312 /* If the cache is being used and a cached memory block of the required size
2313    is available, remove it from the cache array and use it. */
2314       mem = ( use_cache && size <= MXCSIZE ) ? cache[ size ] : NULL;
2315       if( mem ) {
2316          cache[ size ] = mem->next;
2317          mem->next = NULL;
2318          mem->size = (size_t) size;
2319 
2320 /* Initialise the memory (but not the header) if required. */
2321          if( init ) (void) memset( (char *) mem + SIZEOF_MEMORY, 0, size );
2322 
2323 /* Otherwise, allocate a new memory block using "malloc" or "calloc". */
2324       } else {
2325          if( init ) {
2326             mem = CALLOC( 1, SIZEOF_MEMORY + size );
2327          } else {
2328             mem = MALLOC( SIZEOF_MEMORY + size );
2329          }
2330 
2331 /* Report an error if malloc failed. */
2332          if ( !mem ) {
2333 
2334 #if HAVE_STRERROR_R
2335             strerror_r( errno, errbuf, ERRBUF_LEN );
2336             errstat = errbuf;
2337 #else
2338             errstat = strerror( errno );
2339 #endif
2340             astError( AST__NOMEM, "malloc: %s", status, errstat );
2341             astError( AST__NOMEM, "Failed to allocate %lu bytes of memory.", status,
2342                       (unsigned long) size );
2343 
2344 /* If successful, set the "magic number" in the header and also store
2345    the size. */
2346          } else {
2347             mem->magic = MAGIC( mem, size );
2348             mem->size = size;
2349             mem->next = NULL;
2350 
2351 #ifdef MEM_DEBUG
2352             mem->id = -1;
2353             mem->prev = NULL;
2354 #endif
2355 
2356          }
2357       }
2358 
2359 /* Do nothing more if no memory is being returned. */
2360       if( mem ) {
2361 
2362 #ifdef MEM_DEBUG
2363       Issue( mem, status );
2364 #endif
2365 
2366 /* Increment the memory pointer to the start of the region of
2367    allocated memory to be used by the caller.*/
2368          result = mem;
2369          result = (char *) result + SIZEOF_MEMORY;
2370       }
2371    }
2372 
2373 /* Return the result. */
2374    return result;
2375 }
2376 #undef ERRBUF_LEN
2377 
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)2378 static char *ChrMatcher( const char *test, const char *end, const char *template,
2379                          const char *pattern, const char *subs[], int nsub,
2380                          int ignore, int expdoll, char ***mres, int *mlen,
2381                          const char **matchend, int *status ){
2382 /*
2383 *  Name:
2384 *     ChrMatcher
2385 
2386 *  Purpose:
2387 *     Performs substitutions on a supplied string.
2388 
2389 *  Type:
2390 *     Private function.
2391 
2392 *  Synopsis:
2393 *     #include "memory.h"
2394 *     char *ChrMatcher( const char *test, const char *end, const char *template,
2395 *                       const char *pattern, const char *subs[], int nsub,
2396 *                       int ignore, int expdoll, char ***mres, int *mlen,
2397 *                       const char **matchend, int *status )
2398 
2399 *  Description:
2400 *     This function is performs most of the work for astChrSub.
2401 
2402 *  Parameters:
2403 *     test
2404 *        The string to be tested.
2405 *     end
2406 *        Pointer to the terminating null character at the end of "test".
2407 *     template
2408 *        The template string. See astChrSub for details.
2409 *     pattern
2410 *        The user supplied "pattern" string (only used for error messages).
2411 *     subs
2412 *        An array of strings holding the values that are to be substituted
2413 *        into each parenthesised substring in "test".
2414 *     nsub
2415 *        The length of the subs arrays.
2416 *     ignore
2417 *        If non-zero, then no substitutions are performed, and any
2418 *        inbalance in parentheses is ignored.
2419 *     expdoll
2420 *        If non-zero, then any "$1", "$2", etc, tokens in the
2421 *        substitution fields will be repalced by the corresponding fields
2422 *        in the test string.
2423 *     mres
2424 *        Address of a location at which to return a pointer to an array
2425 *        of character string pointers. The strings are the sub-sections
2426 *        of "test" that matched the parenthesised sub-sections of
2427 *        "template". The array will have "*m" elements. Ignored if NULL.
2428 *     mlen
2429 *        Address of a location at which to return the length of the
2430 *        returned "mres" array. Ignored if "mres" is NULL.
2431 *     matchend
2432 *        A pointer to a location at which to return a pointer to the
2433 *        character that follows the last character within the supplied test
2434 *        string that matched any parenthesises sub-section of "regexp". A
2435 *        NULL pointer is returned if no matches were found. A NULL pointer
2436 *        may be supplied if the location of the last matching character is
2437 *        not needed.
2438 *     status
2439 *        Pointer to the inherited status variable.
2440 
2441 *  Returned Value:
2442 *     A pointer to a dynamically allocated string holding the result of the
2443 *     substitutions, or NULL if the test string does not match the template
2444 *     string. This string should be freed using astFree when no longer
2445 *     needed.
2446 
2447 *  Notes:
2448 *     -  A NULL pointer is returned if this function is invoked with the
2449 *     global error status set or if it should fail for any reason, or if
2450 *     the supplied test string does not match the template.
2451 */
2452 
2453 /* Local Variables: */
2454    char **matches;
2455    char **newsubs;
2456    char **parts;
2457    char *allowed;
2458    char *r;
2459    char *result;
2460    char *sres;
2461    char *stest;
2462    char stemp[10];
2463    const char *aaa;
2464    const char *aa;
2465    const char *a;
2466    const char *b;
2467    int allow;
2468    int dollar;
2469    int end_sub;
2470    int greedy;
2471    int i;
2472    int in_sub;
2473    int ipart;
2474    int match;
2475    int matchlen;
2476    int max_na;
2477    int min_na;
2478    int na;
2479    int nb;
2480    int nmatch;
2481    int npart;
2482    int partlen;
2483    int reslen;
2484    int start_sub;
2485    size_t stl;
2486 
2487 /* Initialisation. */
2488    if( mres ) *mlen = 0;
2489    aaa = NULL;
2490    if( matchend ) *matchend = NULL;
2491 
2492 /* Check the global error status. */
2493    if( !astOK ) return NULL;
2494 
2495 /* more initialisation. */
2496    result = NULL;
2497    allowed = NULL;
2498 
2499 /* Get memory for a set of pointers to copies of the test sub-strings that
2500    fall between the sub-strings being replaced. */
2501    parts = astMalloc( sizeof( char *)*(size_t) ( nsub + 1 ) );
2502 
2503 /* Get memory for a set of pointers to copies of the test sub-strings that
2504    match the parenthesised sub-strings in the template. */
2505    matches = astMalloc( sizeof( char *)*(size_t) nsub );
2506 
2507 /* Initialise pointers to the next test and template characters to read. */
2508    a = test;
2509    b = template;
2510 
2511 /* Initialise the pointer to the start of the previous test character */
2512    aa = test;
2513 
2514 /* Assume the test string matches the template. */
2515    match = 1;
2516 
2517 /* The template pointer is not currently in a substitution field. */
2518    in_sub = 0;
2519 
2520 /* Initialise the number of substitution fields found so far. */
2521    npart = 0;
2522    nmatch = 0;
2523 
2524 /* Loop until we have reached the end of either the test or template
2525    string. We break out of the loop early if we find that the test string
2526    does not match the template string. */
2527    while( match && *a && *b ) {
2528 
2529 /* Examine the string at the start of the template string. This returns a
2530    string of allowed (or disallowed) characters that the next test character
2531    can match, the number of template characters consumed, the minimum number
2532    of test characters that must match the allowed character set, and a flag
2533    indicating if the number of matching test characters can exceed the
2534    minimum number or must be exactly equal to the minimum number.  */
2535       allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow,
2536                                 &min_na, &max_na, &start_sub, &end_sub,
2537                                 &greedy, status );
2538       if( !astOK ) break;
2539 
2540 /* Increment the the pointer to the next template character. */
2541       b += nb;
2542 
2543 /* If the leading field in the template indicates the start of a
2544    substitution field, record the test string up to the current point. */
2545       if( start_sub ){
2546 
2547 /* Do nothing if we are ignoring substitutions. */
2548          if( ! ignore ){
2549 
2550 /* Store a pointer to the first test character that matches the
2551    substitution template. */
2552             aaa = a;
2553 
2554 /* Report an error and abort if we are already inside a substitution
2555    field */
2556             if( in_sub ) {
2557                astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
2558                          "missing ')'.", status, pattern );
2559                break;
2560             }
2561 
2562 /* Indicate that we are now in a substitution field. */
2563             in_sub = 1;
2564 
2565 /* If possible, store a copy of the test string that started at the end
2566    of the previous substitution field and ends at the current point.
2567    First ensure the "parts" array is large enough since the string may
2568    contain more than "nsub" parenthesised sub-strings. */
2569             parts = astGrow( parts, npart + 1, sizeof( char * ) );
2570             if( parts ) {
2571                partlen = ( a - aa );
2572                parts[ npart ] = astStore( NULL, aa, partlen + 1 );
2573                if( parts[ npart ] ) {
2574                   parts[ npart ][ partlen ] = 0;
2575                   npart++;
2576                }
2577             }
2578          }
2579 
2580 /* If the leading field in the template indicates the end of a
2581    substitution field, initialise the start of the next part of the test
2582    string. */
2583       } else if( end_sub ){
2584 
2585 /* Do nothing if we are ignoring substitutions. */
2586          if( ! ignore ){
2587 
2588 /* Report an error and abort if we are not currently in a substitution
2589    field. */
2590             if( ! in_sub ) {
2591                astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
2592                          "missing '('.", status, pattern );
2593                break;
2594             }
2595 
2596 /* We are no longer in a substitution field. */
2597             in_sub = 0;
2598 
2599 /* If possible, store a copy of the test string that matched the
2600    substitution template. */
2601             matches = astGrow( matches, nmatch + 1, sizeof( char * ) );
2602             if( matches ) {
2603                matchlen = ( a - aaa );
2604                matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 );
2605                if( matches[ nmatch ] ) {
2606                   matches[ nmatch ][ matchlen ] = 0;
2607                   nmatch++;
2608                   if( matchend ) *matchend = a;
2609                }
2610             }
2611 
2612 /* Record the start of the next test string part. */
2613             aa = a;
2614          }
2615 
2616 /* Otherwise, find how many characters at the front of the test string
2617    match the leading field in the template. Find the number of leading
2618    characters in the test string that are contained in the set of
2619    characters allowed by the leading field in the template. */
2620       } else {
2621          if( !allowed ) {
2622             na = strlen( a );
2623 
2624          } else if( allow ) {
2625             na = strspn( a, allowed );
2626 
2627          } else {
2628             na = strcspn( a, allowed );
2629          }
2630 
2631 /* Check that the minmum number of matching characters is available. */
2632          if( na < min_na ){
2633             match = 0;
2634             break;
2635          }
2636 
2637 /* Dont match more characters than are needed. */
2638          if( na > max_na ) na = max_na;
2639 
2640 /* We cannot match more characters than are available. */
2641          if( na < max_na ) max_na = na;
2642 
2643 /* If we have exhausted the template, match the maximum number of
2644    characters. */
2645          if( ! *b ) {
2646             na = max_na;
2647 
2648 /* If we still have a match, we may choose to use fewer than the max
2649    allowed number of test characters in order to allow the next template
2650    field to be matched. Don't need to do this if we have reached the end
2651    of the template. */
2652          } else if( max_na > min_na ) {
2653             match = 0;
2654 
2655 /* If a greedy quantifier was used, try using a decreasing number of test
2656    characters, starting at the maximum allowed and decreasing down to the
2657    minimum, until a number is found which allows the rest of the string
2658    to be matched. */
2659             if( greedy ) {
2660                for( na = max_na; na >= min_na; na-- ) {
2661                   r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0,
2662                                   NULL, NULL, NULL, status );
2663                   if( r ) {
2664                      match = 1;
2665                      r = astFree( r );
2666                      break;
2667                   }
2668                }
2669 
2670 /* If a non-greedy quantifier was used, try using an increasing number of
2671    test characters, starting at the minimum allowed and increasing up to
2672    the maximum, until a number is found which allows the rest of the string
2673    to be matched. */
2674             } else {
2675                for( na = min_na; na <= max_na; na++ ) {
2676                   r = ChrMatcher( a + na, end, b, pattern, NULL, 0, 1, 0,
2677                                   NULL, NULL, NULL, status );
2678                   if( r ) {
2679                      match = 1;
2680                      r = astFree( r );
2681                      break;
2682                   }
2683                }
2684             }
2685          }
2686 
2687 /* Increment the the pointer to the next test character. */
2688          a += na;
2689          if( a > end ) a = end;
2690       }
2691    }
2692 
2693 /* If the test string is finished but the template string is not, see if
2694    the next part of the template string will match a null test string.
2695    But ignore the ends of substitution fields. */
2696    if( !*a && *b && match ) {
2697       while( *b && *b != ')' ) {
2698          allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow,
2699                                    &min_na, &max_na, &start_sub, &end_sub,
2700                                    &greedy, status );
2701          b += nb;
2702          allowed = astFree( allowed );
2703 
2704          if( min_na > 0 ) {
2705             match = 0;
2706             break;
2707          }
2708       }
2709    }
2710 
2711 /* If the next character in the template is a closing parenthesis, then
2712    we are finishing a substitution field. */
2713    if( match && *b == ')' ) {
2714 
2715 /*Check we are not ignoring substitutions. */
2716       if( ! ignore ){
2717 
2718 /* Report an error and abort if we are not currently in a substitution
2719    field. */
2720          if( ! in_sub ) {
2721             astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
2722                       "missing '('.", status, pattern );
2723          }
2724 
2725 /* We are no longer in a substitution field. */
2726          in_sub = 0;
2727 
2728 /* If possible, store a copy of the test string that matched the
2729    substitution field. */
2730          matches = astGrow( matches, nmatch + 1, sizeof( char * ) );
2731          if( matches ) {
2732             matchlen = ( a - aaa );
2733             matches[ nmatch ] = astStore( NULL, aaa, matchlen + 1 );
2734             if( matches[ nmatch ] ) {
2735                matches[ nmatch ][ matchlen ] = 0;
2736                nmatch++;
2737                if( matchend ) *matchend = a;
2738             }
2739          }
2740 
2741          aa = a;
2742       }
2743       b++;
2744    }
2745 
2746 /* If the test string is finished but the template string is not, see if
2747    the rest of the template string will match a null test string. */
2748    if( !*a && *b && match ) {
2749 
2750       while( *b ) {
2751          allowed = CheckTempStart( template, b, pattern, allowed, &nb, &allow,
2752                                    &min_na, &max_na, &start_sub, &end_sub,
2753                                    &greedy, status );
2754          b += nb;
2755          allowed = astFree( allowed );
2756 
2757          if( min_na > 0 ) {
2758             match = 0;
2759             break;
2760          }
2761       }
2762 
2763    }
2764 
2765 /* No match if either string was not used completely. */
2766    if( *a || *b ) match = 0;
2767 
2768 /* Report an error if we are still inside a substitution field */
2769    if( match && in_sub && !ignore ) {
2770       astError( AST__BADSUB, "Invalid pattern matching template \"%s\": "
2771                 "missing ')'.", status, pattern );
2772       match = 0;
2773    }
2774 
2775 /* If we have a match, construct the returned string. */
2776    if( match && parts ) {
2777 
2778 /* Store the test string following the final substitution field. */
2779       parts = astGrow( parts, npart + 1, sizeof( char * ) );
2780       if( parts ) {
2781          partlen = ( a - aa );
2782          parts[ npart ] = astStore( NULL, aa, partlen + 1 );
2783          if( parts[ npart ] ) {
2784             parts[ npart ][ partlen ] = 0;
2785             npart++;
2786          }
2787       }
2788 
2789 /* If required, expand  $1, $2, etc within the replacement strings. */
2790       if( expdoll) {
2791          newsubs = astMalloc( sizeof( char * )*nsub );
2792          if( newsubs ) {
2793             for( i = 0; i < nsub; i++ ) {
2794                stl = strlen( subs[ i ] );
2795                stest = astStore( NULL, subs[ i ], stl + 1 );
2796                for( dollar = 1; dollar <= nsub; dollar++ ) {
2797                   sprintf( stemp, ".*($%d).*", dollar );
2798                   sres = ChrMatcher( stest, stest + stl, stemp, stemp,
2799                                      (void *) ( matches + dollar - 1 ),
2800                                      1, 0, 0, NULL, NULL, NULL, status );
2801                   if( sres ) {
2802                      (void) astFree( stest );
2803                      stest = sres;
2804                   }
2805                }
2806                newsubs[ i ] = stest;
2807             }
2808          }
2809 
2810       } else {
2811          newsubs = (char **) subs;
2812       }
2813 
2814 /* Concatenate the sub-strings to form the final string. */
2815       reslen = 0;
2816       for( ipart = 0; ipart < npart - 1; ipart++ ) {
2817          result = astAppendString( result, &reslen, parts[ ipart ] );
2818          if( ipart < nsub ) {
2819             result = astAppendString( result, &reslen, newsubs[ ipart ] );
2820          } else {
2821             result = astAppendString( result, &reslen, matches[ ipart ] );
2822          }
2823       }
2824       result = astAppendString( result, &reslen, parts[ ipart ] );
2825 
2826 /* Free resources. */
2827       if( newsubs && newsubs != (char **) subs ) {
2828          for( i = 0; i < nsub; i++ ) {
2829             newsubs[ i ] = astFree( newsubs[ i ] );
2830          }
2831          newsubs = astFree( newsubs );
2832       }
2833    }
2834 
2835    allowed = astFree( allowed );
2836    for( ipart = 0; ipart < npart; ipart++ ) {
2837       parts[ ipart ] = astFree( parts[ ipart ] );
2838    }
2839    parts = astFree( parts );
2840 
2841 /* If required, return the array holding the test sub-strings that
2842    matched the parenthesised template sub-strings, together with
2843    the length of the array. Otherwise, free the memory holding these
2844    strings. */
2845    if( mres ) {
2846       *mres = matches;
2847       *mlen = nmatch;
2848 
2849    } else if( matches ) {
2850       for( i = 0; i < nmatch; i++ ) {
2851          matches[ i ] = astFree( matches[ i ] );
2852       }
2853       matches = astFree( matches );
2854 
2855    }
2856 
2857 /* Return the result. */
2858    return result;
2859 }
2860 
astMemCaching_(int newval,int * status)2861 int astMemCaching_( int newval, int *status ){
2862 /*
2863 *++
2864 *  Name:
2865 *     astMemCaching
2866 
2867 *  Purpose:
2868 *     Controls whether allocated but unused memory is cached in this module.
2869 
2870 *  Type:
2871 *     Public function.
2872 
2873 *  Synopsis:
2874 *     #include "memory.h"
2875 *     int astMemCaching( int newval )
2876 
2877 *  Description:
2878 *     This function sets a flag indicating if allocated but unused memory
2879 *     should be cached or not. It also returns the original value of the
2880 *     flag.
2881 *
2882 *     If caching is switched on or off as a result of this call, then the
2883 *     current contents of the cache are discarded.
2884 *
2885 *     Note, each thread has a separate cache. Calling this function
2886 *     affects only the currently executing thread.
2887 
2888 *  Parameters:
2889 *     newval
2890 *        The new value for the MemoryCaching tuning parameter (see
2891 *        astTune in objectc.c). If AST__TUNULL is supplied, the current
2892 *        value is left unchanged.
2893 
2894 *  Returned Value:
2895 *     astMemCaching()
2896 *        The original value of the MemoryCaching tuning parameter.
2897 
2898 *--
2899 */
2900 
2901 /* Local Variables: */
2902    astDECLARE_GLOBALS
2903    int i;
2904    int result;
2905    Memory *mem;
2906 
2907 #ifdef MEM_DEBUG
2908    int id_list_size;
2909    int *id_list;
2910 #endif
2911 
2912 /* Check the global error status. */
2913    if ( !astOK ) return 0;
2914 
2915 /* If needed, get a pointer to the thread specific global data structure. */
2916    astGET_GLOBALS(NULL);
2917 
2918 /* Store the original value of the tuning parameter. */
2919    result = use_cache;
2920 
2921 /* If a new value is to be set. */
2922    if( newval != AST__TUNULL ) {
2923 
2924 /* If the cache has been initialised, empty it. */
2925       if( cache_init ) {
2926 
2927 /* If we are listing the ID of every memory block in the cache, count the
2928    number of blocks in the cache and then allocate an array to store the ID
2929    values in. This is done so that we can sort them before displaying them. */
2930 #ifdef MEM_DEBUG
2931          if( List_Cache ) {
2932             Memory *next;
2933 
2934             id_list_size = 0;
2935             for( i = 0; i <= MXCSIZE; i++ ) {
2936                next = cache[ i ];
2937                while( next ) {
2938                   id_list_size++;
2939                   next = next->next;
2940                }
2941             }
2942 
2943             id_list = MALLOC( sizeof(int)*id_list_size );
2944             if( !id_list ) {
2945                astError( AST__INTER, "astMemCaching: Cannot allocate %lu "
2946                          "bytes of memory", status, (unsigned long)(sizeof(int)*id_list_size) );
2947             }
2948 
2949             id_list_size = 0;
2950 
2951          } else {
2952             id_list = NULL;
2953          }
2954 #endif
2955 
2956          for( i = 0; i <= MXCSIZE; i++ ) {
2957             while( cache[ i ] ) {
2958                mem = cache[ i ];
2959                cache[ i ] = mem->next;
2960                mem->size = (size_t) i;
2961 
2962 #ifdef MEM_DEBUG
2963                if( id_list ) {
2964                   id_list[ id_list_size++ ] = mem->id;
2965                }
2966 #endif
2967 
2968                FREE( mem );
2969             }
2970          }
2971 
2972 /* If we are displaying the IDs of memory blocks still in the cache, sort
2973    them using a bubblesort algorithm, then display them. */
2974 #ifdef MEM_DEBUG
2975          if( id_list ) {
2976 
2977             if( id_list_size == 0 ) {
2978                printf( "Emptying the AST memory cache - (the cache is "
2979                        "already empty)\n" );
2980 
2981             } else {
2982                int sorted, j, t;
2983 
2984                sorted = 0;
2985                for( j = id_list_size - 2; !sorted && j >= 0; j-- ) {
2986                   sorted = 1;
2987                   for( i = 0; i <= j; i++ ) {
2988                      if( id_list[ i ] > id_list[ i + 1 ] ) {
2989                         sorted = 0;
2990                         t = id_list[ i ];
2991                         id_list[ i ] = id_list[ i + 1 ];
2992                         id_list[ i + 1 ] = t;
2993                      }
2994                   }
2995                }
2996 
2997                printf( "Emptying the AST memory cache - freeing the "
2998                        "following memory blocks: ");
2999                for( i = 0; i < id_list_size; i++ ) printf( "%d ", id_list[ i ] );
3000                printf( "\n" );
3001 
3002             }
3003          }
3004 #endif
3005 
3006 /* Otherwise, initialise the cache array to hold a NULL pointer at every
3007    element. */
3008       } else {
3009          for( i = 0; i <= MXCSIZE; i++ ) cache[ i ] = NULL;
3010          cache_init = 1;
3011       }
3012 
3013 /* Store the new value. */
3014       use_cache = newval;
3015 
3016    }
3017 
3018 /* Return the original value. */
3019    return result;
3020 }
3021 
astRealloc_(void * ptr,size_t size,int * status)3022 void *astRealloc_( void *ptr, size_t size, int *status ) {
3023 /*
3024 *++
3025 *  Name:
3026 *     astRealloc
3027 
3028 *  Purpose:
3029 *     Change the size of a dynamically allocated region of memory.
3030 
3031 *  Type:
3032 *     Public function.
3033 
3034 *  Synopsis:
3035 *     #include "memory.h"
3036 *     void *astRealloc( void *ptr, size_t size )
3037 
3038 *  Description:
3039 *     This function changes the size of a dynamically allocated region
3040 *     of memory, preserving its contents up to the minimum of the old
3041 *     and new sizes. This may involve copying the contents to a new
3042 *     location, so a new pointer is returned (and the old memory freed
3043 *     if necessary).
3044 *
3045 *     This function is similar to the standard C "realloc" function
3046 *     except that it provides better security against programming
3047 *     errors and also supports the allocation of zero-size memory
3048 *     regions (indicated by a NULL pointer).
3049 
3050 *  Parameters:
3051 *     ptr
3052 *        Pointer to previously allocated memory (or NULL if the
3053 *        previous size of the allocated memory was zero).
3054 *     size
3055 *        New size required for the memory region. This may be zero, in
3056 *        which case a NULL pointer is returned (no error results). It
3057 *        should not be negative.
3058 
3059 *  Returned Value:
3060 *     astRealloc()
3061 *        If the memory was reallocated successfully, a pointer to the
3062 *        start of the new memory region is returned (this may be the same
3063 *        as the original pointer). If size was given as zero, a NULL
3064 *        pointer is returned.
3065 
3066 *  Notes:
3067 *     - If this function is invoked with the error status set, or if
3068 *     it fails for any reason, the original pointer value is returned
3069 *     and the memory contents are unchanged. Note that this behaviour
3070 *     differs from that of the standard C "realloc" function which
3071 *     returns NULL if it fails.
3072 *--
3073 */
3074 
3075 /* Local Constants: */
3076 #define ERRBUF_LEN 80
3077 
3078 /* Local Variables: */
3079    astDECLARE_GLOBALS
3080    char errbuf[ ERRBUF_LEN ];    /* Buffer for system error message */
3081    char *errstat;                /* Pointer to system error message */
3082    int isdynamic;                /* Was memory allocated dynamically? */
3083    void *result;                 /* Returned pointer */
3084    Memory *mem;                  /* Pointer to memory header */
3085 
3086 /* Check the global error status. */
3087    if ( !astOK ) return ptr;
3088 
3089 /* Initialise. */
3090    result = ptr;
3091 
3092 /* If needed, get a pointer to the thread specific global data structure. */
3093    astGET_GLOBALS(NULL);
3094 
3095 /* If a NULL pointer was supplied, use astMalloc to allocate some new
3096    memory. */
3097    if ( !ptr ) {
3098       result = astMalloc( size );
3099 
3100 /* Otherwise, check that the pointer supplied points at memory
3101    allocated by a function in this module (IsDynamic sets the global
3102    error status if it does not). */
3103    } else {
3104       IS_DYNAMIC( ptr, isdynamic );
3105       if ( isdynamic ) {
3106 
3107 /* Check that a negative size has not been given and report an error
3108    if necessary. */
3109          if ( size < (size_t) 0 ) {
3110             astError( AST__MEMIN,
3111                "Invalid attempt to reallocate a block of memory to %ld bytes.", status,
3112                       (long) size );
3113 
3114 /* If OK, obtain a pointer to the memory header. */
3115          } else {
3116             mem = (Memory *) ( (char *) ptr - SIZEOF_MEMORY );
3117 
3118 /* If the new size is zero, free the old memory and set a NULL return
3119    pointer value. */
3120             if ( size == (size_t) 0 ) {
3121                astFree( ptr );
3122                result = NULL;
3123 
3124 /* Otherwise, reallocate the memory. */
3125             } else {
3126 
3127 /* If the cache is being used, for small memory blocks, do the equivalent of
3128                mem = REALLOC( mem, SIZEOF_MEMORY + size );
3129 
3130    using astMalloc, astFree and memcpy explicitly in order to ensure
3131    that the memory blocks are cached. */
3132                if( use_cache && ( mem->size <= MXCSIZE || size <= MXCSIZE ) ) {
3133                   result = astMalloc( size );
3134                   if( result ) {
3135                      if( mem->size < size ) {
3136                         memcpy( result, ptr, mem->size );
3137                      } else {
3138                         memcpy( result, ptr, size );
3139                      }
3140                      astFree( ptr );
3141 
3142                   } else {
3143                      result = ptr;
3144                   }
3145 
3146 /* For other memory blocks simply use realloc. */
3147                } else {
3148 
3149 #ifdef MEM_DEBUG
3150                   DeIssue( mem, status );
3151 #endif
3152 
3153                   mem = REALLOC( mem, SIZEOF_MEMORY + size );
3154 
3155 /* If this failed, report an error and return the original pointer
3156    value. */
3157                   if ( !mem ) {
3158 #if HAVE_STRERROR_R
3159                      strerror_r( errno, errbuf, ERRBUF_LEN );
3160                      errstat = errbuf;
3161 #else
3162                      errstat = strerror( errno );
3163 #endif
3164                      astError( AST__NOMEM, "realloc: %s", status, errstat );
3165                      astError( AST__NOMEM, "Failed to reallocate a block of "
3166                                "memory to %ld bytes.", status, (long) size );
3167 
3168 /* If successful, set the new "magic" value and size in the memory
3169    header and obtain a pointer to the start of the region of memory to
3170    be used by the caller. */
3171                   } else {
3172                      mem->magic = MAGIC( mem, size );
3173                      mem->size = size;
3174                      mem->next = NULL;
3175 #ifdef MEM_DEBUG
3176                      mem->id = -1;
3177                      mem->prev = NULL;
3178                      Issue( mem, status );
3179 #endif
3180                      result = mem;
3181                      result = (char *) result + SIZEOF_MEMORY;
3182                   }
3183                }
3184             }
3185          }
3186       }
3187    }
3188 
3189 /* Return the result. */
3190    return result;
3191 }
3192 #undef ERRBUF_LEN
3193 
astRemoveLeadingBlanks_(char * string,int * status)3194 void astRemoveLeadingBlanks_( char *string, int *status ) {
3195 /*
3196 *++
3197 *  Name:
3198 *     astRemoveLeadingBlanks
3199 
3200 *  Purpose:
3201 *     Remove any leading white space from a string.
3202 
3203 *  Type:
3204 *     Public function.
3205 
3206 *  Synopsis:
3207 *     #include "memory.h"
3208 *     void astRemoveLeadingBlanks( char *string )
3209 
3210 *  Description:
3211 *     This function moves characters in the supplied string to the left
3212 *     in order to remove any leading white space.
3213 
3214 *  Parameters:
3215 *     string
3216 *        Pointer to the string.
3217 
3218 *--
3219 */
3220 
3221 /* Local Variables: */
3222    char *c, *d;
3223 
3224 /* Check a string has been supplied. */
3225    if( string ){
3226 
3227 /* Get a pointer to the first non-white character in the string. */
3228       c = string;
3229       while( *c && isspace( *c ) ) c++;
3230 
3231 /* Do nothing more if there are no leading spaces. */
3232       if( c > string ) {
3233 
3234 /* Copy all characters (excluding the trailing null) to the left to
3235    over-write the leading spaces. */
3236          d = string;
3237          while( *c ) *(d++) = *(c++);
3238 
3239 /* Terminate the returned string. */
3240          *d = 0;
3241       }
3242    }
3243 }
3244 
astSizeOf_(const void * ptr,int * status)3245 size_t astSizeOf_( const void *ptr, int *status ) {
3246 /*
3247 *++
3248 *  Name:
3249 *     astSizeOf
3250 
3251 *  Purpose:
3252 *     Determine the size of a dynamically allocated region of memory.
3253 
3254 *  Type:
3255 *     Public function.
3256 
3257 *  Synopsis:
3258 *     #include "memory.h"
3259 *     size_t astSizeOf( const void *ptr )
3260 
3261 *  Description:
3262 *     This function returns the size of a region of dynamically
3263 *     allocated memory.
3264 
3265 *  Parameters:
3266 *     ptr
3267 *        Pointer to dynamically allocated memory (or NULL if the size
3268 *        of the allocated memory was zero).
3269 
3270 *  Returned Value:
3271 *     astSizeOf()
3272 *        The allocated size. This will be zero if a NULL pointer was
3273 *        supplied (no error will result).
3274 
3275 *  Notes:
3276 *     - A value of zero is returned if this function is invoked with
3277 *     the global error status set, or if it fails for any reason.
3278 *--
3279 */
3280 
3281 /* Local Variables: */
3282    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3283    int isdynamic;                /* Was the memory allocated dynamically? */
3284    size_t size;                  /* Memory size */
3285 
3286 /* Check the global error status. */
3287    if ( !astOK ) return (size_t) 0;
3288 
3289 /* Initialise. */
3290    size = (size_t) 0;
3291 
3292 /* If needed, get a pointer to the thread specific global data structure. */
3293    astGET_GLOBALS(NULL);
3294 
3295 /* Check if a non-NULL valid pointer has been given. If so, extract
3296    the memory size from the header which precedes it. */
3297    if ( ptr ){
3298       IS_DYNAMIC( ptr, isdynamic );
3299       if( isdynamic ) size = ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size;
3300    }
3301 
3302 /* Return the result. */
3303    return size;
3304 }
3305 
SizeOfMemory(int * status)3306 static size_t SizeOfMemory( int *status ){
3307 /*
3308 *  Name:
3309 *     SizeOfMemory
3310 
3311 *  Purpose:
3312 *     Returns the size of a Memory structure, padded to an 8 byte
3313 *     boundary.
3314 
3315 *  Type:
3316 *     Private function.
3317 
3318 *  Synopsis:
3319 *     size_t SizeOfMemory( int *status )
3320 
3321 *  Description:
3322 *     This function returns the size of a Memory structure used to
3323 *     store header information about any block of memory allocated by this
3324 *     module. The returned value may be larger than the actual size of
3325 *     the Memory structure in order to ensure that the pointer returned by
3326 *     astMalloc etc points to an 8 byte boundary. Failure to do this can
3327 *     result in some operating systems having problems. E.g Solaris
3328 *     requires this alignment if the returned pointer is going to be used to
3329 *     store doubles.
3330 
3331 *  Parameters:
3332 *     status
3333 *        Pointer to the inherited status variable.
3334 
3335 *  Returned Value:
3336 *     The size to use for a Memory structure.
3337 
3338 *  Notes:
3339 *     - The returned value is also stored in the module variable
3340 *     sizeof_memory.
3341 */
3342 
3343 /* Local Variables: */
3344    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3345 
3346 /* If needed, get a pointer to the thread specific global data structure. */
3347    astGET_GLOBALS(NULL);
3348 
3349 /* Get the basic size of a Memory structure. */
3350    sizeof_memory = sizeof( Memory );
3351 
3352 /* Now increase the returned value to ensure it is a multiple of 8. Mask
3353    off all but the last 3 bits, xor with 0x7 to get the remainder, add 1
3354    to make it a multiple of 8 bytes. */
3355    sizeof_memory += ((sizeof_memory & 0x7) ? ((sizeof_memory & 0x7) ^ 0x7) + 1 : 0);
3356 
3357 /* Return the value */
3358    return sizeof_memory;
3359 
3360 }
3361 
astTSizeOf_(const void * ptr,int * status)3362 size_t astTSizeOf_( const void *ptr, int *status ) {
3363 /*
3364 *+
3365 *  Name:
3366 *     astTSizeOf
3367 
3368 *  Purpose:
3369 *     Determine the total size of a dynamically allocated region of memory.
3370 
3371 *  Type:
3372 *     Protected function.
3373 
3374 *  Synopsis:
3375 *     #include "memory.h"
3376 *     size_t astTSizeOf( const void *ptr )
3377 
3378 *  Description:
3379 *     This function returns the size of a region of dynamically
3380 *     allocated memory, including the extra memory used to store
3381 *     the header information for the memory block (size and magic number).
3382 
3383 *  Parameters:
3384 *     ptr
3385 *        Pointer to dynamically allocated memory (or NULL if the size
3386 *        of the allocated memory was zero).
3387 
3388 *  Returned Value:
3389 *     The allocated size. This will be zero if a NULL pointer was
3390 *     supplied (no error will result).
3391 
3392 *  Notes:
3393 *     - A value of zero is returned if this function is invoked with
3394 *     the global error status set, or if it fails for any reason.
3395 *     - This function is documented as protected because it should not
3396 *     be invoked by external code. However, it is available via the
3397 *     external C interface so that it may be used when writing (e.g.)
3398 *     foreign language or graphics interfaces.
3399 *-
3400 */
3401 
3402 /* Local Variables: */
3403    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3404    int isdynamic;                /* Was the memory allocated dynamically? */
3405    size_t size;                  /* Memory size */
3406 
3407 /* Check the global error status. */
3408    if ( !astOK ) return (size_t) 0;
3409 
3410 /* If needed, get a pointer to the thread specific global data structure. */
3411    astGET_GLOBALS(NULL);
3412 
3413 /* Initialise. */
3414    size = (size_t) 0;
3415 
3416 /* Check if a non-NULL valid pointer has been given. If so, extract
3417    the memory size from the header which precedes it. */
3418    if ( ptr ){
3419       IS_DYNAMIC( ptr, isdynamic );
3420       if( isdynamic ) size = SIZEOF_MEMORY +
3421                              ( (Memory *) ( (char *) ptr - SIZEOF_MEMORY ) )->size;
3422    }
3423 
3424 /* Return the result. */
3425    return size;
3426 }
3427 
astStore_(void * ptr,const void * data,size_t size,int * status)3428 void *astStore_( void *ptr, const void *data, size_t size, int *status ) {
3429 /*
3430 *++
3431 *  Name:
3432 *     astStore
3433 
3434 *  Purpose:
3435 *     Store data in dynamically allocated memory.
3436 
3437 *  Type:
3438 *     Public function.
3439 
3440 *  Synopsis:
3441 *     #include "memory.h"
3442 *     void *astStore( void *ptr, const void *data, size_t size )
3443 
3444 *  Description:
3445 *     This function stores data in dynamically allocated memory,
3446 *     allocating the memory (or adjusting the size of previously
3447 *     allocated memory) to match the amount of data to be stored.
3448 
3449 *  Parameters:
3450 *     ptr
3451 *        Pointer to previously allocated memory (or NULL if none has
3452 *        yet been allocated).
3453 *     data
3454 *        Pointer to the start of the data to be stored. This may be
3455 *        given as NULL if there are no data, in which case it will be
3456 *        ignored and this function behaves like astRealloc, preserving
3457 *        the existing memory contents.
3458 *     size
3459 *        The total size of the data to be stored and/or the size of
3460 *        memory to be allocated. This may be zero, in which case the
3461 *        data parameter is ignored, any previously-allocated memory is
3462 *        freed and a NULL pointer is returned.
3463 
3464 *  Returned Value:
3465 *     astStore()
3466 *        If the data were stored successfully, a pointer to the start of
3467 *        the possibly new memory region is returned (this may be the same
3468 *        as the original pointer). If size was given as zero, a NULL
3469 *        pointer is returned.
3470 
3471 *  Notes:
3472 *     - This is a convenience function for use when storing data of
3473 *     arbitrary size in memory which is to be allocated
3474 *     dynamically. It is appropriate when the size of the data will
3475 *     not change frequently because the size of the memory region will
3476 *     be adjusted to fit the data on every invocation.
3477 *     - If this function is invoked with the error status set, or if
3478 *     it fails for any reason, the original pointer value is returned
3479 *     and the memory contents are unchanged.
3480 *--
3481 */
3482 
3483 /* Local Variables: */
3484    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3485    int valid;                    /* Is the memory pointer usable? */
3486    void *new;                    /* Pointer to returned memory */
3487 
3488 /* Check the global error status. */
3489    if ( !astOK ) return ptr;
3490 
3491 /* If needed, get a pointer to the thread specific global data structure. */
3492    astGET_GLOBALS(NULL);
3493 
3494 /* Initialise. */
3495    new = ptr;
3496 
3497 /* If the new size is zero, use astRealloc to free any previously
3498    allocated memory. Also re-allocate the memory if the data pointer
3499    is NULL (in which case we want to preserve its contents). */
3500    if ( ( size == (size_t) 0 ) || !data ) {
3501       new = astRealloc( ptr, size );
3502 
3503 /* In other cases, we do not want to preserve any memory
3504    contents. Check if the incoming memory pointer is valid (IsDynamic
3505    sets the global error status if it is not). */
3506    } else {
3507       if ( !ptr ){
3508          valid = 1;
3509       } else {
3510          IS_DYNAMIC( ptr, valid );
3511       }
3512       if( valid ) {
3513 
3514 /* Allocate the new memory. If successful, free the old memory (if
3515    necessary) and copy the data into it. */
3516          new = astMalloc( size );
3517          if ( astOK ) {
3518             if ( ptr ) ptr = astFree( ptr );
3519             (void) memcpy( new, data, size );
3520 
3521 /* If memory allocation failed, do not free the old memory but return
3522    a pointer to it. */
3523          } else {
3524             new = ptr;
3525          }
3526       }
3527    }
3528 
3529 /* Return the result. */
3530    return new;
3531 }
3532 
astString_(const char * chars,int nchars,int * status)3533 char *astString_( const char *chars, int nchars, int *status ) {
3534 /*
3535 *++
3536 *  Name:
3537 *     astString
3538 
3539 *  Purpose:
3540 *     Create a C string from an array of characters.
3541 
3542 *  Type:
3543 *     Public function.
3544 
3545 *  Synopsis:
3546 *     #include "memory.h"
3547 *     char *astString( const char *chars, int nchars )
3548 
3549 *  Description:
3550 *     This function allocates memory to hold a C string and fills the
3551 *     string with the sequence of characters supplied. It then
3552 *     terminates the string with a null character and returns a
3553 *     pointer to its start. The memory used for the string may later
3554 *     be de-allocated using astFree.
3555 *
3556 *     This function is intended for constructing null terminated C
3557 *     strings from arrays of characters which are not null terminated,
3558 *     such as when importing a character argument from a Fortran 77
3559 *     program.
3560 
3561 *  Parameters:
3562 *     chars
3563 *        Pointer to the array of characters to be used to fill the string.
3564 *     nchars
3565 *        The number of characters in the array (zero or more).
3566 
3567 *  Returned Value:
3568 *     astString()
3569 *        If successful, the function returns a pointer to the start of
3570 *        the allocated string. If the number of characters is zero, a
3571 *        zero-length string is still allocated and a pointer to it is
3572 *        returned.
3573 
3574 *  Notes:
3575 *     - A pointer value of NULL is returned if this function is
3576 *     invoked with the global error status set or if it fails for any
3577 *     reason.
3578 *--
3579 */
3580 
3581 /* Local Variables: */
3582    char *result;                 /* Pointer value to return */
3583 
3584 /* Initialise. */
3585    result = NULL;
3586 
3587 /* Check the global error status. */
3588    if ( !astOK ) return result;
3589 
3590 /* Check that the number of characters in the string is valid and
3591    report an error if it is not. */
3592    if ( nchars < 0 ) {
3593       astError( AST__NCHIN, "astString: Invalid attempt to allocate a string "
3594                 "with %d characters.", status, nchars);
3595 
3596 /* Allocate memory to hold the string. */
3597    } else {
3598       result = (char *) astMalloc( (size_t) ( nchars + 1 ) );
3599 
3600 /* If successful, copy the characters into the string. */
3601       if ( astOK && result ) {
3602          (void) memcpy( result, chars, (size_t) nchars );
3603 
3604 /* Terminate the string. */
3605          result[ nchars ] = '\0';
3606       }
3607    }
3608 
3609 /* Return the result. */
3610    return result;
3611 }
3612 
astStringArray_(const char * chars,int nel,int len,int * status)3613 char **astStringArray_( const char *chars, int nel, int len, int *status ) {
3614 /*
3615 *++
3616 *  Name:
3617 *     astStringArray
3618 
3619 *  Purpose:
3620 *     Create an array of C strings from an array of characters.
3621 
3622 *  Type:
3623 *     Public function.
3624 
3625 *  Synopsis:
3626 *     #include "memory.h"
3627 *     char **astStringArray( const char *chars, int nel, int len )
3628 
3629 *  Description:
3630 *     This function turns an array of fixed-length character data into
3631 *     a dynamicllay allocated array of null-terminated C strings with
3632 *     an index array that may be used to access them.
3633 *
3634 *     The array of character data supplied is assumed to hold "nel"
3635 *     adjacent fixed-length strings (without terminating nulls), each
3636 *     of length "len" characters. This function allocates memory and
3637 *     creates a null-terminated copy of each of these strings. It also
3638 *     creates an array of "nel" pointers which point at the start of
3639 *     each of these new strings. A pointer to this index array is
3640 *     returned.
3641 *
3642 *     The memory used is allocated in a single block and should later
3643 *     be de-allocated using astFree.
3644 s
3645 *  Parameters:
3646 *     chars
3647 *        Pointer to the array of input characters. The number of characters
3648 *        in this array should be at least equal to (nel * len).
3649 *     nel
3650 *        The number of fixed-length strings in the input character
3651 *        array. This may be zero but should not be negative.
3652 *     len
3653 *        The number of characters in each fixed-length input
3654 *        string. This may be zero but should not be negative.
3655 
3656 *  Returned Value:
3657 *     astStringArray()
3658 *        A pointer to the start of the index array, which contains "nel"
3659 *        pointers pointing at the start of each null-terminated output
3660 *        string.
3661 *
3662 *        The returned pointer should be passed to astFree to de-allocate
3663 *        the memory used when it is no longer required. This will free
3664 *        both the index array and the memory used by the strings it
3665 *        points at.
3666 
3667 *  Notes:
3668 *     - A NULL pointer will also be returned if the value of "nel" is
3669 *     zero, in which case no memory is allocated.
3670 *     - A pointer value of NULL will also be returned if this function
3671 *     is invoked with the global error status set or if it fails for
3672 *     any reason.
3673 *--
3674 */
3675 
3676 /* Local Variables: */
3677    char **result;                 /* Result pointer to return */
3678    char *out_str;                 /* Pointer to start of next output string */
3679    const char *in_str;            /* Pointer to start of next input string */
3680    int i;                         /* Loop counter for array elements */
3681 
3682 /* Initialise. */
3683    result = NULL;
3684 
3685 /* Check the global error status. */
3686    if ( !astOK ) return result;
3687 
3688 /* Check that the array size is valid and report an error if it is
3689    not. */
3690    if ( nel < 0 ) {
3691       astError( AST__NELIN,
3692                 "astStringArray: Invalid attempt to allocate an array of "
3693                 "%d strings.", status, nel );
3694 
3695 /* If the string length will be used, check that it is valid and
3696    report an error if it is not. */
3697    } else if ( ( nel > 0 ) && ( len < 0 ) ) {
3698       astError( AST__NCHIN,
3699                 "astStringArray: Invalid attempt to allocate an "
3700                 "array of strings with %d characters in each.", status, len );
3701 
3702 /* Allocate memory to hold the array of string pointers plus the
3703    string data (with terminating nulls). */
3704    } else {
3705       result = astMalloc( sizeof( char * ) * (size_t) nel +
3706                           (size_t) ( nel * ( len + 1 ) ) );
3707 
3708 /* If successful, initialise pointers to the start of the current
3709    input and output strings. */
3710       if( astOK ){
3711          in_str = chars;
3712          out_str = (char *) ( result + nel );
3713 
3714 /* Loop to copy each string. */
3715          for ( i = 0; i < nel; i++ ) {
3716             (void) memcpy( out_str, in_str, (size_t) len );
3717 
3718 /* Terminate the output string. */
3719             out_str[ len ] = '\0';
3720 
3721 /* Store a pointer to the start of the output string in the array of
3722    character pointers. */
3723             result[ i ] = out_str;
3724 
3725 /* Increment the pointers to the start of the next string. */
3726             out_str += len + 1;
3727             in_str += len;
3728          }
3729       }
3730    }
3731 
3732 /* Return the result. */
3733    return result;
3734 }
3735 
astStringCase_(const char * string,int upper,int * status)3736 char *astStringCase_( const char *string, int upper, int *status ) {
3737 /*
3738 *++
3739 *  Name:
3740 *     astStringCase
3741 
3742 *  Purpose:
3743 *     Convert a string to upper or lower case.
3744 
3745 *  Type:
3746 *     Public function.
3747 
3748 *  Synopsis:
3749 *     #include "memory.h"
3750 *     char *astStringCase( const char string, int upper )
3751 
3752 *  Description:
3753 *     This function converts a supplied string to upper or lower case,
3754 *     storing the result in dynamically allocated memory. The astChrCase
3755 *     function is similar, but stores the result in a supplied buffer.
3756 
3757 *  Parameters:
3758 *     string
3759 *        Pointer to the null terminated string to be converted.
3760 *     upper
3761 *        If non-zero, the string is converted to upper case. Otherwise it
3762 *        is converted to lower case.
3763 
3764 *  Returned Value:
3765 *     astStringCase()
3766 *        If successful, the function returns a pointer to the start of
3767 *        the allocated string. The returned memory should be freed using
3768 *        astFree when no longer needed.
3769 
3770 *  Notes:
3771 *     - A pointer value of NULL is returned if this function is
3772 *     invoked with the global error status set or if it fails for any
3773 *     reason.
3774 *--
3775 */
3776 
3777 /* Local Variables: */
3778    char *pout;                   /* Pointer to next output character */
3779    char *result;                 /* Pointer value to return */
3780    const char *pin;              /* Pointer to next input character */
3781    int i;                        /* Character index */
3782    int len;                      /* String length */
3783 
3784 /* Initialise. */
3785    result = NULL;
3786 
3787 /* Check the global error status. */
3788    if ( !astOK ) return result;
3789 
3790 /* Get the length of the supplied string, excluding the trailing null. */
3791    len = strlen( string );
3792 
3793 /* Allocate memory to hold the converted string, plus terminating null. */
3794    result = (char *) astMalloc( (size_t) ( len + 1 ) );
3795 
3796 /* If successful, copy the characters into the string, converting each
3797    one to the requested case. */
3798    if ( result ) {
3799       pin = string;
3800       pout = result;
3801 
3802       if( upper ) {
3803          for( i = 0; i < len; i++ ) {
3804             *(pout++) = toupper( (int) *(pin++) );
3805          }
3806 
3807       } else {
3808 
3809          for( i = 0; i < len; i++ ) {
3810             *(pout++) = tolower( (int) *(pin++) );
3811          }
3812       }
3813 
3814 /* Terminate the string. */
3815       *pout = '\0';
3816    }
3817 
3818 /* Return the result. */
3819    return result;
3820 }
3821 
astChrLen_(const char * string,int * status)3822 size_t astChrLen_( const char *string, int *status ) {
3823 /*
3824 *++
3825 *  Name:
3826 *     astChrLen
3827 
3828 *  Purpose:
3829 *     Determine the used length of a string.
3830 
3831 *  Type:
3832 *     Public function.
3833 
3834 *  Synopsis:
3835 *     #include "memory.h"
3836 *     size_t astChrLen( const char *string )
3837 
3838 *  Description:
3839 *     This function returns the used length of a string. This excludes any
3840 *     trailing white space or non-printable characters (such as the
3841 *     trailing null character).
3842 
3843 *  Parameters:
3844 *     string
3845 *        Pointer to the string.
3846 
3847 *  Returned Value:
3848 *     astChrLen()
3849 *        The number of characters in the supplied string, not including the
3850 *        trailing newline, and any trailing white-spaces or non-printable
3851 *        characters.
3852 
3853 *--
3854 */
3855 
3856 /* Local Variables: */
3857    const char *c;           /* Pointer to the next character to check */
3858    size_t ret;              /* The returned string length */
3859 
3860 /* Initialise the returned string length. */
3861    ret = 0;
3862 
3863 /* Check a string has been supplied. */
3864    if( string ){
3865 
3866 /* Check each character in turn, starting with the last one. */
3867       ret = strlen( string );
3868       c = string + ret - 1;
3869       while( ret ){
3870          if( isprint( (int) *c ) && !isspace( (int) *c ) ) break;
3871          c--;
3872          ret--;
3873       }
3874    }
3875 
3876 /* Return the answer. */
3877    return ret;
3878 
3879 }
3880 
astSscanf_(const char * str,const char * fmt,...)3881 int astSscanf_( const char *str, const char *fmt, ...) {
3882 /*
3883 *+
3884 *  Name:
3885 *     astSscanf
3886 
3887 *  Purpose:
3888 *     A wrapper for the ANSI sscanf function.
3889 
3890 *  Type:
3891 *     Protected function.
3892 
3893 *  Synopsis:
3894 *     #include "memory.h"
3895 *     int astSscanf( const char *str, const char *fmt, ...)
3896 
3897 *  Description:
3898 *     This function is a direct plug-in replacement for sscanf. It ensures ANSI
3899 *     behaviour is available on all platforms, including those (such as
3900 *     MacOS) on which have the native sscanf function exhibits non-ANSI
3901 *     behaviour.
3902 
3903 *  Parameters:
3904 *     str
3905 *        Pointer to the string to be scanned.
3906 *     fmt
3907 *        Pointer to the format string which defines the fields to be
3908 *        looked for within "str".
3909 *     ...
3910 *        Pointers to locations at which to return the value of each
3911 *        succesfuly converted field, in the order specified in "fmt".
3912 
3913 *  Returned Value:
3914 *     The number of fields which were succesfully read from "str".
3915 *-
3916 */
3917 
3918 /* Local Variables: */
3919    char *c;                 /* Pointer to the next character to check */
3920    char *newfor;            /* Pointer to modified format string */
3921    const char *d;           /* Pointer to the next character to check */
3922    int *status;             /* Pointer to inherited status value */
3923    int iptr;                /* Index into ptr array */
3924    int lfor;                /* No. of characters in format string */
3925    int lstr;                /* No. of characters in scanned string */
3926    int nc;                  /* No. of characters read from str */
3927    int nfld;                /* No. of counted field specifiers found so far */
3928    int nptr;                /* Np. of pointers stored */
3929    int ret;                 /* The returned number of conversions */
3930    va_list args;            /* Variable argument list pointer */
3931    void *fptr;              /* The next supplied pointer */
3932    void *ptr[ VMAXFLD ];    /* Array of supplied pointers */
3933 
3934 /* Initialise the variable argument list pointer. */
3935    va_start( args, fmt );
3936 
3937 /* Get a pointer to the integer holding the inherited status value. */
3938    status = astGetStatusPtr;
3939 
3940 /* Initialise the returned string length. */
3941    ret = 0;
3942 
3943 /* Check a string and format have been supplied. */
3944    if( str && fmt ){
3945 
3946 /* Go through the format string, counting the number of field specifiers which
3947    will return a value, and storing the corresponding points in the ptr
3948    array. */
3949       nptr = 0;
3950       c = (char *) fmt;
3951       while( *c ) {
3952 
3953 /* Field specifiers are marked by a % sign. */
3954          if( *c == '%' ) {
3955 
3956 /* Look at the character following the % sign. Quit if the end of the string
3957    has been reached. */
3958             c++;
3959             if( *c ) {
3960 
3961 /* If the % sign is followed by a "*" or another "%", then there will be no
3962    corresponding pointer in the variable argument list "args". Ignore such
3963    field specifiers. */
3964                if( *c != '*' && *c != '%' ) {
3965 
3966 /* If possible store the corresponding pointer from the variable argument
3967    list supplied to this function. Report an error if there are too many. */
3968                   if ( nptr < VMAXFLD ) {
3969                      ptr[ nptr++ ] = va_arg( args, void *);
3970 
3971 /* If the current field specifier is "%n" the corresponding pointer
3972    should be a pointer to an integer. We initialise the integer to zero.
3973    We need to do this because sscanf does not include "%n" values in the
3974    returned count of succesful conversions, and so there is no sure way
3975    of knowing whether a value has been stored for a "%n" field, and so
3976    whether it is safe to use it as an index into the supplied. */
3977                      if( *c == 'n' ) *( (int *) ptr[ nptr - 1 ] ) = 0;
3978 
3979                   } else {
3980                      astError( AST__INTER, "astSscanf: Format string "
3981                                "'%s' contains more than %d fields "
3982                                "(AST internal programming error).", status,
3983                                fmt, VMAXFLD );
3984                      break;
3985                   }
3986                }
3987 
3988 /* Move on the first character following the field specifier. */
3989                c++;
3990             }
3991 
3992 /* If this is not the start of a field specifier, pass on. */
3993          } else {
3994             c++;
3995          }
3996       }
3997 
3998 /* Fill any unused pointers with NULL. */
3999       for( iptr = nptr; iptr < VMAXFLD; iptr++ ) ptr[iptr] = NULL;
4000 
4001 /* Get the length of the string to be scanned. */
4002       lstr = strlen( str );
4003 
4004 /* Get the length of the format string excluding any trailing white space. */
4005       lfor = astChrLen( fmt );
4006 
4007 /* Bill Joye reports that MacOS sscanf fails to return the correct number of
4008    characters read (using a %n conversion) if there is a space before the
4009    %n. So check for this. Does the format string contain " %n"? */
4010       c = strstr( fmt, " %n" );
4011       if( c && astOK ) {
4012 
4013 /* Take a copy of the supplied format string (excluding any trailing spaces). */
4014          newfor = (char *) astStore( NULL, (void *) fmt, (size_t) lfor + 1 );
4015          if( newfor ) {
4016 
4017 /* Ensure the string is terminated (in case the supplied format string
4018    has any trailing spaces). */
4019             newfor[ lfor ] = 0;
4020 
4021 /* Remove all spaces from before any %n. */
4022             c = strstr( (const char *) newfor, " %n" );
4023             while( c ) {
4024                while( *(c++) ) *( c - 1 ) = *c;
4025                c = strstr( newfor, " %n" );
4026             }
4027 
4028 /* Use the native sscanf with the modified format string. Note, we cannot
4029    use vsscanf because it is not ANSI C. Instead, we list the pointers
4030    explicitly. */
4031             ret = sscanf( str, newfor, ptr[0], ptr[1], ptr[2], ptr[3],
4032                           ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9],
4033                           ptr[10], ptr[11], ptr[12], ptr[13], ptr[14],
4034                           ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] );
4035 
4036 /* Now look through the original format string for conversions specifiers.
4037    If any %n conversions are found which are preceded by a space, then
4038    correct the returned character counts to include any spaces following the
4039    corresponding point in the scanned string. */
4040             nfld = 0;
4041             iptr = 0;
4042             c = (char *) fmt;
4043             while( *c ) {
4044 
4045 /* Field specifiers are marked by a % sign. */
4046                if( *c == '%' ) {
4047 
4048 /* Look at the character following the % sign. Quit if the end of the string
4049    has been reached. */
4050                   c++;
4051                   if( *c ) {
4052 
4053 /* If the % sign is followed by a "*" or another "%", then there will be no
4054    corresponding pointer in the variable argument list "args". Ignore such
4055    field specifiers. */
4056                      if( *c != '*' && *c != '%' ) {
4057 
4058 /* Get the supplied pointer corresponding to this field specifier. */
4059                         fptr = ptr[ iptr++ ];
4060 
4061 /* Increment the number of matched fields required. "%n" specifiers are not
4062    included in the value returned by sscanf so skip over them. */
4063                         if( *c != 'n' ) {
4064                            nfld++;
4065 
4066 /* If the % sign is followed by a "n", and was preceded by a space, we
4067    may need to correct the returned character count. */
4068                         } else if( c > fmt + 1 && *(c-2) == ' ' ) {
4069 
4070 /* Do not correct the returned value if sscanf did not get as far as this
4071    field specifier before an error occurred. */
4072                            if( ret >= nfld ) {
4073 
4074 /* Get the original character count produced by sscanf. */
4075                               nc = *( (int *) fptr );
4076 
4077 /* For each space in "str" which follows, increment the returned count by
4078    one (so long as the original count is not zero or more than the length
4079    of the string - this is not foolproof, but I can't think of a better
4080    check - all uses of %n in AST initialize the supplied count to zero
4081    before calling sscanf so a value fo zero is a safe (ish) bet that the
4082    supplied string doesn't match the supplied format). */
4083                               if( nc > 0 && nc < lstr ) {
4084                                  d = str + nc;
4085                                  while( *(d++) == ' ' ) nc++;
4086                                  *( (int *) fptr ) = nc;
4087                               }
4088                            }
4089                         }
4090                      }
4091 
4092 /* Move on the first character following the field specifier. */
4093                      c++;
4094                   }
4095 
4096 /* If this is not the start of a field specifier, pass on. */
4097                } else {
4098                   c++;
4099                }
4100             }
4101 
4102 /* Release the temporary copy of the format string. */
4103             newfor = (char *) astFree( (void *) newfor );
4104          }
4105 
4106 /* If the format string should not trigger any known problems, use sscanf
4107    directly. */
4108       } else if( astOK ) {
4109          ret = sscanf( str, fmt, ptr[0], ptr[1], ptr[2], ptr[3],
4110                        ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9],
4111                        ptr[10], ptr[11], ptr[12], ptr[13], ptr[14],
4112                        ptr[15], ptr[16], ptr[17], ptr[18], ptr[19] );
4113       }
4114    }
4115 
4116 /* Tidy up the argument pointer. */
4117    va_end( args );
4118 
4119 /* Return the answer. */
4120    return ret;
4121 
4122 }
4123 
4124 
4125 /* The next functions are used only when memory debugging is
4126    switched on via the MEM_DEBUG macro. They can be used for locating
4127    memory leaks, etc. */
4128 #ifdef MEM_DEBUG
4129 
astActiveMemory_(const char * label)4130 void astActiveMemory_( const char *label ) {
4131 /*
4132 *+
4133 *  Name:
4134 *     astActiveMemory
4135 
4136 *  Purpose:
4137 *     Display a list of any currently active AST memory pointers.
4138 
4139 *  Type:
4140 *     Protected function.
4141 
4142 *  Synopsis:
4143 *     #include "memory.h"
4144 *     astActiveMemory( const char *label )
4145 
4146 *  Description:
4147 *     This function displays a list of the identifiers for all currently
4148 *     active AST memory chunks. The list is written to standard output
4149 *     using "printf", preceded by the supplied text.
4150 
4151 *  Parameters:
4152 *     label
4153 *        A textual label to display before the memody id values (may be
4154 *        NULL).
4155 
4156 *  Notes:
4157 *     - This function attempts to execute even if an error has occurred.
4158 *     - Memory blocks which are not usually freed are not reported. Such
4159 *     blocks are typically used by AST to hold internal state information.
4160 *-
4161 */
4162 
4163    Memory *next;
4164 
4165    if( label ) printf("%s: ", label );
4166    next = Active_List;
4167    if( next ) {
4168       while( next ) {
4169          if( !next->perm ) {
4170             printf( "%d(%s:%d) ", next->id, next->file, next->line );
4171          }
4172          next = next->next;
4173       }
4174    } else {
4175       printf("There are currently no active AST memory blocks.");
4176    }
4177    printf("\n");
4178 
4179 }
4180 
astWatchMemory_(int id)4181 void astWatchMemory_( int id ) {
4182 /*
4183 *+
4184 *  Name:
4185 *     astWatchMemory
4186 
4187 *  Purpose:
4188 *     Indicate uses of the memory block with the specified identifier
4189 *     should be reported.
4190 
4191 *  Type:
4192 *     Protected function.
4193 
4194 *  Synopsis:
4195 *     #include "memory.h"
4196 *     astWatchMemory( int id )
4197 
4198 *  Description:
4199 *     This function forces astMemoryAlarm to be invoked when key
4200 *     operations are performed on a specified memory block. These key
4201 *     operations include; allocation, freeing, copying and cloning of
4202 *     Objects, etc.
4203 *
4204 *     astMemoryAlarm reports a message when called identifying the memory
4205 *     block and the action performed on it. When using a debugger, these
4206 *     events can be trapped and investigated by setting a debugger
4207 *     breakpoint in astMemoryAlarm_.
4208 
4209 *  Parameters:
4210 *     id
4211 *        The identifier of the memory block which is to be watched.
4212 
4213 *  Notes:
4214 *     - This function attempts to execute even if an error has occurred.
4215 *-
4216 */
4217    Watched_ID = id;
4218 }
4219 
astMemoryId_(const void * ptr,int * status)4220 int astMemoryId_( const void *ptr, int *status ){
4221 /*
4222 *+
4223 *  Name:
4224 *     astMemoryId
4225 
4226 *  Purpose:
4227 *     Return the integer identifier for a memory block.
4228 
4229 *  Type:
4230 *     Protected function.
4231 
4232 *  Synopsis:
4233 *     #include "memory.h"
4234 *     int astMemoryId( const void *ptr )
4235 
4236 *  Description:
4237 *     This function returns the integer identifier associated with a
4238 *     memory block allocated by function sin this module.
4239 
4240 *  Parameters:
4241 *     ptr
4242 *        The pointer (a genuine C pointer, not an encoded object
4243 *        identifier).
4244 
4245 *  Returned Value:
4246 *     The integer identifier. A value of -1 is returned if "ptr" is NULL.
4247 
4248 *-
4249 */
4250    astDECLARE_GLOBALS
4251    astGET_GLOBALS(NULL);
4252    return ptr ? ((Memory *)(ptr-SIZEOF_MEMORY))->id : -1;
4253 }
4254 
astMemoryPtr_(int id)4255 void *astMemoryPtr_( int id ){
4256 /*
4257 *+
4258 *  Name:
4259 *     astMemoryPtr
4260 
4261 *  Purpose:
4262 *     Return a pointer to the memory block with a given identifier.
4263 
4264 *  Type:
4265 *     Protected function.
4266 
4267 *  Synopsis:
4268 *     #include "memory.h"
4269 *     void *astMemoryPtr( int id )
4270 
4271 *  Description:
4272 *     This function returns a pointer to the memory block with a given
4273 *     identifier. NULL is returned if the given identifier is not active.
4274 
4275 *  Parameters:
4276 *     id
4277 *        The identifier for an active memory block.
4278 
4279 *  Returned Value:
4280 *     The pointer to the memory block. NULL is returned if no active memory
4281 *     with the given ID can be found. Note, this is always a genuine C
4282 *     pointer (even for public Object pointers).
4283 
4284 *-
4285 */
4286    Memory *next;
4287    void *ret;
4288 
4289    ret = NULL;
4290    next = Active_List;
4291    while( next ) {
4292       if( next->id == id ) {
4293          ret = next + 1;
4294          break;
4295       }
4296    }
4297 
4298    return ret;
4299 }
4300 
astMemoryAlarm_(const char * verb)4301 void astMemoryAlarm_( const char *verb ){
4302 /*
4303 *+
4304 *  Name:
4305 *     astMemoryAlarm
4306 
4307 *  Purpose:
4308 *     Called when a watched memory ID is used.
4309 
4310 *  Type:
4311 *     Protected function.
4312 
4313 *  Synopsis:
4314 *     #include "memory.h"
4315 *     void astMemoryAlarm( const char *verb )
4316 
4317 *  Description:
4318 *     This function is called when a watched memory ID is used. See
4319 *     astWatchMemory.
4320 
4321 *  Parameters:
4322 *     verb
4323 *        Text to include in message.
4324 *-
4325 */
4326 
4327    printf( "astMemoryAlarm: Memory id %d has been %s.\n", Watched_ID, verb );
4328 }
4329 
astMemoryStats_(int reset,size_t * peak,size_t * current,int * status)4330 void astMemoryStats_( int reset, size_t *peak, size_t *current, int *status ) {
4331 /*
4332 *+
4333 *  Name:
4334 *     astMemoryStats
4335 
4336 *  Purpose:
4337 *     Return the current and peak AST memory usage.
4338 
4339 *  Type:
4340 *     Protected function.
4341 
4342 *  Synopsis:
4343 *     #include "memory.h"
4344 *     astMemoryStats( int reset, size_t *peak, size_t *current )
4345 
4346 *  Description:
4347 *     This function returns the current amount of memory allocated
4348 *     using AST memory management functions, and the peak amount of
4349 *     simultaneously allocated memory since the last time the peak value
4350 *     was reset.
4351 
4352 *  Parameters:
4353 *     reset
4354 *        If non-zero, the peak value is reset to the current usage
4355 *        upon return.
4356 *     peak
4357 *        Address at which to return the peak memory usage since the last
4358 *        reset, in bytes.
4359 *     current
4360 *        Address at which to return the current memory usage, in bytes.
4361 
4362 *-
4363 */
4364 
4365    LOCK_DEBUG_MUTEX;
4366 
4367    if( peak ) *peak = Peak_Usage;
4368    if( current ) *current = Current_Usage;
4369    if( reset ) Peak_Usage = Current_Usage;
4370 
4371    UNLOCK_DEBUG_MUTEX;
4372 }
4373 
astMemoryWarning_(size_t threshold,int * status)4374 void astMemoryWarning_( size_t threshold, int *status ) {
4375 /*
4376 *+
4377 *  Name:
4378 *     astMemoryWarning
4379 
4380 *  Purpose:
4381 *     Issues a warning memory goes over a specified threshold.
4382 
4383 *  Type:
4384 *     Protected function.
4385 
4386 *  Synopsis:
4387 *     #include "memory.h"
4388 *     astMemoryWarning( size_t threshold )
4389 
4390 *  Description:
4391 *     This function prints a warning message to standard output if the
4392 *     AST memory usage exceeds the specified threshold.
4393 
4394 *  Parameters:
4395 *     threshold
4396 *        The memory allocation, in bytes, at which a warning should be issued,
4397 *        Supply zero to suppress warnings.
4398 
4399 *  Notes:
4400 *     - This function is used to reset the threshold to zero when the first
4401 *     warning is issued in order to prevent a flood of warnings appearing.
4402 *     Therefore, setting a debugger breakpoint in this function
4403 *     ("astMemoryWarning_" - do not forget the trailing underscore)
4404 *     allows you to locate the point at which memory allocation first
4405 *     exceeds the threshold.
4406 
4407 *-
4408 */
4409 
4410    LOCK_DEBUG_MUTEX;
4411 
4412    Warn_Usage = threshold;
4413 
4414    UNLOCK_DEBUG_MUTEX;
4415 }
4416 
astMemoryUse_(const void * ptr,const char * verb,int * status)4417 void astMemoryUse_( const void *ptr, const char *verb, int *status ){
4418 /*
4419 *+
4420 *  Name:
4421 *     astMemoryUse
4422 
4423 *  Purpose:
4424 *     Called to report the use of a memory block pointer.
4425 
4426 *  Type:
4427 *     Protected function.
4428 
4429 *  Synopsis:
4430 *     #include "memory.h"
4431 *     void astMemoryUse( void *ptr, const char *verb )
4432 
4433 *  Description:
4434 *     If the supplied memory block is being watched, astMemoryAlarm is
4435 *     called to report the use of the pointer. The reported text includes
4436 *     the supplied "verb". A memory block can be watched by calling
4437 *     astWatchMemory.
4438 
4439 *  Parameters:
4440 *     ptr
4441 *        A pointer to the memory block being used. The pointer must have
4442 *        been returned by one of the AST memory management functions (e.g.
4443 *        astMalloc, astRealloc, etc).
4444 *     verb
4445 *        A verb indicating what is being done to the pointer.
4446 *-
4447 */
4448 
4449    astDECLARE_GLOBALS
4450    astGET_GLOBALS(NULL);
4451 
4452    if( ptr && astMemoryId( ptr ) == Watched_ID ) {
4453       if( !Quiet_Use || !strcmp( verb, ISSUED ) ||
4454                         !strcmp( verb, FREED ) ) {
4455          astMemoryAlarm( verb );
4456       }
4457    }
4458 }
4459 
astMemoryTune_(const char * name,int value,int * status)4460 int astMemoryTune_( const char *name, int value, int *status ){
4461 /*
4462 *+
4463 *  Name:
4464 *     astMemoryTune
4465 
4466 *  Purpose:
4467 *     Set a tuning parameter for the memory debugging functions.
4468 
4469 *  Type:
4470 *     Protected function.
4471 
4472 *  Synopsis:
4473 *     #include "memory.h"
4474 *     int astMemoryTune( const char *name, int value )
4475 
4476 *  Description:
4477 *     There are a few tuning parameters which control the behaviour of
4478 *     the memory debugging functions. This function allows these tuning
4479 *     parameters to be queried or set.
4480 
4481 *  Parameters:
4482 *     name
4483 *        The name of the tuning parameter to query or set. Valid names are:
4484 *
4485 *        "Keep_ID": A boolean flag indicating if a new ID should be issued
4486 *        for a cached memory block each time it is returned by astMalloc?
4487 *        Otherwise, the same ID value is used throughtout the life of a
4488 *        memory block. Default is zero (false).
4489 *
4490 *        "List_Cache": A boolean flag which if non-zero (true) causes the
4491 *        ID of every memory block in the cache to be reported when the
4492 *        cache is emptied by astFlushMemory.
4493 *
4494 *        "Quiet_Use": A boolean flag controlling the number of reports issued
4495 *        when a memory block is being watched (see astWatchMemory). If
4496 *        non-zero (true), then the only events which are reported are the
4497 *        issuing of a memory block pointer by astMalloc or astRealloc,and
4498 *        the freeing (or caching) of a memory block by astFree. If Quiet_Use
4499 *        is zero (the default), then additional reports are made for
4500 *        memory blocks used to hold AST Objects whenever the Object is
4501 *        copied, cloned, or checked.
4502 *     value
4503 *        The new value for the tuning parameter. If AST__TUNULL is
4504 *        supplied, the original value is left unchanged.
4505 
4506 *  Returned Value:
4507 *     The original value of the tuning parameter.
4508 
4509 *-
4510 */
4511 
4512    int result = AST__TUNULL;
4513 
4514    if( name ) {
4515 
4516       if( astChrMatch( name, "Keep_ID" ) ) {
4517          result = Keep_ID;
4518          if( value != AST__TUNULL ) Keep_ID = value;
4519 
4520       } else if( astChrMatch( name, "Quiet_Use" ) ) {
4521          result = Quiet_Use;
4522          if( value != AST__TUNULL ) Quiet_Use = value;
4523 
4524       } else if( astChrMatch( name, "List_Cache" ) ) {
4525          result = List_Cache;
4526          if( value != AST__TUNULL ) List_Cache = value;
4527 
4528       } else if( astOK ) {
4529          astError( AST__TUNAM, "astMemoryTune: Unknown AST memory tuning "
4530                    "parameter specified \"%s\".", status, name );
4531       }
4532    }
4533 
4534    return result;
4535 }
4536 
astBeginPM_(int * status)4537 void astBeginPM_( int *status ) {
4538 /*
4539 *+
4540 *  Name:
4541 *     astBeginPM
4542 
4543 *  Purpose:
4544 *     Start a block of permanent memory allocations.
4545 
4546 *  Type:
4547 *     Protected function.
4548 
4549 *  Synopsis:
4550 *     #include "memory.h"
4551 *     astBeginPM
4552 
4553 *  Description:
4554 *     This function indicates that all memory allocations made by calls
4555 *     to other functions in this module (e.g. astMalloc), up to the
4556 *     astEndPM call which matches the astBeginPM call,  will not usually
4557 *     be freed explicitly. Matching astBeginPM/astEndPM calls should be
4558 *     used to enclose all code which allocates memory which is never
4559 *     freed explitly by AST. Such memory allocations may be freed if
4560 *     required, using the astFlushMemory function (but note this should
4561 *     only be done once all use of AST by an application has finished).
4562 *
4563 *     Matching pairs of astBeginPM/astEndPM calls can be nested up to a
4564 *     maximum depth of 20.
4565 
4566 *-
4567 */
4568 
4569    LOCK_DEBUG_MUTEX;
4570 
4571 /* The global Perm_Mem flag indicates whether or not subsequent memory
4572    management functions in this module should store pointers to allocated
4573    blocks in the PM_List array. Push the current value of this flag
4574    onto a stack, and set the value to 1. */
4575    if( PM_Stack_Size >= PM_STACK_MAXSIZE ){
4576       if( astOK ) {
4577          astError( AST__INTER, "astBeginPM: Maximum stack size has been "
4578                    "exceeded (internal AST programming error)." , status);
4579       }
4580 
4581    } else {
4582       PM_Stack[ PM_Stack_Size++ ] = Perm_Mem;
4583       Perm_Mem = 1;
4584    }
4585    UNLOCK_DEBUG_MUTEX;
4586 }
4587 
astEndPM_(int * status)4588 void astEndPM_( int *status ) {
4589 /*
4590 *+
4591 *  Name:
4592 *     astEndPM
4593 
4594 *  Purpose:
4595 *     End a block of permanent memory allocations.
4596 
4597 *  Type:
4598 *     Protected function.
4599 
4600 *  Synopsis:
4601 *     #include "memory.h"
4602 *     astEndPM
4603 
4604 *  Description:
4605 *     This function indicates the end of the block of permanent memory
4606 *     allocations started by the matching call to astBeginPM. See
4607 *     astBeginPM for further details.
4608 
4609 *-
4610 */
4611 
4612    LOCK_DEBUG_MUTEX;
4613 
4614 /* The global Perm_Mem flag indicates whether or not subsequent memory
4615    management functions in this module should store pointers to allocated
4616    blocks in the PM_List array. Pop the value from the top of this stack. */
4617    if( PM_Stack_Size == 0 ){
4618       if( astOK ) {
4619          astError( AST__INTER, "astEndPM: astEndPM called without "
4620                    "matching astBeginPM (internal AST programming error)." , status);
4621       }
4622 
4623    } else {
4624       Perm_Mem = PM_Stack[ --PM_Stack_Size ];
4625    }
4626 
4627    UNLOCK_DEBUG_MUTEX;
4628 }
4629 
astFlushMemory_(int leak,int * status)4630 void astFlushMemory_( int leak, int *status ) {
4631 /*
4632 *+
4633 *  Name:
4634 *     astFlushMemory
4635 
4636 *  Purpose:
4637 *     Free all permanent and cached memory blocks.
4638 
4639 *  Type:
4640 *     Protected function.
4641 
4642 *  Synopsis:
4643 *     #include "memory.h"
4644 *     astFlushMemory( int leak );
4645 
4646 *  Description:
4647 *     This function should only be called once all use of AST by an
4648 *     application has finished. It frees any allocated but currently
4649 *     unused memory stored in an internal cache of unused memory
4650 *     pointers. (Note, it does not free any memory used permanently to
4651 *     store internal AST state information).
4652 *
4653 *     It is not normally necessary to call this function since the memory
4654 *     will be freed anyway by the operating system when the application
4655 *     terminates. However, it can be called if required in order to
4656 *     stop memory management tools such as valgrind from reporting that
4657 *     the memory has not been freed at the end of an application.
4658 *
4659 *     In addition, if "leak" is non-zero this function will also report
4660 *     an error if any active AST memory pointers remain which have not
4661 *     been freed (other than pointers for the cached and permanent
4662 *     memory described above). Leakage of active memory blocks can be
4663 *     investigated using astActiveMemory and astWatchMemory.
4664 
4665 *  Parameters:
4666 *     leak
4667 *        Should an error be reported if any non-permanent memory blocks
4668 *        are found to be active?
4669 
4670 *-
4671 */
4672 
4673 /* Local Variables: */
4674    Memory *next;
4675    int nact;
4676    int istat;
4677 
4678 /* Empty the cache. */
4679    astMemCaching( astMemCaching( AST__TUNULL ) );
4680 
4681 /* Free and count all non-permanent memory blocks. */
4682    nact = 0;
4683    next = Active_List;
4684    while( Active_List ) {
4685       next = Active_List->next;
4686       if( !Active_List->perm ) {
4687          nact++;
4688          FREE( Active_List );
4689       }
4690       Active_List = next;
4691    }
4692 
4693 /* Report an error if any active pointers remained. if an error has
4694    already occurred, use the existing status value. */
4695    if( nact && leak ){
4696 
4697       if( astOK ) {
4698          istat = AST__INTER;
4699       } else {
4700          istat = astStatus;
4701       }
4702       astError( istat, "astFlushMemory: %d AST memory blocks have not "
4703                 "been released (programming error).", status, nact );
4704 
4705    } else {
4706       printf("astFlushMemory: All AST memory blocks were released correctly.\n" );
4707    }
4708 }
4709 
astCheckMemory_(int * status)4710 void astCheckMemory_( int *status ) {
4711 /*
4712 *+
4713 *  Name:
4714 *     astCheckMemory
4715 
4716 *  Purpose:
4717 *     Check that all AST memory blocks have been released.
4718 
4719 *  Type:
4720 *     Protected function.
4721 
4722 *  Synopsis:
4723 *     #include "memory.h"
4724 *     astCheckMemory
4725 
4726 *  Description:
4727 *     This macro reports an error if any active AST memory pointers
4728 *     remain which have not been freed (other than pointers for cached
4729 *     and "permanently allocated" memory). Leakage of active memory blocks
4730 *     can be investigated using astActiveMemory and astWatchMemory.
4731 *-
4732 */
4733 
4734 /* Local Variables: */
4735    Memory *next;
4736    int nact;
4737    int istat;
4738 
4739 /* Empty the cache. */
4740    astMemCaching( astMemCaching( AST__TUNULL ) );
4741 
4742 /* Count all non-permanent memory blocks. */
4743    nact = 0;
4744    next = Active_List;
4745    while( Active_List ) {
4746       next = Active_List->next;
4747       if( !Active_List->perm ) nact++;
4748       Active_List = next;
4749    }
4750 
4751 /* Report an error if any active pointers remained. If an error has
4752    already occurred, use the existing status value. */
4753    if( nact ){
4754 
4755       if( astOK ) {
4756          istat = AST__INTER;
4757       } else {
4758          istat = astStatus;
4759       }
4760       astError( istat, "astCheckMemory: %d AST memory blocks have not "
4761                 "been released (programming error).", status, nact );
4762 
4763    } else {
4764       printf("astCheckMemory: All AST memory blocks were released correctly.\n" );
4765    }
4766 }
4767 
Issue(Memory * mem,int * status)4768 static void Issue( Memory *mem, int *status ) {
4769 /*
4770 *  Name:
4771 *     Issue
4772 
4773 *  Purpose:
4774 *     Indicate that a pointer to a memory block has been issued.
4775 
4776 *  Type:
4777 *     Private function.
4778 
4779 *  Synopsis:
4780 *     #include "memory.h"
4781 *     void Issue( Memory *mem, int *status );
4782 
4783 *  Description:
4784 *     Initialises the extra debug items in the Memory header, and adds the
4785 *     Memory structure to the list of active memory blocks.
4786 
4787 *  Parameters:
4788 *     mem
4789 *        Pointer to the Memory structure.
4790 *     status
4791 *        Pointer to the inherited status value.
4792 */
4793 
4794 /* Local Variables: */
4795    astDECLARE_GLOBALS
4796 
4797 /* Return if no pointer was supplied. */
4798    if( !mem ) return;
4799 
4800    LOCK_DEBUG_MUTEX;
4801    astGET_GLOBALS(NULL);
4802 
4803 /* Store a unique identifier for this pointer. Unless global Keep_ID is
4804    non-zero, a new identifier is used each time the pointer becomes active
4805    (i.e. each time it is remove from the cache or malloced). */
4806    if( !Keep_ID || mem->id < 0 ) mem->id = ++Next_ID;
4807 
4808 /* Record the file name and line number where it was issued. */
4809    if( AST__GLOBALS && AST__GLOBALS->Error.Current_File ) {
4810       strncpy( mem->file, AST__GLOBALS->Error.Current_File, sizeof(mem->file) );
4811       mem->file[ sizeof(mem->file) - 1 ] = 0;
4812       mem->line = AST__GLOBALS->Error.Current_Line;
4813    } else {
4814       mem->file[ 0 ] = 0;
4815       mem->line = 0;
4816    }
4817 
4818 /* Indicate if this is a permanent memory block (i.e. it will usually not
4819    be freed by AST). */
4820    mem->perm = Perm_Mem;
4821 
4822 /* Add it to the double linked list of active pointers. */
4823    mem->next = Active_List;
4824    mem->prev = NULL;
4825    if( Active_List ) Active_List->prev = mem;
4826    Active_List = mem;
4827 
4828 /* Report that the pointer is being issued. */
4829    astMemoryUse( (void *) mem + SIZEOF_MEMORY, ISSUED );
4830 
4831 /* Update the current and peak memory usage. */
4832    Current_Usage += mem->size + SIZEOF_MEMORY;
4833    if( Current_Usage > Peak_Usage ) Peak_Usage = Current_Usage;
4834 
4835 /* If the current allocation is above the threshold set using
4836    astMemoryWarning, issue a warning message, and then reset the threshold
4837    to zero to prevent further warnings being issued, and to allow a
4838    debugger breakpoint to be set. */
4839    if( Current_Usage > Warn_Usage &&
4840        Warn_Usage > 0 ) {
4841       printf( "Warning - AST memory allocation has exceeded %ld bytes - "
4842               "dumping catalogue of active memory blocks to file 'memory.dump'\n",
4843               Warn_Usage );
4844 
4845 /* Create a file holding the details of all currently active memory blocks. It can be
4846    examined using topcat. */
4847       FILE *fd = fopen( "memory.dump", "w" );
4848       if( fd ) {
4849          Memory *next;
4850 
4851          fprintf( fd, "# id size perm file line\n");
4852          next = Active_List;
4853          if( next ) {
4854             while( next ) {
4855                if( !next->perm ) {
4856                   fprintf( fd, "%d %zu %d %s %d\n", next->id, next->size,
4857                            next->perm, next->file, next->line );
4858                }
4859                next = next->next;
4860             }
4861          }
4862 
4863          fclose(fd );
4864       }
4865 
4866       Warn_Usage  = 0;
4867    }
4868 
4869    UNLOCK_DEBUG_MUTEX;
4870 }
4871 
DeIssue(Memory * mem,int * status)4872 static void DeIssue( Memory *mem, int *status ) {
4873 /*
4874 *  Name:
4875 *     DeIssue
4876 
4877 *  Purpose:
4878 *     Indicate that a pointer to a memory block has been freed.
4879 
4880 *  Type:
4881 *     Private function.
4882 
4883 *  Synopsis:
4884 *     #include "memory.h"
4885 *     void DeIssue( Memeory *mem, int *status );
4886 
4887 *  Description:
4888 *     Initialises the extra debug items in the Memory header, and adds the
4889 *     Memory structure to the list of active memory blocks.
4890 
4891 *  Parameters:
4892 *     mem
4893 *        Pointer to the Memory structure.
4894 *     status
4895 *        Pointer to the inherited status value.
4896 */
4897 
4898 /* Local Variables: */
4899    astDECLARE_GLOBALS
4900    Memory *next;
4901    Memory *prev;
4902 
4903 /* Return if no pointer was supplied. */
4904    if( !mem ) return;
4905 
4906    LOCK_DEBUG_MUTEX;
4907    astGET_GLOBALS(NULL);
4908 
4909 /* Report that the pointer is being freed. */
4910    astMemoryUse( (void *) mem + SIZEOF_MEMORY, FREED );
4911 
4912 /* Remove the block from the double linked list of active pointers. */
4913    next = mem->next;
4914    prev = mem->prev;
4915    if( prev ) prev->next = next;
4916    if( next ) next->prev = prev;
4917    if( mem == Active_List ) Active_List = next;
4918    mem->next = NULL;
4919    mem->prev = NULL;
4920 
4921 /* Update the current memory usage. */
4922    Current_Usage -= mem->size + SIZEOF_MEMORY;
4923 
4924    UNLOCK_DEBUG_MUTEX;
4925 }
4926 
4927 
4928 #endif
4929 
4930 
4931 
4932 
4933 
4934 
4935 /* The next functions are used only when profiling AST application. */
4936 #ifdef MEM_PROFILE
4937 
4938 
astStartTimer_(const char * file,int line,const char * name,int * status)4939 void astStartTimer_( const char *file, int line, const char *name, int *status ) {
4940 /*
4941 *+
4942 *  Name:
4943 *     astStartTimer
4944 
4945 *  Purpose:
4946 *     Measure the time spent until the corresponding call to astStopTimer.
4947 
4948 *  Type:
4949 *     Protected function.
4950 
4951 *  Synopsis:
4952 *     #include "memory.h"
4953 *     void astStartTimer( const char *name );
4954 
4955 *  Description:
4956 *     This function looks for a timer with the specified name within the
4957 *     current parent timer. If no timer with the given name is found, a
4958 *     new timer is created and initialised to zero. The current absolute
4959 *     time (elapsed, user and system) is recorded in the timer. The new
4960 *     timer then becomes the current timer.
4961 
4962 *  Parameters:
4963 *     name
4964 *        A label for the timer. This should be unique within the
4965 *        enclosing parent timer.
4966 
4967 *  Notes:
4968 *     - This function should only be used in a single-threaded environment.
4969 *     - This function returns without action if timers are currently
4970 *     disabled (see astEnableTimers).
4971 
4972 *-
4973 */
4974 
4975 /* Local Variables: */
4976    int n, found, i;
4977    AstTimer *t;
4978    struct tms buf;
4979 
4980 /* Check inherited status. Also return if timers are currently disabled. */
4981    if( !Enable_Timers || *status != 0 ) return;
4982 
4983 /* See if a timer with the given name exists in the list of child timers
4984    within the current timer. */
4985    found = 0;
4986    if( Current_Timer ) {
4987       for( i = 0; i < Current_Timer->nchild; i++ ) {
4988          t = Current_Timer->children[ i ];
4989          if( !strcmp( t->name, name ) ) {
4990             found = 1;
4991             break;
4992          }
4993       }
4994    }
4995 
4996 /* If not, create and initialise one now, and add it into the list of
4997    children within the current timer. */
4998    if( !found ) {
4999       t = astMalloc( sizeof( AstTimer ) );
5000       t->id = Timer_Count++;
5001       t->et = 0;
5002       t->ut = 0;
5003       t->st = 0;
5004       t->nentry = 0;
5005       t->name = name;
5006       t->file = file;
5007       t->line = line;
5008       t->parent = Current_Timer;
5009       t->nchild = 0;
5010       t->children = NULL;
5011 
5012       if( Current_Timer ) {
5013          n = (Current_Timer->nchild)++;
5014          Current_Timer->children = astGrow( Current_Timer->children,
5015                                             sizeof( AstTimer *),
5016                                             Current_Timer->nchild );
5017          Current_Timer->children[ n ] = t;
5018       }
5019    }
5020 
5021 /* Record the current absolute times (elapsed, user and system) within
5022    the new timer. */
5023    t->e0 = times(&buf);
5024    t->u0 = buf.tms_utime;
5025    t->s0 = buf.tms_stime;
5026 
5027 /* Increment the number of entries into the timer. */
5028    (t->nentry)++;
5029 
5030 /* Use the new timer as the current timer until the corresponding call to
5031    astStopTimer. */
5032    Current_Timer = t;
5033 }
5034 
astEnableTimers_(int enable,int * status)5035 void astEnableTimers_( int enable, int *status ) {
5036 /*
5037 *+
5038 *  Name:
5039 *     astEnableTimers
5040 
5041 *  Purpose:
5042 *     Set a global flag indicating if the use of AST timers is enabled.
5043 
5044 *  Type:
5045 *     Protected function.
5046 
5047 *  Synopsis:
5048 *     #include "memory.h"
5049 *     void astStartTimer( int enable );
5050 
5051 *  Description:
5052 *     This function sets a global flag that enables otr disables the user
5053 *     of AST Timers. If timers are disabled, the astStartTimer and
5054 *     astStopTimer functions will return without action.
5055 
5056 *  Parameters:
5057 *     enable
5058 *        If non-zero, timers will be used.
5059 
5060 *  Notes:
5061 *     - This function should only be used in a single-threaded environment.
5062 
5063 *-
5064 */
5065    Enable_Timers = enable;
5066 }
5067 
astStopTimer_(int * status)5068 void astStopTimer_( int *status ) {
5069 /*
5070 *+
5071 *  Name:
5072 *     astStopTimer
5073 
5074 *  Purpose:
5075 *     Record the time spent since the corresponding call to astStartTimer.
5076 
5077 *  Type:
5078 *     Protected function.
5079 
5080 *  Synopsis:
5081 *     #include "memory.h"
5082 *     void astStopTimer;
5083 
5084 *  Description:
5085 *     This function obtains the time increments since the corresponding
5086 *     call to astStartTimer, and adds these increments onto the total
5087 *     times stored in the current timer. It then changes the current
5088 *     timer to be the parent timer associated the current timer on entry.
5089 *
5090 *     If the current timer on entry has no parent (i.e. is a top level
5091 *     timer), the times spent in the top-level timer, and all its
5092 *     descendent timers, are displayed.
5093 
5094 *  Notes:
5095 *     - This function should only be used in a single-threaded environment.
5096 *     - This function returns without action if timers are currently
5097 *     disabled (see astEnableTimers).
5098 
5099 *-
5100 */
5101 
5102 /* Local Variables: */
5103    AstTimer *flat;
5104    AstTimer *t;
5105    int i;
5106    int nflat;
5107    struct tms buf;
5108 
5109 /* Check inherited status. Also return if timers are currently disabled. */
5110    if( !Enable_Timers || !Current_Timer || *status != 0 ) return;
5111 
5112 /* Get the current absolute times, and thus find the elapsed times since the
5113    corresponding call to astStartTimer. Use these elapsed times to increment
5114    the total times spent in the timer. */
5115    Current_Timer->et += ( times(&buf) - Current_Timer->e0 );
5116    Current_Timer->st += ( buf.tms_stime - Current_Timer->s0 );
5117    Current_Timer->ut += ( buf.tms_utime - Current_Timer->u0 );
5118 
5119 /* If this is a top level timer, display the times spent in the current
5120    timer, and in all its descendent timers. This also frees the memory
5121    used by the timers. */
5122    if( !Current_Timer->parent ) {
5123       flat = NULL;
5124       nflat = 0;
5125       Current_Timer = ReportTimer( Current_Timer, 0, &flat, &nflat, status );
5126 
5127 /* Sort and display the flat list of timers, then free the memory used by
5128    the flat list. */
5129       qsort( flat, nflat, sizeof( AstTimer), CompareTimers2 );
5130       printf("\n\n");
5131       t = flat;
5132       for( i = 0; i < nflat; i++,t++ ) {
5133          printf( "%s (%s:%d): ", t->name, t->file, t->line );
5134          printf( "elapsed=%ld ", (long int) t->et );
5135 /*
5136          printf( "system=%ld ", (long int) t->st );
5137          printf( "user=%ld ", (long int) t->ut );
5138 */
5139          printf( "calls=%d ", t->nentry );
5140          printf("\n");
5141       }
5142       flat = astFree( flat );
5143 
5144 /* If this is not a top level timer, restore the parent timer as the
5145    curent timer. */
5146    } else {
5147       Current_Timer = Current_Timer->parent;
5148    }
5149 }
5150 
ReportTimer(AstTimer * t,int ind,AstTimer ** flat,int * nflat,int * status)5151 static AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat,
5152                               int *nflat, int *status ) {
5153 /*
5154 *  Name:
5155 *     ReportTimer
5156 
5157 *  Purpose:
5158 *     Free and report the times spent in a given timer, and all descendents.
5159 
5160 *  Type:
5161 *     Private function.
5162 
5163 *  Synopsis:
5164 *     #include "memory.h"
5165 *     AstTimer *ReportTimer( AstTimer *t, int ind, AstTimer **flat,
5166 *                            int *nflat, int *status )
5167 
5168 *  Description:
5169 *     This routines reports to standard output the times spent in the
5170 *     supplied timer. It then calls itself recursively to report the times
5171 *     spent in each of the child timers of the supplied timer.
5172 *
5173 *     It also frees the memory used to hold the supplied timer.
5174 
5175 *  Parameters:
5176 *     t
5177 *        Pointer to the AstTimer structure.
5178 *     ind
5179 *        The number of spaces of indentation to display before the timer
5180 *        details.
5181 *     flat
5182 *        Address of a pointer to the start of an array of AstTimers. The
5183 *        number of elements in this array is given by "*nflat". Each
5184 *        Timer in this array holds the accumulated total for all entries
5185 *        into a given timer, from all parent contexts.
5186 *     nflat
5187 *        Address of an int holding the current length of the "*flat" array.
5188 *     status
5189 *        Pointer to the inherited status value.
5190 */
5191 
5192 /* Local Variables: */
5193    int found;
5194    int i;
5195    AstTimer *ft;
5196    AstTimer *parent;
5197 
5198 /* Check inherited status */
5199    if( *status != 0 ) return NULL;
5200 
5201 /* Display a single line of text containing the times stored in the supplied
5202    timer, preceded by the requested number of spaces. */
5203    for( i = 0; i < ind; i++ ) printf(" ");
5204    printf( "%s (%s:%d): ", t->name, t->file, t->line );
5205 
5206    printf( "id=%d ", t->id );
5207    printf( "elapsed=%ld ", (long int) t->et );
5208 /*
5209    printf( "system=%ld ", (long int) t->st );
5210    printf( "user=%ld ", (long int) t->ut );
5211 */
5212    printf( "calls=%d ", t->nentry );
5213 
5214 /* If there are any children, end the line with an opening bvrace. */
5215    if( t->nchild ) printf("{");
5216    printf("\n");
5217 
5218 /* If there is more than one child, sort them into descending order of
5219    elapsed time usage. */
5220    if( t->nchild > 1 ) qsort( t->children, t->nchild, sizeof( AstTimer * ),
5221                               CompareTimers );
5222 
5223 /* Increment the indentation and call this function recursively to
5224    display and free each child timer. */
5225    ind += 3;
5226    for( i = 0; i < t->nchild; i++ ) {
5227       (t->children)[ i ] = ReportTimer( (t->children)[ i ], ind, flat,
5228                                         nflat, status );
5229    }
5230 
5231 /* Delimit the children by displaying a closing brace. */
5232    if( t->nchild ) {
5233       for( i = 0; i < ind - 3; i++ ) printf(" ");
5234       printf("}\n");
5235    }
5236 
5237 /* See if this timer is contained within itself at a higher level. */
5238    parent = t->parent;
5239    while( parent && ( parent->line != t->line ||
5240                       strcmp( parent->file, t->file ) ) ) {
5241       parent = parent->parent;
5242    }
5243 
5244 /* If not, search for a timer in the "flat" array of timers that has the same
5245    source file and line number. */
5246    if( !parent ) {
5247       found = 0;
5248       ft = *flat;
5249       for( i = 0; i < *nflat; i++, ft++ ) {
5250          if( ft->line == t->line &&
5251              !strcmp( ft->file, t->file ) ) {
5252             found = 1;
5253             break;
5254          }
5255       }
5256 
5257 /* If not found, add a new timer to the end of the "flat" array and
5258    initialise it. */
5259       if( !found ) {
5260          i = (*nflat)++;
5261          *flat = astGrow( *flat, *nflat, sizeof( AstTimer ) );
5262          ft = (*flat) + i;
5263          ft->id = 0;
5264          ft->et = t->et;
5265          ft->ut = t->ut;
5266          ft->st = t->st;
5267          ft->nentry = t->nentry;
5268          ft->name = t->name;
5269          ft->file = t->file;
5270          ft->line = t->line;
5271          ft->parent = NULL;
5272          ft->nchild = 0;
5273          ft->children = NULL;
5274 
5275 
5276 /* If found, increment the properites to include the supplied timer. */
5277       } else {
5278          ft->et += t->et;
5279          ft->ut += t->ut;
5280          ft->st += t->st;
5281          ft->nentry += t->nentry;
5282       }
5283    }
5284 
5285 /* Free the memory used by the supplied timer. */
5286    t->children = astFree( t->children );
5287    return astFree( t );
5288 }
5289 
5290 
CompareTimers(const void * a,const void * b)5291 static int CompareTimers( const void *a, const void *b ){
5292    return ((*((AstTimer **) b ))->et) - ((*((AstTimer **) a ))->et);
5293 }
5294 
CompareTimers2(const void * a,const void * b)5295 static int CompareTimers2( const void *a, const void *b ){
5296    return (((AstTimer *) b )->et) - (((AstTimer *) a )->et);
5297 }
5298 
5299 #endif
5300