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