summaryrefslogtreecommitdiffstats
path: root/ast/keymap.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:28:07 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2018-01-09 19:28:07 (GMT)
commit3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58 (patch)
treef278119398ae5d67a6a338705a76db420f6b8f7e /ast/keymap.c
parent1332d38f2805d986ea130e43218c0d2e870b4dc1 (diff)
downloadblt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.zip
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.gz
blt-3bfbbb90d4d6ebd44cc5eac38af24d1f78318a58.tar.bz2
update ast 8.6.2
Diffstat (limited to 'ast/keymap.c')
-rw-r--r--ast/keymap.c10972
1 files changed, 10972 insertions, 0 deletions
diff --git a/ast/keymap.c b/ast/keymap.c
new file mode 100644
index 0000000..df722ca
--- /dev/null
+++ b/ast/keymap.c
@@ -0,0 +1,10972 @@
+/*
+*class++
+* Name:
+* KeyMap
+
+* Purpose:
+* Store a set of key/value pairs.
+
+* Constructor Function:
+c astKeyMap
+f AST_KEYMAP
+
+* Description:
+* The KeyMap class is used to store a set of values with associated keys
+* which identify the values. The keys are strings. These may be case
+* sensitive or insensitive as selected by the KeyCase attribute, and
+* trailing spaces are ignored. The value associated with a key can be
+* integer (signed 4 and 2 byte, or unsigned 1 byte), floating point
+* (single or double precision),
+c void pointer,
+* character string or AST Object pointer. Each
+* value can be a scalar or a one-dimensional vector. A KeyMap is
+* conceptually similar to a Mapping in that a KeyMap transforms an
+* input into an output - the input is the key, and the output is the
+* value associated with the key. However, this is only a conceptual
+* similarity, and it should be noted that the KeyMap class inherits from
+* the Object class rather than the Mapping class. The methods of the
+* Mapping class cannot be used with a KeyMap.
+
+* Inheritance:
+* The KeyMap class inherits from the Object class.
+
+* Attributes:
+* In addition to those attributes common to all Objects, every
+* KeyMap also has the following attributes:
+*
+* - KeyCase: Sets the case in which keys are stored
+* - KeyError: Report an error if the requested key does not exist?
+* - SizeGuess: The expected size of the KeyMap.
+* - SortBy: Determines how keys are sorted in a KeyMap.
+* - MapLocked: Prevent new entries being added to the KeyMap?
+
+* Functions:
+c In addition to those functions applicable to all Objects, the
+c following functions may also be applied to all KeyMaps:
+f In addition to those routines applicable to all Objects, the
+f following routines may also be applied to all KeyMaps:
+*
+c - astMapDefined: Does a KeyMap contain a defined value for a key?
+c - astMapGetC: Get a scalar or vector entry as a single string.
+c - astMapGet0<X>: Get a named scalar entry from a KeyMap
+c - astMapGet1<X>: Get a named vector entry from a KeyMap
+c - astMapGetElem<X>: Get an element of a named vector entry from a KeyMap
+c - astMapHasKey: Does the KeyMap contain a named entry?
+c - astMapKey: Return the key name at a given index in the KeyMap
+c - astMapLenC: Get the length of a named character entry in a KeyMap
+c - astMapLength: Get the length of a named entry in a KeyMap
+c - astMapCopy: Copy entries from one KeyMap into another
+c - astMapPut0<X>: Add a new scalar entry to a KeyMap
+c - astMapPut1<X>: Add a new vector entry to a KeyMap
+c - astMapPutElem<X>: Puts a value into a vector entry in a KeyMap
+c - astMapPutU: Add a new entry to a KeyMap with an undefined value
+c - astMapRemove: Removed a named entry from a KeyMap
+c - astMapRename: Rename an existing entry in a KeyMap
+c - astMapSize: Get the number of entries in a KeyMap
+c - astMapType: Return the data type of a named entry in a map
+f - AST_MAPDEFINED: Does a KeyMap contain a defined value for a key?
+f - AST_MAPGETC: Get a scalar or vector entry as a single string.
+f - AST_MAPGET0<X>: Get a named scalar entry from a KeyMap
+f - AST_MAPGET1<X>: Get a named vector entry from a KeyMap
+f - AST_MAPGETELEM<X>: Get an element of a named vector entry from a KeyMap
+f - AST_MAPHASKEY: Does the KeyMap contain a named entry?
+f - AST_MAPKEY: Return the key name at a given index in the KeyMap
+f - AST_MAPLENC: Get the length of a named character entry in a KeyMap
+f - AST_MAPLENGTH: Get the length of a named entry in a KeyMap
+f - AST_MAPCOPY: Copy entries from one KeyMap into another
+f - AST_MAPPUT0<X>: Add a new scalar entry to a KeyMap
+f - AST_MAPPUT1<X>: Add a new vector entry to a KeyMap
+f - AST_MAPPUTELEM<X>: Puts a value into a vector entry in a KeyMap
+f - AST_MAPPUTU: Add a new entry to a KeyMap with an undefined value
+f - AST_MAPREMOVE: Removed a named entry from a KeyMap
+f - AST_MAPRENAME: Rename an existing entry in a KeyMap
+f - AST_MAPSIZE: Get the number of entries in a KeyMap
+f - AST_MAPTYPE: Return the data type of a named entry in a map
+
+* Copyright:
+* Copyright (C) 1997-2006 Council for the Central Laboratory of the
+* Research Councils
+* Copyright (C) 2008-2010 Science & Technology Facilities Council.
+* All Rights Reserved.
+
+* Licence:
+* This program is free software: you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation, either
+* version 3 of the License, or (at your option) any later
+* version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General
+* License along with this program. If not, see
+* <http://www.gnu.org/licenses/>.
+
+* Authors:
+* DSB: B.S. Berry (Starlink)
+
+* History:
+* 12-NOV-2004 (DSB):
+* Original version.
+* 5-JAN-2005 (DSB):
+* Added astMapLenC method.
+* 17-JAN-2005 (DSB):
+* Remove "void *" arithmetic.
+* 25-JAN-2005 (DSB):
+* Added more DEBUG blocks
+* 30-SEP-2005 (DSB):
+* Allow an integer to be read from a formatted floating point value.
+* 6-DEC-2005 (DSB):
+* Remove astMapGet0C stuff from description of astMapGet1C.
+* 14-FEB-2006 (DSB):
+* Override astGetObjSize.
+* 1-MAR-2006 (DSB):
+* Replace astSetPermMap within DEBUG blocks by astBeginPM/astEndPM.
+* 5-JUN-2006 (DSB):
+* Added support for single precision entries.
+* 30-NOV-2007 (DSB):
+* Added SizeGuess attribute.
+* 4-DEC-2007 (DSB):
+* Allow size of hash table to grow dynamically as more entries are
+* added to the KeyMap.
+* 5-DEC-2007 (DSB):
+* Ensure mapsize is always a power of 2.
+* 6-DEC-2007 (DSB):
+* - Define the minium table size rather than the default SizeGuess
+* value, and derive the default SizeGuess value from the minimum
+* table size.
+* - Use "&" rather than "%" to get the hash table index from the
+* full width hash value (& may be faster than %).
+* 7-MAR-2008 (DSB):
+* Added support for pointer ("P") entries.
+* 31-MAR-2009 (DSB):
+* Remove rounding errors from formatted double values.
+* 27-APR-2009 (DSB):
+* Added astMapGetElem<X>.
+* 1-SEP-2009 (DSB):
+* Added KeyError attribute.
+* 12-FEB-2010 (DSB):
+* When converting an entry value between double and string, treat
+* "<bad>" as the formatted version of AST__BAD.
+* 3-MAR-2010 (DSB):
+* Added astMapPutElem<X>.
+* 27-APR-2010 (DSB):
+* Added MapLocked attribute.
+* 4-MAY-2010 (DSB):
+* - Propagate MapLocked and KeyError attributes to any encapsulated
+* KeyMaps.
+* - Added astMapCopy method.
+* - Added astMapPutU method and AST__UNDEFTYPE data type.
+* 11-AUG-2010 (DSB):
+* Added SortBy attribute.
+* 12-AUG-2010 (DSB):
+* Speed up access to large KeyMaps.
+* 13-AUG-2010 (DSB):
+* - No need to sort all entries when doubling the table size since
+* changing the table size does not change the linked list of sorted
+* entries.
+* - Initialise the sortby attribute to the cleared value, rather
+* than the default value.
+* 2-OCT-2010 (DSB):
+* Added support for short int valued entries.
+* 24-NOV-2010 (DSB):
+* Fix memory leak in astMapPutElemC and astMapPutElemA.
+* 26-NOV-2010 (DSB):
+* Added support for unsigned byte valued entries.
+* 3-DEC-2010 (DSB):
+* Added KeyCase attribute.
+* 14-JAN-2011 (DSB):
+* Fix bug that prevented zero length strings being stored in a
+* keymap.
+* 17-SEP-2012 (DSB):
+* Fix bug that prevented UNDEF entries from being read back in
+* from a dump of a KeyMap.
+* 18-MAR-2013 (DSB):
+* Added astMapDefined.
+* 18-JUL-2013 (DSB):
+* Added SortBy options "KeyAgeUp" and "KeyAgeDown".
+* 9-SEP-2016 (DSB):
+* Guard against memory corruption that could occur after making
+* 50 (AST__KEYMAP_CONVERTVALUE_MAX_STRINGS) calls to put a string
+* into a KeyMap using astMapPutElemC.
+* 16-MAR-2017 (DSB):
+* Added astMapGetC.
+*class--
+*/
+
+/* Module Macros. */
+/* ============== */
+/* Set the name of the class we are implementing. This indicates to
+ the header files that define class interfaces that they should make
+ "protected" symbols available. */
+#define astCLASS KeyMap
+
+/* Minimum size for the hash table. */
+#define MIN_TABLE_SIZE 16
+
+/* The maximum number of entries per element of the hash table. If this
+ value is exceeded the hash table will be doubled in size. */
+#define MAX_ENTRIES_PER_TABLE_ENTRY 10
+
+/* String used to represent the formatetd version of AST__BAD. */
+#define BAD_STRING "<bad>"
+
+/* Integer values to represent the different values of the SortBy attribute. */
+#define SORTBY_NONE 0
+#define SORTBY_AGEUP 1
+#define SORTBY_AGEDOWN 2
+#define SORTBY_KEYUP 3
+#define SORTBY_KEYDOWN 4
+#define SORTBY_KEYAGEUP 5
+#define SORTBY_KEYAGEDOWN 6
+
+
+/* Include files. */
+/* ============== */
+/* Interface definitions. */
+/* ---------------------- */
+
+#include "globals.h" /* Thread-safe global data access */
+#include "error.h" /* Error reporting facilities */
+#include "memory.h" /* Memory management facilities */
+#include "object.h" /* Base Object class */
+#include "pointset.h" /* For AST__BAD */
+#include "channel.h" /* I/O channels */
+#include "keymap.h" /* Interface definition for this class */
+#include "globals.h" /* Thread-safe global data access */
+
+/* Error code definitions. */
+/* ----------------------- */
+#include "ast_err.h" /* AST error codes */
+
+/* C header files. */
+/* --------------- */
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* Type Definitions */
+/* ================ */
+
+/* This structure is a AstMapEntry holding a scalar int */
+typedef struct Entry0I {
+ struct AstMapEntry entry; /* The parent Entry information */
+ int value; /* The integer value */
+} Entry0I;
+
+/* This structure is a AstMapEntry holding a scalar double */
+typedef struct Entry0D {
+ struct AstMapEntry entry; /* The parent Entry information */
+ double value; /* The floating point value */
+} Entry0D;
+
+/* This structure is a AstMapEntry holding a scalar short int */
+typedef struct Entry0S {
+ struct AstMapEntry entry; /* The parent Entry information */
+ short int value; /* The short int value */
+} Entry0S;
+
+/* This structure is a AstMapEntry holding a scalar unsigned byte
+ (unsigned char) */
+typedef struct Entry0B {
+ struct AstMapEntry entry; /* The parent Entry information */
+ unsigned char value; /* The byte value */
+} Entry0B;
+
+/* This structure is a AstMapEntry holding a scalar float */
+typedef struct Entry0F {
+ struct AstMapEntry entry; /* The parent Entry information */
+ float value; /* The floating point value */
+} Entry0F;
+
+/* This structure is a AstMapEntry holding a scalar string */
+typedef struct Entry0C {
+ struct AstMapEntry entry; /* The parent Entry information */
+ const char *value; /* The string pointer */
+} Entry0C;
+
+/* This structure is a AstMapEntry holding a scalar AST Object */
+typedef struct Entry0A {
+ struct AstMapEntry entry; /* The parent Entry information */
+ AstObject *value; /* The Object pointer */
+ struct AstMapEntry *next; /* Pointer to next AST Object entry */
+ struct AstMapEntry *prev; /* Pointer to previous AST Object entry */
+} Entry0A;
+
+/* This structure is a AstMapEntry holding a scalar void pointer */
+typedef struct Entry0P {
+ struct AstMapEntry entry; /* The parent Entry information */
+ void *value; /* The pointer */
+} Entry0P;
+
+/* This structure is a AstMapEntry holding a 1D array of ints */
+typedef struct Entry1I {
+ struct AstMapEntry entry; /* The parent Entry information */
+ int *value; /* The integer values */
+} Entry1I;
+
+/* This structure is a AstMapEntry holding a 1D array of doubles */
+typedef struct Entry1D {
+ struct AstMapEntry entry; /* The parent Entry information */
+ double *value; /* The floating point values */
+} Entry1D;
+
+/* This structure is a AstMapEntry holding a 1D array of short ints */
+typedef struct Entry1S {
+ struct AstMapEntry entry; /* The parent Entry information */
+ short int *value; /* The short int values */
+} Entry1S;
+
+/* This structure is a AstMapEntry holding a 1D array of unsigned bytes */
+typedef struct Entry1B {
+ struct AstMapEntry entry; /* The parent Entry information */
+ unsigned char *value; /* The byte values */
+} Entry1B;
+
+/* This structure is a AstMapEntry holding a 1D array of floats */
+typedef struct Entry1F {
+ struct AstMapEntry entry; /* The parent Entry information */
+ float *value; /* The floating point values */
+} Entry1F;
+
+/* This structure is a AstMapEntry holding a 1D array of strings */
+typedef struct Entry1C {
+ struct AstMapEntry entry; /* The parent Entry information */
+ const char **value; /* The string pointers */
+} Entry1C;
+
+/* This structure is a AstMapEntry holding a 1D array of AST Objects */
+typedef struct Entry1A {
+ struct AstMapEntry entry; /* The parent Entry information */
+ AstObject **value; /* The Object pointers */
+ struct AstMapEntry *next; /* Pointer to next AST Object entry */
+ struct AstMapEntry *prev; /* Pointer to previous AST Object entry */
+} Entry1A;
+
+/* This structure is a AstMapEntry holding a 1D array of void pointers. */
+typedef struct Entry1P {
+ struct AstMapEntry entry; /* The parent Entry information */
+ void **value; /* The pointers */
+} Entry1P;
+
+
+/* Module Variables. */
+/* ================= */
+
+/* Address of this static variable is used as a unique identifier for
+ member of this class. */
+static int class_check;
+
+/* Pointers to parent class methods which are extended by this class. */
+static int (* parent_getobjsize)( AstObject *, int * );
+static const char *(* parent_getattrib)( AstObject *, const char *, int * );
+static int (* parent_testattrib)( AstObject *, const char *, int * );
+static void (* parent_clearattrib)( AstObject *, const char *, int * );
+static void (* parent_setattrib)( AstObject *, const char *, int * );
+
+#if defined(THREAD_SAFE)
+static int (* parent_managelock)( AstObject *, int, int, AstObject **, int * );
+#endif
+
+/* Define macros for accessing each item of thread specific global data. */
+#ifdef THREAD_SAFE
+
+/* Define how to initialise thread-specific globals. */
+#define GLOBAL_inits \
+ globals->Class_Init = 0; \
+ globals->GetAttrib_Buff[ 0 ] = 0; \
+ globals->ConvertValue_Init = 0; \
+ globals->ConvertValue_Istr = 0; \
+ globals->ConvertValue_Buff[ 0 ] = 0; \
+ globals->MapKey_Init = 0; \
+ globals->MapKey_Istr = 0;
+
+/* Create the function that initialises global data for this module. */
+astMAKE_INITGLOBALS(KeyMap)
+
+/* Define macros for accessing each item of thread specific global data. */
+#define class_init astGLOBAL(KeyMap,Class_Init)
+#define class_vtab astGLOBAL(KeyMap,Class_Vtab)
+#define getattrib_buff astGLOBAL(KeyMap,GetAttrib_Buff)
+#define convertvalue_strings astGLOBAL(KeyMap,ConvertValue_Strings)
+#define convertvalue_istr astGLOBAL(KeyMap,ConvertValue_Istr)
+#define convertvalue_init astGLOBAL(KeyMap,ConvertValue_Init)
+#define convertvalue_buff astGLOBAL(KeyMap,ConvertValue_Buff)
+#define mapkey_strings astGLOBAL(KeyMap,MapKey_Strings)
+#define mapkey_istr astGLOBAL(KeyMap,MapKey_Istr)
+#define mapkey_init astGLOBAL(KeyMap,MapKey_Init)
+
+
+
+/* If thread safety is not needed, declare and initialise globals at static
+ variables. */
+#else
+
+/* Buffer returned by GetAttrib. */ \
+static char getattrib_buff[ AST__KEYMAP_GETATTRIB_BUFF_LEN + 1 ];
+
+/* Strings returned by ConvertValue */ \
+static char *convertvalue_strings[ AST__KEYMAP_CONVERTVALUE_MAX_STRINGS ];
+
+/* Offset of next string in "ConvertValue_Strings" */ \
+static int convertvalue_istr;
+
+/* "ConvertValue_Strings" array initialised? */ \
+static int convertvalue_init;
+
+/* ConvertValue string buffer */ \
+static char convertvalue_buff[ AST__KEYMAP_CONVERTVALUE_BUFF_LEN + 1 ];
+
+/* Strings returned by MapKey */ \
+static char *mapkey_strings[ AST__KEYMAP_MAPKEY_MAX_STRINGS ];
+
+/* Offset of next string in "MapKey_Strings" */ \
+static int mapkey_istr;
+
+/* "MapKey_Strings" array initialised? */ \
+static int mapkey_init;
+
+
+/* Define the class virtual function table and its initialisation flag
+ as static variables. */
+static AstKeyMapVtab class_vtab; /* Virtual function table */
+static int class_init = 0; /* Virtual function table initialised? */
+
+#endif
+
+/* External Interface Function Prototypes. */
+/* ======================================= */
+/* The following functions have public prototypes only (i.e. no
+ protected prototypes), so we must provide local prototypes for use
+ within this module. */
+AstKeyMap *astKeyMapId_( const char *, ... );
+
+/* Prototypes for Private Member Functions. */
+/* ======================================== */
+static AstMapEntry *AddTableEntry( AstKeyMap *, int, AstMapEntry *, int, int * );
+static AstMapEntry *CopyMapEntry( AstMapEntry *, int * );
+static AstMapEntry *FreeMapEntry( AstMapEntry *, int * );
+static AstMapEntry *RemoveTableEntry( AstKeyMap *, int, const char *, int * );
+static AstMapEntry *SearchTableEntry( AstKeyMap *, int, const char *, int * );
+static const char *ConvertKey( AstKeyMap *, const char *, char *, int, const char *, int * );
+static const char *GetKey( AstKeyMap *, int index, int * );
+static const char *MapIterate( AstKeyMap *, int, int * );
+static const char *MapKey( AstKeyMap *, int index, int * );
+static const char *SortByString( int, const char *, int * );
+static int CompareEntries( const void *, const void * );
+static int ConvertValue( void *, int, void *, int, int * );
+static int GetObjSize( AstObject *, int * );
+static int HashFun( const char *, int, unsigned long *, int * );
+static int KeyCmp( const char *, const char * );
+static int MapDefined( AstKeyMap *, const char *, int * );
+static int MapGet0A( AstKeyMap *, const char *, AstObject **, int * );
+static int MapGet0C( AstKeyMap *, const char *, const char **, int * );
+static int MapGet0D( AstKeyMap *, const char *, double *, int * );
+static int MapGet0S( AstKeyMap *, const char *, short int *, int * );
+static int MapGet0B( AstKeyMap *, const char *, unsigned char *, int * );
+static int MapGet0F( AstKeyMap *, const char *, float *, int * );
+static int MapGet0I( AstKeyMap *, const char *, int *, int * );
+static int MapGet0P( AstKeyMap *, const char *, void **, int * );
+static int MapGet1A( AstKeyMap *, const char *, int, int *, AstObject **, int * );
+static int MapGet1C( AstKeyMap *, const char *, int, int, int *, char *, int * );
+static int MapGet1D( AstKeyMap *, const char *, int, int *, double *, int * );
+static int MapGet1B( AstKeyMap *, const char *, int, int *, unsigned char *, int * );
+static int MapGet1S( AstKeyMap *, const char *, int, int *, short int *, int * );
+static int MapGet1F( AstKeyMap *, const char *, int, int *, float *, int * );
+static int MapGet1I( AstKeyMap *, const char *, int, int *, int *, int * );
+static int MapGet1P( AstKeyMap *, const char *, int, int *, void **, int * );
+static int MapGetC( AstKeyMap *, const char *, const char **, int * );
+static int MapGetElemA( AstKeyMap *, const char *, int, AstObject **, int * );
+static int MapGetElemC( AstKeyMap *, const char *, int, int, char *, int * );
+static int MapGetElemD( AstKeyMap *, const char *, int, double *, int * );
+static int MapGetElemB( AstKeyMap *, const char *, int, unsigned char *, int * );
+static int MapGetElemS( AstKeyMap *, const char *, int, short int *, int * );
+static int MapGetElemF( AstKeyMap *, const char *, int, float *, int * );
+static int MapGetElemI( AstKeyMap *, const char *, int, int *, int * );
+static int MapGetElemP( AstKeyMap *, const char *, int, void **, int * );
+static int MapHasKey( AstKeyMap *, const char *, int * );
+static int MapLenC( AstKeyMap *, const char *, int * );
+static int MapLength( AstKeyMap *, const char *, int * );
+static int MapSize( AstKeyMap *, int * );
+static int MapType( AstKeyMap *, const char *, int * );
+static int SortByInt( const char *, const char *, int * );
+static size_t SizeOfEntry( AstMapEntry *, int * );
+static void AddToObjectList( AstKeyMap *, AstMapEntry *, int * );
+static void AddToSortedList( AstKeyMap *, AstMapEntry *, int * );
+static void CheckCircle( AstKeyMap *, AstObject *, const char *, int * );
+static void Copy( const AstObject *, AstObject *, int * );
+static void CopyTableEntry( AstKeyMap *, AstKeyMap *, int, int * );
+static void Delete( AstObject *, int * );
+static void DoubleTableSize( AstKeyMap *, int * );
+static void Dump( AstObject *, AstChannel *, int * );
+static void DumpEntry( AstMapEntry *, AstChannel *, int, int * );
+static void FreeTableEntry( AstKeyMap *, int itab, int * );
+static void InitMapEntry( AstMapEntry *, int, int, int * );
+static void MapCopy( AstKeyMap *, AstKeyMap *, int * );
+static void MapPut0A( AstKeyMap *, const char *, AstObject *, const char *, int * );
+static void MapPut0C( AstKeyMap *, const char *, const char *, const char *, int * );
+static void MapPut0D( AstKeyMap *, const char *, double, const char *, int * );
+static void MapPut0B( AstKeyMap *, const char *, unsigned char, const char *, int * );
+static void MapPut0S( AstKeyMap *, const char *, short int, const char *, int * );
+static void MapPut0F( AstKeyMap *, const char *, float, const char *, int * );
+static void MapPut0I( AstKeyMap *, const char *, int, const char *, int * );
+static void MapPut0P( AstKeyMap *, const char *, void *, const char *, int * );
+static void MapPut1A( AstKeyMap *, const char *, int, AstObject *const [], const char *, int * );
+static void MapPut1C( AstKeyMap *, const char *, int, const char *const [], const char *, int * );
+static void MapPut1D( AstKeyMap *, const char *, int, const double *, const char *, int * );
+static void MapPut1B( AstKeyMap *, const char *, int, const unsigned char *, const char *, int * );
+static void MapPut1S( AstKeyMap *, const char *, int, const short int *, const char *, int * );
+static void MapPut1F( AstKeyMap *, const char *, int, const float *, const char *, int * );
+static void MapPut1I( AstKeyMap *, const char *, int, const int *, const char *, int * );
+static void MapPut1P( AstKeyMap *, const char *, int, void *const [], const char *, int * );
+static void MapPutElemA( AstKeyMap *, const char *, int, AstObject *, int * );
+static void MapPutElemC( AstKeyMap *, const char *, int, const char *, int * );
+static void MapPutElemD( AstKeyMap *, const char *, int, double, int * );
+static void MapPutElemB( AstKeyMap *, const char *, int, unsigned char, int * );
+static void MapPutElemS( AstKeyMap *, const char *, int, short int, int * );
+static void MapPutElemF( AstKeyMap *, const char *, int, float, int * );
+static void MapPutElemI( AstKeyMap *, const char *, int, int, int * );
+static void MapPutElemP( AstKeyMap *, const char *, int, void *, int * );
+static void MapPutU( AstKeyMap *, const char *, const char *, int * );
+static void MapRemove( AstKeyMap *, const char *, int * );
+static void MapRename( AstKeyMap *, const char *, const char *, int * );
+static void NewTable( AstKeyMap *, int, int * );
+static void RemoveFromSortedList( AstKeyMap *, AstMapEntry *, int * );
+static void RemoveFromObjectList( AstKeyMap *, AstMapEntry *, int * );
+static void SortEntries( AstKeyMap *, int * );
+
+static const char *GetAttrib( AstObject *, const char *, int * );
+static int TestAttrib( AstObject *, const char *, int * );
+static void ClearAttrib( AstObject *, const char *, int * );
+static void SetAttrib( AstObject *, const char *, int * );
+
+static int GetSizeGuess( AstKeyMap *, int * );
+static int TestSizeGuess( AstKeyMap *, int * );
+static void ClearSizeGuess( AstKeyMap *, int * );
+static void SetSizeGuess( AstKeyMap *, int, int * );
+
+static int GetSortBy( AstKeyMap *, int * );
+static int TestSortBy( AstKeyMap *, int * );
+static void ClearSortBy( AstKeyMap *, int * );
+static void SetSortBy( AstKeyMap *, int, int * );
+
+static int GetKeyError( AstKeyMap *, int * );
+static int TestKeyError( AstKeyMap *, int * );
+static void ClearKeyError( AstKeyMap *, int * );
+static void SetKeyError( AstKeyMap *, int, int * );
+
+static int GetKeyCase( AstKeyMap *, int * );
+static int TestKeyCase( AstKeyMap *, int * );
+static void ClearKeyCase( AstKeyMap *, int * );
+static void SetKeyCase( AstKeyMap *, int, int * );
+
+static int GetMapLocked( AstKeyMap *, int * );
+static int TestMapLocked( AstKeyMap *, int * );
+static void ClearMapLocked( AstKeyMap *, int * );
+static void SetMapLocked( AstKeyMap *, int, int * );
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *, int, int, AstObject **, int * );
+#endif
+
+/* Member functions. */
+/* ================= */
+static AstMapEntry *AddTableEntry( AstKeyMap *this, int itab,
+ AstMapEntry *entry, int keymember,
+ int *status ){
+/*
+* Name:
+* AddTableEntry
+
+* Purpose:
+* Add an new entry to a linked-list of KeyMap entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstMapEntry *AddTableEntry( AstKeyMap *this, int itab,
+* AstMapEntry *entry, int keymember,
+* int *status ){
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function adds the supplied MapEntry to the head of the linked
+* list of MapEntries stored at the specified entry of the hash table.
+* If this results in the linked list having too many entries, then a
+* new larger hash table is allocated and the entries in the existing
+* table are moved into the new table.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* itab
+* Index of the hash table element to be searched.
+* entry
+* Pointer to the MapEntry to be added.
+* keymember
+* A unique integer identifier for the key that increases
+* monotonically with age of the key. If this is negative,
+* the next available identifier will be used automatically.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A NULL pointer.
+
+*/
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* Put a pointer to the MapEntry which is currently at the head of the
+ linked list in the "next" component of the supplied MapEntry. */
+ entry->next = this->table[ itab ];
+
+/* Store the supplied MapEntry pointer in the requested element of the
+ hash table. */
+ this->table[ itab ] = entry;
+
+/* Increment the length of linked list. */
+ this->nentry[ itab ]++;
+
+/* Each new entry added to the KeyMap has a unique member index that is
+ never re-used. */
+ entry->member = (this->member_count)++;
+
+/* Each key added to the KeyMap also has a separate unique member index,
+ but this index is re-used each time the same key is added into the
+ KeyMap. So changing the value associated with a key does not cause the
+ keymember value to change. */
+ if( keymember >= 0 ) {
+ entry->keymember = keymember;
+ } else {
+ entry->keymember = (this->member_count)++;
+ }
+
+/* Insert the supplied MapEntry into a list sorted by key. */
+ AddToSortedList( this, entry, status );
+
+/* If the entry is of type AST__OBJECTTYPE, add it to the head of the
+ list of AST__OBJECTTYPE entries in the KeyMap. */
+ AddToObjectList( this, entry, status );
+
+/* If the population of this table entry is now too large, double the size
+ of the table, moving the table entries to appropriate places in the
+ new larger table. */
+ if( this->nentry[ itab ] > MAX_ENTRIES_PER_TABLE_ENTRY ) {
+ DoubleTableSize( this, status );
+ }
+
+/* Return a NULL pointer. */
+ return NULL;
+}
+
+static void AddToObjectList( AstKeyMap *this, AstMapEntry *entry, int *status ){
+/*
+* Name:
+* AddToObjectList
+
+* Purpose:
+* Add AST__OBJECTTYPE entries into a linked-list of such entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void AddToObjectList( AstKeyMap *this, AstMapEntry *entry, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* If the supplied MapEntry holds one or more pointers to AST Objects,
+* then the entry is added to a linked list of such entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* entry
+* Pointer to the MapEntry to be added.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ Entry0A *scalar; /* Pointer to a scalar AST__OBJECTTYPE entry */
+ Entry1A *vector; /* Pointer to a vector AST__OBJECTTYPE entry */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Do nothing if the entry does not hold AST Object pointers. */
+ if( entry->type == AST__OBJECTTYPE ) {
+
+/* If the list is not currently empty, add the new entry into the list. */
+ if( this->firstA ) {
+
+/* Store a pointer to the new entry as the previous link in the current
+ first entry in the list. */
+ if( this->firstA->nel == 0 ) {
+ scalar = (Entry0A *) this->firstA;
+ scalar->prev = entry;
+ } else {
+ vector = (Entry1A *) this->firstA;
+ vector->prev = entry;
+ }
+
+/* Store a pointer to the current first entry as the next link in the new
+ entry, and nullify the previus link. */
+ if( entry->nel == 0 ) {
+ scalar = (Entry0A *) entry;
+ scalar->next = this->firstA;
+ scalar->prev = NULL;
+ } else {
+ vector = (Entry1A *) entry;
+ vector->next = this->firstA;
+ vector->prev = NULL;
+ }
+
+/* If the list is currently empty, nullify both links in the entry. */
+ } else {
+ if( entry->nel == 0 ) {
+ scalar = (Entry0A *) entry;
+ scalar->next = NULL;
+ scalar->prev = NULL;
+ } else {
+ vector = (Entry1A *) entry;
+ vector->next = NULL;
+ vector->prev = NULL;
+ }
+
+ }
+
+/* Store the new entry as the first entry. */
+ this->firstA = entry;
+ }
+}
+
+static void AddToSortedList( AstKeyMap *this, AstMapEntry *entry, int *status ){
+/*
+* Name:
+* AddToSortedList
+
+* Purpose:
+* Add an entry into the linked-list of sorted KeyMap entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void AddToSortedList( AstKeyMap *this, AstMapEntry *entry, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function adds the supplied MapEntry into the linked list of
+* sorted MapEntries at a position that maintains the sorted order.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* entry
+* Pointer to the MapEntry to be added.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *hi; /* MapEntry at high end of current range */
+ AstMapEntry *lo; /* MapEntry at low end of current range */
+ AstMapEntry *mid; /* MapEntry at middle of current range */
+ int cmp; /* Result of comparing two entries */
+ int istep; /* Step counter */
+ int nstep; /* Number of entries in current range */
+ int sortby; /* How to sort the keys */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the SortBy value. */
+ sortby = astGetSortBy( this );
+
+/* Do nothing if no sorting is required. */
+ if( sortby != SORTBY_NONE ) {
+
+/* Get pointers to the entries at the start and end of the sorted list. */
+ lo = this->first;
+ hi = lo ? lo->sprev : NULL;
+
+/* Store sortby value in the mapentry structures. */
+ if( lo ) lo->sortby = sortby;
+ if( hi ) hi->sortby = sortby;
+ entry->sortby = sortby;
+
+/* If the sorted list is empty, just store the supplied entry at the
+ head, and set the links to point back to itself. */
+ if( !lo ) {
+ this->first = entry;
+ entry->sprev = entry;
+ entry->snext = entry;
+
+/* If the new entry comes before the first entry or is equal to the first
+ entry, record it as the new first entry, and insert it into the linked
+ list before the original first entry. */
+ } else if( CompareEntries( &entry, &lo ) <= 0 ) {
+ this->first = entry;
+ entry->snext = lo;
+ entry->sprev = hi;
+ lo->sprev = entry;
+ hi->snext = entry;
+
+/* If the new entry comes after the last entry or is equal to the last
+ entry, insert it into the linked list after the last entry. */
+ } else if( CompareEntries( &entry, &hi ) >= 0 ) {
+ entry->snext = lo;
+ entry->sprev = hi;
+ lo->sprev = entry;
+ hi->snext = entry;
+
+/* If the list only contains two values, insert the new entry into the linked
+ list between the existing two entries. */
+ } else if( lo->snext == hi ) {
+ entry->snext = hi;
+ entry->sprev = lo;
+ lo->snext = entry;
+ hi->sprev = entry;
+
+/* Otherwise we do a binary chop within the existing sorted list to find the
+ correct position for the new entry. */
+ } else {
+
+/* Get a pointer to the entry mid way between the hi and lo entries. The
+ mid entry will be on the upper side of half way if there are an even
+ number of entries. */
+ nstep = this->nsorted/2;
+ mid = lo;
+ for( istep = 0; istep < nstep; istep++ ) mid = mid->snext;
+
+/* Loop until we have a pointer to the first entry which is equal to or
+ higher than the new entry. */
+ while( lo->snext != hi ) {
+
+/* The next step will be half the length of the previous step. Do not
+ allow the step size to fall to zero. */
+ nstep = ( nstep > 1 ) ? nstep/2 : 1;
+
+/* Compare the new entry with the current mid-way entry. */
+ mid->sortby = sortby;
+ cmp = CompareEntries( &entry, &mid );
+
+/* If the new entry comes before the mid entry, use the mid entry as the
+ next hi entry, and go down the list by the new step size to find the
+ new mid-way entry. */
+ if( cmp < 0 ) {
+ hi = mid;
+ for( istep = 0; istep < nstep; istep++ ) mid = mid->sprev;
+
+/* If the new entry comes after the mid entry, use the mid entry as the
+ next lo entry, and go up the list by the new step size to find the
+ new mid-way entry. */
+ } else if( cmp > 0 ) {
+ lo = mid;
+ for( istep = 0; istep < nstep; istep++ ) mid = mid->snext;
+
+/* If the new entry is equal to the mid entry, use the mid entry as hi
+ and set lo to the previous entry. This causes the loop to quit. */
+ } else {
+ hi = mid;
+ lo = mid->sprev;
+ }
+ }
+
+/* Insert the new entry into the list between lo and hi. */
+ entry->sprev = lo;
+ entry->snext = hi;
+ lo->snext = entry;
+ hi->sprev = entry;
+ }
+
+/* Increment the number of entries in the sorted list. */
+ (this->nsorted)++;
+ }
+}
+
+static void CheckCircle( AstKeyMap *this, AstObject *obj, const char *method, int *status ) {
+/*
+* Name:
+* CheckCircle
+
+* Purpose:
+* Check for circular dependencies between KeyMaps.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void CheckCircle( AstKeyMap *this, AstObject *obj, const char *method, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function checks that the given AstObject is not a KeyMap which
+* contains "this". If it is, an error is reported.
+
+* Parameters:
+* this
+* The KeyMap pointer.
+* obj
+* Pointer to the AstObject to be inserted into the KeyMap, or NULL.
+* method
+* Name of method to include in error messages.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstKeyMap *keymap; /* The KeyMap being added to "this" */
+ AstObject **vec; /* Pointer to list of AstObject pointers */
+ const char *key; /* The i'th key within second KeyMap */
+ int i; /* Index of entry within second KeyMap */
+ int j; /* Index within the vector of values */
+ int len; /* No. of AST pointers stored in the entry */
+ int nkey; /* No. of entries in the second KeyMap */
+
+/* Check the global error status. */
+ if( !astOK ) return;
+
+/* Return if the AstObject is not a KeyMap. */
+ if( obj && astIsAKeyMap( obj ) ) {
+ keymap = (AstKeyMap *) obj;
+
+/* First check if the supplied Objects are the same. You cannot store a
+ KeyMap as an entry within itself. */
+ if( keymap == this ) {
+ astError( AST__KYCIR, "%s(%s): Cannot add a %s into another "
+ "%s because they are same %s.", status, method,
+ astGetClass( this ), astGetClass( this ),
+ astGetClass( this ), astGetClass( this ) );
+
+/* Otherwise, loop through all the entries in the KeyMap looking for AstObject
+ entries. */
+ } else {
+ nkey = astMapSize( keymap );
+ for( i = 0; i < nkey && astOK; i++ ) {
+ key = astMapKey( keymap, i );
+ if( astMapType( keymap, key ) == AST__OBJECTTYPE ) {
+
+/* Find the number of AstObject pointers stored in this entry, and
+ allocate memory to store a copy of the every pointer. */
+ len = astMapLength( keymap, key );
+ vec = astMalloc( sizeof( AstObject *) * len );
+ if( vec ) {
+
+/* Extract pointers to the AstObjects at this entry, and loop round them. */
+ astMapGet1A( keymap, key, len, &len, vec );
+ for( j = 0; j < len; j++ ) {
+
+/* If this entry is a KeyMap, we need to check if is the same as "this"
+ or contains "this". */
+ if( astIsAKeyMap( vec[ j ] ) ) {
+
+/* If it is the same as "this", report an error. */
+ if( vec[ j ] == (AstObject *) this ) {
+ astError( AST__KYCIR, "%s(%s): Cannot add a KeyMap "
+ "into another KeyMap because the first "
+ "KeyMap contains the second KeyMap.", status,
+ method, astGetClass( this ) );
+ break;
+
+/* Otherwise, see if it contains "this". */
+ } else {
+ CheckCircle( this, vec[ j ], method, status );
+ }
+ }
+
+/* Free resources. */
+ vec[ j ] = astAnnul( vec[ j ] );
+ }
+ vec = astFree( vec );
+ }
+ }
+ }
+ }
+ }
+}
+
+static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* ClearAttrib
+
+* Purpose:
+* Clear an attribute value for a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void ClearAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* KeyMap member function (over-rides the astClearAttrib protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function clears the value of a specified attribute for a
+* KeyMap, so that the default value will subsequently be used.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* attrib
+* Pointer to a null-terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Check the attribute name and clear the appropriate attribute. */
+
+/* SizeGuess. */
+/* ---------- */
+ if ( !strcmp( attrib, "sizeguess" ) ) {
+ astClearSizeGuess( this );
+
+/* KeyError. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keyerror" ) ) {
+ astClearKeyError( this );
+
+/* KeyCase. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keycase" ) ) {
+ astClearKeyCase( this );
+
+/* MapLocked. */
+/* --------- */
+ } else if ( !strcmp( attrib, "maplocked" ) ) {
+ astClearMapLocked( this );
+
+/* SortBy. */
+/* ------- */
+ } else if ( !strcmp( attrib, "sortby" ) ) {
+ astClearSortBy( this );
+
+/* If the attribute is still not recognised, pass it on to the parent
+ method for further interpretation. */
+ } else {
+ (*parent_clearattrib)( this_object, attrib, status );
+ }
+}
+
+static void ClearKeyCase( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astClearKeyCase
+
+* Purpose:
+* Clear the value of the KeyCase attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetKeyCase( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function Clears the KeyCase attribute of a KeyMap. It reports
+* an error if the KeyMap contains any entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+*-
+*/
+
+/* Local Variables: */
+ int defval; /* Default KeyCase value */
+ int itab; /* Index into hash table */
+ int oldval; /* Old KeyCase value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Save the old value. */
+ oldval = astGetKeyCase( this );
+
+/* Clear it. */
+ this->keycase = -1;
+
+/* Get the default value. */
+ defval = astGetKeyCase( this );
+
+/* If the old value and the default value are not the same, we must check
+ that the KeyMap is empty. If not, restore the old value and report an
+ error. */
+ if( defval != oldval ) {
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+ if( this->nentry[ itab ] > 0 ) {
+ this->keycase = oldval;
+ astError( AST__NOWRT, "astClearAttrib(KeyMap): Illegal attempt to "
+ "clear the KeyCase attribute of a non-empty KeyMap.",
+ status);
+ break;
+ }
+ }
+ }
+}
+
+static void ClearKeyError( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astClearKeyError
+
+* Purpose:
+* Clear the value of the KeyError attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astClearKeyError( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function clears the value of the KeyError attribute for a
+* KeyMap. It clears the attribute recursively in any KeyMaps
+* contained within the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+*-
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+ AstObject **obj_list; /* List of pointers to AST Object entries */
+ int i; /* Index into hash table */
+ int iel; /* Index of current vector element */
+ int nel; /* Number of elements in vector */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Clear the KeyError value in the supplied KeyMap. */
+ this->keyerror = -INT_MAX;
+
+/* Loop round each entry in the hash table. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry. */
+ next = this->table[ i ];
+
+/* Loop round all entries in this element of the hash table. */
+ while( next && astOK ) {
+
+/* If this entry has an Object data type, see if holds any KeyMaps. */
+ if( next->type == AST__OBJECTTYPE ) {
+
+/* Get the number of objects to check, and a pointer to the first. */
+ nel = next->nel;
+ if( nel == 0 ) {
+ obj_list = &( ((Entry0A *)next)->value );
+ nel = 1;
+ } else {
+ obj_list = ((Entry1A *)next)->value;
+ }
+
+/* Loop round checking all Objects. */
+ for( iel = 0; iel < nel; iel++ ) {
+
+/* If this Object is a KeyMap, clear its KeyError attribute. */
+ if( astIsAKeyMap( obj_list[ iel ] ) ) {
+ astClearKeyError( (AstKeyMap *) obj_list[ iel ] );
+ }
+ }
+ }
+
+/* Get a pointer to the next entry. */
+ next = next->next;
+ }
+ }
+}
+
+static void ClearMapLocked( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astClearMapLocked
+
+* Purpose:
+* Clear the value of the MapLocked attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astClearMapLocked( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function clears the value of the MapLocked attribute for a
+* KeyMap. It clears the attribute recursively in any KeyMaps
+* contained within the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+*-
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+ AstObject **obj_list; /* List of pointers to AST Object entries */
+ int i; /* Index into hash table */
+ int iel; /* Index of current vector element */
+ int nel; /* Number of elements in vector */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Clear the MapLocked value in the supplied KeyMap. */
+ this->maplocked = -INT_MAX;
+
+/* Loop round each entry in the hash table. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry. */
+ next = this->table[ i ];
+
+/* Loop round all entries in this element of the hash table. */
+ while( next && astOK ) {
+
+/* If this entry has an Object data type, see if holds any KeyMaps. */
+ if( next->type == AST__OBJECTTYPE ) {
+
+/* Get the number of objects to check, and a pointer to the first. */
+ nel = next->nel;
+ if( nel == 0 ) {
+ obj_list = &( ((Entry0A *)next)->value );
+ nel = 1;
+ } else {
+ obj_list = ((Entry1A *)next)->value;
+ }
+
+/* Loop round checking all Objects. */
+ for( iel = 0; iel < nel; iel++ ) {
+
+/* If this Object is a KeyMap, clear its MapLocked attribute. */
+ if( astIsAKeyMap( obj_list[ iel ] ) ) {
+ astClearMapLocked( (AstKeyMap *) obj_list[ iel ] );
+ }
+ }
+ }
+
+/* Get a pointer to the next entry. */
+ next = next->next;
+ }
+ }
+}
+
+static void ClearSizeGuess( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astClearSizeGuess
+
+* Purpose:
+* Clear the value of the SizeGuess attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astClearSizeGuess( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function clears the value of the SizeGuess attribute for a
+* KeyMap. It reports an error if the KeyMap contains any entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+*-
+*/
+
+/* Local Variables: */
+ int empty; /* Is the KeyMap empty? */
+ int itab; /* Index into hash table */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* See if the KeyMap is empty. */
+ empty = 1;
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+ if( this->nentry[ itab ] > 0 ) {
+ empty = 0;
+ break;
+ }
+ }
+
+/* If not report an error. */
+ if( !empty ) {
+ astError( AST__NOWRT, "astClearAttrib(KeyMap): Illegal attempt to "
+ "clear the SizeGuess attribute of a non-empty KeyMap." , status);
+
+/* Otherwise, store the "cleared" value and change the size of the hash
+ table. */
+ } else {
+ this->sizeguess = INT_MAX;
+ NewTable( this, MIN_TABLE_SIZE, status );
+ }
+}
+
+static void ClearSortBy( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astClearSortBy
+
+* Purpose:
+* Clear the value of the SortBy attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astClearSortBy( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function clears the value of the SortBy attribute for a
+* KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+*-
+*/
+
+/* Local Variables: */
+ int oldval; /* The old sortby value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the original SortBy value. */
+ oldval = astGetSortBy( this );
+
+/* Clear the SortBy value in the supplied KeyMap. */
+ this->sortby = -INT_MAX;
+
+/* If the value has changed, re-sort the keys. */
+ if( oldval != astGetSortBy( this ) ) SortEntries( this, status );
+}
+
+static int CompareEntries( const void *first_void, const void *second_void ) {
+/*
+* Name:
+* CompareEntries
+
+* Purpose:
+* Determine the sorting order of two mapEntries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int CompareEntries( const void *first, const void *second )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function returns a value indicating if the first MapEntry
+* is less than, equal to, or greater than the second MapEntry using
+* the indicated sorting method. It is designed for use with the
+* "qsort" function, and therefore must used "void *" pointers.
+
+* Parameters:
+* first
+* Pointer to the address of the first MapEntry.
+* second
+* Pointer to the address of the second MapEntry.
+
+* Returned Value:
+* -1 if "first" is less than "second". This implies that "first"
+* should come before "second" in the sorted list.
+*
+* 0 if "first" is equal to "second".
+*
+* +1 if "first" is greater than "second". This implies that "first"
+* should come after "second" in the sorted list.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *first; /* Pointer to first MapEntry structure */
+ AstMapEntry *second; /* Pointer to second MapEntry structure */
+ int result; /* Returned value */
+ int sortby; /* Sorting method */
+
+/* Initialise returned value */
+ result = 0;
+
+/* Get pointers to the MapEntry structures, and get the sorting method. */
+ first = *( (AstMapEntry **) first_void );
+ second = *( (AstMapEntry **) second_void );
+ sortby = first->sortby;
+
+/* First handle sorting by increasing age of the value */
+ if( sortby == SORTBY_AGEUP ) {
+ if( first->member < second->member ) {
+ result = 1;
+ } else if( first->member > second->member ) {
+ result = -1;
+ } else {
+ result = 0;
+ }
+
+/* Next handle sorting by decreasing age of the value */
+ } else if( sortby == SORTBY_AGEDOWN ) {
+ if( first->member < second->member ) {
+ result = -1;
+ } else if( first->member > second->member ) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+
+/* Next handle sorting by increasing age of the key */
+ } else if( sortby == SORTBY_KEYAGEUP ) {
+ if( first->keymember < second->keymember ) {
+ result = 1;
+ } else if( first->keymember > second->keymember ) {
+ result = -1;
+ } else {
+ result = 0;
+ }
+
+/* Next handle sorting by decreasing age of the key */
+ } else if( sortby == SORTBY_KEYAGEDOWN ) {
+ if( first->keymember < second->keymember ) {
+ result = -1;
+ } else if( first->keymember > second->keymember ) {
+ result = 1;
+ } else {
+ result = 0;
+ }
+
+/* Next handle sorting by increasing alphabetical position. */
+ } else if( sortby == SORTBY_KEYUP ) {
+ result = KeyCmp( first->key, second->key );
+
+/* Next handle sorting by decreasing alphabetical position. */
+ } else if( sortby == SORTBY_KEYDOWN ) {
+ result = KeyCmp( second->key, first->key );
+
+ }
+
+/* Return the result. */
+ return result;
+
+}
+
+static const char *ConvertKey( AstKeyMap *this, const char *skey, char *keybuf,
+ int blen, const char *method, int *status ){
+/*
+* Name:
+* ConvertValue
+
+* Purpose:
+* Convert the supplied key to upper case if required.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* const char *ConvertKey( AstKeyMap *this, const char *skey, char *keybuf,
+* int blen, const char *method, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function converts the supplied key string to uppercase if the
+* KeyCase attribute it currently set to zero in the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* skey
+* Pointer to the supplied key string.
+* keybuf
+* Pointer to a buffer in which to place the converted string. This
+* will only be used if the supplied key string needs to be
+* converted.
+* blen
+* The length of the "keybuf" buffer. This should include room for
+* a terminating null character.
+* method
+* Pointer to a string holding the name of the method to include in
+* any error message.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* If the KeyMap's KeyCase attribute is currently set to a non-zero
+* value, the returned value will be a copy of "skey". Otherwise it
+* will be copy of "keybuf" (the buffer holding the upper case version
+* of the supplied string).
+
+* Notes:
+* - The valeu of "skey" will be returned if this function is invoked
+* with the global error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ const char *result;
+ int len;
+
+/* Initialise. */
+ result = skey;
+
+/* Check the global error status and the supplied pointers. */
+ if( !astOK ) return result;
+
+/* If the KeyCase attribute is non-zero, return "skey". Otherwise, convert
+ the "skey" string to upper case and return "keybuf". Report an error if
+ the key is too long. */
+ if( !astGetKeyCase( this ) && astOK ) {
+ len = astChrLen( skey );
+ if( len >= blen ) {
+ astError( AST__BIGKEY, "%s(%s): Supplied key '%s' is too long "
+ "(keys must be no more than %d characters long).",
+ status, method, astGetClass( this ), skey, blen - 1 );
+ } else {
+ astChrCase( skey, keybuf, 1, blen );
+ result = keybuf;
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int ConvertValue( void *raw, int raw_type, void *out, int out_type, int *status ) {
+/*
+* Name:
+* ConvertValue
+
+* Purpose:
+* Convert a value from one KeyMap data type to another.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int ConvertValue( void *raw, int raw_type, void *out, int out_type, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function converts a supplied value from one KeyMap data type to
+* another, if possible.
+
+* Parameters:
+* raw
+* Pointer to input value.
+* raw_type
+* The data type of the input value.
+* out
+* Pointer to the location at which to store the output value. This
+* may be NULL, in which case the conversion is still performed if
+* possible, but the result of the conversion is thrown away. If the
+* output value is a pointer to a string, it should not be modified
+* by the caller in any way. Neither should it be freed by the caller.
+* out_type
+* The data type of the output value.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Non-zero if the conversion was performed succesfully, otherwise zero.
+* In the case of the output type being AST__STRINGTYPE, the returned
+* non-zero value will be the length of the formatted string (including
+* the terminating null character). This value will be returned correctly
+* even if "out" is NULL.
+
+* Notes:
+* - Zero will be returned if this function is invoked with the global
+* error status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstObject *aval; /* AstObject pointer value */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ const char *cval; /* Pointer to string value */
+ const char *cvalue; /* Pointer to output string value */
+ double dval; /* Double precision value */
+ float fval; /* Single precision value */
+ int i; /* Loop count */
+ int ival; /* Integer value */
+ int n1; /* Number of characters at reduced precision */
+ int n2; /* Number of characters at full precision */
+ int nc; /* Number of characters read from string */
+ int nval; /* Number of values read from string */
+ int result; /* Returned flag */
+ short int sval; /* Short int value */
+ unsigned char bval; /* Byte value */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status and the supplied pointers. */
+ if( !astOK || !raw ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(NULL);
+
+/* If the "convertvalue_strings" array has not been initialised, fill it with
+ NULL pointers. */
+ if( !convertvalue_init ) {
+ convertvalue_init = 1;
+ for( i = 0; i < AST__KEYMAP_CONVERTVALUE_MAX_STRINGS; i++ ) convertvalue_strings[ i ] = NULL;
+ }
+
+/* Assume conversion is possible */
+ result = 1;
+ cvalue = NULL;
+
+/* Do nothing if both data types are AST__UNDEFTYPE. */
+ if( raw_type == AST__UNDEFTYPE && out_type == AST__UNDEFTYPE ) {
+
+/* Indicate failure if one of the two types is AST__UNDEFTYPE and the
+ other is not. */
+ } else if( raw_type == AST__UNDEFTYPE || out_type == AST__UNDEFTYPE ) {
+ result = 0;
+
+/* Otherwise, consider conversion from "int". */
+ } else if( raw_type == AST__INTTYPE ) {
+ ival = *( (int *) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ if( out ) *( (int *) out ) = ival;
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ if( out ) *( (short int *) out ) = (short int) ival;
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ if( out ) *( (unsigned char *) out ) = (unsigned char) ival;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ if( out ) *( (float *) out ) = (float) ival;
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ if( out ) *( (double *) out ) = (double) ival;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ (void) sprintf( convertvalue_buff, "%d", ival );
+ cvalue = convertvalue_buff;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Otherwise, consider conversion from "short int". */
+ } else if( raw_type == AST__SINTTYPE ) {
+ sval = *( (short int *) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ if( out ) *( (int *) out ) = sval;
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ if( out ) *( (short int *) out ) = sval;
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ if( out ) *( (unsigned char *) out ) = sval;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ if( out ) *( (float *) out ) = (float) sval;
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ if( out ) *( (double *) out ) = (double) sval;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ (void) sprintf( convertvalue_buff, "%d", (int) sval );
+ cvalue = convertvalue_buff;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Otherwise, consider conversion from "byte". */
+ } else if( raw_type == AST__BYTETYPE ) {
+ bval = *( (unsigned char *) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ if( out ) *( (int *) out ) = bval;
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ if( out ) *( (short int *) out ) = bval;
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ if( out ) *( (unsigned char *) out ) = bval;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ if( out ) *( (float *) out ) = (float) bval;
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ if( out ) *( (double *) out ) = (double) bval;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ (void) sprintf( convertvalue_buff, "%d", (int) bval );
+ cvalue = convertvalue_buff;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Consider conversion from "double". */
+ } else if( raw_type == AST__DOUBLETYPE ) {
+ dval = *( (double *) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ if( out ) *( (int *) out ) = (int)( dval + 0.5 );
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ if( out ) *( (short int *) out ) = (int)( dval + 0.5 );
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ if( out ) *( (unsigned char *) out ) = (int)( dval + 0.5 );
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ if( out ) *( (double *) out ) = dval;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ if( out ) *( (float *) out ) = (float) dval;
+
+/* Consider conversion to "const char *". If reducing the number of
+ decimal places by two produces a saving of 10 or more characters,
+ assume the least significant two characters are rounding error. */
+ } else if( out_type == AST__STRINGTYPE ) {
+ if( dval != AST__BAD ) {
+ n1 = sprintf( convertvalue_buff, "%.*g", DBL_DIG - 2, dval );
+ n2 = sprintf( convertvalue_buff, "%.*g", DBL_DIG, dval );
+ if( n2 - n1 > 9 ) {
+ (void) sprintf( convertvalue_buff, "%.*g", DBL_DIG - 2, dval );
+ }
+ cvalue = convertvalue_buff;
+ } else {
+ cvalue = BAD_STRING;
+ }
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Consider conversion from "float". */
+ } else if( raw_type == AST__FLOATTYPE ) {
+ fval = *( (float *) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ if( out ) *( (int *) out ) = (int)( fval + 0.5 );
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ if( out ) *( (short int *) out ) = (int)( fval + 0.5 );
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ if( out ) *( (unsigned char *) out ) = (int)( fval + 0.5 );
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ if( out ) *( (double *) out ) = (double) fval;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ if( out ) *( (float *) out ) = fval;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ (void) sprintf( convertvalue_buff, "%.*g", FLT_DIG, fval );
+ cvalue = convertvalue_buff;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Consider conversion from "const char *". */
+ } else if( raw_type == AST__STRINGTYPE ) {
+ cval = *( (const char **) raw );
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ nc = 0;
+ nval = astSscanf( cval, " %d %n", &ival, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (int *) out ) = ival;
+ } else {
+ nc = 0;
+ nval = astSscanf( cval, " %lf %n", &dval, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (int *) out ) = (int) ( dval + 0.5 );
+ } else {
+ result = 0;
+ }
+ }
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ nc = 0;
+ nval = astSscanf( cval, " %d %n", &ival, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (short int *) out ) = ival;
+ } else {
+ nc = 0;
+ nval = astSscanf( cval, " %lf %n", &dval, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (short int *) out ) = (int) ( dval + 0.5 );
+ } else {
+ result = 0;
+ }
+ }
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ nc = 0;
+ nval = astSscanf( cval, " %d %n", &ival, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (unsigned char *) out ) = ival;
+ } else {
+ nc = 0;
+ nval = astSscanf( cval, " %lf %n", &dval, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (unsigned char *) out ) = (int) ( dval + 0.5 );
+ } else {
+ result = 0;
+ }
+ }
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ nc = 0;
+ nval = astSscanf( cval, " " BAD_STRING " %n", &nc );
+ if( ( astSscanf( cval, " " BAD_STRING " %n", &nc ) == 0 ) &&
+ ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (double *) out ) = AST__BAD;
+
+ } else if( ( astSscanf( cval, " %lf %n", &dval, &nc ) == 1 ) &&
+ ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (double *) out ) = dval;
+
+ } else {
+ result = 0;
+ }
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ nc = 0;
+ nval = astSscanf( cval, " %f %n", &fval, &nc );
+ if( ( nval == 1 ) && ( nc >= (int) strlen( cval ) ) ) {
+ if( out ) *( (float *) out ) = fval;
+ } else {
+ result = 0;
+ }
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ cvalue = cval;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Consider conversion from "AstObject *". */
+ } else if( raw_type == AST__OBJECTTYPE ) {
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ result = 0;
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ result = 0;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ result = 0;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ result = 0;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ aval = *( (AstObject **) raw );
+ if( out ) *( (AstObject **) out ) = aval ? astClone( aval ) : NULL;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ result = 0;
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Consider conversion from "void *". */
+ } else if( raw_type == AST__POINTERTYPE ) {
+
+/* Consider conversion to "int". */
+ if( out_type == AST__INTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "short int". */
+ } else if( out_type == AST__SINTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "byte". */
+ } else if( out_type == AST__BYTETYPE ) {
+ result = 0;
+
+/* Consider conversion to "double". */
+ } else if( out_type == AST__DOUBLETYPE ) {
+ result = 0;
+
+/* Consider conversion to "float". */
+ } else if( out_type == AST__FLOATTYPE ) {
+ result = 0;
+
+/* Consider conversion to "const char *". */
+ } else if( out_type == AST__STRINGTYPE ) {
+ result = 0;
+
+/* Consider conversion to "AstObject *". */
+ } else if( out_type == AST__OBJECTTYPE ) {
+ result = 0;
+
+/* Consider conversion to "void *". */
+ } else if( out_type == AST__POINTERTYPE ) {
+ if( out ) *( (void **) out ) = *( (void **) raw );
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ out_type );
+ }
+
+/* Report an error if the data type is unknown. */
+ } else {
+ result = 0;
+ astError( AST__INTER, "ConvertValue(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* If the output is a string, store a copy of the resulting string in
+ dynamically allocated memory, putting a pointer to the copy into the next
+ element of the "convertvalue_strings" array. (This process also de-allocates
+ any previously allocated memory pointed at by this "convertvalue_strings"
+ element, so the earlier string is effectively replaced by the new
+ one.) */
+ if( out_type == AST__STRINGTYPE && astOK && result && cvalue ) {
+ result = strlen( cvalue ) + 1;
+
+ astBeginPM;
+ convertvalue_strings[ convertvalue_istr ] = astStore( convertvalue_strings[ convertvalue_istr ], cvalue,
+ (size_t) result );
+ astEndPM;
+
+/* If OK, return a pointer to the copy and increment "convertvalue_istr" to use the
+ next element of "convertvalue_strings" on the next invocation. Recycle "convertvalue_istr" to
+ zero when all elements have been used. */
+ if ( astOK ) {
+ if( out ) *( (const char **) out ) = convertvalue_strings[ convertvalue_istr++ ];
+ if( convertvalue_istr == ( AST__KEYMAP_CONVERTVALUE_MAX_STRINGS - 1 ) ) convertvalue_istr = 0;
+ }
+ }
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+}
+
+
+static AstMapEntry *CopyMapEntry( AstMapEntry *in, int *status ){
+/*
+* Name:
+* CopyMapEntry
+
+* Purpose:
+* Produces a copy of the supplied KeyMap entry.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstMapEntry *CopyMapEntry( AstMapEntry *in, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function creates a deep copy of the supplied KeyMap entry.
+
+* Parameters:
+* in
+* Pointer to the MapEntry to be copied. NULL may be supplied in
+* which case NULL will be returned.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the new copy. The link to the next MapEntry in the
+* linked list is set NULL in the returned copy.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstMapEntry *result; /* Returned pointer */
+ AstObject **alist; /* Pointer to list of AST object pointers */
+ AstObject *obj; /* Pointer to AstObject value */
+ const char **slist; /* Pointer to list of text pointers */
+ const char *text; /* Pointer to text string */
+ int i; /* Loop count */
+ int nel; /* No. of values in entry vector (0 => scalar) */
+ int type; /* Entry data type */
+ size_t size; /* Size of Entry structure */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status and the supplied pointer. */
+ if ( !astOK || !in ) return result;
+
+/* Get the size, data type and length of the MapEntry. */
+ size = SizeOfEntry( in, status );
+ nel = in->nel;
+ type = in->type;
+
+/* Do a byte-for-byte copy of the supplied MapEntry. */
+ result = astStore( NULL, in, size );
+
+/* Copy or nullify pointers in the AstMapEntry structure. */
+ result->next = NULL;
+ result->snext = NULL;
+ result->sprev = NULL;
+ text = in->key;
+ result->key = text ? astStore( NULL, text, strlen( text ) + 1 ) : NULL;
+ text = in->comment;
+ result->comment = text ? astStore( NULL, text, strlen( text ) + 1 ) : NULL;
+
+/* Nothing further to do for undefined values. */
+ if( type == AST__UNDEFTYPE ) {
+
+/* Next deal with string entries. */
+ } else if( type == AST__STRINGTYPE ) {
+
+/* Scalar valued entries... */
+ if( nel == 0 ) {
+
+/* Take a copy of the single string in the input entry. */
+ text = ( (Entry0C *) in )->value;
+ ( (Entry0C *) result )->value = text ? astStore( NULL, text,
+ strlen( text ) + 1 ) : NULL;
+/* Vector valued entries... */
+ } else {
+
+/* Allocate an array to store the string pointers. */
+ slist = astMalloc( sizeof(char *)*(size_t)nel );
+ ( (Entry1C *) result )->value = slist;
+
+/* Copy the strings. */
+ if( slist ) {
+ for( i = 0; i < nel; i++ ) {
+ text = ( (Entry1C *) in )->value[ i ];
+ slist[ i ] = text ? astStore( NULL, text, strlen( text ) + 1 ) : NULL;
+ }
+ }
+ }
+
+/* Similarly deal with AST Object entries. */
+ } else if( type == AST__OBJECTTYPE ) {
+ if( nel == 0 ) {
+ obj = ( (Entry0A *) in )->value;
+ ( (Entry0A *) result )->value = obj ? astCopy( obj ) : NULL;
+ ( (Entry0A *) result )->next = NULL;
+ ( (Entry0A *) result )->prev = NULL;
+ } else {
+ alist = astMalloc( sizeof(AstObject *)*(size_t)nel );
+ ( (Entry1A *) result )->value = alist;
+ if( alist ) {
+ for( i = 0; i < nel; i++ ) {
+ obj = ( (Entry1A *) in )->value[ i ];
+ alist[ i ] = obj ? astCopy( obj ) : NULL;
+ }
+ ( (Entry1A *) result )->next = NULL;
+ ( (Entry1A *) result )->prev = NULL;
+ }
+ }
+
+/* Now deal with integer entries. Scalar entries do not need any further
+ action. If this is a vector entry copy the values array. */
+ } else if( type == AST__INTTYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1I *) result )->value = astStore( NULL,
+ ( (Entry1I *) in )->value,
+ sizeof( int )*(size_t)nel );
+ }
+
+/* Now deal with short int entries. Scalar entries do not need any further
+ action. If this is a vector entry copy the values array. */
+ } else if( type == AST__SINTTYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1S *) result )->value = astStore( NULL,
+ ( (Entry1S *) in )->value,
+ sizeof( short int )*(size_t)nel );
+ }
+
+/* Now deal with byte entries. Scalar entries do not need any further
+ action. If this is a vector entry copy the values array. */
+ } else if( type == AST__BYTETYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1B *) result )->value = astStore( NULL,
+ ( (Entry1B *) in )->value,
+ sizeof( unsigned char )*(size_t)nel );
+ }
+
+/* Similarly deal with floating point entries. */
+ } else if( type == AST__DOUBLETYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1D *) result )->value = astStore( NULL,
+ ( (Entry1D *) in )->value,
+ sizeof( double )*(size_t)nel );
+ }
+
+ } else if( type == AST__FLOATTYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1F *) result )->value = astStore( NULL,
+ ( (Entry1F *) in )->value,
+ sizeof( float )*(size_t)nel );
+ }
+
+/* Similarly deal with void pointer entries. */
+ } else if( type == AST__POINTERTYPE ) {
+ if( nel > 0 ) {
+ ( (Entry1P *) result )->value = astStore( NULL,
+ ( (Entry1P *) in )->value,
+ sizeof( void * )*(size_t)nel );
+ }
+
+/* Report an error if the data type is unknown. */
+ } else {
+ astError( AST__INTER, "CopyMapEntry(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+
+/* If an error has occurred, attempt to delete the returned MapEntry. */
+ if( !astOK ) result = FreeMapEntry( result, status );
+
+/* Return the result. */
+ return result;
+}
+
+static void CopyTableEntry( AstKeyMap *in, AstKeyMap *out, int itab, int *status ){
+/*
+* Name:
+* CopyTableEntry
+
+* Purpose:
+* Produces a deep copy of a hash table element.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void CopyTableEntry( AstKeyMap *in, AstKeyMap *out, int itab, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function creates a deep copy of the linked-list of KeyMap entries
+* stored in the specified element of the input KeyMaps hash table.
+
+* Parameters:
+* in
+* Pointer to the input KeyMap.
+* out
+* Pointer to the output KeyMap.
+* itab
+* Index of the hash table element to be copied.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry **link; /* Address to store foward link */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* The "link" variable holds the address of the location at which the
+ pointer to the next copied MapEntry should be stored. Initialise this to
+ be the address of the required element of the output hash table. */
+ link = &( out->table[ itab ] );
+
+/* The "next" variable holds the address of the next MapEntry to be
+ copied. Initialise this to the MapEntry at the head of the linked list
+ associated with the specified index of the input KeyMaps hash table. */
+ next = in->table[ itab ];
+
+/* If the hash table element is empty, store a null pointer and pass on. */
+ if( !next ) {
+ out->table[ itab ] = NULL;
+
+/* Otherwise copy the liked list. */
+ } else {
+
+/* Loop round until we have copied all entries. */
+ while( next && astOK ) {
+
+/* Copy the next entry, storing the resulting pointer at the position
+ indicated by "link". */
+ *link = CopyMapEntry( next, status );
+
+/* If the entry is of type AST__OBJECTTYPE, add it to the head of the
+ list of AST__OBJECTTYPE entries in the output KeyMap. */
+ AddToObjectList( out, *link, status );
+
+/* Update "link" and "next" */
+ next = next->next;
+ link = &( (*link)->next );
+ }
+ }
+
+/* Set the number of entries in the output to be the same as the input. */
+ out->nentry[ itab ] = in->nentry[ itab ];
+
+/* If an error has occurred, attempt to delete the returned MapEntry. */
+ if( !astOK ) FreeTableEntry( out, itab, status );
+}
+
+static void DoubleTableSize( AstKeyMap *this, int *status ) {
+/*
+* Name:
+* DoubleTableSize
+
+* Purpose:
+* Double the size of the hash table in a KeyMap
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void DoubleTableSize( AstKeyMap *this, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function creates a new hash table which has twice as many
+* elements as the current hash table, and moves all the entries out
+* of the old table into the new table (at their new positions).
+
+* Parameters:
+* this
+* The KeyMap pointer.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry **newtable;
+ AstMapEntry *next;
+ AstMapEntry *new_next;
+ int *newnentry;
+ int bitmask;
+ int i;
+ int newi;
+ int newmapsize;
+
+/* Check the global error status. */
+ if( !astOK ) return;
+
+/* Determine the new hash table size. Since mapsize starts out as a power
+ of 2 (ensured by the NewTable function), the new mapsize will also be
+ a power of 2. Also, create a bit mask that can be used to zero the
+ upper bits in a full width hash value. */
+ newmapsize = 2*this->mapsize;
+ bitmask = newmapsize - 1;
+
+/* Create the new arrays, leaving the old arrays intact for the moment. */
+ newtable = astMalloc( newmapsize*sizeof( AstMapEntry * ) );
+ newnentry = astMalloc( newmapsize*sizeof( int ) );
+ if( astOK ) {
+
+/* Initialise the new table. */
+ for( i = 0; i < newmapsize; i++ ) {
+ newtable[ i ] = NULL;
+ newnentry[ i ] = 0;
+ }
+
+/* Loop round each of the existing table entries. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* The "next" variable holds the address of the next MapEntry to be
+ moved. Initialise this to the MapEntry at the head of the linked list
+ associated with the specified index of the input KeyMaps hash table. */
+ next = this->table[ i ];
+
+/* Loop round until we have moved all entries. */
+ while( next && astOK ) {
+
+/* Find the index within the new table at which to store this entry. */
+ newi = ( next->hash & bitmask );
+
+/* Save the pointer to the next entry following the current one in the
+ linked list. */
+ new_next = next->next;
+
+/* Put a pointer to the MapEntry which is currently at the head of the
+ linked list in the "next" component of the current MapEntry. */
+ next->next = newtable[ newi ];
+
+/* Store the supplied MapEntry pointer in the requested element of the
+ hash table. */
+ newtable[ newi ] = next;
+
+/* Increment the length of linked list. */
+ newnentry[ newi ]++;
+
+/* Use the pointer to the next map entry to be moved. */
+ next = new_next;
+ }
+ }
+ }
+
+/* If OK, delete the existing table and use the new table */
+ if( astOK ) {
+ this->mapsize = newmapsize;
+
+ (void) astFree( this->table );
+ this->table = newtable;
+
+ (void) astFree( this->nentry );
+ this->nentry = newnentry;
+
+/* If not OK, delete the new table. */
+ } else {
+ newtable = astFree( newtable );
+ newnentry = astFree( newnentry );
+ }
+}
+
+static void DumpEntry( AstMapEntry *entry, AstChannel *channel, int nentry, int *status ) {
+/*
+* Name:
+* DumpEntry
+
+* Purpose:
+* Dump a single AstMapEntry to a Channel.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void DumpEntry( AstMapEntry *entry, AstChannel *channel, int nentry )
+
+* Description:
+* This function dumps the supplied MapEntry to the supplied Channel.
+
+* Parameters:
+* entry
+* Pointer to the MapEntry whose data are being written.
+* channel
+* Pointer to the Channel to which the data are being written.
+* nentry
+* The integer index value to use when describing the MapEntry in
+* the dump.
+*/
+
+/* Local Variables: */
+ char buff[20]; /* Buffer for item names */
+ const char *com; /* Pointer to comment string */
+ int index; /* Index into vector valued entry */
+ int nel; /* Number of elements in value */
+ int type; /* Entry data type */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Dump the entry key. */
+ (void) sprintf( buff, "Key%d", nentry );
+ astWriteString( channel, buff, 1, 1, entry->key, "Item name" );
+
+/* Dump the comment if not blank. */
+ if( entry->comment && *(entry->comment) ) {
+ (void) sprintf( buff, "Com%d", nentry );
+ astWriteString( channel, buff, 1, 1, entry->comment, "Item comment" );
+ }
+
+/* Get the data type and the length of the Entry. */
+ type = entry->type;
+ nel = entry->nel;
+
+/* Dump the entry data type. */
+ if( type == AST__STRINGTYPE ) {
+ com = "Item data type (string)";
+
+ } else if( type == AST__OBJECTTYPE ) {
+ com = "Item data type (AST Object)";
+
+ } else if( type == AST__INTTYPE ) {
+ com = "Item data type (int)";
+
+ } else if( type == AST__SINTTYPE ) {
+ com = "Item data type (short int)";
+
+ } else if( type == AST__BYTETYPE ) {
+ com = "Item data type (unsigned byte)";
+
+ } else if( type == AST__DOUBLETYPE ) {
+ com = "Item data type (double)";
+
+ } else if( type == AST__FLOATTYPE ) {
+ com = "Item data type (float)";
+
+ } else if( type == AST__POINTERTYPE ) {
+ com = "Item data type (pointer)";
+
+ } else if( type == AST__UNDEFTYPE ) {
+ com = "Item data type (undefined)";
+
+ } else {
+ com = "";
+ astError( AST__INTER, "DumpEntry(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+ (void) sprintf( buff, "Typ%d", nentry );
+ astWriteInt( channel, buff, 1, 1, entry->type, com );
+
+/* Dump the vector length */
+ if( entry->nel > 0 ) {
+ (void) sprintf( buff, "Nel%d", nentry );
+ astWriteInt( channel, buff, 1, 1, entry->nel, "Vector length" );
+ }
+
+/* First deal with integer entries. */
+ if( type == AST__INTTYPE ) {
+ if( entry->nel == 0 ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteInt( channel, buff, 1, 1, ((Entry0I *)entry)->value, "Item value" );
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteInt( channel, buff, 1, 1, ((Entry1I *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+
+/* Similarly, deal with short int entries. */
+ } else if( type == AST__SINTTYPE ) {
+ if( entry->nel == 0 ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteInt( channel, buff, 1, 1, (int) ((Entry0S *)entry)->value, "Item value" );
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteInt( channel, buff, 1, 1, (int) ((Entry1S *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+
+/* Similarly, deal with byte entries. */
+ } else if( type == AST__BYTETYPE ) {
+ if( entry->nel == 0 ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteInt( channel, buff, 1, 1, (int) ((Entry0B *)entry)->value, "Item value" );
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteInt( channel, buff, 1, 1, (int) ((Entry1B *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+
+/* Similarly deal with floating point entries. */
+ } else if( type == AST__DOUBLETYPE ) {
+ if( entry->nel == 0 ) {
+ if( ((Entry0D *)entry)->value != AST__BAD ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteDouble( channel, buff, 1, 1, ((Entry0D *)entry)->value, "Item value" );
+ }
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ if( ((Entry1D *)entry)->value[ index ] != AST__BAD ) {
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteDouble( channel, buff, 1, 1, ((Entry1D *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+ }
+
+/* Similarly deal with single precision floating point entries. */
+ } else if( type == AST__FLOATTYPE ) {
+ if( entry->nel == 0 ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteDouble( channel, buff, 1, 1, (double) ((Entry0F *)entry)->value, "Item value" );
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteDouble( channel, buff, 1, 1, (double) ((Entry1F *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+
+/* Do the same for string values. */
+ } else if( type == AST__STRINGTYPE ) {
+ if( entry->nel == 0 ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteString( channel, buff, 1, 1, ((Entry0C *)entry)->value, "Item value" );
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteString( channel, buff, 1, 1, ((Entry1C *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+
+/* Do the same for Object values. */
+ } else if( type == AST__OBJECTTYPE ) {
+ if( entry->nel == 0 ) {
+ if( ((Entry0A *)entry)->value ) {
+ (void) sprintf( buff, "Val%d", nentry );
+ astWriteObject( channel, buff, 1, 1, ((Entry0A *)entry)->value, "Item value" );
+ }
+ } else {
+ com = "Item values";
+ for( index = 0; index < nel; index++ ){
+ if( ((Entry1A *)entry)->value[ index ] ) {
+ (void) sprintf( buff, "V%d_%d", nentry, index + 1 );
+ astWriteObject( channel, buff, 1, 1, ((Entry1A *)entry)->value[ index ], com );
+ com = "";
+ }
+ }
+ }
+
+/* Void pointer values cannot be dumped. */
+ } else if( type == AST__POINTERTYPE ) {
+ astError( AST__INTER, "DumpEntry(KeyMap): Cannot dump KeyMaps in "
+ "which the values are arbitrary C pointers (possible "
+ "programming error)." , status);
+
+/* Nothing further to do for undefined values. */
+ } else if( type == AST__UNDEFTYPE ) {
+
+/* Report an error if the data type is unknown. */
+ } else if( astOK ) {
+ astError( AST__INTER, "DumpEntry(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+}
+
+static AstMapEntry *FreeMapEntry( AstMapEntry *in, int *status ){
+/*
+* Name:
+* FreeMapEntry
+
+* Purpose:
+* Frees the supplied KeyMap entry.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstMapEntry *FreeMapEntry( AstMapEntry *in, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function frees resources used by the supplied MapEntry, then
+* frees the MapEntry structure itself and returns a NULL pointer.
+
+* Parameters:
+* in
+* Pointer to the MapEntry to be freed. NULL may be supplied in
+* which the function returns without action.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A NULL pointer.
+
+* Notes:
+* - It is the callers responsibility to ensure that any other MapEntry
+* which refers to the supplied MapEntry (e.g. through the "next" link
+* in the MapEntry structure) is modified to take account of the
+* freeing of the supplied MapEntry.
+* - This function attempts to execute even if it is invoked with the
+* global error status set.
+*/
+
+/* Local Variables: */
+ AstObject **alist; /* Pointer to list of AST object pointers */
+ AstObject *obj; /* Pointer to AST object */
+ const char **slist; /* Pointer to list of text pointers */
+ int i; /* Loop count */
+ int nel; /* No. of values in entry vector (0 => scalar) */
+ int type; /* Entry data type */
+
+/* Check the supplied pointer. */
+ if( !in ) return NULL;
+
+/* Get the data type and length of the MapEntry. */
+ nel = in->nel;
+ type = in->type;
+
+/* First deal with string entries. */
+ if( type == AST__STRINGTYPE ) {
+
+/* For scalar valued entries, free the single string in the input entry. */
+ if( nel == 0 ) {
+ ( (Entry0C *) in )->value = (const char *) astFree( ( void *) ( (Entry0C *) in )->value );
+
+/* For vector valued entries, free the strings, then free the array storing
+ the string pointers. */
+ } else {
+ slist = ( (Entry1C *) in )->value;
+ if( slist ) {
+ for( i = 0; i < nel; i++ ) slist[ i ] = astFree( (void *) slist[ i ] );
+ ( (Entry1C *) in )->value = astFree( (void *) slist );
+ }
+ }
+
+/* Similarly deal with AST Object entries. */
+ } else if( type == AST__OBJECTTYPE ) {
+ if( nel == 0 ) {
+ obj = ( (Entry0A *) in )->value;
+ if( obj ) ( (Entry0A *) in )->value = astAnnul( obj );
+ ( (Entry0A *) in )->next = NULL;
+ ( (Entry0A *) in )->prev = NULL;
+ } else {
+ alist = ( (Entry1A *) in )->value;
+ if( alist ) {
+ for( i = 0; i < nel; i++ ) {
+ if( alist[ i ] ) alist[ i ] = astAnnul( alist[ i ] );
+ }
+ ( (Entry1A *) in )->value = astFree( alist );
+ ( (Entry1A *) in )->next = NULL;
+ ( (Entry1A *) in )->prev = NULL;
+ }
+ }
+
+/* Now deal with integer entries. Scalar entries do not need any further
+ action. If this is a vector entry free the values array. */
+ } else if( type == AST__INTTYPE ) {
+ if( nel > 0 ) ( (Entry1I *) in )->value = astFree( ( (Entry1I *) in )->value );
+
+/* Now deal with short int entries. Scalar entries do not need any further
+ action. If this is a vector entry free the values array. */
+ } else if( type == AST__SINTTYPE ) {
+ if( nel > 0 ) ( (Entry1S *) in )->value = astFree( ( (Entry1S *) in )->value );
+
+/* Now deal with byte entries. Scalar entries do not need any further
+ action. If this is a vector entry free the values array. */
+ } else if( type == AST__BYTETYPE ) {
+ if( nel > 0 ) ( (Entry1B *) in )->value = astFree( ( (Entry1B *) in )->value );
+
+/* Similarly deal with void * pointer entries. */
+ } else if( type == AST__POINTERTYPE ) {
+ if( nel > 0 ) ( (Entry1P *) in )->value = astFree( ( (Entry1P *) in )->value );
+
+/* Similarly deal with floating point entries. */
+ } else if( type == AST__DOUBLETYPE ) {
+ if( nel > 0 ) ( (Entry1D *) in )->value = astFree( ( (Entry1D *) in )->value );
+
+/* Similarly deal with single precision floating point entries. */
+ } else if( type == AST__FLOATTYPE ) {
+ if( nel > 0 ) ( (Entry1F *) in )->value = astFree( ( (Entry1F *) in )->value );
+
+/* Nothing further to do for undefined values. */
+ } else if( type == AST__UNDEFTYPE ) {
+
+/* Report an error if the data type is unknown. */
+ } else {
+ astError( AST__INTER, "FreeMapEntry(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+
+/* Free or nullify pointers in the AstMapEntry structure. */
+ in->next = NULL;
+ in->snext = NULL;
+ in->sprev = NULL;
+ in->key = astFree( (void *) in->key );
+ in->comment = astFree( (void *) in->comment );
+
+/* Free the complete AstMapEntry structure. */
+ astFree( in );
+
+/* Return a NULL pointer. */
+ return NULL;
+}
+
+static void FreeTableEntry( AstKeyMap *this, int itab, int *status ){
+/*
+* Name:
+* FreeTableEntry
+
+* Purpose:
+* Frees the linked list of KeyMap entries stored in a given element of
+* the hash table.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void FreeTableEntry( AstKeyMap *this, int itab, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function frees resources used by all the MapEntries in the
+* linked list associated with the specified element of the hash table
+* of the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap
+* itab
+* Index of the hash table element to free.
+* status
+* Pointer to the inherited status variable.
+
+* Notes:
+* - This function attempts to execute even if it is invoked with the
+* global error status set.
+*/
+
+/* Local Variables: */
+ AstMapEntry *link; /* Pointer the next but one MapEntry to be freed */
+ AstMapEntry *next; /* Pointer the next MapEntry to be freed */
+
+/* Check it is safe to proceed. */
+ if( this && itab >= 0 && itab < this->mapsize ) {
+
+/* Store a pointer to the MapEntry which is to be freed next. */
+ next = this->table[ itab ];
+
+/* Loop round freeing all MapEntries in the linked list. */
+ while( next ) {
+
+/* Store a pointer to the MapEntry which will be freed after this one. */
+ link = next->next;
+
+/* Free this MapEntry */
+ (void) FreeMapEntry( next, status );
+
+/* Set up the next MapEntry to be freed. */
+ next = link;
+ }
+
+/* Store a NULL pointer in the table element. */
+ this->table[ itab ] = NULL;
+
+/* Sets the number of entries in this hash table element to zero. */
+ this->nentry[ itab ] = 0;
+ }
+}
+
+static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* GetAttrib
+
+* Purpose:
+* Get the value of a specified attribute for a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* const char *GetAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* KeyMap member function (over-rides the protected astGetAttrib
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a pointer to the value of a specified
+* attribute for a KeyMap, formatted as a character string.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* attrib
+* Pointer to a null-terminated string containing the name of
+* the attribute whose value is required. This name should be in
+* lower case, with all white space removed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* - Pointer to a null-terminated string containing the attribute
+* value.
+
+* Notes:
+* - The returned string pointer may point at memory allocated
+* within the KeyMap, or at static memory. The contents of the
+* string may be over-written or the pointer may become invalid
+* following a further invocation of the same function or any
+* modification of the KeyMap. A copy of the string should
+* therefore be made if necessary.
+* - A NULL pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+ const char *result; /* Pointer value to return */
+ int ival; /* Attribute value */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this_object);
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Compare "attrib" with each recognised attribute name in turn,
+ obtaining the value of the required attribute. If necessary, write
+ the value into "getattrib_buff" as a null-terminated string in an appropriate
+ format. Set "result" to point at the result string. */
+
+/* SizeGuess. */
+/* ---------- */
+ if ( !strcmp( attrib, "sizeguess" ) ) {
+ ival = astGetSizeGuess( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", ival );
+ result = getattrib_buff;
+ }
+
+/* KeyCase. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keycase" ) ) {
+ ival = astGetKeyCase( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", ival );
+ result = getattrib_buff;
+ }
+
+/* KeyError. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keyerror" ) ) {
+ ival = astGetKeyError( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", ival );
+ result = getattrib_buff;
+ }
+
+/* MapLocked. */
+/* --------- */
+ } else if ( !strcmp( attrib, "maplocked" ) ) {
+ ival = astGetMapLocked( this );
+ if ( astOK ) {
+ (void) sprintf( getattrib_buff, "%d", ival );
+ result = getattrib_buff;
+ }
+
+/* SortBy. */
+/* --------- */
+ } else if ( !strcmp( attrib, "sortby" ) ) {
+ ival = astGetSortBy( this );
+ if ( astOK ) {
+ result = SortByString( ival, "astGetAttrib", status );
+ }
+
+/* If the attribute name was not recognised, pass it on to the parent
+ method for further interpretation. */
+ } else {
+ result = (*parent_getattrib)( this_object, attrib, status );
+ }
+
+/* Return the result. */
+ return result;
+
+}
+
+static int GetObjSize( AstObject *this_object, int *status ) {
+/*
+* Name:
+* GetObjSize
+
+* Purpose:
+* Return the in-memory size of an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int GetObjSize( AstObject *this, int *status )
+
+* Class Membership:
+* KeyMap member function (over-rides the astGetObjSize protected
+* method inherited from the parent class).
+
+* Description:
+* This function returns the in-memory size of the supplied KeyMap,
+* in bytes.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The Object size, in bytes.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to KeyMap structure */
+ AstMapEntry *next; /* Pointer the next MapEntry */
+ AstObject **alist; /* Pointer to list of AST object pointers */
+ AstObject *obj; /* Pointer to AST object */
+ const char **slist; /* Pointer to list of text pointers */
+ int i; /* Loop count */
+ int itab; /* Table entry index */
+ int nel; /* No. of values in entry vector (0 => scalar) */
+ int result; /* Result value to return */
+ int type; /* Entry data type */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointers to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Invoke the GetObjSize method inherited from the parent class, and then
+ add on any components of the class structure defined by thsi class
+ which are stored in dynamically allocated memory. */
+ result = (*parent_getobjsize)( this_object, status );
+
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+ next = this->table[ itab ];
+ while( next ) {
+ nel = next->nel;
+ type = next->type;
+
+ if( type == AST__STRINGTYPE ) {
+
+ if( nel == 0 ) {
+ result += astTSizeOf( ( void *) ( (Entry0C *) next )->value );
+
+ } else {
+ slist = ( (Entry1C *) next )->value;
+ if( slist ) {
+ for( i = 0; i < nel; i++ ) result += astTSizeOf( (void *) slist[ i ] );
+ result += astTSizeOf( (void *) slist );
+ }
+ }
+
+ } else if( type == AST__OBJECTTYPE ) {
+ if( nel == 0 ) {
+ obj = ( (Entry0A *) next )->value;
+ result += astGetObjSize( obj );
+ } else {
+ alist = ( (Entry1A *) next )->value;
+ if( alist ) {
+ for( i = 0; i < nel; i++ ) {
+ result += astGetObjSize( alist[ i ] );
+ }
+ result += astTSizeOf( alist );
+ }
+ }
+
+ } else if( type == AST__POINTERTYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1P *) next )->value );
+
+ } else if( type == AST__INTTYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1I *) next )->value );
+
+ } else if( type == AST__SINTTYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1S *) next )->value );
+
+ } else if( type == AST__BYTETYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1B *) next )->value );
+
+ } else if( type == AST__DOUBLETYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1D *) next )->value );
+
+ } else if( type == AST__FLOATTYPE ) {
+ if( nel > 0 ) result += astTSizeOf( ( (Entry1F *) next )->value );
+
+ } else if( type == AST__UNDEFTYPE ) {
+
+ } else {
+ astError( AST__INTER, "astGetObjSize(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+
+ result += astTSizeOf( (void *) next->key );
+ result += astTSizeOf( (void *) next->comment );
+ result += astTSizeOf( next );
+
+ next = next->next;
+ }
+ }
+
+/* If an error occurred, clear the result value. */
+ if ( !astOK ) result = 0;
+
+/* Return the result, */
+ return result;
+}
+
+static const char *GetKey( AstKeyMap *this, int index, int *status ) {
+/*
+* Name:
+* GetKey
+
+* Purpose:
+* Get the key at a given index within the KeyMap.
+
+* Type:
+* Private member function.
+
+* Synopsis:
+* #include "keymap.h"
+* const char *GetKey( AstKeyMap *this, int index, int *status )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns a string holding the key for the entry with
+* the given index within the KeyMap. The index associated with a
+* given key is determined by the current setting of the SortBy attribute.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* index
+* The index into the KeyMap. The first entry has index zero, and the last
+* has index "size-1", where "size" is the value returned by the
+* astMapSize function. An error is reported if the supplied index is
+* out of bounds.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A pointer to a null-terminated string containing the key.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the AST error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstMapEntry *entry; /* Pointer to the entry */
+ const char *result; /* Pointer value to return */
+ int ifirst; /* Index of first entry in this table element */
+ int ilast; /* Index of last entry in this table element */
+ int istep; /* Entry count */
+ int itab; /* Index into hash table */
+ int nstep; /* No. of entries to skip */
+ int sortby; /* The value of the SortBy attribute */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get the SortBy value. */
+ sortby = astGetSortBy( this );
+
+/* First deal with unsorted keys. */
+ if( sortby == SORTBY_NONE ) {
+
+/* Loop round each entry in the hash table. */
+ ilast = -1;
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+
+/* Find the index of the first and the last Entry in the linked list associated
+ with this element of the hash table. */
+ ifirst = ilast + 1;
+ ilast += this->nentry[ itab ];
+
+/* Pass on if we have not yet reached the element containing the required
+ key. */
+ if( ilast >= index ) {
+
+/* Find how many steps we need to proceed down the linked list to reach
+ the required index. */
+ nstep = index - ifirst;
+
+/* Make this many steps down the linked list.*/
+ entry = this->table[ itab ];
+ for( istep = 0; entry && istep < nstep; istep++ ) entry = entry->next;
+
+/* Return a pointer to the key string, and break out of the loop. */
+ if( entry ) result = entry->key;
+ break;
+
+ }
+ }
+
+/* Now deal with sorted keys. */
+ } else {
+
+/* Get a pointer to the first entry in the sorted list. */
+ entry = this->first;
+
+/* Move up the sorted list by the required number of entries. */
+ for( istep = 0; entry && istep < index; istep++ ) entry = entry->snext;
+
+/* Return a pointer to the key string. */
+ if( entry ) result = entry->key;
+ }
+
+/* Report an error if the element was not found. */
+ if( !result && astOK ) {
+ astError( AST__MPIND, "astMapKey(%s): Cannot find element "
+ "%d (zero-based) of the %s.", status, astGetClass( this ),
+ index, astGetClass( this ) );
+ }
+
+/* Return the result.*/
+ return result;
+}
+
+static int GetSizeGuess( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astGetSizeGuess
+
+* Purpose:
+* Get the value of the SizeGuess attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* int astGetSizeGuess( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns the value of the SizeGuess attribute for a
+* KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+* Returned Value:
+* The value of the SizeGuess attribute.
+
+* Notes:
+* - A value of zero is returned if this function is invoked with the
+* global error status set.
+
+*-
+*/
+
+/* Local Variables: */
+ int result; /* Returned value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Return the attribute value using a default if not set. */
+ return ( this->sizeguess == INT_MAX ) ?
+ MIN_TABLE_SIZE*MAX_ENTRIES_PER_TABLE_ENTRY : this->sizeguess;
+}
+
+static int HashFun( const char *key, int bitmask, unsigned long *hash, int *status ){
+/*
+* Name:
+* HashFun
+
+* Purpose:
+* Returns an integer hash code for a string
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int HashFun( const char *key, int bitmask, int *hash, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function returns an integer hash code for the supplied string,
+* This is the value that isused as the index into the hash table for
+* the specified key.
+
+* Parameters:
+* key
+* Pointer to the string. Trailing spaces are ignored.
+* bitmask
+* A bit mask that is used to zero the upper bits of a full width
+* hash value in order to produce the required array index. This
+* should be one less than the length of the hash table.
+* hash
+* Pointer to a location at which to put the full width hash value.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* An integer in the range zero to ( mapsize - 1 ).
+
+* Notes:
+* - A value of zero is returned if this function is invoked with the
+* global error status set.
+*/
+
+/* Local Variables: */
+ int c;
+
+/* Check the local error status. */
+ if ( !astOK ) return 0;
+
+/* djb2: This hash function was first reported by Dan Bernstein many years
+ ago in comp.lang.c Each through the "hile" loop corresponds to
+ "hash = hash*33 + c ". Ignore spaces so that trailing spaces used to
+ pad F77 character variables will be ignored. */
+ *hash = 5381;
+ while( (c = *key++) ) {
+ if( c != ' ' ) {
+ *hash = ((*hash << 5) + *hash) + c;
+ }
+ }
+ return ( *hash & bitmask );
+}
+
+void astInitKeyMapVtab_( AstKeyMapVtab *vtab, const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitKeyMapVtab
+
+* Purpose:
+* Initialise a virtual function table for a KeyMap.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astInitKeyMapVtab( AstKeyMapVtab *vtab, const char *name )
+
+* Class Membership:
+* KeyMap vtab initialiser.
+
+* Description:
+* This function initialises the component of a virtual function
+* table which is used by the KeyMap class.
+
+* Parameters:
+* vtab
+* Pointer to the virtual function table. The components used by
+* all ancestral classes will be initialised if they have not already
+* been initialised.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the virtual function table belongs (it
+* is this pointer value that will subsequently be returned by the Object
+* astClass function).
+*-
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstObjectVtab *object; /* Pointer to Object component of Vtab */
+
+/* Check the local error status. */
+ if ( !astOK ) return;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Initialize the component of the virtual function table used by the
+ parent class. */
+ astInitObjectVtab( (AstObjectVtab *) vtab, name );
+
+/* Store a unique "magic" value in the virtual function table. This
+ will be used (by astIsAKeyMap) to determine if an object belongs
+ to this class. We can conveniently use the address of the (static)
+ class_check variable to generate this unique value. */
+ vtab->id.check = &class_check;
+ vtab->id.parent = &(((AstObjectVtab *) vtab)->id);
+
+/* Initialise member function pointers. */
+/* ------------------------------------ */
+/* Store pointers to the member functions (implemented here) that provide
+ virtual methods for this class. */
+
+ vtab->MapGet0P = MapGet0P;
+ vtab->MapGet0A = MapGet0A;
+ vtab->MapGet0C = MapGet0C;
+ vtab->MapGet0D = MapGet0D;
+ vtab->MapGet0F = MapGet0F;
+ vtab->MapGet0I = MapGet0I;
+ vtab->MapGet0B = MapGet0B;
+ vtab->MapGet0S = MapGet0S;
+ vtab->MapGet1P = MapGet1P;
+ vtab->MapGet1A = MapGet1A;
+ vtab->MapGet1C = MapGet1C;
+ vtab->MapGet1D = MapGet1D;
+ vtab->MapGet1F = MapGet1F;
+ vtab->MapGet1I = MapGet1I;
+ vtab->MapGet1B = MapGet1B;
+ vtab->MapGet1S = MapGet1S;
+ vtab->MapGetC = MapGetC;
+ vtab->MapGetElemP = MapGetElemP;
+ vtab->MapGetElemA = MapGetElemA;
+ vtab->MapGetElemC = MapGetElemC;
+ vtab->MapGetElemD = MapGetElemD;
+ vtab->MapGetElemF = MapGetElemF;
+ vtab->MapGetElemI = MapGetElemI;
+ vtab->MapGetElemS = MapGetElemS;
+ vtab->MapGetElemB = MapGetElemB;
+ vtab->MapPutElemP = MapPutElemP;
+ vtab->MapPutElemA = MapPutElemA;
+ vtab->MapPutElemC = MapPutElemC;
+ vtab->MapPutElemD = MapPutElemD;
+ vtab->MapPutElemF = MapPutElemF;
+ vtab->MapPutElemI = MapPutElemI;
+ vtab->MapPutElemS = MapPutElemS;
+ vtab->MapPutElemB = MapPutElemB;
+ vtab->MapPut0A = MapPut0A;
+ vtab->MapPut0P = MapPut0P;
+ vtab->MapPut0C = MapPut0C;
+ vtab->MapPut0D = MapPut0D;
+ vtab->MapPut0F = MapPut0F;
+ vtab->MapPut0I = MapPut0I;
+ vtab->MapPut0S = MapPut0S;
+ vtab->MapPut0B = MapPut0B;
+ vtab->MapPut1P = MapPut1P;
+ vtab->MapPut1A = MapPut1A;
+ vtab->MapPut1C = MapPut1C;
+ vtab->MapPut1D = MapPut1D;
+ vtab->MapPut1F = MapPut1F;
+ vtab->MapPut1I = MapPut1I;
+ vtab->MapPut1S = MapPut1S;
+ vtab->MapPut1B = MapPut1B;
+ vtab->MapPutU = MapPutU;
+ vtab->MapRemove = MapRemove;
+ vtab->MapRename = MapRename;
+ vtab->MapCopy = MapCopy;
+ vtab->MapDefined = MapDefined;
+ vtab->MapSize = MapSize;
+ vtab->MapLenC = MapLenC;
+ vtab->MapLength = MapLength;
+ vtab->MapType = MapType;
+ vtab->MapHasKey = MapHasKey;
+ vtab->MapKey = MapKey;
+ vtab->MapIterate = MapIterate;
+
+ vtab->ClearSizeGuess = ClearSizeGuess;
+ vtab->SetSizeGuess = SetSizeGuess;
+ vtab->GetSizeGuess = GetSizeGuess;
+ vtab->TestSizeGuess = TestSizeGuess;
+
+ vtab->ClearSortBy = ClearSortBy;
+ vtab->SetSortBy = SetSortBy;
+ vtab->GetSortBy = GetSortBy;
+ vtab->TestSortBy = TestSortBy;
+
+ vtab->ClearKeyError = ClearKeyError;
+ vtab->SetKeyError = SetKeyError;
+ vtab->GetKeyError = GetKeyError;
+ vtab->TestKeyError = TestKeyError;
+
+ vtab->ClearKeyCase = ClearKeyCase;
+ vtab->SetKeyCase = SetKeyCase;
+ vtab->GetKeyCase = GetKeyCase;
+ vtab->TestKeyCase = TestKeyCase;
+
+ vtab->ClearMapLocked = ClearMapLocked;
+ vtab->SetMapLocked = SetMapLocked;
+ vtab->GetMapLocked = GetMapLocked;
+ vtab->TestMapLocked = TestMapLocked;
+
+/* Save the inherited pointers to methods that will be extended, and
+ replace them with pointers to the new member functions. */
+ object = (AstObjectVtab *) vtab;
+
+/* Store replacement pointers for methods which will be over-ridden by
+ new member functions implemented here. */
+ parent_getobjsize = object->GetObjSize;
+ object->GetObjSize = GetObjSize;
+
+ parent_clearattrib = object->ClearAttrib;
+ object->ClearAttrib = ClearAttrib;
+ parent_getattrib = object->GetAttrib;
+ object->GetAttrib = GetAttrib;
+ parent_setattrib = object->SetAttrib;
+ object->SetAttrib = SetAttrib;
+ parent_testattrib = object->TestAttrib;
+ object->TestAttrib = TestAttrib;
+
+#if defined(THREAD_SAFE)
+ parent_managelock = object->ManageLock;
+ object->ManageLock = ManageLock;
+#endif
+
+/* Declare the destructor, copy constructor and dump function. */
+ astSetDelete( vtab, Delete );
+ astSetCopy( vtab, Copy );
+ astSetDump( vtab, Dump, "KeyMap", "Map of key/value pairs" );
+
+/* If we have just initialised the vtab for the current class, indicate
+ that the vtab is now initialised, and store a pointer to the class
+ identifier in the base "object" level of the vtab. */
+ if( vtab == &class_vtab ) {
+ class_init = 1;
+ astSetVtabClassIdentifier( vtab, &(vtab->id) );
+ }
+}
+
+static void InitMapEntry( AstMapEntry *entry, int type, int nel, int *status ){
+/*
+* Name:
+* InitMapEntry
+
+* Purpose:
+* initialise a MapEntry structure to null values.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void InitMapEntry( AstMapEntry *entry, int type, int nel, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function initialises the contents of a MapEntry to null values.
+
+* Parameters:
+* this
+* Pointer to the MapEntry.
+* type
+* The type of the MapEntry.
+* nel
+* The number of elements in the entry: 0 = scalar, >0 = vector.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Check the global error status. */
+ if( !astOK ) return;
+
+/* Initialise all elements with in the MapEntry structure. */
+ entry->next = NULL;
+ entry->key = NULL;
+ entry->hash = 0;
+ entry->type = type;
+ entry->nel = nel;
+ entry->comment = NULL;
+ entry->defined = 0;
+ entry->snext = NULL;
+ entry->sprev = NULL;
+ entry->member = 0;
+ entry->keymember = 0;
+ entry->sortby = SORTBY_NONE;
+
+ if( type == AST__OBJECTTYPE ) {
+ if( nel == 0 ) {
+ ( (Entry0A *) entry )->next = NULL;
+ ( (Entry0A *) entry )->prev = NULL;
+ } else {
+ ( (Entry1A *) entry )->next = NULL;
+ ( (Entry1A *) entry )->prev = NULL;
+ }
+ }
+
+}
+
+static int KeyCmp( const char *key1, const char *key2 ) {
+/*
+* Name:
+* KeyCmp
+
+* Purpose:
+* Compares keys for equality.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int KeyCmp( const char *key1, const char *key2 )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function compares two strings. It is like strcmp except that it
+* ignores trailing spaces.
+
+* Parameters:
+* key1
+* Pointer to first string.
+* key2
+* Pointer to second string.
+
+* Returned Value:
+* One if the keys differ. Zero if they are identical (except for
+* trailing spaces).
+
+*/
+
+/* Local Variables: */
+ const char *k1; /* Pointer to next "key1" character */
+ const char *k2; /* Pointer to next "key2" character */
+ int result; /* Returned flag */
+
+/* Check the strings are deifned. */
+ if ( !key1 || !key2 ) return 0;
+
+/* Get pointers to the first characters to differ, or to the first null
+ character, which ever comes first. */
+ k1 = key1;
+ k2 = key2;
+ while( *k1 && ( *k1 == *k2 ) ) {
+ k1++;
+ k2++;
+ }
+
+/* If both characters are null, the strings are identical. If neither is null,
+ the string definitely differ. If one is null, we need to check if the
+ other one only has spaces to the end of the string. */
+ if( *k1 ) {
+ if( *k2 ) {
+ result = ( *k1 > *k2 ) ? 1 : -1;
+ } else {
+ while( *k1 == ' ' ) k1++;
+ result = ( *k1 == 0 ) ? 0 : 1;
+ }
+ } else {
+ if( *k2 ) {
+ while( *k2 == ' ' ) k2++;
+ result = ( *k2 == 0 ) ? 0 : -1;
+ } else {
+ result = 0;
+ }
+ }
+
+/* Return the result. */
+ return result;
+}
+
+#if defined(THREAD_SAFE)
+static int ManageLock( AstObject *this_object, int mode, int extra,
+ AstObject **fail, int *status ) {
+/*
+* Name:
+* ManageLock
+
+* Purpose:
+* Manage the thread lock on an Object.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "object.h"
+* AstObject *ManageLock( AstObject *this, int mode, int extra,
+* AstObject **fail, int *status )
+
+* Class Membership:
+* KeyMap member function (over-rides the astManageLock protected
+* method inherited from the parent class).
+
+* Description:
+* This function manages the thread lock on the supplied Object. The
+* lock can be locked, unlocked or checked by this function as
+* deteremined by parameter "mode". See astLock for details of the way
+* these locks are used.
+
+* Parameters:
+* this
+* Pointer to the Object.
+* mode
+* An integer flag indicating what the function should do:
+*
+* AST__LOCK: Lock the Object for exclusive use by the calling
+* thread. The "extra" value indicates what should be done if the
+* Object is already locked (wait or report an error - see astLock).
+*
+* AST__UNLOCK: Unlock the Object for use by other threads.
+*
+* AST__CHECKLOCK: Check that the object is locked for use by the
+* calling thread (report an error if not).
+* extra
+* Extra mode-specific information.
+* fail
+* If a non-zero function value is returned, a pointer to the
+* Object that caused the failure is returned at "*fail". This may
+* be "this" or it may be an Object contained within "this". Note,
+* the Object's reference count is not incremented, and so the
+* returned pointer should not be annulled. A NULL pointer is
+* returned if this function returns a value of zero.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* A local status value:
+* 0 - Success
+* 1 - Could not lock or unlock the object because it was already
+* locked by another thread.
+* 2 - Failed to lock a POSIX mutex
+* 3 - Failed to unlock a POSIX mutex
+* 4 - Bad "mode" value supplied.
+
+* Notes:
+* - This function attempts to execute even if an error has already
+* occurred.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to KeyMap structure */
+ AstMapEntry *next; /* Pointer the next MapEntry */
+ AstObject **alist; /* Pointer to list of AST object pointers */
+ AstObject *obj; /* Pointer to AST object */
+ int i; /* Loop count */
+ int nel; /* No. of values in entry vector (0 => scalar) */
+ int result; /* Returned status value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the supplied pointer is not NULL. */
+ if( !this_object ) return result;
+
+/* Obtain a pointers to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Invoke the ManageLock method inherited from the parent class. */
+ if( !result ) result = (*parent_managelock)( this_object, mode, extra,
+ fail, status );
+
+/* Invoke the astManageLock method on any Objects contained within
+ the supplied Object. */
+
+ next = this->firstA;
+ while( next ) {
+ nel = next->nel;
+ if( nel == 0 ) {
+ obj = ( (Entry0A *) next )->value;
+ if( !result ) result = astManageLock( obj, mode, extra, fail );
+ next = ( (Entry0A *) next)->next;
+ } else {
+ alist = ( (Entry1A *) next )->value;
+ if( alist ) {
+ for( i = 0; i < nel; i++ ) {
+ if( !result ) result = astManageLock( alist[ i ], mode,
+ extra, fail );
+ }
+ }
+ next = ( (Entry1A *) next)->next;
+ }
+ }
+
+ return result;
+
+}
+#endif
+
+static void MapCopy( AstKeyMap *this, AstKeyMap *that, int *status ) {
+/*
+*++
+* Name:
+c astMapCopy
+f AST_MAPCOPY
+
+* Purpose:
+* Copy entries from one KeyMap into another.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c void astMapCopy( AstKeyMap *this, AstKeyMap *that )
+f CALL AST_MAPCOPY( THIS, THAT, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This function
+f This routine
+* copies all entries from one KeyMap into another.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the destination KeyMap.
+c that
+f THAT = INTEGER (Given)
+* Pointer to the source KeyMap.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - Entries from the source KeyMap will replace any existing entries in
+* the destination KeyMap that have the same key.
+* - The one exception to the above rule is that if a source entry
+* contains a scalar KeyMap entry, and the destination contains a
+* scalar KeyMap entry with the same key, then the source KeyMap entry
+* will be copied into the destination KeyMap entry using this function,
+* rather than simply replacing the destination KeyMap entry.
+* - If the destination entry has a non-zero value for its MapLocked
+* attribute, then an error will be reported if the source KeyMap
+* contains any keys that do not already exist within the destination
+* KeyMap.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *in_entry; /* Pointer to next source entry to copy */
+ AstMapEntry *out_entry;/* Pointer to existing destination entry */
+ AstObject *in_obj; /* Pointer for source Object entry */
+ AstObject *out_obj; /* Pointer for destination Object entry */
+ const char *key; /* Key for current entry */
+ int i; /* Index into source hash table */
+ int itab; /* Index of destination hash table element */
+ int keymember; /* Identifier for key */
+ int merged; /* Were source and destination KeyMaps merged? */
+ unsigned long hash; /* Full width hash value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Loop round all entries in the source hash table. */
+ for( i = 0; i < that->mapsize; i++ ) {
+
+/* Get a pointer to the next source KeyMap entry. */
+ in_entry = that->table[ i ];
+
+/* Loop round all entries in this element of the source hash table. */
+ while( in_entry && astOK ) {
+
+/* Get its key. */
+ key = in_entry->key;
+
+/* Search for a destination entry with the same key. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+ out_entry = SearchTableEntry( this, itab, key, status );
+
+/* If the destination KeyMap does not contain an entry with the current
+ key, store a copy of the entry in the destination, or report an error
+ if the destination's MapLocked attribute is set. */
+ if( !out_entry ) {
+ if( astGetMapLocked( this ) ) {
+ astError( AST__BADKEY, "astMapCopy(%s): Failed to copy "
+ "item \"%s\": \"%s\" is not a known item.", status,
+ astGetClass( this ), key, key );
+ } else {
+ out_entry = CopyMapEntry( in_entry, status );
+ out_entry = AddTableEntry( this, itab, out_entry, -1, status );
+ }
+
+/* If the destination KeyMap contains an entry with the current key... */
+ } else {
+
+/* The usual thing is to just replace the existing entry in the
+ destination with a copy of the source entry. The one case where this is
+ not done is if both entries are scalar KeyMaps. In this case the source
+ KeyMap is merged into the destination KeyMap using this function. First
+ see if we have this situation, and if so, copy the entries from the
+ source KeyMap to the destination KeyMap. */
+ merged = 0;
+ if( in_entry->nel == 0 || in_entry->nel == 1 ) {
+ if( out_entry->nel == 0 || out_entry->nel == 1 ) {
+ if( in_entry->type == AST__OBJECTTYPE &&
+ out_entry->type == AST__OBJECTTYPE ) {
+
+ if( in_entry->nel == 0 ) {
+ in_obj = ((Entry0A *)in_entry)->value;
+ } else {
+ in_obj = (((Entry1A *)in_entry)->value)[ 0 ];
+ }
+
+ if( out_entry->nel == 0 ) {
+ out_obj = ((Entry0A *)out_entry)->value;
+ } else {
+ out_obj = (((Entry1A *)out_entry)->value)[ 0 ];
+ }
+
+ if( astIsAKeyMap( in_obj ) &&
+ astIsAKeyMap( out_obj ) ) {
+ astMapCopy( (AstKeyMap *) out_obj,
+ (AstKeyMap *) in_obj );
+ merged = 1;
+ }
+ }
+ }
+ }
+
+/* If the source and desination entries are not KeyMaps, then just remove
+ the entry in the desination KeyMap and add a copy of the source entry.
+ But retain the original keymember value since we are just changing the
+ value of an existing key. */
+ if( ! merged ) {
+ out_entry = RemoveTableEntry( this, itab, key, status );
+ keymember = out_entry->keymember;
+ (void) FreeMapEntry( out_entry, status );
+ out_entry = CopyMapEntry( in_entry, status );
+ out_entry = AddTableEntry( this, itab, out_entry, keymember, status );
+ }
+ }
+
+/* Update the address of the next MapEntry in the source. */
+ in_entry = in_entry->next;
+ }
+ }
+}
+
+static const char *MapKey( AstKeyMap *this, int index, int *status ) {
+/*
+*++
+* Name:
+c astMapKey
+f AST_MAPKEY
+
+* Purpose:
+* Get the key at a given index within the KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c const char *astMapKey( AstKeyMap *this, int index )
+f RESULT = AST_MAPKEY( THIS, INDEX, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns a string holding the key for the entry with
+* the given index within the KeyMap.
+*
+* This function is intended primarily as a means of iterating round all
+* the elements in a KeyMap. For this purpose, the number of entries in
+* the KeyMap should first be found using
+c astMapSize
+f AST_MAPSIZE
+* and this function should then be called in a loop, with the index
+* value going from
+c zero to one less than the size of the KeyMap.
+f one to the size of the KeyMap.
+* The index associated with a given entry is determined by the SortBy
+* attribute.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c index
+f INDEX = INTEGER (Given)
+* The index into the KeyMap. The first entry has index
+c zero, and the last has index "size-1", where "size" is the value
+c returned by the astMapSize function.
+f one, and the last has index SIZE, the value returned by the
+f AST_MAPSIZE function.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapKey()
+c A pointer to a null-terminated string containing the key.
+f AST_MAPKEY = CHARACTER * ( AST__SZCHR )
+f The key value.
+
+* Notes:
+c - The returned pointer is guaranteed to remain valid and the
+c string to which it points will not be over-written for a total
+c of 50 successive invocations of this function. After this, the
+c memory containing the string may be re-used, so a copy of the
+c string should be made if it is needed for longer than this.
+c - A NULL pointer will be returned if this function is invoked
+c with the AST error status set, or if it should fail for any
+c reason.
+f - A blank string will be returned if this function is invoked
+f with STATUS set to an error value, or if it should fail for any
+f reason.
+*--
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ const char *result; /* Pointer value to return */
+ const char *value; /* Pointer to key value */
+ int i; /* Loop counter for initialisation */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* If the "mapkey_strings" array has not been initialised, fill it with
+ NULL pointers. */
+ if ( !mapkey_init ) {
+ mapkey_init = 1;
+ for ( i = 0; i < AST__KEYMAP_MAPKEY_MAX_STRINGS; i++ ) mapkey_strings[ i ] = NULL;
+ }
+
+/* Obtain a pointer to the required key value. */
+ value = GetKey( this, index, status );
+
+/* If OK, store a copy of the resulting string in dynamically
+ allocated memory, putting a pointer to the copy into the next
+ element of the "mapkey_strings" array. (This process also de-allocates
+ any previously allocated memory pointed at by this "mapkey_strings"
+ element, so the earlier string is effectively replaced by the new
+ one.) */
+ if ( astOK ) {
+ astBeginPM;
+ mapkey_strings[ mapkey_istr ] = astStore( mapkey_strings[ mapkey_istr ], value,
+ strlen( value ) + (size_t) 1 );
+ astEndPM;
+
+/* If OK, return a pointer to the copy and increment "mapkey_istr" to use the
+ next element of "mapkey_strings" on the next invocation. Recycle "mapkey_istr" to
+ zero when all elements have been used. */
+ if ( astOK ) {
+ result = mapkey_strings[ mapkey_istr++ ];
+ if ( mapkey_istr == ( AST__KEYMAP_MAPKEY_MAX_STRINGS - 1 ) ) mapkey_istr = 0;
+ }
+ }
+
+/* Return the result. */
+ return result;
+
+}
+
+/*
+*++
+* Name:
+c astMapPut0<X>
+f AST_MAPPUT0<X>
+
+* Purpose:
+* Add a scalar value to a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c void astMapPut0<X>( AstKeyMap *this, const char *key, <X>type value,
+c const char *comment );
+f CALL AST_MAPPUT0<X>( THIS, KEY, VALUE, COMMENT, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This is a set of functions
+f This is a set of routine
+* for adding scalar values to a KeyMap. You should use a
+c function
+f routine
+* which matches the data type of the data you wish to add to the KeyMap
+* by replacing <X> in the generic
+c function name astMapPut0<X>
+f routine name AST_MAPPUT0<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap in which to store the supplied value.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* A character string to be stored with the value, which can later
+* be used to identify the value. Trailing spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c value
+f VALUE = <X>type (Given)
+* The value to be stored. The data type of this value should match the
+* 1-character type code appended to the
+c function name (e.g. if you are using astMapPut0A, the type of this
+c value should be "pointer to AstObject").
+f routine name (e.g. if you are using AST_MAPPUT0A, the type of this
+f value should be "integer pointer for an AstObject").
+c comment
+f COMMENT = CHARACTER * ( * ) (Given)
+f A comment string to be stored with the value.
+c A pointer to a null-terminated comment string to be stored with the
+c value. A NULL pointer may be supplied, in which case no comment is
+c stored.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - If the supplied key is already in use in the KeyMap, the new value
+* will replace the old value.
+* - If the stored value is an AST Object pointer, the Object's reference
+* count is incremented by this call. Any subsequent changes made to
+* the Object using the returned pointer will be reflected in any
+* any other active pointers for the Object, including any obtained
+* later using
+c astMapget0A.
+f AST_MAPGET0A.
+* The reference count for the Object will be decremented when the
+* KeyMap is destroyed, or the entry is removed or over-written with a
+* different pointer.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name astMapPut0<X>
+f routine, you should replace <X> in the generic routine name AST_MAPPUT0<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - D: double
+c - F: float
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: unsigned byte (i.e. unsigned char)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: Unsigned byte
+*
+c For example, astMapPut0D would be used to store a "double" value,
+c while astMapPut0I would be used to store an "int", etc.
+f For example, AST_MAPPUT0D would be used to store a DOUBLE PRECISION value,
+f while AST_MAPPUT0I would be used to store an INTEGER, etc.
+c
+c Note that KeyMaps containing generic "void *" pointers cannot be
+c written out using astShow or astWrite. An error will be reported if
+c this is attempted.
+*--
+*/
+/* Define a macro to implement the function for a specific data type. */
+#define MAKE_MAPPUT0(X,Xtype,Itype,ValExp) \
+static void MapPut0##X( AstKeyMap *this, const char *skey, Xtype value, \
+ const char *comment, int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ AstMapEntry *oldent; /* Pointer to existing MapEntry */ \
+ Entry0##X *entry; /* Structure holding the data for the new Entry */ \
+ const char *key; /* Pointer to key string to use */ \
+ char *p; /* Pointer to next key character */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ int itab; /* Index of hash table element to use */ \
+ int keylen; /* Length of supplied key string */ \
+ int keymember; /* Identifier for existing key */ \
+ int there; /* Did the entry already exist in the KeyMap? */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Perform any necessary checks on the supplied value to be stored. */ \
+ CHECK_##X \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapPut0" #X, \
+ status ); \
+\
+/* Allocate memory for the new MapEntry. */ \
+ entry = astMalloc( sizeof( Entry0##X ) ); \
+ if( astOK ) { \
+\
+/* Initialise the new structure.*/ \
+ mapentry = (AstMapEntry *) entry; \
+ InitMapEntry( mapentry, Itype, 0, status ); \
+\
+/* Now store the new values. */ \
+ keylen = strlen( key ); \
+ mapentry->key = astStore( NULL, key, keylen + 1 ); \
+ if( comment ) mapentry->comment = astStore( NULL, comment, strlen( comment ) + 1 ); \
+ mapentry->defined = 1; \
+ entry->value = ValExp; \
+\
+/* Terminate the key string to exclude any trailing spaces. */ \
+ if( astOK ) { \
+ p = (char *) mapentry->key + keylen; \
+ while( --p >= mapentry->key ) { \
+ if( *p == ' ' ) { \
+ *p = 0; \
+ } else { \
+ break; \
+ } \
+ } \
+ } \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which to store the new entry. */ \
+ itab = HashFun( mapentry->key, this->mapsize - 1, &(mapentry->hash), status ); \
+\
+/* Remove any existing entry with the given key from the table element. \
+ First save the key identifier. */ \
+ oldent = RemoveTableEntry( this, itab, mapentry->key, status ); \
+ if( oldent ) { \
+ keymember = oldent->keymember; \
+ oldent = FreeMapEntry( oldent, status ); \
+ there = 1; \
+ } else { \
+ keymember = -1; \
+ there = 0; \
+ } \
+\
+/* If the KeyMap is locked we report an error if an attempt is made to add a value for \
+ a new key. */ \
+ if( !there && astGetMapLocked( this ) ) { \
+ astError( AST__BADKEY, "astMapPut0" #X "(%s): Failed to add item \"%s\" to a KeyMap: " \
+ "\"%s\" is not a known item.", status, astGetClass( this ), key, key ); \
+ } \
+\
+/* If all has gone OK, store the new entry at the head of the linked list \
+ associated with the selected table entry. */ \
+ if( astOK ) { \
+ mapentry = AddTableEntry( this, itab, mapentry, keymember, status ); \
+\
+/* If anything went wrong, try to delete the new entry. */ \
+ } else { \
+ mapentry = FreeMapEntry( mapentry, status ); \
+ } \
+ } \
+}
+
+/* Define macros which perform any necessary checks on the supplied value
+ to be stored. For Object entries, check that we are not adding a KeyMap
+ which already contains "this". This avoids circular dependencies.
+ Other types do not need any checks. */
+#define CHECK_A CheckCircle( this, value, "astMapPut0A", status );
+#define CHECK_I
+#define CHECK_D
+#define CHECK_F
+#define CHECK_C
+#define CHECK_P
+#define CHECK_S
+#define CHECK_B
+
+/* Expand the above macro to generate a function for each required
+ data type. */
+MAKE_MAPPUT0(I,int,AST__INTTYPE,value)
+MAKE_MAPPUT0(D,double,AST__DOUBLETYPE,value)
+MAKE_MAPPUT0(F,float,AST__FLOATTYPE,value)
+MAKE_MAPPUT0(C,const char *,AST__STRINGTYPE,astStore(NULL,value,strlen(value)+1))
+MAKE_MAPPUT0(A,AstObject *,AST__OBJECTTYPE,(value?astClone(value):NULL))
+MAKE_MAPPUT0(P,void *,AST__POINTERTYPE,value)
+MAKE_MAPPUT0(S,short int,AST__SINTTYPE,value)
+MAKE_MAPPUT0(B,unsigned char,AST__BYTETYPE,value)
+
+/* Undefine the macro. */
+#undef MAKE_MAPPUT0
+#undef CHECK_A
+#undef CHECK_I
+#undef CHECK_S
+#undef CHECK_D
+#undef CHECK_F
+#undef CHECK_C
+#undef CHECK_P
+#undef CHECK_B
+
+/*
+*++
+* Name:
+c astMapPut1<X>
+f AST_MAPPUT1<X>
+
+* Purpose:
+* Add a vector value to a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c void astMapPut1<X>( AstKeyMap *this, const char *key, int size,
+c const <X>type value[], const char *comment );
+f CALL AST_MAPPUT1<X>( THIS, KEY, SIZE, VALUE, COMMENT, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This is a set of functions
+f This is a set of routine
+* for adding vector values to a KeyMap. You should use a
+c function
+f routine
+* which matches the data type of the data you wish to add to the KeyMap
+* by replacing <X> in the generic
+c function name astMapPut1<X>
+f routine name AST_MAPPUT1<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap in which to store the supplied values.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* A character string to be stored with the values, which can later
+* be used to identify the values. Trailing spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c size
+f SIZE = INTEGER (Given)
+* The number of elements in the supplied array of values.
+c value
+f VALUE( * ) = <X>type (Given)
+* The array of values to be stored. The data type of this value should
+* match the 1-character type code appended to the
+c function name (e.g. if you are using astMapPut1A, the type of this
+c value should be "array of pointers to AstObject").
+f routine name (e.g. if you are using AST_MAPPUT1A, the type of this
+f value should be "integer pointer for an AstObject)".
+c comment
+f COMMENT = CHARACTER * ( * ) (Given)
+f A comment string to be stored with the values.
+c A pointer to a null-terminated comment string to be stored with the
+c values. A NULL pointer may be supplied, in which case no comment is
+c stored.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - If the supplied key is already in use in the KeyMap, the new values
+* will replace the old values.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name astMapPut1<X>
+f routine, you should replace <X> in the generic routine name AST_MAPPUT1<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - D: double
+c - F: float
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: Unsigned byte (i.e. char)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: Unsigned byte
+*
+c For example, astMapPut1D would be used to store "double" values,
+c while astMapPut1I would be used to store "int", etc.
+f For example, AST_MAPPUT1D would be used to store DOUBLE PRECISION values,
+f while AST_MAPPUT1I would be used to store INTEGER, etc.
+c
+c Note that KeyMaps containing generic "void *" pointers cannot be
+c written out using astShow or astWrite. An error will be reported if
+c this is attempted.
+*--
+*/
+/* Define a macro to implement the function for a specific data type. */
+#define MAKE_MAPPUT1(X,Xtype,Itype,ValExp) \
+static void MapPut1##X( AstKeyMap *this, const char *skey, int size, \
+ Xtype value[], const char *comment, \
+ int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ AstMapEntry *oldent; /* Pointer to existing MapEntry */ \
+ Entry1##X *entry; /* Structure holding the data for the new Entry */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ const char *key; /* Pointer to key string to use */ \
+ char *p; /* Pointer to next key character */ \
+ int itab; /* Index of hash table element to use */ \
+ int i; /* Loop count */ \
+ int keylen; /* Length of supplied key string */ \
+ int keymember; /* Identifier for existing key */ \
+ int there; /* Did the entry already exist in the KeyMap? */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Perform any necessary checks on the supplied value to be stored. */ \
+ CHECK_##X \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapPut1" #X, \
+ status ); \
+\
+/* Allocate memory for the new MapEntry. */ \
+ entry = astMalloc( sizeof( Entry1##X ) ); \
+ if( astOK ) { \
+\
+/* Initialise the new structure.*/ \
+ mapentry = (AstMapEntry *) entry; \
+ InitMapEntry( mapentry, Itype, size, status ); \
+\
+/* Now store the new values. */ \
+ keylen = strlen( key ); \
+ mapentry->key = astStore( NULL, key, keylen + 1 ); \
+ if( comment ) mapentry->comment = astStore( NULL, comment, strlen( comment ) + 1 ); \
+ mapentry->defined = 1; \
+ entry->value = astMalloc( sizeof( Xtype )*(size_t)size ); \
+\
+ if( astOK ) { \
+ for( i = 0; i < size; i++ ) { \
+ entry->value[ i ] = ValExp; \
+ } \
+\
+/* Terminate the key string to exclude any trailing spaces. */ \
+ p = (char *) mapentry->key + keylen; \
+ while( --p >= mapentry->key ) { \
+ if( *p == ' ' ) { \
+ *p = 0; \
+ } else { \
+ break; \
+ } \
+ } \
+ } \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which to store the new entry. */ \
+ itab = HashFun( mapentry->key, this->mapsize - 1, &(mapentry->hash), status ); \
+\
+/* Remove any existing entry with the given key from the table element. \
+ First save the key identifier. */ \
+ oldent = RemoveTableEntry( this, itab, mapentry->key, status ); \
+ if( oldent ) { \
+ keymember = oldent->keymember; \
+ oldent = FreeMapEntry( oldent, status ); \
+ there = 1; \
+ } else { \
+ keymember = -1; \
+ there = 0; \
+ } \
+\
+/* If the KeyMap is locked we report an error if an attempt is made to add a value for \
+ a new key. */ \
+ if( !there && astGetMapLocked( this ) ) { \
+ astError( AST__BADKEY, "astMapPut1" #X "(%s): Failed to add item \"%s\" to a KeyMap: " \
+ "\"%s\" is not a known item.", status, astGetClass( this ), key, key ); \
+ } \
+\
+/* If all has gone OK, store the new entry at the head of the linked list \
+ associated with the selected table entry. */ \
+ if( astOK ) { \
+ mapentry = AddTableEntry( this, itab, mapentry, keymember, status ); \
+\
+/* If anything went wrong, try to delete the new entry. */ \
+ } else { \
+ mapentry = FreeMapEntry( mapentry, status ); \
+ } \
+ } \
+}
+
+/* Define macros which perform any necessary checks on the supplied values
+ to be stored. For Object entries, check that we are not adding a KeyMap
+ which already contains "this". This avoids circular dependencies.
+ Other types do not need any checks. */
+#define CHECK_A \
+for( i = 0; i < size; i++ ) { \
+ CheckCircle( this, value[ i ], "astMapPut1A", status ); \
+}
+#define CHECK_I
+#define CHECK_S
+#define CHECK_B
+#define CHECK_D
+#define CHECK_F
+#define CHECK_C
+#define CHECK_P
+
+/* Expand the above macro to generate a function for each required
+ data type. */
+MAKE_MAPPUT1(D,const double,AST__DOUBLETYPE,value[i])
+MAKE_MAPPUT1(F,const float,AST__FLOATTYPE,value[i])
+MAKE_MAPPUT1(I,const int,AST__INTTYPE,value[i])
+MAKE_MAPPUT1(C,const char *const,AST__STRINGTYPE,astStore(NULL,value[i],strlen(value[i])+1))
+MAKE_MAPPUT1(A,AstObject *const,AST__OBJECTTYPE,(value[i]?astClone(value[i]):NULL))
+MAKE_MAPPUT1(P,void *const,AST__POINTERTYPE,value[i])
+MAKE_MAPPUT1(S,const short int,AST__SINTTYPE,value[i])
+MAKE_MAPPUT1(B,const unsigned char,AST__BYTETYPE,value[i])
+
+/* Undefine the macro. */
+#undef MAKE_MAPPUT1
+#undef CHECK_A
+#undef CHECK_I
+#undef CHECK_B
+#undef CHECK_S
+#undef CHECK_D
+#undef CHECK_F
+#undef CHECK_C
+#undef CHECK_P
+
+void astMapPut1AId_( AstKeyMap *this, const char *skey, int size,
+ AstObject *const value[], const char *comment,
+ int *status ) {
+/*
+* Name:
+* astMapPut1AId_
+
+* Purpose:
+* Add a vector of AstObject pointers to a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "ast.h"
+* void astMapPut1A( AstKeyMap *this, const char *key, int size,
+* AstObject *const value[], const char *comment )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the public implementation of the astMapPut1A function
+* It is identical to astMapPut1A_ except that ID values are supplied
+* via the "value" parameter instead of a true C pointers.
+
+* Parameters:
+* (see astMapPut1<X>)
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ AstMapEntry *oldent; /* Pointer to existing MapEntry */
+ AstObject *op; /* Object pointer */
+ Entry1A *entry; /* Structure holding the data for the new Entry */
+ char *p; /* Pointer to next key character */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ const char *key; /* Pointer to key string to use */ \
+ int i; /* Loop count */
+ int itab; /* Index of hash table element to use */
+ int keylen; /* Length of supplied key string */
+ int keymember; /* Identifier for existing key */
+ int there; /* Did the entry already exist in the KeyMap? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapPut1A",
+ status );
+
+/* Allocate memory for the new MapEntry. */
+ entry = astMalloc( sizeof( Entry1A ) );
+ if( astOK ) {
+
+/* Initialise the new structure.*/
+ mapentry = (AstMapEntry *) entry;
+ InitMapEntry( mapentry, AST__OBJECTTYPE, size, status );
+
+/* Now store the new values. */
+ keylen = strlen( key );
+ mapentry->key = astStore( NULL, key, keylen + 1 );
+ if( comment ) mapentry->comment = astStore( NULL, comment, strlen( comment ) + 1 );
+ mapentry->defined = 1;
+ entry->value = astMalloc( sizeof( AstObject * )*(size_t)size );
+
+ if( astOK ) {
+ for( i = 0; i < size; i++ ) {
+ op = value[ i ] ? astMakePointer( value[ i ] ) : NULL;
+ entry->value[ i ] = op ? astClone( op ) : NULL;
+ }
+
+/* Terminate the key string to exclude any trailing spaces. */ \
+ p = (char *) mapentry->key + keylen;
+ while( --p >= mapentry->key ) {
+ if( *p == ' ' ) {
+ *p = 0;
+ } else {
+ break;
+ }
+ }
+ }
+
+/* Use the hash function to determine the element of the hash table in
+ which to store the new entry. */
+ itab = HashFun( mapentry->key, this->mapsize - 1, &(mapentry->hash), status );
+
+/* Remove any existing entry with the given key from the table element. */
+ oldent = RemoveTableEntry( this, itab, mapentry->key, status );
+ if( oldent ) {
+ keymember = oldent->keymember;
+ oldent = FreeMapEntry( oldent, status );
+ there = 1;
+ } else {
+ there = 0;
+ keymember = -1;
+ }
+
+/* If the KeyMap is locked we report an error if an attempt is made to add a value for
+ a new key. */
+ if( !there && astGetMapLocked( this ) ) {
+ astError( AST__BADKEY, "astMapPut1A(%s): Failed to add item \"%s\" to a KeyMap: "
+ "\"%s\" is not a known item.", status, astGetClass( this ), key, key );
+ }
+
+/* If all has gone OK, store the new entry at the head of the linked list
+ associated with the selected table entry. */
+ if( astOK ) {
+ mapentry = AddTableEntry( this, itab, mapentry, keymember, status );
+
+/* If anything went wrong, try to delete the new entry. */
+ } else {
+ mapentry = FreeMapEntry( mapentry, status );
+ }
+ }
+}
+
+static void MapPutU( AstKeyMap *this, const char *skey, const char *comment,
+ int *status ) {
+/*
+*++
+* Name:
+c astMapPutU
+f AST_MAPPUTU
+
+* Purpose:
+* Add an entry to a KeyMap with an undefined value.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c void astMapPutU( AstKeyMap *this, const char *key, const char *comment );
+f CALL AST_MAPPUTU( THIS, KEY, COMMENT, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This function
+f This routine
+* adds a new entry to a KeyMap, but no value is stored with the
+* entry. The entry therefore has a special data type represented by
+* symbolic constant AST__UNDEFTYPE.
+*
+* An example use is to add entries with undefined values to a KeyMap
+* prior to locking them with the MapLocked attribute. Such entries
+* can act as placeholders for values that can be added to the KeyMap
+* later.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap in which to store the supplied value.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* A character string to be stored with the value, which can later
+* be used to identify the value. Trailing spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c comment
+f COMMENT = CHARACTER * ( * ) (Given)
+f A comment string to be stored with the value.
+c A pointer to a null-terminated comment string to be stored with the
+c value. A NULL pointer may be supplied, in which case no comment is
+c stored.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Notes:
+* - If the supplied key is already in use in the KeyMap, the value
+* associated with the key will be removed.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ AstMapEntry *oldent; /* Pointer to existing MapEntry */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ const char *key; /* Pointer to key string to use */
+ char *p; /* Pointer to next key character */
+ int itab; /* Index of hash table element to use */
+ int keylen; /* Length of supplied key string */
+ int keymember; /* Identifier for existing key */
+ int there; /* Did the entry already exist in the KeyMap? */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapPutU",
+ status );
+
+/* Allocate memory for the new MapEntry. */
+ mapentry = astMalloc( sizeof( AstMapEntry ) );
+ if( astOK ) {
+
+/* Initialise the new structure.*/
+ InitMapEntry( mapentry, AST__UNDEFTYPE, 0, status );
+
+/* Now store the new values. */
+ keylen = strlen( key );
+ mapentry->key = astStore( NULL, key, keylen + 1 );
+ if( comment ) mapentry->comment = astStore( NULL, comment, strlen( comment ) + 1 );
+ mapentry->defined = 0;
+
+/* Terminate the key string to exclude any trailing spaces. */
+ if( astOK ) {
+ p = (char *) mapentry->key + keylen;
+ while( --p >= mapentry->key ) {
+ if( *p == ' ' ) {
+ *p = 0;
+ } else {
+ break;
+ }
+ }
+ }
+
+/* Use the hash function to determine the element of the hash table in
+ which to store the new entry. */
+ itab = HashFun( mapentry->key, this->mapsize - 1, &(mapentry->hash), status );
+
+/* Remove any existing entry with the given key from the table element. */
+ oldent = RemoveTableEntry( this, itab, mapentry->key, status );
+ if( oldent ) {
+ keymember = oldent->keymember;
+ oldent = FreeMapEntry( oldent, status );
+ there = 1;
+ } else {
+ keymember = -1;
+ there = 0;
+ }
+
+/* If the KeyMap is locked we report an error if an attempt is made to add a value for
+ a new key. */
+ if( !there && astGetMapLocked( this ) ) {
+ astError( AST__BADKEY, "astMapPutU(%s): Failed to add item \"%s\" to a KeyMap: "
+ "\"%s\" is not a known item.", status, astGetClass( this ), key, key );
+ }
+
+/* If all has gone OK, store the new entry at the head of the linked list
+ associated with the selected table entry. */
+ if( astOK ) {
+ mapentry = AddTableEntry( this, itab, mapentry, keymember, status );
+
+/* If anything went wrong, try to delete the new entry. */
+ } else {
+ mapentry = FreeMapEntry( mapentry, status );
+ }
+ }
+}
+
+/*
+*++
+* Name:
+c astMapGet0<X>
+f AST_MAPGET0<X>
+
+* Purpose:
+* Get a scalar value from a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c int astMapGet0<X>( AstKeyMap *this, const char *key, <X>type *value );
+f RESULT = AST_MAPGET0<X>( THIS, KEY, VALUE, STATUS )
+f RESULT = AST_MAPGET0C( THIS, KEY, VALUE, L, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is a set of functions for retrieving a scalar value from a KeyMap.
+* You should replace <X> in the generic function name
+c astMapGet0<X>
+f AST_MAPGET0<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+* The stored value is converted to the data type indiced by <X>
+* before being returned (an error is reported if it is not possible to
+* convert the stored value to the requested data type).
+f Note, the version of this function which returns character strings,
+f AST_MAPGET0C, has an extra parameter in which is returned the number
+f of characters written into the supplied CHARACTER variable.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored. The supplied string is converted to upper
+* case before use if the KeyCase attribute is currently set to zero.
+c value
+f VALUE = <X>type (Returned)
+c A pointer to a buffer in which to return the requested value.
+f The requested value.
+* If the requested key is not found, or if it is found but has an
+* undefined value (see
+c astMapPutU),
+f AST_MAPPUTU),
+* then the contents of the
+* buffer on entry to this function will be unchanged on exit.
+c For pointer types ("A" and "C"), the buffer should be a suitable
+c pointer, and the address of this pointer should be supplied as the
+c "value" parameter.
+f L = INTEGER (Returned)
+f This parameter is only present in the interface for the AST_MAPGET0C
+f function. It is returned holding the number of characters
+f written into the CHARACTER variable supplied for parameter VALUE.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapGet0<X>()
+f AST_MAPGET0<X> = LOGICAL
+c A non-zero value
+f .TRUE.
+* is returned if the requested key name was found, and does not have
+* an undefined value (see
+c astMapPutU). Zero
+f AST_MAPPUTU). .FALSE.
+* is returned otherwise.
+
+* Notes:
+* - No error is reported if the requested key cannot be found in the
+* given KeyMap, but a
+c zero
+f .FALSE.
+* value will be returned as the function value. The supplied buffer
+* will be returned unchanged.
+* - If the stored value is a vector value, then the first value in
+* the vector will be returned.
+c - A string pointer returned by astMapGet0C is guaranteed to remain valid
+c and the string to which it points will not be over-written for a
+c total of 50 successive invocations of this function. After this,
+c the memory containing the string may be re-used, so a copy of
+c the string should be made if it is needed for longer than this. The
+c calling code should never attempt to free the returned pointer
+c (for instance, using astFree).
+* - If the returned value is an AST Object pointer, the Object's reference
+* count is incremented by this call. Any subsequent changes made to
+* the Object using the returned pointer will be reflected in any
+* any other active pointers for the Object. The returned pointer
+* should be annulled using
+c astAnnul
+f AST_ANNUL
+* when it is no longer needed.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name astMapGet0<X>
+f routine, you should replace <X> in the generic routine name AST_MAPGET0<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - F: float
+c - D: double
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: Unsigned byte (i.e. word)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: Unsigned byte
+*
+c For example, astMapGet0D would be used to get a "double" value,
+c while astMapGet0I would be used to get an "int", etc.
+f For example, AST_MAPGET0D would be used to get a DOUBLE PRECISION value,
+f while AST_MAPGET0I would be used to get an INTEGER, etc.
+*--
+*/
+/* Define a macro to implement the function for a specific data type. */
+#define MAKE_MAPGET0(X,Xtype,Itype) \
+static int MapGet0##X( AstKeyMap *this, const char *skey, Xtype *value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ const char *key; /* Pointer to key string to use */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ int itab; /* Index of hash table element to use */ \
+ int raw_type; /* Data type of stored value */ \
+ int result; /* Returned flag */ \
+ unsigned long hash; /* Full width hash value */ \
+ void *raw; /* Pointer to stored value */ \
+\
+/* Initialise */ \
+ result = 0; \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return result; \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGet0" #X, \
+ status ); \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which the key will be stored. */ \
+ itab = HashFun( key, this->mapsize - 1, &hash, status ); \
+\
+/* Search the relevent table entry for the required MapEntry. */ \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+\
+/* Skip rest if the key was not found. */ \
+ if( mapentry ) { \
+\
+/* Get the address of the raw value, and its data type. */ \
+ raw_type = mapentry->type; \
+ if( raw_type == AST__INTTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0I *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1I *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__SINTTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0S *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1S *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__BYTETYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0B *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1B *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__DOUBLETYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0D *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1D *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__FLOATTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0F *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1F *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__POINTERTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0P *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1P *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0C *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1C *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ if( mapentry->nel == 0 ) { \
+ raw = &( ((Entry0A *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1A *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__UNDEFTYPE ){ \
+ raw = NULL; \
+\
+ } else { \
+ raw = NULL; \
+ astError( AST__INTER, "astMapGet0<X>(KeyMap): Illegal map entry data " \
+ "type %d encountered (internal AST programming error).", status, \
+ raw_type ); \
+ } \
+\
+/* Convert the value, storing the result the supplied buffer. Report an \
+ error if conversion is not possible. */ \
+ if( !raw ) { \
+ result = 0; \
+\
+ } else if( !ConvertValue( raw, raw_type, value, Itype, status ) && astOK ){ \
+ astError( AST__MPGER, "astMapGet0" #X "(%s): The value of KeyMap key " \
+ "\"%s\" cannot be read using the requested data " \
+ "type.", status,astGetClass( this ), key ); \
+\
+ } else { \
+ result = 1; \
+ } \
+\
+/* If the KeyError attribute is non-zero, report an error if the key is not \
+ found */ \
+ } else if( astGetKeyError( this ) && astOK ) { \
+ astError( AST__MPKER, "astMapGet0" #X "(%s): No value was found for " \
+ "%s in the supplied KeyMap.", status, astGetClass( this ), \
+ key ); \
+ } \
+\
+/* If an error occurred, return zero. */ \
+ if( !astOK ) result = 0; \
+\
+/* Return the result.*/ \
+ return result; \
+}
+
+/* Expand the above macro to generate a function for each required
+ data type. */
+MAKE_MAPGET0(I,int,AST__INTTYPE)
+MAKE_MAPGET0(D,double,AST__DOUBLETYPE)
+MAKE_MAPGET0(F,float,AST__FLOATTYPE)
+MAKE_MAPGET0(C,const char *,AST__STRINGTYPE)
+MAKE_MAPGET0(A,AstObject *,AST__OBJECTTYPE)
+MAKE_MAPGET0(P,void *,AST__POINTERTYPE)
+MAKE_MAPGET0(S,short int,AST__SINTTYPE)
+MAKE_MAPGET0(B,unsigned char,AST__BYTETYPE)
+
+/* Undefine the macro. */
+#undef MAKE_MAPGET0
+
+int astMapGet0AId_( AstKeyMap *this, const char *skey, AstObject **value, int *status ) {
+/*
+* Name:
+* astMapGet0AId_
+
+* Purpose:
+* Get a scalar AstObject pointer from a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "ast.h"
+* int astMapGet0A( AstKeyMap *this, const char *key, AstObject **value )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the public implementation of the astMapGet0A function
+* It is identical to astMapGet0A_ except that an ID value is returned
+* via the "value" parameter instead of a true C pointer. This is required
+* because this conversion cannot be performed by the macro that invokes
+* the function.
+
+* Parameters:
+* (see astMapGet0<X>)
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ const char *key; /* Pointer to key string to use */ \
+ int itab; /* Index of hash table element to use */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned flag */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGet0A",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+
+/* Get the address of the raw value, and its data type. */
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ if( mapentry->nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw = NULL;
+
+ } else {
+ raw = NULL;
+ astError( AST__INTER, "astMapGet0<X>(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* Convert the value, storing the result the supplied buffer. Report an
+ error if conversion is not possible. */
+ if( !raw ) {
+ result = 0;
+
+ } else if( !ConvertValue( raw, raw_type, value, AST__OBJECTTYPE, status ) && astOK ){
+ astError( AST__MPGER, "astMapGet0A(%s): The value of KeyMap key "
+ "\"%s\" cannot be read using the requested data "
+ "type.", status, astGetClass( this ), key );
+
+ } else {
+ result = 1;
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapGet0A(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If required, return an ID value for the Object. */
+ if( result && *value ) *value = astMakeId( *value );
+
+/* Return the result.*/
+ return result;
+}
+
+/*
+*++
+* Name:
+c astMapGet1<X>
+f AST_MAPGET1<X>
+
+* Purpose:
+* Get a vector value from a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c int astMapGet1<X>( AstKeyMap *this, const char *key, int mxval,
+c int *nval, <X>type *value )
+c int astMapGet1C( AstKeyMap *this, const char *key, int l, int mxval,
+c int *nval, const char *value )
+f RESULT = AST_MAPGET1<X>( THIS, KEY, MXVAL, NVAL, VALUE, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is a set of functions for retrieving a vector value from a KeyMap.
+* You should replace <X> in the generic function name
+c astMapGet1<X>
+f AST_MAPGET1<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+* The stored value is converted to the data type indiced by <X>
+* before being returned (an error is reported if it is not possible to
+* convert the stored value to the requested data type).
+c Note, the astMapGet1C function has an extra parameter "l" which
+c specifies the maximum length of each string to be stored in the
+c "value" buffer (see the "astMapGet1C" section below).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c mxval
+f MXVAL = INTEGER (Given)
+* The number of elements in the
+c "value" array.
+f VALUE array.
+c nval
+f NVAL = INTEGER (Returned)
+c The address of an integer in which to put the
+f The
+* number of elements stored in the
+c "value" array.
+* Any unused elements of the array are left unchanged.
+c value
+f VALUE( MXVAL ) = <X>type (Returned)
+c A pointer to an array in which to return the requested values.
+f The requested values.
+* If the requested key is not found, or if it is found but has an
+* undefined value (see
+c astMapPutU),
+f AST_MAPPUTU),
+* then the contents of the
+* buffer on entry to this function will be unchanged on exit.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapGet1<X>()
+f AST_MAPGET1<X> = LOGICAL
+c A non-zero value
+f .TRUE.
+* is returned if the requested key name was found, and does not have
+* an undefined value (see
+c astMapPutU). Zero
+f AST_MAPPUTU). .FALSE.
+* is returned otherwise.
+
+* Notes:
+* - No error is reported if the requested key cannot be found in the
+* given KeyMap, but a
+c zero
+f .FALSE.
+* value will be returned as the function value. The supplied array
+* will be returned unchanged.
+* - If the stored value is a scalar value, then the value will be
+* returned in the first element of the supplied array, and
+c "nval"
+f NVAL
+* will be returned set to 1.
+
+c astMapGet1C:
+c The "value" buffer supplied to the astMapGet1C function should be a
+c pointer to a character array with "mxval*l" elements, where "l" is
+c the maximum length of a string to be returned. The value of "l"
+c should be supplied as an extra parameter following "key" when
+c invoking astMapGet1C, and should include space for a terminating
+c null character.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name astMapGet1<X>
+f routine, you should replace <X> in the generic routine name AST_MAPGET1<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - D: double
+c - F: float
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: Unsigned byte (i.e. char)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: Unsigned byte
+*
+c For example, astMapGet1D would be used to get "double" values, while
+c astMapGet1I would be used to get "int" values, etc. For D or I, the
+c supplied "value" parameter should be a pointer to an array of doubles
+c or ints, with "mxval" elements. For C, the supplied "value" parameter
+c should be a pointer to a character string with "mxval*l" elements.
+c For A, the supplied "value" parameter should be a pointer to an
+c array of AstObject pointers.
+f For example, AST_MAPGET1D would be used to get DOUBLE PRECISION values,
+f while AST_MAPGET1I would be used to get INTEGER values, etc.
+
+*--
+*/
+/* Define a macro to implement the function for a specific data type
+(excluding "C" since that needs an extra parameter). */
+#define MAKE_MAPGET1(X,Xtype,Itype) \
+static int MapGet1##X( AstKeyMap *this, const char *skey, int mxval, int *nval, Xtype *value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ const char *key; /* Pointer to key string to use */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ int i; /* Element index */ \
+ int itab; /* Index of hash table element to use */ \
+ int nel; /* Number of elements in raw vector */ \
+ int raw_type; /* Data type of stored value */ \
+ int result; /* Returned flag */ \
+ size_t raw_size; /* Size of a single raw value */ \
+ unsigned long hash; /* Full width hash value */ \
+ void *raw; /* Pointer to stored value */ \
+\
+/* Initialise */ \
+ result = 0; \
+ *nval = 0; \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return result; \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGet1" #X, \
+ status ); \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which the key will be stored. */ \
+ itab = HashFun( key, this->mapsize - 1, &hash, status ); \
+\
+/* Search the relevent table entry for the required MapEntry. */ \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+\
+/* Skip rest if the key was not found. */ \
+ if( mapentry ) { \
+ result = 1; \
+\
+/* Get the address of the first raw value, and its data type. Also get \
+ the size of each element of the vector. */ \
+ nel = mapentry->nel; \
+ raw_type = mapentry->type; \
+ if( raw_type == AST__INTTYPE ){ \
+ raw_size = sizeof( int ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0I *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1I *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__DOUBLETYPE ){ \
+ raw_size = sizeof( double ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0D *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1D *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__SINTTYPE ){ \
+ raw_size = sizeof( short int ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0S *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1S *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__BYTETYPE ){ \
+ raw_size = sizeof( unsigned char ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0B *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1B *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__POINTERTYPE ){ \
+ raw_size = sizeof( void * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0P *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1P *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__FLOATTYPE ){ \
+ raw_size = sizeof( float ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0F *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1F *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ raw_size = sizeof( const char * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0C *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1C *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ raw_size = sizeof( AstObject * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0A *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1A *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__UNDEFTYPE ){ \
+ raw_size = 0; \
+ raw = NULL; \
+\
+ } else { \
+ raw_size = 0; \
+ raw = NULL; \
+ astError( AST__INTER, "astMapGet1<X>(KeyMap): Illegal map entry data " \
+ "type %d encountered (internal AST programming error).", status, \
+ raw_type ); \
+ } \
+\
+/* Treat scalars as single-value vectors. */ \
+ if( nel == 0 ) nel = 1; \
+\
+/* Ensure no more than "mxval" values are returned. */ \
+ if( nel > mxval ) nel = mxval; \
+\
+/* Return the number of values stored in the buffer. */ \
+ *nval = nel; \
+\
+/* Loop round all values in the vector. */ \
+ for( i = 0; i < nel && astOK; i++ ) { \
+\
+/* Convert the value, storing the result in the supplied buffer. Report an \
+ error if conversion is not possible. */ \
+ if( !raw ) { \
+ result = 0; \
+\
+ } else if( !ConvertValue( raw, raw_type, value + i, Itype, status ) && astOK ){ \
+ astError( AST__MPGER, "astMapGet1" #X "(%s): The value of " \
+ "element %d of KeyMap key \"%s\" cannot be read using " \
+ "the requested data type.", status,astGetClass( this ), i + 1, key ); \
+ } \
+\
+/* Increment the pointers to the next raw value. */ \
+ raw = (char *) raw + raw_size; \
+ } \
+\
+/* If the KeyError attribute is non-zero, report an error if the key is not \
+ found */ \
+ } else if( astGetKeyError( this ) && astOK ) { \
+ astError( AST__MPKER, "astMapGet1" #X "(%s): No value was found for " \
+ "%s in the supplied KeyMap.", status, astGetClass( this ), \
+ key ); \
+ } \
+\
+/* If an error occurred,return zero. */ \
+ if( !astOK ) result = 0; \
+\
+/* Return the result.*/ \
+ return result; \
+}
+
+/* Expand the above macro to generate a function for each required
+ data type (except C which is done differently). */
+MAKE_MAPGET1(I,int,AST__INTTYPE)
+MAKE_MAPGET1(D,double,AST__DOUBLETYPE)
+MAKE_MAPGET1(F,float,AST__FLOATTYPE)
+MAKE_MAPGET1(A,AstObject *,AST__OBJECTTYPE)
+MAKE_MAPGET1(P,void *,AST__POINTERTYPE)
+MAKE_MAPGET1(S,short int,AST__SINTTYPE)
+MAKE_MAPGET1(B,unsigned char,AST__BYTETYPE)
+
+/* Undefine the macro. */
+#undef MAKE_MAPGET1
+
+
+static int MapGet1C( AstKeyMap *this, const char *skey, int l, int mxval,
+ int *nval, char *value, int *status ) {
+/*
+* Name:
+* MapGet1C
+
+* Purpose:
+* Get a vector value from a KeyMap.
+
+* Type:
+* Private member function.
+
+* Synopsis:
+* #include "ast.h"
+* int MapGet1C( AstKeyMap *this, const char *key, int l, int mxval,
+* int *nval, char *value, int *status )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the implementation of astMapGet1<X> for <X> = "C". We
+* cannot use the MAKE_MAPGET1 macro for this because the string
+* version of this function has an extra parameter giving the maximum
+* length of each string which can be stored in the supplied buffer.
+
+* Parameters:
+* (see astMapGet1<X>)
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ char *val; /* Pointer to next buffer element */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ const char *cvalue; /* Pointer to converted string */
+ const char *key; /* Pointer to key string to use */ \
+ int i; /* Element index */
+ int itab; /* Index of hash table element to use */
+ int nel; /* Number of elements in raw vector */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned flag */
+ size_t raw_size; /* Size of a single raw value */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+ *nval = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGet1C",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+ result = 1;
+
+/* Get the address of the first raw value, and its data type. Also get
+ the size of each element of the vector. */
+ nel = mapentry->nel;
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ raw_size = sizeof( int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ raw_size = sizeof( void * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ raw_size = sizeof( double );
+ if( nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ raw_size = sizeof( short int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ raw_size = sizeof( unsigned char );
+ if( nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ raw_size = sizeof( float );
+ if( nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ raw_size = sizeof( const char * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ raw_size = sizeof( AstObject * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw_size = 0;
+ raw = NULL;
+
+ } else {
+ raw_size = 0;
+ raw = NULL;
+ astError( AST__INTER, "astMapGet1C(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* Treat scalars as single-value vectors. */
+ if( nel == 0 ) nel = 1;
+
+/* Ensure no more than "mxval" values are returned. */
+ if( nel > mxval ) nel = mxval;
+
+/* Return the number of values stored in the buffer. */
+ *nval = nel;
+
+/* Loop round all values in the vector. */
+ val = value;
+ for( i = 0; i < nel && astOK; i++ ) {
+
+/* Convert the value, storing the result in the supplied buffer. Report an
+ error if conversion is not possible. */
+ if( !raw ) {
+ result = 0;
+
+ } else if( !ConvertValue( raw, raw_type, &cvalue, AST__STRINGTYPE, status ) && astOK ){
+ astError( AST__MPGER, "astMapGet1C(%s): The value of "
+ "element %d of KeyMap key \"%s\" cannot be read using "
+ "the requested data type.", status,astGetClass( this ), i + 1, key );
+
+/* If succesful, copy the string into the supplied buffer, or as much of
+ it as will fit. Leave room for a trailing null character. */
+ } else {
+ strncpy( val, cvalue, l - 1 );
+ val[ l - 1 ] = 0;
+ }
+
+/* Increment the pointers to the next raw value and the next buffer
+ location. */
+ raw = (char *) raw + raw_size;
+ val += l;
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapGet1C(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If an error occurred,return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result.*/
+ return result;
+}
+
+int astMapGet1AId_( AstKeyMap *this, const char *skey, int mxval, int *nval,
+ AstObject **value, int *status ) {
+/*
+* Name:
+* astMapGet1AId_
+
+* Purpose:
+* Get a vector of AstObject pointers from a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "ast.h"
+* int astMapGet1A( AstKeyMap *this, const char *key, int mxval, int *nval,
+* AstObject **value )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the public implementation of the astMapGet1A function
+* It is identical to astMapGet1A_ except that ID values are returned
+* via the "value" parameter instead of a true C pointers. This is required
+* because this conversion cannot be performed by the macro that invokes
+* the function.
+
+* Parameters:
+* (see astMapGet1<X>)
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ AstObject *avalue; /* Pointer to AstObject */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ const char *key; /* Pointer to key string to use */ \
+ int i; /* Element index */
+ int itab; /* Index of hash table element to use */
+ int nel; /* Number of elements in raw vector */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned flag */
+ size_t raw_size; /* Size of a single raw value */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+ *nval = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGet1A",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+ result = 1;
+
+/* Get the address of the first raw value, and its data type. Also get
+ the size of each element of the vector. */
+ nel = mapentry->nel;
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ raw_size = sizeof( int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ raw_size = sizeof( double );
+ if( nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ raw_size = sizeof( short int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ raw_size = sizeof( unsigned char );
+ if( nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ raw_size = sizeof( void * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ raw_size = sizeof( float );
+ if( nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ raw_size = sizeof( const char * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ raw_size = sizeof( AstObject * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw_size = 0;
+ raw = NULL;
+
+ } else {
+ raw_size = 0;
+ raw = NULL;
+ astError( AST__INTER, "astMapGet1A(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).",
+ status, raw_type );
+ }
+
+/* Treat scalars as single-value vectors. */
+ if( nel == 0 ) nel = 1;
+
+/* Ensure no more than "mxval" values are returned. */
+ if( nel > mxval ) nel = mxval;
+
+/* Return the number of values stored in the buffer. */
+ *nval = nel;
+
+/* Loop round all values in the vector. */
+ for( i = 0; i < nel && astOK; i++ ) {
+
+/* Convert the value, storing the result in the supplied buffer. Report an
+ error if conversion is not possible. */
+ if( !raw ) {
+ result = 0;
+
+ } else if( !ConvertValue( raw, raw_type, &avalue, AST__OBJECTTYPE, status ) && astOK ){
+ astError( AST__MPGER, "astMapGet1A(%s): The value of "
+ "element %d of KeyMap key \"%s\" cannot be read using "
+ "the requested data type.", status, astGetClass( this ),
+ i + 1, key );
+
+/* If succesful, return an ID value for the Object. */
+ } else {
+ value[ i ] = avalue ? astMakeId( avalue ) : NULL;
+ }
+
+/* Increment the pointers to the next raw value. */
+ raw = (char *) raw + raw_size;
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapGet1A(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If an error occurred,return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result.*/
+ return result;
+}
+
+static int MapGetC( AstKeyMap *this, const char *key, const char **value, int *status ) {
+/*
+*++
+* Name:
+c astMapGetC
+f AST_MAPGETC
+
+* Purpose:
+* Get a scalar or vector value from a KeyMap as a single string.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c int astMapGetC( AstKeyMap *this, const char *key, const char **value );
+f RESULT = AST_MAPGETC( THIS, KEY, VALUE, L, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function gets a named value from a KeyMap as a single string.
+* For scalar values it is equivalent to
+c astMapGet0C.
+f AST_MAPGET0C.
+* If the value is a vector, the returned string is a comma-separated
+* list of the vector elements, enclosed in parentheses.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored. The supplied string is converted to upper
+* case before use if the KeyCase attribute is currently set to zero.
+c value
+f VALUE = CHARACTER * ( * ) (Returned)
+c Address at which to return a pointer to the required string value.
+f The requested value.
+* If the requested key is not found, or if it is found but has an
+* undefined value (see
+c astMapPutU), then the contents of the supplied pointer
+f AST_MAPPUTU), then the contents of the supplied string
+* are unchanged on exit.
+f L = INTEGER (Returned)
+f This parameter is only present in the interface for the AST_MAPGET0C
+f function. It is returned holding the number of characters
+f written into the CHARACTER variable supplied for parameter VALUE.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapGetC()
+f AST_MAPGETC = LOGICAL
+c A non-zero value
+f .TRUE.
+* is returned if the requested key name was found, and does not have
+* an undefined value (see
+c astMapPutU). Zero
+f AST_MAPPUTU). .FALSE.
+* is returned otherwise.
+
+* Notes:
+* - No error is reported if the requested key cannot be found in the
+* given KeyMap, but a
+c zero
+f .FALSE.
+* value will be returned as the function value. The supplied buffer
+* will be returned unchanged.
+c - The string pointer returned by astMapGetC is guaranteed to remain valid
+c and the string to which it points will not be over-written for a
+c total of 50 successive invocations of this function. After this,
+c the memory containing the string may be re-used, so a copy of
+c the string should be made if it is needed for longer than this. The
+c calling code should never attempt to free the returned pointer
+c (for instance, using astFree).
+*--
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Declare the thread specific global data */
+ char *buf; /* Buffer for all string values */
+ char *cvalue; /* Pointer to returned string */
+ char *pb; /* Pointer to start of next section of buffer */
+ int i; /* Loop count */
+ int mxlen; /* Max length of any string in the vector */
+ int nval; /* No. of elements in vector */
+ int result; /* Returned flag */
+ int nc; /* Current length of total string */
+
+/* Check the global error status. */
+ if ( !astOK ) return 0;
+
+/* Get a pointer to the structure holding thread-specific global data. */
+ astGET_GLOBALS(this);
+
+/* If the "convertvalue_strings" array has not been initialised, fill it with
+ NULL pointers. */
+ if( !convertvalue_init ) {
+ convertvalue_init = 1;
+ for( i = 0; i < AST__KEYMAP_CONVERTVALUE_MAX_STRINGS; i++ ) convertvalue_strings[ i ] = NULL;
+ }
+
+/* See how many elements are stored in the requested entry. */
+ nval = astMapLength( this, key );
+
+/* If the requested entry does not exist, return without further action. */
+ if( nval == 0 ) {
+ result = 0;
+
+/* If the requested entry is a scalar, just call astMapGet0C to get the
+ required string. */
+ } else if( nval == 1 ) {
+ result = astMapGet0C( this, key, value );
+
+/* If the requested entry is a vector, use astMapGet1C to get all the
+ strings stored in dynamic memory. */
+ } else {
+
+/* First get the maximum length of any one string stored in the vector. */
+ mxlen = astMapLenC( this, key );
+
+/* Allocate a buffer big enough to hold all elements assuming they are
+ all the maximum length. Include room for a terminating null on each
+ string. */
+ buf = astMalloc( (mxlen + 1)*nval*sizeof( *buf ) );
+ if( astOK ) {
+
+/* Store the strings in the buffer. */
+ result = astMapGet1C( this, key, mxlen+1, nval, &nval, buf );
+ if( result ) {
+
+/* Combine the individual strings into a single comma-delimited list,
+ enclosed in parentheses, and stored in dynamic memory. */
+ nc = 0;
+ cvalue = astAppendString( NULL, &nc, "(" );
+ pb = buf;
+ for( i = 0; i < nval; i++ ) {
+ if( i ) cvalue = astAppendString( cvalue, &nc, "," );
+ cvalue = astAppendString( cvalue, &nc, pb );
+ pb += mxlen + 1;
+ }
+ cvalue = astAppendString( cvalue, &nc, ")" );
+
+/* Put a pointer to the total string into the next element of the "convertvalue_strings"
+ array, freeing any value already stored in the next element first. */
+ if( cvalue && astOK ) {
+ (void) astFree( convertvalue_strings[ convertvalue_istr ] );
+ convertvalue_strings[ convertvalue_istr ] = cvalue;
+
+/* Increment "convertvalue_istr" to use the next element of "convertvalue_strings" on
+ the next invocation. Recycle "convertvalue_istr" to zero when all elements have been
+ used. */
+ if( ++convertvalue_istr == ( AST__KEYMAP_CONVERTVALUE_MAX_STRINGS - 1 ) )
+ convertvalue_istr = 0;
+
+/* Return a pointer to the striong now stored in the "convertvalue_strings"
+ array. */
+ *value = cvalue;
+ }
+ }
+ }
+
+/* Free the space used to hold the values buffer. */
+ buf = astFree( buf );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+
+/*
+*++
+* Name:
+c astMapGetElem<X>
+f AST_MAPGETELEM<X>
+
+* Purpose:
+* Get a single element of a vector value from a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c int astMapGetElem<X>( AstKeyMap *this, const char *key, int elem,
+c <X>type *value )
+c int astMapGetElemC( AstKeyMap *this, const char *key, int l, int elem,
+c char *value )
+f RESULT = AST_MAPGETELEM<X>( THIS, KEY, ELEM, VALUE, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is a set of functions for retrieving a single element of a vector
+* value from a KeyMap. You should replace <X> in the generic function name
+c astMapGetElem<X>
+f AST_MAPGETELEM<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+* The stored value is converted to the data type indiced by <X>
+* before being returned (an error is reported if it is not possible to
+* convert the stored value to the requested data type).
+c Note, the astMapGetElemC function has an extra parameter "l" which
+c specifies the maximum length of the string to be stored in the
+c "value" buffer (see the "astMapGetElemC" section below).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c elem
+f ELEM = INTEGER (Given)
+* The index of the required vector element, starting at
+c zero.
+f one.
+* An error will be reported if the value is outside the range of
+* the vector.
+c value
+f VALUE = <X>type (Returned)
+c A pointer to a buffer in which to return the requested value.
+f The requested value.
+* If the requested key is not found, or if it is found but has an
+* undefined value (see
+c astMapPutU),
+f AST_MAPPUTU),
+* then the contents of the
+* buffer on entry to this function will be unchanged on exit.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapGetElem<X>()
+f AST_MAPGETELEM<X> = LOGICAL
+c A non-zero value
+f .TRUE.
+* is returned if the requested key name was found, and does not have
+* an undefined value (see
+c astMapPutU). Zero
+f AST_MAPPUTU). .FALSE.
+* is returned otherwise.
+
+* Notes:
+* - No error is reported if the requested key cannot be found in the
+* given KeyMap, or if it has an undefined value, but a
+c zero
+f .FALSE.
+* value will be returned as the function value.
+
+c astMapGetElemC:
+c The "value" buffer supplied to the astMapGetElemC function should be a
+c pointer to a character array with "l" elements, where "l" is the
+c maximum length of the string to be returned. The value of "l"
+c should be supplied as an extra parameter following "key" when
+c invoking astMapGetElemC, and should include space for a terminating
+c null character.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name
+c astMapGetElem<X>
+f routine, you should replace <X> in the generic routine name
+f AST_MAPGETELEM<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - D: double
+c - F: float
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: Unsigned byte (i.e. char)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: Unsigned byte
+*
+c For example, astMapGetElemD would be used to get a "double" value, while
+c astMapGetElemI would be used to get an "int" value, etc. For D or I, the
+c supplied "value" parameter should be a pointer to a double or int. For
+c C, the supplied "value" parameter should be a pointer to a character
+c string with "l" elements. For A, the supplied "value" parameter should
+c be a pointer to an AstObject pointer.
+f For example, AST_MAPGETELEMD would be used to get a DOUBLE PRECISION
+f value, while AST_MAPGETELEMI would be used to get an INTEGER value, etc.
+
+*--
+*/
+/* Define a macro to implement the function for a specific data type
+(excluding "C" since that needs an extra parameter). */
+#define MAKE_MAPGETELEM(X,Xtype,Itype) \
+static int MapGetElem##X( AstKeyMap *this, const char *skey, int elem, \
+ Xtype *value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ const char *key; /* Pointer to key string to use */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ int itab; /* Index of hash table element to use */ \
+ int nel; /* Number of elements in raw vector */ \
+ int raw_type; /* Data type of stored value */ \
+ int result; /* Returned flag */ \
+ size_t raw_size; /* Size of a single raw value */ \
+ unsigned long hash; /* Full width hash value */ \
+ void *raw; /* Pointer to stored value */ \
+\
+/* Initialise */ \
+ result = 0; \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return result; \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGetElem" #X, \
+ status ); \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which the key will be stored. */ \
+ itab = HashFun( key, this->mapsize - 1, &hash, status ); \
+\
+/* Search the relevent table entry for the required MapEntry. */ \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+\
+/* Skip rest if the key was not found. */ \
+ if( mapentry ) { \
+ result = 1; \
+\
+/* Get the address of the first raw value, and its data type. Also get \
+ the size of each element of the vector. */ \
+ nel = mapentry->nel; \
+ raw_type = mapentry->type; \
+ if( raw_type == AST__INTTYPE ){ \
+ raw_size = sizeof( int ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0I *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1I *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__DOUBLETYPE ){ \
+ raw_size = sizeof( double ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0D *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1D *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__SINTTYPE ){ \
+ raw_size = sizeof( short int ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0S *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1S *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__BYTETYPE ){ \
+ raw_size = sizeof( unsigned char ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0B *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1B *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__POINTERTYPE ){ \
+ raw_size = sizeof( void * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0P *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1P *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__FLOATTYPE ){ \
+ raw_size = sizeof( float ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0F *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1F *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ raw_size = sizeof( const char * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0C *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1C *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ raw_size = sizeof( AstObject * ); \
+ if( nel == 0 ) { \
+ raw = &( ((Entry0A *)mapentry)->value ); \
+ } else { \
+ raw = ((Entry1A *)mapentry)->value; \
+ } \
+\
+ } else if( raw_type == AST__UNDEFTYPE ){ \
+ raw = NULL; \
+\
+ } else { \
+ raw_size = 0; \
+ raw = NULL; \
+ astError( AST__INTER, "astMapGetElem<X>(KeyMap): Illegal map entry " \
+ "data type %d encountered (internal AST programming " \
+ "error).", status, raw_type ); \
+ } \
+\
+/* Treat scalars as single-value vectors. */ \
+ if( nel == 0 ) nel = 1; \
+\
+/* Ensure the requested element is within the bounds of the vector */ \
+ if( elem >= nel || elem < 0 ) { \
+ if( astOK ) { \
+ astError( AST__MPVIN, "astMapGetElem<X>(KeyMap): Illegal " \
+ "zero-based vector index %d supplied for KeyMap " \
+ "entry '%s' - the vector has %d elements.", status, \
+ elem, key, nel ); \
+ } \
+\
+/* Get a pointer to the requested raw value. */ \
+ } else if( raw ) { \
+ raw = (char *) raw + elem*raw_size; \
+\
+/* Convert the requested value, storing the result in the supplied buffer. \
+ Report an error if conversion is not possible. */ \
+ if( !ConvertValue( raw, raw_type, value, Itype, status ) && astOK ){ \
+ astError( AST__MPGER, "astMapGetElem" #X "(%s): The value of " \
+ "element %d of KeyMap key \"%s\" cannot be read using " \
+ "the requested data type.", status, astGetClass( this ), \
+ elem + 1, key ); \
+ } \
+ } \
+\
+/* If the KeyError attribute is non-zero, report an error if the key is not \
+ found */ \
+ } else if( astGetKeyError( this ) && astOK ) { \
+ astError( AST__MPKER, "astMapGetElem" #X "(%s): No value was found for " \
+ "%s in the supplied KeyMap.", status, astGetClass( this ), \
+ key ); \
+ } \
+\
+/* If an error occurred,return zero. */ \
+ if( !astOK ) result = 0; \
+\
+/* Return the result.*/ \
+ return result; \
+}
+
+/* Expand the above macro to generate a function for each required
+ data type (except C which is done differently). */
+MAKE_MAPGETELEM(I,int,AST__INTTYPE)
+MAKE_MAPGETELEM(D,double,AST__DOUBLETYPE)
+MAKE_MAPGETELEM(F,float,AST__FLOATTYPE)
+MAKE_MAPGETELEM(A,AstObject *,AST__OBJECTTYPE)
+MAKE_MAPGETELEM(P,void *,AST__POINTERTYPE)
+MAKE_MAPGETELEM(S,short int,AST__SINTTYPE)
+MAKE_MAPGETELEM(B,unsigned char,AST__BYTETYPE)
+
+/* Undefine the macro. */
+#undef MAKE_MAPGETELEM
+
+
+static int MapGetElemC( AstKeyMap *this, const char *skey, int l, int elem,
+ char *value, int *status ) {
+/*
+* Name:
+* MapGetElemC
+
+* Purpose:
+* Get a single element of a vector value from a KeyMap.
+
+* Type:
+* Private member function.
+
+* Synopsis:
+* #include "ast.h"
+* int MapGetElemC( AstKeyMap *this, const char *key, int l, int elem,
+* char *value, int *status )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the implementation of astMapGetElem<X> for <X> = "C". We
+* cannot use the MAKE_MAPGETELEM macro for this because the string
+* version of this function has an extra parameter giving the maximum
+* length of each string which can be stored in the supplied buffer.
+
+* Parameters:
+* (see astMapGetElem<X>)
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ const char *cvalue; /* Pointer to converted string */
+ int itab; /* Index of hash table element to use */
+ int nel; /* Number of elements in raw vector */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned flag */
+ size_t raw_size; /* Size of a single raw value */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGetElemC",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+ result = 1;
+
+/* Get the address of the first raw value, and its data type. Also get
+ the size of each element of the vector. */
+ nel = mapentry->nel;
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ raw_size = sizeof( int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ raw_size = sizeof( void * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ raw_size = sizeof( double );
+ if( nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ raw_size = sizeof( short int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ raw_size = sizeof( unsigned char );
+ if( nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ raw_size = sizeof( float );
+ if( nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ raw_size = sizeof( const char * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ raw_size = sizeof( AstObject * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw = NULL;
+
+ } else {
+ raw_size = 0;
+ raw = NULL;
+ astError( AST__INTER, "astMapGetElemC(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* Treat scalars as single-value vectors. */
+ if( nel == 0 ) nel = 1;
+
+/* Ensure the requested element is within the bounds of the vector */
+ if( elem >= nel || elem < 0 ) {
+ if( astOK ) {
+ astError( AST__MPVIN, "astMapGetElemC(KeyMap): Illegal vector "
+ "index %d supplied for KeyMap entry '%s' - should be "
+ "in the range 1 to %d.", status, elem + 1, key, nel + 1 );
+ }
+
+/* Get a pointer to the requested raw value. */
+ } else if( raw ){
+ raw = (char *) raw + elem*raw_size;
+
+/* Convert the value, storing the result in the supplied buffer. Report an
+ error if conversion is not possible. */
+ if( !ConvertValue( raw, raw_type, &cvalue, AST__STRINGTYPE, status ) && astOK ){
+ astError( AST__MPGER, "astMapGetElemC(%s): The value of "
+ "element %d of KeyMap key \"%s\" cannot be read using "
+ "the requested data type.", status,astGetClass( this ),
+ elem + 1, key );
+
+/* If succesful, copy the string into the supplied buffer, or as much of
+ it as will fit. Leave room for a trailing null character. */
+ } else {
+ strncpy( value, cvalue, l - 1 );
+ value[ l - 1 ] = 0;
+ }
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapGetElemC(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If an error occurred,return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result.*/
+ return result;
+}
+
+int astMapGetElemAId_( AstKeyMap *this, const char *skey, int elem,
+ AstObject **value, int *status ) {
+/*
+* Name:
+* astMapGetElemAId_
+
+* Purpose:
+* Get a single element of a vector of AstObject pointers from a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "ast.h"
+* int astMapGetElemA( AstKeyMap *this, const char *key, int elem,
+* AstObject **value )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is the public implementation of the astMapGetElemA function
+* It is identical to astMapGetElemA_ except that an ID value is returned
+* via the "value" parameter instead of a true C pointer. This is required
+* because this conversion cannot be performed by the macro that invokes
+* the function.
+
+* Parameters:
+* (see astMapGet1<X>)
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ AstObject *avalue; /* Pointer to AstObject */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ int nel; /* Number of elements in raw vector */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned flag */
+ size_t raw_size; /* Size of a single raw value */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapGetElemA",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+ result = 1;
+
+/* Get the address of the first raw value, and its data type. Also get
+ the size of each element of the vector. */
+ nel = mapentry->nel;
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ raw_size = sizeof( int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ raw_size = sizeof( short int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ raw_size = sizeof( unsigned char );
+ if( nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ raw_size = sizeof( double );
+ if( nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ raw_size = sizeof( void * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ raw_size = sizeof( float );
+ if( nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ raw_size = sizeof( const char * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ raw_size = sizeof( AstObject * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw = NULL;
+
+ } else {
+ raw_size = 0;
+ raw = NULL;
+ astError( AST__INTER, "astMapGetElemA(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* Treat scalars as single-value vectors. */
+ if( nel == 0 ) nel = 1;
+
+/* Ensure the requested element is within the bounds of the vector */
+ if( elem >= nel || elem < 0 ) {
+ if( astOK ) {
+ astError( AST__MPVIN, "astMapGetElemA(KeyMap): Illegal vector "
+ "index %d supplied for KeyMap entry '%s' - should be "
+ "in the range 1 to %d.", status, elem + 1, key, nel + 1 );
+ }
+
+/* Get a pointer to the requested raw value. */
+ } else if( raw ){
+ raw = (char *) raw + elem*raw_size;
+
+/* Convert the value, storing the result in the supplied buffer. Report an
+ error if conversion is not possible. */
+ if( !ConvertValue( raw, raw_type, &avalue, AST__OBJECTTYPE, status ) && astOK ){
+ astError( AST__MPGER, "astMapGetElemA(%s): The value of "
+ "element %d of KeyMap key \"%s\" cannot be read using "
+ "the requested data type.", status,astGetClass( this ),
+ elem + 1, key );
+
+/* If succesful, return an ID value for the Object. */
+ } else {
+ *value = avalue ? astMakeId( avalue ) : NULL;
+ }
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapGetElemA(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If an error occurred,return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result.*/
+ return result;
+}
+
+static int MapDefined( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapDefined
+f AST_MAPDEFINED
+
+* Purpose:
+* Check if a KeyMap contains a defined value for a key.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c int astMapDefined( AstKeyMap *this, const char *key );
+f RESULT = AST_MAPDEFINED( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function checks to see if a KeyMap contains a defined value for
+* a given key. If the key is present in the KeyMap but has an
+* undefined value it returns
+c zero (unlike astMapHasKey which would return non-zero).
+f .FALSE. (unlike AST_MAPHASKEY which would return .TRUE.).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored. The supplied string is converted to upper
+* case before use if the KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapDefined()
+f AST_MAPDEFINED = LOGICAL
+c A non-zero value
+f .TRUE.
+* is returned if the requested key name is present in the KeyMap
+* and has a defined value.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ int result; /* Returned flag */
+ unsigned long hash; /* Full width hash value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapDefined",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+
+/* Set the result depending on the entry data type. */
+ if( mapentry->type == AST__UNDEFTYPE ){
+ result = 0;
+ } else {
+ result = 1;
+ }
+
+/* If the KeyError attribute is non-zero, report an error if the key is not
+ found */
+ } else if( astGetKeyError( this ) && astOK ) {
+ astError( AST__MPKER, "astMapDefined(%s): No value was found for "
+ "%s in the supplied KeyMap.", status, astGetClass( this ),
+ key );
+ }
+
+/* If an error occurred, return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result.*/
+ return result;
+}
+
+static int MapHasKey( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapHasKey
+f AST_MAPHASKEY
+
+* Purpose:
+* Check if an entry with a given key exists in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c int astMapHasKey( AstKeyMap *this, const char *key )
+f RESULT = AST_MAPHASKEY( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns a flag indicating if the KeyMap contains an
+* entry with the given key.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the KeyMap entry. Trailing spaces are
+* ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapHasKey()
+f AST_MAPHASKEY = LOGICAL
+c Non-zero if the key was found, and zero otherwise.
+f .TRUE. if the key was found, and .FALSE. otherwise.
+
+* Notes:
+c - A non-zero function value
+f - .TRUE.
+* is returned if the key exists but has an undefined value (that is,
+* the returned value does not depend on whether the entry has a
+* defined value or not). See also
+c astMapDefined, which returns zero in such a case.
+f AST_MAPDEFINED, which returns zero in such a case.
+* - A function value of
+c zero
+f .FALSE.
+* will be returned if an error has already occurred, or if this
+* function should fail for any reason.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to entry in linked list */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ int result; /* Returned value */
+ unsigned long hash; /* Full width hash value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapHasKey",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Set a non-zero return value if the key was found. */
+ if( mapentry ) result = 1;
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+
+}
+
+static void MapRemove( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapRemove
+f AST_MAPREMOVE
+
+* Purpose:
+* Removed a named entry from a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c void astMapRemove( AstKeyMap *this, const char *key )
+f CALL AST_MAPREMOVE( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This function
+f This routine
+* removes a named entry from a KeyMap. It returns without action if the
+* KeyMap does not contain the specified key.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+*--
+*/
+
+/* Local Variables: */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ unsigned long hash; /* Full width hash value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapRemove",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry and remove it. */
+ (void) FreeMapEntry( RemoveTableEntry( this, itab, key, status ), status );
+}
+
+static void MapRename( AstKeyMap *this, const char *soldkey, const char *snewkey,
+ int *status ) {
+/*
+*++
+* Name:
+c astMapRename
+f AST_MAPRENAME
+
+* Purpose:
+* Rename an existing KeyMap entry.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c void astMapRename( AstKeyMap *this, const char *oldkey, const char *newkey )
+f CALL AST_MAPRENAME( THIS, OLDKEY, NEWKEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+c This function
+f This routine
+* associated a new key with an existing entry in a KeyMap. It returns
+* without action if the oldkey does not exist in the KeyMap.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c oldkey
+f OLDKEY = CHARACTER * ( * ) (Given)
+* The character string identifying the entry to be renamed. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c newkey
+f NEKEY = CHARACTER * ( * ) (Given)
+* The new character string to associated with the renamed entry.
+* Trailing spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *entry; /* Pointer to the entry being renamed */
+ AstMapEntry *oldent; /* Pointer to old entry with new name */
+ const char *oldkey; /* Pointer to key string to use */
+ char oldkeybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ const char *newkey; /* Pointer to key string to use */
+ char newkeybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ char *p; /* Pointer to next key character */
+ int itab; /* Index of hash table element to use */
+ int keylen; /* Length of supplied key string */
+ int keymember; /* Identifier for new key */
+ int there; /* Did the entry already exist in the KeyMap? */
+ unsigned long hash; /* Full width hash value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Convert the supplied keys to upper case if required. */
+ oldkey = ConvertKey( this, soldkey, oldkeybuf, AST__MXKEYLEN + 1,
+ "astMapRename", status );
+ newkey = ConvertKey( this, snewkey, newkeybuf, AST__MXKEYLEN + 1,
+ "astMapRename", status );
+
+/* Do nothing if the keys are the same. */
+ if( strcmp( oldkey, newkey ) ){
+
+/* Use the hash function to determine the element of the hash table in
+ which the old key will be stored. */
+ itab = HashFun( oldkey, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. Remove it
+ from the list, but do not free it. */
+ entry = RemoveTableEntry( this, itab, oldkey, status );
+
+/* Skip rest if the key was not found. */
+ if( entry ) {
+
+/* Store the new key string, and terminate it to exclude any trailing
+ spaces. */
+ keylen = strlen( newkey );
+ entry->key = astStore( (void *) entry->key, newkey, keylen + 1 );
+ if( astOK ) {
+ p = (char *) entry->key + keylen;
+ while( --p >= entry->key ) {
+ if( *p == ' ' ) {
+ *p = 0;
+ } else {
+ break;
+ }
+ }
+ }
+
+/* Use the hash function to determine the element of the hash table in
+ which to store the entry with its new key. */
+ itab = HashFun( entry->key, this->mapsize - 1, &(entry->hash), status );
+
+/* Remove and free any existing entry with the given key from the table
+ element. */
+ oldent = RemoveTableEntry( this, itab, entry->key, status );
+ if( oldent ) {
+ keymember = oldent->keymember;
+ oldent = FreeMapEntry( oldent, status );
+ there = 1;
+ } else {
+ keymember = -1;
+ there = 0;
+ }
+
+/* If the KeyMap is locked we report an error if an attempt is made to
+ introduce a new key. */
+ if( !there && astGetMapLocked( this ) ) {
+ astError( AST__BADKEY, "astMapRename(%s): Failed to rename item "
+ "\"%s\" in a KeyMap to \"%s\": \"%s\" is not a known "
+ "item.", status, astGetClass( this ), oldkey, newkey,
+ newkey );
+ }
+
+/* If all has gone OK, store the renamed entry at the head of the linked list
+ associated with the selected table entry. */
+ if( astOK ) {
+ entry = AddTableEntry( this, itab, entry, keymember, status );
+
+/* If anything went wrong, try to delete the renamed entry. */
+ } else {
+ entry = FreeMapEntry( entry, status );
+ }
+ }
+ }
+}
+
+static int MapSize( AstKeyMap *this, int *status ) {
+/*
+*++
+* Name:
+c astMapSize
+f AST_MAPSIZE
+
+* Purpose:
+* Get the number of entries in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c int astMapSize( AstKeyMap *this )
+f RESULT = AST_MAPSIZE( THIS, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns the number of entries in a KeyMap.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapSize()
+f AST_MAPSIZE = INTEGER
+* The number of entries in the KeyMap.
+
+* Notes:
+* - A function value of zero will be returned if an error has already
+* occurred, or if this function should fail for any reason.
+
+*--
+*/
+
+/* Local Variables: */
+ int itab; /* Index of hash table element to use */
+ int result; /* Returned value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Add up the number of entries in all elements of the hash table. */
+ for( itab = 0; itab < this->mapsize; itab++ ) result += this->nentry[ itab ];
+
+/* Return the result. */
+ return result;
+
+}
+
+static int MapLenC( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapLenC
+f AST_MAPLENC
+
+* Purpose:
+* Get the number of characters in a character entry in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c int astMapLenC( AstKeyMap *this, const char *key )
+f RESULT = AST_MAPLENC( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns the minimum length that a character variable
+* must have in order to be able to store a specified entry in
+* the supplied KeyMap. If the named entry is a vector entry, then the
+* returned value is the length of the longest element of the vector
+* value.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the KeyMap entry. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapLenC()
+f AST_MAPLENC = INTEGER
+* The length (i.e. number of characters) of the longest formatted
+* value associated with the named entry.
+c This does not include the trailing null character.
+
+* Notes:
+* - A function value of zero will be returned without error if the
+* named entry cannot be formatted as a character string.
+* - A function value of zero will be returned if an error has already
+* occurred, or if this function should fail for any reason.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int i; /* Element index */
+ int itab; /* Index of hash table element to use */
+ int l; /* Length of formatted vector element */
+ int nel; /* Number of elements in raw vector */
+ int raw_type; /* Data type of stored value */
+ int result; /* Returned value */
+ size_t raw_size; /* Size of a single raw value */
+ unsigned long hash; /* Full width hash value */
+ void *raw; /* Pointer to stored value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapLenC",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+
+/* Get the address of the first raw value, and its data type. Also get
+ the size of each element of the vector. */
+ nel = mapentry->nel;
+ raw_type = mapentry->type;
+ if( raw_type == AST__INTTYPE ){
+ raw_size = sizeof( int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0I *)mapentry)->value );
+ } else {
+ raw = ((Entry1I *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__POINTERTYPE ){
+ raw_size = sizeof( void * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0P *)mapentry)->value );
+ } else {
+ raw = ((Entry1P *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__DOUBLETYPE ){
+ raw_size = sizeof( double );
+ if( nel == 0 ) {
+ raw = &( ((Entry0D *)mapentry)->value );
+ } else {
+ raw = ((Entry1D *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__SINTTYPE ){
+ raw_size = sizeof( short int );
+ if( nel == 0 ) {
+ raw = &( ((Entry0S *)mapentry)->value );
+ } else {
+ raw = ((Entry1S *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__BYTETYPE ){
+ raw_size = sizeof( unsigned char );
+ if( nel == 0 ) {
+ raw = &( ((Entry0B *)mapentry)->value );
+ } else {
+ raw = ((Entry1B *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__FLOATTYPE ){
+ raw_size = sizeof( float );
+ if( nel == 0 ) {
+ raw = &( ((Entry0F *)mapentry)->value );
+ } else {
+ raw = ((Entry1F *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__STRINGTYPE ){
+ raw_size = sizeof( const char * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0C *)mapentry)->value );
+ } else {
+ raw = ((Entry1C *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__OBJECTTYPE ){
+ raw_size = sizeof( AstObject * );
+ if( nel == 0 ) {
+ raw = &( ((Entry0A *)mapentry)->value );
+ } else {
+ raw = ((Entry1A *)mapentry)->value;
+ }
+
+ } else if( raw_type == AST__UNDEFTYPE ){
+ raw_size = 0;
+ raw = NULL;
+
+ } else {
+ raw_size = 0;
+ raw = NULL;
+ astError( AST__INTER, "astMapLenC(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ raw_type );
+ }
+
+/* Treat scalars as single-value vectors. */
+ if( nel == 0 ) nel = 1;
+
+/* Skip undefined values. */
+ if( raw ) {
+
+/* Initialise the maximum length of any formatted value in the entry. */
+ result= 0;
+
+/* Loop round all values in the vector. */
+ for( i = 0; i < nel && astOK; i++ ) {
+
+/* Go through the motions of formatting the value. We do not actually
+ need the formatted string (just its length) so we provide a NULL pointer
+ for the output buffer. The entry is ignored if it cannot be formatted.
+ Note, the length returned by ConvertValue includes the terminating null,
+ so decrement it first. */
+ l = ConvertValue( raw, raw_type, NULL, AST__STRINGTYPE, status );
+ if( --l > result ) result = l;
+
+/* Increment the pointer to the next raw value. */
+ raw = (char *) raw + raw_size;
+ }
+ }
+ }
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+
+}
+
+static int MapLength( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapLength
+f AST_MAPLENGTH
+
+* Purpose:
+* Get the vector length of an entry in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c int astMapLength( AstKeyMap *this, const char *key )
+f RESULT = AST_MAPLENGTH( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns the vector length of a named entry in a KeyMap,
+* (that is, how many values are associated with the entry).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the KeyMap entry. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapLength()
+f AST_MAPLENGTH = INTEGER
+* The length of the entry. One for a scalar, greater than one for
+* a vector. A value of zero is returned if the KeyMap does not
+* contain the named entry.
+
+* Notes:
+* - A function value of zero will be returned if an error has already
+* occurred, or if this function should fail for any reason.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to entry in linked list */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ int result; /* Returned value */
+ unsigned long hash; /* Full width hash value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapLength",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Skip rest if the key was not found. */
+ if( mapentry ) {
+
+/* Store the netry length */
+ result = mapentry->nel;
+
+/* Return 1 for a scalar. */
+ if( result == 0 ) result = 1;
+
+ }
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) result = 0;
+
+/* Return the result. */
+ return result;
+
+}
+
+/*
+*++
+* Name:
+c astMapPutElem<X>
+f AST_MAPPUTELEM<X>
+
+* Purpose:
+* Put a value into an element of a vector value in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "ast.h"
+c void astMapPutElem<X>( AstKeyMap *this, const char *key, int elem,
+c <X>type value )
+f CALL AST_MAPPUTELEM<X>( THIS, KEY, ELEM, VALUE, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This is a set of functions for storing a value in a single element of
+* a vector value in a KeyMap. You should replace <X> in the generic
+* function name
+c astMapPutElem<X>
+f AST_MAPPUTELEM<X>
+* by an appropriate 1-character type code (see the "Data Type Codes"
+* section below for the code appropriate to each supported data type).
+* The supplied value is converted from the data type indicated by <X>
+* to the data type of the KeyMap entry before being stored (an error
+* is reported if it is not possible to convert the value to the
+* required data type).
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the value to be retrieved. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+c elem
+f ELEM = INTEGER (Given)
+* The index of the vector element to modify, starting at
+c zero.
+f one.
+c value
+f VALUE = <X>type (Given)
+* The value to store.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Applicability:
+* KeyMap
+* If the
+c "elem"
+f ELEM
+* index is outside the range of the vector, the length of
+* the vector will be increased by one element and the supplied
+* value will be stored at the end of the vector in the new element.
+* Table
+* If the
+c "elem"
+f ELEM
+* index is outside the range of the vector, an error will be
+* reported. The number of elements in each cell of a column is
+* specified when the column is created using
+c astAddColumn.
+f AST_ADDCOLUMN.
+
+* Notes:
+* - If the entry originally holds a scalar value, it will be treated
+* like a vector entry of length 1.
+* - If the specified key cannot be found in the given KeyMap, or is
+* found but has an undefined value, a new
+* vector entry with the given name, and data type implied by <X>, is
+* created and the supplied value is stored in its first entry.
+
+* Data Type Codes:
+* To select the appropriate
+c function, you should replace <X> in the generic function name
+c astMapPutElem<X>
+f routine, you should replace <X> in the generic routine name
+f AST_MAPPUTELEM<X>
+* with a 1-character data type code, so as to match the data type <X>type
+* of the data you are processing, as follows:
+c - D: double
+c - F: float
+c - I: int
+c - C: "const" pointer to null terminated character string
+c - A: Pointer to AstObject
+c - P: Generic "void *" pointer
+c - S: short int
+c - B: Unsigned byte (i.e. char)
+f - D: DOUBLE PRECISION
+f - R: REAL
+f - I: INTEGER
+f - C: CHARACTER
+f - A: INTEGER used to identify an AstObject
+f - S: INTEGER*2 (short integer)
+f - B: BYTE (unsigned)
+*
+c For example, astMapPutElemD would be used to put a "double" value, while
+c astMapPutElemI would be used to put an "int" value, etc. For D or I, the
+c supplied "value" parameter should be a double or int. For
+c C, the supplied "value" parameter should be a pointer to a character
+c string. For A, the supplied "value" parameter should be an AstObject
+c pointer.
+f For example, AST_MAPPUTELEMD would be used to put a DOUBLE PRECISION
+f value, while AST_MAPPUTELEMI would be used to put an INTEGER value, etc.
+
+*--
+*/
+/* Define a macro to implement the function for a specific data type
+(excluding "C" since that needs an extra parameter). */
+#define MAKE_MAPPUTELEM(X,Xtype,Itype) \
+static void MapPutElem##X( AstKeyMap *this, const char *skey, int elem, \
+ Xtype value, int *status ) { \
+\
+/* Local Variables: */ \
+ AstMapEntry *mapentry; /* Pointer to parent MapEntry structure */ \
+ const char *key; /* Pointer to key string to use */ \
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */ \
+ int itab; /* Index of hash table element to use */ \
+ int nel; /* Number of elements in raw vector */ \
+ int new; /* Was a new uninitialised element created? */ \
+ int raw_type; /* Data type of stored value */ \
+ size_t raw_size; /* Size of a single raw value */ \
+ unsigned long hash; /* Full width hash value */ \
+ void *raw; /* Pointer to stored value */ \
+\
+/* Check the global error status. */ \
+ if ( !astOK ) return; \
+\
+/* Perform any necessary checks on the supplied value to be stored. */ \
+ CHECK_##X \
+\
+/* Convert the supplied key to upper case if required. */ \
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapPutElem" #X, \
+ status ); \
+\
+/* Use the hash function to determine the element of the hash table in \
+ which the key will be stored. */ \
+ itab = HashFun( key, this->mapsize - 1, &hash, status ); \
+\
+/* Search the relevent table entry for the required MapEntry. */ \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+\
+/* If the key was not found, or was found but has an undefined value, create \
+ a new one with a single element, \
+ and store the supplied value in it. */ \
+ if( !mapentry || mapentry->type == AST__UNDEFTYPE ) { \
+ astMapPut1##X( this, key, 1, &value, NULL ); \
+\
+/* If the key was found.... */ \
+ } else { \
+\
+/* Get the current length of the vector (0=>scalar), and the data type. */ \
+ nel = mapentry->nel; \
+ raw_type = mapentry->type; \
+\
+/* Do each data type in turn. */ \
+ if( raw_type == AST__INTTYPE ){ \
+\
+/* If the existing entry is scalar, create a new vector entry with the \
+ same name, value, data type and comment. Then get a pointer to the new \
+ entry, and indicate that we now have a vector entry of length 1. */ \
+ if( nel == 0 ) { \
+ astMapPut1I( this, key, 1, &( ((Entry0I *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+\
+/* Get the address of the first raw value in the vector. Also get \
+ the size of each element of the vector. */ \
+ raw = ((Entry1I *)mapentry)->value; \
+ raw_size = sizeof( int ); \
+\
+/* Handle other data type in the same way. */ \
+ } else if( raw_type == AST__SINTTYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1S( this, key, 1, &( ((Entry0S *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1S *)mapentry)->value; \
+ raw_size = sizeof( short int ); \
+\
+ } else if( raw_type == AST__BYTETYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1B( this, key, 1, &( ((Entry0B *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1B *)mapentry)->value; \
+ raw_size = sizeof( unsigned char ); \
+\
+ } else if( raw_type == AST__DOUBLETYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1D( this, key, 1, &( ((Entry0D *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1D *)mapentry)->value; \
+ raw_size = sizeof( double ); \
+\
+ } else if( raw_type == AST__POINTERTYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1P( this, key, 1, &( ((Entry0P *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1P *)mapentry)->value; \
+ raw_size = sizeof( void * ); \
+\
+ } else if( raw_type == AST__FLOATTYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1F( this, key, 1, &( ((Entry0F *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1F *)mapentry)->value; \
+ raw_size = sizeof( float ); \
+\
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1C( this, key, 1, &( ((Entry0C *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1C *)mapentry)->value; \
+ raw_size = sizeof( const char * ); \
+\
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ if( nel == 0 ) { \
+ astMapPut1A( this, key, 1, &( ((Entry0A *)mapentry)->value ), \
+ mapentry->comment ); \
+ mapentry = SearchTableEntry( this, itab, key, status ); \
+ nel = 1; \
+ } \
+ raw = ((Entry1A *)mapentry)->value; \
+ raw_size = sizeof( AstObject * ); \
+\
+ } else { \
+ raw_size = 0; \
+ raw = NULL; \
+ astError( AST__INTER, "astMapPutElem<X>(KeyMap): Illegal map entry " \
+ "data type %d encountered (internal AST programming " \
+ "error).", status, raw_type ); \
+ } \
+\
+/* If the requested element is outside the bounds of the vector, extend \
+ the vector by one element. */ \
+ new = ( elem >= nel || elem < 0 ); \
+ if( new ) { \
+ elem = nel++; \
+ raw = astGrow( raw, nel, raw_size ); \
+ if( astOK ) { \
+ mapentry->nel = nel; \
+ if( raw_type == AST__INTTYPE ){ \
+ ((Entry1I *)mapentry)->value = (int *) raw; \
+ } else if( raw_type == AST__SINTTYPE ){ \
+ ((Entry1S *)mapentry)->value = (short int *) raw; \
+ } else if( raw_type == AST__BYTETYPE ){ \
+ ((Entry1B *)mapentry)->value = (unsigned char *) raw; \
+ } else if( raw_type == AST__DOUBLETYPE ){ \
+ ((Entry1D *)mapentry)->value = (double *) raw; \
+ } else if( raw_type == AST__POINTERTYPE ){ \
+ ((Entry1P *)mapentry)->value = (void *) raw; \
+ } else if( raw_type == AST__FLOATTYPE ){ \
+ ((Entry1F *)mapentry)->value = (float *) raw; \
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ ((Entry1C *)mapentry)->value = (const char **) raw; \
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ ((Entry1A *)mapentry)->value = (AstObject **) raw; \
+ } \
+ } \
+ } \
+\
+/* Get a pointer to the requested element. */ \
+ if( astOK ) { \
+ raw = (char *) raw + elem*raw_size; \
+\
+/* Free any memory used by the value already in the requested element. */ \
+ if( ! new ) { \
+ if( raw_type == AST__STRINGTYPE ){ \
+ char **cp = (char **) raw; \
+ *cp = astFree( *cp ); \
+ } else if( raw_type == AST__OBJECTTYPE ){ \
+ AstObject **op = (AstObject **) raw; \
+ if( *op ) *op = astAnnul( *op ); \
+ } \
+ } \
+\
+/* Convert the supplied value, storing the result in the requested element. \
+ Report an error if conversion is not possible. */ \
+ if( !ConvertValue( &value, Itype, raw, raw_type, status ) && astOK ){ \
+ astError( AST__MPPER, "astMapPutElem" #X "(%s): The supplied " \
+ "value cannot be converted to the data type of " \
+ "KeyMap key \"%s\".", status, astGetClass( this ), \
+ key ); \
+\
+/* For strings, the "raw" value is a copy of a pointer stored in the global \
+ "convertvalue_strings" array. These pointers should never be freed other \
+ than within the ConvertValue function (otherwise you can end up with \
+ spurious "invalid pointer" errors). But the "raw" value will be freed \
+ when as part of the KeyMap when the KeyMap is destroyed. So we replace \
+ the "raw" value with a new copy. */ \
+ } else if( raw_type == AST__STRINGTYPE ){ \
+ char **cp = (char **) raw; \
+ *cp = astStore( NULL, *cp, strlen( *cp ) + 1 ); \
+ } \
+ } \
+ } \
+}
+
+/* Define macros which perform any necessary checks on the supplied value
+ to be stored. For Object entries, check that we are not adding a KeyMap
+ which already contains "this". This avoids circular dependencies.
+ Other types do not need any checks. */
+#define CHECK_A CheckCircle( this, value, "astMapPutElemA", status );
+#define CHECK_I
+#define CHECK_B
+#define CHECK_S
+#define CHECK_D
+#define CHECK_F
+#define CHECK_C
+#define CHECK_P
+
+/* Expand the above macro to generate a function for each required
+ data type. */
+MAKE_MAPPUTELEM(I,int,AST__INTTYPE)
+MAKE_MAPPUTELEM(D,double,AST__DOUBLETYPE)
+MAKE_MAPPUTELEM(F,float,AST__FLOATTYPE)
+MAKE_MAPPUTELEM(A,AstObject *,AST__OBJECTTYPE)
+MAKE_MAPPUTELEM(P,void *,AST__POINTERTYPE)
+MAKE_MAPPUTELEM(C,const char *,AST__STRINGTYPE)
+MAKE_MAPPUTELEM(S,short int,AST__SINTTYPE)
+MAKE_MAPPUTELEM(B,unsigned char,AST__BYTETYPE)
+
+/* Undefine the macro. */
+#undef MAKE_MAPPUTELEM
+#undef CHECK_A
+#undef CHECK_I
+#undef CHECK_B
+#undef CHECK_S
+#undef CHECK_D
+#undef CHECK_F
+#undef CHECK_C
+#undef CHECK_P
+
+
+static int MapType( AstKeyMap *this, const char *skey, int *status ) {
+/*
+*++
+* Name:
+c astMapType
+f AST_MAPTYPE
+
+* Purpose:
+* Get the data type of an entry in a KeyMap.
+
+* Type:
+* Public virtual function.
+
+* Synopsis:
+c #include "keymap.h"
+c int astMapType( AstKeyMap *this, const char *key )
+f RESULT = AST_MAPTYPE( THIS, KEY, STATUS )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns a value indicating the data type of a
+* named entry in a KeyMap. This is the data type which was used when the
+* entry was added to the KeyMap.
+
+* Parameters:
+c this
+f THIS = INTEGER (Given)
+* Pointer to the KeyMap.
+c key
+f KEY = CHARACTER * ( * ) (Given)
+* The character string identifying the KeyMap entry. Trailing
+* spaces are ignored.
+* The supplied string is converted to upper case before use if the
+* KeyCase attribute is currently set to zero.
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astMapType()
+f AST_MAPTYPE = INTEGER
+* One of AST__INTTYPE (for integer), AST__SINTTYPE (for
+c short int),
+f INTEGER*2),
+* AST__BYTETYPE (for unsigned bytes
+c - i.e. unsigned chars
+* ) AST__DOUBLETYPE (for double
+* precision floating point), AST__FLOATTYPE (for single
+* precision floating point), AST__STRINGTYPE (for character string),
+* AST__OBJECTTYPE (for AST Object pointer), AST__POINTERTYPE (for
+* arbitrary C pointer) or AST__UNDEFTYPE (for undefined values
+* created by
+c astMapPutU).
+f AST_MAPPUTU).
+* AST__BADTYPE is returned if the supplied key is not found in the KeyMap.
+
+* Notes:
+* - A function value of AST__BADTYPE will be returned if an error has
+* already occurred, or if this function should fail for any reason.
+
+*--
+*/
+
+/* Local Variables: */
+ AstMapEntry *mapentry; /* Pointer to entry in linked list */
+ const char *key; /* Pointer to key string to use */
+ char keybuf[ AST__MXKEYLEN + 1 ]; /* Buffer for upper cas key */
+ int itab; /* Index of hash table element to use */
+ int result; /* Returned value */
+ unsigned long hash; /* Full width hash value */
+
+/* Initialise */
+ result = AST__BADTYPE;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Convert the supplied key to upper case if required. */
+ key = ConvertKey( this, skey, keybuf, AST__MXKEYLEN + 1, "astMapType",
+ status );
+
+/* Use the hash function to determine the element of the hash table in
+ which the key will be stored. */
+ itab = HashFun( key, this->mapsize - 1, &hash, status );
+
+/* Search the relevent table entry for the required MapEntry. */
+ mapentry = SearchTableEntry( this, itab, key, status );
+
+/* Store the type if found. */
+ if( mapentry ) result = mapentry->type;
+
+/* If an error has occurred, return zero. */
+ if( !astOK ) result = AST__BADTYPE;
+
+/* Return the result. */
+ return result;
+
+}
+
+static const char *MapIterate( AstKeyMap *this, int reset, int *status ) {
+/*
+*+
+* Name:
+* astMapIterate
+
+* Purpose:
+* Iterate through the keys in a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* const char *astMapIterate( AstKeyMap *this, int reset, int *status )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* If "reset" is non-zero, this function returns a pointer to a string
+* holding the first key in the KeyMap. On subsequent invocation (if
+* reset is zero) it returns a pointer to the next key in the KeyMap. The
+* context is stored within the KeyMap structure, so calls on different
+* KeyMaps can be mixed.
+*
+* The order in which keys are returned is determined by the KeyMap
+* SortBy attribute.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* reset
+* If non-zero, return the first key in the KeyMap. Otherwise,
+* returns the key following the one returned by the previous
+* invocation of this function.
+
+* Returned Value:
+* A pointer to the null-terminated string holding the next key,
+* or NULL if there are no more keys in the KeyMap. The returned
+* string should NOT be freed or modified.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked
+* with the AST error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ AstMapEntry *entry; /* Pointer to the entry */
+ const char *key; /* Pointer value to return */
+ int itab; /* Index into hash table */
+ int sortby; /* The value of the SortBy attribute */
+
+/* Initialise. */
+ key = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return key;
+
+/* Get the SortBy value. */
+ sortby = astGetSortBy( this );
+
+/* First deal with unsorted keys. */
+ if( sortby == SORTBY_NONE ) {
+
+/* Get the index of the hash table to check first. Also get a pointer to
+ the entry within the hash table to check next. */
+ if( reset ){
+ itab = 0;
+ entry = this->table[ 0 ];
+ } else {
+ itab = this->iter_itab;
+ entry = this->iter_entry;
+ }
+
+/* Move through elements of the hash table until we have a non-null entry. */
+ while( !entry && ++itab < this->mapsize ) {
+ entry = this->table[ itab ];
+ }
+
+/* Return a pointer to the key. */
+ if( entry ) {
+ key = entry->key;
+
+/* Move on to the next entry in the unsorted linked list, saving the context
+ in the KeyMap structure. */
+ this->iter_itab = itab;
+ this->iter_entry = entry->next;
+ }
+
+/* Now deal with sorted keys. */
+ } else {
+
+/* If starting from the beginning, use the "first" entry. Otherwise, use
+ the nxt entry. */
+ if( reset ) {
+ entry = this->first;
+ } else {
+ entry = this->iter_entry;
+ }
+
+/* If we have an entry, return a pointer to its key, and then update the
+ context to point to the next entry in the *sorted* list. */
+ if( entry ) {
+ key = entry->key;
+ this->iter_entry = entry->snext;
+ }
+ }
+
+/* If no more entries were found, reset the context in the KeyMap
+ structure. */
+ if( ! key ) {
+ this->iter_itab = 0;
+ this->iter_entry = NULL;
+ }
+
+/* Return the result.*/
+ return key;
+}
+
+static void NewTable( AstKeyMap *this, int size, int *status ){
+/*
+* Name:
+* NewTable
+
+* Purpose:
+* Create a new hash table.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void NewTable( AstKeyMap *this, int size, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function removes any existing hash table and allocates memory
+* for a new one of the specified size (except that the supplied size
+* is modified to be the next higher power of 2). The table is
+* initialised to indicate that it is empty.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* size
+* The reuqired size of the hash table.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ int i;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Ensure the table size is at least MIN_TABLE_SIZE and is a power of 2. */
+ if( size <= MIN_TABLE_SIZE ) {
+ size = MIN_TABLE_SIZE;
+ } else {
+ size = (int) ( 0.5 + pow( 2.0, ceil( log( size )/log( 2.0 ) ) ) );
+ }
+
+/* Remove any existing entries. */
+ for( i = 0; i < this->mapsize; i++ ) FreeTableEntry( this, i, status );
+
+/* Do nothing more if the table size is not changing. */
+ if( size != this->mapsize ) {
+
+/* Modify the size of the existing table. */
+ this->mapsize = size;
+ this->table = astGrow( this->table, size, sizeof( AstMapEntry * ) );
+ this->nentry = astGrow( this->nentry, size, sizeof( int ) );
+
+/* Initialise the new table. */
+ if( astOK ) {
+ for( i = 0; i < size; i++ ) {
+ this->table[ i ] = NULL;
+ this->nentry[ i ] = 0;
+ }
+ }
+ }
+}
+
+static void RemoveFromObjectList( AstKeyMap *this, AstMapEntry *entry,
+ int *status ){
+/*
+* Name:
+* RemoveFromObjectList
+
+* Purpose:
+* Remove an entry from the linked-list of AST__OBJECTTYPE entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void RemoveFromObjectList( AstKeyMap *this, AstMapEntry *entry,
+* int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function removes the supplied MapEntry from the linked list of
+* AST__OBJECTTYPE entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* entry
+* Pointer to the MapEntry to be removed.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *a; /* Previous entry */
+ AstMapEntry *b; /* Next entry */
+ Entry0A *scalar; /* Pointer to a scalar AST__OBJECTTYPE entry */
+ Entry1A *vector; /* Pointer to a vector AST__OBJECTTYPE entry */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Do nothing if the entry does not hold AST Object pointers. */
+ if( entry->type == AST__OBJECTTYPE ) {
+
+/* Get pointers to the MapEntries before and after the entry being
+ removed. At the same time, nullify both pointers in the entry itself. */
+ if( entry->nel == 0 ) {
+ scalar = (Entry0A *) entry;
+ a = scalar->prev;
+ b = scalar->next;
+ scalar->prev = NULL;
+ scalar->next = NULL;
+ } else {
+ vector = (Entry1A *) entry;
+ a = vector->prev;
+ b = vector->next;
+ vector->prev = NULL;
+ vector->next = NULL;
+ }
+
+/* Set the forward link in the previous entry. */
+ if( a ) {
+ if( a->nel == 0 ) {
+ scalar = (Entry0A *) a;
+ scalar->next = b;
+ } else {
+ vector = (Entry1A *) a;
+ vector->next = b;
+ }
+
+/* If we are removing the list head, store the following entry as the new head. */
+ } else {
+ this->firstA = b;
+ }
+
+/* Set the backward link in the next entry. */
+ if( b ) {
+ if( b->nel == 0 ) {
+ scalar = (Entry0A *) b;
+ scalar->prev = a;
+ } else {
+ vector = (Entry1A *) b;
+ vector->prev = a;
+ }
+ }
+ }
+}
+
+static void RemoveFromSortedList( AstKeyMap *this, AstMapEntry *entry,
+ int *status ){
+/*
+* Name:
+* RemoveFromSortedList
+
+* Purpose:
+* Remove an entry from the linked-list of sorted KeyMap entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void RemoveFromSortedList( AstKeyMap *this, AstMapEntry *entry,
+* int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function removes the supplied MapEntry from the linked list of
+* sorted MapEntries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* entry
+* Pointer to the MapEntry to be removed.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Next higher MapEntry */
+ AstMapEntry *prev; /* Next lower MapEntry */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get pointers to the entries on either side of the entry to be removed. */
+ next = entry->snext;
+ prev = entry->sprev;
+
+/* If the entry is not in the sorted list, abort. */
+ if( next && prev ) {
+
+/* Connect the previous to the next, bypassing the entry being removed. */
+ next->sprev = prev;
+ prev->snext = next;
+
+/* NULLify the next and previous entries stored in the entry being
+ removed. */
+ entry->snext = NULL;
+ entry->sprev = NULL;
+
+/* Decrement the number of entries in the sorted list. */
+ (this->nsorted)--;
+
+/* If the entry being removed is the first entry, store a pointer to the new
+ first entry. */
+ if( this->nsorted == 0 ) {
+ this->first = NULL;
+ } else if( entry == this->first ) {
+ this->first = next;
+ }
+ }
+}
+
+static AstMapEntry *RemoveTableEntry( AstKeyMap *this, int itab,
+ const char *key, int *status ){
+/*
+* Name:
+* RemoveTableEntry
+
+* Purpose:
+* Remove an entry from a linked-list of KeyMap entries.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstMapEntry *RemoveTableEntry( AstKeyMap *this, int itab,
+* const char *key, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function removes any entries with the specified key from the
+* linked-list of entries stored at the specified entry of the hash
+* table. If the supplied key is found in the list, a pointer to the
+* first removed entry is returned. Otherwise, a NULL pointer is returned.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* itab
+* Index of the hash table element to be searched.
+* key
+* The key string to be searched for. Trailing spaces are ignored.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the removed Entry, or NULL if no matching entry found.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry **link; /* Address to store foward link */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+ AstMapEntry *result;
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* The "next" variable holds the address of the next MapEntry to be
+ checked. Initialise this to the MapEntry at the head of the linked
+ list associated with the supplied element of the hash table. */
+ next = this->table[ itab ];
+
+/* The "link" variable holds the address of the location at which the
+ pointer to the MapEntry following the removed MapEntry should be stored.
+ Initialise this to be the address of the hash table element. */
+ link = &( this->table[ itab ] );
+
+/* Loop round until we have checked all entries. */
+ while( next && astOK ) {
+
+/* If the key for the current entry macthes the supplied key... */
+ if( !KeyCmp( next->key, key ) ) {
+
+/* Remove the MapEntry from the list sorted by key. */
+ RemoveFromSortedList( this, next, status );
+
+/* If the entry is of type AST__OBJECTTYPE, remove it from the
+ list of AST__OBJECTTYPE entries. */
+ RemoveFromObjectList( this, next, status );
+
+/* Store a pointer to the next MapEntry in the list, replacing the
+ original pointer to the MapEntry which is being deleted. */
+ *link = next->next;
+
+/* Return a pointer to the first matching MapEntry. Free any subsequent
+ matching MapEntries. */
+ if( result ) {
+ FreeMapEntry( next, status );
+ } else {
+ result = next;
+ }
+
+/* Decrement the number of entries in the linked list. */
+ this->nentry[ itab ]--;
+
+/* Set up the next MapEntry to be freed. */
+ next = *link;
+
+/* If the key for the current entry does not match the supplied key... */
+ } else {
+
+/* Update the address at which to store the pointer to the next MapEntry
+ in the list. */
+ link = &(next->next);
+
+/* Update the address of the next MapEntry in the list. */
+ next = next->next;
+ }
+ }
+
+/* Return the result */
+ return result;
+}
+
+static AstMapEntry *SearchTableEntry( AstKeyMap *this, int itab, const char *key, int *status ){
+/*
+* Name:
+* SearchTableEntry
+
+* Purpose:
+* Search an element of a has table for a given key.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstMapEntry *SearchTableEntry( AstKeyMap *this, int itab, const char *key, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function searches the specified element of the KeyMaps hash table
+* until an element is found which has a key matching the supplied key.
+* The address of this entry is returned. If no suitable entry is found,
+* then NULL is returned.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* itab
+* The index of the hash table to be searched.
+* key
+* The key string to be searched for. Trailing spaces are ignored.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The address of the first MapEntry in the linked list which refers
+* to the given key, or NULL if the key is not found.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Pointer to next Entry to check */
+ AstMapEntry *result; /* Returned pointer */
+
+/* Initialise */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* The "next" variable holds the address of the next MapEntry to be
+ checked. Initialise this to the supplied MapEntry. */
+ next = this->table[ itab ];
+
+/* Loop round until we have checked all entries. */
+ while( next ) {
+
+/* If the key for the current entry matches the supplied key, store the
+ MapEntry pointer and break. */
+ if( !KeyCmp( next->key, key ) ) {
+ result = next;
+ break;
+ }
+
+/* Update the address of the next MapEntry in the list. */
+ next = next->next;
+
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
+/*
+* Name:
+* SetAttrib
+
+* Purpose:
+* Set an attribute value for a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void SetAttrib( AstObject *this, const char *setting )
+
+* Class Membership:
+* KeyMap member function (over-rides the astSetAttrib protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function assigns an attribute value for a KeyMap, the
+* attribute and its value being specified by means of a string of
+* the form:
+*
+* "attribute= value "
+*
+* Here, "attribute" specifies the attribute name and should be in
+* lower case with no white space present. The value to the right
+* of the "=" should be a suitable textual representation of the
+* value to be assigned and this will be interpreted according to
+* the attribute's data type. White space surrounding the value is
+* only significant for string attributes.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* setting
+* Pointer to a null-terminated string specifying the new attribute
+* value.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+ int ival; /* Attribute value */
+ int len; /* Length of setting string */
+ int nc; /* Number of characters read by astSscanf */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Obtain the length of the setting string. */
+ len = (int) strlen( setting );
+
+/* Test for each recognised attribute in turn, using "astSscanf" to parse
+ the setting string and extract the attribute value (or an offset to
+ it in the case of string values). In each case, use the value set
+ in "nc" to check that the entire string was matched. Once a value
+ has been obtained, use the appropriate method to set it. */
+
+/* SizeGuess. */
+/* ---------- */
+ if ( nc = 0,
+ ( 1 == astSscanf( setting, "sizeguess= %d %n", &ival, &nc ) )
+ && ( nc >= len ) ) {
+ astSetSizeGuess( this, ival );
+
+/* KeyCase. */
+/* --------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "keycase= %d %n", &ival, &nc ) )
+ && ( nc >= len ) ) {
+ astSetKeyCase( this, ival );
+
+/* KeyError. */
+/* --------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "keyerror= %d %n", &ival, &nc ) )
+ && ( nc >= len ) ) {
+ astSetKeyError( this, ival );
+
+/* MapLocked. */
+/* --------- */
+ } else if ( nc = 0,
+ ( 1 == astSscanf( setting, "maplocked= %d %n", &ival, &nc ) )
+ && ( nc >= len ) ) {
+ astSetMapLocked( this, ival );
+
+/* SortBy. */
+/* ------- */
+ } else if ( nc = 0,
+ ( 0 == astSscanf( setting, "sortby= %n%*s %n", &ival, &nc ) )
+ && ( nc >= len ) ) {
+ astSetSortBy( this, SortByInt( setting + ival, "astSetAttrib", status ) );
+
+/* If the attribute is still not recognised, pass it on to the parent
+ method for further interpretation. */
+ } else {
+ (*parent_setattrib)( this_object, setting, status );
+ }
+}
+
+static void SetKeyCase( AstKeyMap *this, int keycase, int *status ) {
+/*
+*+
+* Name:
+* astSetKeyCase
+
+* Purpose:
+* Set the value of the KeyCase attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetKeyCase( AstKeyMap *this, int keycase )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function sets a new value for the KeyCase attribute of a
+* KeyMap. It reports an error if the KeyMap contains any entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* keycase
+* The new attribute value.
+
+*-
+*/
+
+/* Local Variables: */
+ int ok; /* Can the KeyCase value be changed? */
+ int itab; /* Index into hash table */
+ int newval; /* New KeyCase value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Normalise the new value */
+ newval = keycase ? 1 : 0;
+
+/* If the KeyCase value is to be changed, see if the KeyMap is empty. */
+ ok = 1;
+ if( astGetKeyCase( this ) != newval ) {
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+ if( this->nentry[ itab ] > 0 ) {
+ ok = 0;
+ break;
+ }
+ }
+ }
+
+/* If not report an error. */
+ if( !ok ) {
+ astError( AST__NOWRT, "astSetAttrib(KeyMap): Illegal attempt to "
+ "change the KeyCase attribute of a non-empty KeyMap." , status);
+
+/* Otherwise, store the new value. */
+ } else {
+ this->keycase = newval;
+ }
+}
+
+static void SetKeyError( AstKeyMap *this, int keyerror, int *status ) {
+/*
+*+
+* Name:
+* astSetKeyError
+
+* Purpose:
+* Set the value of the KeyError attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetKeyError( AstKeyMap *this, int keyerror )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function sets the value of the KeyError attribute for a
+* KeyMap. It also sets the attribute recursively in any KeyMaps
+* contained within the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* keyerror
+* The new value for the attribute.
+*-
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+ AstObject **obj_list; /* List of pointers to AST Object entries */
+ int i; /* Index into hash table */
+ int iel; /* Index of current vector element */
+ int nel; /* Number of elements in vector */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Set the KeyError value in the supplied KeyMap. */
+ this->keyerror = keyerror ? 1 : 0;
+
+/* Loop round each entry in the hash table. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry. */
+ next = this->table[ i ];
+
+/* Loop round all entries in this element of the hash table. */
+ while( next && astOK ) {
+
+/* If this entry has an Object data type, see if holds any KeyMaps. */
+ if( next->type == AST__OBJECTTYPE ) {
+
+/* Get the number of objects to check, and a pointer to the first. */
+ nel = next->nel;
+ if( nel == 0 ) {
+ obj_list = &( ((Entry0A *)next)->value );
+ nel = 1;
+ } else {
+ obj_list = ((Entry1A *)next)->value;
+ }
+
+/* Loop round checking all Objects. */
+ for( iel = 0; iel < nel; iel++ ) {
+
+/* If this Object is a KeyMap, set its KeyError attribute. */
+ if( astIsAKeyMap( obj_list[ iel ] ) ) {
+ astSetKeyError( (AstKeyMap *) obj_list[ iel ], keyerror );
+ }
+ }
+ }
+
+/* Get a pointer to the next entry. */
+ next = next->next;
+ }
+ }
+}
+
+static void SetMapLocked( AstKeyMap *this, int maplocked, int *status ) {
+/*
+*+
+* Name:
+* astSetMapLocked
+
+* Purpose:
+* Set the value of the MapLocked attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetMapLocked( AstKeyMap *this, int maplocked )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function sets the value of the MapLocked attribute for a
+* KeyMap. It also sets the attribute recursively in any KeyMaps
+* contained within the supplied KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* maplocked
+* The new value for the attribute.
+*-
+*/
+
+/* Local Variables: */
+ AstMapEntry *next; /* Pointer to next Entry to copy */
+ AstObject **obj_list; /* List of pointers to AST Object entries */
+ int i; /* Index into hash table */
+ int iel; /* Index of current vector element */
+ int nel; /* Number of elements in vector */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Set the MapLocked value in the supplied KeyMap. */
+ this->maplocked = maplocked ? 1 : 0;
+
+/* Loop round each entry in the hash table. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry. */
+ next = this->table[ i ];
+
+/* Loop round all entries in this element of the hash table. */
+ while( next && astOK ) {
+
+/* If this entry has an Object data type, see if holds any KeyMaps. */
+ if( next->type == AST__OBJECTTYPE ) {
+
+/* Get the number of objects to check, and a pointer to the first. */
+ nel = next->nel;
+ if( nel == 0 ) {
+ obj_list = &( ((Entry0A *)next)->value );
+ nel = 1;
+ } else {
+ obj_list = ((Entry1A *)next)->value;
+ }
+
+/* Loop round checking all Objects. */
+ for( iel = 0; iel < nel; iel++ ) {
+
+/* If this Object is a KeyMap, set its MapLocked attribute. */
+ if( astIsAKeyMap( obj_list[ iel ] ) ) {
+ astSetMapLocked( (AstKeyMap *) obj_list[ iel ], maplocked );
+ }
+ }
+ }
+
+/* Get a pointer to the next entry. */
+ next = next->next;
+ }
+ }
+}
+
+static void SetSizeGuess( AstKeyMap *this, int sizeguess, int *status ) {
+/*
+*+
+* Name:
+* astSetSizeGuess
+
+* Purpose:
+* Set the value of the SizeGuess attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetSizeGuess( AstKeyMap *this, int sizeguess )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function sets a new value for the SizeGuess attribute of a
+* KeyMap. It reports an error if the KeyMap contains any entries.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* sizeguess
+* The new attribute value.
+
+*-
+*/
+
+/* Local Variables: */
+ int empty; /* Is the KeyMap empty? */
+ int itab; /* Index into hash table */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* See if the KeyMap is empty. */
+ empty = 1;
+ for( itab = 0; itab < this->mapsize; itab++ ) {
+ if( this->nentry[ itab ] > 0 ) {
+ empty = 0;
+ break;
+ }
+ }
+
+/* If not report an error. */
+ if( !empty ) {
+ astError( AST__NOWRT, "astSetAttrib(KeyMap): Illegal attempt to "
+ "change the SizeGuess attribute of a non-empty KeyMap." , status);
+
+/* Otherwise, store the new value and change the size of the hash
+ table. */
+ } else {
+ this->sizeguess = sizeguess;
+ NewTable( this, sizeguess/MAX_ENTRIES_PER_TABLE_ENTRY, status );
+ }
+}
+
+static void SetSortBy( AstKeyMap *this, int sortby, int *status ) {
+/*
+*+
+* Name:
+* astSetSortBy
+
+* Purpose:
+* Set the value of the SortBy attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* void astSetSortBy( AstKeyMap *this, int sortby )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function sets the value of the SortBy attribute for a
+* KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* sortby
+* The new value for the attribute.
+*-
+*/
+
+/* Local Variables: */
+ int oldval; /* The old sortby value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Get the old SortBy value. */
+ oldval = astGetSortBy( this );
+
+/* Set the new SortBy value. */
+ this->sortby = sortby;
+
+/* If the value has changed, re-sort the keys. */
+ if( oldval != sortby ) SortEntries( this, status );
+
+}
+
+static size_t SizeOfEntry( AstMapEntry *entry, int *status ){
+/*
+* Name:
+* SizeOfEntry
+
+* Purpose:
+* Return the size of the supplied MapEntry structure.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* size_t SizeOfEntry( AstMapEntry *entry, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function returns the size of the supplied MapEntry structure.
+
+* Parameters:
+* entry
+* Pointer to the MapEntry.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The size of the MapEntry structure. This does not include the size
+* of any data for which pointers are stored in the MapEntry structure.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*/
+
+/* Local Variables: */
+ size_t result; /* Returned value */
+ int nel; /* Entry length */
+ int type; /* Data type */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status and the supplied pointer. */
+ if ( !astOK || !entry ) return result;
+
+/* Get the data type and length of the MapEntry. */
+ type = entry->type;
+ nel = entry->nel;
+
+/* Deal with each type. */
+ if( type == AST__STRINGTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0C ) : sizeof( Entry1C );
+
+ } else if( type == AST__OBJECTTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0A ) : sizeof( Entry1A );
+
+ } else if( type == AST__INTTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0I ) : sizeof( Entry1I );
+
+ } else if( type == AST__POINTERTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0P ) : sizeof( Entry1P );
+
+ } else if( type == AST__SINTTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0S ) : sizeof( Entry1S );
+
+ } else if( type == AST__BYTETYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0B ) : sizeof( Entry1B );
+
+ } else if( type == AST__DOUBLETYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0D ) : sizeof( Entry1D );
+
+ } else if( type == AST__FLOATTYPE ) {
+ result = ( nel == 0 ) ? sizeof( Entry0F ) : sizeof( Entry1F );
+
+ } else if( type == AST__UNDEFTYPE ) {
+ result = sizeof( AstMapEntry );
+
+/* Report an error if the data type is unknown. */
+ } else {
+ astError( AST__INTER, "SizeOfEntry(KeyMap): Illegal map entry data "
+ "type %d encountered (internal AST programming error).", status,
+ type );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static int SortByInt( const char *sortby, const char *method, int *status ){
+/*
+* Name:
+* SortByInt
+
+* Purpose:
+* Get the integer associated with a string SortBy value.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int SortByInt( const char *sortby, const char *method, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function returns the integer associated with the supplied
+* string SortBy value.
+
+* Parameters:
+* sortby
+* Pointer to the string SortBy value (case insensitive).
+* method
+* Pointer to a string holding the name of the calling method for
+* inclusion in error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* The associated SortBy integer.
+
+*/
+
+/* Local Variables: */
+ int result; /* The returned integer */
+
+/* Initialise. */
+ result = SORTBY_NONE;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Check each known value. */
+ if( astChrMatch( sortby, "None" ) ) {
+ result = SORTBY_NONE;
+
+ } else if( astChrMatch( sortby, "AgeUp" ) ) {
+ result = SORTBY_AGEUP;
+
+ } else if( astChrMatch( sortby, "AgeDown" ) ) {
+ result = SORTBY_AGEDOWN;
+
+ } else if( astChrMatch( sortby, "KeyAgeUp" ) ) {
+ result = SORTBY_KEYAGEUP;
+
+ } else if( astChrMatch( sortby, "KeyAgeDown" ) ) {
+ result = SORTBY_KEYAGEDOWN;
+
+ } else if( astChrMatch( sortby, "KeyUp" ) ) {
+ result = SORTBY_KEYUP;
+
+ } else if( astChrMatch( sortby, "KeyDown" ) ) {
+ result = SORTBY_KEYDOWN;
+
+ } else {
+ astError( AST__INTER, "%s(KeyMap): Illegal SortBy value %s "
+ "encountered.", status, method, sortby );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static const char *SortByString( int sortby, const char *method, int *status ){
+/*
+* Name:
+* SortByString
+
+* Purpose:
+* Get the string associated with an integer SortBy value.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* const char *SortByString( int sortby, const char *method, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function returns the string associated with the supplied
+* integer SortBy value.
+
+* Parameters:
+* sortby
+* The integer SortBy value.
+* method
+* Pointer to a string holding the name of the calling method for
+* inclusion in error messages.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* Pointer to the associated SortBy string.
+
+*/
+
+/* Local Variables: */
+ const char *result; /* The returned string */
+
+/* Initialise. */
+ result = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Check each value. */
+ if( sortby == SORTBY_NONE ) {
+ result = "None";
+
+ } else if( sortby == SORTBY_AGEUP ) {
+ result = "AgeUp";
+
+ } else if( sortby == SORTBY_AGEDOWN ) {
+ result = "AgeDown";
+
+ } else if( sortby == SORTBY_KEYAGEUP ) {
+ result = "KeyAgeUp";
+
+ } else if( sortby == SORTBY_KEYAGEDOWN ) {
+ result = "KeyAgeDown";
+
+ } else if( sortby == SORTBY_KEYUP ) {
+ result = "KeyUp";
+
+ } else if( sortby == SORTBY_KEYDOWN ) {
+ result = "KeyDown";
+
+ } else {
+ astError( AST__INTER, "%s(KeyMap): Illegal integer SortBy value %d "
+ "encountered (internal AST programming error).", status,
+ method, sortby );
+ }
+
+/* Return the result. */
+ return result;
+}
+
+static void SortEntries( AstKeyMap *this, int *status ){
+/*
+* Name:
+* SortEntries
+
+* Purpose:
+* Ensure the entries in a KeyMap are sorted correctly.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* void SortEntries( AstKeyMap *this, int *status )
+
+* Class Membership:
+* KeyMap member function.
+
+* Description:
+* This function sorts all the entries in the supplied KeyMap in
+* the manner indicated by the SortBy attribute value in the KeyMap.
+* A double linked list is maintained indicating the ordering, with
+* the first entry in the sorted list being pointed to by "this->first".
+* Each entry contains "snext" and "sprev" pointers that point to the
+* next and previous entries in the sorted list. The number of entries
+* in the sorted list (which should usually equal the total number of
+* entries currently in the KeyMap), is stored in "this->nsorted".
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* status
+* Pointer to the inherited status variable.
+
+*/
+
+/* Local Variables: */
+ AstMapEntry **ents;
+ AstMapEntry **pent;
+ AstMapEntry **a;
+ AstMapEntry **b;
+ AstMapEntry *entry;
+ int i;
+ int nent;
+ int sortby;
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Empty the sorted list. */
+ this->nsorted = 0;
+ this->first = NULL;
+
+/* Get the SortBy value. */
+ sortby = astGetSortBy( this );
+
+/* Do nothing more if no sorting is required. */
+ if( sortby != SORTBY_NONE ) {
+
+/* Get the number of entries in the keyMap. */
+ nent = astMapSize( this );
+
+/* Only sort if the KeyMap is not empty. */
+ if( nent > 0 ) {
+
+/* Allocate an array with one element for each entry. Each element is a
+ pointer to a MapEntry structure. */
+ ents = astMalloc( sizeof( *ents )*nent );
+ if( astOK ) {
+
+/* Loop round all entries in the hash table. */
+ pent = ents;
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry. */
+ entry = this->table[ i ];
+
+/* Loop round all entries in this element of the hash table. */
+ while( entry ) {
+
+/* Store the sorting method in the MapEntry. */
+ entry->sortby = sortby;
+
+/* Put a pointer to the MapEntry into the array. */
+ *(pent++) = entry;
+
+/* Update the address of the next MapEntry in the source. */
+ entry = entry->next;
+ }
+ }
+
+/* No need for sorting if there is only one entry. */
+ if( nent == 1 ) {
+ ents[ 0 ]->snext = ents[ 0 ];
+ ents[ 0 ]->sprev = ents[ 0 ];
+
+/* Sort the array of pointers if there is more than one entry... */
+ } else {
+ qsort( ents, nent, sizeof( *ents ), CompareEntries );
+
+/* Establish the double linked list. */
+ a = ents;
+ b = ents + 1;
+ for( i = 1; i < nent; i++ ) {
+ (*b)->sprev = *a;
+ (*a)->snext = *b;
+ a = b++;
+ }
+
+ b = ents;
+ (*b)->sprev = *a;
+ (*a)->snext = *b;
+
+ }
+
+/* Store a pointer to the first entry in the sorted list. */
+ this->first = ents[ 0 ];
+
+/* Store the number of entrie sin the sorted list. */
+ this->nsorted = nent;
+ }
+
+/* Free resources. */
+ ents = astFree( ents );
+ }
+ }
+}
+
+static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
+/*
+* Name:
+* TestAttrib
+
+* Purpose:
+* Test if a specified attribute value is set for a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* int TestAttrib( AstObject *this, const char *attrib, int *status )
+
+* Class Membership:
+* KeyMap member function (over-rides the astTestAttrib protected
+* method inherited from the Mapping class).
+
+* Description:
+* This function returns a boolean result (0 or 1) to indicate whether
+* a value has been set for one of a KeyMap's attributes.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+* attrib
+* Pointer to a null-terminated string specifying the attribute
+* name. This should be in lower case with no surrounding white
+* space.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* One if a value has been set, otherwise zero.
+
+* Notes:
+* - A value of zero will be returned if this function is invoked
+* with the global status set, or if it should fail for any reason.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+ int result; /* Result value to return */
+
+/* Initialise. */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Check the attribute name and test the appropriate attribute. */
+
+/* SizeGuess. */
+/* ---------- */
+ if ( !strcmp( attrib, "sizeguess" ) ) {
+ result = astTestSizeGuess( this );
+
+/* KeyCase. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keycase" ) ) {
+ result = astTestKeyCase( this );
+
+/* KeyError. */
+/* --------- */
+ } else if ( !strcmp( attrib, "keyerror" ) ) {
+ result = astTestKeyError( this );
+
+/* MapLocked. */
+/* --------- */
+ } else if ( !strcmp( attrib, "maplocked" ) ) {
+ result = astTestMapLocked( this );
+
+/* SortBy. */
+/* ------- */
+ } else if ( !strcmp( attrib, "sortby" ) ) {
+ result = astTestSortBy( this );
+
+/* If the attribute is still not recognised, pass it on to the parent
+ method for further interpretation. */
+ } else {
+ result = (*parent_testattrib)( this_object, attrib, status );
+ }
+
+/* Return the result, */
+ return result;
+}
+
+static int TestSizeGuess( AstKeyMap *this, int *status ) {
+/*
+*+
+* Name:
+* astTestSizeGuess
+
+* Purpose:
+* Test the value of the SizeGuess attribute for a KeyMap.
+
+* Type:
+* Protected virtual function.
+
+* Synopsis:
+* #include "keymap.h"
+* int astTestSizeGuess( AstKeyMap *this )
+
+* Class Membership:
+* KeyMap method.
+
+* Description:
+* This function returns a non-zero value if the SizeGuess attribute
+* has been set in a KeyMap.
+
+* Parameters:
+* this
+* Pointer to the KeyMap.
+
+* Returned Value:
+* Non-zero if the SizeGuess attribute is set.
+
+* Notes:
+* - A value of zero is returned if this function is invoked with the
+* global error status set.
+
+*-
+*/
+
+/* Local Variables: */
+ int result; /* Returned value */
+
+/* Initialise */
+ result = 0;
+
+/* Check the global error status. */
+ if ( !astOK ) return result;
+
+/* Return non-zero if the attribute is still set to its "not set" value. */
+ return ( this->sizeguess != INT_MAX );
+}
+
+/* Functions which access class attributes. */
+/* ---------------------------------------- */
+
+/*
+*att++
+* Name:
+* SizeGuess
+
+* Purpose:
+* The expected size of the KeyMap.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer.
+
+* Description:
+* This is attribute gives an estimate of the number of entries that
+* will be stored in the KeyMap. It is used to tune the internal
+* properties of the KeyMap for speed and efficiency. A larger value
+* will result in faster access at the expense of increased memory
+* requirements. However if the SizeGuess value is much larger than
+* the actual size of the KeyMap, then there will be little, if any,
+* speed gained by making the SizeGuess even larger. The default value
+* is 300.
+*
+* The value of this attribute can only be changed if the KeyMap is
+* empty. Its value can be set conveniently when creating the KeyMap.
+* An error will be reported if an attempt is made to set or clear the
+* attribute when the KeyMap contains any entries.
+
+* Applicability:
+* KeyMap
+* All KeyMaps have this attribute.
+*att--
+*/
+
+/*
+*att++
+* Name:
+* KeyCase
+
+* Purpose:
+* Are keys case sensitive?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* This attribute is a boolean value which controls how keys are
+* used. If KeyCase is zero, then key strings supplied to any method
+* are automatically converted to upper case before being used. If
+* KeyCase is non-zero (the default), then supplied key strings are
+* used without modification.
+*
+* The value of this attribute can only be changed if the KeyMap is
+* empty. Its value can be set conveniently when creating the KeyMap.
+* An error will be reported if an attempt is made to change the
+* attribute value when the KeyMap contains any entries.
+
+* Applicability:
+* KeyMap
+* All KeyMaps have this attribute.
+* Table
+* The Table class over-rides this attribute by forcing it to zero.
+* That is, keys within a Table are always case insensitive.
+*att--
+*/
+astMAKE_GET(KeyMap,KeyCase,int,1,(this->keycase == -1 ? 1 : this->keycase))
+astMAKE_TEST(KeyMap,KeyCase,( this->keycase != -1 ))
+
+/*
+*att++
+* Name:
+* KeyError
+
+* Purpose:
+* Report an error when getting the value of a non-existant KeyMap entry?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* This attribute is a boolean value which controls how the
+c astMapGet...
+f AST_MAPGET...
+* functions behave if the requested key is not found in the KeyMap.
+* If KeyError is zero (the default), then these functions will return
+c zero
+f .FALSE.
+* but no error will be reported. If KeyError is non-zero, then the
+* same values are returned but an error is also reported.
+
+* Notes:
+* - When setting a new value for KeyError, the supplied value is
+* propagated to any KeyMaps contained within the supplied KeyMap.
+* - When clearing the KeyError attribute, the attribute is also
+* cleared in any KeyMaps contained within the supplied KeyMap.
+
+* Applicability:
+* KeyMap
+* All KeyMaps have this attribute.
+*att--
+*/
+astMAKE_GET(KeyMap,KeyError,int,0,( ( this->keyerror != -INT_MAX ) ?
+ this->keyerror : 0 ))
+astMAKE_TEST(KeyMap,KeyError,( this->keyerror != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* MapLocked
+
+* Purpose:
+* Prevent new entries being added to a KeyMap?
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* Integer (boolean).
+
+* Description:
+* If this boolean attribute is set to
+c a non-zero value,
+f .TRUE.,
+* an error will be reported if an attempt is made to add a new entry
+* to the KeyMap. Note, the value associated with any existing entries
+* can still be changed, but no new entries can be stored in the KeyMap.
+* The default value
+c (zero)
+f (.FALSE.)
+* allows new entries to be added to the KeyMap.
+
+* Notes:
+* - When setting a new value for MapLocked, the supplied value is
+* propagated to any KeyMaps contained within the supplied KeyMap.
+* - When clearing the MapLocked attribute, the attribute is also
+* cleared in any KeyMaps contained within the supplied KeyMap.
+
+* Applicability:
+* KeyMap
+* All KeyMaps have this attribute.
+*att--
+*/
+astMAKE_GET(KeyMap,MapLocked,int,0,( ( this->maplocked != -INT_MAX ) ?
+ this->maplocked : 0 ))
+astMAKE_TEST(KeyMap,MapLocked,( this->maplocked != -INT_MAX ))
+
+/*
+*att++
+* Name:
+* SortBy
+
+* Purpose:
+* Determines how keys are sorted in a KeyMap.
+
+* Type:
+* Public attribute.
+
+* Synopsis:
+* String.
+
+* Description:
+* This attribute determines the order in which keys are returned by the
+c astMapKey
+f AST_MAPKEY
+* function. It may take the following values (the default is "None"):
+*
+* - "None": The keys are returned in an arbitrary order. This is the
+* fastest method as it avoids the need for a sorted list of keys to
+* be maintained and used.
+*
+* - "AgeDown": The keys are returned in the order in which values were
+* stored in the KeyMap, with the key for the most recent value being
+* returned last. If the value of an existing entry is changed, it goes
+* to the end of the list.
+*
+* - "AgeUp": The keys are returned in the order in which values were
+* stored in the KeyMap, with the key for the most recent value being
+* returned first. If the value of an existing entry is changed, it goes
+* to the top of the list.
+*
+* - "KeyAgeDown": The keys are returned in the order in which they
+* were originally stored in the KeyMap, with the most recent key being
+* returned last. If the value of an existing entry is changed, its
+* position in the list does not change.
+*
+* - "KeyAgeUp": The keys are returned in the order in which they
+* were originally stored in the KeyMap, with the most recent key being
+* returned first. If the value of an existing entry is changed, its
+* position in the list does not change.
+*
+* - "KeyDown": The keys are returned in alphabetical order, with "A..."
+* being returned last.
+*
+* - "KeyUp": The keys are returned in alphabetical order, with "A..."
+* being returned first.
+
+* Notes:
+* - If a new value is assigned to SortBy (or if SortBy is cleared),
+* all entries currently in the KeyMap are re-sorted according to the
+* new SortBy value.
+
+* Applicability:
+* KeyMap
+* All KeyMaps have this attribute.
+*att--
+*/
+astMAKE_GET(KeyMap,SortBy,int,SORTBY_NONE,( ( this->sortby != -INT_MAX ) ?
+ this->sortby : SORTBY_NONE ))
+astMAKE_TEST(KeyMap,SortBy,( this->sortby != -INT_MAX ))
+
+/* Copy constructor. */
+/* ----------------- */
+static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
+/*
+* Name:
+* Copy
+
+* Purpose:
+* Copy constructor for KeyMap objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Copy( const AstObject *objin, AstObject *objout, int *status )
+
+* Description:
+* This function implements the copy constructor for KeyMap objects.
+
+* Parameters:
+* objin
+* Pointer to the object to be copied.
+* objout
+* Pointer to the object being constructed.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* - This constructor makes a deep copy.
+*/
+
+/* Local Variables: */
+ AstKeyMap *in; /* Pointer to input KeyMap */
+ AstKeyMap *out; /* Pointer to output KeyMap */
+ int i; /* Index into hash table */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain pointers to the input and output KeyMap structures. */
+ in = (AstKeyMap *) objin;
+ out = (AstKeyMap *) objout;
+
+/* For safety, first clear any references to the input memory from
+ the output KeyMap. */
+ out->table = NULL;
+ out->nentry = NULL;
+ out->first = NULL;
+ out->firstA = NULL;
+
+/* Make copies of the table entries. */
+ out->table = astMalloc( sizeof( AstMapEntry * )*( out->mapsize ) );
+ out->nentry = astMalloc( sizeof( int )*( out->mapsize ) );
+
+ for( i = 0; i < out->mapsize; i++ ) CopyTableEntry( in, out, i, status );
+
+/* Create the required sorted key list in the new KeyMap. */
+ SortEntries( out, status );
+
+/* If an error occurred, clean up by freeing all memory allocated above. */
+ if ( !astOK ) {
+ for( i = 0; i < out->mapsize; i++ ) FreeTableEntry( out, i, status );
+ out->table = astFree( out->table );
+ out->nentry = astFree( out->nentry );
+ }
+}
+
+/* Destructor. */
+/* ----------- */
+static void Delete( AstObject *obj, int *status ) {
+/*
+* Name:
+* Delete
+
+* Purpose:
+* Destructor for KeyMap objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Delete( AstObject *obj, int *status )
+
+* Description:
+* This function implements the destructor for KeyMap objects.
+
+* Parameters:
+* obj
+* Pointer to the object to be deleted.
+* status
+* Pointer to the inherited status variable.
+
+* Returned Value:
+* void
+
+* Notes:
+* This function attempts to execute even if the global error status is
+* set.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+ int i; /* Loop count */
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) obj;
+
+/* Free all allocated memory. */
+ for( i = 0; i < this->mapsize; i++ ) FreeTableEntry( this, i, status );
+
+/* Free memory used to hold tables. */
+ this->table = astFree( this->table );
+ this->nentry = astFree( this->nentry );
+
+/* Nullify other pointers. */
+ this->first = NULL;
+ this->firstA = NULL;
+}
+
+/* Dump function. */
+/* -------------- */
+static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
+/*
+* Name:
+* Dump
+
+* Purpose:
+* Dump function for KeyMap objects.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* void Dump( AstObject *this, AstChannel *channel, int *status )
+
+* Description:
+* This function implements the Dump function which writes out data
+* for the KeyMap class to an output Channel.
+
+* Parameters:
+* this
+* Pointer to the KeyMap whose data are being written.
+* channel
+* Pointer to the Channel to which the data are being written.
+* status
+* Pointer to the inherited status variable.
+*/
+
+/* Local Variables: */
+ AstKeyMap *this; /* Pointer to the KeyMap structure */
+ AstMapEntry *next; /* Pointer to the next AstMapEntry to dump */
+ int i; /* Index into hash table */
+ int nentry; /* Number of entries dumped so far */
+ int set; /* Is attribute set? */
+ int ival; /* Attribute value */
+
+/* Check the global error status. */
+ if ( !astOK ) return;
+
+/* Obtain a pointer to the KeyMap structure. */
+ this = (AstKeyMap *) this_object;
+
+/* Initialise the number of KeyMap entries dumped so far. */
+ nentry = 0;
+
+/* SizeGuess. */
+/* ---------- */
+ set = TestSizeGuess( this, status );
+ ival = set ? GetSizeGuess( this, status ) : astGetSizeGuess( this );
+ astWriteInt( channel, "SzGss", set, 0, ival, "Guess at KeyMap size" );
+
+/* SortBy. */
+/* ------- */
+ set = TestSortBy( this, status );
+ ival = set ? GetSortBy( this, status ) : astGetSortBy( this );
+ astWriteString( channel, "SortBy", set, 0, SortByString( ival, "astDump",
+ status ),
+ "Sorting scheme for keys" );
+
+/* KeyCase. */
+/* --------- */
+ set = TestKeyCase( this, status );
+ ival = set ? GetKeyCase( this, status ) : astGetKeyCase( this );
+ astWriteInt( channel, "KyCas", set, 0, ival, "Are keys case sensitive?" );
+
+/* KeyError. */
+/* --------- */
+ set = TestKeyError( this, status );
+ ival = set ? GetKeyError( this, status ) : astGetKeyError( this );
+ astWriteInt( channel, "KyErr", set, 0, ival, "Report non-existant keys?" );
+
+/* MapLocked. */
+/* --------- */
+ set = TestMapLocked( this, status );
+ ival = set ? GetMapLocked( this, status ) : astGetMapLocked( this );
+ astWriteInt( channel, "MpLck", set, 0, ival, "Prevent addition of new entries?" );
+
+/* MapSize. */
+/* -------- */
+ astWriteInt( channel, "MapSz", 1, 1, this->mapsize, "Size of hash table" );
+
+/* member count. */
+ astWriteInt( channel, "MemCnt", 1, 1, this->member_count, "Total member count" );
+
+/* Loop round each entry in the hash table. */
+ for( i = 0; i < this->mapsize; i++ ) {
+
+/* Get a pointer to the next KeyMap entry to dump. */
+ next = this->table[ i ];
+
+/* Loop round dumping all KeyMap entries in this element of the hash table. */
+ while( next && astOK ) {
+ DumpEntry( next, channel, ++nentry, status );
+
+/* Get a pointer to the next entry to dump. */
+ next = next->next;
+
+ }
+ }
+}
+
+/* Standard class functions. */
+/* ========================= */
+/* Implement the astIsAKeyMap and astCheckKeyMap functions using the macros
+ defined for this purpose in the "object.h" header file. */
+astMAKE_ISA(KeyMap,Object)
+astMAKE_CHECK(KeyMap)
+
+AstKeyMap *astKeyMap_( const char *options, int *status, ...) {
+/*
+*++
+* Name:
+c astKeyMap
+f AST_KEYMAP
+
+* Purpose:
+* Create a KeyMap.
+
+* Type:
+* Public function.
+
+* Synopsis:
+c #include "keymap.h"
+c AstKeyMap *astKeyMap( const char *options, ... )
+f RESULT = AST_KEYMAP( OPTIONS, STATUS )
+
+* Class Membership:
+* KeyMap constructor.
+
+* Description:
+* This function creates a new empty KeyMap and optionally initialises its
+* attributes. Entries can then be added to the KeyMap using the
+c astMapPut0<X> and astMapPut1<X> functions.
+f AST_MAPPUT0<X> and AST_MAPPUT1<X> functions.
+*
+* The KeyMap class is used to store a set of values with associated keys
+* which identify the values. The keys are strings. These may be case
+* sensitive or insensitive as selected by the KeyCase attribute, and
+* trailing spaces are ignored. The value associated with a key can be
+* integer (signed 4 and 2 byte, or unsigned 1 byte), floating point
+* (single or double precision),
+c void pointer,
+* character string or AST Object pointer. Each
+* value can be a scalar or a one-dimensional vector. A KeyMap is
+* conceptually similar to a Mapping in that a KeyMap transforms an
+* input into an output - the input is the key, and the output is the
+* value associated with the key. However, this is only a conceptual
+* similarity, and it should be noted that the KeyMap class inherits from
+* the Object class rather than the Mapping class. The methods of the
+* Mapping class cannot be used with a KeyMap.
+
+* Parameters:
+c options
+f OPTIONS = CHARACTER * ( * ) (Given)
+c Pointer to a null-terminated string containing an optional
+c comma-separated list of attribute assignments to be used for
+c initialising the new KeyMap. The syntax used is identical to
+c that for the astSet function and may include "printf" format
+c specifiers identified by "%" symbols in the normal way.
+f A character string containing an optional comma-separated
+f list of attribute assignments to be used for initialising the
+f new KeyMap. The syntax used is identical to that for the
+f AST_SET routine.
+c ...
+c If the "options" string contains "%" format specifiers, then
+c an optional list of additional arguments may follow it in
+c order to supply values to be substituted for these
+c specifiers. The rules for supplying these are identical to
+c those for the astSet function (and for the C "printf"
+c function).
+f STATUS = INTEGER (Given and Returned)
+f The global status.
+
+* Returned Value:
+c astKeyMap()
+f AST_MAP = INTEGER
+* A pointer to the new KeyMap.
+
+* Notes:
+* - A null Object pointer (AST__NULL) will be returned if this
+c function is invoked with the AST error status set, or if it
+f function is invoked with STATUS set to an error value, or if it
+* should fail for any reason.
+
+* Status Handling:
+* The protected interface to this function includes an extra
+* parameter at the end of the parameter list descirbed above. This
+* parameter is a pointer to the integer inherited status
+* variable: "int *status".
+
+*--
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstKeyMap *new; /* Pointer to new KeyMap */
+ va_list args; /* Variable argument list */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the KeyMap, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitKeyMap( NULL, sizeof( AstKeyMap ), !class_init, &class_vtab, "KeyMap" );
+
+/* If successful, note that the virtual function table has been
+ initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the options string
+ to the astVSet method to initialise the new KeyMap's attributes. */
+ va_start( args, status );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return a pointer to the new KeyMap. */
+ return new;
+}
+
+AstKeyMap *astKeyMapId_( const char *options, ... ) {
+/*
+* Name:
+* astKeyMapId_
+
+* Purpose:
+* Create a KeyMap.
+
+* Type:
+* Private function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstKeyMap *astKeyMapId_( const char *options, ... )
+
+* Class Membership:
+* KeyMap constructor.
+
+* Description:
+* This function implements the external (public) interface to the
+* astKeyMap constructor function. It returns an ID value (instead
+* of a true C pointer) to external users, and must be provided
+* because astKeyMap_ has a variable argument list which cannot be
+* encapsulated in a macro (where this conversion would otherwise
+* occur).
+*
+* The variable argument list also prevents this function from
+* invoking astKeyMap_ directly, so it must be a re-implementation
+* of it in all respects, except for the final conversion of the
+* result to an ID value.
+
+* Parameters:
+* As for astKeyMap_.
+
+* Returned Value:
+* The ID value associated with the new KeyMap.
+*/
+
+/* Local Variables: */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ AstKeyMap *new; /* Pointer to new KeyMap */
+ va_list args; /* Variable argument list */
+
+ int *status; /* Pointer to inherited status value */
+
+/* Get a pointer to the inherited status value. */
+ status = astGetStatusPtr;
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(NULL);
+
+/* Check the global status. */
+ if ( !astOK ) return NULL;
+
+/* Initialise the KeyMap, allocating memory and initialising the
+ virtual function table as well if necessary. */
+ new = astInitKeyMap( NULL, sizeof( AstKeyMap ), !class_init, &class_vtab, "KeyMap" );
+
+/* If successful, note that the virtual function table has been
+ initialised. */
+ if ( astOK ) {
+ class_init = 1;
+
+/* Obtain the variable argument list and pass it along with the options string
+ to the astVSet method to initialise the new KeyMap's attributes. */
+ va_start( args, options );
+ astVSet( new, options, NULL, args );
+ va_end( args );
+
+/* If an error occurred, clean up by deleting the new object. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return an ID value for the new KeyMap. */
+ return astMakeId( new );
+}
+
+AstKeyMap *astInitKeyMap_( void *mem, size_t size, int init, AstKeyMapVtab *vtab,
+ const char *name, int *status ) {
+/*
+*+
+* Name:
+* astInitKeyMap
+
+* Purpose:
+* Initialise a KeyMap.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstKeyMap *astInitKeyMap( void *mem, size_t size, int init, AstKeyMapVtab *vtab,
+* const char *name )
+
+* Class Membership:
+* KeyMap initialiser.
+
+* Description:
+* This function is provided for use by class implementations to initialise
+* a new KeyMap object. It allocates memory (if necessary) to accommodate
+* the KeyMap plus any additional data associated with the derived class.
+* It then initialises a KeyMap structure at the start of this memory. If
+* the "init" flag is set, it also initialises the contents of a virtual
+* function table for a KeyMap at the start of the memory passed via the
+* "vtab" parameter.
+
+* Parameters:
+* mem
+* A pointer to the memory in which the KeyMap is to be created. This
+* must be of sufficient size to accommodate the KeyMap data
+* (sizeof(KeyMap)) plus any data used by the derived class. If a value
+* of NULL is given, this function will allocate the memory itself using
+* the "size" parameter to determine its size.
+* size
+* The amount of memory used by the KeyMap (plus derived class data).
+* This will be used to allocate memory if a value of NULL is given for
+* the "mem" parameter. This value is also stored in the KeyMap
+* structure, so a valid value must be supplied even if not required for
+* allocating memory.
+* init
+* A logical flag indicating if the KeyMap's virtual function table is
+* to be initialised. If this value is non-zero, the virtual function
+* table will be initialised by this function.
+* vtab
+* Pointer to the start of the virtual function table to be associated
+* with the new KeyMap.
+* name
+* Pointer to a constant null-terminated character string which contains
+* the name of the class to which the new object belongs (it is this
+* pointer value that will subsequently be returned by the astClass
+* method).
+
+* Returned Value:
+* A pointer to the new KeyMap.
+
+* Notes:
+* - A NULL pointer will be returned if this function is invoked with the
+* global error status set, or if it should fail for any reason.
+*-
+*/
+
+/* Local Variables: */
+ AstKeyMap *new; /* Pointer to the new KeyMap */
+
+/* Check the global error status. */
+ if ( !astOK ) return NULL;
+
+/* If necessary, initialise the virtual function table. */
+ if ( init ) astInitKeyMapVtab( vtab, name );
+
+/* Initialise an Object structure (the parent class) as the first component
+ within the KeyMap structure, allocating memory if necessary. */
+ new = (AstKeyMap *) astInitObject( mem, size, 0, (AstObjectVtab *) vtab,
+ name );
+
+ if ( astOK ) {
+
+/* Initialise the KeyMap data. */
+/* ---------------------------- */
+/* Initialise all attributes to their "undefined" values. */
+ new->sizeguess = INT_MAX;
+ new->mapsize = 0;
+ new->table = NULL;
+ new->nentry = NULL;
+ new->keycase = -1;
+ new->keyerror = -INT_MAX;
+ new->maplocked = -INT_MAX;
+ new->sortby = -INT_MAX;
+ new->first = NULL;
+ new->nsorted = 0;
+ new->member_count = 0;
+ new->firstA = NULL;
+ new->iter_itab = 0;
+ new->iter_entry = NULL;
+
+ NewTable( new, MIN_TABLE_SIZE, status );
+
+/* If an error occurred, clean up by deleting the new KeyMap. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return a pointer to the new KeyMap. */
+ return new;
+}
+
+AstKeyMap *astLoadKeyMap_( void *mem, size_t size, AstKeyMapVtab *vtab,
+ const char *name, AstChannel *channel, int *status ) {
+/*
+*+
+* Name:
+* astLoadKeyMap
+
+* Purpose:
+* Load a KeyMap.
+
+* Type:
+* Protected function.
+
+* Synopsis:
+* #include "keymap.h"
+* AstKeyMap *astLoadKeyMap( void *mem, size_t size, AstKeyMapVtab *vtab,
+* const char *name, AstChannel *channel )
+
+* Class Membership:
+* KeyMap loader.
+
+* Description:
+* This function is provided to load a new KeyMap using data read
+* from a Channel. It first loads the data used by the parent class
+* (which allocates memory if necessary) and then initialises a
+* KeyMap structure in this memory, using data read from the input
+* Channel.
+*
+* If the "init" flag is set, it also initialises the contents of a
+* virtual function table for a KeyMap at the start of the memory
+* passed via the "vtab" parameter.
+
+
+* Parameters:
+* mem
+* A pointer to the memory into which the KeyMap is to be
+* loaded. This must be of sufficient size to accommodate the
+* KeyMap data (sizeof(KeyMap)) plus any data used by derived
+* classes. If a value of NULL is given, this function will
+* allocate the memory itself using the "size" parameter to
+* determine its size.
+* size
+* The amount of memory used by the KeyMap (plus derived class
+* data). This will be used to allocate memory if a value of
+* NULL is given for the "mem" parameter. This value is also
+* stored in the KeyMap structure, so a valid value must be
+* supplied even if not required for allocating memory.
+*
+* If the "vtab" parameter is NULL, the "size" value is ignored
+* and sizeof(AstKeyMap) is used instead.
+* vtab
+* Pointer to the start of the virtual function table to be
+* associated with the new KeyMap. If this is NULL, a pointer
+* to the (static) virtual function table for the KeyMap class
+* is used instead.
+* name
+* Pointer to a constant null-terminated character string which
+* contains the name of the class to which the new object
+* belongs (it is this pointer value that will subsequently be
+* returned by the astGetClass method).
+*
+* If the "vtab" parameter is NULL, the "name" value is ignored
+* and a pointer to the string "KeyMap" is used instead.
+
+* Returned Value:
+* A pointer to the new KeyMap.
+
+* Notes:
+* - A null pointer will be returned if this function is invoked
+* with the global error status set, or if it should fail for any
+* reason.
+*-
+*/
+
+/* Local Variables: */
+ AstKeyMap *new; /* Pointer to the new KeyMap */
+ AstObject **alist; /* Pointer to vector of entry values */
+ AstObject *aval; /* AST Object value for an entry */
+ astDECLARE_GLOBALS /* Pointer to thread-specific global data */
+ char *com; /* Pointer to comment string for an entry */
+ char *key; /* Pointer to key string for an entry */
+ char *sval; /* String value for an entry */
+ char buff[ 30 ]; /* Buffer for key names */
+ const char **slist; /* Pointer to vector of entry values */
+ double *dlist; /* Pointer to vector of entry values */
+ double dval; /* Floating point value for an entry */
+ float *flist; /* Pointer to vector of entry values */
+ int *ilist; /* Pointer to vector of entry values */
+ int index; /* Index of next array element in a vector entry */
+ int ival; /* Integer value for an entry */
+ int mapsize; /* Size for new hash table */
+ int nel; /* Vector length */
+ int nentry; /* Number of KeyMap entries read so far */
+ int type; /* Data type for an entry */
+ short int *wlist; /* Pointer to vector of entry values */
+ short int wval; /* Short int value for an entry */
+ unsigned char *blist; /* Pointer to vector of entry values */
+ unsigned char bval; /* Byte value for an entry */
+
+/* Get a pointer to the thread specific global data structure. */
+ astGET_GLOBALS(channel);
+
+/* Initialise. */
+ new = NULL;
+
+/* Check the global error status. */
+ if ( !astOK ) return new;
+
+/* If a NULL virtual function table has been supplied, then this is
+ the first loader to be invoked for this KeyMap. In this case the
+ KeyMap belongs to this class, so supply appropriate values to be
+ passed to the parent class loader (and its parent, etc.). */
+ if ( !vtab ) {
+ size = sizeof( AstKeyMap );
+ vtab = &class_vtab;
+ name = "KeyMap";
+
+/* If required, initialise the virtual function table for this class. */
+ if ( !class_init ) {
+ astInitKeyMapVtab( vtab, name );
+ class_init = 1;
+ }
+ }
+
+/* Invoke the parent class loader to load data for all the ancestral
+ classes of the current one, returning a pointer to the resulting
+ partly-built KeyMap. */
+ new = astLoadObject( mem, size, (AstObjectVtab *) vtab, name, channel );
+
+ if ( astOK ) {
+
+/* Inidicate the KeyMap is empty. */
+ new->mapsize = 0;
+ new->table = NULL;
+ new->nentry = NULL;
+ new->firstA = NULL;
+ new->iter_itab = 0;
+ new->iter_entry = NULL;
+
+/* Read input data. */
+/* ================ */
+/* Request the input Channel to read all the input data appropriate to
+ this class into the internal "values list". */
+ astReadClassData( channel, "KeyMap" );
+
+/* Now read each individual data item from this list and use it to
+ initialise the appropriate instance variable(s) for this class. */
+
+/* SizeGuess. */
+/* ---------- */
+ new->sizeguess = astReadInt( channel, "szgss", INT_MAX );
+ if ( TestSizeGuess( new, status ) ) SetSizeGuess( new, new->sizeguess, status );
+
+/* KeyCase. */
+/* --------- */
+ new->keycase = astReadInt( channel, "kycas", -INT_MAX );
+ if ( TestKeyCase( new, status ) ) SetKeyCase( new, new->keycase, status );
+
+/* KeyError. */
+/* --------- */
+ new->keyerror = astReadInt( channel, "kyerr", -INT_MAX );
+ if ( TestKeyError( new, status ) ) SetKeyError( new, new->keyerror, status );
+
+/* MapLocked. */
+/* --------- */
+ new->maplocked = astReadInt( channel, "mplck", -INT_MAX );
+ if ( TestMapLocked( new, status ) ) SetMapLocked( new, new->maplocked, status );
+
+/* SortBy. */
+/* ------- */
+ sval = astReadString( channel, "sortby", " " );
+ new->sortby = -INT_MAX;
+ if( astOK && strcmp( sval, " " ) ) {
+ new->sortby = SortByInt( sval, "astRead", status );
+ }
+ if( TestSortBy( new, status ) ) SetSortBy( new, new->sortby, status );
+ sval = astFree( sval );
+
+/* MapSize. */
+/* -------- */
+ mapsize = astReadInt( channel, "mapsz", MIN_TABLE_SIZE );
+ NewTable( new, mapsize, status );
+
+/* Entries... */
+/* ---------- */
+
+/* Initialise the index of the next AstMapEntry to be read. */
+ nentry = 0;
+
+/* Read Entries until no more are found */
+ while( astOK ) {
+ nentry++;
+
+/* Get the entry key. */
+ (void) sprintf( buff, "key%d", nentry );
+ key = astReadString( channel, buff, NULL );
+
+/* We have finished reading entries if no key was found. */
+ if( !key ) break;
+
+/* Get the entry comment. */
+ (void) sprintf( buff, "com%d", nentry );
+ com = astReadString( channel, buff, NULL );
+
+/* Get the entry data type. */
+ (void) sprintf( buff, "typ%d", nentry );
+ type = astReadInt( channel, buff, AST__BADTYPE );
+
+ if( type == AST__BADTYPE && astOK ) {
+ astError( AST__BDFTS, "astLoadKeyMap(%s): No data type code found "
+ "whilst reading a %s.", status, name, name );
+
+ }
+
+/* Get the vector length. */
+ (void) sprintf( buff, "nel%d", nentry );
+ nel = astReadInt( channel, buff, 0 );
+
+/* Get the entry member number. Set the KeyMap member count to this value
+ so that the next entry added to the KeyMap will get this value as its
+ member index. */
+ (void) sprintf( buff, "mem%d", nentry );
+ new->member_count = astReadInt( channel, buff, 0 );
+
+/* First deal with integer entries. */
+ if( type == AST__INTTYPE ) {
+
+/* For scalar entries, use "val<nentry>" to get the value then create a new
+ entry and add it to the KeyMap. */
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ ival = astReadInt( channel, buff, 0 );
+ MapPut0I( new, key, ival, com, status );
+
+/* If we must have an array of values... */
+ } else {
+
+/* Create an array to hold the values. */
+ ilist = astMalloc( sizeof(int)*nel );
+
+/* Loop round reading values. */
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ ilist[ index ] = astReadInt( channel, buff, 0 );
+ }
+
+/* Create the KeyMap entry. */
+ MapPut1I( new, key, nel, ilist, com, status );
+
+/* Free resources. */
+ ilist = astFree( ilist );
+ }
+
+/* Do the same for short int values. */
+ } else if( type == AST__SINTTYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ wval = (short int) astReadInt( channel, buff, 0 );
+ MapPut0S( new, key, wval, com, status );
+ } else {
+ wlist = astMalloc( sizeof(short int)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ wlist[ index ] = (short int) astReadInt( channel, buff, 0 );
+ }
+ MapPut1S( new, key, nel, wlist, com, status );
+ wlist = astFree( wlist );
+ }
+
+/* Do the same for byte values. */
+ } else if( type == AST__BYTETYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ bval = (unsigned char) astReadInt( channel, buff, 0 );
+ MapPut0B( new, key, bval, com, status );
+ } else {
+ blist = astMalloc( sizeof(unsigned char)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ blist[ index ] = (unsigned char) astReadInt( channel, buff, 0 );
+ }
+ MapPut1B( new, key, nel, blist, com, status );
+ blist = astFree( blist );
+ }
+
+/* Do the same for double values. */
+ } else if( type == AST__DOUBLETYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ dval = astReadDouble( channel, buff, AST__BAD );
+ MapPut0D( new, key, dval, com, status );
+ } else {
+ dlist = astMalloc( sizeof(double)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ dlist[ index ] = astReadDouble( channel, buff, AST__BAD );
+ }
+ MapPut1D( new, key, nel, dlist, com, status );
+ dlist = astFree( dlist );
+ }
+
+/* Do the same for float values. */
+ } else if( type == AST__FLOATTYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ dval = astReadDouble( channel, buff, 0.0 );
+ MapPut0F( new, key, (float) dval, com, status );
+ } else {
+ flist = astMalloc( sizeof(float)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ flist[ index ] = (float) astReadDouble( channel, buff, 0.0 );
+ }
+ MapPut1F( new, key, nel, flist, com, status );
+ flist = astFree( flist );
+ }
+
+/* Do the same for string values. */
+ } else if( type == AST__STRINGTYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ sval = astReadString( channel, buff, "" );
+ MapPut0C( new, key, sval, com, status );
+ sval = astFree( sval );
+ } else {
+ slist = astMalloc( sizeof(const char *)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ slist[ index ] = astReadString( channel, buff, "" );
+ }
+ MapPut1C( new, key, nel, slist, com, status );
+ for( index = 0; astOK && index < nel; index++ ) {
+ slist[ index ] = astFree( (void *) slist[ index ] );
+ }
+ slist = astFree( slist );
+ }
+
+/* Do the same for object values. */
+ } else if( type == AST__OBJECTTYPE ) {
+ if( nel == 0 ) {
+ (void) sprintf( buff, "val%d", nentry );
+ aval = astReadObject( channel, buff, NULL );
+ MapPut0A( new, key, aval, com, status );
+ if( aval ) aval = astAnnul( aval );
+ } else {
+ alist = astMalloc( sizeof(AstObject *)*nel );
+ for( index = 0; astOK && index < nel; index++ ) {
+ (void) sprintf( buff, "v%d_%d", nentry, index + 1 );
+ alist[ index ] = astReadObject( channel, buff, NULL );
+ }
+ MapPut1A( new, key, nel, alist, com, status );
+ for( index = 0; astOK && index < nel; index++ ) {
+ if( alist[ index ] ) alist[ index ] = astAnnul( alist[ index ] );
+ }
+ alist = astFree( alist );
+ }
+
+/* Undef values have no value. */
+ } else if( type == AST__UNDEFTYPE ) {
+ MapPutU( new, key, com, status );
+
+/* Report an error if the data type is unknown. */
+ } else if( astOK ) {
+ astError( AST__BDFTS, "astLoadKeyMap(%s): Unknown data type code "
+ "(%d) encountered whilst reading a %s.", status, name, type,
+ name );
+ }
+/* Free resources. */
+ key = astFree( key );
+ if( com ) com = astFree( com );
+
+ }
+
+/* Set the final member count for the KeyMap. */
+ new->member_count = astReadInt( channel, "memcnt", 0 );
+
+/* If an error occurred, clean up by deleting the new KeyMap. */
+ if ( !astOK ) new = astDelete( new );
+ }
+
+/* Return the new KeyMap pointer. */
+ return new;
+}
+
+/* Virtual function interfaces. */
+/* ============================ */
+/* These provide the external interface to the virtual functions defined by
+ this class. Each simply checks the global error status and then locates and
+ executes the appropriate member function, using the function pointer stored
+ in the object's virtual function table (this pointer is located using the
+ astMEMBER macro defined in "object.h").
+
+ Note that the member function may not be the one defined here, as it may
+ have been over-ridden by a derived class. However, it should still have the
+ same interface. */
+
+#define MAKE_MAPPUT0_(X,Xtype) \
+void astMapPut0##X##_( AstKeyMap *this, const char *key, Xtype value, \
+ const char *comment, int *status ){ \
+ if ( !astOK ) return; \
+ (**astMEMBER(this,KeyMap,MapPut0##X))(this,key,value,comment, status ); \
+}
+MAKE_MAPPUT0_(D,double)
+MAKE_MAPPUT0_(F,float)
+MAKE_MAPPUT0_(I,int)
+MAKE_MAPPUT0_(C,const char *)
+MAKE_MAPPUT0_(A,AstObject *)
+MAKE_MAPPUT0_(P,void *)
+MAKE_MAPPUT0_(S,short int)
+MAKE_MAPPUT0_(B,unsigned char)
+#undef MAKE_MAPPUT0_
+
+
+#define MAKE_MAPPUT1_(X,Xtype) \
+void astMapPut1##X##_( AstKeyMap *this, const char *key, int size, \
+ Xtype value[], const char *comment, \
+ int *status ){ \
+ if ( !astOK ) return; \
+ (**astMEMBER(this,KeyMap,MapPut1##X))(this,key,size,value,comment, status ); \
+}
+MAKE_MAPPUT1_(S,const short int)
+MAKE_MAPPUT1_(B,const unsigned char)
+MAKE_MAPPUT1_(D,const double)
+MAKE_MAPPUT1_(F,const float)
+MAKE_MAPPUT1_(I,const int)
+MAKE_MAPPUT1_(C,const char *const)
+MAKE_MAPPUT1_(A,AstObject *const)
+MAKE_MAPPUT1_(P,void *const)
+#undef MAKE_MAPPUT1_
+
+#define MAKE_MAPGET0_(X,Xtype) \
+int astMapGet0##X##_( AstKeyMap *this, const char *key, Xtype *value, int *status ){ \
+ if ( !astOK ) return 0; \
+ return (**astMEMBER(this,KeyMap,MapGet0##X))(this,key,value, status ); \
+}
+MAKE_MAPGET0_(D,double)
+MAKE_MAPGET0_(S,short int)
+MAKE_MAPGET0_(B,unsigned char)
+MAKE_MAPGET0_(F,float)
+MAKE_MAPGET0_(I,int)
+MAKE_MAPGET0_(C,const char *)
+MAKE_MAPGET0_(A,AstObject *)
+MAKE_MAPGET0_(P,void *)
+#undef MAKE_MAPGET0_
+
+
+int astMapGetC_( AstKeyMap *this, const char *key, const char **value, int *status ){ \
+ if ( !astOK ) return 0; \
+ return (**astMEMBER(this,KeyMap,MapGetC))(this,key,value, status ); \
+}
+
+
+#define MAKE_MAPGET1_(X,Xtype) \
+int astMapGet1##X##_( AstKeyMap *this, const char *key, int mxval, int *nval, \
+ Xtype *value, int *status ){ \
+ if ( !astOK ) return 0; \
+ return (**astMEMBER(this,KeyMap,MapGet1##X))(this,key,mxval,nval,value,status); \
+}
+MAKE_MAPGET1_(B,unsigned char)
+MAKE_MAPGET1_(S,short int)
+MAKE_MAPGET1_(D,double)
+MAKE_MAPGET1_(F,float)
+MAKE_MAPGET1_(I,int)
+MAKE_MAPGET1_(A,AstObject *)
+MAKE_MAPGET1_(P,void *)
+#undef MAKE_MAPGET1_
+
+#define MAKE_MAPGETELEM_(X,Xtype) \
+int astMapGetElem##X##_( AstKeyMap *this, const char *key, int elem, \
+ Xtype *value, int *status ){ \
+ if ( !astOK ) return 0; \
+ return (**astMEMBER(this,KeyMap,MapGetElem##X))(this,key,elem,value,status); \
+}
+MAKE_MAPGETELEM_(B,unsigned char)
+MAKE_MAPGETELEM_(S,short int)
+MAKE_MAPGETELEM_(D,double)
+MAKE_MAPGETELEM_(F,float)
+MAKE_MAPGETELEM_(I,int)
+MAKE_MAPGETELEM_(A,AstObject *)
+MAKE_MAPGETELEM_(P,void *)
+#undef MAKE_MAPGETELEM_
+
+int astMapGet1C_( AstKeyMap *this, const char *key, int l, int mxval, int *nval,
+ char *value, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapGet1C))(this,key,l,mxval,nval,value,status);
+}
+
+int astMapGetElemC_( AstKeyMap *this, const char *key, int l, int elem,
+ char *value, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapGetElemC))(this,key,l,elem,value,status);
+}
+
+#define MAKE_MAPPUTELEM_(X,Xtype) \
+void astMapPutElem##X##_( AstKeyMap *this, const char *key, int elem, \
+ Xtype value, int *status ){ \
+ if ( !astOK ) return; \
+ (**astMEMBER(this,KeyMap,MapPutElem##X))(this,key,elem,value,status); \
+}
+MAKE_MAPPUTELEM_(B,unsigned char)
+MAKE_MAPPUTELEM_(S,short int)
+MAKE_MAPPUTELEM_(D,double)
+MAKE_MAPPUTELEM_(F,float)
+MAKE_MAPPUTELEM_(I,int)
+MAKE_MAPPUTELEM_(A,AstObject *)
+MAKE_MAPPUTELEM_(C,const char *)
+MAKE_MAPPUTELEM_(P,void *)
+#undef MAKE_MAPPUTELEM_
+
+void astMapPutU_( AstKeyMap *this, const char *key, const char *comment, int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,KeyMap,MapPutU))(this,key,comment,status);
+}
+
+void astMapRemove_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,KeyMap,MapRemove))(this,key,status);
+}
+void astMapRename_( AstKeyMap *this, const char *oldkey, const char *newkey,
+ int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,KeyMap,MapRename))(this,oldkey,newkey,status);
+}
+void astMapCopy_( AstKeyMap *this, AstKeyMap *that, int *status ){
+ if ( !astOK ) return;
+ (**astMEMBER(this,KeyMap,MapCopy))(this,that,status);
+}
+int astMapDefined_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapDefined))(this,key,status);
+}
+int astMapSize_( AstKeyMap *this, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapSize))(this,status);
+}
+int astMapLenC_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapLenC))(this,key,status);
+}
+int astMapLength_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapLength))(this,key,status);
+}
+int astMapType_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapType))(this,key,status);
+}
+int astMapHasKey_( AstKeyMap *this, const char *key, int *status ){
+ if ( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,MapHasKey))(this,key,status);
+}
+const char *astMapKey_( AstKeyMap *this, int index, int *status ){
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,KeyMap,MapKey))(this,index,status);
+}
+const char *astMapIterate_( AstKeyMap *this, int reset, int *status ){
+ if ( !astOK ) return NULL;
+ return (**astMEMBER(this,KeyMap,MapIterate))(this,reset,status);
+}
+int astGetSizeGuess_( AstKeyMap *this, int *status ){
+ if( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,GetSizeGuess))(this,status);
+}
+int astTestSizeGuess_( AstKeyMap *this, int *status ){
+ if( !astOK ) return 0;
+ return (**astMEMBER(this,KeyMap,TestSizeGuess))(this,status);
+}
+void astClearSizeGuess_( AstKeyMap *this, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,ClearSizeGuess))(this,status);
+}
+void astSetSizeGuess_( AstKeyMap *this, int sizeguess, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,SetSizeGuess))(this,sizeguess,status);
+}
+
+void astClearMapLocked_( AstKeyMap *this, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,ClearMapLocked))(this,status);
+}
+void astSetMapLocked_( AstKeyMap *this, int maplocked, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,SetMapLocked))(this,maplocked,status);
+}
+
+void astClearKeyError_( AstKeyMap *this, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,ClearKeyError))(this,status);
+}
+void astSetKeyError_( AstKeyMap *this, int keyerror, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,SetKeyError))(this,keyerror,status);
+}
+
+void astClearSortBy_( AstKeyMap *this, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,ClearSortBy))(this,status);
+}
+void astSetSortBy_( AstKeyMap *this, int sortby, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,SetSortBy))(this,sortby,status);
+}
+
+void astClearKeyCase_( AstKeyMap *this, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,ClearKeyCase))(this,status);
+}
+void astSetKeyCase_( AstKeyMap *this, int keycase, int *status ){
+ if( !astOK ) return;
+ (**astMEMBER(this,KeyMap,SetKeyCase))(this,keycase,status);
+}
+