1 /*
2 *class++
3 
4 *  Name:
5 *     Object
6 
7 *  Purpose:
8 *     Base class for all AST Objects.
9 
10 *  Constructor Function:
11 *     None.
12 
13 *  Description:
14 *     This class is the base class from which all other classes in the
15 *     AST library are derived. It provides all the basic Object
16 *     behaviour and Object manipulation facilities required throughout
17 *     the library. There is no Object constructor, however, as Objects
18 *     on their own are not useful.
19 
20 *  Inheritance:
21 *     The Object base class does not inherit from any other class.
22 
23 *  Attributes:
24 *     All Objects have the following attributes:
25 *
26 *     - Class: Object class name
27 *     - ID: Object identification string
28 *     - Ident: Permanent Object identification string
29 *     - Nobject: Number of Objects in class
30 *     - ObjSize: The in-memory size of the Object in bytes
31 *     - RefCount: Count of active Object pointers
32 *     - UseDefs: Allow use of default values for Object attributes?
33 
34 *  Functions:
35 c     The following functions may be applied to all Objects:
36 f     The following routines may be applied to all Objects:
37 *
38 c     - astAnnul: Annul a pointer to an Object
39 c     - astBegin: Begin a new AST context
40 c     - astClear: Clear attribute values for an Object
41 c     - astClone: Clone a pointer to an Object
42 c     - astCopy: Copy an Object
43 c     - astDelete: Delete an Object
44 c     - astEnd: End an AST context
45 c     - astEscapes: Control whether graphical escape sequences are removed
46 c     - astExempt: Exempt an Object pointer from AST context handling
47 c     - astExport: Export an Object pointer to an outer context
48 c     - astGet<X>: Get an attribute value for an Object
49 c     - astHasAttribute: Test if an Object has a named attribute
50 c     - astImport: Import an Object pointer to the current context
51 c     - astIsA<Class>: Test class membership
52 c     - astLock: Lock an Object for use by the calling thread
53 c     - astToString: Create an in-memory serialisation of an Object
54 c     - astSame: Do two AST pointers refer to the same Object?
55 c     - astSet: Set attribute values for an Object
56 c     - astSet<X>: Set an attribute value for an Object
57 c     - astShow: Display a textual representation of an Object on standard
58 c     output
59 c     - astTest: Test if an attribute value is set for an Object
60 c     - astTune: Set or get an integer AST tuning parameter
61 c     - astTuneC: Set or get a character AST tuning parameter
62 c     - astUnlock: Unlock an Object for use by other threads
63 c     - astFromString: Re-create an Object from an in-memory serialisation
64 c     - astVersion: Return the verson of the AST library being used.
65 f     - AST_ANNUL: Annul a pointer to an Object
66 f     - AST_BEGIN: Begin a new AST context
67 f     - AST_CLEAR: Clear attribute values for an Object
68 f     - AST_CLONE: Clone a pointer to an Object
69 f     - AST_COPY: Copy an Object
70 f     - AST_DELETE: Delete an Object
71 f     - AST_END: End an AST context
72 f     - AST_ESCAPES: Control whether graphical escape sequences are removed
73 f     - AST_EXEMPT: Exempt an Object pointer from AST context handling
74 f     - AST_EXPORT: Export an Object pointer to an outer context
75 f     - AST_GET<X>: Get an attribute value for an Object
76 f     - AST_HASATTRIBUTE: Test if an Object has a named attribute
77 f     - AST_IMPORT: Import an Object pointer to the current context
78 f     - AST_ISA<CLASS>: Test class membership
79 f     - AST_SAME: Do two AST pointers refer to the same Object?
80 f     - AST_SET: Set attribute values for an Object
81 f     - AST_SET<X>: Set an attribute value for an Object
82 f     - AST_SHOW: Display a textual representation of an Object on standard
83 f     output
84 f     - AST_TEST: Test if an attribute value is set for an Object
85 f     - AST_TUNE: Set or get an integer AST tuning parameter
86 f     - AST_TUNEC: Set or get a character AST tuning parameter
87 f     - AST_VERSION: Return the verson of the AST library being used.
88 
89 *  Copyright:
90 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
91 *     Research Councils
92 *     Copyright (C) 2010 Science & Technology Facilities Council.
93 *     All Rights Reserved.
94 
95 *  Licence:
96 *     This program is free software: you can redistribute it and/or
97 *     modify it under the terms of the GNU Lesser General Public
98 *     License as published by the Free Software Foundation, either
99 *     version 3 of the License, or (at your option) any later
100 *     version.
101 *
102 *     This program is distributed in the hope that it will be useful,
103 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
104 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
105 *     GNU Lesser General Public License for more details.
106 *
107 *     You should have received a copy of the GNU Lesser General
108 *     License along with this program.  If not, see
109 *     <http://www.gnu.org/licenses/>.
110 
111 *  Authors:
112 *     RFWS: R.F. Warren-Smith (Starlink)
113 *     DSB: David S. Berry (Starlink)
114 
115 *  History:
116 *     1-FEB-1996 (RFWS):
117 *        Original version.
118 *     22-APR-1996 (RFWS):
119 *        Added attribute setting functions.
120 *     2-JUL-1996 (RFWS):
121 *        Added functions to support the external interface (using
122 *        identfiers).
123 *     10-SEP-1996 (RFWS):
124 *        Added I/O facilities.
125 *     30-MAY-1997 (RFWS):
126 *        Add ID attribute.
127 *     14-JUL-1997 (RFWS):
128 *        Add astExempt function.
129 *     14-OCT-1997 (RFWS):
130 *        Fixed uninitialised use of "dynamic" in astCopy_.
131 *     14-NOV-1997 (RFWS):
132 *        Remove the subversive C "strtok" function.
133 *     20-JAN-1998 (RFWS):
134 *        Make the astClear and astRVSet methods virtual.
135 *     29-APR-1998 (RFWS):
136 *        Fixed bug in algorithm for encoding Object IDs.
137 *     15-SEP-1999 (RFWS)
138 *        Made astAnnulId accessible from protected code.
139 *     12-APR-2000 (DSB):
140 *        Zero all memory allocated for a new Object in InitObject before
141 *        storing any new values in the memory.
142 *     3-APR-2001 (DSB):
143 *        Added the Ident attribute.
144 *     28-SEP-2001 (DSB):
145 *        Modified VSet to ensure a non-null string always follows the equal
146 *        sign in the attribute setting passed to SetAttrib.
147 *     27-NOV-2002 (DSB):
148 *        Modified astShow to use astWrite instead of astDump, so that
149 *        invocations of astShow will be included in the count of the
150 *        number of invocations of astWrite returned by astWriteInvocations.
151 *     8-JAN-2003 (DSB):
152 *        Changed private InitVtab method to protected astInitObjectVtab
153 *        method.
154 *     8-FEB-2004 (DSB):
155 *        Added astEscapes.
156 *     10-FEB-2004 (DSB):
157 *        Added debug conditional code to keep track of memory leaks.
158 *     22-AUG-2004 (DSB):
159 *        Added astEqual
160 *     27-JAN-2005 (DSB):
161 *        Correct use of ->ident pointers, and added further DEBUG blocks.
162 *     11-MAR-2005 (DSB):
163 *        Added attribute UseDefs.
164 *     14-FEB-2006 (DSB):
165 *        Added attribute ObjSize.
166 *     23-FEB-2006 (DSB):
167 *        Added MemoryCaching tuning parameter.
168 *     27-FEB-2006 (DSB):
169 *        Include Objects returned by astCopy in the ObjectCaching system.
170 *     28-FEB-2006 (DSB):
171 *        Use astOK to protect against errors within astGrow.
172 *     1-MAR-2006 (DSB):
173 *        Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
174 *     26-MAY-2006 (DSB):
175 *        Correct handling of commas within the attribute value supplied
176 *        to astSetC.
177 *     30-MAY-2006 (DSB):
178 *        Correct the correction made to handle commas within attribute
179 *     6-JUN-2007 (DSB):
180 *        Fix harmless compiler warnings.
181 *     21-JUN-2007 (DSB):
182 *        In astSet<X>, ignore trailing spaces in the attribute name.
183 *     22-JUN-2007 (DSB):
184 *        - Make astVSet return a pointer to dynamic memory holding the
185 *        expanded setting string.
186 *        - Add astSetVtab, and astCast.
187 *     27-JUN-2007 (DSB):
188 *        Modify astInitObject so that it ignores the supplied "size" value
189 *        if some memory is supplied.
190 *     2-JULY-2007 (DSB):
191 *        Fix memory access problem in VSet.
192 *     20-SEP-2007 (DSB):
193 *        In astDelete, ensure the error status is reset before calling
194 *        astGrow to extend the vtab free list.
195 *     22-APR-2008 (DSB):
196 *        Added astSame.
197 *     24-OCT-2008 (DSB):
198 *        Prevent a mutex deadlock that could occur when annulling an
199 *        Object ID.
200 *     28-JAN-2008 (DSB):
201 *        Allow unlocked objects to be annulled using astAnnul.
202 *     14-OCT-2009 (DSB):
203 *        Modify astCast to make it a virtual function and add type
204 *        checking.
205 *     7-APR-2010 (DSB):
206 *        Added method astHasAttribute.
207 *     24-AUG-2010 (DSB):
208 *        Allow commas to be included in attribute values supplied to
209 *        astSet or astVSet by putting quotes around the attribute value.
210 *     16-JUN-2011 (DSB):
211 *        Added component "iref" to the Object structure. This is an
212 *        integer identifier for each object that is unique within the
213 *        class of the object. Useful for debugging.
214 *     22-JUL-2011 (DSB):
215 *        Add methods astSetProxy and astGetProxy.
216 *     2-SEP-2011 (DSB):
217 *        Add functions astToString and astFromString.
218 *     13-SEP-2013 (DSB):
219 *        Report an error in astAnnul if the supplied object handle is owned by
220 *        a different thread. Note, the Object itself does not need to be owned
221 *        by the current thread, since it should be possible for a thread to
222 *        relinquish a pointer to an object (i.e. a handle) without actually
223 *        owning the object itself.
224 *     6-JAN-2014 (DSB):
225 *        Added method astEnvSet.
226 *class--
227 */
228 
229 /* Module Macros. */
230 /* ============== */
231 /* Set the name of the class we are implementing. This indicates to
232    the header files that define class interfaces that they should make
233    "protected" symbols available. */
234 #define astCLASS Object
235 
236 #define INVALID_CONTEXT -1   /* Context value for handles that have no
237                                 associated Object */
238 #define UNOWNED_CONTEXT -2   /* Context value for handles for objects
239                                 that are not locked by any thread */
240 
241 
242 /* Include files. */
243 /* ============== */
244 
245 /* Configuration information */
246 /* ------------------------ */
247 #include "version.h"             /* Version numbers */
248 #if HAVE_CONFIG_H
249 #include <config.h>
250 #endif
251 
252 /* Interface definitions. */
253 /* ---------------------- */
254 #include "error.h"               /* Error reporting facilities */
255 #include "memory.h"              /* Memory allocation facilities */
256 #include "channel.h"             /* I/O channels */
257 #include "object.h"              /* Interface definition for this class */
258 #include "plot.h"                /* Plot class (for astStripEscapes) */
259 #include "globals.h"             /* Thread-safe global data access */
260 
261 /* Error code definitions. */
262 /* ----------------------- */
263 #include "ast_err.h"             /* AST error codes */
264 
265 /* C header files. */
266 /* --------------- */
267 #include <ctype.h>
268 #include <errno.h>
269 #include <float.h>
270 #include <stdarg.h>
271 #include <stddef.h>
272 #include <stdio.h>
273 #include <stdlib.h>
274 #include <string.h>
275 #include <limits.h>
276 
277 /* Type Definitions */
278 /* ================ */
279 /* Structure used to pass data between astToString/FromString and the
280    corresponding Channel source and sink functions. */
281 typedef struct StringData {
282    char *ptr;      /* Pointer to serialisation text */
283    char *buff;     /* Pointer to a buffer for a single line of text */
284    int len;        /* Current length of serialisation text */
285 } StringData;
286 
287 /* Module Variables. */
288 /* ================= */
289 
290 /* The following globals have the same values in all threads and so do
291    not need to be in thread-specific data. */
292 /* ------------------------------------------------------------------ */
293 
294 /* Character-valued tuning parameters. */
295 #define MAXLEN_TUNEC 200
296 static char hrdel[ MAXLEN_TUNEC ] = "%-%^50+%s70+h%+";
297 static char mndel[ MAXLEN_TUNEC ] = "%-%^50+%s70+m%+";
298 static char scdel[ MAXLEN_TUNEC ] = "%-%^50+%s70+s%+";
299 static char dgdel[ MAXLEN_TUNEC ] = "%-%^53+%s60+o%+";
300 static char amdel[ MAXLEN_TUNEC ] = "%-%^20+%s85+'%+";
301 static char asdel[ MAXLEN_TUNEC ] = "%-%^20+%s85+\"%+";
302 static char exdel[ MAXLEN_TUNEC ] = "10%-%^50+%s70+";
303 
304 /* A pointer full of zeros. */
305 static AstObject *zero_ptr;
306 
307 /* A flag which indicates what should happen when an AST Object is
308    deleted. If this flag is non-zero, the memory used by the Object is
309    not freed, but a pointer to it is placed on the end of a list of free
310    memory chunk pointers so that the memory can be re-used if necessary
311    avoiding the need to re-allocate memory with malloc (which is slow).
312    A separate list of free memory chunks is kept for each class because
313    each class object will require chunks of a different size. Pointers
314    to these lists are stored in the virtual function table associated
315    with each class. All memory on these lists is freed when object
316    caching is switched off via the astTune function. */
317 static int object_caching = 0;
318 
319 /* Set up global data access, mutexes, etc, needed for thread safety. */
320 #ifdef THREAD_SAFE
321 
322 /* Define the initial values for the global data for this module. */
323 #define GLOBAL_inits \
324    globals->Retain_Esc = 0; \
325    globals->Context_Level = 0; \
326    globals->GetAttrib_Buff[ 0 ] = 0; \
327    globals->AstGetC_Init = 0; \
328    globals->AstGetC_Istr = 0; \
329    globals->Active_Handles = NULL; \
330    globals->Class_Init = 0; \
331    globals->Nvtab = 0; \
332    globals->Known_Vtabs = NULL;
333 
334 /* Create the function that initialises global data for this module. */
335 astMAKE_INITGLOBALS(Object)
336 
337 /* Define macros for accessing each item of thread specific global data. */
338 #define retain_esc  astGLOBAL(Object,Retain_Esc)
339 #define context_level  astGLOBAL(Object,Context_Level)
340 #define active_handles  astGLOBAL(Object,Active_Handles)
341 #define getattrib_buff  astGLOBAL(Object,GetAttrib_Buff)
342 #define astgetc_strings  astGLOBAL(Object,AstGetC_Strings)
343 #define astgetc_istr  astGLOBAL(Object,AstGetC_Istr)
344 #define astgetc_init  astGLOBAL(Object,AstGetC_Init)
345 #define class_init astGLOBAL(Object,Class_Init)
346 #define class_vtab astGLOBAL(Object,Class_Vtab)
347 #define nvtab astGLOBAL(Object,Nvtab)
348 #define known_vtabs astGLOBAL(Object,Known_Vtabs)
349 
350 /* mutex1 is used to prevent tuning parameters being accessed by more
351    than one thread at any one time.  */
352 static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
353 #define LOCK_MUTEX1 pthread_mutex_lock( &mutex1 );
354 #define UNLOCK_MUTEX1 pthread_mutex_unlock( &mutex1 );
355 
356 /* mutex2 is used to prevent the global lists of object handles being
357    accessed by more than one thread at any one time.  */
358 static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
359 #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
360 #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
361 
362 /* Each Object contains two mutexes. The primary mutex (mutex1) is used
363    to guard access to all aspects of the Object except for the "locker"
364    and "ref_count" items. The secondary mutex (mutex2) is used to guard
365    access to these two remaining items. We need this secondary mutex
366    since the "locker" and "ref_count" items need to be accessable within
367    a thread even if that thread has not locked the Object using astLock.
368    Define macros for accessing these two mutexes. */
369 #define LOCK_PMUTEX(this) (pthread_mutex_lock(&((this)->mutex1)))
370 #define UNLOCK_PMUTEX(this) (pthread_mutex_unlock(&((this)->mutex1)))
371 #define LOCK_SMUTEX(this) (pthread_mutex_lock(&((this)->mutex2)))
372 #define UNLOCK_SMUTEX(this) (pthread_mutex_unlock(&((this)->mutex2)))
373 
374 
375 
376 
377 
378 /* If thread safety is not needed, declare and initialise globals at static
379    variables. */
380 #else
381 
382 /* Define the class virtual function table and its initialisation flag as
383    static variables. */
384 static int class_init = 0;       /* Virtual function table initialised? */
385 static AstObjectVtab class_vtab; /* Virtual function table */
386 
387 /* A list of pointers to all the known class virtual function tables. */
388 static int nvtab = 0;
389 static AstObjectVtab **known_vtabs = NULL;
390 
391 /* A flag which indicates if AST functions which return text strings
392    should retain any graphical escape sequences (as interpreted by the
393    Plot class). */
394 static int retain_esc = 0;
395 
396 /* Context level (Begin/End/Exempt/Export) */
397 static int context_level = 0;
398 
399 /* Array of list heads for each context (each list is a list of Handle
400    structures). */
401 static int *active_handles = NULL;
402 
403 /* String returned by GetAttrib. */
404 static char getattrib_buff[ AST__GETATTRIB_BUFF_LEN + 1 ] = "";
405 
406 /* Pointers to string buffers returned by astGetC. */
407 static char *astgetc_strings[ AST__ASTGETC_MAX_STRINGS ];
408 
409 /* Offset of next string in "AstGetC_Strings" */
410 static int astgetc_istr = 0;
411 
412 /* "AstGetC_Strings" array initialised? */
413 static int astgetc_init = 0;
414 
415 /* Null macros for mutex locking and unlocking */
416 #define LOCK_MUTEX1
417 #define UNLOCK_MUTEX1
418 #define LOCK_MUTEX2
419 #define UNLOCK_MUTEX2
420 #define LOCK_PMUTEX(this)
421 #define LOCK_SMUTEX(this)
422 #define UNLOCK_PMUTEX(this)
423 #define UNLOCK_SMUTEX(this)
424 
425 #endif
426 
427 
428 /* Prototypes for Private Member Functions. */
429 /* ======================================== */
430 static AstObject *Cast( AstObject *, AstObject *, int * );
431 static const char *GetID( AstObject *, int * );
432 static const char *GetAttrib( AstObject *, const char *, int * );
433 static const char *GetIdent( AstObject *, int * );
434 static const char *Get( AstObject *, const char *, int * );
435 static const char *FromStringSource( void );
436 static int Equal( AstObject *, AstObject *, int * );
437 static int GetObjSize( AstObject *, int * );
438 static int HasAttribute( AstObject *, const char *, int * );
439 static int Same( AstObject *, AstObject *, int * );
440 static int TestAttrib( AstObject *, const char *, int * );
441 static int TestID( AstObject *, int * );
442 static int TestIdent( AstObject *, int * );
443 static unsigned long Magic( const AstObject *, size_t, int * );
444 static void CleanAttribs( AstObject *, int * );
445 static void Clear( AstObject *, const char *, int * );
446 static void ClearAttrib( AstObject *, const char *, int * );
447 static void ClearIdent( AstObject *, int * );
448 static void ClearID( AstObject *, int * );
449 static void Dump( AstObject *, AstChannel *, int * );
450 static void EmptyObjectCache( int * );
451 static void ToStringSink( const char * );
452 static void SetAttrib( AstObject *, const char *, int * );
453 static void SetID( AstObject *, const char *, int * );
454 static void SetIdent( AstObject *, const char *, int * );
455 static void Show( AstObject *, int * );
456 static void VSet( AstObject *, const char *, char **, va_list, int * );
457 static void EnvSet( AstObject *, int * );
458 
459 static int GetUseDefs( AstObject *, int * );
460 static int TestUseDefs( AstObject *, int * );
461 static void ClearUseDefs( AstObject *, int * );
462 static void SetUseDefs( AstObject *, int, int * );
463 
464 #if defined(THREAD_SAFE)
465 static void ChangeThreadVtab( AstObject *, int * );
466 static int ManageLock( AstObject *, int, int, AstObject **, int * );
467 #endif
468 
469 /* Member functions. */
470 /* ================= */
astAnnul_(AstObject * this,int * status)471 AstObject *astAnnul_( AstObject *this, int *status ) {
472 /*
473 *++
474 *  Name:
475 c     astAnnul
476 f     AST_ANNUL
477 
478 *  Purpose:
479 *     Annul a pointer to an Object.
480 
481 *  Type:
482 *     Public function.
483 
484 *  Synopsis:
485 c     #include "object.h"
486 c     AstObject *astAnnul( AstObject *this )
487 f     CALL AST_ANNUL( THIS, STATUS )
488 
489 *  Class Membership:
490 *     Object method.
491 
492 *  Description:
493 c     This function annuls a pointer to an Object so that it is no
494 f     This routine annuls a pointer to an Object so that it is no
495 *     longer recognised as a valid pointer by the AST library. Any
496 *     resources associated with the pointer are released and made
497 *     available for re-use.
498 *
499 c     This function also decrements the Object's RefCount attribute by
500 f     This routine also decrements the Object's RefCount attribute by
501 *     one. If this attribute reaches zero (which happens when the last
502 *     pointer to the Object is annulled), then the Object is deleted.
503 
504 *  Parameters:
505 c     this
506 c        The Object pointer to be annulled.
507 f     THIS = INTEGER (Given and Returned)
508 f        The Object pointer to be annulled. A null pointer value (AST__NULL)
509 f        is always returned.
510 f     STATUS = INTEGER (Given and Returned)
511 f        The global status.
512 
513 c  Returned Value:
514 c     astAnnul()
515 c        A null Object pointer (AST__NULL) is always returned.
516 c
517 *  Applicability:
518 *     Object
519 c        This function applies to all Objects.
520 f        This routine applies to all Objects.
521 
522 *  Notes:
523 c     - This function will attempt to annul the pointer even if the
524 c     Object is not currently locked by the calling thread (see astLock).
525 c     - This function attempts to execute even if the AST error
526 c     status is set
527 f     - This routine attempts to execute even if STATUS is set to an
528 f     error value
529 *     on entry, although no further error report will be
530 *     made if it subsequently fails under these circumstances. In
531 *     particular, it will fail if the pointer suppled is not valid,
532 *     but this will only be reported if the error status is clear on
533 *     entry.
534 *--
535 */
536 
537 /* Check the pointer to ensure it identifies a valid Object (this
538    generates an error if it doesn't). */
539    if ( !astIsAObject( this ) ) return NULL;
540 
541 /* Get a lock on the object's secondary mutex. This mutex guards access
542    to the "ref_count" and "locker" components of the AstObject structure. */
543    LOCK_SMUTEX(this);
544 
545 #ifdef MEM_DEBUG
546    {   int rc;
547        char buf[100];
548        rc = this->ref_count;
549        sprintf(buf,"annulled (refcnt: %d -> %d)", rc, rc-1 );
550        astMemoryUse( this, buf );
551    }
552 #endif
553 
554 /* Decrement the Object's reference count. */
555    --(this->ref_count);
556 
557 /* Unlock the object's secondary mutex. */
558    UNLOCK_SMUTEX(this);
559 
560 /* Decrement the Object's reference count and delete the Object if
561    necessary. */
562    if ( !this->ref_count ) (void) astDelete( this );
563 
564 /* Always return NULL. */
565    return NULL;
566 }
567 
Cast(AstObject * this,AstObject * obj,int * status)568 static AstObject *Cast( AstObject *this, AstObject *obj, int *status ) {
569 /*
570 *+
571 *  Name:
572 *     astCast
573 
574 *  Purpose:
575 *     Cast an Object into an instance of a sub-class.
576 
577 *  Type:
578 *     Protected virtual function.
579 
580 *  Synopsis:
581 *     #include "object.h"
582 *     AstObject *astCast( AstObject *this, AstObject *obj )
583 
584 *  Class Membership:
585 *     Object method.
586 
587 *  Description:
588 *     This function returns a deep copy of an ancestral component of the
589 *     supplied object. The required class of the ancestral component is
590 *     specified by another object. Specifically, if "this" and "new" are
591 *     of the same class, a copy of "this" is returned. If "this" is an
592 *     instance of a subclass of "obj", then a copy of the component
593 *     of "this" that matches the class of "obj" is returned. Otherwise,
594 *     a NULL pointer is returned without error.
595 
596 *  Parameters:
597 *     this
598 *        Pointer to the Object to be cast.
599 *     obj
600 *        Pointer to an Object that defines the class of the returned Object.
601 *        The returned Object will be of the same class as "obj".
602 
603 *  Returned Value:
604 *     A pointer to the new Object. NULL if "this" is not a sub-class of
605 *     "obj", or if an error occurs.
606 
607 *  Notes:
608 *     - A NULL pointer will be returned if this function is invoked
609 *     with the global error status set, or if it should fail for any
610 *     reason.
611 *-
612 */
613 
614 /* Local Variables: */
615    AstObject *new;
616    int generation_gap;
617 
618 /* Initialise */
619    new = NULL;
620 
621 /* Check inherited status */
622    if( !astOK ) return new;
623 
624 /* Check pointer have been supplied. */
625    if( this && obj ) {
626 
627 /* See how many steps up the class inheritance ladder it is from "this" to
628    "obj". A positive value is returned if "this" is a sub-class of "obj".
629    A negative value is returned if "obj" is a sub-class of "this". Zero
630    is returned if they are of the same class. AST__COUSIN is returned if
631    they share a common ancestor but are not on the same line of descent. */
632       generation_gap = astClassCompare( astVTAB( this ), astVTAB( obj ) );
633 
634 /* If the two objects are of the same class, just return a copy of
635    "this". */
636       if( generation_gap == 0 ) {
637          new = astCopy( this );
638 
639 /* If "this" is a subclass of "obj", return a deep copy of "this" cast
640    into the class of "obj". */
641       } else if( generation_gap != AST__COUSIN && generation_gap > 0 ) {
642          new = astCastCopy( this, obj );
643 
644       }
645    }
646 
647 /* Return the new pointer. */
648    return new;
649 }
650 
astCastCopy_(AstObject * this,AstObject * obj,int * status)651 AstObject *astCastCopy_( AstObject *this, AstObject *obj, int *status ) {
652 /*
653 *+
654 *  Name:
655 *     astCastCopy
656 
657 *  Purpose:
658 *     Cast an Object into an instance of a sub-class, without type-checking.
659 
660 *  Type:
661 *     Protected function.
662 
663 *  Synopsis:
664 *     #include "object.h"
665 *     AstObject *astCastCopy( AstObject *this, AstObject *obj )
666 
667 *  Class Membership:
668 *     Object method.
669 
670 *  Description:
671 *     This function returns a deep copy of an ancestral component of the
672 *     supplied object. The required class of the ancestral component is
673 *     specified by another object. No checks are performed that "this" is
674 *     a sub-class of "obj".
675 *
676 *     It works by temporarily changing the vtab in "this" to be the same
677 *     as in "obj", and then doing a deep copy, and then re-instating the
678 *     original vtab.
679 
680 *  Parameters:
681 *     this
682 *        Pointer to the Object to be cast.
683 *     obj
684 *        Pointer to an Object that defines the class of the returned Object.
685 *        The returned Object will be of the same class as "obj".
686 
687 *  Returned Value:
688 *     A pointer to the new Object.
689 
690 *  Notes:
691 *     - A NULL pointer will be returned if this function is invoked
692 *     with the global error status set, or if it should fail for any
693 *     reason.
694 *-
695 */
696 
697 /* Local Variables: */
698    AstObject *new;
699    AstObjectVtab *this_vtab;
700    size_t this_size;
701 
702 /* Initialise */
703    new = NULL;
704 
705 /* Check inherited status */
706    if( !astOK ) return new;
707 
708 /* Check pointer have been supplied. */
709    if( this && obj ) {
710 
711 /* Save a pointer to the original virtual function tables for "this". */
712       this_vtab = astVTAB( this );
713 
714 /* Temporarily change the vtab of "this" to that of "obJ". */
715       this->vtab = astVTAB( obj );
716 
717 /* Temporarily change the size of "this" to be the size of "obj". */
718       this_size = this->size;
719       this->size = obj->size;
720 
721 /* Now take a copy of the object (now considered to be an instance of the
722    class specified by "obj"). */
723       new = astCopy( this );
724 
725 /* Re-instate the original Object vtab and size. */
726       this->vtab = this_vtab;
727       this->size = this_size;
728 
729 /* The sub-clas to which "this" originally belonged may have extended the
730    range of values allowed for one or more of the attributes inherited from
731    the "obj" class. This means that the current attribute values stored
732    in the returned object may be inappropriate for the class of "obj". An
733    example is the System attribute defined by the Frame class, and extended
734    by sub-classes of Frame. So we now call astCleanAttribs to ensure that
735    any inappropriate attribute values are cleared in the returned object. */
736       astCleanAttribs( new );
737    }
738 
739 /* Return the new pointer. */
740    return new;
741 }
742 
743 #if defined(THREAD_SAFE)
ChangeThreadVtab(AstObject * this,int * status)744 static void ChangeThreadVtab( AstObject *this, int *status ){
745 /*
746 *  Name:
747 *     ChangeThreadVtab
748 
749 *  Purpose:
750 *     Modify an Object structure so that it refers to a vtab created by
751 *     the currently executing thread.
752 
753 *  Type:
754 *     Private function.
755 
756 *  Synopsis:
757 *     #include "object.h"
758 *     void ChangeThreadVtab( AstObject *this, int *status )
759 
760 *  Class Membership:
761 *     Object member function.
762 
763 *  Description:
764 *     Each Object structure contains a pointer to a virtual function
765 *     table (vtab) that identifies information about the class to
766 *     which the Object belongs (function pointers, Object caches,
767 *     etc). In order to avoid use of mutexes (which can slow down AST
768 *     applications enormously), each thread has its own set of vtab
769 *     structures (one for each AST class) stored in thread-specific
770 *     data. Each time an Object is locked by the currently executing
771 *     thread, this function should be called to change the vtab pointer
772 *     in the Object to refer to the vtab relevant to the currently
773 *     executing thread.
774 
775 *  Parameters:
776 *     this
777 *        Pointer to the Object.
778 *     status
779 *        Pointer to the inherited status variable.
780 
781 */
782 
783 /* Local Variables: */
784    astDECLARE_GLOBALS
785    const char *class;
786    int i;
787 
788 /* Check the global error status. */
789    if ( !astOK ) return;
790 
791 /* Get a pointer to Thread-specific data for the currently executing thread. */
792    astGET_GLOBALS(this);
793 
794 /* Get the class name for the supplied Object. This uses the existing
795    vtab pointer in the Object structure to locate the required GetClass
796    method and the class name. This vtab pointer may be for a vtab created
797    by a different thread to the one currently executing, but this shouldn't
798    matter since we are not modifying the vtab contents. */
799    class = astGetClass( this );
800 
801 /* Check a class name was obtained */
802    if( class ) {
803 
804 /* Loop round the vtab structures created by the currently executing thread. */
805       for( i = 0; i < nvtab; i++ ) {
806 
807 /* If the current vtab is for a class that matches the class of the
808    supplied Object, then store a pointer to the vtab in the Object
809    structure, and exit. */
810          if( !strcmp( class, known_vtabs[ i ]->class ) ) {
811             this->vtab = known_vtabs[ i ];
812             break;
813          }
814       }
815    }
816 }
817 #endif
818 
astCheckLock_(AstObject * this,int * status)819 AstObject *astCheckLock_( AstObject *this, int *status ) {
820 /*
821 *+
822 *  Name:
823 *     astCheckLock
824 
825 *  Purpose:
826 *     Check that supplied Object is locked by the calling thread.
827 
828 *  Type:
829 *     Protected function.
830 
831 *  Synopsis:
832 *     #include "object.h"
833 *     AstObject *astCheckLock( AstObject *this )
834 
835 *  Class Membership:
836 *     Object method.
837 
838 *  Description:
839 *     This function reports an error if the supplied object has not
840 *     previously been locked (using astLock) by the calling thread.
841 
842 *  Parameters:
843 *     this
844 *        Pointer to the Object.
845 
846 *  Returned Value:
847 *     A copy of the supplied pointer ("this") is returned. The Object
848 *     reference count is not changed.
849 
850 *  Notes:
851 *     - This function attempts to execute even if an error has already
852 *     occurred.
853 
854 *-
855 */
856 
857 /* This function does nothing in the non-threads version of libast. */
858 #if defined(THREAD_SAFE)
859 
860 /* Local Variables; */
861    AstObject *fail;
862 
863 /* Check the supplied pointer. */
864    if( this ) {
865 
866 /* First use the private ManageLock function rather than the virtual
867    astManageLock method to check the top level Object is locked for use
868    by the current thread. This saves time and allows a more appropriate
869    error message to be issued. */
870       if( ManageLock( this, AST__CHECKLOCK, 0, NULL, status ) ) {
871          if( astOK ) {
872             astError( AST__LCKERR, "astCheckLock(%s): The supplied %s cannot "
873                       "be used since it is not locked for use by the current "
874                       "thread (programming error).", status, astGetClass( this ),
875                       astGetClass( this ) );
876          }
877 
878 /* If the top level Object is locked, now use the virtual astManageLock
879    method to check any objects contained within the top level Object. */
880       } else if( astManageLock( this, AST__CHECKLOCK, 0, &fail ) ) {
881          if( astOK ) {
882             astError( AST__LCKERR, "astCheckLock(%s): The supplied %s cannot "
883                       "be used since a %s contained within the %s is not "
884                       "locked for use by the current thread (programming "
885                       "error).", status, astGetClass( this ),
886                        astGetClass( this ), astGetClass( fail ),
887                        astGetClass( this ) );
888          }
889       }
890    }
891 #endif
892 
893 /* Return the supploed pointer. */
894    return this;
895 
896 }
897 
astClassCompare_(AstObjectVtab * class1,AstObjectVtab * class2,int * status)898 int astClassCompare_( AstObjectVtab *class1, AstObjectVtab *class2,
899                       int *status ) {
900 /*
901 *+
902 *  Name:
903 *     astClassCompare
904 
905 *  Purpose:
906 *     Determine the relationship between two AST classes.
907 
908 *  Type:
909 *     Protected function.
910 
911 *  Synopsis:
912 *     #include "object.h"
913 *     int astClassCompare( AstObjectVtab *class1, AstObjectVtab *class2 )
914 
915 *  Class Membership:
916 *     Object method.
917 
918 *  Description:
919 *     This function returns the number of steps up the class inheritance
920 *     ladder from the class specified by "class1" to the class specified
921 *     by "class2".
922 
923 *  Parameters:
924 *     class1
925 *        Pointer to a virtual function table describing the first AST class.
926 *     class2
927 *        Pointer to a virtual function table describing the second AST class.
928 
929 *  Returned Value:
930 *     The generation gap between "class1" and "class2". The result will be
931 *     positive if "class1" is a subclass of "class2", negative if "class2"
932 *     is a subclass of "class1", zero if they are of the same class (or
933 *     an error occurs), or AST__COUSIN if they are not on the same line
934 *     of descent.
935 
936 *-
937 */
938 
939 /* Local Variables: */
940    AstClassIdentifier *class1_id;
941    AstClassIdentifier *class2_id;
942    AstClassIdentifier *id;
943    int *class1_check;
944    int *class2_check;
945    int result;
946 
947 /* Initialise */
948    result = 0;
949 
950 /* Check inherited status */
951    if( !astOK ) return result;
952 
953 /* Check pointer have been supplied. */
954    if( class1 && class2 ) {
955 
956 /* Get pointers to the AstClassIdentifier that identifies the top-level
957    class of each vtab. */
958       class1_id = class1->top_id;
959       class2_id = class2->top_id;
960 
961 /* Class membership is specified by the "check" value in each class
962    identifier. Get the check values for both vtabs. */
963       class1_check = class1_id->check;
964       class2_check = class2_id->check;
965 
966 /* Try walking up the class heirarchy of "class1" until the class of
967    "class2" is reached. The top-level AstObject class has a NULL "parent"
968    pointer in its class identifier structure. */
969       id = class1_id;
970       while( id && ( id->check != class2_check ) ) {
971          id = id->parent;
972          result++;
973       }
974 
975 /* If "class1" is not a subclass of "class2", try walking up the class
976    heirarchy of "class2" until the class of "class1" is reached. */
977       if( !id ) {
978          result = 0;
979          id = class2_id;
980          while( id && ( id->check != class1_check ) ) {
981             id = id->parent;
982             result--;
983          }
984 
985 /* If "class2" is not a subclass of "class1", return AST__COUSIN. */
986          if( !id ) result = AST__COUSIN;
987       }
988    }
989 
990 /* Return the generation gap. */
991    return result;
992 }
993 
CleanAttribs(AstObject * this_object,int * status)994 static void CleanAttribs( AstObject *this_object, int *status ) {
995 /*
996 *+
997 *  Name:
998 *     astCleanAttribs
999 
1000 *  Purpose:
1001 *     Clear any invalid set attribute values.
1002 
1003 *  Type:
1004 *     Protected virtual function.
1005 
1006 *  Synopsis:
1007 *     #include "object.h"
1008 *     void astCleanAttribs( AstObject *this, int *status )
1009 
1010 *  Class Membership:
1011 *     Object method.
1012 
1013 *  Description:
1014 *     This function clears any attributes that are currently set to
1015 *     invalid values in the supplied object. This can happen for instance
1016 *     when an object is cast into an instance of a parent class using
1017 *     astCast, since sub-classes can extend the range of valid values
1018 *     an attribute can take.
1019 
1020 *  Parameters:
1021 *     this
1022 *        Pointer to the Object to be cleaned.
1023 *-
1024 */
1025 
1026 /* The base Object class has no attributes that need cleaning. */
1027 
1028 }
1029 
Clear(AstObject * this,const char * attrib,int * status)1030 static void Clear( AstObject *this, const char *attrib, int *status ) {
1031 /*
1032 *++
1033 *  Name:
1034 c     astClear
1035 f     AST_CLEAR
1036 
1037 *  Purpose:
1038 *     Clear attribute values for an Object.
1039 
1040 *  Type:
1041 *     Public virtual function.
1042 
1043 *  Synopsis:
1044 c     #include "object.h"
1045 c     void astClear( AstObject *this, const char *attrib )
1046 f     CALL AST_CLEAR( THIS, ATTRIB, STATUS )
1047 
1048 *  Class Membership:
1049 *     Object method.
1050 
1051 *  Description:
1052 c     This function clears the values of a specified set of attributes
1053 f     This routine clears the values of a specified set of attributes
1054 *     for an Object. Clearing an attribute cancels any value that has
1055 *     previously been explicitly set for it, so that the standard
1056 *     default attribute value will subsequently be used instead. This
1057 c     also causes the astTest function to return the value zero for
1058 f     also causes the AST_TEST function to return the value .FALSE. for
1059 *     the attribute, indicating that no value has been set.
1060 
1061 *  Parameters:
1062 c     this
1063 f     THIS = INTEGER (Given)
1064 *        Pointer to the Object.
1065 c     attrib
1066 f     ATTRIB = CHARACTER * ( * ) (Given)
1067 c        Pointer to a null-terminated character string containing a
1068 c        comma-separated list of the names of the attributes to be cleared.
1069 f        A character string containing a comma-separated list of the
1070 f        names of the attributes to be cleared.
1071 f     STATUS = INTEGER (Given and Returned)
1072 f        The global status.
1073 
1074 *  Applicability:
1075 *     Object
1076 c        This function applies to all Objects.
1077 f        This routine applies to all Objects.
1078 
1079 *  Notes:
1080 *     - Attribute names are not case sensitive and may be surrounded
1081 *     by white space.
1082 *     - It does no harm to clear an attribute whose value has not been
1083 *     set.
1084 *     - An error will result if an attempt is made to clear the value
1085 *     of a read-only attribute.
1086 *--
1087 */
1088 
1089 /* Local Variables: */
1090    char *buff;                   /* Pointer to character buffer */
1091    char *name;                   /* Pointer to individual attribute name */
1092    char *name_end;               /* Pointer to null at end of name */
1093    int i;                        /* Loop counter for characters */
1094    int j;                        /* Non-blank character count */
1095    int len;                      /* Length of attrib string */
1096 
1097 /* Check the global error status. */
1098    if ( !astOK ) return;
1099 
1100 /* Obtain the length of the attrib string. */
1101    len = (int) strlen( attrib );
1102    if ( len != 0 ) {
1103 
1104 /* Allocate memory and store a copy of the string. */
1105       buff = astStore( NULL, attrib, (size_t) ( len + 1 ) );
1106       if ( astOK ) {
1107 
1108 /* Loop to process each element in the comma-separated list. */
1109          name = buff;
1110          while ( name ) {
1111 
1112 /* Change the comma at the end of each element to a null to terminate
1113    the name. */
1114             if ( ( name_end = strchr( name, ',' ) ) ) *name_end = '\0';
1115 
1116 /* Remove white space and upper case characters from the attribute
1117    name. */
1118             for ( i = j = 0; name[ i ]; i++ ) {
1119                if ( !isspace( name[ i ] ) ) name[ j++ ] = tolower( name[ i ] );
1120             }
1121 
1122 /* Terminate the attribute name and pass it to astClearAttrib to clear
1123    the attribute (unless it is all blank, in which case we ignore
1124    it). */
1125             name[ j ] = '\0';
1126             if ( j ) astClearAttrib( this, name );
1127 
1128 /* Check for errors and abort if any clear operation fails. Otherwise,
1129    process the next attribute. */
1130             if ( !astOK ) break;
1131             name = name_end ? name_end + 1 : NULL;
1132          }
1133       }
1134 
1135 /* Free the memory allocated for the string buffer. */
1136       buff = astFree( buff );
1137    }
1138 }
1139 
ClearAttrib(AstObject * this,const char * attrib,int * status)1140 static void ClearAttrib( AstObject *this, const char *attrib, int *status ) {
1141 /*
1142 *+
1143 *  Name:
1144 *     astClearAttrib
1145 
1146 *  Purpose:
1147 *     Clear an attribute value for an Object.
1148 
1149 *  Type:
1150 *     Protected virtual function.
1151 
1152 *  Synopsis:
1153 *     #include "object.h"
1154 *     void astClearAttrib( AstObject *this, const char *attrib )
1155 
1156 *  Class Membership:
1157 *     Object method.
1158 
1159 *  Description:
1160 *     This function clears the value of a specified attribute for an
1161 *     Object, so that the default value will subsequently be used.
1162 
1163 *  Parameters:
1164 *     this
1165 *        Pointer to the Object.
1166 *     attrib
1167 *        Pointer to a null-terminated string specifying the attribute
1168 *        name.  This should be in lower case with no surrounding white
1169 *        space.
1170 
1171 *  Notes:
1172 *     - The Object class does not have any writable attributes, so
1173 *     this function merely reports an error. It is intended to be
1174 *     extended by other class definitions.
1175 *-
1176 */
1177 
1178 /* Check the global error status. */
1179    if ( !astOK ) return;
1180 
1181 /* Check the attribute name and clear the appropriate attribute. */
1182 
1183 /* ID. */
1184 /* --- */
1185    if ( !strcmp( attrib, "id" ) ) {
1186       astClearID( this );
1187 
1188 /* Ident. */
1189 /* ------ */
1190    } else if ( !strcmp( attrib, "ident" ) ) {
1191       astClearIdent( this );
1192 
1193 /* UseDefs. */
1194 /* -------- */
1195    } else if ( !strcmp( attrib, "usedefs" ) ) {
1196       astClearUseDefs( this );
1197 
1198 /* Read-only attributes. */
1199 /* --------------------- */
1200 /* Test if the attribute string matches any of the read-only
1201    attributes of this class. If it does, then report an error. */
1202    } else if ( !strcmp( attrib, "class" ) ||
1203                !strcmp( attrib, "nobject" ) ||
1204                !strcmp( attrib, "objsize" ) ||
1205                !strcmp( attrib, "refcount" ) ) {
1206       astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
1207                 "value for a %s.", status, attrib, astGetClass( this ) );
1208       astError( AST__NOWRT, "This is a read-only attribute." , status);
1209 
1210 /* Since no writable attributes are defined for the Object class, any
1211    attempt to clear a value for anything else is also an error. */
1212    } else {
1213       astError( AST__BADAT, "astClear: The attribute name \"%s\" is invalid "
1214                "for a %s.", status, attrib, astGetClass( this ) );
1215    }
1216 }
1217 
astClone_(AstObject * this,int * status)1218 AstObject *astClone_( AstObject *this, int *status ) {
1219 /*
1220 *++
1221 *  Name:
1222 c     astClone
1223 f     AST_CLONE
1224 
1225 *  Purpose:
1226 *     Clone (duplicate) an Object pointer.
1227 
1228 *  Type:
1229 *     Public function.
1230 
1231 *  Synopsis:
1232 c     #include "object.h"
1233 c     AstObject *astClone( AstObject *this )
1234 f     RESULT = AST_CLONE( THIS, STATUS )
1235 
1236 *  Class Membership:
1237 *     Object method.
1238 
1239 *  Description:
1240 *     This function returns a duplicate pointer to an existing
1241 *     Object. It also increments the Object's RefCount attribute to
1242 *     keep track of how many pointers have been issued.
1243 *
1244 *     Note that this function is NOT equivalent to an assignment
1245 *     statement, as in general the two pointers will not have the same
1246 *     value.
1247 
1248 *  Parameters:
1249 c     this
1250 f     THIS = INTEGER (Given)
1251 *        Original pointer to the Object.
1252 f     STATUS = INTEGER (Given and Returned)
1253 f        The global status.
1254 
1255 *  Returned Value:
1256 c     astClone()
1257 f     AST_CLONE = INTEGER
1258 *        A duplicate pointer to the same Object.
1259 
1260 *  Applicability:
1261 *     Object
1262 *        This function applies to all Objects.
1263 
1264 *  Notes:
1265 *     - A null Object pointer (AST__NULL) will be returned if this
1266 c     function is invoked with the AST error status set, or if it
1267 f     function is invoked with STATUS set to an error value, or if it
1268 *     should fail for any reason.
1269 *--
1270 */
1271 
1272 /* Check the global error status. */
1273    if ( !astOK ) return NULL;
1274 
1275 /* Get a lock on the object's secondary mutex. This mutex guards access
1276    to the "ref_count" and "locker" components of the AstObject structure. */
1277    LOCK_SMUTEX(this);
1278 
1279 #ifdef MEM_DEBUG
1280    {   int rc;
1281        char buf[100];
1282        rc = this->ref_count;
1283        sprintf(buf,"cloned (refcnt: %d -> %d)", rc, rc+1 );
1284        astMemoryUse( this, buf );
1285    }
1286 #endif
1287 
1288 /* Increment the Object's reference count. */
1289    this->ref_count++;
1290 
1291 /* Unlock the object's secondary mutex. */
1292    UNLOCK_SMUTEX(this);
1293 
1294 /* Return a new pointer to the Object. */
1295    return this;
1296 }
1297 
astCopy_(const AstObject * this,int * status)1298 AstObject *astCopy_( const AstObject *this, int *status ) {
1299 /*
1300 *++
1301 *  Name:
1302 c     astCopy
1303 f     AST_COPY
1304 
1305 *  Purpose:
1306 *     Copy an Object.
1307 
1308 *  Type:
1309 *     Public function.
1310 
1311 *  Synopsis:
1312 c     #include "object.h"
1313 c     AstObject *astCopy( const AstObject *this )
1314 f     RESULT = AST_COPY( THIS, STATUS )
1315 
1316 *  Class Membership:
1317 *     Object method.
1318 
1319 *  Description:
1320 *     This function creates a copy of an Object and returns a pointer
1321 *     to the resulting new Object. It makes a "deep" copy, which
1322 *     contains no references to any other Object (i.e. if the original
1323 *     Object contains references to other Objects, then the actual
1324 *     data are copied, not simply the references). This means that
1325 *     modifications may safely be made to the copy without indirectly
1326 *     affecting any other Object.
1327 
1328 *  Parameters:
1329 c     this
1330 f     THIS = INTEGER (Given)
1331 *        Pointer to the Object to be copied.
1332 f     STATUS = INTEGER (Given and Returned)
1333 f        The global status.
1334 
1335 *  Returned Value:
1336 c     astCopy()
1337 f     AST_COPY = INTEGER
1338 *        Pointer to the new Object.
1339 
1340 *  Applicability:
1341 *     Object
1342 *        This function applies to all Objects.
1343 
1344 *  Notes:
1345 *     - A null Object pointer (AST__NULL) will be returned if this
1346 c     function is invoked with the AST error status set, or if it
1347 f     function is invoked with STATUS set to an error value, or if it
1348 *     should fail for any reason.
1349 *--
1350 */
1351 
1352 /* Local Variables: */
1353    AstObject *new;               /* Pointer to new object */
1354    AstObjectVtab *vtab;          /* Pointer to object vtab */
1355    int i;                        /* Loop counter for copy constructors */
1356 
1357 /* Initiallise. */
1358    new = NULL;
1359 
1360 /* Check the global error status. */
1361    if ( !astOK ) return new;
1362 
1363 /* Re-use cached memory, or allocate new memory using the size of the input
1364    object, to store the output Object. */
1365 
1366    vtab = this->vtab;
1367    if( object_caching ){
1368 
1369       if( vtab->nfree > 0 ) {
1370          new = vtab->free_list[ --(vtab->nfree) ];
1371          vtab->free_list[ vtab->nfree ] = NULL;
1372       } else {
1373          new = astMalloc( this->size );
1374       }
1375 
1376    } else {
1377       new = astMalloc( this->size );
1378    }
1379 
1380    if ( astOK ) {
1381 
1382 /* Perform an initial byte-by-byte copy of the entire object
1383    structure. */
1384       (void) memcpy( (void *) new, (const void *) this, this->size );
1385 
1386 /* Initialise any components of the new Object structure that need to
1387    differ from the input. */
1388       new->check = Magic( new, new->size, status );
1389       new->dynamic = 1;
1390       new->ref_count = 1;
1391       new->id = NULL;   /* ID attribute is not copied (but Ident is copied) */
1392       new->proxy = NULL;
1393 
1394 /* Copy the persistent identifier string. */
1395       if( this->ident ) {
1396          new->ident = astStore( NULL, this->ident, strlen( this->ident ) + 1 );
1397       }
1398 
1399 /* Create a new mutex for the new Object, and lock it for use by the
1400    current thread. */
1401 #ifdef THREAD_SAFE
1402       if( pthread_mutex_init( &(new->mutex1), NULL ) != 0 && astOK ) {
1403          astError( AST__INTER, "astInitObject(%s): Failed to "
1404                    "initialise POSIX mutex1 for the new Object.", status,
1405                    vtab->class );
1406       }
1407       if( pthread_mutex_init( &(new->mutex2), NULL ) != 0 && astOK ) {
1408          astError( AST__INTER, "astInitObject(%s): Failed to "
1409                    "initialise POSIX mutex2 for the new Object.", status,
1410                    vtab->class );
1411       }
1412       new->locker = -1;
1413       new->globals = NULL;
1414       (void) ManageLock( new, AST__LOCK, 0, NULL, status );
1415 #endif
1416 
1417 /* Loop to execute any copy constructors declared by derived classes. */
1418       for ( i = 0; i < vtab->ncopy; i++ ) {
1419 
1420 /* Invoke each copy constructor in turn. */
1421          (*vtab->copy[ i ])( this, new, status );
1422 
1423 /* If any copy constructor fails, work backwards through the
1424    corresponding destructor functions, invoking each in turn to undo
1425    the copy operations that have been completed so far. */
1426          if ( !astOK ) {
1427             for ( ; i >= 0; i-- ) {
1428                (*vtab->delete[ i ])( new, status );
1429             }
1430 
1431 /* Zero the entire new Object structure (to prevent accidental re-use
1432    of any of its values after deletion). */
1433             (void) memset( new, 0, new->size );
1434 
1435 /* Free the Object's memory and ensure that a NULL pointer will be
1436    returned. */
1437             new = astFree( new );
1438 
1439 /* Quit trying to copy the Object. */
1440             break;
1441          }
1442       }
1443    }
1444 
1445 /* If OK, increment the count of active objects. */
1446    if ( astOK ) vtab->nobject++;
1447 
1448 /* Return a pointer to the new Object. */
1449    return new;
1450 }
1451 
astDelete_(AstObject * this,int * status)1452 AstObject *astDelete_( AstObject *this, int *status ) {
1453 /*
1454 *++
1455 *  Name:
1456 c     astDelete
1457 f     AST_DELETE
1458 
1459 *  Purpose:
1460 *     Delete an Object.
1461 
1462 *  Type:
1463 *     Public function.
1464 
1465 *  Synopsis:
1466 c     #include "object.h"
1467 c     AstObject *astDelete( AstObject *this )
1468 f     CALL AST_DELETE( THIS, STATUS )
1469 
1470 *  Class Membership:
1471 *     Object method.
1472 
1473 *  Description:
1474 c     This function deletes an Object, freeing all resources
1475 f     This routine deletes an Object, freeing all resources
1476 *     associated with it and rendering any remaining pointers to the
1477 *     Object invalid.
1478 *
1479 *     Note that deletion is unconditional, regardless of whether other
1480 *     pointers to the Object are still in use (possibly within other
1481 *     Objects). A safer approach is to defer deletion, until all
1482 c     references to an Object have expired, by using astBegin/astEnd
1483 c     (together with astClone and astAnnul if necessary).
1484 f     references to an Object have expired, by using AST_BEGIN/AST_END
1485 f     (together with AST_CLONE and AST_ANNUL if necessary).
1486 
1487 *  Parameters:
1488 c     this
1489 c        Pointer to the Object to be deleted.
1490 f     THIS = INTEGER (Given and Returned)
1491 f        Pointer to the Object to be deleted. A null pointer value
1492 f        (AST__NULL) is always returned.
1493 f     STATUS = INTEGER (Given and Returned)
1494 f        The global status.
1495 
1496 c  Returned Value:
1497 c     astDelete()
1498 c        A null Object pointer (AST__NULL) is always returned.
1499 c
1500 *  Applicability:
1501 *     Object
1502 c        This function applies to all Objects.
1503 f        This routine applies to all Objects.
1504 
1505 *  Notes:
1506 c     - This function attempts to execute even if the AST error status
1507 c     is set
1508 f     - This routine attempts to execute even if STATUS is set to an error
1509 f     value
1510 *     on entry, although no further error report will be
1511 *     made if it subsequently fails under these circumstances.
1512 *--
1513 */
1514 
1515 /* Local Variables: */
1516    AstObjectVtab *vtab;          /* Pointer to virtual function table */
1517    int dynamic;                  /* Was memory allocated dynamically? */
1518    int i;                        /* Loop counter for destructors */
1519    int ifree;                    /* Index of next slot on free list */
1520    int status_value;             /* AST error status value */
1521    size_t size;                  /* Object size */
1522 
1523 /* Check the pointer to ensure it identifies a valid Object (this
1524    generates an error if it doesn't). */
1525    if ( !astIsAObject( this ) ) return NULL;
1526 
1527 /* Loop through all the destructors associated with the Object by derived
1528    classes (working up the class hierarchy). */
1529    for ( i = this->vtab->ndelete - 1; i >= 0; i-- ) {
1530 
1531 /* Invoke each destructor in turn. Attempt to continue even if destructors
1532    fail. */
1533       ( *this->vtab->delete[ i ] )( this, status );
1534    }
1535 
1536 /* Free the ID strings. */
1537    this->id = astFree( this->id );
1538    this->ident = astFree( this->ident );
1539 
1540 /* Attempt to unlock the Object and destroy its mutexes. */
1541 #if defined(THREAD_SAFE)
1542    (void) ManageLock( this, AST__UNLOCK, 0, NULL, status );
1543    pthread_mutex_destroy( &(this->mutex1) );
1544    pthread_mutex_destroy( &(this->mutex2) );
1545 #endif
1546 
1547 /* Save the virtual function table address and note if the Object's
1548    memory was allocated dynamically. Also note its size. */
1549    vtab = this->vtab;
1550    dynamic = this->dynamic;
1551    size = this->size;
1552 
1553 /* Zero the entire Object structure (to prevent accidental re-use of
1554    any of its values after deletion). */
1555    (void) memset( this, 0, size );
1556 
1557 /* If necessary, free the Object's memory. If object caching is switched
1558    on, the memory is not in fact freed; it is merely placed onto the end
1559    of the list of free memory blocks included in the virtual function table
1560    of the AST class concerned. astGrow returns immediately if an error
1561    has already occurred, so we need to reset the error status explicitly
1562    before calling astGrow. */
1563    if ( dynamic ) {
1564       if( object_caching ) {
1565          ifree = (vtab->nfree)++;
1566 
1567          status_value = astStatus;
1568          astClearStatus;
1569          vtab->free_list = astGrow( vtab->free_list, vtab->nfree,
1570                                     sizeof(AstObject *) );
1571          astSetStatus( status_value );
1572 
1573          if( vtab->free_list ) vtab->free_list[ ifree ] = this;
1574       } else {
1575          (void) astFree( this );
1576       }
1577    }
1578 
1579 /* Decrement the count of active Objects. */
1580    vtab->nobject--;
1581 
1582 /* Always return NULL. */
1583    return NULL;
1584 }
1585 
Dump(AstObject * this,AstChannel * channel,int * status)1586 static void Dump( AstObject *this, AstChannel *channel, int *status ) {
1587 /*
1588 *+
1589 *  Name:
1590 *     astDump
1591 
1592 *  Purpose:
1593 *     Write an Object to a Channel.
1594 
1595 *  Type:
1596 *     Protected function.
1597 
1598 *  Synopsis:
1599 *     #include "object.h"
1600 *     void astDump( AstObject *this, AstChannel *channel )
1601 
1602 *  Class Membership:
1603 *     Object method.
1604 
1605 *  Description:
1606 *     This function writes an Object to a Channel, appending it to any
1607 *     previous Objects written to that Channel.
1608 
1609 *  Parameters:
1610 *     this
1611 *        Pointer to the Object to be written.
1612 *     channel
1613 *        Pointer to the output Channel.
1614 *-
1615 */
1616 
1617 /* Local Variables: */
1618    AstObjectVtab *vtab;          /* Pointer to virtual function table */
1619    const char *sval;             /* Pointer to string value */
1620    int helpful;                  /* Helpful to show value even if not set? */
1621    int idump;                    /* Loop counter for dump functions */
1622    int ival;                     /* Attribute value */
1623    int set;                      /* Attribute value set? */
1624 
1625 /* Check the global error status. */
1626    if ( !astOK ) return;
1627 
1628 /* Write an initial "Begin" item, giving the class name of the Object
1629    being written. Also supply a pointer to the comment associated with
1630    the most recently-declared dump function in the Object's virtual
1631    function table. This should describe the class to which the Object
1632    belongs (assuming it has correctly declared its dump function). */
1633    astWriteBegin( channel, astGetClass( this ),
1634                   this->vtab->dump_comment[ this->vtab->ndump - 1 ] );
1635 
1636 /* Write out instance variable information for the base Object
1637    class. Accompany these with appropriate comment strings, possibly
1638    depending on the values being written.*/
1639 
1640 /* In the case of attributes, we first use the appropriate (private)
1641    Test...  member function to see if they are set. If so, we then use
1642    the (private) Get... function to obtain the value to be written
1643    out.
1644 
1645    For attributes which are not set, we use the astGet... method to
1646    obtain the value instead. This will supply a default value
1647    (possibly provided by a derived class which over-rides this method)
1648    which is more useful to a human reader as it corresponds to the
1649    actual default attribute value.  Since "set" will be zero, these
1650    values are for information only and will not be read back. */
1651 
1652 /* ID. */
1653 /* --- */
1654    set = TestID( this, status );
1655    sval = set ? GetID( this, status ) : astGetID( this );
1656 
1657 /* Don't show an un-set ID value if it is blank. */
1658    helpful = ( sval && *sval );
1659    astWriteString( channel, "ID", set, helpful, sval,
1660                    "Object identification string" );
1661 
1662 /* Ident. */
1663 /* --- */
1664    set = TestIdent( this, status );
1665    sval = set ? GetIdent( this, status ) : astGetIdent( this );
1666 
1667 /* Don't show an un-set Ident value if it is blank. */
1668    helpful = ( sval && *sval );
1669    astWriteString( channel, "Ident", set, helpful, sval,
1670                    "Permanent Object identification string" );
1671 
1672 /* UseDefs */
1673 /* ------- */
1674    set = TestUseDefs( this, status );
1675    ival = set ? GetUseDefs( this, status ) : astGetUseDefs( this );
1676    astWriteInt( channel, "UseDfs", set, 0, ival,
1677                 ival ? "Default attribute values can be used" :
1678                        "Default values cannot be used" );
1679 
1680 /* RefCnt. */
1681 /* ------- */
1682    LOCK_SMUTEX(this);
1683    ival = this->ref_count;
1684    UNLOCK_SMUTEX(this);
1685 
1686    astWriteInt( channel, "RefCnt", 0, 0, ival,
1687                 "Count of active Object pointers" );
1688 
1689 
1690 /* Nobj. */
1691 /* ----- */
1692    vtab = this->vtab;
1693    astWriteInt( channel, "Nobj", 0, 0, vtab->nobject,
1694                 "Count of active Objects in same class" );
1695 
1696 /* Terminate the information above with an "IsA" item for the base
1697    Object class. */
1698    astWriteIsA( channel, "Object", "AST Object" );
1699 
1700 /* Now loop to perform the same operation for each additional class
1701    from which the Object inherits (the Object class itself does not
1702    declare a dump function). Invoke the dump function for each class
1703    in turn, working down the class hierarchy, to write out instance
1704    variable information for that class. */
1705    for ( idump = 0; idump < this->vtab->ndump; idump++ ) {
1706       ( *this->vtab->dump[ idump ] )( this, channel, status );
1707 
1708 /* Terminate the output from all except the final dump function with
1709    an appropriate "IsA" item describing the class whose data have just
1710    been written. */
1711       if ( idump != ( this->vtab->ndump - 1 ) ) {
1712          astWriteIsA( channel, this->vtab->dump_class[ idump ],
1713                       this->vtab->dump_comment[ idump ] );
1714       }
1715 
1716 /* Quit looping if an error occurs. */
1717       if ( !astOK ) break;
1718    }
1719 
1720 /* Terminate the output from the final dump function with an "End"
1721    item to match the initial "Begin" item. */
1722    astWriteEnd( channel, astGetClass( this ) );
1723 }
1724 
EmptyObjectCache(int * status)1725 static void EmptyObjectCache( int *status ){
1726 /*
1727 *  Name:
1728 *     EmptyObjectCache
1729 
1730 *  Purpose:
1731 *     Free all memory blocks currently on the free list of any class.
1732 
1733 *  Type:
1734 *     Private function.
1735 
1736 *  Synopsis:
1737 *     #include "object.h"
1738 *     EmptyObjectCache( int *status )
1739 
1740 *  Class Membership:
1741 *     Object member function.
1742 
1743 *  Description:
1744 *     This function empties the cache of Object memory by freeing all
1745 *     memory blocks on the free_list of all classes.
1746 
1747 *  Parameters:
1748 *     status
1749 *        Pointer to the inherited status variable.
1750 
1751 *  Notes:
1752 *     -  This function attempts to execute even if an error has occurred.
1753 */
1754 
1755 /* Local Variables: */
1756    astDECLARE_GLOBALS    /* Thread-specific global data */
1757    int iblock;           /* Index of next entry in free list */
1758    int itab;             /* Index of next virtual function table */
1759    AstObjectVtab *vtab;  /* Pointer to next virtual function table */
1760 
1761 /* Get a pointer to Thread-specific global data. */
1762    astGET_GLOBALS(NULL);
1763 
1764 /* Loop round all the virtual function tables which are known about. */
1765    for( itab = 0; itab < nvtab; itab++ ) {
1766       vtab = known_vtabs[ itab ];
1767 
1768 /* Free all memory blocks stored on the free list for this class. */
1769       for( iblock = 0; iblock < vtab->nfree; iblock++ ) {
1770          (vtab->free_list)[ iblock ] = astFree( (vtab->free_list)[ iblock ] );
1771       }
1772 
1773 /* Free the memory used to hold the free list, and indicate it has zero
1774    length. */
1775       vtab->free_list = astFree( vtab->free_list );
1776       vtab->nfree = 0;
1777    }
1778 }
1779 
EnvSet(AstObject * this,int * status)1780 static void EnvSet( AstObject *this, int *status ) {
1781 /*
1782 *+
1783 *  Name:
1784 *     astEnvSet
1785 
1786 *  Purpose:
1787 *     Set default values for an Object's attributes.
1788 
1789 *  Type:
1790 *     Protected virtual function.
1791 
1792 *  Synopsis:
1793 *     #include "object.h"
1794 *     void astEnvSet( AstObject *this )
1795 
1796 *  Class Membership:
1797 *     Object method.
1798 
1799 *  Description:
1800 *     This function assigns a set of attribute values for an Object,
1801 *     the attributes and their values being specified by means of an
1802 *     environment variable of the form "<CLASSNAME>_OPTIONS" that has
1803 *     a value of the form:
1804 *
1805 *        "attribute1 = value1, attribute2 = value2, ... "
1806 *
1807 *     Here, "attribute" specifies an attribute name and the value to
1808 *     the right of each "=" sign should be a suitable textual
1809 *     representation of the value to be assigned to that
1810 *     attribute. This will be interpreted according to the attribute's
1811 *     data type.
1812 
1813 *  Parameters:
1814 *     this
1815 *        Pointer to the Object.
1816 
1817 *  Notes:
1818 *     - See astVSet for details of how the setting strings are
1819 *     interpreted.
1820 *-
1821 */
1822 
1823 /* Local Variables: */
1824    char varname[ 100 ];
1825    const char *attrs = NULL;
1826    const char *class = NULL;
1827 
1828 /* Check the global error status. */
1829    if ( !astOK ) return;
1830 
1831 /* Get the string holding default attribute values for the class of the
1832    supplied object. This string is held in the class virtual function
1833    table. */
1834    attrs = this->vtab->defaults;
1835 
1836 /* If this is the first time the defaults have been requested, get the
1837    list of defaults from the environment variable "<CLASSNAME>_OPTIONS"
1838    and store in the virtual function table. */
1839    if( !attrs ) {
1840 
1841 /* Get the class name. */
1842       class = astGetClass( this );
1843 
1844 /* Form the upper-case name of the environment variable. */
1845       if( class ) {
1846          sprintf( varname, "%s_OPTIONS", class );
1847          astChrCase( NULL, varname, 1, sizeof( varname ) );
1848 
1849 /* Get the value of the environment variable. */
1850          attrs = getenv( varname );
1851 
1852 /* If no defaults were specified store the string "None". */
1853          if( ! attrs ) attrs = "None";
1854 
1855 /* Store a copy in the virtual function table. */
1856          astBeginPM;
1857          this->vtab->defaults = astStore( NULL, attrs, strlen( attrs ) + 1 );
1858          astEndPM;
1859       }
1860    }
1861 
1862 /* If any defaults were specified, set the corresponding attributes. */
1863    if( attrs && strcmp( attrs, "None" ) ) astSet( this, attrs, status );
1864 
1865 }
1866 
Equal(AstObject * this,AstObject * that,int * status)1867 static int Equal( AstObject *this, AstObject *that, int *status ){
1868 /*
1869 *+
1870 *  Name:
1871 *     astEqual
1872 
1873 *  Purpose:
1874 *     Check equality of two AST Objects.
1875 
1876 *  Type:
1877 *     Public (but undocumented) function.
1878 
1879 *  Synopsis:
1880 *     #include "object.h"
1881 *     int astEqual( AstObject *this, AstObject *this )
1882 
1883 *  Class Membership:
1884 *     Object virtual function.
1885 
1886 *  Description:
1887 *     This function returns non-zero if the two pointers identify
1888 *     equivalent objects.
1889 
1890 *  Parameters:
1891 *     this
1892 *        Pointer to the first Object.
1893 *     that
1894 *        Pointer to the second Object.
1895 
1896 *  Returned Value:
1897 *     Non-zero if the objects are equivalent.
1898 
1899 *  Notes:
1900 *    - This function is available in the public interface even though it is
1901 *    documented as protected. This is because it is difficult to document
1902 *    precisely which aspects of two Objects must be equal in order for this
1903 *    function to return a non-zero value. Each class of Object supplies
1904 *    its own Equal method that tests which-ever attributes the class
1905 *    considers to be significiant.
1906 *    - The implementation of this function provided by the base Object
1907 *    class simply compares the class names and the structure size.
1908 *    Sub-classes should override this method to provide more appropriate tests.
1909 *    - Zero is returned if an error has already occurred, or if
1910 *    this function should fail for any reason.
1911 
1912 *-
1913 */
1914 
1915 /* Local Variables: */
1916    int result;
1917 
1918 /* Check inherited status */
1919    if( !astOK ) return 0;
1920 
1921 /* Objects are equivalent if they are the same object. */
1922    if( this == that ) {
1923       result = 1;
1924 
1925 /* Otherwise, check the structure size and class names */
1926    } else {
1927       result = ( this->size == that->size &&
1928                  !strcmp( astGetClass( this ), astGetClass( that ) ) );
1929    }
1930 
1931    return result;
1932 }
1933 
Get(AstObject * this,const char * attrib,int * status)1934 static const char *Get( AstObject *this, const char *attrib, int *status ) {
1935 /*
1936 *  Name:
1937 *     Get
1938 
1939 *  Purpose:
1940 *     Get the value of a specified attribute for an Object.
1941 
1942 *  Type:
1943 *     Private function.
1944 
1945 *  Synopsis:
1946 *     #include "object.h"
1947 *     const char *Get( AstObject *this, const char *attrib, int *status )
1948 
1949 *  Class Membership:
1950 *     Object member function.
1951 
1952 *  Description:
1953 *     This function returns a pointer to the value of a specified
1954 *     attribute for an Object, formatted as a character string. It is
1955 *     mainly a wrap-up used internally for invoking the astGetAttrib
1956 *     method. It converts the attribute name to lower case and removes
1957 *     white space before invoking the method. This saves derived
1958 *     classes that over-ride the astGetAttrib method from having to do
1959 *     this themselves.
1960 
1961 *  Parameters:
1962 *     this
1963 *        Pointer to the Object.
1964 *     attrib
1965 *        Pointer to a null-terminated string containing the name of
1966 *        the attribute whose value is required. This may contain mixed
1967 *        case and white space, but should not be composed entirely of
1968 *        white space.
1969 *     status
1970 *        Pointer to the inherited status variable.
1971 
1972 *  Returned Value:
1973 *     - Pointer to a null-terminated string containing the attribute
1974 *     value.
1975 
1976 *  Notes:
1977 *     - The returned string pointer may point at memory allocated
1978 *     within the Object, or at static memory. The contents of the
1979 *     string may be over-written or the pointer may become invalid
1980 *     following a further invocation of the same function or any
1981 *     modification of the Object. A copy of the string should
1982 *     therefore be made if necessary.
1983 *     - A NULL pointer will be returned if this function is invoked
1984 *     with the global error status set, or if it should fail for any
1985 *     reason.
1986 */
1987 
1988 /* Local Variables: */
1989    char *buff;                   /* Pointer to local string buffer */
1990    const char *result;           /* Pointer value to return */
1991    int i;                        /* Loop counter for characters */
1992    int j;                        /* Non-blank character count */
1993 
1994 /* Initialise. */
1995    result = NULL;
1996 
1997 /* Check the global error status. */
1998    if ( !astOK ) return result;
1999 
2000 /* Allocate a local buffer long enough to hold the attribute name
2001    string. */
2002    buff = astMalloc( strlen( attrib ) + (size_t) 1 );
2003    if ( astOK ) {
2004 
2005 /* Copy the attribute name characters into the buffer, omitting all
2006    white space and converting to lower case. */
2007       for ( i = j = 0; attrib[ i ]; i++ ) {
2008          if ( !isspace( attrib[ i ] ) ) buff[ j++ ] = tolower( attrib[ i ] );
2009       }
2010 
2011 /* Terminate the copied string. */
2012       buff[ j ] = '\0';
2013 
2014 /* If no characters were copied, the attribute name was blank, so
2015    report an error. */
2016       if ( !j ) {
2017          if( astOK ) astError( AST__BADAT, "astGet(%s): A blank attribute "
2018                                "name was given.", status, astGetClass( this ) );
2019 
2020 /* Of OK, invoke astGetAttrib to obtain a pointer to the attribute
2021    value formatted as a character string. */
2022       } else {
2023          result = astGetAttrib( this, buff );
2024 
2025 /* If required, strip out graphical escape sequences. */
2026          if( !astEscapes( -1 ) ) result = astStripEscapes( result );
2027       }
2028    }
2029 
2030 /* Free the local string buffer. */
2031    buff = astFree( buff );
2032 
2033 /* If an error occurred, clear the result value. */
2034    if ( !astOK ) result = NULL;
2035 
2036 /* Return the result. */
2037    return result;
2038 }
2039 
GetAttrib(AstObject * this,const char * attrib,int * status)2040 static const char *GetAttrib( AstObject *this, const char *attrib, int *status ) {
2041 /*
2042 *+
2043 *  Name:
2044 *     astGetAttrib
2045 
2046 *  Purpose:
2047 *     Get the value of a specified attribute for an Object.
2048 
2049 *  Type:
2050 *     Protected virtual function.
2051 
2052 *  Synopsis:
2053 *     #include "object.h"
2054 *     const char *astGetAttrib( AstObject *this, const char *attrib )
2055 
2056 *  Class Membership:
2057 *     Object method.
2058 
2059 *  Description:
2060 *     This function returns a pointer to the value of a specified
2061 *     attribute for an Object, formatted as a character string.
2062 
2063 *  Parameters:
2064 *     this
2065 *        Pointer to the Object.
2066 *     attrib
2067 *        Pointer to a null-terminated string containing the name of
2068 *        the attribute whose value is required. This name should be in
2069 *        lower case, with all white space removed.
2070 
2071 *  Returned Value:
2072 *     - Pointer to a null-terminated string containing the attribute
2073 *     value.
2074 
2075 *  Notes:
2076 *     - The returned string pointer may point at memory allocated
2077 *     within the Object, or at static memory. The contents of the
2078 *     string may be over-written or the pointer may become invalid
2079 *     following a further invocation of the same function or any
2080 *     modification of the Object. A copy of the string should
2081 *     therefore be made if necessary.
2082 *     - A NULL pointer will be returned if this function is invoked
2083 *     with the global error status set, or if it should fail for any
2084 *     reason.
2085 *-
2086 */
2087 
2088 /* Local Variables: */
2089    astDECLARE_GLOBALS            /* Thread-specific global data */
2090    const char *result;           /* Pointer value to return */
2091    int nobject;                  /* Nobject attribute value */
2092    int objsize;                  /* ObjSize attribute value */
2093    int ref_count;                /* RefCount attribute value */
2094    int usedefs;                  /* UseDefs attribute value */
2095 
2096 /* Initialise. */
2097    result = NULL;
2098 
2099 /* Check the global error status. */
2100    if ( !astOK ) return result;
2101 
2102 /* Get a pointer to Thread-specific global data. */
2103    astGET_GLOBALS(this);
2104 
2105 /* Compare "attrib" with each recognised attribute name in turn,
2106    obtaining the value of the required attribute. If necessary, write
2107    the value into "getattrib_buff" as a null-terminated string in an
2108    appropriate format.  Set "result" to point at the result string. */
2109 
2110 /* Class. */
2111 /* ------ */
2112    if ( !strcmp( attrib, "class" ) ) {
2113       result = astGetClass( this );
2114 
2115 /* ID. */
2116 /* --- */
2117    } else if ( !strcmp( attrib, "id" ) ) {
2118       result = astGetID( this );
2119 
2120 /* Ident. */
2121 /* ------ */
2122    } else if ( !strcmp( attrib, "ident" ) ) {
2123       result = astGetIdent( this );
2124 
2125 /* UseDefs */
2126 /* ------- */
2127    } else if ( !strcmp( attrib, "usedefs" ) ) {
2128       usedefs = astGetUseDefs( this );
2129       if ( astOK ) {
2130          (void) sprintf( getattrib_buff, "%d", usedefs );
2131          result = getattrib_buff;
2132       }
2133 
2134 /* Nobject. */
2135 /* -------- */
2136    } else if ( !strcmp( attrib, "nobject" ) ) {
2137       nobject = astGetNobject( this );
2138       if ( astOK ) {
2139          (void) sprintf( getattrib_buff, "%d", nobject );
2140          result = getattrib_buff;
2141       }
2142 
2143 /* ObjSize */
2144 /* ------- */
2145    } else if ( !strcmp( attrib, "objsize" ) ) {
2146       objsize = astGetObjSize( this );
2147       if ( astOK ) {
2148          (void) sprintf( getattrib_buff, "%d", objsize );
2149          result = getattrib_buff;
2150       }
2151 
2152 /* RefCount. */
2153 /* --------- */
2154    } else if ( !strcmp( attrib, "refcount" ) ) {
2155       ref_count = astGetRefCount( this );
2156       if ( astOK ) {
2157          (void) sprintf( getattrib_buff, "%d", ref_count );
2158          result = getattrib_buff;
2159       }
2160 
2161 /* If the attribute name was not recognised, then report an error. */
2162    } else if( astOK ){
2163       astError( AST__BADAT, "astGet: The %s given does not have an attribute "
2164                 "called \"%s\".", status, astGetClass( this ), attrib );
2165    }
2166 
2167 /* Return the result. */
2168    return result;
2169 }
2170 
astGetClass_(const AstObject * this,int * status)2171 const char *astGetClass_( const AstObject *this, int *status ) {
2172 /*
2173 *+
2174 *  Name:
2175 *     astGetClass
2176 
2177 *  Purpose:
2178 *     Obtain the value of the Class attribute for an Object.
2179 
2180 *  Type:
2181 *     Protected function.
2182 
2183 *  Synopsis:
2184 *     #include "object.h"
2185 *     const char *astGetClass( const AstObject *this )
2186 
2187 *  Class Membership:
2188 *     Object method.
2189 
2190 *  Description:
2191 *     This function returns a pointer to the Class string for an
2192 *     Object. This contains the name of the class which created the
2193 *     Object.
2194 
2195 *  Parameters:
2196 *     this
2197 *        Pointer to the Object.
2198 
2199 *  Returned Value:
2200 *     Pointer to a string containing the class name.
2201 
2202 *  Notes:
2203 *     - This function does not check the global error status before
2204 *     executing.  This is to allow it to be used to obtain class names
2205 *     for inclusion in error messages.
2206 *     - A pointer to an explanatory string will be returned if this
2207 *     function is given a pointer which does not identify an Object.
2208 *-
2209 */
2210 
2211 /* Local Variables: */
2212    const char *name;             /* Pointer to returned string */
2213 
2214 /* First check if the Object pointer supplied is NULL, and set the
2215    returned pointer accordingly. */
2216    if ( !this ) {
2217       name = "<NULL>";
2218 
2219 /* Also check if the supposed Object has the correct "magic number" in
2220    its check field. If not, it is not an Object. */
2221    } else if ( this->check != Magic( this, this->size, status ) ) {
2222       name = "<unknown>";
2223 
2224 /* If OK, obtain a pointer to the class name from the Object's virtual
2225    function table. */
2226    } else {
2227       name = this->vtab->class;
2228    }
2229 
2230 /* Return the result. */
2231    return name;
2232 }
2233 
astGetNobject_(const AstObject * this,int * status)2234 int astGetNobject_( const AstObject *this, int *status ) {
2235 /*
2236 *+
2237 *  Name:
2238 *     astGetNobject
2239 
2240 *  Purpose:
2241 *     Obtain the value of the Nobject attribute for an Object.
2242 
2243 *  Type:
2244 *     Protected function.
2245 
2246 *  Synopsis:
2247 *     #include "object.h"
2248 *     int astGetNobject( const AstObject *this )
2249 
2250 *  Class Membership:
2251 *     Object method.
2252 
2253 *  Description:
2254 *     This function returns the value of the Nobject attribute for an
2255 *     Object. This is a count of the number of active Objects in the
2256 *     same class as the Object supplied. This count does not include
2257 *     Objects in derived classes.
2258 
2259 *  Parameters:
2260 *     this
2261 *        Pointer to the Object.
2262 
2263 *  Returned Value:
2264 *     The number of active Objects.
2265 
2266 *  Notes:
2267 *     - A value of zero will be returned if this function is invoked
2268 *     with the global error status set, or if it should fail for any
2269 *     reason.
2270 *-
2271 */
2272 
2273 /* Check the global error status. */
2274    if ( !astOK ) return 0;
2275 
2276 /* Return the active object count. */
2277    return this->vtab->nobject;
2278 }
2279 
GetObjSize(AstObject * this,int * status)2280 static int GetObjSize( AstObject *this, int *status ) {
2281 /*
2282 *+
2283 *  Name:
2284 *     astGetObjSize
2285 
2286 *  Purpose:
2287 *     Determine the in-memory size of the Object.
2288 
2289 *  Type:
2290 *     Protected virtual function.
2291 
2292 *  Synopsis:
2293 *     #include "object.h"
2294 *     int astGetObjSize( AstObject *this )
2295 
2296 *  Class Membership:
2297 *     Object method.
2298 
2299 *  Description:
2300 *     This function returns the in-memory size of an Object.
2301 
2302 *  Parameters:
2303 *     this
2304 *        Pointer to the Object.
2305 
2306 *  Returned Value:
2307 *     The Object size, in bytes.
2308 
2309 *  Notes:
2310 *     - A value of zero will be returned if this function is invoked
2311 *     with the global error status set, or if it should fail for any
2312 *     reason.
2313 *-
2314 */
2315 
2316 /* Check the global error status. */
2317    if ( !astOK ) return 0;
2318 
2319 /* Return the object size. */
2320    return this->size;
2321 }
2322 
astGetProxy_(AstObject * this,int * status)2323 void *astGetProxy_( AstObject *this, int *status ) {
2324 /*
2325 *+
2326 *  Name:
2327 *     astGetProxy
2328 
2329 *  Purpose:
2330 *     Get a pointer to the foreign language proxy used to represent a
2331 *     given AST Object.
2332 
2333 *  Type:
2334 *     Undocumented public function.
2335 
2336 *  Synopsis:
2337 *     #include "object.h"
2338 *     void *astGetProxy( AstObject *this )
2339 
2340 *  Class Membership:
2341 *     Object method.
2342 
2343 *  Description:
2344 *     This function returns any pointer stored previously in the AST
2345 *     Object using astSetProxy. If no such pointer has been stored, a
2346 *     NULL pointer is returned.
2347 
2348 *  Parameters:
2349 *     this
2350 *        Pointer to the Object.
2351 
2352 *  Returned Value:
2353 *     Pointer to the proxy object, or NULL.
2354 
2355 *  Notes:
2356 *     - This function is public, but is currently undocumented since it
2357 *     is only of interest to people writing AST interfaces for other
2358 *     languages.
2359 *     - This function attempts to execute even if the AST error status
2360 *     is set on entry, although no further error report will be made
2361 *     if it subsequently fails under these circumstances.
2362 *-
2363 */
2364    return this ? this->proxy : NULL;
2365 }
2366 
astGetRefCount_(AstObject * this,int * status)2367 int astGetRefCount_( AstObject *this, int *status ) {
2368 /*
2369 *+
2370 *  Name:
2371 *     astGetRefCount
2372 
2373 *  Purpose:
2374 *     Obtain the value of the RefCount attribute for an Object.
2375 
2376 *  Type:
2377 *     Protected function.
2378 
2379 *  Synopsis:
2380 *     #include "object.h"
2381 *     int astGetRefCount( const AstObject *this )
2382 
2383 *  Class Membership:
2384 *     Object method.
2385 
2386 *  Description:
2387 *     This function returns the value of the read-only RefCount
2388 *     attribute for an Object. This is a "reference count" of the
2389 *     number of active pointers to it, as accounted for by astClone
2390 *     and astAnnul (plus the pointer issued when it was created).  If
2391 *     the reference count for an Object falls to zero when astAnnul is
2392 *     invoked, the object will be deleted.
2393 
2394 *  Parameters:
2395 *     this
2396 *        Pointer to the Object.
2397 
2398 *  Returned Value:
2399 *     The reference count.
2400 
2401 *  Notes:
2402 *     - A value of zero will be returned if this function is invoked
2403 *     with the global error status set, or if it should fail for any
2404 *     reason.
2405 *-
2406 */
2407 
2408 /* Local Variables; */
2409    int result;          /* Returned value */
2410 
2411 /* Check the global error status. */
2412    if ( !astOK ) return 0;
2413 
2414 /* Get a lock on the object's secondary mutex. This mutex guards access
2415    to the "ref_count" and "locker" components of the AstObject structure. */
2416    LOCK_SMUTEX(this);
2417 
2418 /* Get the reference count. */
2419    result = this->ref_count;
2420 
2421 /* Unlock the object's secondary mutex. */
2422    UNLOCK_SMUTEX(this);
2423 
2424 /* Return the result. */
2425    return result;
2426 }
2427 
2428 /*
2429 *++
2430 *  Name:
2431 c     astGet<X>
2432 f     AST_GET<X>
2433 
2434 *  Purpose:
2435 *     Get an attribute value for an Object.
2436 
2437 *  Type:
2438 *     Public functions.
2439 
2440 *  Synopsis:
2441 c     #include "object.h"
2442 c     <X>type astGet<X>( AstObject *this, const char *attrib )
2443 f     RESULT = AST_GET<X>( THIS, ATTRIB, STATUS )
2444 
2445 *  Class Membership:
2446 *     Object methods.
2447 
2448 *  Description:
2449 *     This is a family of functions which return a specified attribute
2450 *     value for an Object using one of several different data
2451 *     types. The type is selected by replacing <X> in the function name
2452 c     by C, D, F, I or L, to obtain a result in const char* (i.e. string),
2453 c     double, float, int, or long format, respectively.
2454 f     by C, D, I, L or R, to obtain a result in Character, Double
2455 f     precision, Integer, Logical or Real format, respectively.
2456 *
2457 *     If possible, the attribute value is converted to the type you
2458 *     request. If conversion is not possible, an error will result.
2459 
2460 *  Parameters:
2461 c     this
2462 f     THIS = INTEGER (Given)
2463 *        Pointer to the Object.
2464 c     attrib
2465 f     ATTRIB = CHARACTER * ( * ) (Given)
2466 c        Pointer to a null-terminated string containing the name of
2467 c        the attribute whose value is required.
2468 f        A character string containing the name of the attribute whose
2469 f        value is required.
2470 f     STATUS = INTEGER (Given and Returned)
2471 f        The global status.
2472 
2473 *  Returned Value:
2474 c     astGet<X>()
2475 f     AST_GET<X> = <X>type
2476 c        The attribute value, in the data type corresponding to <X> (or,
2477 c        in the case of astGetC, a pointer to a constant null-terminated
2478 c        character string containing this value).
2479 f        The attribute value, in the data type corresponding to <X>.
2480 
2481 *  Applicability:
2482 *     Object
2483 *        These functions apply to all Objects.
2484 
2485 *  Examples:
2486 c     printf( "RefCount = %d\n", astGetI( z, "RefCount" ) );
2487 c        Prints the RefCount attribute value for Object "z" as an int.
2488 c     title = astGetC( axis, "Title" );
2489 c        Obtains a pointer to a null-terminated character string containing
2490 c        the Title attribute of Object "axis".
2491 f     WRITE( *, '('' RefCount = '', A10 )' ) AST_GETC( Z, 'RefCount', STATUS )
2492 f        Prints the RefCount attribute value for Object Z as a character
2493 f        string.
2494 f     NAXES = AST_GETI( FRAME, 'Naxes', STATUS )
2495 f        Obtains the value of the Naxes attribute for Object FRAME as an
2496 f        integer.
2497 
2498 *  Notes:
2499 *     - Attribute names are not case sensitive and may be surrounded
2500 *     by white space.
2501 *     - An appropriate "null" value will be returned if this function
2502 c     is invoked with the AST error status set, or if it should
2503 f     is invoked with STATUS set to an error value, or if it should
2504 *     fail for any reason. This null value is zero for numeric
2505 c     values and NULL for pointer values.
2506 f     values, .FALSE. for logical values, and blank for character values.
2507 f     - Numerical attribute values of zero translate to logical value
2508 f     .FALSE. and all other numerical values translate to .TRUE..
2509 c     - The pointer returned by astGetC is guaranteed to remain valid
2510 c     and the string to which it points will not be over-written for a
2511 c     total of 50 successive invocations of this function. After this,
2512 c     the memory containing the string may be re-used, so a copy of
2513 c     the string should be made if it is needed for longer than this.
2514 *--
2515 */
2516 
2517 /* Define a macro that expands to implement the astGetX_ member
2518    functions required. The arguments to this macro are:
2519 
2520       code
2521          The character that appears at the end of the function name.
2522       type
2523          The C type of the function return value.
2524       format
2525          A quoted string containing a astSscanf format specifier that
2526          will read the attribute value into a variable of the required
2527          data type. This format should transfer 1 astSscanf value.
2528 */
2529 #define MAKE_GETX(code,type,format) \
2530 type astGet##code##_( AstObject *this, const char *attrib, int *status ) { \
2531 \
2532 /* Local Variables: */ \
2533    const char *str;              /* Pointer to string attribute value */ \
2534    int nc;                       /* Number of characters read from string */ \
2535    int nval;                     /* Number of values read from string */ \
2536    type result;                  /* Value to return */ \
2537    type value;                   /* Converted value */ \
2538 \
2539 /* Initialise. */ \
2540    result = (type) 0; \
2541 \
2542 /* Check the global error status. */ \
2543    if ( !astOK ) return result; \
2544 \
2545 /* Obtain the attribute value as a string. */ \
2546    str = Get( this, attrib, status ); \
2547    if ( astOK ) { \
2548 \
2549 /* Read the value from the string, ignoring surrounding white \
2550    space. */ \
2551       nc = 0; \
2552       nval = astSscanf( str, " " format " %n", &value, &nc ); \
2553 \
2554 /* Check that the number of values read was 1 and that all the \
2555    string's characters were consumed. If so, use the result. */ \
2556       if ( ( nval == 1 ) && ( nc >= (int) strlen( str ) ) ) { \
2557          result = value; \
2558 \
2559 /* If the read was unsuccessful, report an error. */ \
2560       } else if( astOK ) { \
2561          astError( AST__ATGER, "astGet" #code "(%s): The attribute " \
2562                    "value \"%s=%s\" cannot be read using the requested data " \
2563                    "type.", status,astGetClass( this ), attrib, str ); \
2564       } \
2565    } \
2566 \
2567 /* Return the result. */ \
2568    return result; \
2569 }
2570 
2571 /* Use this macro to create all the GetX_ private member functions,
2572    except SetC (which is handled separately). */
2573 MAKE_GETX(D,double,"%lf")
2574 MAKE_GETX(F,float,"%f")
2575 MAKE_GETX(I,int,"%d")
2576 MAKE_GETX(L,long,"%ld")
2577 
2578 /* Handle GetC separately because memory must be allocated to hold the
2579    returned character values. */
astGetC_(AstObject * this,const char * attrib,int * status)2580 const char *astGetC_( AstObject *this, const char *attrib, int *status ) {
2581 
2582 /* Local Variables: */
2583    astDECLARE_GLOBALS            /* Thread-specific global data */
2584    const char *result;           /* Pointer value to return */
2585    const char *value;            /* Pointer to attribute value */
2586    int i;                        /* Loop count */
2587 
2588 /* Initialise. */
2589    result = NULL;
2590 
2591 /* Check the global error status. */
2592    if ( !astOK ) return result;
2593 
2594 /* Get a pointer to Thread-specific global data. */
2595    astGET_GLOBALS(this);
2596 
2597 /* If the "strings" array has not been initialised, fill it with
2598    NULL pointers. */
2599    if ( !astgetc_init ) {
2600       astgetc_init = 1;
2601       for ( i = 0; i < AST__ASTGETC_MAX_STRINGS; i++ ) astgetc_strings[ i ] = NULL;
2602    }
2603 
2604 /* Obtain a pointer to the required attribute value, formatted as a
2605    character string. */
2606    value = Get( this, attrib, status );
2607 
2608 /* If OK, store a copy of the resulting string in dynamically
2609    allocated memory, putting a pointer to the copy into the next
2610    element of the "astgetc_strings" array.  (This process also de-allocates
2611    any previously allocated memory pointed at by this "strings"
2612    element, so the earlier string is effectively replaced by the new
2613    one.) */
2614    if ( astOK ) {
2615 
2616       astBeginPM;
2617       astgetc_strings[ astgetc_istr ] = astStore( astgetc_strings[ astgetc_istr ],
2618                                              value, strlen( value ) + (size_t) 1 );
2619       astEndPM;
2620 
2621 /* If OK, return a pointer to the copy and increment "astgetc_istr" to use the
2622    next element of "astgetc_strings" on the next invocation. Recycle
2623    "astgetc_istr" to zero when all elements have been used. */
2624       if ( astOK ) {
2625          result = astgetc_strings[ astgetc_istr++ ];
2626          if ( astgetc_istr == ( AST__ASTGETC_MAX_STRINGS - 1 ) ) astgetc_istr = 0;
2627       }
2628    }
2629 
2630 /* Return the result. */
2631    return result;
2632 
2633 }
2634 
HasAttribute(AstObject * this,const char * attrib,int * status)2635 static int HasAttribute( AstObject *this, const char *attrib, int *status ) {
2636 /*
2637 *++
2638 *  Name:
2639 c     astHasAttribute
2640 f     AST_HASATTRIBUTE
2641 
2642 *  Purpose:
2643 *     Test if an Object has a named attribute.
2644 
2645 *  Type:
2646 *     Public function.
2647 
2648 *  Synopsis:
2649 c     #include "object.h"
2650 c     int astHasAttribute( AstObject *this, const char *attrib )
2651 f     RESULT = AST_HASATTRIBUTE( THIS, ATTRIB, STATUS )
2652 
2653 *  Class Membership:
2654 *     Object method.
2655 
2656 *  Description:
2657 c     This function returns a boolean result (0 or 1) to indicate
2658 f     This function returns a logical result to indicate
2659 *     whether the supplied Object has an attribute with the supplied name.
2660 
2661 *  Parameters:
2662 c     this
2663 f     THIS = INTEGER (Given)
2664 *        Pointer to the first Object.
2665 c     attrib
2666 f     ATTRIB = INTEGER (Given)
2667 c        Pointer to a string holding the
2668 f        The
2669 *        name of the attribute to be tested.
2670 f     STATUS = INTEGER (Given and Returned)
2671 f        The global status.
2672 
2673 *  Returned Value:
2674 c     astHasAttribute()
2675 c        One if the Object has the named attribute, otherwise zero.
2676 f     AST_SAME = LOGICAL
2677 f        .TRUE. if the Object has the named attribute, otherwise
2678 f        .FALSE.
2679 
2680 *  Applicability:
2681 *     Object
2682 c        This function applies to all Objects.
2683 f        This routine applies to all Objects.
2684 
2685 *  Notes:
2686 c     - A value of zero will be returned if this function is invoked
2687 c     with the AST error status set, or if it should fail for any reason.
2688 f     - A value of .FALSE. will be returned if this function is invoked
2689 f     with STATUS set to an error value, or if it should fail for any reason.
2690 *--
2691 */
2692 
2693 /* Local Variables: */
2694    int oldrep;           /* Original AST error reporting flag */
2695    int result;           /* Returned value */
2696 
2697 /* Check the global error status. */
2698    if ( !astOK ) return 0;
2699 
2700 /* Temporarily switch off error reporting. */
2701    oldrep = astReporting( 0 );
2702 
2703 /* Attempt to get a value for the specified attribute. */
2704    (void) Get( this, attrib, status );
2705 
2706 /* An error will have been reported if the object does not have the
2707    requested attribute. Set the result and clear the error status. */
2708    if( !astOK ) {
2709       result = 0;
2710       astClearStatus;
2711    } else {
2712       result = 1;
2713    }
2714 
2715 /* Re-instate the original error reporting flag. */
2716    (void) astReporting( oldrep );
2717 
2718 /* Return the result. */
2719    return result;
2720 }
2721 
Magic(const AstObject * this,size_t size,int * status)2722 static unsigned long Magic( const AstObject *this, size_t size, int *status ) {
2723 /*
2724 *  Name:
2725 *     Magic
2726 
2727 *  Purpose:
2728 *     Generate a "magic number" for an Object.
2729 
2730 *  Type:
2731 *     Private function.
2732 
2733 *  Synopsis:
2734 *     #include "object.h"
2735 *     unsigned long Magic( const AstObject *this, size_t size, int *status )
2736 
2737 *  Class Membership:
2738 *     Object member function.
2739 
2740 *  Description:
2741 *     This function generates a "magic number" which is a function of an Object
2742 *     pointer (address) and an Object size. This number may be stored in an
2743 *     Object to allow it to be recognised as a valid Object by other routines
2744 *     and to provide security against argument passing errors, etc.
2745 
2746 *  Parameters:
2747 *     this
2748 *        Pointer to an Object.
2749 *     size
2750 *        The Object size.
2751 *     status
2752 *        Pointer to the inherited status variable.
2753 
2754 *  Returned Value:
2755 *     The magic number.
2756 
2757 *  Notes:
2758 *     -  This function does not perform any error checking.
2759 */
2760 
2761 /* Form the bit-wise exclusive OR between the Object address and the Object
2762    size, then add 2 and invert the bits. Return the result as an unsigned
2763    long integer. */
2764    return ~( ( ( (unsigned long) this ) ^ ( (unsigned long) size ) ) +
2765              ( (unsigned long) 2 ) );
2766 }
2767 
2768 #if defined(THREAD_SAFE)
ManageLock(AstObject * this,int mode,int extra,AstObject ** fail,int * status)2769 static int ManageLock( AstObject *this, int mode, int extra,
2770                        AstObject **fail, int *status ) {
2771 /*
2772 *+
2773 *  Name:
2774 *     astManageLock
2775 
2776 *  Purpose:
2777 *     Manage the thread lock on an Object.
2778 
2779 *  Type:
2780 *     Protected function.
2781 
2782 *  Synopsis:
2783 *     #include "object.h"
2784 *     int astManageLock( AstObject *this, int mode, int extra,
2785 *                        AstObject **fail )
2786 
2787 *  Class Membership:
2788 *     Object method.
2789 
2790 *  Description:
2791 *     This function manages the thread lock on the supplied Object. The
2792 *     lock can be locked, unlocked or checked by this function as
2793 *     deteremined by parameter "mode". See astLock for details of the way
2794 *     these locks are used.
2795 
2796 *  Parameters:
2797 *     this
2798 *        Pointer to the Object.
2799 *     mode
2800 *        An integer flag indicating what the function should do:
2801 *
2802 *        AST__LOCK: Lock the Object for exclusive use by the calling
2803 *        thread. The "extra" value indicates what should be done if the
2804 *        Object is already locked (wait or report an error - see astLock).
2805 *
2806 *        AST__UNLOCK: Unlock the Object for use by other threads.
2807 *
2808 *        AST__CHECKLOCK: Check that the object is locked for use by the
2809 *        calling thread.
2810 *     extra
2811 *        Extra mode-specific information.
2812 *     fail
2813 *        If a non-zero function value is returned, a pointer to the
2814 *        Object that caused the failure is returned at "*fail". This may
2815 *        be "this" or it may be an Object contained within "this". Note,
2816 *        the Object's reference count is not incremented, and so the
2817 *        returned pointer should not be annulled. A NULL pointer is
2818 *        returned if this function returns a value of zero.
2819 
2820 *  Returned Value:
2821 *     A status value:
2822 *        0 - Success.
2823 *        1 - Could not lock or unlock the object because it was already
2824 *            locked by another thread.
2825 *        2 - Failed to lock a POSIX mutex
2826 *        3 - Failed to unlock a POSIX mutex
2827 *        4 - Bad "mode" value supplied.
2828 *        5 - Check failed - object is locked by a different thread
2829 *        6 - Check failed - object is unlocked
2830 *
2831 
2832 *  Notes:
2833 *     - This function attempts to execute even if an error has already
2834 *     occurred.
2835 
2836 *-
2837 */
2838 
2839 /* Local Variables: */
2840    astDECLARE_GLOBALS            /* Thread-specific global data */
2841    int result;                   /* Returned value */
2842 
2843 /* Initialise */
2844    result = 0;
2845    if( fail ) *fail = NULL;
2846 
2847 /* Check the supplied point is not NULL. */
2848    if( ! this ) return result;
2849 
2850 /* Get a pointer to Thread-specific global data. */
2851    astGET_GLOBALS(NULL);
2852 
2853 /* Get a lock on the object's secondary mutex. This gives us exclusive
2854    access to the "locker" (and "ref_count") component in the AstObject
2855    structure. All other components in the structure are guarded by the
2856    primary mutex (this->mutex1). */
2857    if( LOCK_SMUTEX(this) ) {
2858       result = 2;
2859 
2860 /* If the secondary mutex was locked succesfully, first deal with cases
2861    where the caller wants to lock the Object for exclusive use by the
2862    calling thread. */
2863    } else if( mode == AST__LOCK ) {
2864 
2865 /* If the Object is not currently locked, lock the Object primary mutex
2866    and record the identity of the calling thread in the Object. */
2867       if( this->locker == -1 ) {
2868          if( LOCK_PMUTEX(this) ) result = 2;
2869          this->locker = AST__THREAD_ID;
2870          this->globals = AST__GLOBALS;
2871          ChangeThreadVtab( this, status );
2872 
2873 /* If the Object is already locked by the calling thread, do nothing. */
2874       } else if( this->locker == AST__THREAD_ID ) {
2875 
2876 /* If the object is locked by a different thread, and the caller is
2877    willing to wait, attempt to lock the Object primary mutex. This will
2878    cause the calling thread to block until the Object is release by the
2879    thread that currently has it locked. Then store the identity of the
2880    calling thread (the new lock owner). We first need to release the
2881    secondary mutex so that the other thread can modify the "locker"
2882    component in the AstObject structure when it releases the Object
2883    (using this function). We then re-lock the secondary mutex so this
2884    thread can change the "locker" component safely. */
2885       } else if( extra ) {
2886          if( UNLOCK_SMUTEX(this) ) {
2887             result = 3;
2888          } else if( LOCK_PMUTEX(this) ) {
2889             result = 2;
2890          } else if( LOCK_SMUTEX(this) ) {
2891             result = 2;
2892          }
2893          this->locker = AST__THREAD_ID;
2894          this->globals = AST__GLOBALS;
2895          ChangeThreadVtab( this, status );
2896 
2897 /* If the caller does not want to wait until the Object is available,
2898    return a status of 1. */
2899       } else {
2900          result = 1;
2901       }
2902 
2903 /* Unlock the Object for use by other threads. */
2904    } else if( mode == AST__UNLOCK ) {
2905 
2906 /* Do nothing if the Object is currently unlocked. */
2907       if( this->locker == -1 ) {
2908 
2909 /* If the object is currently locked by the calling thread, clear the
2910    identity of the thread that owns the lock and unlock the primary
2911    mutex. */
2912       } else if( this->locker == AST__THREAD_ID ) {
2913          this->locker = -1;
2914          this->globals = NULL;
2915          if( UNLOCK_PMUTEX(this) ) result = 3;
2916 
2917 /* Return an error status value if the Object is locked by another
2918    thread. */
2919       } else {
2920          result = 1;
2921       }
2922 
2923 /* Check the Object is locked by the calling thread. Return a status of 1 if
2924    not. */
2925    } else if( mode == AST__CHECKLOCK ) {
2926       if( this->locker == -1 ) {
2927          result = 6;
2928       } else if( this->locker != AST__THREAD_ID ) {
2929          result = 5;
2930       }
2931 
2932 /* Return a status of 4 for any other modes. */
2933    } else {
2934       result = 4;
2935    }
2936 
2937 /* Unlock the secondary mutex so that other threads can access the "locker"
2938    component in the Object to see if it is locked. */
2939    if( UNLOCK_SMUTEX(this) ) result = 3;
2940 
2941 /* If the operation failed, return a pointer to the failed object. */
2942    if( result && fail ) *fail = this;
2943 
2944 /* Return the status value */
2945    return result;
2946 }
2947 #endif
2948 
astToString_(AstObject * this,int * status)2949 char *astToString_( AstObject *this, int *status ) {
2950 /*
2951 c++
2952 *  Name:
2953 *     astToString
2954 
2955 *  Purpose:
2956 *     Create an in-memory serialisation of an Object
2957 
2958 *  Type:
2959 *     Public function.
2960 
2961 *  Synopsis:
2962 *     #include "object.h"
2963 *     char *astToString( AstObject *this )
2964 
2965 *  Class Membership:
2966 *     Object method.
2967 
2968 *  Description:
2969 *     This function returns a string holding a minimal textual
2970 *     serialisation of the supplied AST Object. The Object can re
2971 *     re-created from the serialisation using astFromString.
2972 
2973 *  Parameters:
2974 *     this
2975 *        Pointer to the Object to be serialised.
2976 
2977 *  Returned Value:
2978 *     astToString()
2979 *        Pointer to dynamically allocated memory holding the
2980 *        serialisation, or NULL if an error occurs. The pointer
2981 *        should be freed when no longer needed using astFree.
2982 
2983 c--
2984 */
2985 
2986 /* Local Variables: */
2987    StringData data;              /* Data passed to the sink function */
2988    AstChannel *channel;          /* Pointer to output Channel */
2989 
2990 /* Check the global error status. */
2991    if ( !astOK ) return NULL;
2992 
2993 /* Create a Channel which will write to an expanding dynamically
2994    allocated memory buffer. Set Channel attributes to exclude all
2995    non-essential characters. */
2996    channel = astChannel( NULL, ToStringSink, "Comment=0,Full=-1,Indent=0",
2997                          status );
2998 
2999 /* Initialise the data structure used to communicate with the sink
3000    function, and store a pointer to it in the Channel. */
3001    data.ptr = NULL;
3002    data.buff = NULL;
3003    data.len = 0;
3004    astPutChannelData( channel, &data );
3005 
3006 /* Write the Object to the Channel. */
3007    astWrite( channel, this );
3008 
3009 /* Annul the Channel pointer. */
3010    channel = astAnnul( channel );
3011 
3012 /* Free the returned string if an error has occurred. */
3013    if( !astOK ) data.ptr = astFree( data.ptr );
3014 
3015 /* Return the pointer. */
3016    return data.ptr;
3017 }
3018 
ToStringSink(const char * text)3019 static void ToStringSink( const char *text ){
3020 /*
3021 *  Name:
3022 *     ToStringSink
3023 
3024 *  Purpose:
3025 *     A Channel sink function for use by the astToString method.
3026 
3027 *  Type:
3028 *     Private function.
3029 
3030 *  Synopsis:
3031 *     #include "object.h"
3032 *      ToStringSink( const char *text )
3033 
3034 *  Class Membership:
3035 *     Object member function.
3036 
3037 *  Description:
3038 *     This function appends the supplied line of text to the end of a
3039 *     dynamically growing memory block.
3040 
3041 *  Parameters:
3042 *     text
3043 *        Pointer to the null-terminated line of text to be stored.
3044 
3045 */
3046 
3047 /* Local Variables: */
3048    StringData *data;     /* Data passed to the sink function */
3049    int *status;          /* Pointer to local status value */
3050    int status_value;     /* Local status value */
3051 
3052 /* Set up the local status */
3053    status_value = 0;
3054    status = &status_value;
3055 
3056 /* Get a pointer to the structure holding the current memory pointer and
3057    the length of the currently allocated memory. */
3058    data = astChannelData;
3059 
3060 /* Append the supplied text to the end of the string, and update the
3061    string length. */
3062    data->ptr = astAppendString( data->ptr, &(data->len), text );
3063 
3064 /* Append a newline character to the end of the string, and update the
3065    string length. */
3066    data->ptr = astAppendString( data->ptr, &(data->len), "\n" );
3067 }
3068 
astSet_(void * this_void,const char * settings,int * status,...)3069 void astSet_( void *this_void, const char *settings, int *status, ... ) {
3070 /*
3071 *++
3072 *  Name:
3073 c     astSet
3074 f     AST_SET
3075 
3076 *  Purpose:
3077 *     Set attribute values for an Object.
3078 
3079 *  Type:
3080 *     Public function.
3081 
3082 *  Synopsis:
3083 c     #include "object.h"
3084 c     void astSet( AstObject *this, const char *settings, ... )
3085 f     CALL AST_SET( THIS, SETTINGS, STATUS )
3086 
3087 *  Class Membership:
3088 *     Object method.
3089 
3090 *  Description:
3091 c     This function assigns a set of attribute values to an Object,
3092 f     This routine assigns a set of attribute values to an Object,
3093 *     over-riding any previous values. The attributes and their new
3094 *     values are specified via a character string, which should
3095 *     contain a comma-separated list of the form:
3096 *
3097 *        "attribute_1 = value_1, attribute_2 = value_2, ... "
3098 *
3099 *     where "attribute_n" specifies an attribute name, and the value
3100 *     to the right of each "=" sign should be a suitable textual
3101 *     representation of the value to be assigned. This value will be
3102 *     interpreted according to the attribute's data type.
3103 c
3104 c     The string supplied may also contain "printf"-style format
3105 c     specifiers, identified by "%" signs in the usual way. If
3106 c     present, these will be substituted by values supplied as
3107 c     additional optional arguments (using the normal "printf" rules)
3108 c     before the string is used.
3109 
3110 *  Parameters:
3111 c     this
3112 f     THIS = INTEGER (Given)
3113 *        Pointer to the Object.
3114 c     settings
3115 f     SETTINGS = CHARACTER * ( * ) (Given)
3116 c        Pointer to a null-terminated character string containing a
3117 c        comma-separated list of attribute settings in the form described
3118 c        above.
3119 f        A character string containing a comma-separated list of
3120 f        attribute settings in the form described above.
3121 c     ...
3122 c        Optional additional arguments which supply values to be
3123 c        substituted for any "printf"-style format specifiers that
3124 c        appear in the "settings" string.
3125 f     STATUS = INTEGER (Given and Returned)
3126 f        The global status.
3127 
3128 *  Applicability:
3129 *     Object
3130 c        This function applies to all Objects.
3131 f        This routine applies to all Objects.
3132 
3133 *  Examples:
3134 c     astSet( map, "Report = 1, Zoom = 25.0" );
3135 c        Sets the Report attribute for Object "map" to the value 1 and
3136 c        the Zoom attribute to 25.0.
3137 c     astSet( frame, "Label( %d ) =Offset along axis %d", axis, axis );
3138 c        Sets the Label(axis) attribute for Object "frame" to a
3139 c        suitable string, where the axis number is obtained from
3140 c        "axis", a variable of type int.
3141 c     astSet( frame, "Title =%s", mystring );
3142 c        Sets the Title attribute for Object "frame" to the contents of
3143 c        the string "mystring".
3144 f     CALL AST_SET( MAP, 'Report = 1, Zoom = 25.0', STATUS )
3145 f        Sets the Report attribute for Object MAP to the value 1 and
3146 f        the Zoom attribute to 25.0.
3147 f     CALL AST_SET( FRAME, 'Label( 1 ) =Offset from cluster axis', STATUS )
3148 f        Sets the Label(1) attribute for Object FRAME to a suitable
3149 f        string.
3150 
3151 *  Notes:
3152 *     - Attribute names are not case sensitive and may be surrounded
3153 *     by white space.
3154 *     - White space may also surround attribute values, where it will
3155 *     generally be ignored (except for string-valued attributes where
3156 *     it is significant and forms part of the value to be assigned).
3157 *     - To include a literal comma in the value assigned to an attribute,
3158 *     the whole attribute value should be enclosed in quotation markes.
3159 c     Alternatively, you can use "%s" format and supply the value as a
3160 c     separate additional argument to astSet (or use the astSetC
3161 c     function instead).
3162 c     - The same procedure may be adopted if "%" signs are to be included
3163 c     and are not to be interpreted as format specifiers (alternatively,
3164 c     the "printf" convention of writing "%%" may be used).
3165 *     - An error will result if an attempt is made to set a value for
3166 *     a read-only attribute.
3167 *--
3168 
3169 *  Implementation Notes:
3170 *     - Because this function has a variable argument list, it is
3171 *     invoked by a macro that evaluates to a function pointer (not a
3172 *     function invocation) and no checking or casting of arguments is
3173 *     performed before the function is invoked. Because of this, the
3174 *     Object identifier is of type (void *) and is converted and
3175 *     validated within the function itself.
3176 *     - This implementation of astSet is designed to be used within AST,
3177 *     and has an explicit status parameter. From outside AST, the astSet
3178 *     macro will invoke the astSetId_ function which does not have an
3179 *     status parameter.
3180 
3181 *--
3182 */
3183 
3184 /* Local Variables: */
3185    AstObject *this;              /* Pointer to the Object structure */
3186    va_list args;                 /* Variable argument list */
3187 
3188 /* Check the global error status. */
3189    if ( !astOK ) return;
3190 
3191 /* Obtain and validate a pointer to the Object structure. */
3192    this = astCheckObject( this_void );
3193    if ( astOK ) {
3194 
3195 /* Obtain the variable argument list and pass all arguments to the
3196    astVSet method for interpretation. */
3197       va_start( args, status );
3198       astVSet( this, settings, NULL, args );
3199       va_end( args );
3200    }
3201 }
3202 
SetAttrib(AstObject * this,const char * setting,int * status)3203 static void SetAttrib( AstObject *this, const char *setting, int *status ) {
3204 /*
3205 *+
3206 *  Name:
3207 *     astSetAttrib
3208 
3209 *  Purpose:
3210 *     Set an attribute value for an Object.
3211 
3212 *  Type:
3213 *     Protected virtual function.
3214 
3215 *  Synopsis:
3216 *     #include "object.h"
3217 *     void astSetAttrib( AstObject *this, const char *setting )
3218 
3219 *  Class Membership:
3220 *     Object method.
3221 
3222 *  Description:
3223 *     This function assigns an attribute value for an Object, the attribute and
3224 *     its value being specified by means of a string of the form:
3225 *
3226 *        "attribute= value "
3227 *
3228 *     Here, "attribute" specifies the attribute name and should be in lower
3229 *     case with no white space present. The value to the right of the "="
3230 *     should be a suitable textual representation of the value to be assigned
3231 *     and this will be interpreted according to the attribute's data type.
3232 *     White space surrounding the value is only significant for string
3233 *     attributes.
3234 
3235 *  Parameters:
3236 *     this
3237 *        Pointer to the Object.
3238 *     setting
3239 *        Pointer to a null-terminated string specifying the new attribute
3240 *        value.
3241 
3242 *  Notes:
3243 *     - The Object class does not have any writable attributes, so
3244 *     this function merely reports an error. It is intended to be
3245 *     extended by other class definitions.
3246 *-
3247 */
3248 
3249 /* Local Variables: */
3250    int id;                       /* Offset of ID string */
3251    int ival;                     /* Integer attribute value */
3252    int len;                      /* Length of setting string */
3253    int nc;                       /* Number of characters read by astSscanf */
3254 
3255 /* Check the global error status. */
3256    if ( !astOK ) return;
3257 
3258 /* Obtain the length of the setting string. */
3259    len = (int) strlen( setting );
3260 
3261 /* Test for each recognised attribute in turn, using "astSscanf" to parse
3262    the setting string and extract the attribute value (or an offset to
3263    it in the case of string values). In each case, use the value set
3264    in "nc" to check that the entire string was matched. Once a value
3265    has been obtained, use the appropriate method to set it. */
3266 
3267 /* ID. */
3268 /* --- */
3269    if ( nc = 0, ( 0 == astSscanf( setting, "id=%n%*[^\n]%n", &id, &nc ) )
3270                 && ( nc >= len ) ) {
3271       astSetID( this, setting + id );
3272 
3273 /* Ident. */
3274 /* ------ */
3275    } else if ( nc = 0, ( 0 == astSscanf( setting, "ident=%n%*[^\n]%n", &id, &nc ) )
3276                 && ( nc >= len ) ) {
3277       astSetIdent( this, setting + id );
3278 
3279 /* UseDefs */
3280 /* ------- */
3281    } else if ( nc = 0,
3282                ( 1 == astSscanf( setting, "usedefs= %d %n", &ival, &nc ) )
3283                && ( nc >= len ) ) {
3284       astSetUseDefs( this, ival );
3285 
3286 /* Define a macro to see if the setting string matches any of the
3287    read-only attributes of this class and use this to report an error
3288    if it does. */
3289 #define MATCH(attrib) \
3290         ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
3291                   ( nc >= len ) )
3292 
3293    } else if ( MATCH( "class" ) ||
3294                MATCH( "nobject" ) ||
3295                MATCH( "objsize" ) ||
3296                MATCH( "refcount" ) ) {
3297       astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
3298                 setting, astGetClass( this ) );
3299       astError( AST__NOWRT, "This is a read-only attribute." , status);
3300 
3301 /* Since no writable attributes are defined for the Object class, any
3302    attempt to set a value for anything else is also an error. */
3303    } else {
3304       astError( AST__BADAT, "astSet: The attribute setting \"%s\" is invalid "
3305                "for a %s.", status, setting, astGetClass( this ) );
3306    }
3307 
3308 /* Undefine macros local to this function. */
3309 #undef MATCH
3310 }
3311 
astSetCopy_(AstObjectVtab * vtab,void (* copy)(const AstObject *,AstObject *,int *),int * status)3312 void astSetCopy_( AstObjectVtab *vtab,
3313                   void (* copy)( const AstObject *, AstObject *, int * ), int *status ) {
3314 /*
3315 *+
3316 *  Name:
3317 *     astSetCopy
3318 
3319 *  Purpose:
3320 *     Declare a copy constructor for an Object.
3321 
3322 *  Type:
3323 *     Protected function.
3324 
3325 *  Synopsis:
3326 *     #include "object.h"
3327 *     void astSetCopy( AstObjectVtab *vtab,
3328 *                      void (* copy)( const AstObject *, AstObject * ) )
3329 
3330 *  Class Membership:
3331 *     Object method.
3332 
3333 *  Description:
3334 *     This function is provided so that class definitions can declare a copy
3335 *     constructor to be associated with an Object that is being constructed.
3336 *     When a copy is later performed on the Object, the copy constructor of
3337 *     each class to which the Object belongs will be invoked in turn (working
3338 *     down the class hierarchy). The copy constructor is passed pointers to the
3339 *     source and destination Objects. It should implement the copy and return
3340 *     void.
3341 
3342 *  Parameters:
3343 *     vtab
3344 *        Pointer to the Object's virtual function table, in which the copy
3345 *        constructor's pointer is to be stored for future use.
3346 *     copy
3347 *        Pointer to the copy constructor function.
3348 
3349 *  Notes:
3350 *     -  When an Object is copied, a byte-by-byte copy of its structure is
3351 *     automatically made before any copy constructors are invoked. A copy
3352 *     constructor need only be provided if this does not suffice (e.g. if the
3353 *     structure contains pointers to other data).
3354 *     - If a copy constructor is declared for a class, then a
3355 *     destructor for that class must also be declared (using
3356 *     astSetDelete) so that there is a one-to-one correspondence
3357 *     between copy constructors and their associated destructors.
3358 *     -  Copy constructors should check the global error status in the normal
3359 *     way and should set it (and report an error) if they fail.
3360 *-
3361 */
3362 
3363 
3364 /* Check the global status. */
3365    if ( !astOK ) return;
3366 
3367 /* Indicate that subsequent memory allocations may never be freed (other
3368    than by any AST exit handler). */
3369    astBeginPM;
3370 
3371 /* Expand the array of copy constructor pointers in the virtual function table
3372    (if necessary) to accommodate the new one. */
3373    vtab->copy = astGrow( vtab->copy, vtab->ncopy + 1,
3374                         sizeof( void (*)( const AstObject *, AstObject * ) ) );
3375 
3376 /* If OK, store the new function pointer and increment the count of copy
3377    constructors. */
3378    if ( astOK ) {
3379       vtab->copy[ vtab->ncopy++ ] = copy;
3380    }
3381 
3382 /* Mark the end of the section in which memory allocations may never be freed
3383    (other than by any AST exit handler). */
3384    astEndPM;
3385 
3386 }
3387 
astSetDelete_(AstObjectVtab * vtab,void (* delete)(AstObject *,int *),int * status)3388 void astSetDelete_( AstObjectVtab *vtab, void (* delete)( AstObject *, int * ), int *status ) {
3389 /*
3390 *+
3391 *  Name:
3392 *     astSetDelete
3393 
3394 *  Purpose:
3395 *     Declare a destructor for an Object.
3396 
3397 *  Type:
3398 *     Protected function.
3399 
3400 *  Synopsis:
3401 *     #include "object.h"
3402 *     void astSetDelete( AstObjectVtab *vtab, void (* delete)( AstObject * ) )
3403 
3404 *  Class Membership:
3405 *     Object method.
3406 
3407 *  Description:
3408 *     This function is provided so that class definitions can declare a
3409 *     destructor to be associated with an Object. When the Object is later
3410 *     deleted, the destructor declared by each class to which the Object
3411 *     belongs will be invoked in turn (working up the class hierarchy). The
3412 *     destructor is passed a pointer to the Object. It should free any
3413 *     resources (e.g. memory) associated with it and return void. It should
3414 *     not free the memory containing the Object itself.
3415 
3416 *  Parameters:
3417 *     vtab
3418 *        Pointer to the Object's virtual function table, in which the
3419 *        destructor's pointer is to be stored for future use.
3420 *     delete
3421 *        Pointer to the destructor function.
3422 
3423 *  Notes:
3424 *     - A destructor need not be declared for a class if there are no
3425 *     resources to free.
3426 *     - If a destructor is declared for a class, then a copy
3427 *     constructor for that class must also be declared (using
3428 *     astSetCopy) so that there is a one-to-one correspondence between
3429 *     copy constructors and their associated destructors.
3430 *     - A destructor function should generally attempt to execute even
3431 *     if the global error status is set on entry, but should not
3432 *     report further errors in that case (errors should be reported
3433 *     normally if status is not set on entry).
3434 *-
3435 */
3436 
3437 
3438 /* Check the global status. */
3439    if ( !astOK ) return;
3440 
3441 /* Indicate that subsequent memory allocations may never be freed (other
3442    than by any AST exit handler). */
3443    astBeginPM;
3444 
3445 /* Expand the array of destructor pointers in the virtual function table (if
3446    necessary) to accommodate the new one. */
3447    vtab->delete = astGrow( vtab->delete, vtab->ndelete + 1,
3448                            sizeof( void (*)( AstObject * ) ) );
3449 
3450 /* If OK, store the new function pointer and increment the count of
3451    destructors. */
3452    if ( astOK ) {
3453       vtab->delete[ vtab->ndelete++ ] = delete;
3454    }
3455 
3456 /* Mark the end of the section in which memory allocations may never be freed
3457    (other than by any AST exit handler). */
3458    astEndPM;
3459 
3460 }
3461 
astSetDump_(AstObjectVtab * vtab,void (* dump)(AstObject *,AstChannel *,int *),const char * class,const char * comment,int * status)3462 void astSetDump_( AstObjectVtab *vtab,
3463                   void (* dump)( AstObject *, AstChannel *, int * ),
3464                   const char *class, const char *comment, int *status ) {
3465 /*
3466 *+
3467 *  Name:
3468 *     astSetDump
3469 
3470 *  Purpose:
3471 *     Declare a dump function for an Object.
3472 
3473 *  Type:
3474 *     Protected function.
3475 
3476 *  Synopsis:
3477 *     #include "object.h"
3478 *     void astSetDump( AstObjectVtab *vtab,
3479 *                      void (* dump)( AstObject *, AstChannel * ),
3480 *                      const char *class, const char *comment )
3481 
3482 *  Class Membership:
3483 *     Object method.
3484 
3485 *  Description:
3486 *     This function is provided so that class definitions can declare
3487 *     a dump function to be associated with an Object that is being
3488 *     constructed.  When the astWrite (or astShow or astToString) method
3489 *     is later used to write the Object to a Channel, the dump function
3490 *     of each class to which the Object belongs will be invoked in turn
3491 *     (working down the class hierarchy). The dump function is passed
3492 *     pointers to the Object and the output Channel. It should write
3493 *     out any internal values (e.g. instance variables) for its class
3494 *     that are to be kept (using the protected astWrite... methods of
3495 *     the Channel) and return void.
3496 
3497 *  Parameters:
3498 *     vtab
3499 *        Pointer to the Object's virtual function table, in which the
3500 *        dump function's pointer is to be stored for future use.
3501 *     dump
3502 *        Pointer to the dump function.
3503 *     class
3504 *        Pointer to a constant null-terminated string (residing in
3505 *        static memory) containing the name of the class that is
3506 *        declaring the dump function.
3507 *     comment
3508 *        Pointer to a constant null-terminated string (residing in
3509 *        static memory) containing a comment to associate with the
3510 *        dump function.  This should normally describe the purpose of
3511 *        the class that is declaring the dump function.
3512 
3513 *  Notes:
3514 *     - Dump functions should check the global error status in the
3515 *     normal way and should set it (and report an error) if they fail.
3516 *-
3517 */
3518 
3519 /* Check the global error status. */
3520    if ( !astOK ) return;
3521 
3522 /* Indicate that subsequent memory allocations may never be freed (other
3523    than by any AST exit handler). */
3524    astBeginPM;
3525 
3526 /* Expand the arrays of pointers to dump functions and related data in
3527    the virtual function table (if necessary) to accommodate the new
3528    one. */
3529    vtab->dump = astGrow( vtab->dump, vtab->ndump + 1,
3530                          sizeof( void (*)( AstObject *, AstChannel * ) ) );
3531    vtab->dump_class = astGrow( vtab->dump_class, vtab->ndump + 1,
3532                                sizeof( char * ) );
3533    vtab->dump_comment = astGrow( vtab->dump_comment, vtab->ndump + 1,
3534                                  sizeof( char * ) );
3535 
3536 /* If OK, store the new pointers (to the dump function, class name and
3537    comment) and increment the count of dump functions. */
3538    if ( astOK ) {
3539       vtab->dump[ vtab->ndump ] = dump;
3540       vtab->dump_class[ vtab->ndump ] = class;
3541       vtab->dump_comment[ vtab->ndump ] = comment;
3542       vtab->ndump++;
3543    }
3544 
3545 /* Mark the end of the section in which memory allocations may never be
3546    freed (other than by any AST exit handler). */
3547    astEndPM;
3548 }
3549 
astSetProxy_(AstObject * this,void * proxy,int * status)3550 void astSetProxy_( AstObject *this, void *proxy, int *status ) {
3551 /*
3552 *+
3553 *  Name:
3554 *     astSetProxy
3555 
3556 *  Purpose:
3557 *     Store a pointer to the foreign language proxy used to represent a
3558 *     given AST Object.
3559 
3560 *  Type:
3561 *     Undocumented public function.
3562 
3563 *  Synopsis:
3564 *     #include "object.h"
3565 *     void astSetProxy( AstObject *this, void *proxy )
3566 
3567 *  Class Membership:
3568 *     Object method.
3569 
3570 *  Description:
3571 *     This function stores the supplied pointer in the AST Object so that
3572 *     it can be retrieved later using astGetProxy.
3573 *
3574 *     The supplied pointer should point to a structure that is used
3575 *     to represent the AST Object within some external system. It is
3576 *     expected that the external system will check each object reference
3577 *     returned by AST to see if it has an associated proxy object. If not
3578 *     (i.e. if astGetProxy returns NULL), a new external object will be
3579 *     created to represent the AST Object, and a pointer to it will be
3580 *     stored in the AST Object using astSetProxy. If the AST Object
3581 *     already has a proxy, the AST reference is annulled and the existing
3582 *     proxy object is used by the external system.
3583 
3584 *  Parameters:
3585 *     this
3586 *        Pointer to the Object.
3587 *     proxy
3588 *        Pointer to the proxy object, or NULL.
3589 
3590 *  Notes:
3591 *     - The suppied pointer is not used within AST itself, other than to
3592 *     be returned by the astGetProxy method.
3593 *     - This function is public, but is currently undocumented since it
3594 *     is only of interest to people writing AST interfaces for other
3595 *     languages.
3596 *-
3597 */
3598    if( !astOK ) return;
3599    this->proxy = proxy;
3600 }
3601 
astSetVtab_(AstObject * this,AstObjectVtab * vtab,int * status)3602 void astSetVtab_( AstObject *this, AstObjectVtab *vtab, int *status ) {
3603 /*
3604 *+
3605 *  Name:
3606 *     astSetVtab
3607 
3608 *  Purpose:
3609 *     Change the virtual function table associated with an Object.
3610 
3611 *  Type:
3612 *     Protected function.
3613 
3614 *  Synopsis:
3615 *     #include "object.h"
3616 *     void astSetVtab( AstObject *this, AstObjectVtab *vtab )
3617 
3618 *  Class Membership:
3619 *     Object method.
3620 
3621 *  Description:
3622 *     This function changes the virtual function table associated with an
3623 *     Object. This may be needed, for instance, if a super-class
3624 *     initialises a parent class structure with a NULL vtab, causing the
3625 *     vtab of the parent class to be used instead of the super-class.
3626 *     Whilst the super-class object is being constructed its inherited methods
3627 *     will be determined by the parent class. Once the super-class object
3628 *     has been constructed, it can invoke this fuction in order to
3629 *     set the vtab to the super-class vtab, thus causing the method
3630 *     implementations provided by the super-cvlass to be used.
3631 
3632 *  Parameters:
3633 *     this
3634 *        Pointer to the Object to be modified.
3635 *     vtab
3636 *        Pointer to the virtual function table to store in the Object.
3637 *-
3638 */
3639    if( this ) this->vtab = vtab;
3640 }
3641 
Same(AstObject * this,AstObject * that,int * status)3642 static int Same( AstObject *this, AstObject *that, int *status ) {
3643 /*
3644 *++
3645 *  Name:
3646 c     astSame
3647 f     AST_SAME
3648 
3649 *  Purpose:
3650 *     Test if two AST pointers refer to the same Object.
3651 
3652 *  Type:
3653 *     Public function.
3654 
3655 *  Synopsis:
3656 c     #include "object.h"
3657 c     int astSame( AstObject *this,  AstObject *that )
3658 f     RESULT = AST_SAME( THIS, THAT, STATUS )
3659 
3660 *  Class Membership:
3661 *     Object method.
3662 
3663 *  Description:
3664 c     This function returns a boolean result (0 or 1) to indicate
3665 f     This function returns a logical result to indicate
3666 *     whether two pointers refer to the same Object.
3667 
3668 *  Parameters:
3669 c     this
3670 f     THIS = INTEGER (Given)
3671 *        Pointer to the first Object.
3672 c     that
3673 f     THAT = INTEGER (Given)
3674 *        Pointer to the second Object.
3675 f     STATUS = INTEGER (Given and Returned)
3676 f        The global status.
3677 
3678 *  Returned Value:
3679 c     astSame()
3680 c        One if the two pointers refer to the same Object, otherwise zero.
3681 f     AST_SAME = LOGICAL
3682 f        .TRUE. if the two pointers refer to the same Object, otherwise
3683 f        .FALSE.
3684 
3685 *  Applicability:
3686 *     Object
3687 c        This function applies to all Objects.
3688 f        This routine applies to all Objects.
3689 
3690 *  Notes:
3691 *     - Two independent Objects that happen to be identical are not
3692 *     considered to be the same Object by this function.
3693 c     - A value of zero will be returned if this function is invoked
3694 c     with the AST error status set, or if it should fail for any reason.
3695 f     - A value of .FALSE. will be returned if this function is invoked
3696 f     with STATUS set to an error value, or if it should fail for any reason.
3697 *--
3698 */
3699 
3700 /* Check the global error status. */
3701    if ( !astOK ) return 0;
3702 
3703 /* Return the result. */
3704    return ( this == that ) ? 1 : 0;
3705 }
3706 
3707 /*
3708 *++
3709 *  Name:
3710 c     astSet<X>
3711 f     AST_SET<X>
3712 
3713 *  Purpose:
3714 *     Set an attribute value for an Object.
3715 
3716 *  Type:
3717 *     Public functions.
3718 
3719 *  Synopsis:
3720 c     #include "object.h"
3721 c     void astSet<X>( AstObject *this, const char *attrib, <X>type value )
3722 f     CALL AST_SET<X>( THIS, ATTRIB, VALUE, STATUS )
3723 
3724 *  Class Membership:
3725 *     Object methods.
3726 
3727 *  Description:
3728 c     This is a family of functions which set a specified attribute
3729 f     This is a family of routines which set a specified attribute
3730 *     value for an Object using one of several different data
3731 c     types. The type is selected by replacing <X> in the function name
3732 f     types. The type is selected by replacing <X> in the routine name
3733 c     by C, D, F, I or L, to supply a value in const char* (i.e. string),
3734 c     double, float, int, or long format, respectively.
3735 f     by C, D, I, L or R, to supply a value in Character, Double
3736 f     precision, Integer, Logical or Real format, respectively.
3737 *
3738 *     If possible, the value you supply is converted to the type of
3739 *     the attribute. If conversion is not possible, an error will
3740 *     result.
3741 
3742 *  Parameters:
3743 c     this
3744 f     THIS = INTEGER (Given)
3745 *        Pointer to the Object.
3746 c     attrib
3747 f     ATTRIB = CHARACTER * ( * ) (Given)
3748 c        Pointer to a null-terminated character string containing the
3749 c        name of the attribute whose value is to be set.
3750 f        A character string containing the name of the attribute whose
3751 f        value is to be set.
3752 c     value
3753 f     VALUE = <X>type (Given)
3754 c        The value to be set for the attribute, in the data type corresponding
3755 c        to <X> (or, in the case of astSetC, a pointer to a null-terminated
3756 c        character string containing this value).
3757 f        The value to be set for the attribute, in the data type corresponding
3758 f        to <X>.
3759 f     STATUS = INTEGER (Given and Returned)
3760 f        The global status.
3761 
3762 *  Applicability:
3763 *     Object
3764 c        These functions apply to all Objects.
3765 f        These routines apply to all Objects.
3766 
3767 *  Examples:
3768 c     astSetI( frame, "Preserve", 1 );
3769 c        Sets the Preserve attribute value for Object "frame" to 1.
3770 c     astSetC( plot, "Format(1)", "%.2g" );
3771 c        Sets the Format(1) attribute value for Object "plot" to the
3772 c        character string "%.2g".
3773 f     CALL AST_SETC( PLOT, 'Title', CVALUE, STATUS )
3774 f        Sets the Title attribute value for Object PLOT to the contents
3775 f        of the character variable CVALUE.
3776 f     CALL AST_SETL( FRAME, 'Preserve', .TRUE., STATUS );
3777 f        Sets the Preserve attribute value for Object FRAME to 1 (true).
3778 
3779 *  Notes:
3780 *     - Attribute names are not case sensitive and may be surrounded
3781 *     by white space.
3782 f     - The logical value .FALSE. will translate to a numerical attribute
3783 f     value of zero and logical .TRUE. will translate to one.
3784 *     - An error will result if an attempt is made to set a value for
3785 *     a read-only attribute.
3786 *--
3787 */
3788 
3789 /* Define a macro that expands to implement the astSetX_ member
3790    functions required. The arguments to this macro are:
3791 
3792       code
3793          The character that appears at the end of the function name.
3794       type
3795          The C type of the function "value" parameter.
3796       format
3797          A quoted string containing a sprintf format specifier that will
3798          format the supplied value as a character string. This format should
3799          consume 2 sprintf arguments: a field width and the value to be
3800          formatted.
3801       fmtlen
3802          The number of characters in the format specifier (above).
3803       fieldsz
3804          The value of the field width to be used by the format specifier.
3805 */
3806 #define MAKE_SETX(code,type,format,fmtlen,fieldsz) \
3807 void astSet##code##_( AstObject *this, const char *attrib, type value, int *status ) { \
3808 \
3809 /* Local Variables: */ \
3810    char *setting;                /* Pointer to attribute setting string */ \
3811    int len;                      /* Length of attribute name */ \
3812 \
3813 /* Check the global status. */ \
3814    if ( !astOK ) return; \
3815 \
3816 /* Obtain the length of the attribute name and allocate memory to hold \
3817    this name plus the format specifier to be appended to it. */ \
3818    len = (int) astChrLen( attrib ); \
3819    setting = astMalloc( (size_t) ( len + fmtlen + 2 ) ); \
3820 \
3821 /* Make a copy of the attribute name in the allocated memory. */ \
3822    if ( astOK ) { \
3823       (void) memcpy( setting, attrib, (size_t) len ); \
3824       setting[ len ] = 0; \
3825 \
3826 /* Append "=", followed by the format specifier, to construct a \
3827    suitable "setting" string for use by astSet. */ \
3828       (void) strcat( setting, "=" format ); \
3829 \
3830 /* Invoke astSet to set the attribute value. */ \
3831       astSet( this, setting, status, fieldsz, value ); \
3832    } \
3833 \
3834 /* Free the allocated memory. */ \
3835    setting = astFree( setting ); \
3836 }
3837 
3838 /* Use this macro to create all the SetX_ private member functions. */
3839 MAKE_SETX(D,double,"%.*g",4,DBL_DIG)
3840 MAKE_SETX(F,float,"%.*g",4,FLT_DIG)
3841 MAKE_SETX(I,int,"%.*d",4,1)
3842 MAKE_SETX(L,long,"%.*ld",5,1)
3843 
3844 
3845 /* The astSetC_ function is implemented separately so that commas can be
3846    handled. Since astSetC can only be used to set a single attribute
3847    value, we know that any commas in the supplied value are included
3848    within the attribuite value, rather than being used as delimiters
3849    between adjacent attribute settings. To avoid VSet using them as
3850    delimiters, they are replaced here by '\r' before calling astSet, and
3851    VSet then converts them back to commas. */
3852 
astSetC_(AstObject * this,const char * attrib,const char * value,int * status)3853 void astSetC_( AstObject *this, const char *attrib, const char *value, int *status ) {
3854 
3855 /* Local Variables: */
3856    char *d;                      /* Pointer to next setting character */
3857    char *newv;                   /* Pointer to new attribute value string */
3858    char *setting;                /* Pointer to attribute setting string */
3859    const char *c;                /* Pointer to next value character */
3860    int len;                      /* Length of attribute name */
3861 
3862 /* Check the global status. */
3863    if ( !astOK ) return;
3864 
3865 /* Produce a copy of the supplied attribute value in which any commas
3866    are replaced by carriage returns ("\r"). */
3867    newv = astMalloc( (size_t)( strlen( value ) + 1 ) );
3868    if( newv ) {
3869       d = newv;
3870       c = value;
3871       while( *c ) {
3872          if( *c == ',' ) {
3873             *d = '\r';
3874          } else {
3875             *d = *c;
3876          }
3877          c++;
3878          d++;
3879       }
3880       *d = 0;
3881 
3882 /* Obtain the length of the attribute name and allocate memory to hold
3883    this name plus the format specifier to be appended to it. */
3884       len = (int) astChrLen( attrib );
3885       setting = astMalloc( (size_t) ( len + 5 ) );
3886 
3887 /* Make a copy of the attribute name in the allocated memory. */
3888       if ( astOK ) {
3889          (void) memcpy( setting, attrib, (size_t) len );
3890          setting[ len ] = 0;
3891 
3892 /* Append "=", followed by the format specifier, to construct a
3893    suitable "setting" string for use by astSet. */
3894          (void) strcat( setting, "=%*s" );
3895 
3896 /* Invoke astSet to set the attribute value. */
3897          astSet( this, setting, status, 0, newv );
3898       }
3899 
3900 /* Free the allocated memory. */
3901       setting = astFree( setting );
3902    }
3903    newv = astFree( newv );
3904 }
3905 
Show(AstObject * this,int * status)3906 static void Show( AstObject *this, int *status ) {
3907 /*
3908 *++
3909 *  Name:
3910 c     astShow
3911 f     AST_SHOW
3912 
3913 *  Purpose:
3914 *     Display a textual representation of an Object on standard output.
3915 
3916 *  Type:
3917 *     Public function.
3918 
3919 *  Synopsis:
3920 c     #include "object.h"
3921 c     void astShow( AstObject *this )
3922 f     CALL AST_SHOW( THIS, STATUS )
3923 
3924 *  Class Membership:
3925 *     Object method.
3926 
3927 *  Description:
3928 c     This function displays a textual description of any AST Object
3929 f     This routine displays a textual description of any AST Object
3930 *     on standard output. It is provided primarily as an aid to
3931 *     debugging.
3932 
3933 *  Parameters:
3934 c     this
3935 f     THIS = INTEGER (Given)
3936 *        Pointer to the Object to be displayed.
3937 f     STATUS = INTEGER (Given and Returned)
3938 f        The global status.
3939 
3940 *  Applicability:
3941 *     Object
3942 c        This function applies to all Objects.
3943 f        This routine applies to all Objects.
3944 *--
3945 */
3946 
3947 /* Local Variables: */
3948    AstChannel *channel;          /* Pointer to output Channel */
3949 
3950 /* Check the global error status. */
3951    if ( !astOK ) return;
3952 
3953 /* Create a Channel which will write to standard output. */
3954    channel = astChannel( NULL, NULL, "", status );
3955 
3956 /* Write the Object to the Channel. */
3957    astWrite( channel, this );
3958 
3959 /* Annul the Channel pointer. */
3960    channel = astAnnul( channel );
3961 }
3962 
astTest_(AstObject * this,const char * attrib,int * status)3963 int astTest_( AstObject *this, const char *attrib, int *status ) {
3964 /*
3965 *++
3966 *  Name:
3967 c     astTest
3968 f     AST_TEST
3969 
3970 *  Purpose:
3971 *     Test if an Object attribute value is set.
3972 
3973 *  Type:
3974 *     Public function.
3975 
3976 *  Synopsis:
3977 c     #include "object.h"
3978 c     int astTest( AstObject *this, const char *attrib )
3979 f     RESULT = AST_TEST( THIS, ATTRIB, STATUS )
3980 
3981 *  Class Membership:
3982 *     Object method.
3983 
3984 *  Description:
3985 c     This function returns a boolean result (0 or 1) to indicate
3986 f     This function returns a logical result to indicate
3987 *     whether a value has been explicitly set for one of an Object's
3988 *     attributes.
3989 
3990 *  Parameters:
3991 c     this
3992 f     THIS = INTEGER (Given)
3993 *        Pointer to the Object.
3994 c     attrib
3995 f     ATTRIB = CHARACTER * ( * ) (Given)
3996 c        Pointer to a null-terminated character string containing
3997 c        the name of the attribute to be tested.
3998 f        A character string containing the name of the attribute to be
3999 f        tested.
4000 f     STATUS = INTEGER (Given and Returned)
4001 f        The global status.
4002 
4003 *  Returned Value:
4004 c     astTest()
4005 c        One if a value has previously been explicitly set for the attribute
4006 c        (and hasn't been cleared), otherwise zero.
4007 f     AST_TEST = LOGICAL
4008 f        .TRUE. if a value has previously been explicitly set for the
4009 f        attribute (and hasn't been cleared), otherwise .FALSE..
4010 
4011 *  Applicability:
4012 *     Object
4013 c        This function applies to all Objects.
4014 f        This routine applies to all Objects.
4015 
4016 *  Notes:
4017 *     - Attribute names are not case sensitive and may be surrounded
4018 *     by white space.
4019 c     - A value of zero will be returned if this function is invoked
4020 f     - A value of .FALSE. will be returned if this function is invoked
4021 c     with the AST error status set, or if it should fail for any reason.
4022 f     with STATUS set to an error value, or if it should fail for any reason.
4023 c     - A value of zero will also be returned if this function is used
4024 f     - A value of .FALSE. will also be returned if this function is used
4025 *     to test a read-only attribute, although no error will result.
4026 *--
4027 */
4028 
4029 /* Local Variables: */
4030    char *buff;                   /* Pointer to character buffer */
4031    int i;                        /* Loop counter for characters */
4032    int j;                        /* Non-blank character count */
4033    int len;                      /* Length of attrib string */
4034    int result;                   /* Result value to return */
4035 
4036 /* Initialise. */
4037    result = 0;
4038 
4039 /* Check the global error status. */
4040    if ( !astOK ) return result;
4041 
4042 /* Obtain the length of the attrib string. */
4043    len = (int) strlen( attrib );
4044 
4045 /* Allocate memory and store a copy of the string. */
4046    buff = astStore( NULL, attrib, (size_t) ( len + 1 ) );
4047    if ( astOK ) {
4048 
4049 /* Remove white space and upper case characters. */
4050       for ( i = j = 0; buff[ i ]; i++ ) {
4051          if ( !isspace( buff[ i ] ) ) buff[ j++ ] = tolower( buff[ i ] );
4052       }
4053 
4054 /* Terminate the attribute name and pass it to astTestAttrib to test
4055    the attribute. */
4056       buff[ j ] = '\0';
4057       result = astTestAttrib( this, buff );
4058    }
4059 
4060 /* Free the memory allocated for the string buffer. */
4061    buff = astFree( buff );
4062 
4063 /* If an error occurred, clear the result value. */
4064    if ( !astOK ) result = 0;
4065 
4066 /* Return the result. */
4067    return result;
4068 }
4069 
TestAttrib(AstObject * this,const char * attrib,int * status)4070 static int TestAttrib( AstObject *this, const char *attrib, int *status ) {
4071 /*
4072 *+
4073 *  Name:
4074 *     astTestAttrib
4075 
4076 *  Purpose:
4077 *     Test if a specified attribute value is set for an Object.
4078 
4079 *  Type:
4080 *     Protected virtual function.
4081 
4082 *  Synopsis:
4083 *     #include "object.h"
4084 *     int astTestAttrib( AstObject *this, const char *attrib )
4085 
4086 *  Class Membership:
4087 *     Object method.
4088 
4089 *  Description:
4090 *     This function returns a boolean result (0 or 1) to indicate whether
4091 *     a value has been set for one of an Object's attributes.
4092 
4093 *  Parameters:
4094 *     this
4095 *        Pointer to the Object.
4096 *     attrib
4097 *        Pointer to a null-terminated string specifying the attribute
4098 *        name.  This should be in lower case with no surrounding white
4099 *        space.
4100 
4101 *  Returned Value:
4102 *     One if a value has been set, otherwise zero.
4103 
4104 *  Notes:
4105 *     - A value of zero will be returned if this function is invoked
4106 *     with the global status set, or if it should fail for any reason.
4107 *-
4108 */
4109 
4110 /* Local Variables: */
4111    int result;                   /* Result value to return */
4112 
4113 /* Initialise. */
4114    result = 0;
4115 
4116 /* Check the global error status. */
4117    if ( !astOK ) return result;
4118 
4119 /* Check the attribute name and test the appropriate attribute. */
4120 
4121 /* ID. */
4122 /* --- */
4123    if ( !strcmp( attrib, "id" ) ) {
4124       result = astTestID( this );
4125 
4126 /* Ident. */
4127 /* ------ */
4128    } else if ( !strcmp( attrib, "ident" ) ) {
4129       result = astTestIdent( this );
4130 
4131 /* UseDefs */
4132 /* ------- */
4133    } else if ( !strcmp( attrib, "usedefs" ) ) {
4134       result = astTestUseDefs( this );
4135 
4136 /* Test if the attribute string matches any of the read-only
4137    attributes of this class. If it does, then return zero. */
4138    } else if ( !strcmp( attrib, "class" ) ||
4139                !strcmp( attrib, "nobject" ) ||
4140                !strcmp( attrib, "objsize" ) ||
4141                !strcmp( attrib, "refcount" ) ) {
4142       result = 0;
4143 
4144 /* Any attempt to test any other attribute is an error. */
4145    } else if( astOK ){
4146       astError( AST__BADAT, "astTest: The attribute name \"%s\" is invalid "
4147                "for a %s.", status, attrib, astGetClass( this ) );
4148    }
4149 
4150 /* Return the result, */
4151    return result;
4152 }
4153 
astTune_(const char * name,int value,int * status)4154 int astTune_( const char *name, int value, int *status ) {
4155 /*
4156 *++
4157 *  Name:
4158 c     astTune
4159 f     AST_TUNE
4160 
4161 *  Purpose:
4162 *     Set or get an integer-valued AST global tuning parameter.
4163 
4164 *  Type:
4165 *     Public function.
4166 
4167 *  Synopsis:
4168 c     #include "object.h"
4169 c     int astTune( const char *name, int value )
4170 f     RESULT = AST_TUNE( NAME, VALUE, STATUS )
4171 
4172 *  Class Membership:
4173 *     Object function.
4174 
4175 *  Description:
4176 *     This function returns the current value of an integer-valued AST
4177 *     global tuning parameter, optionally storing a new value for the
4178 *     parameter. For character-valued tuning parameters, see
4179 c     astTuneC.
4180 f     AST_TUNEC.
4181 
4182 *  Parameters:
4183 c     name
4184 f     NAME = CHARACTER * ( * ) (Given)
4185 *        The name of the tuning parameter (case-insensitive).
4186 c     value
4187 f     VALUE = INTEGER (Given)
4188 *        The new value for the tuning parameter. If this is AST__TUNULL,
4189 *        the existing current value will be retained.
4190 f     STATUS = INTEGER (Given and Returned)
4191 f        The global status.
4192 
4193 *  Returned Value:
4194 c     astTune()
4195 f     AST_TUNE = INTEGER
4196 c        The original value of the tuning parameter. A default value will
4197 *        be returned if no value has been set for the parameter.
4198 
4199 *  Tuning Parameters:
4200 *     ObjectCaching
4201 *        A boolean flag which indicates what should happen
4202 *        to the memory occupied by an AST Object when the Object is deleted
4203 *        (i.e. when its reference count falls to zero or it is deleted using
4204 c        astDelete).
4205 f        AST_DELETE).
4206 *        If this is zero, the memory is simply freed using the systems "free"
4207 *        function. If it is non-zero, the memory is not freed. Instead a
4208 *        pointer to it is stored in a pool of such pointers, all of which
4209 *        refer to allocated but currently unused blocks of memory. This allows
4210 *        AST to speed up subsequent Object creation by re-using previously
4211 *        allocated memory blocks rather than allocating new memory using the
4212 *        systems malloc function. The default value for this parameter is
4213 *        zero. Setting it to a non-zero value will result in Object memory
4214 *        being cached in future. Setting it back to zero causes any memory
4215 *        blocks currently in the pool to be freed. Note, this tuning parameter
4216 *        only controls the caching of memory used to store AST Objects. To
4217 *        cache other memory blocks allocated by AST, use MemoryCaching.
4218 *     MemoryCaching
4219 *        A boolean flag similar to ObjectCaching except
4220 *        that it controls caching of all memory blocks of less than 300 bytes
4221 *        allocated by AST (whether for internal or external use), not just
4222 *        memory used to store AST Objects.
4223 
4224 *  Notes:
4225 c     - This function attempts to execute even if the AST error
4226 c     status is set
4227 f     - This routine attempts to execute even if STATUS is set to an
4228 f     error value
4229 *     on entry, although no further error report will be
4230 *     made if it subsequently fails under these circumstances.
4231 *     - All threads in a process share the same AST tuning parameters
4232 *     values.
4233 *--
4234 */
4235 
4236    int result = AST__TUNULL;
4237 
4238    if( name ) {
4239 
4240       LOCK_MUTEX1;
4241 
4242       if( astChrMatch( name, "ObjectCaching" ) ) {
4243          result = object_caching;
4244          if( value != AST__TUNULL ) {
4245             object_caching = value;
4246             if( !object_caching ) EmptyObjectCache( status );
4247          }
4248 
4249       } else if( astChrMatch( name, "MemoryCaching" ) ) {
4250          result = astMemCaching( value );
4251 
4252       } else if( astOK ) {
4253          astError( AST__TUNAM, "astTune: Unknown AST tuning parameter "
4254                    "specified \"%s\".", status, name );
4255       }
4256 
4257       UNLOCK_MUTEX1;
4258 
4259    }
4260 
4261    return result;
4262 }
4263 
astTuneC_(const char * name,const char * value,char * buff,int bufflen,int * status)4264 void astTuneC_( const char *name, const char *value, char *buff,
4265                 int bufflen, int *status ) {
4266 /*
4267 *++
4268 *  Name:
4269 c     astTuneC
4270 f     AST_TUNEC
4271 
4272 *  Purpose:
4273 *     Set or get a character-valued AST global tuning parameter.
4274 
4275 *  Type:
4276 *     Public function.
4277 
4278 *  Synopsis:
4279 c     #include "object.h"
4280 c     void astTuneC( const char *name, const char *value, char *buff,
4281 c                    int bufflen )
4282 f     CALL AST_TUNEC( NAME, VALUE, BUFF, STATUS )
4283 
4284 *  Class Membership:
4285 *     Object function.
4286 
4287 *  Description:
4288 *     This function returns the current value of a character-valued
4289 *     AST global tuning parameter, optionally storing a new value
4290 *     for the parameter. For integer-valued tuning parameters, see
4291 c     astTune.
4292 f     AST_TUNE.
4293 
4294 *  Parameters:
4295 c     name
4296 f     NAME = CHARACTER * ( * ) (Given)
4297 *        The name of the tuning parameter (case-insensitive).
4298 c     value
4299 f     VALUE = CHARACTER * ( ) (Given)
4300 *        The new value for the tuning parameter. If this is
4301 f        AST__TUNULLC,
4302 c        NULL,
4303 *        the existing current value will be retained.
4304 c     buff
4305 f     BUFF = CHARACTER * ( ) (Given)
4306 *        A character string in which to return the original value of
4307 *        the tuning parameter. An error will be reported if the buffer
4308 *        is too small to hold the value.
4309 c        NULL may be supplied if the old value is not required.
4310 c     bufflen
4311 c        The size of the supplied "buff" array. Ignored if "buff" is NULL.
4312 f     STATUS = INTEGER (Given and Returned)
4313 f        The global status.
4314 
4315 *  Tuning Parameters:
4316 *     HRDel
4317 *        A string to be drawn following the hours field in a formatted
4318 *        sky axis value when "g" format is in use (see the Format
4319 *        attribute). This string may include escape sequences to produce
4320 *        super-scripts, etc. (see the Escapes attribute for details
4321 *        of the escape sequences allowed). The default value is
4322 *        "%-%^50+%s70+h%+" which produces a super-script "h".
4323 *     MNDel
4324 *        A string to be drawn following the minutes field in a formatted
4325 *        sky axis value when "g" format is in use. The default value is
4326 *        "%-%^50+%s70+m%+" which produces a super-script "m".
4327 *     SCDel
4328 *        A string to be drawn following the seconds field in a formatted
4329 *        sky axis value when "g" format is in use. The default value is
4330 *        "%-%^50+%s70+s%+" which produces a super-script "s".
4331 *     DGDel
4332 *        A string to be drawn following the degrees field in a formatted
4333 *        sky axis value when "g" format is in use. The default value is
4334 *        "%-%^53+%s60+o%+" which produces a super-script "o".
4335 *     AMDel
4336 *        A string to be drawn following the arc-minutes field in a formatted
4337 *        sky axis value when "g" format is in use. The default value is
4338 *        "%-%^20+%s85+'%+" which produces a super-script "'" (single quote).
4339 *     ASDel
4340 *        A string to be drawn following the arc-seconds field in a formatted
4341 *        sky axis value when "g" format is in use. The default value is
4342 *        "%-%^20+%s85+\"%+" which produces a super-script """ (double quote).
4343 *     EXDel
4344 *        A string to be drawn to introduce the exponent in a value when "g"
4345 *        format is in use. The default value is "10%-%^50+%s70+" which
4346 *        produces "10" followed by the exponent as a super-script.
4347 
4348 *  Notes:
4349 c     - This function attempts to execute even if the AST error
4350 c     status is set
4351 f     - This routine attempts to execute even if STATUS is set to an
4352 f     error value
4353 *     on entry, although no further error report will be
4354 *     made if it subsequently fails under these circumstances.
4355 *     - All threads in a process share the same AST tuning parameters
4356 *     values.
4357 *--
4358 */
4359 
4360 /* Local Variables: */
4361    char *p = NULL;
4362    int len;
4363 
4364 /* Check the name of a tuning parameter was supplied. */
4365    if( name ) {
4366 
4367 /* Serialise access to the tuning parameters since they are common to all
4368    threads. */
4369       LOCK_MUTEX1;
4370 
4371 /* Get a pointer to the buffer that holds the value of the requested
4372    tuning parameter. */
4373       if( astChrMatch( name, "hrdel" ) ) {
4374          p = hrdel;
4375       } else if( astChrMatch( name, "mndel" ) ) {
4376          p = mndel;
4377       } else if( astChrMatch( name, "scdel" ) ) {
4378          p = scdel;
4379       } else if( astChrMatch( name, "dgdel" ) ) {
4380          p = dgdel;
4381       } else if( astChrMatch( name, "amdel" ) ) {
4382          p = amdel;
4383       } else if( astChrMatch( name, "asdel" ) ) {
4384          p = asdel;
4385       } else if( astChrMatch( name, "exdel" ) ) {
4386          p = exdel;
4387 
4388 /* Report an error if an the tuning parameter name is unknown. */
4389       } else if( astOK ) {
4390          p = NULL;
4391          astError( AST__TUNAM, "astTuneC: Unknown AST tuning parameter "
4392                    "specified \"%s\".", status, name );
4393       }
4394 
4395 /* If the existing value was found. */
4396       if( p ) {
4397 
4398 /* And is to be returned in the supplied buffer... */
4399          if( buff ) {
4400 
4401 /* Check that the buffer is long enough. If so, copy the current value
4402    into the buffer, otherwise report an error. */
4403             len = strlen( p ) ;
4404             if( len < bufflen ) {
4405                strcpy( buff, p );
4406             } else {
4407                astError( AST__TUNAM, "astTuneC: Supplied string variable "
4408                          "is too small - the current '%s' value (%s) has "
4409                          "%d characters.", status, name, p, len );
4410             }
4411          }
4412 
4413 /* If a new value is to be stored.... */
4414          if( value ) {
4415 
4416 /* Report an error if it is too long to fit in the static buffer. */
4417             len = strlen( value ) ;
4418             if( len >= MAXLEN_TUNEC ) {
4419                astError( AST__TUNAM, "astTuneC: Supplied value for '%s' "
4420                          "(%s) is too long - must not be longer than %d "
4421                          "characters.", status, name, value, MAXLEN_TUNEC );
4422 
4423 /* Otherwise, copy the new value into the static buffer. */
4424             } else {
4425                strcpy( p, value );
4426             }
4427          }
4428       }
4429 
4430       UNLOCK_MUTEX1;
4431    }
4432 }
4433 
astFromString_(const char * string,int * status)4434 AstObject *astFromString_( const char *string, int *status ) {
4435 /*
4436 c++
4437 *  Name:
4438 *     astFromString
4439 
4440 *  Purpose:
4441 *     Re-create an Object from an in-memory serialisation
4442 
4443 *  Type:
4444 *     Public function.
4445 
4446 *  Synopsis:
4447 *     #include "object.h"
4448 *     AstObject *astFromString( const char *string )
4449 
4450 *  Class Membership:
4451 *     Object method.
4452 
4453 *  Description:
4454 *     This function returns a pointer to a new Object created from the
4455 *     supplied text string, which should have been created by astToString.
4456 
4457 *  Parameters:
4458 *     string
4459 *        Pointer to a text string holding an Object serialisation created
4460 *        previously by astToString.
4461 
4462 *  Returned Value:
4463 *     astFromString()
4464 *        Pointer to a new Object created from the supplied serialisation,
4465 *        or NULL if the serialisation was invalid, or an error occurred.
4466 
4467 c--
4468 */
4469 
4470 /* Local Variables: */
4471    StringData data;              /* Data passed to the source function */
4472    AstChannel *channel;          /* Pointer to output Channel */
4473    AstObject *result;            /* Pointer to returned Object */
4474 
4475 /* Check the global error status and supplied serialisation. */
4476    if ( !astOK || !string ) return NULL;
4477 
4478 /* Create a Channel which will read from the supplied serialisation. */
4479    channel = astChannel( FromStringSource, NULL, "", status );
4480 
4481 /* Initialise the data structure used to communicate with the source
4482    function, and store a pointer to it in the Channel. */
4483    data.ptr = (char *) string;
4484    data.buff = NULL;
4485    data.len = 0;
4486    astPutChannelData( channel, &data );
4487 
4488 /* Read an Object from the Channel. */
4489    result = astRead( channel );
4490 
4491 /* Annul the Channel pointer. */
4492    channel = astAnnul( channel );
4493 
4494 /* Free the line buffer. */
4495    data.buff = astFree( data.buff );
4496 
4497 /* Annul the returned Object if an error has occurred. */
4498    if( !astOK ) result = astAnnul( result );
4499 
4500 /* Return the Object pointer. */
4501    return result;
4502 }
4503 
FromStringSource(void)4504 static const char *FromStringSource( void ){
4505 /*
4506 *  Name:
4507 *     FromStringSource
4508 
4509 *  Purpose:
4510 *     A Channel source function for use by the astFromString method.
4511 
4512 *  Type:
4513 *     Private function.
4514 
4515 *  Synopsis:
4516 *     #include "object.h"
4517 *     result = FromStringSource( void )
4518 
4519 *  Class Membership:
4520 *     Object member function.
4521 
4522 *  Description:
4523 *     This function reads the next line of text from a serialisation and
4524 *     returns a pointer to it, or NULL if no lines remain.
4525 
4526 *  Returned Value:
4527 *     Pointer to the null terminated line of text or NULL if no lines
4528 *     remain.
4529 */
4530 
4531 /* Local Variables: */
4532    StringData *data;     /* Data passed to the sink function */
4533    char *nl;             /* Pointer to next newline character */
4534    int *status;          /* Pointer to local status value */
4535    int nc;               /* Number of characters to read from serialisation */
4536    int status_value;     /* Local status value */
4537 
4538 /* Set up the local status */
4539    status_value = 0;
4540    status = &status_value;
4541 
4542 /* Get a pointer to the structure holding a pointer to the next line, and
4543    to the buffer to return. */
4544    data = astChannelData;
4545 
4546 /* Return NULL if no text remains to be read. */
4547    if( !data->ptr || (data->ptr)[0] == 0 ) return NULL;
4548 
4549 /* Find the next newline (if any) in the serialisation. */
4550    nl = strchr( data->ptr, '\n' );
4551 
4552 /* Get the number of characters to copy. */
4553    nc = nl ? nl - data->ptr : strlen( data->ptr );
4554 
4555 /* Copy them into the returned buffer, including an extra character for
4556    the terminating null. */
4557    data->buff = astStore( data->buff, data->ptr, nc + 1 );
4558 
4559 /* Store the terminating null. */
4560    (data->buff)[ nc ] = 0;
4561 
4562 /* Update the pointer to the next character to read from the
4563    serialisation. */
4564    data->ptr = nl ? nl + 1 : NULL;
4565 
4566 /* Return the buffer. */
4567    return data->buff;
4568 }
4569 
VSet(AstObject * this,const char * settings,char ** text,va_list args,int * status)4570 static void VSet( AstObject *this, const char *settings, char **text,
4571                   va_list args, int *status ) {
4572 /*
4573 *+
4574 *  Name:
4575 *     astVSet
4576 
4577 *  Purpose:
4578 *     Set values for an Object's attributes.
4579 
4580 *  Type:
4581 *     Protected virtual function.
4582 
4583 *  Synopsis:
4584 *     #include "object.h"
4585 *     void astVSet( AstObject *this, const char *settings, char **text,
4586 *                   va_list args )
4587 
4588 *  Class Membership:
4589 *     Object method.
4590 
4591 *  Description:
4592 *     This function assigns a set of attribute values for an Object,
4593 *     the attributes and their values being specified by means of a
4594 *     string containing a comma-separated list of the form:
4595 *
4596 *        "attribute1 = value1, attribute2 = value2, ... "
4597 *
4598 *     Here, "attribute" specifies an attribute name and the value to
4599 *     the right of each "=" sign should be a suitable textual
4600 *     representation of the value to be assigned to that
4601 *     attribute. This will be interpreted according to the attribute's
4602 *     data type.
4603 *
4604 *     The string supplied may also contain "printf"-style format
4605 *     specifiers identified by a "%" sign in the usual way. If
4606 *     present, these will be substituted by values supplied as
4607 *     optional arguments (as a va_list variable argument list), using
4608 *     the normal "printf" rules, before the string is used.
4609 
4610 *  Parameters:
4611 *     this
4612 *        Pointer to the Object.
4613 *     settings
4614 *        Pointer to a null-terminated string containing a
4615 *        comma-separated list of attribute settings.
4616 *     text
4617 *        Pointer to a location at which to return a pointer to dynamic
4618 *        memory holding a copy of the expanded setting string. This memory
4619 *        should be freed using astFree when no longer needed. If a NULL
4620 *        pointer is supplied, no string is created.
4621 *     args
4622 *        The variable argument list which contains values to be
4623 *        substituted for any "printf"-style format specifiers that
4624 *        appear in the "settings" string.
4625 
4626 *  Notes:
4627 *     - Attribute names are not case sensitive.
4628 *     - White space may surround attribute names and will be ignored.
4629 *     - White space may also surround attribute values where it will
4630 *     be ignored (except for string-valued attributes where it is
4631 *     significant and forms part of the value to be assigned).
4632 *     - After this function has substituted values for "printf"-style
4633 *     format specifiers it splits the "settings" string into
4634 *     individual attribute settings which it passes one at a time to
4635 *     the protected astSetAttrib method (after removal of white space
4636 *     and conversion of attribute names to lower case). The
4637 *     astSetAttrib method should therefore be extended by derived
4638 *     classes which define new attributes, and this will allow the
4639 *     astVSet (and astSet) methods to have access to those attributes.
4640 *     - This function provides the same functionality as the astSet
4641 *     public method but accepts a va_list variable argument list
4642 *     instead of a variable number of arguments. It is provided for
4643 *     use by functions in other class implementations which accept a
4644 *     variable number of arguments and must therefore pass their
4645 *     argument list to this method in va_list form.
4646 *-
4647 */
4648 
4649 /* Local Constants: */
4650    const int min_buff_len = 1024; /* Minimum size of formatting buffer */
4651 #define ERRBUF_LEN 80
4652 
4653 /* Local Variables: */
4654    char errbuf[ ERRBUF_LEN ];    /* Buffer for system error message */
4655    char *errstat;                /* Pointer to error message */
4656    char *assign;                 /* Pointer to assigment substring */
4657    char *assign_end;             /* Pointer to null at end of assignment */
4658    char *buff1;                  /* Pointer to temporary string buffer */
4659    char *buff2;                  /* Pointer to temporary string buffer */
4660    char *buff3;                  /* Pointer to temporary string buffer */
4661    char *eq1;                    /* Pointer to 1st equals sign */
4662    int buff_len;                 /* Length of temporary buffer */
4663    int i;                        /* Loop counter for characters */
4664    int j;                        /* Offset for revised assignment character */
4665    int len;                      /* Length of settings string */
4666    int lo;                       /* Convert next character to lower case? */
4667    int nc;                       /* Number of vsprintf output characters */
4668    int quoted;                   /* Are we in a quoted string? */
4669    int stat;                     /* Value of errno after an error */
4670    int tq;                       /* Test if the next non-space is a quote? */
4671 
4672 /* Initialise */
4673    if( text ) *text = NULL;
4674 
4675 /* Check the global error status. */
4676    if ( !astOK ) return;
4677 
4678 /* Obtain the length of the "settings" string and test it is not
4679    zero. If it is, there is nothing more to do. */
4680    len = (int) strlen( settings );
4681    if ( len != 0 ) {
4682 
4683 /* Allocate memory and store a copy of the string. */
4684       buff1 = astStore( NULL, settings, (size_t) ( len + 1 ) );
4685       if ( astOK ) {
4686 
4687 /* Convert each comma in the string into '\n'. This is to distinguish
4688    commas initially present from those introduced by the formatting to
4689    be performed below. We only do this if there is more than one equals
4690    sign in the setting string, since otherwise any commas are probably
4691    characters contained within a string attribute value. Ignore commas
4692    that occur within quoted strings. */
4693          eq1 = strchr( buff1, '=' );
4694          if( eq1 && strchr( eq1 + 1, '=' ) ) {
4695             quoted = 0;
4696             for ( i = 0; i < len; i++ ) {
4697                if( !quoted ) {
4698                   if ( buff1[ i ] == ',' ) {
4699                      buff1[ i ] = '\n';
4700                   } else if( buff1[ i ] == '"' ) {
4701                      quoted = 1;
4702                   }
4703                } else if( buff1[ i ] == '"' ){
4704                   quoted = 0;
4705                }
4706             }
4707          }
4708 
4709 /* Calculate a size for a further buffer twice the size of the first
4710    one.  Ensure it is not less than a minimum size and then allocate
4711    this buffer. */
4712          buff_len = 2 * len;
4713          if ( buff_len < min_buff_len ) buff_len = min_buff_len;
4714          buff2 = astMalloc( (size_t) ( buff_len + 1 ) );
4715          if ( astOK ) {
4716 
4717 /* Use "vsprintf" to substitute values for any format specifiers in
4718    the "settings" string, writing the resulting string into the second
4719    buffer. */
4720             errno = 0;
4721             nc = vsprintf( buff2, buff1, args );
4722 
4723 /* Get a copy of the expanded string to return as the function value and
4724    convert newlines back to commas. */
4725             if( text ) {
4726                *text = astStore( NULL, buff2, nc + 1 );
4727                if( *text ) {
4728                   for ( i = 0; i <= nc; i++ ) {
4729                      if ( (*text)[ i ] == '\n' ) (*text)[ i ] = ',';
4730                   }
4731                }
4732             }
4733 
4734 /* The possibilities for error detection are limited here, but check
4735    if an error value was returned and report an error. Include
4736    information from errno if it was set. */
4737             if ( nc < 0 ) {
4738                if( astOK ) {
4739                   stat = errno;
4740 
4741                   if( stat ) {
4742 #if HAVE_STRERROR_R
4743                      strerror_r( stat, errbuf, ERRBUF_LEN );
4744                      errstat = errbuf;
4745 #else
4746                      errstat = strerror( stat );
4747 #endif
4748                   } else {
4749                      *errbuf = 0;
4750                      errstat = errbuf;
4751                   }
4752 
4753                   astError( AST__ATSER, "astVSet(%s): Error formatting an "
4754                             "attribute setting%s%s.", status, astGetClass( this ),
4755                             stat? " - " : "", errstat );
4756                   astError( AST__ATSER, "The setting string was \"%s\".", status,
4757                             settings );
4758                }
4759 
4760 /* Also check that the result buffer did not overflow. If it did,
4761    memory will probably have been corrupted but this cannot be
4762    prevented with "vsprintf" (although we try and make the buffer
4763    large enough). Report the error and abort. */
4764             } else if ( nc > buff_len ) {
4765                if( astOK ) {
4766                   astError( AST__ATSER, "astVSet(%s): Internal buffer overflow "
4767                             "while formatting an attribute setting - the result "
4768                             "exceeds %d characters.", status, astGetClass( this ),
4769                             buff_len );
4770                   astError( AST__ATSER, "The setting string was \"%s\".", status,
4771                             settings );
4772                }
4773 
4774 /* If all is OK, loop to process each formatted attribute assignment
4775    (these are now separated by '\n' characters). */
4776 	    } else {
4777                assign = buff2;
4778                while ( assign ) {
4779 
4780 /* Change the '\n' at the end of each assignment to a null to
4781    terminate it. */
4782                   if ( ( assign_end = strchr( assign, '\n' ) ) ) {
4783                      *assign_end = '\0';
4784                   }
4785 
4786 /* Before making the assignment, loop to remove white space and upper
4787    case characters from the attribute name. */
4788                   lo = 1;
4789                   tq = -1;
4790                   quoted = 0;
4791                   for ( i = j = 0; assign[ i ]; i++ ) {
4792 
4793 /* Note when an '=' sign is encountered (this signals the end of the
4794    attribute name). */
4795                      if ( assign[ i ] == '=' ) lo = 0;
4796 
4797 /* Before the '=' sign, convert all characters to lower case and move
4798    everything to the left to eliminate white space. Afer the '=' sign,
4799    copy all characters to their new location unchanged, except for any
4800    delimiting quotes, which are removed. astSetC replaces commas in the
4801    attribute value by '\r' characters. Reverse this now. */
4802                      if ( !lo || !isspace( assign[ i ] ) ) {
4803                         if( assign[ i ] == '\r' ) {
4804                            assign[ j++ ] = ',';
4805 
4806                         } else if( lo ) {
4807                            assign[ j++ ] = tolower( assign[ i ] );
4808 
4809                         } else {
4810                            assign[ j++ ] = assign[ i ];
4811 
4812                            if( tq > 0 && !isspace( assign[ i ] ) ) {
4813                               if( assign[ i ] == '"' ) {
4814                                  quoted = 1;
4815                                  j--;
4816                               }
4817                               tq = 0;
4818                            }
4819 
4820                         }
4821                      }
4822 
4823 /* If the current character is the initial '=' sign, set "tq" positive,
4824    meaning "check if the next non-space character is a quote". */
4825                      if ( assign[ i ] == '=' && tq == -1 ) tq = 1;
4826                   }
4827 
4828 /* if the value was quoted. remove the trailing quote. */
4829                   if( quoted ) {
4830                      j--;
4831                      while( isspace( assign[ j ] ) ) j--;
4832                      if( assign[ j ] == '"' ) j--;
4833                      j++;
4834                   }
4835 
4836 /* Terminate the revised assignment string and pass it to astSetAttrib
4837    to make the assignment (unless the string was all blank, in which
4838    case we ignore it). */
4839                   assign[ j ] = '\0';
4840                   if ( j ) {
4841 
4842 /* If there are no characters to the right of the equals sign append a
4843    space after the equals sign. Without this, a string such as "Title="
4844    would not be succesfully matched against the attribute name "Title"
4845    within SetAttrib. */
4846                      if( assign[ j - 1 ] == '=' ) {
4847                         buff3 = astStore( NULL, assign,
4848                                           (size_t) j + 2 );
4849                         if ( astOK ) {
4850                            buff3[ j ] = ' ';
4851                            buff3[ j + 1 ] = '\0';
4852                            astSetAttrib( this, buff3 );
4853                         }
4854                         buff3 = astFree( buff3 );
4855 
4856                      } else {
4857                         astSetAttrib( this, assign );
4858                      }
4859                   }
4860 
4861 /* Check for errors and abort if any assignment fails. Otherwise,
4862    process the next assignment substring. */
4863                   if ( !astOK ) break;
4864                   assign = assign_end ? assign_end + 1 : NULL;
4865                }
4866 	    }
4867          }
4868 
4869 /* Free the memory allocated for string buffers. */
4870          buff2 = astFree( buff2 );
4871       }
4872       buff1 = astFree( buff1 );
4873    }
4874 }
4875 #undef ERRBUF_LEN
4876 
4877 /* Attribute access functions. */
4878 /* --------------------------- */
4879 /*
4880 *att++
4881 *  Name:
4882 *     Class
4883 
4884 *  Purpose:
4885 *     Object class name.
4886 
4887 *  Type:
4888 *     Public attribute.
4889 
4890 *  Synopsis:
4891 *     Character string, read-only.
4892 
4893 *  Description:
4894 *     This attribute gives the name of the class to which an Object
4895 *     belongs.
4896 
4897 *  Applicability:
4898 *     Object
4899 *        All Objects have this attribute.
4900 *att--
4901 */
4902 
4903 /*
4904 *att++
4905 *  Name:
4906 *     ID
4907 
4908 *  Purpose:
4909 *     Object identification string.
4910 
4911 *  Type:
4912 *     Public attribute.
4913 
4914 *  Synopsis:
4915 *     String.
4916 
4917 *  Description:
4918 *     This attribute contains a string which may be used to identify
4919 *     the Object to which it is attached. There is no restriction on
4920 *     the contents of this string, which is not used internally by the
4921 *     AST library, and is simply returned without change when
4922 *     required. The default value is an empty string.
4923 *
4924 *     An identification string can be valuable when, for example,
4925 c     several Objects have been stored in a file (using astWrite) and
4926 f     several Objects have been stored in a file (using AST_WRITE) and
4927 c     are later retrieved (using astRead). Consistent use of the ID
4928 f     are later retrieved (using AST_READ). Consistent use of the ID
4929 *     attribute allows the retrieved Objects to be identified without
4930 *     depending simply on the order in which they were stored.
4931 *
4932 *     This attribute may also be useful during debugging, to
4933 c     distinguish similar Objects when using astShow to display them.
4934 f     distinguish similar Objects when using AST_SHOW to display them.
4935 
4936 *  Applicability:
4937 *     Object
4938 *        All Objects have this attribute.
4939 
4940 *  Notes:
4941 *     - Unlike most other attributes, the value of the ID attribute is
4942 *     not transferred when an Object is copied. Instead, its value is
4943 *     undefined (and therefore defaults to an empty string) in any
4944 *     copy. However, it is retained in any external representation of
4945 c     an Object produced by the astWrite function.
4946 f     an Object produced by the AST_WRITE routine.
4947 *att--
4948 */
4949 /* Clear the ID value by freeing the allocated memory and assigning a
4950    NULL pointer. */
4951 astMAKE_CLEAR(Object,ID,id,astFree( this->id ))
4952 
4953 /* If the ID value is not set, supply a default in the form of a
4954    pointer to the constant string "". */
4955 astMAKE_GET(Object,ID,const char *,NULL,( this->id ? this->id : "" ))
4956 
4957 /* Set an ID value by freeing any previously allocated memory,
4958    allocating new memory and storing the string. */
4959 astMAKE_SET(Object,ID,const char *,id,astStore( this->id, value,
4960                                                 strlen( value ) + (size_t) 1 ))
4961 
4962 /* The ID value is set if the pointer to it is not NULL. */
4963 astMAKE_TEST(Object,ID,( this->id != NULL ))
4964 
4965 /*
4966 *att++
4967 *  Name:
4968 *     Ident
4969 
4970 *  Purpose:
4971 *     Permanent Object identification string.
4972 
4973 *  Type:
4974 *     Public attribute.
4975 
4976 *  Synopsis:
4977 *     String.
4978 
4979 *  Description:
4980 *     This attribute is like the ID attribute, in that it contains a
4981 *     string which may be used to identify the Object to which it is
4982 *     attached. The only difference between ID and Ident is that Ident
4983 *     is transferred when an Object is copied, but ID is not.
4984 
4985 *  Applicability:
4986 *     Object
4987 *        All Objects have this attribute.
4988 
4989 *att--
4990 */
4991 /* Clear the Ident value by freeing the allocated memory and assigning a
4992    NULL pointer. */
4993 astMAKE_CLEAR(Object,Ident,ident,astFree( this->ident ))
4994 
4995 /* If the Ident value is not set, supply a default in the form of a
4996    pointer to the constant string "". */
4997 astMAKE_GET(Object,Ident,const char *,NULL,( this->ident ? this->ident : "" ))
4998 
4999 /* Set an Ident value by freeing any previously allocated memory,
5000    allocating new memory and storing the string. */
5001 astMAKE_SET(Object,Ident,const char *,ident,astStore( this->ident, value,
5002                                                 strlen( value ) + (size_t) 1 ))
5003 
5004 /* The Ident value is set if the pointer to it is not NULL. */
5005 astMAKE_TEST(Object,Ident,( this->ident != NULL ))
5006 
5007 /*
5008 *att++
5009 *  Name:
5010 *     UseDefs
5011 
5012 *  Purpose:
5013 *     Use default values for unspecified attributes?
5014 
5015 *  Type:
5016 *     Public attribute.
5017 
5018 *  Synopsis:
5019 *     Integer (boolean).
5020 
5021 *  Description:
5022 *     This attribute specifies whether default values should be used
5023 *     internally for object attributes which have not been assigned a
5024 *     value explicitly. If a non-zero value (the default) is supplied for
5025 *     UseDefs, then default values will be used for attributes which have
5026 *     not explicitly been assigned a value. If zero is supplied for UseDefs,
5027 *     then an error will be reported if an attribute for which no explicit
5028 *     value has been supplied is needed internally within AST.
5029 *
5030 *     Many attributes (including the UseDefs attribute itself) are unaffected
5031 *     by the setting of the UseDefs attribute, and default values will always
5032 *     be used without error for such attributes. The "Applicability:" section
5033 *     below lists the attributes which are affected by the setting of UseDefs.
5034 
5035 *     Note, UseDefs only affects access to attributes internally within
5036 *     AST. The public accessor functions such as
5037 c     astGetC
5038 f     AST_GETC
5039 *     is unaffected by the UseDefs attribute - default values will always
5040 *     be returned if no value has been set. Application code should use the
5041 c     astTest
5042 f     AST_TEST
5043 *     function if required to determine if a value has been set for an
5044 *     attribute.
5045 
5046 *  Applicability:
5047 *     Object
5048 *        All Objects have this attribute, but ignore its setting except
5049 *        as described below for individual classes.
5050 *     FrameSet
5051 *        The default value of UseDefs for a FrameSet is redefined to be
5052 *        the UseDefs value of its current Frame.
5053 *     CmpFrame
5054 *        The default value of UseDefs for a CmpFrame is redefined to be
5055 *        the UseDefs value of its first component Frame.
5056 *     Region
5057 *        The default value of UseDefs for a Region is redefined to be
5058 *        the UseDefs value of its encapsulated Frame.
5059 *     Frame
5060 *        If UseDefs is zero, an error is reported when aligning Frames if the
5061 *        Epoch, ObsLat or ObsLon attribute is required but has not been
5062 *        assigned a value explicitly.
5063 *     SkyFrame
5064 *        If UseDefs is zero, an error is reported when aligning SkyFrames
5065 *        if any of the following attributes are required but have not been
5066 *        assigned a value explicitly: Epoch, Equinox.
5067 *     SpecFrame
5068 *        If UseDefs is zero, an error is reported when aligning SpecFrames
5069 *        if any of the following attributes are required but have not been
5070 *        assigned a value explicitly: Epoch, RefRA, RefDec, RestFreq,
5071 *        SourceVel, StdOfRest.
5072 *     DSBSpecFrame
5073 *        If UseDefs is zero, an error is reported when aligning DSBSpecFrames
5074 *        or when accessing the ImagFreq attribute if any of the following
5075 *        attributes are required but have not been assigned a value explicitly:
5076 *        Epoch, DSBCentre, IF.
5077 *att--
5078 */
astMAKE_CLEAR(Object,UseDefs,usedefs,CHAR_MAX)5079 astMAKE_CLEAR(Object,UseDefs,usedefs,CHAR_MAX)
5080 astMAKE_GET(Object,UseDefs,int,1,((this->usedefs!=CHAR_MAX)?this->usedefs:1))
5081 astMAKE_SET(Object,UseDefs,int,usedefs,((value)?1:0))
5082 astMAKE_TEST(Object,UseDefs,(this->usedefs!=CHAR_MAX))
5083 
5084 /*
5085 *att++
5086 *  Name:
5087 *     Nobject
5088 
5089 *  Purpose:
5090 *     Number of Objects in class.
5091 
5092 *  Type:
5093 *     Public attribute.
5094 
5095 *  Synopsis:
5096 *     Integer, read-only.
5097 
5098 *  Description:
5099 *     This attribute gives the total number of Objects currently in
5100 *     existence in the same class as the Object whose attribute value
5101 *     is requested. This count does not include Objects which belong
5102 *     to derived (more specialised) classes.
5103 *
5104 *     This attribute is mainly intended for debugging. It can be used
5105 *     to detect whether Objects which should have been deleted have,
5106 *     in fact, been deleted.
5107 
5108 *  Applicability:
5109 *     Object
5110 *        All Objects have this attribute.
5111 *att--
5112 */
5113 
5114 /*
5115 *att++
5116 *  Name:
5117 *     ObjSize
5118 
5119 *  Purpose:
5120 *     The in-memory size of the Object.
5121 
5122 *  Type:
5123 *     Public attribute.
5124 
5125 *  Synopsis:
5126 *     Integer, read-only.
5127 
5128 *  Description:
5129 *     This attribute gives the total number of bytes of memory used by
5130 *     the Object. This includes any Objects which are encapsulated within
5131 *     the supplied Object.
5132 
5133 *  Applicability:
5134 *     Object
5135 *        All Objects have this attribute.
5136 *att--
5137 */
5138 
5139 /*
5140 *att++
5141 *  Name:
5142 *     RefCount
5143 
5144 *  Purpose:
5145 *     Count of active Object pointers.
5146 
5147 *  Type:
5148 *     Public attribute.
5149 
5150 *  Synopsis:
5151 *     Integer, read-only.
5152 
5153 *  Description:
5154 *     This attribute gives the number of active pointers associated
5155 *     with an Object. It is modified whenever pointers are created or
5156 c     annulled (by astClone, astAnnul or astEnd for example). The count
5157 f     annulled (by AST_CLONE, AST_ANNUL or AST_END for example). The count
5158 *     includes the initial pointer issued when the Object was created.
5159 *
5160 *     If the reference count for an Object falls to zero as the result
5161 *     of annulling a pointer to it, then the Object will be deleted.
5162 
5163 *  Applicability:
5164 *     Object
5165 *        All Objects have this attribute.
5166 *att--
5167 */
5168 
5169 /* Standard class functions. */
5170 /* ========================= */
5171 /*
5172 *+
5173 *  Name:
5174 *     astCheck<Class>
5175 
5176 *  Purpose:
5177 *     Validate class membership.
5178 
5179 *  Type:
5180 *     Protected function.
5181 
5182 *  Synopsis:
5183 *     #include "class.h"
5184 *     Ast<Class> *astCheck<Class>( Ast<Class> *this )
5185 
5186 *  Class Membership:
5187 *     <Class> class function.
5188 
5189 *  Description:
5190 *     This function validates membership of the class called <Class>,
5191 *     or of any class derived from it. If the Object is not a member,
5192 *     or the pointer supplied does not identify a valid Object, an
5193 *     error is reported and the global error status is set to
5194 *     AST__OBJIN.
5195 
5196 *  Parameters:
5197 *     this
5198 *        Pointer to the Object.
5199 
5200 *  Returned Value:
5201 *     The function always returns a copy of the "this" pointer
5202 *     (whether it finds it valid or not).
5203 
5204 *  Notes:
5205 *     - Each class provides a function (astCheck<Class>) of this form,
5206 *     where <Class> and <class> are replaced by the class name (with
5207 *     appropriate capitalisation).
5208 *     - Normal error status checking is performed, so this function
5209 *     will not execute if the global error status is set on entry (the
5210 *     usual function value will be returned, however).
5211 *     - This function is primarily intended for validating Object
5212 *     pointers passed to member functions as part of a class
5213 *     interface.
5214 *-
5215 */
5216 
5217 /* Implement the astCheckObject function using the macro defined for this
5218    purpose in the "object.h" header file. */
5219 astMAKE_CHECK(Object)
5220 
5221 int astIsAObject_( const AstObject *this, int *status ) {
5222 /*
5223 *++
5224 *  Name:
5225 c     astIsA<Class>
5226 f     AST_ISA<CLASS>
5227 
5228 *  Purpose:
5229 *     Test membership of a class by an Object.
5230 
5231 *  Type:
5232 *     Public function.
5233 
5234 *  Synopsis:
5235 c     #include "class.h"
5236 c     int astIsA<Class>( const Ast<Class> *this )
5237 f     RESULT = AST_ISA<CLASS>( THIS, STATUS )
5238 
5239 *  Class Membership:
5240 *     Class function.
5241 
5242 *  Description:
5243 *     This is a family of functions which test whether an Object is a
5244 c     member of the class called <Class>, or of any class derived from
5245 f     member of the class called <CLASS>, or of any class derived from
5246 *     it.
5247 
5248 *  Parameters:
5249 c     this
5250 f     THIS = INTEGER (Given)
5251 *        Pointer to the Object.
5252 f     STATUS = INTEGER (Given and Returned)
5253 f        The global status.
5254 
5255 *  Returned Value:
5256 c     astIsA<Class>()
5257 c        One if the Object belongs to the class called <Class> (or to a
5258 c        class derived from it), otherwise zero.
5259 f     AST_ISA<CLASS> = LOGICAL
5260 f        .TRUE. if the Object belongs to the class called <CLASS> (or to
5261 f        a class derived from it), otherwise .FALSE..
5262 
5263 *  Applicability:
5264 *     Object
5265 *        These functions apply to all Objects.
5266 
5267 *  Examples:
5268 c     member = astIsAFrame( obj );
5269 c        Tests whether Object "obj" is a member of the Frame class, or
5270 c        of any class derived from a Frame.
5271 f     MEMBER = AST_ISAFRAME( OBJ, STATUS );
5272 f        Tests whether Object OBJ is a member of the Frame class, or
5273 f        of any class derived from a Frame.
5274 
5275 *  Notes:
5276 c     - Every AST class provides a function (astIsA<Class>) of this
5277 c     form, where <Class> should be replaced by the class name.
5278 f     - Every AST class provides a function (AST_ISA<CLASS>) of this
5279 f     form, where <CLASS> should be replaced by the class name.
5280 c     - This function attempts to execute even if the AST error status
5281 c     is set
5282 f     - This function attempts to execute even if STATUS is set to an
5283 f     error value
5284 *     on entry, although no further error report will be made
5285 *     if it subsequently fails under these circumstances.
5286 c     - A value of zero will be returned if this function should fail
5287 f     - A value of .FALSE. will be returned if this function should fail
5288 *     for any reason. In particular, it will fail if the pointer
5289 *     supplied does not identify an Object of any sort.
5290 *--
5291 */
5292 
5293 /* Local Variables: */
5294    int valid;                    /* Valid object? */
5295 
5296 /* Since this is the base class, the implementation of this function
5297    differs from that in derived classes (in that it fails and
5298    potentially reports an error if the returned result is zero). */
5299 
5300 /* Initialise. */
5301    valid = 0;
5302 
5303 /* Check if a NULL pointer was supplied (this can never be valid). If
5304    OK, check if the Object contains the correct "magic number" in its
5305    check field. */
5306    if ( !this || ( this->check != Magic( this, this->size, status ) ) ) {
5307 
5308 /* If it is not a valid Object, then report an error (but only if the
5309    global error status has not already been set). */
5310       if ( astOK ) {
5311          astError( AST__OBJIN, "astIsAObject(%s): Invalid Object pointer "
5312                    "given (points at address %p).", status, astGetClass( this ),
5313                    (void *) this );
5314       }
5315 
5316 /* Otherwise, note that the Object is valid. */
5317    } else {
5318       valid = 1;
5319    }
5320 
5321 /* Return the result. */
5322    return valid;
5323 }
5324 
astInitObjectVtab_(AstObjectVtab * vtab,const char * name,int * status)5325 void astInitObjectVtab_(  AstObjectVtab *vtab, const char *name, int *status ) {
5326 /*
5327 *+
5328 *  Name:
5329 *     astInitObjectVtab
5330 
5331 *  Purpose:
5332 *     Initialise a virtual function table for a Object.
5333 
5334 *  Type:
5335 *     Protected function.
5336 
5337 *  Synopsis:
5338 *     #include "object.h"
5339 *     void astInitObjectVtab( AstObjectVtab *vtab, const char *name )
5340 
5341 *  Class Membership:
5342 *     Object vtab initialiser.
5343 
5344 *  Description:
5345 *     This function initialises the component of a virtual function
5346 *     table which is used by the Object class.
5347 
5348 *  Parameters:
5349 *     vtab
5350 *        Pointer to the virtual function table.
5351 *     name
5352 *        Pointer to a constant null-terminated character string which contains
5353 *        the name of the class to which the virtual function table belongs (it
5354 *        is this pointer value that will subsequently be returned by the Object
5355 *        astClass function).
5356 *-
5357 */
5358 
5359 /* Local Variables: */
5360    astDECLARE_GLOBALS            /* Thread-specific global data */
5361    int ivtab;                    /* Index of next entry in known_vtabs */
5362 
5363 /* Check the local error status. */
5364    if ( !astOK ) return;
5365 
5366 /* Get a pointer to Thread-specific global data. */
5367    astGET_GLOBALS(NULL);
5368 
5369 /* Initialise the contents of the class identifier. Since this is the
5370    base class, we assign null values to the fields. */
5371    vtab->id.check = NULL;
5372    vtab->id.parent = NULL;
5373 
5374 /* Store pointers to the member functions (implemented here) that provide
5375    virtual methods for this class. */
5376    vtab->Clear = Clear;
5377    vtab->ClearAttrib = ClearAttrib;
5378    vtab->ClearID = ClearID;
5379    vtab->ClearIdent = ClearIdent;
5380    vtab->Dump = Dump;
5381    vtab->Equal = Equal;
5382    vtab->GetAttrib = GetAttrib;
5383    vtab->GetID = GetID;
5384    vtab->GetIdent = GetIdent;
5385    vtab->HasAttribute = HasAttribute;
5386    vtab->Same = Same;
5387    vtab->SetAttrib = SetAttrib;
5388    vtab->SetID = SetID;
5389    vtab->SetIdent = SetIdent;
5390    vtab->Show = Show;
5391    vtab->TestAttrib = TestAttrib;
5392    vtab->TestID = TestID;
5393    vtab->TestIdent = TestIdent;
5394    vtab->EnvSet = EnvSet;
5395    vtab->VSet = VSet;
5396    vtab->Cast = Cast;
5397    vtab->GetObjSize = GetObjSize;
5398    vtab->CleanAttribs = CleanAttribs;
5399 
5400    vtab->TestUseDefs = TestUseDefs;
5401    vtab->SetUseDefs = SetUseDefs;
5402    vtab->ClearUseDefs = ClearUseDefs;
5403    vtab->GetUseDefs = GetUseDefs;
5404 
5405 #if defined(THREAD_SAFE)
5406    vtab->ManageLock = ManageLock;
5407 #endif
5408 
5409 /* Store the pointer to the class name. */
5410    vtab->class = name;
5411 
5412 /* Initialise the count of active objects and the number of destructors,
5413    copy constructors and dump functions. */
5414    vtab->nobject = 0;
5415    vtab->ndelete = 0;
5416    vtab->ncopy = 0;
5417    vtab->ndump = 0;
5418 
5419 /* Initialise the arrays of destructor, copy constructor and dump
5420    function pointers. */
5421    vtab->delete = NULL;
5422    vtab->copy = NULL;
5423    vtab->dump = NULL;
5424    vtab->dump_class = NULL;
5425    vtab->dump_comment = NULL;
5426 
5427 /* Initialise the default attributes to use when creating objects. */
5428    vtab->defaults = NULL;
5429 
5430 /* The virtual function table for each class contains a list of pointers
5431    to memory blocks which have previously been used to store an Object of
5432    the same class, but which have since been deleted using astDelete.
5433    These memory blocks are free to be re-used when a new Object of the
5434    same class is initialised. This saves on the overheads associated with
5435    continuously allocating small blocks of memory using malloc. */
5436    vtab->nfree = 0;
5437    vtab->free_list = NULL;
5438 
5439 /* Add the supplied virtual function table pointer to the end of the list
5440    of known vtabs. */
5441    ivtab = nvtab++;
5442 
5443    astBeginPM;
5444    known_vtabs = astGrow( known_vtabs, nvtab, sizeof( AstObjectVtab *) );
5445    astEndPM;
5446 
5447    if( astOK && known_vtabs ) known_vtabs[ ivtab ] = vtab;
5448 
5449 /* Fill a pointer value with zeros (not necessarily the same thing as a
5450    NULL pointer) for subsequent use. */
5451    (void) memset( &zero_ptr, 0, sizeof( AstObject * ) );
5452 
5453 /* If we have just initialised the vtab for the current class, indicate
5454    that the vtab is now initialised. */
5455    if( vtab == &class_vtab ) class_init = 1;
5456 }
5457 
astInitObject_(void * mem,size_t size,int init,AstObjectVtab * vtab,const char * name,int * status)5458 AstObject *astInitObject_( void *mem, size_t size, int init,
5459                            AstObjectVtab *vtab, const char *name, int *status ) {
5460 /*
5461 *+
5462 *  Name:
5463 *     astInitObject
5464 
5465 *  Purpose:
5466 *     Initialise an Object.
5467 
5468 *  Type:
5469 *     Protected function.
5470 
5471 *  Synopsis:
5472 *     #include "object.h"
5473 *     AstObject *astInitObject( void *mem, size_t size, int init,
5474 *                               AstObjectVtab *vtab, const char *name )
5475 
5476 *  Class Membership:
5477 *     Object initialiser.
5478 
5479 *  Description:
5480 *     This function is provided for use by class implementations to initialise
5481 *     a new Object. It allocates memory (if necessary) to accommodate the
5482 *     Object plus any additional data associated with the derived class. It
5483 *     then initialises an Object structure at the start of this memory. If the
5484 *     "init" flag is set, it also initialises the contents of a virtual
5485 *     function table for an Object at the start of the memory passed via the
5486 *     "vtab" parameter.
5487 
5488 *  Parameters:
5489 *     mem
5490 *        A pointer to the memory in which the Object is to be initialised.
5491 *        This must be of sufficient size to accommodate the Object data
5492 *        (sizeof(Object)) plus any data used by the derived class. If a value
5493 *        of NULL is given, this function will allocate the memory itself using
5494 *        the "size" parameter to determine its size.
5495 *     size
5496 *        The amount of memory used by the Object (plus derived class data).
5497 *        This will be used to allocate memory if a value of NULL is given for
5498 *        the "mem" parameter. This value is also stored in the Object
5499 *        structure, so a valid value must be supplied even if not required for
5500 *        allocating memory.
5501 *     init
5502 *        A logical flag indicating if the Object's virtual function table is
5503 *        to be initialised. If this value is non-zero, the virtual function
5504 *        table will be initialised by this function.
5505 *     vtab
5506 *        Pointer to the start of the virtual function table to be associated
5507 *        with the new Object.
5508 *     name
5509 *        Pointer to a constant null-terminated character string which contains
5510 *        the name of the class to which the new object belongs (it is this
5511 *        pointer value that will subsequently be returned by the Object
5512 *        astClass function).
5513 
5514 *  Returned Value:
5515 *     A pointer to the new Object.
5516 
5517 *  Notes:
5518 *     -  A null pointer will be returned if this function is invoked with the
5519 *     global error status set, or if it should fail for any reason.
5520 *-
5521 */
5522 
5523 /* Local Variables: */
5524    AstObject *new;               /* Pointer to new Object */
5525 
5526 /* Initialise. */
5527    new = NULL;
5528 
5529 /* Check the global error status. */
5530    if ( !astOK ) return new;
5531 
5532 /* Determine if memory must be allocated dynamically. If so, use the last
5533    block of memory in the list of previously allocated but currently
5534    unused blocks identified by the vtab "free_list" array, reducing the
5535    length of the free list by one, and nullifying the entry in the list
5536    for safety. If the list is originally empty, allocate memory for a new
5537    object using astMalloc. */
5538    if( !mem ) {
5539       if( object_caching ) {
5540          if( vtab->nfree > 0 ) {
5541             mem = vtab->free_list[ --(vtab->nfree) ];
5542             vtab->free_list[ vtab->nfree ] = NULL;
5543             if( astSizeOf( mem ) != size && astOK ) {
5544                astError( AST__INTER, "astInitObject(%s): Free block has size "
5545                          "%d but the %s requires %d bytes (internal AST "
5546                          "programming error).", status, vtab->class,
5547                          (int) astSizeOf( mem ), vtab->class, (int) size );
5548             }
5549          } else {
5550             mem = astMalloc( size );
5551          }
5552 
5553       } else {
5554          mem = astMalloc( size );
5555       }
5556 
5557 /* If memory had already been allocated, adjust the "size" value to match
5558    the size of the allocated memory. */
5559    } else {
5560       size = astSizeOf( mem );
5561    }
5562 
5563 /* Obtain a pointer to the new Object. */
5564    if ( astOK ) {
5565       new = (AstObject *) mem;
5566 
5567 /* Zero the entire new Object structure (to prevent accidental re-use
5568    of any of its values after deletion). */
5569       (void) memset( new, 0, size );
5570 
5571 /* If necessary, initialise the virtual function table. */
5572 /* ---------------------------------------------------- */
5573       if ( init ) astInitObjectVtab( vtab, name );
5574       if( astOK ) {
5575 
5576 /* Initialise the Object data. */
5577 /* --------------------------- */
5578 /* Store a unique "magic" value in the Object structure. This will be
5579    used (e.g. by astIsAObject) to determine if a pointer identifies a
5580    valid Object. Note that this differs from the practice in derived
5581    classes, where this number is stored in the virtual function
5582    table. We take a different approach here so that we need not follow
5583    a pointer to the virtual function table obtained from a structure
5584    that hasn't yet been validated as an Object. This minimises the
5585    risk of a memory access violation. */
5586          new->check = Magic( new, size, status );
5587 
5588 /* Associate the Object with its virtual function table. */
5589          new->vtab = vtab;
5590 
5591 /* Store the Object size and note if its memory was dynamically allocated. */
5592          new->size = size;
5593          new->dynamic = astIsDynamic( new );
5594 
5595 /* Initialise the reference count (of Object pointers in use). */
5596          new->ref_count = 1;
5597 
5598 /* Initialise the ID strings. */
5599          new->id = NULL;
5600          new->ident = NULL;
5601 
5602 /* Use default values for unspecified attributes. */
5603          new->usedefs = CHAR_MAX;
5604 
5605 /* Increment the count of active Objects in the virtual function table.
5606    Use the count as a unique identifier (unique within the class) for
5607    the Object. */
5608          new->iref = vtab->nobject++;
5609 
5610 /* Initialise the pointer to an external object that acts as a proxy for
5611    the AST Object within foreign language interfaces. */
5612          new->proxy = NULL;
5613       }
5614 
5615 /* If an error occurred, clean up by deleting the new Object. Otherwise
5616    lock the object for use by the currently executing thread. */
5617       if ( !astOK ) {
5618          new = astDelete( new );
5619 
5620 #ifdef THREAD_SAFE
5621       } else {
5622          if( pthread_mutex_init( &(new->mutex1), NULL ) != 0 && astOK ) {
5623             astError( AST__INTER, "astInitObject(%s): Failed to "
5624                       "initialise POSIX mutex1 for the new Object.", status,
5625                       vtab->class );
5626          }
5627          if( pthread_mutex_init( &(new->mutex2), NULL ) != 0 && astOK ) {
5628             astError( AST__INTER, "astInitObject(%s): Failed to "
5629                       "initialise POSIX mutex2 for the new Object.", status,
5630                       vtab->class );
5631          }
5632          new->locker = -1;
5633          new->globals = NULL;
5634          (void) ManageLock( new, AST__LOCK, 0, NULL, status );
5635          if( !astOK ) new = astDelete( new );
5636 #endif
5637       }
5638    }
5639 
5640 /* Return a pointer to the new Object. */
5641    return new;
5642 }
5643 
astLoadObject_(void * mem,size_t size,AstObjectVtab * vtab,const char * name,AstChannel * channel,int * status)5644 AstObject *astLoadObject_( void *mem, size_t size,
5645                            AstObjectVtab *vtab, const char *name,
5646                            AstChannel *channel, int *status ) {
5647 /*
5648 *+
5649 *  Name:
5650 *     astLoadObject
5651 
5652 *  Purpose:
5653 *     Load an Object.
5654 
5655 *  Type:
5656 *     Protected function.
5657 
5658 *  Synopsis:
5659 *     #include "object.h"
5660 *     AstObject *astLoadObject( void *mem, size_t size,
5661 *                               AstObjectVtab *vtab, const char *name,
5662 *                               AstChannel *channel )
5663 
5664 *  Class Membership:
5665 *     Object loader.
5666 
5667 *  Description:
5668 *     This function is provided to load a new Object using data read
5669 *     from a Channel, and to allocate memory for it if necessary.
5670 *
5671 *     If the "init" flag is set, it also initialises the contents of a
5672 *     virtual function table for an Object at the start of the memory
5673 *     passed via the "vtab" parameter.
5674 
5675 *  Parameters:
5676 *     mem
5677 *        A pointer to the memory into which the Object is to be
5678 *        loaded.  This must be of sufficient size to accommodate the
5679 *        Object data (sizeof(Object)) plus any data used by derived
5680 *        classes. If a value of NULL is given, this function will
5681 *        allocate the memory itself using the "size" parameter to
5682 *        determine its size.
5683 *     size
5684 *        The amount of memory used by the Object (plus derived class
5685 *        data).  This will be used to allocate memory if a value of
5686 *        NULL is given for the "mem" parameter. This value is also
5687 *        stored in the Object structure, so a valid value must be
5688 *        supplied even if not required for allocating memory.
5689 *
5690 *        If the "vtab" parameter is NULL, the "size" value is ignored
5691 *        and sizeof(AstObject) is used instead.
5692 *     vtab
5693 *        Pointer to the start of the virtual function table to be
5694 *        associated with the new Object. If this is NULL, a pointer to
5695 *        the (static) virtual function table for the Object class is
5696 *        used instead.
5697 *     name
5698 *        Pointer to a constant null-terminated character string which
5699 *        contains the name of the class to which the new Object
5700 *        belongs (it is this pointer value that will subsequently be
5701 *        returned by the astGetClass method).
5702 *
5703 *        If the "vtab" parameter is NULL, the "name" value is ignored
5704 *        and a pointer to the string "Object" is used instead.
5705 
5706 *  Returned Value:
5707 *     A pointer to the new Object.
5708 
5709 *  Notes:
5710 *     - A null pointer will be returned if this function is invoked
5711 *     with the global error status set, or if it should fail for any
5712 *     reason.
5713 *-
5714 */
5715 
5716 /* Local Variables: */
5717    astDECLARE_GLOBALS            /* Thread-specific global data */
5718    AstObject *new;               /* Pointer to the new Object */
5719 
5720 /* Initialise. */
5721    new = NULL;
5722 
5723 /* Check the global error status. */
5724    if ( !astOK ) return new;
5725 
5726 /* Get a pointer to Thread-specific global data. */
5727    astGET_GLOBALS(channel);
5728 
5729 /* If a NULL virtual function table has been supplied, then this is
5730    the first loader to be invoked for this Object. In this case the
5731    Object belongs to this class, so supply appropriate values for
5732    initialising it and its virtual function table. */
5733    if ( !vtab ) {
5734       size = sizeof( AstObject );
5735       vtab = &class_vtab;
5736       name = "Object";
5737 
5738 /* If required, initialise the virtual function table for this class. */
5739       if ( !class_init ) {
5740          astInitObjectVtab( vtab, name );
5741          class_init = 1;
5742       }
5743    }
5744 
5745 /* There is no parent class to load, so simply initialise a new Object
5746    structure as if a new Object were being created from scratch. */
5747    new = astInitObject( mem, size, 0, vtab, name );
5748    if ( astOK ) {
5749 
5750 /* Read input data. */
5751 /* ================ */
5752 /* Request the input Channel to read all the input data appropriate to
5753    this class into the internal "values list". */
5754       astReadClassData( channel, "Object" );
5755 
5756 /* Now read each individual data item from this list and use it to
5757    initialise the appropriate instance variable(s) for this class. */
5758       new->id = astReadString( channel, "id", NULL );
5759       new->ident = astReadString( channel, "ident", NULL );
5760       new->usedefs = astReadInt( channel, "usedfs", CHAR_MAX );
5761 
5762 /* We simply read the values for the read-only attributes (just in
5763    case they've been un-commented in the external representation) and
5764    discard them. This prevents any possibility of error due to un-read
5765    input. */
5766       (void) astReadInt( channel, "refcnt", 0 );
5767       (void) astReadInt( channel, "nobj", 0 );
5768 
5769 /* Initialise the pointer to an external object that acts as a proxy for
5770    the AST Object within foreign language interfaces. */
5771       new->proxy = NULL;
5772 
5773 /* If an error occurred, clean up by deleting the new Object. */
5774       if ( !astOK ) new = astDelete( new );
5775    }
5776 
5777 /* Return the new Object pointer. */
5778    return new;
5779 }
5780 
5781 /* Virtual function interfaces. */
5782 /* ============================ */
5783 /* These provide the external interface to the virtual functions defined by
5784    this class. Each simply checks the global error status and then locates and
5785    executes the appropriate member function, using the function pointer stored
5786    in the object's virtual function table (this pointer is located using the
5787    astMEMBER macro defined in "object.h").
5788 
5789    Note that the member function may not be the one defined here, as it may
5790    have been over-ridden by a derived class. However, it should still have the
5791    same interface. */
astClear_(AstObject * this,const char * attrib,int * status)5792 void astClear_( AstObject *this, const char *attrib, int *status ) {
5793    if ( !astOK ) return;
5794    (**astMEMBER(this,Object,Clear))( this, attrib, status );
5795 }
astClearAttrib_(AstObject * this,const char * attrib,int * status)5796 void astClearAttrib_( AstObject *this, const char *attrib, int *status ) {
5797    if ( !astOK ) return;
5798    (**astMEMBER(this,Object,ClearAttrib))( this, attrib, status );
5799 }
astDump_(AstObject * this,AstChannel * channel,int * status)5800 void astDump_( AstObject *this, AstChannel *channel, int *status ) {
5801    if ( !astOK ) return;
5802    (**astMEMBER(this,Object,Dump))( this, channel, status );
5803 }
5804 
5805 #if defined(THREAD_SAFE)
astManageLock_(AstObject * this,int mode,int extra,AstObject ** fail,int * status)5806 int astManageLock_( AstObject *this, int mode, int extra, AstObject **fail,
5807                     int *status ) {
5808    if( !this ) return 0;
5809    return (**astMEMBER(this,Object,ManageLock))( this, mode, extra, fail, status );
5810 }
5811 #endif
5812 
astEqual_(AstObject * this,AstObject * that,int * status)5813 int astEqual_( AstObject *this, AstObject *that, int *status ) {
5814    if ( !astOK ) return 0;
5815    if( this == that ) return 1;
5816    return (**astMEMBER(this,Object,Equal))( this, that, status );
5817 }
astGetAttrib_(AstObject * this,const char * attrib,int * status)5818 const char *astGetAttrib_( AstObject *this, const char *attrib, int *status ) {
5819    if ( !astOK ) return NULL;
5820    return (**astMEMBER(this,Object,GetAttrib))( this, attrib, status );
5821 }
astSetAttrib_(AstObject * this,const char * setting,int * status)5822 void astSetAttrib_( AstObject *this, const char *setting, int *status ) {
5823    if ( !astOK ) return;
5824    (**astMEMBER(this,Object,SetAttrib))( this, setting, status );
5825 }
astShow_(AstObject * this,int * status)5826 void astShow_( AstObject *this, int *status ) {
5827    if ( !astOK ) return;
5828    (**astMEMBER(this,Object,Show))( this, status );
5829 }
astTestAttrib_(AstObject * this,const char * attrib,int * status)5830 int astTestAttrib_( AstObject *this, const char *attrib, int *status ) {
5831    if ( !astOK ) return 0;
5832    return (**astMEMBER(this,Object,TestAttrib))( this, attrib, status );
5833 }
astEnvSet_(AstObject * this,int * status)5834 void astEnvSet_( AstObject *this, int *status ) {
5835    if ( !astOK ) return;
5836    (**astMEMBER(this,Object,EnvSet))( this, status );
5837 }
astVSet_(AstObject * this,const char * settings,char ** text,va_list args,int * status)5838 void astVSet_( AstObject *this, const char *settings, char **text, va_list args, int *status ) {
5839    if ( !astOK ) return;
5840    (**astMEMBER(this,Object,VSet))( this, settings, text, args, status );
5841 }
astGetObjSize_(AstObject * this,int * status)5842 int astGetObjSize_( AstObject *this, int *status ) {
5843    if ( !astOK || !this ) return 0;
5844    return (**astMEMBER(this,Object,GetObjSize))( this, status );
5845 }
astCleanAttribs_(AstObject * this,int * status)5846 void astCleanAttribs_( AstObject *this, int *status ) {
5847    if ( !astOK ) return;
5848    (**astMEMBER(this,Object,CleanAttribs))( this, status );
5849 }
astCast_(AstObject * this,AstObject * obj,int * status)5850 AstObject *astCast_( AstObject *this, AstObject *obj, int *status ) {
5851    if ( !astOK ) return NULL;
5852    return (**astMEMBER(this,Object,Cast))( this, obj, status );
5853 }
astSame_(AstObject * this,AstObject * that,int * status)5854 int astSame_( AstObject *this, AstObject *that, int *status ) {
5855    if ( !astOK ) return 0;
5856    return (**astMEMBER(this,Object,Same))( this, that, status );
5857 }
astHasAttribute_(AstObject * this,const char * attrib,int * status)5858 int astHasAttribute_( AstObject *this, const char *attrib, int *status ) {
5859    if ( !astOK ) return 0;
5860    return (**astMEMBER(this,Object,HasAttribute))( this, attrib, status );
5861 }
5862 
5863 /* External interface. */
5864 /* =================== */
5865 /* The following relates to the external interface to Objects and not
5866    specifically to the implementation of the Object class itself
5867    (although it contains external functions which replace the internal
5868    versions defined earlier). */
5869 
5870 
5871 /* Type Definitions. */
5872 /* ----------------- */
5873 /* Define the Handle structure. This is attached to Objects when they
5874    are accessed via the public (external, user-callable) interface.
5875    Handles provide a buffer between the Object identifiers issued to
5876    external users and the naked C pointers used to handle Objects
5877    internally. They also implement the context levels used by
5878    astBegin, astEnd, astExempt and astExport (which are only available
5879    to external users). */
5880 typedef struct Handle {
5881    AstObject *ptr;               /* C Pointer to the associated Object */
5882    int context;                  /* Context level for this Object */
5883    int check;                    /* Check value to ensure validity */
5884 
5885 #if defined(THREAD_SAFE)
5886    int thread;                   /* Identifier for owning thread */
5887 #endif
5888 
5889 #if defined(MEM_DEBUG)
5890    int id;                       /* The id associated with the memory block
5891                                     holding the Object last associated with
5892                                     this handle. */
5893    AstObjectVtab *vtab;          /* Pointer to the firtual function table of
5894                                     the Object last associated with this
5895                                     handle. */
5896 #endif
5897 
5898 /* Links between Handles are implemented using integer offsets rather
5899    than through pointers. */
5900    int flink;                    /* Backward link to previous Handle */
5901    int blink;                    /* Forward link to next Handle */
5902 } Handle;
5903 
5904 /* Define a union with an overlapping int and AstObject*. This is used
5905    to transfer an integer bit pattern into and out of a pointer
5906    variable used to store an Object identifier. This avoids any
5907    implementation dependent aspects of integer-to-pointer
5908    conversions. */
5909 typedef union IdUnion {
5910    AstObject *pointer;
5911    int integer;
5912 } IdUnion;
5913 
5914 /* Define a union which allows a bit pattern to be accessed as a
5915    signed or unsigned int. */
5916 typedef union MixedInts {
5917    int i;
5918    unsigned u;
5919 } MixedInts;
5920 
5921 /* Static Variables. */
5922 /* ----------------- */
5923 /* The array of Handle structures is a pool of resources available to all
5924    threads. Each thread has its own conext level and its own "active_handles"
5925    array to identify the first Handle at each context level. */
5926 static Handle *handles = NULL; /* Pointer to allocated array of Handles */
5927 static int free_handles = -1; /* Offset to head of free Handle list */
5928 static int nhandles = 0; /* Number of Handles in "handles" array */
5929 static unsigned nids = 0; /* Number of IDs issued to external users */
5930 
5931 #if defined(THREAD_SAFE)
5932 static int unowned_handles = -1; /* Offset to head of unowned Handle
5933                                     list. In a single threaded environment,
5934                                     all handles must be owned by a thread. */
5935 #endif
5936 
5937 #ifdef MEM_DEBUG
5938 static int Watched_Handle = -1; /* A handle index to be watched. Activity
5939                                    on this handle is reported using
5940                                    astHandleUse and astHandleAlarm. */
5941 #endif
5942 
5943 
5944 /* External Interface Function Prototypes. */
5945 /* --------------------------------------- */
5946 /* MYSTATIC should normally be set to "static" to make the following
5947    function have local symbols. But it may be set to blank for debugging
5948    purposes in order to enable these functions to appear in a backtrace
5949    such as produced by the astBacktrace function. */
5950 #define MYSTATIC
5951 
5952 /* Private functions associated with the external interface. */
5953 MYSTATIC AstObject *AssocId( int, int * );
5954 MYSTATIC int CheckId( AstObject *, int, int * );
5955 MYSTATIC void AnnulHandle( int, int * );
5956 MYSTATIC void InitContext( int * );
5957 MYSTATIC void InsertHandle( int, int *, int * );
5958 MYSTATIC void RemoveHandle( int, int *, int * );
5959 
5960 #if defined(MEM_DEBUG)
5961 MYSTATIC void CheckList( int *, int * );
5962 MYSTATIC void CheckInList( int, int *, int, int * );
5963 MYSTATIC int CheckThread( int, int *, int * );
5964 MYSTATIC const char *HandleString( int, char * );
5965 MYSTATIC const char *HeadString( int *, char * );
5966 #endif
5967 
5968 
5969 /* The following functions have public prototypes only (i.e. no
5970    protected prototypes), so we must provide local prototypes for use
5971    within this module. */
5972 AstObject *astDeleteId_( AstObject *, int * );
5973 void astBegin_( void );
5974 void astEnd_( int * );
5975 void astExemptId_( AstObject *, int * );
5976 void astImportId_( AstObject *, int * );
5977 void astSetId_( void *, const char *, ... );
5978 void astLockId_( AstObject *, int, int * );
5979 void astUnlockId_( AstObject *, int, int * );
5980 
5981 
5982 /* External Interface Functions. */
5983 /* ----------------------------- */
AnnulHandle(int ihandle,int * status)5984 MYSTATIC void AnnulHandle( int ihandle, int *status ) {
5985 /*
5986 *  Name:
5987 *     AnnulHandle
5988 
5989 *  Purpose:
5990 *     Annul a Handle and its associated Object pointer.
5991 
5992 *  Type:
5993 *     Private function.
5994 
5995 *  Synopsis:
5996 *     #include "object.h"
5997 *     void AnnulHandle( int ihandle, int *status )
5998 
5999 *  Class Membership:
6000 *     Object member function.
6001 
6002 *  Description:
6003 *     This function annuls an active Handle by annulling the Object
6004 *     pointer it is associated with, deactivating the Handle and
6005 *     returning it to the free Handle list for re-use.
6006 *
6007 *     The reference count for the associated Object is decremented by
6008 *     this function and the Object will be deleted if this reference
6009 *     count falls to zero.
6010 
6011 *  Parameters:
6012 *     ihandle
6013 *        Array offset that identifies the Handle to be annulled in the
6014 *        "handles" array. This is fully validated by this function.
6015 *     status
6016 *        Pointer to the inherited status variable.
6017 
6018 *  Notes:
6019 *     - The Handle supplied should be active, otherwise an error will
6020 *     result and the Handle will not be touched (but no error report
6021 *     will be made if the global error status has already been set).
6022 */
6023 
6024 /* Local Variables: */
6025    astDECLARE_GLOBALS            /* Thread-specific global data */
6026    AstObject *ptr;               /* Object pointer */
6027    int context;                  /* Context level where Handle was issued */
6028 
6029 /* Get a pointer to Thread-specific global data. */
6030    astGET_GLOBALS(NULL);
6031 
6032 /* Check that the handle offset supplied is valid and report an error
6033    if it is not (but only if the global error status has not already
6034    been set). */
6035    if ( ( ihandle < 0 ) || ( ihandle >= nhandles ) ) {
6036       if ( astOK ) {
6037          astError( AST__INHAN, "astAnnulHandle: Invalid attempt to annul an "
6038                    "Object Handle (no. %u).", status, ihandle );
6039          astError( AST__INHAN, "This Handle number is not valid (possible "
6040                    "internal programming error)." , status);
6041       }
6042 
6043 /* If OK, obtain the Handle's context level. */
6044    } else {
6045       context = handles[ ihandle ].context;
6046 
6047 /* If this indicates that the Handle isn't active, then report an
6048    error (but only if the global error status has not already been
6049    set). We allow handles that are currently not owned by any thread to
6050    be annulled. */
6051       if ( context < 0 && context != UNOWNED_CONTEXT ) {
6052          if ( astOK ) {
6053             astError( AST__INHAN, "astAnnulHandle: Invalid attempt to annul "
6054                       "an Object Handle (no. %u).", status, ihandle );
6055             astError( AST__INHAN, "This Handle is not active (possible "
6056                       "internal programming error)." , status);
6057          }
6058 
6059 /* If the Handle is active, annul its Object pointer. The astAnnul
6060    function may call Delete functions supplied by any class, and these
6061    Delete functions may involve annulling external Object IDs, which in
6062    turn requires access to the handles array. For this reason, we release
6063    the mutex that protects access to the handles arrays so that it can
6064    potentially be re-aquired within astAnnul without causing deadlock. */
6065       } else {
6066 
6067 #ifdef MEM_DEBUG
6068          astHandleUse( ihandle, "annulled using check value %d ",
6069                        handles[ ihandle ].check  );
6070 #endif
6071 
6072          ptr = handles[ ihandle ].ptr;
6073          UNLOCK_MUTEX2;
6074          ptr = astAnnul( ptr );
6075          LOCK_MUTEX2;
6076 
6077 /* Remove the Handle from the active list for its context level. */
6078          if( context == UNOWNED_CONTEXT ) {
6079 
6080 #if defined(THREAD_SAFE)
6081             RemoveHandle( ihandle, &unowned_handles, status );
6082 #else
6083             if( astOK ) astError( AST__INTER, "AnnulHandle: reference to "
6084                          "'unowned_handles' in a non-thread-safe context "
6085                          "(internal AST programming error).", status );
6086 #endif
6087 
6088          } else if( active_handles ) {
6089             RemoveHandle( ihandle, &active_handles[ context ], status );
6090 
6091          } else if( astOK ){
6092             astError( AST__INTER, "AnnulHandle: active_handles array has "
6093                       "not been initialised (internal AST programming error).",
6094                       status );
6095          }
6096 
6097 /* Reset the Handle's "context" value (making it inactive) and its "check"
6098    value (so it is no longer associated with an identifier value). */
6099          handles[ ihandle ].ptr = NULL;
6100          handles[ ihandle ].context = INVALID_CONTEXT;
6101          handles[ ihandle ].check = 0;
6102 #if defined(THREAD_SAFE)
6103          handles[ ihandle ].thread = -1;
6104 #endif
6105 
6106 /* Place the modified Handle on the free Handles list ready for re-use. */
6107          InsertHandle( ihandle, &free_handles, status );
6108 
6109       }
6110    }
6111 }
6112 
astAnnulId_(AstObject * this_id,int * status)6113 AstObject *astAnnulId_( AstObject *this_id, int *status ) {
6114 /*
6115 *+
6116 *  Name:
6117 *     AnnulId
6118 
6119 *  Purpose:
6120 *     Annul an external Object identifier.
6121 
6122 *  Type:
6123 *     Protected function.
6124 
6125 *  Synopsis:
6126 *     #include "object.h"
6127 *     AstObject *astAnnulId( AstObject *this )
6128 
6129 *  Class Membership:
6130 *     Object member function.
6131 
6132 *  Description:
6133 *     This function implements the external (public) interface to the
6134 *     astAnnul method. It accepts an active Object identifier, which
6135 *     it annuls, causing the associated Handle to be deactivated and
6136 *     returned to the free Handles list for re-use. It also causes the
6137 *     reference count of the associated Object to be decremented and
6138 *     the Object to be deleted if this reference count falls to zero.
6139 
6140 *  Parameters:
6141 *     this
6142 *        The Object identifier to be annulled.
6143 
6144 *  Returned Value:
6145 *     A NULL C pointer is always returned (this should be translated
6146 *     into an identifier value of zero for external use).
6147 
6148 *  Notes:
6149 *     - This function attempts to execute even if the global error
6150 *     status is set.
6151 *     - The identifier supplied should be associated with an active
6152 *     Object, otherwise an error will result (but no error report will
6153 *     be made if the global error status has already been set).
6154 *     - This function is invoked via the astAnnul macro for external use.
6155 *     For internal use (from protected code which needs to handle external
6156 *     IDs) it should be invoked via the astAnnulId macro (since astAnnul
6157 *     expects a true C pointer as its argument when used internally).
6158 *-
6159 */
6160 
6161 /* Obtain the Object pointer from the ID supplied and validate the
6162    pointer to ensure it identifies a valid Object (this generates an
6163    error if it doesn't). Note, we use "astMakePointer_NoLockCheck",
6164    rather than the usual "astMakePointer" since a thread should be able
6165    to renounce interest in an object without needing to own the object.
6166    If we used "astMakePointer" then a thread could not annul a pointer
6167    unless it owned the object. But having annulled the pointer it could
6168    then not unlock the object for use by another thread (since the
6169    pointer it would need to do this has just been annulled). */
6170    if ( !astIsAObject( astMakePointer_NoLockCheck( this_id ) ) ) return NULL;
6171 
6172 /* Obtain the Handle offset for this Object and annul the Handle and
6173    its associated Object pointer. Report an error if the handle is
6174    currently owned by a different thread. That is, the *Object* need
6175    not be locked by the current thread (as indicated by the use of
6176    astMakePointer above), but the *handle* must be owned by the current
6177    thread. */
6178    LOCK_MUTEX2;
6179    AnnulHandle( CheckId( this_id, 1, status ), status );
6180    UNLOCK_MUTEX2;
6181 
6182 /* Always return a NULL pointer value. */
6183    return NULL;
6184 }
6185 
AssocId(int ihandle,int * status)6186 MYSTATIC AstObject *AssocId( int ihandle, int *status ) {
6187 /*
6188 *  Name:
6189 *     AssocId
6190 
6191 *  Purpose:
6192 *     Associate an identifier value with a Handle.
6193 
6194 *  Type:
6195 *     Private function.
6196 
6197 *  Synopsis:
6198 *     #include "object.h"
6199 *     AstObject *AssocId( int ihandle )
6200 
6201 *  Class Membership:
6202 *     Object member function.
6203 
6204 *  Description:
6205 *     This function takes a zero-based offset into the "handles" array
6206 *     that identifies a Handle associated with an active Object. It
6207 *     encodes this into an identifier value to be issued to an
6208 *     external user to identify that Handle and its Object, and then
6209 *     associates this identifier value with the Handle.
6210 
6211 *  Parameters:
6212 *     ihandle
6213 *        Offset in the "handles" array that identifies the Handle,
6214 *        which should be active (i.e. associated with an active
6215 *        Object). This function will modify the "check" field in this
6216 *        Handle to associate it with the identifier value it returns.
6217 
6218 *  Returned Value:
6219 *     The resulting identifier value.
6220 
6221 *  Notes:
6222 *     - The returned identifier value is, in fact, an int.  This
6223 *     allows the value to be passed easily to other languages
6224 *     (e.g. Fortran) and stored as an integer without loss of
6225 *     information.
6226 *     - The value is stored within C code as type AstObject*.  This
6227 *     means that C code (e.g. function prototypes, etc.) need not be
6228 *     aware that an identifier (as opposed to an Object pointer) is
6229 *     being used, even though the actual bit patterns will be
6230 *     different. The same C code can then be used for both internal
6231 *     and external purposes so long as care is taken to convert
6232 *     between the two representations at appropriate points.
6233 *     - The reverse operation (conversion of an ID back to a handle
6234 *     offset) is performed by CheckId.
6235 *     - A zero identifier value will be returned if this function is
6236 *     invoked with the global status set or if it should fail for any
6237 *     reason.
6238 */
6239 
6240 /* Local Variables: */
6241    AstObject *result;            /* Pointer value to return */
6242    MixedInts test;               /* Union for testing encoding */
6243    MixedInts work;               /* Union for encoding ID value */
6244 
6245 /* Initialise. */
6246    result = astI2P( 0 );
6247 
6248 /* Check the global error status. */
6249    if ( !astOK ) return result;
6250 
6251 /* Copy the Handle offset and clear the lowest 8 bits by shifting
6252    left. */
6253    work.i = ihandle;
6254    work.u = work.u << 8U;
6255 
6256 /* Make a copy of the result shifted right again. Test if any bits
6257    have been lost in this process. If so, there are too many Handles
6258    in use at once to encode them into IDs, so report an error. */
6259    test.u = work.u >> 8U;
6260    if ( test.i != ihandle ) {
6261       astError( AST__XSOBJ, "AssocId(%s): There are too many AST Objects in "
6262                 "use at once.", status, astGetClass( handles[ ihandle ].ptr ) );
6263 
6264 /* If OK, scramble the value by exclusive-ORing with the bit pattern
6265    in AST__FAC (a value unique to this library), also shifted left by
6266    8 bits. This makes it even less likely that numbers from other
6267    sources will be accepted in error as valid IDs. */
6268    } else {
6269       work.u ^= ( ( (unsigned) AST__FAC ) << 8U );
6270 
6271 /* Fill the lowest 8 bits with a count of the total number of IDs
6272    issued so far (which we increment here). This makes each ID unique,
6273    so that an old one that identifies a Handle that has been annulled
6274    and re-used (i.e. associated with a new ID) can be spotted.  We
6275    only use the lowest 8 bits of this count because this provides
6276    adequate error detection to reveal programming errors and we do not
6277    need higher security than this. We also prevent a count of zero
6278    being used, as this could result in a zero identifier value (this
6279    being reserved as the "null" value). */
6280       if ( ++nids > 255U ) nids = 1U;
6281       work.u |= nids;
6282 
6283 /* Store the value as a check count in the Handle. This will be used
6284    to validate the ID in future. */
6285       handles[ ihandle ].check = work.i;
6286 
6287 /* Pack the value into the pointer to be returned. */
6288       result = astI2P( work.i );
6289    }
6290 
6291 /* Return the result. */
6292    return result;
6293 }
6294 
astBegin_(void)6295 void astBegin_( void ) {
6296 /*
6297 *++
6298 *  Name:
6299 c     astBegin
6300 f     AST_BEGIN
6301 
6302 *  Purpose:
6303 *     Begin a new AST context.
6304 
6305 *  Type:
6306 *     Public function.
6307 
6308 *  Synopsis:
6309 c     #include "object.h"
6310 c     void astBegin
6311 f     CALL AST_BEGIN( STATUS )
6312 
6313 *  Class Membership:
6314 *     Object class function.
6315 
6316 *  Description:
6317 c     This macro invokes a function to begin a new AST context.
6318 c     Any Object pointers
6319 f     This routine begins a new AST context. Any Object pointers
6320 *     created within this context will be annulled when it is later
6321 c     ended using astEnd (just as if astAnnul had been invoked),
6322 f     ended using AST_END (just as if AST_ANNUL had been invoked),
6323 c     unless they have first been exported using astExport or rendered
6324 c     exempt using astExempt. If
6325 f     unless they have first been exported using AST_EXPORT or rendered
6326 f     exempt using AST_EXEMPT. If
6327 *     annulling a pointer causes an Object's RefCount attribute to
6328 *     fall to zero (which happens when the last pointer to it is
6329 *     annulled), then the Object will be deleted.
6330 
6331 f  Parameters:
6332 f     STATUS = INTEGER (Given and Returned)
6333 f        The global status.
6334 
6335 *  Applicability:
6336 *     Object
6337 c        This macro applies to all Objects.
6338 f        This routine applies to all Objects.
6339 
6340 *  Notes:
6341 c     - astBegin attempts to execute even if the AST error status
6342 c     is set on entry.
6343 f     - This routine attempts to execute even if STATUS is set to an
6344 f     error value.
6345 c     - Contexts delimited by astBegin and astEnd may be nested to any
6346 c     depth.
6347 f     - Contexts delimited by AST_BEGIN and AST_END may be nested to any
6348 f     depth.
6349 *--
6350 */
6351 
6352 /* Local Variables: */
6353    astDECLARE_GLOBALS            /* Thread-specific global data */
6354    int stat;                     /* Copy of global status */
6355    int *status;                  /* Pointer to inherited status value */
6356 
6357 /* Get a pointer to thread-specific global data. */
6358    astGET_GLOBALS(NULL);
6359 
6360 /* Now that the thread-specific data has been initialised, we can get a
6361    pointer to the threads inherited status value. */
6362    status = astGetStatusPtr;
6363 
6364 /* Save and clear the global status so that memory allocation can be
6365    performed within this function even under error conditions. */
6366    stat = astStatus;
6367    astClearStatus;
6368 
6369 /* Ensure that the active_handles array has been initialised. */
6370    if ( !active_handles ) InitContext( status );
6371 
6372 /* Extend the "active handles" array to accommodate a new context
6373    level. This array contains integer offsets into the "handles" array
6374    to identify the handle which is at the head of the list of active
6375    handles for each context level. */
6376    astBeginPM;
6377    active_handles = astGrow( active_handles, context_level + 2,
6378                              sizeof( int ) );
6379    astEndPM;
6380 
6381 /* Initialise the array element for the new context level to indicate
6382    an empty Handle list. */
6383    if ( astOK ) active_handles[ ++context_level ] = -1;
6384 
6385 /* Restore the original global status value. */
6386    astSetStatus( stat );
6387 }
6388 
CheckId(AstObject * this_id,int lock_check,int * status)6389 MYSTATIC int CheckId( AstObject *this_id, int lock_check, int *status ) {
6390 /*
6391 *  Name:
6392 *     CheckId
6393 
6394 *  Purpose:
6395 *     Check an identifier value and convert it into a Handle offset.
6396 
6397 *  Type:
6398 *     Private function.
6399 
6400 *  Synopsis:
6401 *     #include "object.h"
6402 *     int CheckId( AstObject *this, int lock_check, int *status )
6403 
6404 *  Class Membership:
6405 *     Object member function.
6406 
6407 *  Description:
6408 *     This function takes an identifier value encoded by AssocId and
6409 *     validates it to ensure it is associated with an active
6410 *     Handle. If valid, it converts it back into a zero-based offset
6411 *     which may be used to access the Handle in the "handles"
6412 *     array. Otherwise, an error is reported.
6413 
6414 *  Parameters:
6415 *     this
6416 *        The identifier value to be decoded.
6417 *     lock_check
6418 *        Should an error be reported if the handle is in an Object
6419 *        context for a different thread?
6420 *     status
6421 *        Pointer to the inherited status variable.
6422 
6423 *  Returned Value:
6424 *     The resulting Handle offset, or -1 if the identifier is not
6425 *     valid or any other error occurs.
6426 
6427 *  Notes:
6428 *     - This function attempts to execute even if the global error
6429 *     status is set, but no further error report will be made if it
6430 *     fails under these circumstances.
6431 */
6432 
6433 /* Local Variables: */
6434    astDECLARE_GLOBALS            /* Thread-specific global data */
6435    MixedInts work;               /* Union for decoding ID value */
6436    int id;                       /* ID value as an int */
6437    int ihandle;                  /* Result to return */
6438 
6439 #ifdef MEM_DEBUG
6440    int oldok = astOK;
6441 #endif
6442 
6443 /* Initialise. */
6444    ihandle = -1;
6445 
6446 /* Get a pointer to thread-specific global data. */
6447    astGET_GLOBALS(NULL);
6448 
6449 /* Retrieve the integer Object identifier value from the pointer
6450    supplied. */
6451    id = astP2I( this_id );
6452 
6453 /* Check if a value of zero has been supplied and report an error if
6454    it has. */
6455    if ( !id ) {
6456       if ( astOK ) {
6457          astError( AST__OBJIN, "Invalid Object pointer given (value is "
6458                    "zero)." , status);
6459       }
6460 
6461 /* If OK, reverse the encoding process performed by AssocId to
6462    retrieve the Handle offset. */
6463    } else {
6464       work.i = id;
6465       work.u = ( work.u ^ ( ( (unsigned) AST__FAC ) << 8U ) ) >> 8U;
6466 
6467 /* Check that the offset obtained doesn't extend beyond the limits of
6468    the "handles" array. Report an error if it does. */
6469       if ( ( work.i < 0 ) || ( work.i >= nhandles ) ) {
6470          if ( astOK ) {
6471             astError( AST__OBJIN, "Invalid Object pointer given (value is "
6472                       "%d).", status, id );
6473          }
6474 
6475 /* See if the "check" field matches the ID value and the Handle is
6476    valid (i.e. is associated with an active Object). If not, the
6477    Handle has been annulled and possibly re-used, so report an
6478    error. */
6479       } else if ( ( handles[ work.i ].check != id ) ||
6480                   ( handles[ work.i ].context == INVALID_CONTEXT ) ) {
6481          if ( astOK ) {
6482             astError( AST__OBJIN, "Invalid Object pointer given (value is "
6483                       "%d).", status, id  );
6484             astError( AST__OBJIN, "This pointer has been annulled, or the "
6485                       "associated Object deleted." , status);
6486          }
6487 #if defined(THREAD_SAFE)
6488       } else if(  lock_check && handles[ work.i ].context != UNOWNED_CONTEXT &&
6489                                 handles[ work.i ].thread != AST__THREAD_ID ) {
6490          if ( astOK ) {
6491             astError( AST__OBJIN, "Invalid Object pointer given (value is "
6492                       "%d).", status, id  );
6493             astError( AST__OBJIN, "This pointer is currently owned by "
6494                       "another thread (possible programming error)." , status);
6495          }
6496 #endif
6497 
6498 /* If OK, set the Handle offset to be returned. */
6499       } else {
6500          ihandle = work.i;
6501       }
6502 
6503 #ifdef MEM_DEBUG
6504       if ( oldok && !astOK && ( work.i >= 0 ) && ( work.i < nhandles ) ) {
6505          char buf[200];
6506          astError( astStatus, "Handle properties: %s ", status,
6507                    HandleString( work.i, buf ) );
6508       }
6509 #endif
6510 
6511    }
6512 
6513 /* Return the result. */
6514    return ihandle;
6515 }
6516 
astDeleteId_(AstObject * this_id,int * status)6517 AstObject *astDeleteId_( AstObject *this_id, int *status ) {
6518 /*
6519 *+
6520 *  Name:
6521 *     astDeleteId
6522 
6523 *  Purpose:
6524 *     Delete an Object via an identifier.
6525 
6526 *  Type:
6527 *     Protected function.
6528 
6529 *  Synopsis:
6530 *     #include "object.h"
6531 *     AstObject *astDeleteId_( AstObject *this )
6532 
6533 *  Class Membership:
6534 *     Object member function.
6535 
6536 *  Description:
6537 *     This function implements the external (public) interface to the
6538 *     astDelete method. It accepts an active Object identifier and
6539 *     deletes the associated Object. Before doing so, it annuls all
6540 *     active identifiers associated with the object, deactivates their
6541 *     Handles and returns these Handles to the free Handles list for
6542 *     re-use.
6543 
6544 *  Parameters:
6545 *     this
6546 *        An identifier for the Object to be deleted.
6547 
6548 *  Returned Value:
6549 *     A NULL C pointer is always returned (this should be translated
6550 *     into an identifier value of zero for external use).
6551 
6552 *  Notes:
6553 *     - This function attempts to execute even if the global error
6554 *     status is set.
6555 *     - The identifier supplied should be associated with an active
6556 *     Object, otherwise an error will result (but no error report will
6557 *     be made if the global error status has already been set).
6558 *     - Although this function is documented as "private" and should
6559 *     not be invoked directly from outside this class, it is not a
6560 *     static function and has a public prototype. This is because it
6561 *     must be invoked via the astDelete macro (defined in the
6562 *     "object.h" include file) as part of the public interface.
6563 *-
6564 */
6565 
6566 /* Local Variables: */
6567    AstObject *this;              /* Pointer to Object */
6568    int i;                        /* Loop counter for Handles */
6569    int ihandle;                  /* Object Handle offset */
6570 
6571 /* Obtain the Object pointer from the ID supplied and validate the
6572    pointer to ensure it identifies a valid Object (this generates an
6573    error if it doesn't). */
6574    if ( !astIsAObject( this = astMakePointer( this_id ) ) ) return NULL;
6575 
6576 /* Gain exclusive access to the handles array. */
6577    LOCK_MUTEX2;
6578 
6579 /* Obtain the Handle offset for this Object. */
6580    ihandle = CheckId( this_id, 1, status );
6581    if ( ihandle != -1 ) {
6582 
6583 /* Since the Object is to be deleted, we must annul all identifiers
6584    that refer to it.  Loop to inspect each currently allocated Handle
6585    in the "handles" array. */
6586       for ( i = 0; i < nhandles; i++ ) {
6587 
6588 /* Select active handles and test if their Object pointer refers to
6589    the Object to be deleted. */
6590          if ( ( handles[ i ].context != INVALID_CONTEXT ) &&
6591               ( handles[ i ].ptr == this ) ) {
6592 
6593 /* If so, explicitly set the reference count for the Object to 2 so
6594    that it will not be deleted (yet) when we annul the pointer
6595    associated with the Handle. */
6596             handles[ i ].ptr->ref_count = 2;
6597 
6598 /* Annul the Handle, which frees its resources, decrements the Object
6599    reference count and makes any ID associated with the Handle become
6600    invalid. */
6601             AnnulHandle( i, status );
6602          }
6603       }
6604 
6605 /* If required, tell the user that the handle's object has been deleted. */
6606 #ifdef MEM_DEBUG
6607       astHandleUse( ihandle, "object-deleted" );
6608 #endif
6609    }
6610 
6611    UNLOCK_MUTEX2;
6612 
6613 /* When all Handles associated with the Object have been annulled,
6614    delete the object itself. This over-rides the reference count and
6615    causes any remaining pointers to the Object (e.g. in internal code
6616    or within other Objects) to become invalid. */
6617    this = astDelete( this );
6618 
6619 /* Always return a NULL pointer value. */
6620    return NULL;
6621 }
6622 
astEnd_(int * status)6623 void astEnd_( int *status ) {
6624 /*
6625 *++
6626 *  Name:
6627 c     astEnd
6628 f     AST_END
6629 
6630 *  Purpose:
6631 *     End an AST context.
6632 
6633 *  Type:
6634 *     Public function.
6635 
6636 *  Synopsis:
6637 c     #include "object.h"
6638 c     void astEnd
6639 f     CALL AST_END( STATUS )
6640 
6641 *  Class Membership:
6642 *     Object class function.
6643 
6644 *  Description:
6645 c     This macro invokes a function to end an AST context which was
6646 f     This routine ends an AST context which was
6647 c     begun with a matching invocation of astBegin. Any Object
6648 f     begun with a matching invocation of AST_BEGIN. Any Object
6649 *     pointers created within this context will be annulled (just as
6650 c     if astAnnul had been invoked) and will cease to be valid
6651 f     if AST_ANNUL had been invoked) and will cease to be valid
6652 *     afterwards, unless they have previously been exported using
6653 c     astExport or rendered exempt using astExempt.
6654 f     AST_EXPORT or rendered exempt using AST_EXEMPT.
6655 *     If annulling a pointer causes an Object's RefCount attribute to
6656 *     fall to zero (which happens when the last pointer to it is
6657 *     annulled), then the Object will be deleted.
6658 
6659 *  Parameters:
6660 f     STATUS = INTEGER (Given and Returned)
6661 f        The global status.
6662 
6663 *  Applicability:
6664 *     Object
6665 c        This macro applies to all Objects.
6666 f        This routine applies to all Objects.
6667 
6668 *  Notes:
6669 c     - astEnd attempts to execute even if the AST error status is set.
6670 f     - This routine attempts to execute even if STATUS is set to an
6671 f     error value.
6672 c     - Contexts delimited by astBegin and astEnd may be nested to any
6673 c     depth.
6674 f     - Contexts delimited by AST_BEGIN and AST_END may be nested to any
6675 f     depth.
6676 *--
6677 */
6678 
6679 /* Local Variables: */
6680    astDECLARE_GLOBALS            /* Thread-specific global data */
6681    int ihandle;                  /* Offset of Handle to be annulled */
6682 
6683 /* Get a pointer to Thread-specific global data. */
6684    astGET_GLOBALS(NULL);
6685 
6686 /* Check that the current context level is at least 1, otherwise there
6687    has been no matching use of astBegin, so report an error (unless
6688    the global status has already been set). */
6689    if ( context_level < 1 ) {
6690       if ( astOK ) {
6691          astError( AST__ENDIN, "astEnd: Invalid use of astEnd without a "
6692                    "matching astBegin." , status);
6693       }
6694 
6695 /* If OK, loop while there are still active Handles associated with
6696    the current context level. First gain exclusive access to the handles
6697    array. */
6698    } else if ( active_handles ) {
6699       LOCK_MUTEX2;
6700       while ( ( ihandle = active_handles[ context_level ] ) != -1 ) {
6701 
6702 /* Annul the Handle at the head of the active Handles list. */
6703          AnnulHandle( ihandle, status );
6704 
6705 /* It is just posible that under error conditions inactive Handles
6706    might get left in the active_handles list and AnnulHandle would
6707    then fail. Since this would result in an infinite loop, we check to
6708    see if the handle we have just annulled is still in the list. If
6709    so, transfer it to the free Handles list for re-use. */
6710          if ( ihandle == active_handles[ context_level ] ) {
6711             RemoveHandle( ihandle, &active_handles[ context_level ], status );
6712             InsertHandle( ihandle, &free_handles, status );
6713          }
6714       }
6715 
6716 /* Ensure the context level is decremented unless it was zero to start
6717    with. */
6718       context_level--;
6719 
6720 /* Relinquish access to the handles array. */
6721       UNLOCK_MUTEX2;
6722    }
6723 
6724 }
6725 
astExemptId_(AstObject * this_id,int * status)6726 void astExemptId_( AstObject *this_id, int *status ) {
6727 /*
6728 *++
6729 *  Name:
6730 c     astExempt
6731 f     AST_EXEMPT
6732 
6733 *  Purpose:
6734 *     Exempt an Object pointer from AST context handling.
6735 
6736 *  Type:
6737 *     Public function.
6738 
6739 *  Synopsis:
6740 c     #include "object.h"
6741 c     void astExempt( AstObject *this )
6742 f     CALL AST_EXEMPT( THIS, STATUS )
6743 
6744 *  Class Membership:
6745 *     Object method.
6746 
6747 *  Description:
6748 c     This function exempts an Object pointer from AST context
6749 f     This routine exempts an Object pointer from AST context
6750 c     handling, as implemented by astBegin and astEnd. This means that
6751 f     handling, as implemented by AST_BEGIN and AST_END. This means that
6752 c     the pointer will not be affected when astEnd is invoked and will
6753 f     the pointer will not be affected when AST_END is called and will
6754 *     remain active until the end of the program, or until explicitly
6755 c     annulled using astAnnul.
6756 f     annulled using AST_ANNUL.
6757 *
6758 c     If possible, you should avoid using this function when writing
6759 f     If possible, you should avoid using this routine when writing
6760 *     applications. It is provided mainly for developers of other
6761 *     libraries, who may wish to retain references to AST Objects in
6762 *     internal data structures, and who therefore need to avoid the
6763 c     effects of astBegin and astEnd.
6764 f     effects of AST_BEGIN and AST_END.
6765 
6766 *  Parameters:
6767 c     this
6768 f     THIS = INTEGER (Given)
6769 *        Object pointer to be exempted from context handling.
6770 f     STATUS = INTEGER (Given and Returned)
6771 f        The global status.
6772 
6773 *  Applicability:
6774 *     Object
6775 c        This function applies to all Objects.
6776 f        This routine applies to all Objects.
6777 *--
6778 
6779 *  Implementation Notes:
6780 *     - This function does not exist in the "protected" interface to
6781 *     the Object class and is not available to other class
6782 *     implementations.
6783 */
6784 
6785 /* Local Variables: */
6786    astDECLARE_GLOBALS            /* Thread-specific global data */
6787    int context;                  /* Handle context level */
6788    int ihandle;                  /* Offset of Handle in "handles" array */
6789 
6790 /* Check the global error status. */
6791    if ( !astOK ) return;
6792 
6793 /* Get a pointer to Thread-specific global data. */
6794    astGET_GLOBALS(NULL);
6795 
6796 /* Obtain the Object pointer from the ID supplied and validate the
6797    pointer to ensure it identifies a valid Object. */
6798    (void) astCheckObject( astMakePointer( this_id ) );
6799    if ( astOK ) {
6800 
6801 /* Gain exclusive access to the handles array. */
6802       LOCK_MUTEX2;
6803 
6804 /* Obtain the Handle offset for this Object. */
6805       ihandle = CheckId( this_id, 1, status );
6806       if ( ihandle != -1 ) {
6807 
6808 /* Extract the context level at which the Object was created. */
6809          context = handles[ ihandle ].context;
6810 
6811 /* Set the new context level to zero, where it cannot be affected by
6812    ending any context. */
6813          handles[ ihandle ].context = 0;
6814 
6815 /* Remove the object's Handle from its original active Handles list
6816    and insert it into the list appropriate to its new context
6817    level. */
6818 
6819 #if defined(THREAD_SAFE)
6820          if( context == UNOWNED_CONTEXT ) {
6821             RemoveHandle( ihandle, &unowned_handles, status );
6822          } else {
6823             RemoveHandle( ihandle, &active_handles[ context ], status );
6824          }
6825 #else
6826          RemoveHandle( ihandle, &active_handles[ context ], status );
6827 #endif
6828 
6829          InsertHandle( ihandle, &active_handles[ 0 ], status );
6830 
6831 /* If required, tell the user that the handle has been exempted. */
6832 #ifdef MEM_DEBUG
6833          astHandleUse( ihandle, "exempted" );
6834 #endif
6835       }
6836 
6837       UNLOCK_MUTEX2;
6838    }
6839 }
6840 
astExportId_(AstObject * this_id,int * status)6841 void astExportId_( AstObject *this_id, int *status ) {
6842 /*
6843 *++
6844 *  Name:
6845 c     astExport
6846 f     AST_EXPORT
6847 
6848 *  Purpose:
6849 *     Export an Object pointer to an outer context.
6850 
6851 *  Type:
6852 *     Public function.
6853 
6854 *  Synopsis:
6855 c     #include "object.h"
6856 c     void astExport( AstObject *this )
6857 f     CALL AST_EXPORT( THIS, STATUS )
6858 
6859 *  Class Membership:
6860 *     Object method.
6861 
6862 *  Description:
6863 c     This function exports an Object pointer from the current AST context
6864 f     This routine exports an Object pointer from the current AST context
6865 *     into the context that encloses the current one. This means that
6866 *     the pointer will no longer be annulled when the current context
6867 c     is ended (with astEnd), but only when the next outer context (if
6868 f     is ended (with AST_END), but only when the next outer context (if
6869 *     any) ends.
6870 
6871 *  Parameters:
6872 c     this
6873 f     THIS = INTEGER (Given)
6874 *        Object pointer to be exported.
6875 f     STATUS = INTEGER (Given and Returned)
6876 f        The global status.
6877 
6878 *  Applicability:
6879 *     Object
6880 c        This function applies to all Objects.
6881 f        This routine applies to all Objects.
6882 
6883 *  Notes:
6884 c     - It is only sensible to apply this function to pointers that
6885 f     - It is only sensible to apply this routine to pointers that
6886 *     have been created within (or exported to) the current context
6887 c     and have not been rendered exempt using astExempt.
6888 f     and have not been rendered exempt using AST_EXEMPT.
6889 *     Applying it to an unsuitable Object pointer has no effect.
6890 *--
6891 
6892 *  Implementation Notes:
6893 *     - This function does not exist in the "protected" interface to
6894 *     the Object class and is not available to other class
6895 *     implementations.
6896 */
6897 
6898 /* Local Variables: */
6899    astDECLARE_GLOBALS            /* Thread-specific global data */
6900    int context;                  /* Handle context level */
6901    int ihandle;                  /* Offset of Handle in "handles" array */
6902 
6903 /* Check the global error status. */
6904    if ( !astOK ) return;
6905 
6906 /* Get a pointer to Thread-specific global data. */
6907    astGET_GLOBALS(NULL);
6908 
6909 /* Obtain the Object pointer from the ID supplied and validate the
6910    pointer to ensure it identifies a valid Object. */
6911    (void) astCheckObject( astMakePointer( this_id ) );
6912    if ( astOK ) {
6913 
6914 /* Gain exclusive access to the handles array. */
6915       LOCK_MUTEX2;
6916 
6917 /* Obtain the Handle offset for this Object. */
6918       ihandle = CheckId( this_id, 1, status );
6919       if ( ihandle != -1 ) {
6920 
6921 /* Check that the current context level is at least 1 and report an
6922    error if it is not. */
6923          if ( context_level < 1 ) {
6924             if( astOK ) astError( AST__EXPIN, "astExport(%s): Attempt to export an Object "
6925                                   "from context level zero.", status,
6926                                   astGetClass( handles[ ihandle ].ptr ) );
6927 
6928 /* Extract the context level at which the Object was created. */
6929          } else {
6930             context = handles[ ihandle ].context;
6931 
6932 /* Check that the Object's existing context level is high enough to be
6933    affected by being exported to the next outer context level. If not,
6934    do nothing. */
6935             if ( context > ( context_level - 1 ) ) {
6936 
6937 /* Set the new context level. */
6938                handles[ ihandle ].context = context_level - 1;
6939 
6940 /* Remove the object's Handle from its original active Handles list
6941    and insert it into the list appropriate to its new context
6942    level. */
6943                RemoveHandle( ihandle, &active_handles[ context ], status );
6944                InsertHandle( ihandle, &active_handles[ context_level - 1 ],
6945                              status );
6946 
6947 /* If required, tell the user that the handle has been exempted. */
6948 #ifdef MEM_DEBUG
6949                astHandleUse( ihandle, "exported from context level %d",
6950                               context_level );
6951 #endif
6952             }
6953          }
6954       }
6955       UNLOCK_MUTEX2;
6956    }
6957 }
6958 
astImportId_(AstObject * this_id,int * status)6959 void astImportId_( AstObject *this_id, int *status ) {
6960 /*
6961 *++
6962 *  Name:
6963 c     astImport
6964 f     AST_IMPORT
6965 
6966 *  Purpose:
6967 *     Import an Object pointer to the current context.
6968 
6969 *  Type:
6970 *     Public function.
6971 
6972 *  Synopsis:
6973 c     #include "object.h"
6974 c     void astImport( AstObject *this )
6975 f     CALL AST_IMPORT( THIS, STATUS )
6976 
6977 *  Class Membership:
6978 *     Object method.
6979 
6980 *  Description:
6981 c     This function
6982 f     This routine
6983 *     imports an Object pointer that was created in a higher or lower
6984 *     level context, into the current AST context.
6985 *     This means that the pointer will be annulled when the current context
6986 c     is ended (with astEnd).
6987 f     is ended (with AST_END).
6988 
6989 *  Parameters:
6990 c     this
6991 f     THIS = INTEGER (Given)
6992 *        Object pointer to be imported.
6993 f     STATUS = INTEGER (Given and Returned)
6994 f        The global status.
6995 
6996 *  Applicability:
6997 *     Object
6998 c        This function applies to all Objects.
6999 f        This routine applies to all Objects.
7000 
7001 *--
7002 
7003 *  Implementation Notes:
7004 *     - This function does not exist in the "protected" interface to
7005 *     the Object class and is not available to other class
7006 *     implementations.
7007 */
7008 
7009 /* Local Variables: */
7010    astDECLARE_GLOBALS            /* Thread-specific global data */
7011    int context;                  /* Handle context level */
7012    int ihandle;                  /* Offset of Handle in "handles" array */
7013 
7014 /* Check the global error status. */
7015    if ( !astOK ) return;
7016 
7017 /* Get a pointer to Thread-specific global data. */
7018    astGET_GLOBALS(NULL);
7019 
7020 /* Obtain the Object pointer from the ID supplied and validate the
7021    pointer to ensure it identifies a valid Object. */
7022    (void) astCheckObject( astMakePointer( this_id ) );
7023    if ( astOK ) {
7024 
7025 /* Gain exclusive access to the handles array. */
7026       LOCK_MUTEX2;
7027 
7028 /* Obtain the Handle offset for this Object. */
7029       ihandle = CheckId( this_id, 1, status );
7030       if ( ihandle != -1 ) {
7031 
7032 /* Extract the context level at which the Object was created. */
7033          context = handles[ ihandle ].context;
7034 
7035 /* Do nothing if the Identifier already belongs to the current context. */
7036          if( context != context_level ) {
7037 
7038 /* Set the new context level. */
7039             handles[ ihandle ].context = context_level;
7040 
7041 /* Remove the object's Handle from its original active Handles list
7042    and insert it into the list appropriate to its new context
7043    level. */
7044             RemoveHandle( ihandle, &active_handles[ context ], status );
7045             InsertHandle( ihandle, &active_handles[ context_level ], status );
7046 
7047 /* If required, tell the user that the handle has been imported. */
7048 #ifdef MEM_DEBUG
7049             astHandleUse( ihandle, "imported into context level %d",
7050                            context_level );
7051 #endif
7052          }
7053       }
7054       UNLOCK_MUTEX2;
7055    }
7056 }
7057 
astLockId_(AstObject * this_id,int wait,int * status)7058 void astLockId_( AstObject *this_id, int wait, int *status ) {
7059 /*
7060 c++
7061 *  Name:
7062 *     astLock
7063 
7064 *  Purpose:
7065 *     Lock an Object for exclusive use by the calling thread.
7066 
7067 *  Type:
7068 *     Public function.
7069 
7070 *  Synopsis:
7071 *     #include "object.h"
7072 *     void astLock( AstObject *this, int wait )
7073 
7074 *  Class Membership:
7075 *     Object method.
7076 
7077 *  Description:
7078 *     The thread-safe public interface to AST is designed so that an
7079 *     error is reported if any thread attempts to use an Object that it
7080 *     has not previously locked for its own exclusive use using this
7081 *     function. When an Object is created, it is initially locked by the
7082 *     thread that creates it, so newly created objects do not need to be
7083 *     explicitly locked. However, if an Object pointer is passed to
7084 *     another thread, the original thread must first unlock it (using
7085 *     astUnlock) and the new thread must then lock it (using astLock)
7086 *     before the new thread can use the Object.
7087 *
7088 *     The "wait" parameter determines what happens if the supplied Object
7089 *     is curently locked by another thread when this function is invoked.
7090 
7091 *  Parameters:
7092 *     this
7093 *        Pointer to the Object to be locked.
7094 *     wait
7095 *        If the Object is curently locked by another thread then this
7096 *        function will either report an error or block. If a non-zero value
7097 *        is supplied for "wait", the calling thread waits until the object
7098 *        is available for it to use. Otherwise, an error is reported and
7099 *        the function returns immediately without locking the Object.
7100 
7101 *  Applicability:
7102 *     Object
7103 *        This function applies to all Objects.
7104 
7105 *  Notes:
7106 *     - The astAnnul function is exceptional in that it can be used on
7107 *     pointers for Objects that are not currently locked by the calling
7108 *     thread. All other AST functions will report an error.
7109 *     - The Locked object will belong to the current AST context.
7110 *     - This function returns without action if the Object is already
7111 *     locked by the calling thread.
7112 *     - If simultaneous use of the same object is required by two or more
7113 *     threads, astCopy should be used to to produce a deep copy of
7114 *     the Object for each thread. Each copy should then be unlocked by
7115 *     the parent thread (i.e. the thread that created the copy), and then
7116 *     locked by the child thread (i.e. the thread that wants to use the
7117 *     copy).
7118 *     - This function is only available in the C interface.
7119 *     - This function returns without action if the AST library has
7120 *     been built without POSIX thread support (i.e. the "-with-pthreads"
7121 *     option was not specified when running the "configure" script).
7122 c--
7123 */
7124 
7125 /* This function odes nothing if thread support is not enabvled. */
7126 #if defined(THREAD_SAFE)
7127 
7128 /* Local Variables: */
7129    astDECLARE_GLOBALS            /* Thread-specific global data */
7130    AstObject *fail;              /* Pointer to Object that failed to lock */
7131    AstObject *this;              /* Pointer to Object */
7132    int ihandle;                  /* Index of supplied objetc handle */
7133    int lstat;                    /* Local status value */
7134 
7135 /* Obtain the Object pointer from the ID supplied and validate the
7136    pointer to ensure it identifies a valid Object (this generates an
7137    error if it doesn't). Note, we use the "astMakePointer_NoLockCheck",
7138    since the usual "astMakePointer" macro invokes astCheckLock to report
7139    an error if the Object is not currently locked by the calling thread. */
7140    if ( !astIsAObject( this = astMakePointer_NoLockCheck( this_id ) ) ) return;
7141 
7142 /* Ensure the global data for this class is accessable. Do not use the
7143    globals pointer stored in "*this" because "*this" may be locked by
7144    another thread and so we would pick up the wrong globals. */
7145    astGET_GLOBALS(NULL);
7146 
7147 /* Ensure the running thread has sole access to the static handles arrays. */
7148    LOCK_MUTEX2;
7149 
7150 /* Ensure the Handles arrays have been initialised. */
7151    if ( !active_handles ) InitContext( status );
7152 
7153 /* Get the Handle index for the supplied object identifier. No error is
7154    reported if the handle is not curently associated with a thread.
7155    However, an error is reported if the Handle is associated with any
7156    thread other than the running thread. */
7157    ihandle = CheckId( this_id, 0, status );
7158 
7159 /* We've finished with the handles arrays, for the moment. */
7160    UNLOCK_MUTEX2;
7161 
7162 /* Check the object pointer was valid. */
7163    if( ihandle != -1 ){
7164 
7165 /* The protected astManageLock function implements the public functions,
7166    astLock and astUnlock. */
7167       lstat = astManageLock( this, AST__LOCK, wait, &fail );
7168       if( astOK ) {
7169          if( lstat == 1 ) {
7170             if( fail == this ) {
7171                astError( AST__LCKERR, "astLock(%s): Failed to lock the %s because"
7172                          " it is already locked by another thread (programming "
7173                          "error).", status, astGetClass( this ),
7174                          astGetClass( this ) );
7175 
7176             } else {
7177                astError( AST__LCKERR, "astLock(%s): Failed to lock the %s because"
7178                          " a %s contained within it is already locked by another "
7179                          "thread (programming error).", status,
7180                          astGetClass( this ), astGetClass( this ),
7181                          astGetClass( fail ) );
7182             }
7183 
7184          } else if( lstat == 2 ) {
7185             astError( AST__LCKERR, "astLock(%s): Failed to lock a POSIX mutex.", status,
7186                       astGetClass( this ) );
7187 
7188 /* If the Object is now locked for the running thread... */
7189          } else {
7190 
7191 /* We need access to the handles arrays again. */
7192             LOCK_MUTEX2;
7193 
7194 /* If the supplied handle is not currently assigned to any thread, assign
7195    it to the running thread. */
7196             if( handles[ ihandle ].context == UNOWNED_CONTEXT ) {
7197                RemoveHandle( ihandle, &unowned_handles, status );
7198 
7199 #if defined(MEM_DEBUG)
7200                astHandleUse( ihandle, "locked by thread %d at context level %d",
7201                              handles[ ihandle ].thread, context_level );
7202 #endif
7203 
7204                handles[ ihandle ].thread = AST__THREAD_ID;
7205                handles[ ihandle ].context = context_level;
7206                InsertHandle( ihandle, &active_handles[ context_level ],
7207                                 status );
7208             }
7209 
7210 /* Finished with the handles arrays again. */
7211             UNLOCK_MUTEX2;
7212          }
7213       }
7214    }
7215 #endif
7216 }
7217 
astUnlockId_(AstObject * this_id,int report,int * status)7218 void astUnlockId_( AstObject *this_id, int report, int *status ) {
7219 /*
7220 c++
7221 *  Name:
7222 *     astUnlock
7223 
7224 *  Purpose:
7225 *     Unlock an Object for use by other threads.
7226 
7227 *  Type:
7228 *     Public function.
7229 
7230 *  Synopsis:
7231 *     #include "object.h"
7232 *     void astUnlock( AstObject *this, int report )
7233 
7234 *  Class Membership:
7235 *     Object method.
7236 
7237 *  Description:
7238 *     Unlocks an Object previously locked using astLock, so that other
7239 *     threads can use the Object. See astLock for further details.
7240 
7241 *  Parameters:
7242 *     this
7243 *        Pointer to the Object to be unlocked.
7244 *     report
7245 *        If non-zero, an error will be reported if the supplied Object,
7246 *        or any Object contained within the supplied Object, is not
7247 *        currently locked by the running thread. If zero, such Objects
7248 *        will be left unchanged, and no error will be reported.
7249 
7250 *  Applicability:
7251 *     Object
7252 *        This function applies to all Objects.
7253 
7254 *  Notes:
7255 *     - This function attempts to execute even if the global error
7256 *     status is set, but no further error report will be made if it
7257 *     subsequently fails under these circumstances.
7258 *     - All unlocked Objects are excluded from AST context handling until
7259 *     they are re-locked using astLock.
7260 *     - This function is only available in the C interface.
7261 *     - This function returns without action if the Object is not currently
7262 *     locked by any thread. If it is locked by the running thread, it is
7263 *     unlocked. If it is locked by another thread, an error will be reported
7264 *     if "error" is non-zero.
7265 *     - This function returns without action if the AST library has
7266 *     been built without POSIX thread support (i.e. the "-with-pthreads"
7267 *     option was not specified when running the "configure" script).
7268 c--
7269 */
7270 
7271 /* This function odes nothing if thread support is not enabvled. */
7272 #if defined(THREAD_SAFE)
7273 
7274 /* Local Variables: */
7275    astDECLARE_GLOBALS            /* Thread-specific global data */
7276    AstErrorContext error_context;/* Info about the current error context */
7277    AstObject *fail;              /* Pointer to Object that failed */
7278    AstObject *this;              /* Pointer to Object */
7279    int ihandle;                  /* Index of supplied objetc handle */
7280    int lstat;                    /* Local status value */
7281 
7282 /* Obtain the Object pointer from the ID supplied and validate the
7283    pointer to ensure it identifies a valid Object (this generates an
7284    error if it doesn't). Note, we use the "astMakePointer_NoLockCheck",
7285    since the usual "astMakePointer" macro invokes astCheckLock to report
7286    an error if the Object is not currently locked by the calling thread. */
7287    if ( !astIsAObject( this = astMakePointer_NoLockCheck( this_id ) ) ) return;
7288 
7289 /* Ensure the global data for this class is accessable. */
7290    astGET_GLOBALS(this);
7291 
7292 /* Start a new error reporting context. This saves any existing error status
7293    and then clear the status value. It also defer further error reporting. */
7294    astErrorBegin( &error_context );
7295 
7296 /* Ensure the running thread has sole access to the static handles arrays. */
7297    LOCK_MUTEX2;
7298 
7299 /* Ensure the Handles arrays have been initialised. */
7300    if ( !active_handles ) InitContext( status );
7301 
7302 /* Get the Handle index for the supplied object identifier. Report an error
7303    if the handle is not curently associated with the running thread. */
7304    ihandle = CheckId( this_id, 1, status );
7305 
7306 /* Break the associated of the handle with the current thread so that the
7307    handle is not assigned to any thread. We do this before unlocking the
7308    Object structure (using astManageLock) since as soon as astManageLock
7309    returns, another thread that is waiting for the object to be unlocked
7310    may start up and modify the handle properties. */
7311    if( ihandle >= 0 && handles[ ihandle ].context >= 0 ) {
7312       RemoveHandle( ihandle, &active_handles[ handles[ ihandle ].context ],
7313                     status );
7314 #if defined(MEM_DEBUG)
7315       astHandleUse( ihandle, "unlocked from thread %d at context "
7316                     "level %d", handles[ ihandle ].thread,
7317                     handles[ ihandle ].context );
7318 #endif
7319       handles[ ihandle ].thread = -1;
7320       handles[ ihandle ].context = UNOWNED_CONTEXT;
7321       InsertHandle( ihandle, &unowned_handles, status );
7322    }
7323 
7324 /* We've finished with the handles arrays, for the moment. */
7325    UNLOCK_MUTEX2;
7326 
7327 /* Check the supplied object pointer was valid. */
7328    if( ihandle != -1 ){
7329 
7330 /* The protected astManageLock function implements the public functions,
7331    astLock and astUnlock. */
7332       lstat = astManageLock( this, AST__UNLOCK, 0, &fail );
7333       if( astOK ) {
7334          if( lstat == 1 ) {
7335             if( report ) {
7336                if( fail == this ) {
7337                   astError( AST__LCKERR, "astUnlock(%s): Failed to unlock the %s "
7338                             "because it is locked by another thread (programming "
7339                             "error).", status, astGetClass( this ),
7340                             astGetClass( this ) );
7341 
7342                } else {
7343                   astError( AST__LCKERR, "astUnlock(%s): Failed to unlock the %s "
7344                             "because a %s contained within it is locked by another "
7345                             "thread (programming error).", status,
7346                             astGetClass( this ), astGetClass( this ),
7347                             astGetClass( fail ) );
7348                }
7349             }
7350 
7351          } else if( lstat == 3 ) {
7352             astError( AST__LCKERR, "astUnlock(%s): Failed to unlock a POSIX mutex.", status,
7353                       astGetClass( this ) );
7354 
7355          }
7356       }
7357    }
7358 
7359 /* End the error reporting context. If an error has occurred within this
7360    function, then this will display the deferred error messages so long
7361    as there was no error condition on entry to this function. If there
7362    was an error condition on entry, then the original status value will be
7363    re-instated. */
7364    astErrorEnd( &error_context );
7365 
7366 #endif
7367 }
7368 
astI2P_(int integer,int * status)7369 AstObject *astI2P_( int integer, int *status ) {
7370 /*
7371 *+
7372 *  Name:
7373 *     astI2P
7374 
7375 *  Purpose:
7376 *     Pack an integer Object ID into a pointer.
7377 
7378 *  Type:
7379 *     Public function.
7380 
7381 *  Synopsis:
7382 *     #include "object.h"
7383 *     AstObject *astI2P( int integer )
7384 
7385 *  Class Membership:
7386 *     Object class function.
7387 
7388 *  Description:
7389 *     This function accepts an integer (int) value representing an
7390 *     Object identifier and packs its bit pattern into a pointer value
7391 *     (from which it may subsequently be retrieved using astP2I).
7392 *
7393 *     These functions should be used to avoid any dependency on
7394 *     integer-to-pointer conversions (given that the values are not
7395 *     true pointers) which might affect the exchange of Object
7396 *     identifier values with other languages, such as Fortran 77,
7397 *     where they are stored as integers.
7398 
7399 *  Parameters:
7400 *     integer
7401 *        The integer value to be stored.
7402 
7403 *  Returned Value:
7404 *     The resulting pointer value (which is not usually a valid C pointer).
7405 
7406 *  Notes:
7407 *     - This function does not perform error checking and does not
7408 *     generate errors.
7409 *     - This is a protected function in the sense that it is not
7410 *     intended that external users should invoke it directly.  It is
7411 *     accessible from external code, however, in order that public
7412 *     macros invoked from that code can make use of it.
7413 *-
7414 */
7415 
7416 /* Local Variables: */
7417    IdUnion temp;                 /* Overlapping int and pointer */
7418 
7419 /* Clear the pointer value in the "temp" IdUnion and then set the
7420    integer part of it to the value to be stored. */
7421    temp.pointer = zero_ptr;
7422    temp.integer = integer;
7423 
7424 /* Return the resulting pointer value. */
7425    return temp.pointer;
7426 }
7427 
InitContext(int * status)7428 MYSTATIC void InitContext( int *status ) {
7429 /*
7430 *  Name:
7431 *     InitContext
7432 
7433 *  Purpose:
7434 *     Initialise the first AST context level.
7435 
7436 *  Type:
7437 *     Private function.
7438 
7439 *  Synopsis:
7440 *     #include "object.h"
7441 *     void InitContext( int *status )
7442 
7443 *  Class Membership:
7444 *     Object member function.
7445 
7446 *  Description:
7447 *     This function initialises the first AST context level (the level
7448 *     before any call to astBegin has been made). It should be invoked
7449 *     once, before any use is made of context levels.
7450 
7451 *  Parameters:
7452 *     status
7453 *        Pointer to the inherited status variable.
7454 
7455 *  Parameters:
7456 *     None.
7457 
7458 *  Notes:
7459 *     - This function does nothing after the first successful invocation.
7460 */
7461 
7462 /* Local Variables: */
7463    astDECLARE_GLOBALS            /* Thread-specific global data */
7464 
7465 /* Check the global error status. */
7466    if ( !astOK ) return;
7467 
7468 /* Get a pointer to Thread-specific global data. */
7469    astGET_GLOBALS(NULL);
7470 
7471 /* Check that the active_handles array hasn't already been allocated. */
7472    if ( !active_handles ) {
7473 
7474 /* Allocate and initialise the "active_handles" array. */
7475 
7476       astBeginPM;
7477       active_handles = astMalloc( sizeof( int ) );
7478       astEndPM;
7479 
7480       if ( astOK ) active_handles[ 0 ] = -1;
7481    }
7482 }
7483 
InsertHandle(int ihandle,int * head,int * status)7484 MYSTATIC void InsertHandle( int ihandle, int *head, int *status ) {
7485 /*
7486 *  Name:
7487 *     InsertHandle
7488 
7489 *  Purpose:
7490 *     Insert a Handle into a list.
7491 
7492 *  Type:
7493 *     Private function.
7494 
7495 *  Synopsis:
7496 *     #include "object.h"
7497 *     void InsertHandle( int ihandle, int *head, int *status )
7498 
7499 *  Class Membership:
7500 *     Object member function.
7501 
7502 *  Description:
7503 *     This function inserts a Handle structure into a doubly linked
7504 *     list of such structures composed of elements drawn from the
7505 *     "handles" array. The new list member is inserted in front of the
7506 *     member previously occupying the "head of list" position.
7507 
7508 *  Parameters:
7509 *     ihandle
7510 *        Offset in the "handles" array that identifies the handle to
7511 *        be added to the list.
7512 *     head
7513 *        Address of an int which holds the offset in the "handles"
7514 *        array of the element at the head of the list (or -1 if the
7515 *        list is empty). This value will be updated to identify the
7516 *        new list member.
7517 *     status
7518 *        Pointer to the inherited status variable.
7519 
7520 *  Notes:
7521 *     - This function does not perform error chacking and does not
7522 *     generate errors.
7523 *     - The lists generated by this function use integer offsets into
7524 *     the "handles" array for their links, rather than pointers. This
7525 *     is because the array may be re-located in memory when it needs
7526 *     to be extended, so pointers to its element would not remain
7527 *     valid.
7528 *     - The list elements are drawn from the "handles" array in the
7529 *     first place so that they can be addressed by small integers (the
7530 *     offset in the array). This allows references to Handles to be
7531 *     encoded along with security information into an integer that is
7532 *     sufficiently short to be exported to other languages
7533 *     (e.g. Fortran) which might not be able to accommodate
7534 *     full-length C pointers.
7535 */
7536 
7537 
7538 #if defined(MEM_DEBUG)
7539    char buf[80];
7540    astHandleUse( ihandle, "about to be inserted into %s (%d)",
7541                  HeadString( head, buf ), head );
7542    CheckList( head, status );
7543    CheckInList( ihandle, head, 0, status );
7544 #endif
7545 
7546 /* Check a head pointer was supplied (may not be if an error has
7547    occurred). */
7548    if( ! head ) return;
7549 
7550 /* If the list is empty, the sole new element points at itself. */
7551    if ( *head == -1 ) {
7552       handles[ ihandle ].flink = ihandle;
7553       handles[ ihandle ].blink = ihandle;
7554 
7555 /* Otherwise, insert the new element in front of the element at the
7556    head of the list. */
7557    } else {
7558       handles[ ihandle ].flink = *head;
7559       handles[ ihandle ].blink = handles[ *head ].blink;
7560       handles[ ( handles[ *head ].blink) ].flink = ihandle;
7561       handles[ *head ].blink = ihandle;
7562    }
7563 
7564 /* Update the list head to identify the new element. */
7565    *head = ihandle;
7566 
7567 #if defined(MEM_DEBUG)
7568    CheckList( head, status );
7569    astHandleUse( ihandle, "has been inserted into %s", buf );
7570 #endif
7571 }
7572 
astMakeId_(AstObject * this,int * status)7573 AstObject *astMakeId_( AstObject *this, int *status ) {
7574 /*
7575 *+
7576 *  Name:
7577 *     astMakeId
7578 
7579 *  Purpose:
7580 *     Issue an identifier for an Object.
7581 
7582 *  Type:
7583 *     Protected function.
7584 
7585 *  Synopsis:
7586 *     #include "object.h"
7587 *     AstObject *astMakeId( AstObject *this )
7588 
7589 *  Class Membership:
7590 *     Object member function.
7591 
7592 *  Description:
7593 *     This function takes a normal C pointer to an Object and
7594 *     associates an identifier with it.
7595 
7596 *  Parameters:
7597 *     this
7598 *        Pointer to an Object. Note that this function copies this
7599 *        value (it is not cloned), so the caller should not annul the
7600 *        pointer afterwards.
7601 
7602 *  Returned Value:
7603 *     The resulting identifier value.
7604 
7605 *  Notes:
7606 *     - An identifier value of zero will be returned and the supplied
7607 *     Object pointer will be annulled if this function is invoked with
7608 *     the global error status set or if it should fail for any reason.
7609 *     - A zero identifier value will also be returned if a NULL object
7610 *     pointer is supplied, but this will not provoke an error.
7611 *     - This is a protected function in the sense that it is not
7612 *     intended that external users should invoke it directly.  It is
7613 *     accessible from external code, however, in order that public
7614 *     macros invoked from that code can make use of it.
7615 *-
7616 */
7617 
7618 /* Local Variables: */
7619    astDECLARE_GLOBALS            /* Thread-specific global data */
7620    AstObject *id;                /* ID value to return */
7621    int ihandle;                  /* Handle offset */
7622 
7623 /* Initialise. */
7624    id = astI2P( 0 );
7625    ihandle = 0;
7626 
7627 /* Check the global error status. */
7628    if ( astOK ) {
7629 
7630 /* Get a pointer to Thread-specific global data. */
7631       astGET_GLOBALS(this);
7632 
7633 /* Gain exclusive access to the handles array. */
7634       LOCK_MUTEX2;
7635 
7636 /* If a non-NULL Object pointer was given, we must obtain a Handle
7637    structure to associate with it (otherwise a zero identifier value
7638    is returned without error). */
7639       if ( this ) {
7640 
7641 /* If the free Handles list is not empty, obtain a Handle from it. */
7642          if ( free_handles != -1 ) {
7643             ihandle = free_handles;
7644             RemoveHandle( ihandle, &free_handles, status );
7645 
7646 /* Otherwise, allocate a new Handle by extending the "handles" array
7647    and using the offset of the new element. */
7648          } else {
7649 
7650             astBeginPM;
7651             handles = astGrow( handles, nhandles + 1, sizeof( Handle ) );
7652             astEndPM;
7653 
7654             if ( astOK ) {
7655                ihandle = nhandles++;
7656 
7657                handles[ ihandle ].ptr = NULL;
7658                handles[ ihandle ].context = INVALID_CONTEXT;
7659                handles[ ihandle ].check = 0;
7660                handles[ ihandle ].flink = -1;
7661                handles[ ihandle ].blink = -1;
7662 #if defined(THREAD_SAFE)
7663                handles[ ihandle ].thread = 0;
7664 #endif
7665 
7666 #if defined(MEM_DEBUG)
7667                handles[ ihandle ].id = 0;
7668                handles[ ihandle ].vtab = NULL;
7669 #endif
7670             }
7671          }
7672 
7673 /* If the first AST context level has not yet been initialised, invoke
7674    InitContext to initialise it and allocate memory for the
7675    "active_handles" array which stores context information. */
7676          if ( astOK ) {
7677             if ( !active_handles ) InitContext( status );
7678 
7679 /* Store the Object pointer and current context level in the Handle. */
7680             if ( astOK ) {
7681                handles[ ihandle ].ptr = this;
7682                handles[ ihandle ].context = context_level;
7683 #if defined(THREAD_SAFE)
7684                handles[ ihandle ].thread = AST__THREAD_ID;
7685 #endif
7686 
7687 /* Store extra debugging information in the handle if enabled */
7688 #if defined(MEM_DEBUG)
7689                handles[ ihandle ].id = astMemoryId( this );
7690                handles[ ihandle ].vtab = this->vtab;
7691                astHandleUse( ihandle, "associated with a %s (id %d)",
7692                               astGetClass( this ), astMemoryId( this ));
7693 #endif
7694 
7695 /* Insert the Handle into the active Handles list for the current
7696    context level. */
7697                InsertHandle( ihandle, &active_handles[ context_level ], status );
7698 
7699 /* Associate an identifier value with the Handle. */
7700                id = AssocId( ihandle, status );
7701 
7702 /* If an error occurred, clean up by annulling the Handle. This
7703    ensures that the Object pointer is annulled and returns the unused
7704    Handle to the Free Handle list. */
7705                if ( !astOK ) {
7706                   AnnulHandle( ihandle, status );
7707                   this = NULL;
7708                }
7709 
7710 /* If the Handle wasn't used (because of an earlier error), return it
7711    to the free Handles list. */
7712             } else {
7713                InsertHandle( ihandle, &free_handles, status );
7714             }
7715          }
7716       }
7717       UNLOCK_MUTEX2;
7718    }
7719 
7720 /* If a bad status value was either supplied or generated within this
7721    function, then annul the supplied pointer (unless it is NULL). */
7722    if ( !astOK && this ) (void) astAnnul( this );
7723 
7724 /* Return the identifier value. */
7725    return id;
7726 }
7727 
astMakePointer_(AstObject * this_id,int * status)7728 AstObject *astMakePointer_( AstObject *this_id, int *status ) {
7729 /*
7730 *+
7731 *  Name:
7732 *     astMakePointer
7733 
7734 *  Purpose:
7735 *     Obtain a true C pointer from an Object identifier.
7736 
7737 *  Type:
7738 *     Protected function.
7739 
7740 *  Synopsis:
7741 *     #include "object.h"
7742 *     AstObject *astMakePointer( AstObject *this )
7743 
7744 *  Class Membership:
7745 *     Object class function.
7746 
7747 *  Description:
7748 *     This function accepts an external Object identifier and returns
7749 *     a true C Object pointer that may be de-referenced to access the
7750 *     Object's data and methods.
7751 
7752 *  Parameters:
7753 *     this
7754 *        The identifier value.
7755 
7756 *  Returned Value:
7757 *     The true C pointer value.
7758 
7759 *  Notes:
7760 *     - In a thread-safe context, an error is reported if the supplied
7761 *     Object has not been locked by the calling thread (using astLock)
7762 *     prior to invoking this function.
7763 *     - The object reference count is not modified by this function,
7764 *     so the returned pointer should not be annulled by the caller.
7765 *     - Typically, this function should be used whenever a public
7766 *     function must accept identifier values directly (rather than
7767 *     having them translated automatically into pointers during
7768 *     argument validation by the astCheck<Class> range of functions).
7769 *     - Note that this function will NOT accept a true C pointer as an
7770 *     argument, even when invoked from internal code (with astCLASS
7771 *     defined). An identifier value MUST be supplied, and an error
7772 *     will result if it is not associated with an active Object.
7773 *     - This function attempts to execute even if the global error
7774 *     status is set, but no further error report will be made if it
7775 *     subsequently fails under these circumstances.
7776 *     - This is a protected function in the sense that it is not
7777 *     intended that external users should invoke it directly.  It is
7778 *     accessible from external code, however, in order that public
7779 *     macros invoked from that code can make use of it.
7780 *-
7781 */
7782 
7783 /* Local Variables: */
7784    AstObject *ptr;               /* Pointer value to return */
7785    int ihandle;                  /* Handle offset in "handles" array */
7786 
7787 /* Initialise. */
7788    ptr = NULL;
7789 
7790 /* Gain exclusive access to the handles array. */
7791    LOCK_MUTEX2;
7792 
7793 /* Validate the identifier supplied and derive the Handle offset. */
7794    ihandle = CheckId( this_id, 1, status );
7795 
7796 /* If the identifier was valid, extract the Object pointer from the
7797    Handle. */
7798    if ( ihandle != -1 ) ptr = handles[ ihandle ].ptr;
7799 
7800    UNLOCK_MUTEX2;
7801 
7802 /* Return the result. */
7803    return ptr;
7804 }
7805 
astMakePointer_NoLockCheck_(AstObject * this_id,int * status)7806 AstObject *astMakePointer_NoLockCheck_( AstObject *this_id, int *status ) {
7807 /*
7808 *+
7809 *  Name:
7810 *     astMakePointer_NoLockCheck
7811 
7812 *  Purpose:
7813 *     Obtain a true C pointer from an Object identifier.
7814 
7815 *  Type:
7816 *     Protected function.
7817 
7818 *  Synopsis:
7819 *     #include "object.h"
7820 *     AstObject *astMakePointer_NoLockCheck( AstObject *this )
7821 
7822 *  Class Membership:
7823 *     Object class function.
7824 
7825 *  Description:
7826 *     This function accepts an external Object identifier and returns
7827 *     a true C Object pointer that may be de-referenced to access the
7828 *     Object's data and methods.
7829 *
7830 *     It is identicial to astMakePointer except that it does not check
7831 *     that the supplied Object is locked by the running thread.
7832 
7833 *  Parameters:
7834 *     this
7835 *        The identifier value.
7836 
7837 *  Returned Value:
7838 *     The true C pointer value.
7839 
7840 *  Notes:
7841 *     - The object reference count is not modified by this function,
7842 *     so the returned pointer should not be annulled by the caller.
7843 *     - Typically, this function should be used whenever a public
7844 *     function must accept identifier values directly (rather than
7845 *     having them translated automatically into pointers during
7846 *     argument validation by the astCheck<Class> range of functions).
7847 *     - Note that this function will NOT accept a true C pointer as an
7848 *     argument, even when invoked from internal code (with astCLASS
7849 *     defined). An identifier value MUST be supplied, and an error
7850 *     will result if it is not associated with an active Object.
7851 *     - This function attempts to execute even if the global error
7852 *     status is set, but no further error report will be made if it
7853 *     subsequently fails under these circumstances.
7854 *     - This is a protected function in the sense that it is not
7855 *     intended that external users should invoke it directly.  It is
7856 *     accessible from external code, however, in order that public
7857 *     macros invoked from that code can make use of it.
7858 *-
7859 */
7860 
7861 /* Local Variables: */
7862    AstObject *ptr;               /* Pointer value to return */
7863    int ihandle;                  /* Handle offset in "handles" array */
7864 
7865 /* Initialise. */
7866    ptr = NULL;
7867 
7868 /* Gain exclusive access to the handles array. */
7869    LOCK_MUTEX2;
7870 
7871 /* Validate the identifier supplied and derive the Handle offset. */
7872    ihandle = CheckId( this_id, 0, status );
7873 
7874 /* If the identifier was valid, extract the Object pointer from the
7875    Handle. */
7876    if ( ihandle != -1 ) ptr = handles[ ihandle ].ptr;
7877 
7878    UNLOCK_MUTEX2;
7879 
7880 /* Return the result. */
7881    return ptr;
7882 }
7883 
astP2I_(AstObject * pointer,int * status)7884 int astP2I_( AstObject *pointer, int *status ) {
7885 /*
7886 *+
7887 *  Name:
7888 *     astP2I
7889 
7890 *  Purpose:
7891 *     Extract an integer Object ID from a pointer.
7892 
7893 *  Type:
7894 *     Public function.
7895 
7896 *  Synopsis:
7897 *     #include "object.h"
7898 *     int astP2I( AstObject *pointer )
7899 
7900 *  Class Membership:
7901 *     Object class function.
7902 
7903 *  Description:
7904 *     This function retrieves an integer (int) value representing an
7905 *     Object identifier from a pointer value (into which it has
7906 *     previously been packed using astI2P).
7907 *
7908 *     These functions should be used to avoid any dependency on
7909 *     integer-to-pointer conversions (given that the values are not
7910 *     true pointers) which might affect the exchange of Object
7911 *     identifier values with other languages, such as Fortran 77,
7912 *     where they are stored as integers.
7913 
7914 *  Parameters:
7915 *     pointer
7916 *       The pointer value into which the ID has previously been packed.
7917 
7918 *  Returned Value:
7919 *     The extracted Object identifier value as an integer (int).
7920 
7921 *  Notes:
7922 *     - This function does not perform error checking and does not
7923 *     generate errors.
7924 *     - This is a protected function in the sense that it is not
7925 *     intended that external users should invoke it directly.  It is
7926 *     accessible from external code, however, in order that public
7927 *     macros invoked from that code can make use of it.
7928 *-
7929 */
7930 
7931 /* Local Variables: */
7932    IdUnion temp;                 /* Overlapping int and pointer */
7933 
7934 /* Store the pointer value supplied. */
7935    temp.pointer = pointer;
7936 
7937 /* Return the integer part of it. */
7938    return temp.integer;
7939 }
7940 
RemoveHandle(int ihandle,int * head,int * status)7941 MYSTATIC void RemoveHandle( int ihandle, int *head, int *status ) {
7942 /*
7943 *  Name:
7944 *     RemoveHandle
7945 
7946 *  Purpose:
7947 *     Remove a Handle from a list.
7948 
7949 *  Type:
7950 *     Private function.
7951 
7952 *  Synopsis:
7953 *     #include "object.h"
7954 *     void RemoveHandle( int ihandle, int *head )
7955 
7956 *  Class Membership:
7957 *     Object member function.
7958 
7959 *  Description:
7960 *     This function removes a Handle structure from a doubly linked
7961 *     list of such structures composed of elements drawn from the
7962 *     "handles" array. The "head of list" position is updated if
7963 *     necessary.
7964 
7965 *  Parameters:
7966 *     ihandle
7967 *        Offset in the "handles" array that identifies the Handle to
7968 *        be removed from the list (note that the Handle must actually
7969 *        be in the list, although this function does not check this).
7970 *     head
7971 *        Address of an int which holds the offset in the "handles"
7972 *        array of the element at the head of the list. This value will
7973 *        be updated if necessary to identify the new list head (or set
7974 *        to -1 if removing the Handle causes the list to become
7975 *        empty).
7976 
7977 *  Notes:
7978 *     - This function does not perform error chacking and does not
7979 *     generate errors.
7980 *     - See the InsertHandle function for details of how and why lists
7981 *     of Handles are constructed.
7982 */
7983 
7984 
7985 #if defined(MEM_DEBUG)
7986    char buf[80];
7987    astHandleUse( ihandle, "about to be removed from %s", HeadString( head, buf ) );
7988    CheckList( head, status );
7989    CheckInList( ihandle, head, 1, status );
7990 #endif
7991 
7992 /* Check a head pointer was supplied (may not be if an error has
7993    occurred). */
7994    if( ! head ) return;
7995 
7996 /* Remove the Handle from the list by re-establishing links between
7997    the elements on either side of it. */
7998    handles[ ( handles[ ihandle ].blink ) ].flink = handles[ ihandle ].flink;
7999    handles[ ( handles[ ihandle ].flink ) ].blink = handles[ ihandle ].blink;
8000 
8001 /* If the element removed was at the head of the list, update the head
8002    of list offset to identify the following element. */
8003    if ( ihandle == *head ) {
8004       *head = handles[ ihandle ].flink;
8005 
8006 /* If the head of list still identifies the removed element, then note
8007    that the list is now empty. */
8008       if ( *head == ihandle ) *head = -1;
8009    }
8010 
8011 /* Make the removed element point at itself. */
8012    handles[ ihandle ].flink = ihandle;
8013    handles[ ihandle ].blink = ihandle;
8014 
8015 #if defined(MEM_DEBUG)
8016    astHandleUse( ihandle, "has been removed from %s", buf );
8017    CheckList( head, status );
8018 #endif
8019 }
8020 
astSetId_(void * this_id_void,const char * settings,...)8021 void astSetId_( void *this_id_void, const char *settings, ... ) {
8022 /*
8023 *  Name:
8024 *     astSetId_
8025 
8026 *  Purpose:
8027 *     Set values for an Object's attributes via an identifier.
8028 
8029 *  Type:
8030 *     Private function.
8031 
8032 *  Synopsis:
8033 *     #include "object.h"
8034 *     void astSetId_( AstObject *this, const char *settings, ... )
8035 
8036 *  Class Membership:
8037 *     Object member function.
8038 
8039 *  Description:
8040 *     This function implements the axternal interface to the astSet
8041 *     method (q.v.). It accepts an Object identifier, but otherwise
8042 *     behaves identically to astSet.
8043 
8044 *  Parameters:
8045 *     this
8046 *        Object identifier.
8047 *     settings
8048 *        Pointer to a null-terminated string containing a
8049 *        comma-separated list of attribute settings.
8050 *     ...
8051 *        Optional arguments which supply values to be substituted for
8052 *        any "printf"-style format specifiers that appear in the
8053 *        "settings" string.
8054 
8055 *  Notes:
8056 *     - Because this function has a variable argument list, it is
8057 *     invoked by a macro that evaluates to a function pointer (not a
8058 *     function invocation) and no checking or casting of arguments is
8059 *     performed before the function is invoked. Because of this, the
8060 *     Object identifier is of type (void *) and is converted and
8061 *     validated within the function itself.
8062 */
8063 
8064 /* Local Variables: */
8065    AstObject *this;              /* Pointer to the Object structure */
8066    int *status;                  /* Pointer to inherited status variable */
8067    va_list args;                 /* Variable argument list */
8068 
8069 /* Get a pointer to the integer holding the inherited status value. */
8070    status = astGetStatusPtr;
8071 
8072 /* Check the global error status. */
8073    if ( !astOK ) return;
8074 
8075 /* Obtain the Object pointer from the ID supplied and validate the
8076    pointer to ensure it identifies a valid Object. */
8077    this = astCheckObject( astMakePointer( this_id_void ) );
8078    if ( astOK ) {
8079 
8080 /* Obtain the variable argument list and pass all arguments to the
8081    astVSet method for interpretation. */
8082       va_start( args, settings );
8083       astVSet( this, settings, NULL, args );
8084       va_end( args );
8085    }
8086 }
8087 
astThreadId_(AstObject * this_id,int ptr,int * status)8088 int astThreadId_( AstObject *this_id, int ptr, int *status ) {
8089 /*
8090 c++
8091 *  Name:
8092 *     astThread
8093 
8094 *  Purpose:
8095 *     Determine the thread that owns an Object.
8096 
8097 *  Type:
8098 *     Public function.
8099 
8100 *  Synopsis:
8101 *     #include "object.h"
8102 *     int astThread( AstObject *this, int ptr )
8103 
8104 *  Class Membership:
8105 *     Object method.
8106 
8107 *  Description:
8108 *     Returns an integer that indicates whether the supplied Object (or
8109 *     Object pointer) is currently unlocked, or is currently locked by
8110 *     the running thread, or another thread.
8111 
8112 *  Parameters:
8113 *     this
8114 *        Pointer to the Object to be checked.
8115 *     ptr
8116 *        If non-zero, returns information about the supplied Object
8117 *        pointer, rather than the Object structure itself. See "Object
8118 *        Pointers and Structures" below.
8119 
8120 *  Returned Value:
8121 *     astThread()
8122 *        A value of AST__UNLOCKED is returned if the Object (or pointer)
8123 *        is currently unlocked (i.e. has been unlocked using astUnlock
8124 *        but has not yet been locked using astLock). A value of
8125 *        AST__RUNNING is returned if the Object (or pointer) is currently
8126 *        locked by the running thread. A value of AST__OTHER is returned
8127 *        if the Object (or pointer) is currently locked by the another
8128 *        thread.
8129 
8130 *  Object Pointers and Structures:
8131 *     At any one time, an AST Object can have several distinct pointers,
8132 *     any one of which can be used to access the Object structure. For
8133 *     instance, the astClone function will produce a new distinct pointer
8134 *     for a given Object. In fact, an AST "pointer" is not a real pointer
8135 *     at all - it is an identifier for a "handle" structure, encoded to
8136 *     make it look like a pointer. Each handle contains (amongst othere
8137 *     things) a "real" pointer to the Object structure. This allows more
8138 *     than one handle to refer to the same Object structure. So when you
8139 *     call astClone (for instance) you get back an identifier for a new
8140 *     handle that refers to the same Object as the supplied handle.
8141 *
8142 *     In order to use an Object for anything useful, it must be locked
8143 *     for use by the running thread (either implicitly at creation or
8144 *     explicitly using astLock). The identity of the thread is stored in
8145 *     both the Object structure, and in the handle that was passed to
8146 *     astLock (or returned by the constructor function). Thus it is
8147 *     possible for a thread to have active pointers for Objects that are
8148 *     currently locked by another thread. In general, if such a pointer is
8149 *     passed to an AST function an error will be reported indicating that
8150 *     the Object is currently locked by another thread. The two exceptions
8151 *     to this is that astAnnul can be used to annull such a pointer, and
8152 *     this function can be used to return information about the pointer.
8153 *
8154 *     The other practical consequence of this is that when astEnd is
8155 *     called, all active pointers currently owned by the running thread
8156 *     (at the current context level) are annulled. This includes pointers
8157 *     for Objects that are currently locked by other threads.
8158 *
8159 *     If the "ptr" parameter is zero, then the returned value describes
8160 *     the Object structure itself. If "ptr" is non-zero, then the returned
8161 *     value describes the supplied Object pointer (i.e. handle), rather
8162 *     than the Object structure.
8163 
8164 *  Notes:
8165 *     - This function attempts to execute even if the global error
8166 *     status is set, but no further error report will be made if it
8167 *     subsequently fails under these circumstances.
8168 *     - This function is only available in the C interface.
8169 *     - This function always returns AST__RUNNING if the AST library has
8170 *     been built without POSIX thread support (i.e. the "-with-pthreads"
8171 *     option was not specified when running the "configure" script).
8172 c--
8173 */
8174 
8175 /* Local Variables: */
8176    astDECLARE_GLOBALS       /* Thread-specific global data */
8177    int result;              /* The returned value */
8178 
8179 #if defined(THREAD_SAFE)
8180 
8181 /* More local Variables: */
8182    AstObject *this;
8183    int ihandle;
8184    int check;
8185 
8186 /* Ensure global variables are accessable. */
8187    astGET_GLOBALS(NULL);
8188 #endif
8189 
8190 /* Initialise the returned value */
8191    result = AST__RUNNING;
8192 
8193 /* Nothing more to do if AST was not build with thread support. */
8194 #if defined(THREAD_SAFE)
8195 
8196 /* If the ownership of the handle is being queried... */
8197    if( ptr ) {
8198 
8199 /* Lock the mutex that guards access to the handles array */
8200       LOCK_MUTEX2;
8201 
8202 /* Check the supplied object identifier is valid and get the
8203    corresponding index into the handles array. */
8204       ihandle = CheckId( this_id, 1, status );
8205       if( ihandle != -1 ) {
8206 
8207 /* Set the returned value on the basis of the threa didentifier stored in
8208    the handle structure. */
8209          if( handles[ ihandle ].thread == -1 ) {
8210             result = AST__UNLOCKED;
8211          } else if( handles[ ihandle ].thread != AST__THREAD_ID ) {
8212             result = AST__OTHER;
8213          }
8214       }
8215 
8216 /* Unlock the mutex that guards access to the handles array */
8217       UNLOCK_MUTEX2;
8218 
8219 /* Otherwise, the ownership of the Object is being queried. Obtain the
8220    Object pointer from the ID supplied and validate the pointer to ensure
8221    it identifies a valid Object (this generates an error if it doesn't).
8222    Note, we use the "astMakePointer_NoLockCheck", since the usual
8223    "astMakePointer" macro invokes astCheckLock to report an error if the
8224    Object is not currently locked by the calling thread. */
8225    } else if( astIsAObject( this = astMakePointer_NoLockCheck( this_id ) ) ) {
8226 
8227 /* Determine which thread (if any) has the object locked, and set an
8228    appropriate return value. */
8229       check = astManageLock( this, AST__CHECKLOCK, 0, NULL );
8230 
8231       if( check == 5 ) {
8232          result = AST__OTHER;
8233       } else if( check == 6 ) {
8234          result = AST__UNLOCKED;
8235       }
8236    }
8237 
8238 #endif
8239 
8240 /* Return the result. */
8241    return result;
8242 }
8243 
astVersion_(int * status)8244 int astVersion_( int *status ) {
8245 /*
8246 *++
8247 *  Name:
8248 c     astVersion
8249 f     AST_VERSION
8250 
8251 *  Purpose:
8252 *     Return the version of the AST library being used.
8253 
8254 *  Type:
8255 *     Public function.
8256 
8257 *  Synopsis:
8258 c     #include "object.h"
8259 c     int astVersion
8260 f     RESULT = AST_VERSION()
8261 
8262 *  Class Membership:
8263 *     Object class function.
8264 
8265 *  Description:
8266 c     This macro invokes a function which
8267 f     This function
8268 *     returns an integer representing the version of the AST library
8269 *     being used. The library version is formatted as a string such as
8270 *     "2.0-7" which contains integers representing the "major version" (2),
8271 *     the "minor version" (0) and the "release" (7). The integer returned
8272 *     by this function combines all three integers together into a single
8273 *     integer using the expresion:
8274 *
8275 *     (major version)*1E6 + (minor version)*1E3 + (release)
8276 
8277 *  Returned Value:
8278 c     astVersion
8279 f     AST_VERSION = INTEGER
8280 *        The major version, minor version and release numbers for the AST
8281 *        library, encoded as a single integer.
8282 
8283 *  Applicability:
8284 *     Object
8285 c        This macro applies to all Objects.
8286 f        This routine applies to all Objects.
8287 
8288 *--
8289 */
8290 
8291    return (int) AST__VMAJOR*1E6 + AST__VMINOR*1E3 + AST__RELEASE;
8292 }
8293 
astEscapes_(int new_value,int * status)8294 int astEscapes_( int new_value, int *status ) {
8295 /*
8296 *++
8297 *  Name:
8298 c     astEscapes
8299 f     AST_ESCAPES
8300 
8301 *  Purpose:
8302 *     Control whether graphical escape sequences are included in strings.
8303 
8304 *  Type:
8305 *     Public function.
8306 
8307 *  Synopsis:
8308 c     #include "object.h"
8309 c     int astEscapes( int new_value )
8310 f     RESULT = AST_ESCAPES( NEWVAL, STATUS )
8311 
8312 *  Class Membership:
8313 *     Object class function.
8314 
8315 *  Description:
8316 *     The Plot class defines a set of escape sequences which can be
8317 *     included within a text string in order to control the appearance of
8318 *     sub-strings within the text. See the Escape attribute for a
8319 *     description of these escape sequences. It is usually inappropriate
8320 *     for AST to return strings containing such escape sequences when
8321 *     called by application code. For instance, an application which
8322 *     displays the value of the Title attribute of a Frame usually does
8323 *     not want the displayed string to include potentially long escape
8324 *     sequences which a human read would have difficuly interpreting.
8325 *     Therefore the default behaviour is for AST to strip out such escape
8326 *     sequences when called by application code. This default behaviour
8327 *     can be changed using this function.
8328 
8329 *  Parameters:
8330 c     new_value
8331 f     NEWVAL = INTEGER (Given)
8332 *        A flag which indicates if escapes sequences should be included
8333 *        in returned strings. If zero is supplied, escape sequences will
8334 *        be stripped out of all strings returned by any AST function. If
8335 *        a positive value is supplied, then any escape sequences will be
8336 *        retained in the value returned to the caller. If a negative
8337 *        value is supplied, the current value of the flag will be left
8338 *        unchanged.
8339 
8340 *  Returned Value:
8341 c     astEscapes
8342 f     AST_ESCAPES = INTEGER
8343 *        The value of the flag on entry to this function.
8344 
8345 *  Applicability:
8346 *     Object
8347 c        This macro applies to all Objects.
8348 f        This routine applies to all Objects.
8349 
8350 *  Notes:
8351 *     - This function also controls whether the
8352 c     astStripEscapes
8353 f     AST_STRIPESCAPES
8354 *     function removes escape sequences from the supplied string, or
8355 *     returns the supplied string without change.
8356 *     - This function attempts to execute even if an error has already
8357 *     occurred.
8358 
8359 *--
8360 */
8361 
8362 /* Local Variables: */
8363    astDECLARE_GLOBALS
8364    int old_val;
8365 
8366 /* Get a pointer to Thread-specific global data. */
8367    astGET_GLOBALS(NULL);
8368 
8369 /* Save the old value. */
8370    old_val = retain_esc;
8371 
8372 /* Set the new value. */
8373    if( new_value > 0 ) {
8374       retain_esc = 1;
8375 
8376    } else if( new_value == 0 ) {
8377       retain_esc = 0;
8378    }
8379 
8380 /* Return the old value. */
8381    return old_val;
8382 }
8383 
8384 
8385 #if defined(MEM_DEBUG)
8386 
8387 /* Check each handle in a list is uniquely connected to one other handle
8388    in both the forward and backward directions. */
8389 
CheckList(int * head,int * status)8390 void CheckList( int *head, int *status ) {
8391    int ok;
8392    int ihandle;
8393    char buf[200];
8394    astDECLARE_GLOBALS
8395    if( !astOK ) return;
8396 
8397    astGET_GLOBALS(NULL);
8398 
8399    ok = 1;
8400    if ( *head != -1 ) {
8401       ihandle = *head;
8402       if( handles[ handles[ ihandle ].blink ].flink != ihandle ||
8403           handles[ handles[ ihandle ].flink ].blink != ihandle ) {
8404          ok = 0;
8405 
8406       } else {
8407          if( CheckThread( ihandle, head, status ) ) {
8408             ihandle= handles[ *head ].blink;
8409             while( ihandle != *head ) {
8410                if( handles[ handles[ ihandle ].blink ].flink != ihandle ||
8411                    handles[ handles[ ihandle ].flink ].blink != ihandle ||
8412                    CheckThread( ihandle, head, status ) == 0 ) {
8413                   ok = 0;
8414                   break;
8415                }
8416                ihandle= handles[ ihandle ].blink;
8417             }
8418          }
8419       }
8420    }
8421 
8422    if( !ok ) {
8423       printf("CheckList error in %s\n", HeadString( head, buf ) );
8424       printf("   Central handle: %s\n", HandleString( ihandle, buf ) );
8425 
8426       if( handles[ handles[ ihandle ].blink ].flink != ihandle ) {
8427          printf("   Central handle->blink: %s\n",
8428                  HandleString( handles[ ihandle ].blink, buf ) );
8429          printf("   Central handle->blink->flink: %s\n",
8430                  HandleString( handles[ handles[ ihandle ].blink ].flink, buf ) );
8431       }
8432 
8433       if( handles[ handles[ ihandle ].flink ].blink != ihandle ) {
8434          printf("   Central handle->flink: %s\n",
8435                  HandleString( handles[ ihandle ].flink, buf ) );
8436          printf("   Central handle->flink->blink: %s\n",
8437                  HandleString( handles[ handles[ ihandle ].flink ].blink, buf ) );
8438       }
8439    }
8440 
8441 }
8442 
8443 
8444 /* Check if a specified handle is, or is not, in a given list of handles. */
8445 
CheckInList(int ihandle,int * head,int in,int * status)8446 void CheckInList( int ihandle, int *head, int in, int *status ){
8447    char list[80], buf[200];
8448    int found = 0;
8449    if( !astOK ) return;
8450 
8451    if ( *head != -1 ) {
8452       if( ihandle == *head ) {
8453          found = 1;
8454       } else {
8455          if( CheckThread( ihandle, head, status ) ) {
8456             int jhandle= handles[ *head ].blink;
8457             while( jhandle != *head ) {
8458                if( ihandle == jhandle ) {
8459                   found = 1;
8460                   break;
8461                }
8462                jhandle= handles[ jhandle ].blink;
8463             }
8464          }
8465       }
8466    }
8467 
8468    if( in && !found ) {
8469       printf("Error: Handle %s not in %s\n", HandleString( ihandle, buf ),
8470               HeadString( head, list ) );
8471    } else if( !in && found ) {
8472       printf("Error: Handle %s is in %s\n", HandleString( ihandle, buf ),
8473               HeadString( head, list ) );
8474    }
8475 
8476 }
8477 
8478 /* Check that a handle is owned by the currently executing thread. */
8479 
CheckThread(int ihandle,int * head,int * status)8480 int CheckThread( int ihandle, int *head, int *status ) {
8481    int result = 1;
8482 
8483 #if defined(THREAD_SAFE)
8484 
8485    char buf[200];
8486    astDECLARE_GLOBALS
8487    if( !astOK ) return result;
8488 
8489    astGET_GLOBALS(NULL);
8490 
8491    if( *head == unowned_handles  ) {
8492       if(  handles[ ihandle ].thread != -1 ) {
8493          printf("Handle %s has wrong thread: is %d, should "
8494              "be -1 (i.e. unowned)\n", HandleString( ihandle, buf ),
8495               handles[ ihandle ].thread );
8496 
8497          result = 0;
8498       }
8499 
8500    } else if( *head == free_handles ) {
8501       if(  handles[ ihandle ].thread != -1 ) {
8502          printf("Handle %s has wrong thread: is %d, should "
8503              "be -1 (i.e. free)\n", HandleString( ihandle, buf ),
8504               handles[ ihandle ].thread );
8505          result = 0;
8506       }
8507 
8508    } else if( handles[ ihandle ].thread != AST__THREAD_ID ) {
8509       printf("Handle %s has wrong thread: is %d, should "
8510              "be %d\n", HandleString( ihandle, buf ),
8511               handles[ ihandle ].thread, AST__THREAD_ID );
8512       result = 0;
8513    }
8514 
8515 #endif
8516 
8517    return result;
8518 }
8519 
astWatchHandle_(int handle)8520 void astWatchHandle_( int handle ){
8521    Watched_Handle = handle;
8522 }
8523 
astHandleUse_(int handle,const char * verb,...)8524 void astHandleUse_( int handle, const char *verb, ... ){
8525    va_list args;
8526    if( handle == Watched_Handle ) {
8527       va_start( args, verb );
8528       astHandleAlarm( verb, args );
8529       va_end( args );
8530    }
8531 }
8532 
astHandleAlarm_(const char * verb,va_list args)8533 void astHandleAlarm_( const char *verb, va_list args ){
8534    char buff[200], hbuf[200];
8535    astDECLARE_GLOBALS
8536    astGET_GLOBALS(NULL);
8537 
8538    vsprintf( buff, verb, args );
8539 
8540 #if defined(THREAD_SAFE)
8541    printf( "astHandleAlarm: Handle %s %s (current thread is %d).\n\n",
8542            HandleString( Watched_Handle, hbuf ), buff, AST__THREAD_ID );
8543 #else
8544    printf( "astHandleAlarm: Handle %s %s.\n\n",
8545            HandleString( Watched_Handle, hbuf ), buff );
8546 #endif
8547 }
8548 
HandleString(int ihandle,char * buf)8549 MYSTATIC const char *HandleString( int ihandle, char *buf ){
8550 #if defined(THREAD_SAFE)
8551    astDECLARE_GLOBALS
8552    astGET_GLOBALS(NULL);
8553 
8554    if( ihandle >= 0 ) {
8555       sprintf( buf, "(index:%d v:%d c:%d t:%d i:%d cl:%s) [cur. thread: %d]",
8556                ihandle,
8557                handles[ ihandle ].check,
8558                handles[ ihandle ].context, handles[ ihandle ].thread,
8559                handles[ ihandle ].id,
8560                handles[ ihandle ].vtab ? handles[ ihandle ].vtab->class : "<none>",
8561                AST__THREAD_ID );
8562    } else {
8563       sprintf( buf, "(index:%d <invalid>) [cur. thread: %d]", ihandle,
8564                AST__THREAD_ID );
8565    }
8566 
8567 #else
8568    if( ihandle >= 0 ) {
8569       sprintf( buf, "(index:%d v:%d c:%d i:%d cl:%s)", ihandle,
8570                handles[ ihandle ].check,
8571                handles[ ihandle ].context, handles[ ihandle ].id,
8572                handles[ ihandle ].vtab ? handles[ ihandle ].vtab->class : "<none>" );
8573    } else {
8574       sprintf( buf, "(index:%d <invalid>)", ihandle );
8575    }
8576 #endif
8577    return buf;
8578 }
8579 
HeadString(int * head,char * list)8580 MYSTATIC const char *HeadString( int *head, char *list ){
8581    int i;
8582    astDECLARE_GLOBALS
8583    astGET_GLOBALS(NULL);
8584 
8585    if( head == &free_handles ) {
8586       strcpy( list, "free_handles" );
8587 
8588 #if defined(THREAD_SAFE)
8589    } else if( head == &unowned_handles ) {
8590       strcpy( list, "unowned_handles" );
8591 #endif
8592 
8593    } else {
8594       *list = 0;
8595       for( i = 0; i <= context_level; i++ ) {
8596          if( *head == active_handles[ i ] ) {
8597             sprintf( list, "active_handles[%d]", i );
8598             break;
8599          }
8600       }
8601       if( *list == 0 ) sprintf( list, "unknown handles list with head %d",
8602                                 *head );
8603    }
8604    return list;
8605 }
8606 
8607 #endif
8608