diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 15:55:01 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2019-05-10 15:55:01 (GMT) |
commit | 9646e8d50bc1481de77459d59738826f9c256ad6 (patch) | |
tree | e47684c08ae346d96e3c6ea8780f3886fe74e6f6 /ast/channel.c | |
parent | 37e757832a7f2c690cea41df5bf9cfa9ee18f67f (diff) | |
download | blt-9646e8d50bc1481de77459d59738826f9c256ad6.zip blt-9646e8d50bc1481de77459d59738826f9c256ad6.tar.gz blt-9646e8d50bc1481de77459d59738826f9c256ad6.tar.bz2 |
upgrade ast 8.7.1
Diffstat (limited to 'ast/channel.c')
-rw-r--r-- | ast/channel.c | 6458 |
1 files changed, 0 insertions, 6458 deletions
diff --git a/ast/channel.c b/ast/channel.c deleted file mode 100644 index 9219502..0000000 --- a/ast/channel.c +++ /dev/null @@ -1,6458 +0,0 @@ -/* -*class++ -* Name: -* Channel - -* Purpose: -* Basic (textual) I/O channel. - -* Constructor Function: -c astChannel -f AST_CHANNEL - -* Description: -* The Channel class implements low-level input/output for the AST -* library. Writing an Object to a Channel will generate a textual -* representation of that Object, and reading from a Channel will -* create a new Object from its textual representation. -* -* Normally, when you use a Channel, you should provide "source" -c and "sink" functions which connect it to an external data store -f and "sink" routines which connect it to an external data store -* by reading and writing the resulting text. By default, however, -* a Channel will read from standard input and write to standard -* output. Alternatively, a Channel can be told to read or write from -* specific text files using the SinkFile and SourceFile attributes, -* in which case no sink or source function need be supplied. - -* Inheritance: -* The Channel class inherits from the Object class. - -* Attributes: -* In addition to those attributes common to all Objects, every -* Channel also has the following attributes: -* -* - Comment: Include textual comments in output? -* - Full: Set level of output detail -* - Indent: Indentation increment between objects -* - ReportLevel: Selects the level of error reporting -* - SinkFile: The path to a file to which the Channel should write -* - Skip: Skip irrelevant data? -* - SourceFile: The path to a file from which the Channel should read -* - Strict: Generate errors instead of warnings? - -* Functions: -c In addition to those functions applicable to all Objects, the -c following functions may also be applied to all Channels: -f In addition to those routines applicable to all Objects, the -f following routines may also be applied to all Channels: -* -c - astWarnings: Return warnings from the previous read or write -c - astPutChannelData: Store data to pass to source or sink functions -c - astRead: Read an Object from a Channel -c - astWrite: Write an Object to a Channel -f - AST_WARNINGS: Return warnings from the previous read or write -f - AST_READ: Read an Object from a Channel -f - AST_WRITE: Write an Object to a Channel - -* Copyright: -* Copyright (C) 1997-2006 Council for the Central Laboratory of the -* Copyright (C) 2009 Science & Technology Facilities Council. -* All Rights Reserved. -* Research Councils - -* Licence: -* This program is free software: you can redistribute it and/or -* modify it under the terms of the GNU Lesser General Public -* License as published by the Free Software Foundation, either -* version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Lesser General Public License for more details. -* -* You should have received a copy of the GNU Lesser General -* License along with this program. If not, see -* <http://www.gnu.org/licenses/>. - -* Authors: -* RFWS: R.F. Warren-Smith (Starlink) - -* History: -* 12-AUG-1996 (RFWS): -* Original version. -* 6-SEP-1996: -* Finished initial implementation. -* 11-DEC-1996 (RFWS): -* Added support for foreign language source and sink functions. -* 28-APR-1997 (RFWS): -* Prevent "-0" being written (use "0" instead). -* 27-NOV-2002 (DSB): -* Added astWriteInvocations. -* 8-JAN-2003 (DSB): -* - Changed private InitVtab method to protected astInitChannelVtab -* method. -* - Modified to use protected Vtab initialisation methods when -* loading an Object. -* 1-NOV-2003 (DSB): -* Change the initialiser so that it accepts source and sink -* wrapper functions as arguments (for use by derived classes). -* 16-AUG-2006 (DSB): -* - Document non-destructive nature of unsuccessful astRead calls -* on a FitsChan. -* 3-OCT-2008 (DSB): -* Added "Strict" attribute. -* 11-DEC-2008 (DSB): -* Added astPutChannelData and astChannelData functions. -* 16-JAN-2009 (DSB): -* Added astAddWarning and astWarnings. -* 11-JUN-2009 (DSB): -* Enable astChannelData to be used from within astRead. -* 7-DEC-2009 (DSB): -* Added Indent attribute. -* 12-FEB-2010 (DSB): -* Represent AST__BAD externally using the string "<bad>". -* 23-JUN-2011 (DSB): -* Added attributes SinkFile and SourceFile. -* 2-OCT-2012 (DSB): -* Report an error if an Inf or NaN value is read from the external -* source. -*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 Channel - -/* Define a string containing the maximum length of keywords used to - identify values in the external representation of data. This is - deliberately kept small so as to simplify integration with - standards such as FITS. */ -#define MAX_NAME "8" - -/* Max length of string returned by GetAttrib */ -#define GETATTRIB_BUFF_LEN 50 - -/* String used to represent AST__BAD externally. */ -#define BAD_STRING "<bad>" - -/* Include files. */ -/* ============== */ -/* Interface definitions. */ -/* ---------------------- */ - -#include "globals.h" /* Thread-safe global data access */ -#include "error.h" /* Error reporting facilities */ -#include "memory.h" /* Memory allocation facilities */ -#include "object.h" /* Base Object class */ -#include "channel.h" /* Interface definition for this class */ -#include "loader.h" /* Interface to the global loader */ -#include "keymap.h" /* Storing arbitrary data in an AST Object */ -#include "pointset.h" /* For AST__BAD */ - -/* Error code definitions. */ -/* ----------------------- */ -#include "ast_err.h" /* AST error codes */ - -/* C header files. */ -/* --------------- */ -#include <ctype.h> -#include <errno.h> -#include <float.h> -#include <limits.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> - -/* 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 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 * ); - -/* 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->AstReadClassData_Msg = 0; \ - globals->GetAttrib_Buff[ 0 ] = 0; \ - globals->Items_Written = 0; \ - globals->Current_Indent = 0; \ - globals->Nest = -1; \ - globals->Nwrite_Invoc = 0; \ - globals->Object_Class = NULL; \ - globals->Values_List = NULL; \ - globals->Values_Class = NULL; \ - globals->Values_OK = NULL; \ - globals->End_Of_Object = NULL; \ - globals->Channel_Data = NULL; - -/* Create the function that initialises global data for this module. */ -astMAKE_INITGLOBALS(Channel) - -/* Define macros for accessing each item of thread specific global data. */ -#define class_init astGLOBAL(Channel,Class_Init) -#define class_vtab astGLOBAL(Channel,Class_Vtab) -#define astreadclassdata_msg astGLOBAL(Channel,AstReadClassData_Msg) -#define getattrib_buff astGLOBAL(Channel,GetAttrib_Buff) -#define items_written astGLOBAL(Channel,Items_Written) -#define current_indent astGLOBAL(Channel,Current_Indent) -#define nest astGLOBAL(Channel,Nest) -#define nwrite_invoc astGLOBAL(Channel,Nwrite_Invoc) -#define object_class astGLOBAL(Channel,Object_Class) -#define values_list astGLOBAL(Channel,Values_List) -#define values_class astGLOBAL(Channel,Values_Class) -#define values_ok astGLOBAL(Channel,Values_OK) -#define end_of_object astGLOBAL(Channel,End_Of_Object) -#define channel_data astGLOBAL(Channel,Channel_Data) - - - -static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER; -#define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 ); -#define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 ); - -static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER; -#define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 ); -#define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 ); - -/* If thread safety is not needed, declare and initialise globals at static - variables. */ -#else - -/* Contextual error message reported in astReadClassData? */ -static int astreadclassdata_msg = 0; - -/* Buffer returned by GetAttrib. */ -static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ]; - -/* Count of the number of output items written since the last "Begin" - or "IsA" item. */ -static int items_written = 0; - -/* Amount of indentation to be applied to the next output item. */ -static int current_indent = 0; - -/* Nesting level, used to keep track of data associated with building - Objects when they contain other Objects. */ -static int nest = -1; - -/* The number of times astWrite has been invoked. */ -static int nwrite_invoc = 0; - -/* Pointer to a user-supplied block of memory to be made available to - source or sink functions via the astChannelData function. */ -static void *channel_data = NULL; - -/*** - The following items are all pointers to dynamically allocated - arrays (stacks) that grow as necessary to accommodate one element - for each level of nesting (one more than the value of "nest"). -***/ - -/* Stack of pointers to null-terminated character strings giving the - names of the classes of the Objects being built at each nesting - level. */ -static char **object_class = NULL; - -/* Stack of pointers to the elements designated as the "heads" of - circular, doubly linked lists of name-value associations. */ -static AstChannelValue **values_list = NULL; - -/* Stack of pointers to null-terminated character strings giving the - names of the classes for which the values held in the values lists - are intended. */ -static char **values_class = NULL; - -/* Stack of flags indicating whether the values held in the values - lists are intended for the class loaders currently executing to - build Objects at each nesting level. */ -static int *values_ok = NULL; - -/* Stack of flags indicating whether "End" items have been read for - the Objects being built at each nesting level. */ -static int *end_of_object = NULL; - - -/* Define the class virtual function table and its initialisation flag - as static variables. */ -static AstChannelVtab class_vtab; /* Virtual function table */ -static int class_init = 0; /* Virtual function table initialised? */ -#define LOCK_MUTEX2 -#define UNLOCK_MUTEX2 -#define LOCK_MUTEX3 -#define UNLOCK_MUTEX3 - -#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. */ -AstChannel *astChannelForId_( const char *(*)( void ), - char *(*)( const char *(*)( void ), int * ), - void (*)( const char * ), - void (*)( void (*)( const char * ), - const char *, int * ), - const char *, ... ); -AstChannel *astChannelId_( const char *(*)( void ), void (*)( const char * ), const char *, ... ); - -/* Prototypes for Private Member Functions. */ -/* ======================================== */ -static AstObject *Read( AstChannel *, int * ); -static AstObject *ReadObject( AstChannel *, const char *, AstObject *, int * ); -static AstChannelValue *FreeValue( AstChannelValue *, int * ); -static AstChannelValue *LookupValue( const char *, int * ); -static AstKeyMap *Warnings( AstChannel *, int * ); -static char *GetNextText( AstChannel *, int * ); -static char *InputTextItem( AstChannel *, int * ); -static char *ReadString( AstChannel *, const char *, const char *, int * ); -static char *SourceWrap( const char *(*)( void ), int * ); -static const char *GetAttrib( AstObject *, const char *, int * ); -static double ReadDouble( AstChannel *, const char *, double, int * ); -static int GetComment( AstChannel *, int * ); -static int GetFull( AstChannel *, int * ); -static int GetSkip( AstChannel *, int * ); -static int GetStrict( AstChannel *, int * ); -static int ReadInt( AstChannel *, const char *, int, int * ); -static int TestAttrib( AstObject *, const char *, int * ); -static int TestComment( AstChannel *, int * ); -static int TestFull( AstChannel *, int * ); -static int TestSkip( AstChannel *, int * ); -static int TestStrict( AstChannel *, int * ); -static int Use( AstChannel *, int, int, int * ); -static int Write( AstChannel *, AstObject *, int * ); -static void AddWarning( AstChannel *, int, const char *, const char *, int * ); -static void AppendValue( AstChannelValue *, AstChannelValue **, int * ); -static void ClearAttrib( AstObject *, const char *, int * ); -static void ClearComment( AstChannel *, int * ); -static void ClearFull( AstChannel *, int * ); -static void ClearSkip( AstChannel *, int * ); -static void ClearStrict( AstChannel *, int * ); -static void ClearValues( AstChannel *, int * ); -static void Copy( const AstObject *, AstObject *, int * ); -static void Delete( AstObject *, int * ); -static void Dump( AstObject *, AstChannel *, int * ); -static void GetNextData( AstChannel *, int, char **, char **, int * ); -static void OutputTextItem( AstChannel *, const char *, int * ); -static void PutChannelData( AstChannel *, void *, int * ); -static void PutNextText( AstChannel *, const char *, int * ); -static void ReadClassData( AstChannel *, const char *, int * ); -static void RemoveValue( AstChannelValue *, AstChannelValue **, int * ); -static void SetAttrib( AstObject *, const char *, int * ); -static void SetComment( AstChannel *, int, int * ); -static void SetFull( AstChannel *, int, int * ); -static void SetSkip( AstChannel *, int, int * ); -static void SetStrict( AstChannel *, int, int * ); -static void SinkWrap( void (*)( const char * ), const char *, int * ); -static void Unquote( AstChannel *, char *, int * ); -static void WriteBegin( AstChannel *, const char *, const char *, int * ); -static void WriteDouble( AstChannel *, const char *, int, int, double, const char *, int * ); -static void WriteEnd( AstChannel *, const char *, int * ); -static void WriteInt( AstChannel *, const char *, int, int, int, const char *, int * ); -static void WriteIsA( AstChannel *, const char *, const char *, int * ); -static void WriteObject( AstChannel *, const char *, int, int, AstObject *, const char *, int * ); -static void WriteString( AstChannel *, const char *, int, int, const char *, const char *, int * ); - -static int GetReportLevel( AstChannel *, int * ); -static int TestReportLevel( AstChannel *, int * ); -static void ClearReportLevel( AstChannel *, int * ); -static void SetReportLevel( AstChannel *, int, int * ); - -static int GetIndent( AstChannel *, int * ); -static int TestIndent( AstChannel *, int * ); -static void ClearIndent( AstChannel *, int * ); -static void SetIndent( AstChannel *, int, int * ); - -static const char *GetSourceFile( AstChannel *, int * ); -static int TestSourceFile( AstChannel *, int * ); -static void ClearSourceFile( AstChannel *, int * ); -static void SetSourceFile( AstChannel *, const char *, int * ); - -static const char *GetSinkFile( AstChannel *, int * ); -static int TestSinkFile( AstChannel *, int * ); -static void ClearSinkFile( AstChannel *, int * ); -static void SetSinkFile( AstChannel *, const char *, int * ); - -/* Member functions. */ -/* ================= */ -static void AddWarning( AstChannel *this, int level, const char *msg, - const char *method, int *status ) { -/* -*+ -* Name: -* astAddWarning - -* Purpose: -* Add a warning to a Channel. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astAddWarning( AstChannel *this, int level, const char *msg, -* const char *method, int status, ... ) - -* Class Membership: -* Channel method. - -* Description: -* This function stores a warning message inside a Channel. These -* messages can be retirieved using astWarnings. - -* Parameters: -* this -* Pointer to the Channel. -* level -* Ignore the warning if the ReportLevel attribute value is less -* than "level". -* msg -* The wanting message to store. It may contain printf format -* specifiers. If a NULL pointer is supplied, all warnings -* currently stored in the Channel are removed. -* method -* The method name. -* status -* Inherited status value. -* ... -* Extra values to substitute into the message string as -* replacements for the printf format specifiers. -*- - -* Note: The expansion of the printf format specifiers is done in the -* astAddWarning_ wrapper function. The AddWarning functions defined by -* each class receives the fully expanded message and does not have a -* variable argument list. The variable argument list is included in the -* above prologue in order to document the wrapper function. - -*/ - -/* Local Variables: */ - int i; /* Message index */ - char *a; /* Pointer to copy of message */ - -/* If a NULL pointer was supplied, free all warnings currently in the - Channel. Do this before checking the inherited status so that it works - even if an error has occurred. */ - if( !msg ) { - for( i = 0; i < this->nwarn; i++ ) { - (this->warnings)[ i ] = astFree( (this->warnings)[ i ] ); - } - this->warnings = astFree( this->warnings ); - this->nwarn = 0; - return; - } - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Only proceed if the message level is sufficiently important. */ - if( astGetReportLevel( this ) >= level ) { - -/* If we are being strict, issue an error rather than a warning. */ - if( astGetStrict( this ) ) { - if( astOK ) { - astError( AST__BADIN, "%s(%s): %s", status, method, - astGetClass( this ), msg ); - } - -/* Otherwise, we store a copy of the message in the Channel. */ - } else { - -/* Allocate memory and store a copy of th supplied string in it. */ - a = astStore( NULL, msg, strlen( msg ) + 1 ); - -/* Expand the array of warning pointers in ther Channel structure. */ - this->warnings = astGrow( this->warnings, this->nwarn + 1, - sizeof( char * ) ); - -/* If all is OK so far, store the new warning pointer, and increment the - number of warnings in the Channel. */ - if( astOK ) { - (this->warnings)[ (this->nwarn)++ ] = a; - -/* Otherwise, attempt to free the memory holding the copy of the warning. */ - } else { - a = astFree( a ); - } - } - } -} - -static void AppendValue( AstChannelValue *value, AstChannelValue **head, int *status ) { -/* -* Name: -* AppendValue - -* Purpose: -* Append a Value structure to a list. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void AppendValue( AstChannelValue *value, AstChannelValue **head, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function appends a Value structure to a doubly linked -* circular list of such structures. The new list element is -* inserted just in front of the element occupying the "head of -* list" position (i.e. it becomes the new last element in the -* list). - -* Parameters: -* value -* Pointer to the new element. This must not already be in the -* list. -* head -* Address of a pointer to the element at the head of the list -* (this pointer should be NULL if the list is initially -* empty). This pointer will only be updated if a new element is -* being added to an empty list. -* status -* Pointer to the inherited status variable. - -* Notes: -* - This function does not perform error chacking and does not -* generate errors. -*/ - -/* If the list is initially empty, the sole new element points at - itself. */ - if ( !*head ) { - value->flink = value; - value->blink = value; - -/* Update the list head to identify the new element. */ - *head = value; - -/* Otherwise, insert the new element in front of the element at the - head of the list. */ - } else { - value->flink = *head; - value->blink = ( *head )->blink; - ( *head )->blink = value; - value->blink->flink = value; - } -} - -void *astChannelData_( void ) { -/* -c++ -* Name: -* astChannelData - -* Purpose: -* Return a pointer to user-supplied data stored with a Channel. - -* Type: -* Public macro. - -* Synopsis: -* #include "channel.h" -* void *astChannelData - -* Class Membership: -* Channel macro. - -* Description: -* This macro is intended to be used within the source or sink -* functions associated with a Channel. It returns any pointer -* previously stored in the Channel (that is, the Channel that has -* invoked the source or sink function) using astPutChannelData. -* -* This mechanism is a thread-safe alternative to passing file -* descriptors, etc, via static global variables. - -* Returned Value: -* astChannelData -* The pointer previously stored with the Channel using -* astPutChannelData. A NULL pointer will be returned if no such -* pointer has been stored with the Channel. - -* Applicability: -* Channel -* This macro applies to all Channels. - -* Notes: -* - This routine is not available in the Fortran 77 interface to -* the AST library. -c-- -*/ - astDECLARE_GLOBALS - astGET_GLOBALS(NULL); - return channel_data; -} - -static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { -/* -* Name: -* ClearAttrib - -* Purpose: -* Clear an attribute value for a Channel. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void ClearAttrib( AstObject *this, const char *attrib, int *status ) - -* Class Membership: -* Channel member function (over-rides the astClearAttrib protected -* method inherited from the Object class). - -* Description: -* This function clears the value of a specified attribute for a -* Channel, so that the default value will subsequently be used. - -* Parameters: -* this -* Pointer to the Channel. -* 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: */ - AstChannel *this; /* Pointer to the Channel structure */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Obtain a pointer to the Channel structure. */ - this = (AstChannel *) this_object; - -/* Check the attribute name and clear the appropriate attribute. */ - -/* Comment. */ -/* -------- */ - if ( !strcmp( attrib, "comment" ) ) { - astClearComment( this ); - -/* Full. */ -/* ----- */ - } else if ( !strcmp( attrib, "full" ) ) { - astClearFull( this ); - -/* Indent. */ -/* ------- */ - } else if ( !strcmp( attrib, "indent" ) ) { - astClearIndent( this ); - -/* ReportLevel. */ -/* ------------ */ - } else if ( !strcmp( attrib, "reportlevel" ) ) { - astClearReportLevel( this ); - -/* Skip. */ -/* ----- */ - } else if ( !strcmp( attrib, "skip" ) ) { - astClearSkip( this ); - -/* SourceFile. */ -/* ----------- */ - } else if ( !strcmp( attrib, "sourcefile" ) ) { - astClearSourceFile( this ); - -/* SinkFile. */ -/* --------- */ - } else if ( !strcmp( attrib, "sinkfile" ) ) { - astClearSinkFile( this ); - -/* Strict. */ -/* ------- */ - } else if ( !strcmp( attrib, "strict" ) ) { - astClearStrict( 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 ClearValues( AstChannel *this, int *status ) { -/* -* Name: -* ClearValues - -* Purpose: -* Clear the current values list. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void ClearValues( AstChannel *this, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function clears any (un-read) Value structures remaining in -* the current values list (i.e. at the current nesting level). It -* should be invoked after all required values have been read. -* -* If the values list has not been read, or if any remaining values -* are found (i.e. the list is not empty) then this indicates an -* unrecognised input class or an input value that has not been -* read by a class loader. This implies an error in the loader, or -* bad input data, so an error is reported. -* -* All resources used by any remaining Value structures are freed -* and the values list is left in an empty state. - -* Parameters: -* this -* Pointer to the Channel being read. This is only used for -* constructing error messages. It must not be NULL. -* status -* Pointer to the inherited status variable. - -* Notes: -* - This function attempts to execute even if the global error -* status is set on entry, although no further error report will be -* made if it subsequently fails under these circumstances. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - AstChannelValue **head; /* Address of pointer to values list */ - AstChannelValue *value; /* Pointer to value list element */ - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* If "values_class" is non-NULL, then the values list has previously - been filled with Values for a class. */ - if ( values_class[ nest ] ) { - -/* If "values_ok" is zero, however, then these Values have not yet - been read by a class loader. This must be due to a bad class name - associated with them or because the class data are not available in - the correct order. If we are using strict error reporting, then report - an error (unless the error status is already set). */ - if ( astGetStrict( this ) && !values_ok[ nest ] && astOK ) { - astError( AST__BADIN, - "astRead(%s): Invalid class structure in input data.", status, - astGetClass( this ) ); - astError( AST__BADIN, - "Class \"%s\" is invalid or out of order within a %s.", status, - values_class[ nest ], object_class[ nest ] ); - } - -/* Free the memory holding the class string. */ - values_class[ nest ] = astFree( values_class[ nest ] ); - } - -/* Reset the "values_ok" flag. */ - values_ok[ nest ] = 0; - -/* Now clear any Values remaining in the values list. Obtain the - address of the pointer to the head of this list (at the current - nesting level) and loop to remove Values from the list while it is - not empty. */ - head = values_list + nest; - while ( *head ) { - -/* Obtain a pointer to the first element. */ - value = *head; - -/* Issue a warning. */ - if ( value->is_object ) { - astAddWarning( this, 1, "The Object \"%s = <%s>\" was " - "not recognised as valid input.", "astRead", status, - value->name, astGetClass( value->ptr.object ) ); - } else { - astAddWarning( this, 1, "The value \"%s = %s\" was not " - "recognised as valid input.", "astRead", status, - value->name, value->ptr.string ); - } - -/* Remove the Value structure from the list (which updates the head of - list pointer) and free its resources. */ - RemoveValue( value, head, status ); - value = FreeValue( value, status ); - } -} - -static AstChannelValue *FreeValue( AstChannelValue *value, int *status ) { -/* -* Name: -* FreeValue - -* Purpose: -* Free a dynamically allocated Value structure. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* AstChannelValue *FreeValue( AstChannelValue *value, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function frees a dynamically allocated Value structure, -* releasing all resources used by it. The structure contents must -* have been correctly initialised. - -* Parameters: -* value -* Pointer to the Value structure to be freed. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* A NULL pointer is always returned. - -* Notes: -* - This function attempts to execute even if the global error -* status is set on entry, although no further error report will be -* made if it subsequently fails under these circumstances. -*/ - -/* Check that a non-NULL pointer has been supplied. */ - if ( value ) { - -/* If the "name" component has been allocated, then free it. */ - if ( value->name ) value->name = astFree( value->name ); - -/* If the "ptr" component identifies an Object, then annul the Object - pointer. */ - if ( value->is_object ) { - if ( value->ptr.object ) { - value->ptr.object = astAnnul( value->ptr.object ); - } - -/* Otherwise, if it identifies a string, then free the string. */ - } else { - if ( value->ptr.string ) { - value->ptr.string = astFree( value->ptr.string ); - } - } - -/* Free the Value structure itself. */ - value = astFree( value ); - } - -/* Return a NULL pointer. */ - return NULL; -} - -static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { -/* -* Name: -* GetAttrib - -* Purpose: -* Get the value of a specified attribute for a Channel. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* const char *GetAttrib( AstObject *this, const char *attrib, int *status ) - -* Class Membership: -* Channel member function (over-rides the protected astGetAttrib -* method inherited from the Object class). - -* Description: -* This function returns a pointer to the value of a specified -* attribute for a Channel, formatted as a character string. - -* Parameters: -* this -* Pointer to the Channel. -* 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 Channel, 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 Channel. 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 */ - AstChannel *this; /* Pointer to the Channel structure */ - const char *result; /* Pointer value to return */ - int comment; /* Comment attribute value */ - int full; /* Full attribute value */ - int indent; /* Indent attribute value */ - int report_level; /* ReportLevel attribute value */ - int skip; /* Skip attribute value */ - int strict; /* Report errors insead of warnings? */ - -/* 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 Channel structure. */ - this = (AstChannel *) 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. */ - -/* Comment. */ -/* -------- */ - if ( !strcmp( attrib, "comment" ) ) { - comment = astGetComment( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", comment ); - result = getattrib_buff; - } - -/* Full. */ -/* ----- */ - } else if ( !strcmp( attrib, "full" ) ) { - full = astGetFull( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", full ); - result = getattrib_buff; - } - -/* Indent. */ -/* ------- */ - } else if ( !strcmp( attrib, "indent" ) ) { - indent = astGetIndent( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", indent ); - result = getattrib_buff; - } - -/* ReportLevel. */ -/* ------------ */ - } else if ( !strcmp( attrib, "reportlevel" ) ) { - report_level = astGetReportLevel( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", report_level ); - result = getattrib_buff; - } - -/* Skip. */ -/* ----- */ - } else if ( !strcmp( attrib, "skip" ) ) { - skip = astGetSkip( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", skip ); - result = getattrib_buff; - } - -/* SourceFile. */ -/* ----------- */ - } else if ( !strcmp( attrib, "sourcefile" ) ) { - result = astGetSourceFile( this ); - -/* SinkFile. */ -/* --------- */ - } else if ( !strcmp( attrib, "sinkfile" ) ) { - result = astGetSinkFile( this ); - -/* Strict. */ -/* ------- */ - } else if ( !strcmp( attrib, "strict" ) ) { - strict = astGetStrict( this ); - if ( astOK ) { - (void) sprintf( getattrib_buff, "%d", strict ); - result = getattrib_buff; - } - -/* 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 void GetNextData( AstChannel *this, int skip, char **name, - char **val, int *status ) { -/* -*+ -* Name: -* astGetNextData - -* Purpose: -* Read the next item of data from a data source. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astGetNextData( AstChannel *this, int skip, char **name, -* char **val ) - -* Class Membership: -* Channel method. - -* Description: -* This function reads the next item of input data from a data -* source associated with a Channel and returns the result. -* -* It is layered conceptually on the astGetNextText method, but -* instead of returning the raw input text, it decodes it and -* returns name/value pairs ready for use. Note that in some -* derived classes, where the data are not stored as text, this -* function may not actually use astGetNextText, but will access -* the data directly. - -* Parameters: -* this -* Pointer to the Channel. -* skip -* A non-zero value indicates that a new Object is to be read, -* and that all input data up to the next "Begin" item are to be -* skipped in order to locate it. This is useful if the data -* source contains AST objects interspersed with other data (but -* note that these other data cannot appear inside AST Objects, -* only between them). -* -* A zero value indicates that all input data are significant -* and the next item will therefore be read and an attempt made -* to interpret it whatever it contains. Any other data -* inter-mixed with AST Objects will then result in an error. -* name -* An address at which to store a pointer to a null-terminated -* dynamically allocated string containing the name of the next -* item in the input data stream. This name will be in lower -* case with no surrounding white space. It is the callers -* responsibilty to free the memory holding this string (using -* astFree) when it is no longer required. -* -* A NULL pointer value will be returned (without error) to -* indicate when there are no further input data items to be -* read. -* val -* An address at which to store a pointer to a null-terminated -* dynamically allocated string containing the value associated -* with the next item in the input data stream. No case -* conversion is performed on this string and all white space is -* potentially significant. It is the callers responsibilty to -* free the memory holding this string (using astFree) when it -* is no longer required. -* -* The returned pointer will be NULL if an Object data item is -* read (see the "Data Representation" section). - -* Data Representation: -* The returned data items fall into the following categories: -* -* - Begin: Identified by the name string "begin", this indicates -* the start of an Object definition. The associated value string -* gives the class name of the Object being defined. -* -* - IsA: Identified by the name string "isa", this indicates the -* end of the data associated with a particular class structure -* within the definiton of a larger Object. The associated value -* string gives the name of the class whose data have just been -* read. -* -* - End: Identified by the name string "end", this indicates the -* end of the data associated with a complete Object -* definition. The associated value string gives the class name of -* the Object whose definition is being ended. -* -* - Non-Object: Identified by any other name string plus a -* non-NULL "val" pointer, this gives the value of a non-Object -* structure component (instance variable). The name identifies -* which instance variable it is (within the context of the class -* whose data are being read) and the value is encoded as a string. -* -* - Object: Identified by any other name string plus a NULL "val" -* pointer, this identifies the value of an Object structure -* component (instance variable). The name identifies which -* instance variable it is (within the context of the class whose -* data are being read) and the value is given by subsequent data -* items (so the next item should be a "Begin" item). - -* Notes: -* - NULL pointer values will be returned if this function is -* invoked with the global error status set, or if it should fail -* for any reason. -* - This method is provided primarily so that derived classes may -* over-ride it in order to read from alternative data sources. It -* provides a higher-level interface than astGetNextText, so is -* suitable for classes that either need to read textual data in a -* different format, or to read from non-textual data sources. -*- -*/ - -/* Local Variables: */ - char *line; /* Pointer to input text line */ - int done; /* Data item read? */ - int i; /* Loop counter for string characters */ - int len; /* Length of input text line */ - int nc1; /* Offset to start of first field */ - int nc2; /* Offset to end of first field */ - int nc3; /* Offset to start of second field */ - int nc; /* Number of charaters read by "astSscanf" */ - -/* Initialise the returned values. */ - *name = NULL; - *val = NULL; - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Read the next input line as text (the loop is needed to allow - initial lines to be skipped if the "skip" flag is set). */ - done = 0; - while ( !done && ( line = InputTextItem( this, status ) ) && astOK ) { - -/* If OK, determine the line length. */ - len = strlen( line ); - -/* Non-Object value. */ -/* ----------------- */ -/* Test for lines of the form " name = value" (or similar), where the - name is no more than MAX_NAME characters long (the presence of a - value on the right hand side indicates that this is a non-Object - value, encoded as a string). Ignore these lines if the "skip" flag - is set. */ - if ( nc = 0, - ( !skip - && ( 0 == astSscanf( line, - " %n%*" MAX_NAME "[^ \t=]%n = %n%*[^\n]%n", - &nc1, &nc2, &nc3, &nc ) ) - && ( nc >= len ) ) ) { - -/* Note we have found a data item. */ - done = 1; - -/* Extract the name and value fields. */ - *name = astString( line + nc1, nc2 - nc1 ); - *val = astString( line + nc3, len - nc3 ); - -/* If OK, truncate the value to remove any trailing white space. */ - if ( astOK ) { - i = len - nc3 - 1; - while ( ( i >= 0 ) && isspace( ( *val )[ i ] ) ) i--; - ( *val )[ i + 1 ] = '\0'; - -/* Also remove any quotes from the string. */ - Unquote( this, *val, status ); - } - -/* Object value. */ -/* ------------- */ -/* Test for lines of the form " name = " (or similar), where the name - is no more than MAX_NAME characters long (the absence of a value on - the right hand side indicates that this is an Object, whose - definition follows on subsequent input lines). Ignore these lines - if the "skip" flag is set. */ - } else if ( nc = 0, - ( !skip - && ( 0 == astSscanf( line, - " %n%*" MAX_NAME "[^ \t=]%n = %n", - &nc1, &nc2, &nc ) ) - && ( nc >= len ) ) ) { - -/* Note we have found a data item. */ - done = 1; - -/* Extract the name field but leave the value pointer as NULL. */ - *name = astString( line + nc1, nc2 - nc1 ); - -/* Begin. */ -/* ------ */ -/* Test for lines of the form " Begin Class " (or similar). */ - } else if ( nc = 0, - ( ( 0 == astSscanf( line, - " %*1[Bb]%*1[Ee]%*1[Gg]%*1[Ii]%*1[Nn] %n%*s%n %n", - &nc1, &nc2, &nc ) ) - && ( nc >= len ) ) ) { - -/* Note we have found a data item. */ - done = 1; - -/* Set the returned name to "begin" and extract the associated class - name for the value. Store both of these in dynamically allocated - strings. */ - *name = astString( "begin", 5 ); - *val = astString( line + nc1, nc2 - nc1 ); - -/* IsA. */ -/* ---- */ -/* Test for lines of the form " IsA Class " (or similar). Ignore these - lies if the "skip" flag is set. */ - } else if ( nc = 0, - ( !skip - && ( 0 == astSscanf( line, - " %*1[Ii]%*1[Ss]%*1[Aa] %n%*s%n %n", - &nc1, &nc2, &nc ) ) - && ( nc >= len ) ) ) { - -/* Note we have found a data item. */ - done = 1; - -/* Set the returned name to "isa" and extract the associated class - name for the value. */ - *name = astString( "isa", 3 ); - *val = astString( line + nc1, nc2 - nc1 ); - -/* End. */ -/* ---- */ -/* Test for lines of the form " End Class " (or similar). Ignore these - lines if the "skip" flag is set. */ - } else if ( nc = 0, - ( !skip - && ( 0 == astSscanf( line, - " %*1[Ee]%*1[Nn]%*1[Dd] %n%*s%n %n", - &nc1, &nc2, &nc ) ) - && ( nc >= len ) ) ) { - -/* Note we have found a data item. */ - done = 1; - -/* If found, set the returned name to "end" and extract the associated - class name for the value. */ - *name = astString( "end", 3 ); - *val = astString( line + nc1, nc2 - nc1 ); - -/* If the input line didn't match any of the above and the "skip" flag - is not set, then report an error. */ - } else if ( !skip ) { - astError( AST__BADIN, - "astRead(%s): Cannot interpret the input data: \"%s\".", status, - astGetClass( this ), line ); - } - -/* Free the memory holding the input data as text. */ - line = astFree( line ); - } - -/* If successful, convert the name to lower case. */ - if ( astOK && *name ) { - for ( i = 0; ( *name )[ i ]; i++ ) { - ( *name )[ i ] = tolower( ( *name )[ i ] ); - } - } - -/* If an error occurred, ensure that any memory allocated is freed and - that NULL pointer values are returned. */ - if ( !astOK ) { - *name = astFree( *name ); - *val = astFree( *val ); - } -} - -static char *GetNextText( AstChannel *this, int *status ) { -/* -*+ -* Name: -* GetNextText - -* Purpose: -* Read the next line of input text from a data source. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* char *astGetNextText( AstChannel *this ) - -* Class Membership: -* Channel method. - -* Description: -* This function reads the next "raw" input line of text from the -* data source associated with a Channel. -* -* Each line is returned as a pointer to a null-terminated string -* held in dynamic memory, and it is the caller's responsibility to -* free this memory (using astFree) when it is no longer -* required. A NULL pointer is returned if there are no more input -* lines to be read. - -* Parameters: -* this -* Pointer to the Channel. - -* Returned Value: -* Pointer to a null-terminated string containing the input line -* (held in dynamically allocated memory, which must be freed by -* the caller when no longer required). A NULL pointer is returned -* if there are no more input lines to be read. - -* 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. -* - This method is provided primarily so that derived classes may -* over-ride it in order to read from alternative (textual) data -* sources. -*- -*/ - -/* Local Constants: */ -#define MIN_CHARS 81 /* Initial size for allocating memory */ -#define ERRBUF_LEN 80 - -/* Local Variables: */ - FILE *fd; /* Input file descriptor */ - char *errstat; /* Pointer for system error message */ - char *line; /* Pointer to line data to be returned */ - char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ - const char *sink_file; /* Path to output sink file */ - const char *source_file; /* Path to source file */ - int c; /* Input character */ - int len; /* Length of input line */ - int readstat; /* "errno" value set by "getchar" */ - int size; /* Size of allocated memory */ - -/* Initialise. */ - line = NULL; - -/* Check the global error status. */ - if ( !astOK ) return line; - -/* If the SourceFile attribute of the Channel specifies an input file, - but no input file has yet been opened, open it now. Report an error if - it is the same as the sink file. */ - if( astTestSourceFile( this ) && !this->fd_in ) { - source_file = astGetSourceFile( this ); - - if( this->fd_out ) { - sink_file = astGetSinkFile( this ); - if( astOK && !strcmp( sink_file, source_file ) ) { - astError( AST__RDERR, "astRead(%s): Failed to open input " - "SourceFile '%s' - the file is currently being used " - "as the output SinkFile.", status, astGetClass( this ), - source_file ); - } - } - - if( astOK ) { - this->fd_in = fopen( source_file, "r" ); - if( !this->fd_in ) { - if ( errno ) { -#if HAVE_STRERROR_R - strerror_r( errno, errbuf, ERRBUF_LEN ); - errstat = errbuf; -#else - errstat = strerror( errno ); -#endif - astError( AST__RDERR, "astRead(%s): Failed to open input " - "SourceFile '%s' - %s.", status, astGetClass( this ), - source_file, errstat ); - } else { - astError( AST__RDERR, "astRead(%s): Failed to open input " - "SourceFile '%s'.", status, astGetClass( this ), - source_file ); - } - } - - } - } - -/* Source function defined, but no input file. */ -/* ------------------------------------------- */ -/* If no active input file descriptor is stored in the Channel, but - a source function (and its wrapper function) is defined for the - Channel, use the wrapper function to invoke the source function to - read a line of input text. This is returned in a dynamically - allocated string. */ - if ( !this->fd_in && this->source && this->source_wrap ) { - -/* About to call an externally supplied function which may not be - thread-safe, so lock a mutex first. Also store the channel data - pointer in a global variable so that it can be accessed in the source - function using macro astChannelData. */ - astStoreChannelData( this ); - LOCK_MUTEX3; - line = ( *this->source_wrap )( this->source, status ); - UNLOCK_MUTEX3; - -/* Input file defined, or no source function. */ -/* ------------------------------------------ */ -/* Read the line from the input file or from standard input. */ - } else if( astOK ) { - c = '\0'; - len = 0; - size = 0; - -/* Choose the file descriptor to use. */ - fd = this->fd_in ? this->fd_in : stdin; - -/* Loop to read input characters, saving any "errno" value that may be - set by "getchar" if an error occurs. Quit if an end of file (or - error) occurs or if a newline character is read. */ - while ( errno = 0, c = getc( fd ), readstat = errno, - ( c != EOF ) && ( c != '\n' ) ) { - -/* If no memory has yet been allocated to hold the line, allocate some - now, using MIN_CHARS as the initial line length. */ - if ( !line ) { - line = astMalloc( sizeof( char ) * (size_t) MIN_CHARS ); - size = MIN_CHARS; - -/* If memory has previously been allocated, extend it when necessary - to hold the new input character (plus a terminating null) and note - the new size. */ - } else if ( ( len + 2 ) > size ) { - line = astGrow( line, len + 2, sizeof( char ) ); - if ( !astOK ) break; - size = (int) astSizeOf( line ); - } - -/* Store the character just read. */ - line[ len++ ] = c; - } - -/* If the above loop completed without setting the global error - status, check the last character read and use "ferror" to see if a - read error occurred. If so, report the error, using the saved - "errno" value (but only if one was set). */ - if ( astOK && ( c == EOF ) && ferror( fd ) ) { - if ( readstat ) { -#if HAVE_STRERROR_R - strerror_r( readstat, errbuf, ERRBUF_LEN ); - errstat = errbuf; -#else - errstat = strerror( readstat ); -#endif - astError( AST__RDERR, - "astRead(%s): Read error on standard input - %s.", status, - astGetClass( this ), errstat ); - } else { - astError( AST__RDERR, - "astRead(%s): Read error on standard input.", status, - astGetClass( this ) ); - } - } - -/* If an empty line has been read, allocate memory to hold an empty - string. */ - if ( !line && ( c == '\n' ) ) { - line = astMalloc( sizeof( char ) ); - } - -/* If memory has been allocated and there has been no error, - null-terminate the string of input characters. */ - if ( line ) { - if ( astOK ) { - line[ len ] = '\0'; - -/* If there has been an error, free the allocated memory. */ - } else { - line = astFree( line ); - } - } - } - - -/* Return the result pointer. */ - return line; - -/* Undefine macros local to this function. */ -#undef MIN_CHARS -#undef ERRBUF_LEN -} - -static AstKeyMap *Warnings( AstChannel *this, int *status ){ -/* -*++ -* Name: -c astWarnings -f AST_WARNINGS - -* Purpose: -* Returns any warnings issued by the previous read or write operation. - -* Type: -* Public virtual function. - -* Synopsis: -c #include "channel.h" -c AstKeyMap *astWarnings( AstChannel *this ) -f RESULT = AST_WARNINGS( THIS, STATUS ) - -* Class Membership: -* Channel member function. - -* Description: -* This function returns an AST KeyMap object holding the text of any -* warnings issued as a result of the previous invocation of the -c astRead or astWrite -f AST_READ or AST_WRITE -* function on the Channel. If no warnings were issued, a -c a NULL value -f AST__NULL -* will be returned. -* -* Such warnings are non-fatal and will not prevent the -* read or write operation succeeding. However, the converted object -* may not be identical to the original object in all respects. -* Differences which would usually be deemed as insignificant in most -* usual cases will generate a warning, whereas more significant -* differences will generate an error. -* -* The "Strict" attribute allows this warning facility to be switched -* off, so that a fatal error is always reported for any conversion -* error. - -* Parameters: -c this -f THIS = INTEGER (Given) -* Pointer to the Channel. -f STATUS = INTEGER (Given and Returned) -f The global status. - -* Returned Value: -c astWarnings() -f AST_WARNINGS = INTEGER -* A pointer to the KeyMap holding the warning messages, or -c NULL -f AST__NULL -* if no warnings were issued during the previous read operation. - -* Applicability: -* Channel -* The basic Channel class generates a warning when ever an -* un-recognised item is encountered whilst reading an Object from -* an external data source. If Strict is zero (the default), then -* unexpected items in the Object description are simply ignored, -* and any remaining items are used to construct the returned -* Object. If Strict is non-zero, an error will be reported and a -* NULL Object pointer returned if any unexpected items are -* encountered. -* -* As AST continues to be developed, new attributes are added -* occasionally to selected classes. If an older version of AST is -* used to read external Object descriptions created by a more -* recent version of AST, then the Channel class will, by default, -* ignore the new attributes, using the remaining attributes to -* construct the Object. This is usually a good thing. However, -* since external Object descriptions are often stored in plain -* text, it is possible to edit them using a text editor. This -* gives rise to the possibility of genuine errors in the -* description due to finger-slips, typos, or simple -* mis-understanding. Such inappropriate attributes will be ignored -* if Strict is left at its default zero value. This will cause the -* mis-spelled attribute to revert to its default value, -* potentially causing subtle changes in the behaviour of -* application software. If such an effect is suspected, the Strict -* attribute can be set non-zero, resulting in the erroneous -* attribute being identified in an error message. -* FitsChan -* The returned KeyMap will contain warnings for all conditions -* listed in the Warnings attribute. -* XmlChan -* Reports conversion errors that result in what are usally -* insignificant changes. - -* Notes: -* - The returned KeyMap uses keys of the form "Warning_1", -* "Warning_2", etc. -* - A value of -c NULL will be returned if this function is invoked with the AST -c error status set, -f AST__NULL will be returned if this function is invoked with STATUS -f set to an error value, -* or if it should fail for any reason. -*-- -*/ - -/* Local Variables: */ - AstKeyMap *result; - char key[ 20 ]; - int i; - -/* Check the global status, and supplied keyword name. */ - result = NULL; - if( !astOK ) return result; - -/* Check there are some warnings to return. */ - if( this->nwarn && this->warnings ) { - -/* Create the KeyMap. */ - result = astKeyMap( "", status ); - -/* Loop round all warnings, adding them into the KeyMap. */ - for( i = 0; i < this->nwarn; i++ ){ - sprintf( key, "Warning_%d", i + 1 ); - astMapPut0C( result, key, (this->warnings)[ i ], " " ); - } - } - -/* Return the KeyMap. */ - return result; -} - -AstChannel *astInitChannel_( void *mem, size_t size, int init, - AstChannelVtab *vtab, const char *name, - const char *(* source)( void ), - char *(* source_wrap)( const char *(*)( void ), int * ), - void (* sink)( const char * ), - void (* sink_wrap)( void (*)( const char * ), - const char *, int * ), int *status ) { -/* -*+ -* Name: -* astInitChannel - -* Purpose: -* Initialise a Channel. - -* Type: -* Protected function. - -* Synopsis: -* #include "channel.h" -* AstChannel *astInitChannel( void *mem, size_t size, int init, -* AstChannelVtab *vtab, const char *name, -* const char *(* source)( void ), -* char *(* source_wrap)( const char *(*)( void ), int * ), -* void (* sink)( const char * ), -* void (* sink_wrap)( void (*)( const char * ), -* const char *, int * ) ) - -* Class Membership: -* Channel initialiser. - -* Description: -* This function is provided for use by class implementations to -* initialise a new Channel object. It allocates memory (if -* necessary) to accommodate the Channel plus any additional data -* associated with the derived class. It then initialises a -* Channel 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 Channel at the start of the memory passed -* via the "vtab" parameter. - -* Parameters: -* mem -* A pointer to the memory in which the Channel is to be -* initialised. This must be of sufficient size to accommodate -* the Channel data (sizeof(Channel)) 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 Channel (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 Channel structure, so a valid value must be -* supplied even if not required for allocating memory. -* init -* A boolean flag indicating if the Channel'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 Channel. -* 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). -* source -* Pointer to a "source" function which will be used to obtain -* lines of input text. Generally, this will be obtained by -* casting a pointer to a source function which is compatible -* with the "source_wrap" wrapper function (below). The pointer -* should later be cast back to its original type by the -* "source_wrap" function before the function is invoked. -* -* If "source" is NULL, the Channel will read from standard -* input instead. -* source_wrap -* Pointer to a function which can be used to invoke the -* "source" function supplied (above). This wrapper function is -* necessary in order to hide variations in the nature of the -* source function, such as may arise when it is supplied by a -* foreign (non-C) language interface. -* -* The single parameter of the "source_wrap" function is a -* pointer to the "source" function, and it should cast this -* function pointer (as necessary) and invoke the function with -* appropriate arguments to obtain the next line of input -* text. The "source_wrap" function should then return a pointer -* to a dynamically allocated, null terminated string containing -* the text that was read. The string will be freed (using -* astFree) when no longer required and the "source_wrap" -* function need not concern itself with this. A NULL pointer -* should be returned if there is no more input to read. -* -* If "source_wrap" is NULL, the Channel will read from standard -* input instead. -* sink -* Pointer to a "sink" function which will be used to deliver -* lines of output text. Generally, this will be obtained by -* casting a pointer to a sink function which is compatible with -* the "sink_wrap" wrapper function (below). The pointer should -* later be cast back to its original type by the "sink_wrap" -* function before the function is invoked. -* -* If "sink" is NULL, the Channel will write to standard output -* instead. -* sink_wrap -* Pointer to a function which can be used to invoke the "sink" -* function supplied (above). This wrapper function is necessary -* in order to hide variations in the nature of the sink -* function, such as may arise when it is supplied by a foreign -* (non-C) language interface. -* -* The first parameter of the "sink_wrap" function is a pointer -* to the "sink" function, and the second parameter is a pointer -* to a const, null-terminated character string containing the -* text to be written. The "sink_wrap" function should cast the -* "sink" function pointer (as necessary) and invoke the -* function with appropriate arguments to deliver the line of -* output text. The "sink_wrap" function then returns void. -* -* If "sink_wrap" is NULL, the Channel will write to standard -* output instead. - -* Returned Value: -* A pointer to the new Channel. - -* 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: */ - AstChannel *new; /* Pointer to new Channel */ - -/* Check the global status. */ - if ( !astOK ) return NULL; - -/* If necessary, initialise the virtual function table. */ - if ( init ) astInitChannelVtab( vtab, name ); - -/* Initialise an Object structure (the parent class) as the first - component within the Channel structure, allocating memory if - necessary. */ - new = (AstChannel *) astInitObject( mem, size, 0, - (AstObjectVtab *) vtab, name ); - - if ( astOK ) { - -/* Initialise the Channel data. */ -/* ---------------------------- */ -/* Save the pointers to the source and sink functions and the wrapper - functions that invoke them. */ - new->source = source; - new->source_wrap = source_wrap; - new->sink = sink; - new->sink_wrap = sink_wrap; - -/* Indicate no input or output files have been associated with the - Channel. */ - new->fd_in = NULL; - new->fn_in = NULL; - new->fd_out = NULL; - new->fn_out = NULL; - -/* Set all attributes to their undefined values. */ - new->comment = -INT_MAX; - new->full = -INT_MAX; - new->indent = -INT_MAX; - new->report_level = -INT_MAX; - new->skip = -INT_MAX; - new->strict = -INT_MAX; - new->data = NULL; - new->warnings = NULL; - new->nwarn = 0; - -/* If an error occurred, clean up by deleting the new object. */ - if ( !astOK ) new = astDelete( new ); - } - -/* Return a pointer to the new object. */ - return new; -} - -void astInitChannelVtab_( AstChannelVtab *vtab, const char *name, int *status ) { -/* -*+ -* Name: -* astInitChannelVtab - -* Purpose: -* Initialise a virtual function table for a Channel. - -* Type: -* Protected function. - -* Synopsis: -* #include "channel.h" -* void astInitChannelVtab( AstChannelVtab *vtab, const char *name ) - -* Class Membership: -* Channel vtab initialiser. - -* Description: -* This function initialises the component of a virtual function -* table which is used by the Channel 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 astIsAChannel) 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->AddWarning = AddWarning; - vtab->ClearComment = ClearComment; - vtab->ClearFull = ClearFull; - vtab->ClearSkip = ClearSkip; - vtab->ClearStrict = ClearStrict; - vtab->GetComment = GetComment; - vtab->GetFull = GetFull; - vtab->GetNextData = GetNextData; - vtab->GetNextText = GetNextText; - vtab->GetSkip = GetSkip; - vtab->GetStrict = GetStrict; - vtab->Warnings = Warnings; - vtab->PutNextText = PutNextText; - vtab->Read = Read; - vtab->ReadClassData = ReadClassData; - vtab->ReadDouble = ReadDouble; - vtab->ReadInt = ReadInt; - vtab->ReadObject = ReadObject; - vtab->ReadString = ReadString; - vtab->SetComment = SetComment; - vtab->SetFull = SetFull; - vtab->SetSkip = SetSkip; - vtab->SetStrict = SetStrict; - vtab->TestComment = TestComment; - vtab->TestFull = TestFull; - vtab->TestSkip = TestSkip; - vtab->TestStrict = TestStrict; - vtab->Write = Write; - vtab->WriteBegin = WriteBegin; - vtab->WriteDouble = WriteDouble; - vtab->WriteEnd = WriteEnd; - vtab->WriteInt = WriteInt; - vtab->WriteIsA = WriteIsA; - vtab->WriteObject = WriteObject; - vtab->WriteString = WriteString; - vtab->PutChannelData = PutChannelData; - - vtab->ClearReportLevel = ClearReportLevel; - vtab->GetReportLevel = GetReportLevel; - vtab->SetReportLevel = SetReportLevel; - vtab->TestReportLevel = TestReportLevel; - - vtab->ClearIndent = ClearIndent; - vtab->GetIndent = GetIndent; - vtab->SetIndent = SetIndent; - vtab->TestIndent = TestIndent; - - vtab->ClearSourceFile = ClearSourceFile; - vtab->GetSourceFile = GetSourceFile; - vtab->SetSourceFile = SetSourceFile; - vtab->TestSourceFile = TestSourceFile; - - vtab->ClearSinkFile = ClearSinkFile; - vtab->GetSinkFile = GetSinkFile; - vtab->SetSinkFile = SetSinkFile; - vtab->TestSinkFile = TestSinkFile; - -/* Save the inherited pointers to methods that will be extended, and - replace them with pointers to the new member functions. */ - object = (AstObjectVtab *) vtab; - - 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; - -/* Declare the destructor and copy constructor. */ - astSetDelete( (AstObjectVtab *) vtab, Delete ); - astSetCopy( (AstObjectVtab *) vtab, Copy ); - -/* Declare the Dump function for this class. There is no destructor or - copy constructor. */ - astSetDump( vtab, Dump, "Channel", "Basic I/O Channel" ); - -/* 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 char *InputTextItem( AstChannel *this, int *status ) { -/* -* Name: -* InputTextItem - -* Purpose: -* Read the next item from a data source as text. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* char *InputTextItem( AstChannel *this ) - -* Class Membership: -* Channel member function. - -* Description: -* This function reads the next input data item as text from the -* data source associated with a Channel. It is similar to the -* astGetNextText method (which it invokes), except that it strips -* off any comments along with leading and trailing white -* space. Input lines which are empty or do not contain significant -* characters (e.g. all comment) are skipped, so that only -* significant lines are returned. -* -* Each line is returned as a pointer to a null-terminated string -* held in dynamic memory, and it is the caller's responsibility to -* free this memory (using astFree) when it is no longer -* required. A NULL pointer is returned if there are no more input -* lines to be read. - -* Parameters: -* this -* Pointer to the Channel. - -* Returned Value: -* Pointer to a null-terminated string containing the input line -* (held in dynamically allocated memory, which must be freed by -* the caller when no longer required). A NULL pointer is returned -* if there are no more input lines to be read. - -* 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: */ - char *line; /* Pointer to line data to be returned */ - int i; /* Loop counter for line characters */ - int j; /* Counter for characters */ - int len; /* Length of result line */ - int nonspace; /* Non-space character encountered? */ - int quoted; /* Character is inside quotes? */ - -/* Initialise. */ - line = NULL; - -/* Check the global error status. */ - if ( !astOK ) return line; - -/* Loop to read input lines until one is found which contains useful - characters or end of file is reached (or a read error occurs). */ - while ( !line && ( line = astGetNextText( this ) ) && astOK ) { - -/* Loop to remove comments and leading and trailing white space. */ - len = 0; - nonspace = 0; - quoted = 0; - for ( i = j = 0; line[ i ]; i++ ) { - -/* Note quote characters and ignore all text after the first unquoted - comment character. */ - if ( line[ i ] == '"' ) quoted = !quoted; - if ( ( line[ i ] == '#' ) && !quoted ) break; - -/* Note the first non-space character and ignore everything before - it. */ - if ( ( nonspace = nonspace || !isspace( line[ i ] ) ) ) { - -/* Move each character to its new position in the string. */ - line[ j++ ] = line[ i ]; - -/* Note the final length of the string (ignoring trailing spaces). */ - if ( !isspace( line[ i ] ) ) len = j; - } - } - -/* If the string is not empty, terminate it. */ - if ( len ) { - line[ len ] = '\0'; - -/* Otherwise, free the memory used for the string so that another - input line will be read. */ - } else { - line = astFree( line ); - } - } - -/* Return the result pointer. */ - return line; - -/* Undefine macros local to this function. */ -#undef MIN_CHARS -} - -static AstChannelValue *LookupValue( const char *name, int *status ) { -/* -* Name: -* LookupValue - -* Purpose: -* Look up a Value structure by name. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* AstChannelValue *LookupValue( const char *name ) - -* Class Membership: -* Channel member function. - -* Description: -* This function searches the current values list (i.e. at the -* current nesting level) to identify a Value structure with a -* specified name. If one is found, it is removed from the list and -* a pointer to it is returned. If no suitable Value can be found, -* a NULL pointer is returned instead. - -* Parameters: -* name -* Pointer to a constant null-terminated character string -* containing the name of the required Value. This must be in -* lower case with no surrounding white space. Note that names -* longer than NAME_MAX characters will not match any Value. - -* Returned value: -* Pointer to the required Value structure, or NULL if no suitable -* Value exists. - -* Notes: -* - The returned pointer refers to a dynamically allocated -* structure and it is the callers responsibility to free this when -* no longer required. The FreeValue function must be used for this -* purpose. -* - 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 */ - AstChannelValue **head; /* Address of head of list pointer */ - AstChannelValue *result; /* Pointer value to return */ - AstChannelValue *value; /* Pointer to list element */ - -/* 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(NULL); - -/* Check that the "values_ok" flag is set. If not, the Values in the - values list belong to a different class to that of the current - class loader, so we cannot return any Value. */ - if ( values_ok[ nest ] ) { - -/* Obtain the address of the current "head of list" pointer for the - values list (at the current nesting level). */ - head = values_list + nest; - -/* Obtain the head of list pointer itself and check the list is not - empty. */ - if ( ( value = *head ) ) { - -/* Loop to inspect each list element. */ - while ( 1 ) { - -/* If a name match is found, remove the element from the list, return - a pointer to it and quit searching. */ - if ( !strcmp( name, value->name ) ) { - RemoveValue( value, head, status ); - result = value; - break; - } - -/* Follow the list until we return to the head. */ - value = value->flink; - if ( value == *head ) break; - } - } - } - -/* Return the result. */ - return result; -} - -static void OutputTextItem( AstChannel *this, const char *line, int *status ) { -/* -* Name: -* OutputTextItem - -* Purpose: -* Output a data item formatted as text. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void OutputTextItem( AstChannel *this, const char *line, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function outputs a data item formatted as a text string to -* a data sink associated with a Channel. It keeps track of the -* number of items written. - -* Parameters: -* this -* Pointer to the Channel. -* line -* Pointer to a constant null-terminated string containing the -* data item to be output (no newline character should be -* appended). -* status -* Pointer to the inherited status variable. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Write out the line of text using the astPutNextText method (which - may be over-ridden). */ - astPutNextText( this, line ); - -/* If successful, increment the count of items written. */ - if ( astOK ) items_written++; -} - -static void PutChannelData( AstChannel *this, void *data, int *status ) { -/* -c++ -* Name: -* astPutChannelData - -* Purpose: -* Store arbitrary data to be passed to a source or sink function. - -* Type: -* Public function. - -* Synopsis: -* #include "channel.h" -* void astPutChannelData( AstChannel *this, void *data ) - -* Class Membership: -* Channel method. - -* Description: -* This function stores a supplied arbitrary pointer in the Channel. -* When a source or sink function is invoked by the Channel, the -* invoked function can use the astChannelData macro to retrieve the -* pointer. This provides a thread-safe alternative to passing file -* descriptors, etc, via global static variables. - -* Parameters: -* this -* Pointer to the Channel. -* data -* A pointer to be made available to the source and sink functions -* via the astChannelData macro. May be NULL. - -* Applicability: -* Channel -* All Channels have this function. - -* Notes: -* - This routine is not available in the Fortran 77 interface to -* the AST library. -c-- -*/ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Store the pointer. */ - this->data = data; -} - -static void PutNextText( AstChannel *this, const char *line, int *status ) { -/* -*+ -* Name: -* astPutNextText - -* Purpose: -* Write a line of output text to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astPutNextText( AstChannel *this, const char *line ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes an output line of text to a data sink -* associated with a Channel. - -* Parameters: -* this -* Pointer to the Channel. -* line -* Pointer to a constant null-terminated string containing the -* line of output text to be written (no newline character -* should be appended). - -* Notes: -* - This method is provided primarily so that derived classes may -* over-ride it in order to write to alternative (textual) data -* sinks. -*- -*/ - -/* Local Constants: */ -#define ERRBUF_LEN 80 - -/* Local Variables: */ - char *errstat; /* Pointer for system error message */ - char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */ - const char *sink_file; /* Path to output sink file */ - const char *source_file; /* Path to output source file */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* If the SinkFile attribute of the Channel specifies an output file, - but no output file has yet been opened, open it now. Report an error - if it is the same as the source file. */ - if( astTestSinkFile( this ) && !this->fd_out ) { - sink_file = astGetSinkFile( this ); - - if( this->fd_out ) { - source_file = astGetSourceFile( this ); - if( astOK && !strcmp( sink_file, source_file ) ) { - astError( AST__WRERR, "astWrite(%s): Failed to open output " - "SinkFile '%s' - the file is currently being used " - "as the input SourceFile.", status, astGetClass( this ), - sink_file ); - } - } - - if( astOK ) { - this->fd_out = fopen( sink_file, "w" ); - if( !this->fd_out ) { - if ( errno ) { -#if HAVE_STRERROR_R - strerror_r( errno, errbuf, ERRBUF_LEN ); - errstat = errbuf; -#else - errstat = strerror( errno ); -#endif - astError( AST__WRERR, "astWrite(%s): Failed to open output " - "SinkFile '%s' - %s.", status, astGetClass( this ), - sink_file, errstat ); - } else { - astError( AST__WRERR, "astWrite(%s): Failed to open output " - "SinkFile '%s'.", status, astGetClass( this ), - sink_file ); - } - } - } - } - -/* Check no error occurred above. */ - if( astOK ) { - -/* If an active output file descriptor is stored in the channel, write - the text to it, with a newline appended. */ - if( this->fd_out ) { - (void) fprintf( this->fd_out, "%s\n", line ); - -/* Otherwise, if a sink function (and its wrapper function) is defined for - the Channel, use the wrapper function to invoke the sink function to - output the text line. Since we are about to call an externally supplied - function which may not be thread-safe, lock a mutex first. Also store - the channel data pointer in a global variable so that it can be accessed - in the source function using macro astChannelData. */ - } else if ( this->sink && this->sink_wrap ) { - astStoreChannelData( this ); - LOCK_MUTEX2; - ( *this->sink_wrap )( *this->sink, line, status ); - UNLOCK_MUTEX2; - -/* Otherwise, simply write the text to standard output with a newline - appended. */ - } else { - (void) printf( "%s\n", line ); - } - } -} - -static AstObject *Read( AstChannel *this, int *status ) { -/* -*++ -* Name: -c astRead -f AST_READ - -* Purpose: -* Read an Object from a Channel. - -* Type: -* Public function. - -* Synopsis: -c #include "channel.h" -c AstObject *astRead( AstChannel *this ) -f RESULT = AST_READ( THIS, STATUS ) - -* Class Membership: -* Channel method. - -* Description: -* This function reads the next Object from a Channel and returns a -* pointer to the new Object. - -* Parameters: -c this -f THIS = INTEGER (Given) -* Pointer to the Channel. -f STATUS = INTEGER (Given and Returned) -f The global status. - -* Returned Value: -c astRead() -f AST_READ = INTEGER -* A pointer to the new Object. The class to which this will -* belong is determined by the input data, so is not known in -* advance. - -* Applicability: -* FitsChan -c All successful use of astRead on a FitsChan is destructive, so that -f All successful use of AST_READ on a FitsChan is destructive, so that -* FITS header cards are consumed in the process of reading an Object, -* and are removed from the FitsChan (this deletion can be prevented -* for specific cards by calling the FitsChan -c astRetainFits function). -f AST_RETAINFITS routine). -* An unsuccessful call of -c astRead -f AST_READ -* (for instance, caused by the FitsChan not containing the necessary -* FITS headers cards needed to create an Object) results in the -* contents of the FitsChan being left unchanged. -* StcsChan -* The AST Object returned by a successful use of -c astRead -f AST_READ -* on an StcsChan, will be either a Region or a KeyMap, depending -* on the values of the StcsArea, StcsCoords and StcsProps -* attributes. See the documentation for these attributes for further -* information. - -* Notes: -* - A null Object pointer (AST__NULL) will be returned, without -* error, if the Channel contains no further Objects to be read. -* - A null Object pointer will also be returned if this function -c is invoked with the AST error status set, or if it should fail -f is invoked with STATUS set to an error value, or if it should fail -* for any reason. -*-- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - AstLoaderType *loader; /* Pointer to loader for Object */ - AstObject *new; /* Pointer to new Object */ - char *class; /* Pointer to Object class name string */ - char *name; /* Pointer to data item name */ - int skip; /* Skip non-AST data? */ - int top; /* Reading top-level Object definition? */ - -/* Initialise. */ - new = NULL; - -/* Check the global error status. */ - if ( !astOK ) return new; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Determine if we are reading a top-level (i.e. user-level) Object - definition, as opposed to the definition of an Object contained - within another Object. This is indicated by the current nesting - level. */ - top = ( nest == -1 ); - -/* If reading a top-level object, determine if data lying in between - Object definitions in the input data stream are to be skipped. */ - skip = ( top && astGetSkip( this ) ); - -/* Read the next input data item. If we are reading a top-level Object - definition, skip any unrelated data beforehand. Otherwise read the - data strictly as it comes (there should be no unrelated data - embedded within Object definitions themselves). */ - astGetNextData( this, skip, &name, &class ); - -/* If no suitable data item was found (and no error occurred), we have - reached the end of data. For a top-level Object a NULL Object - pointer is simply returned, but for a nested Object this indicates - that part of the Object definition is missing, so report an - error. */ - if ( astOK ) { - if ( !name ) { - if ( !top ) { - astError( AST__EOCHN, - "astRead(%s): End of input encountered while trying to " - "read an AST Object.", status, astGetClass( this ) ); - } - -/* If a data item was found, check it is a "Begin" item. If not, there - is a data item missing, so report an error and free all memory. */ - } else if ( strcmp( name, "begin" ) ) { - astError( AST__BADIN, - "astRead(%s): Missing \"Begin\" when expecting an Object.", status, - astGetClass( this ) ); - name = astFree( name ); - if ( class ) class = astFree( class ); - -/* If the required "Begin" item was found, free the memory used for the - name string. */ - } else { - name = astFree( name ); - -/* Use the associated class name to locate the loader for that - class. This function will then be used to build the Object. */ - loader = astGetLoader( class, status ); - -/* Extend all necessary stack arrays to accommodate entries for the - next nesting level (this allocates space if none has yet been - allocated). */ - end_of_object = astGrow( end_of_object, nest + 2, sizeof( int ) ); - object_class = astGrow( object_class, nest + 2, sizeof( char * ) ); - values_class = astGrow( values_class, nest + 2, sizeof( char * ) ); - values_list = astGrow( values_list, nest + 2, sizeof( AstChannelValue * ) ); - values_ok = astGrow( values_ok, nest + 2, sizeof( int ) ); - -/* If an error occurred, free the memory used by the class string, - which will not now be used. */ - if ( !astOK ) { - class = astFree( class ); - -/* Otherwise, increment the nesting level and initialise the new stack - elements for this new level. This includes clearing the - "end_of_object" flag so that ReadClassData can read more data, and - storing the class name of the object we are about to read. */ - } else { - nest++; - end_of_object[ nest ] = 0; - object_class[ nest ] = class; - values_class[ nest ] = NULL; - values_list[ nest ] = NULL; - values_ok[ nest ] = 0; - -/* Invoke the loader, which reads the Object definition from the input - data stream and builds the Object. Supply NULL/zero values to the - loader so that it will substitute values appropriate to its own - class. */ - new = (*loader)( NULL, (size_t) 0, NULL, NULL, this, status ); - -/* Clear the values list for the current nesting level. If the list - has not been read or any Values remain in it, an error will - result. */ - ClearValues( this, status ); - -/* If no error has yet occurred, check that the "end_of_object" flag - has been set. If not, the input data were not correctly terminated, - so report an error. */ - if ( astOK && !end_of_object[ nest ] ) { - astError( AST__BADIN, - "astRead(%s): Unexpected end of input (missing end " - "of %s).", status, - astGetClass( this ), object_class[ nest ] ); - } - -/* If an error occurred, report contextual information. Only do this - for top-level Objects to avoid multple messages. */ - if ( !astOK && top ) { - astError( astStatus, "Error while reading a %s from a %s.", status, - class, astGetClass( this ) ); - } - -/* Clear the Object's class string, freeing the associated memory - (note this is the memory allocated for the "class" string - earlier). */ - object_class[ nest ] = astFree( object_class[ nest ] ); - -/* Restore the previous nesting level. */ - nest--; - } - -/* Once the top-level Object has been built, free the memory used by - the stack arrays. */ - if ( top ) { - end_of_object = astFree( end_of_object ); - object_class = astFree( object_class ); - values_class = astFree( values_class ); - values_list = astFree( values_list ); - values_ok = astFree( values_ok ); - } - } - } - -/* If an error occurred, clean up by deleting the new Object and - return a NULL pointer. */ - if ( !astOK ) new = astDelete( new ); - -/* Return the pointer to the new Object. */ - return new; -} - -static void ReadClassData( AstChannel *this, const char *class, int *status ) { -/* -*+ -* Name: -* astReadClassData - -* Purpose: -* Read values from a data source for a class loader. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astReadClassData( AstChannel *this, const char *class ) - -* Class Membership: -* Channel method. - -* Description: -* This function reads the data for a class from the data source -* associated with a Channel, so as to provide values for -* initialising the instance variables of that class as part of -* building a complete Object. This function should be invoked by -* the loader for each class immediately before it attempts to read -* these values. -* -* The values read are placed into the current values list by this -* function. They may then be read from this list by the class -* loader making calls to astReadDouble, astReadInt, astReadObject -* and astReadString. The order in which values are read by the -* loader is unimportant (although using the same order for reading -* as for writing will usually be more efficient) and values are -* removed from the list as they are read. - -* Parameters: -* this -* Pointer to the Channel. -* class -* A pointer to a constant null-terminated string containing the -* name of the class whose loader is requesting the data (note -* this is not usually the same as the class name of the Object -* being built). This value allows the class structure of the -* input data to be validated. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - AstObject *object; /* Pointer to new Object */ - AstChannelValue *value; /* Pointer to Value structure */ - char *name; /* Pointer to data item name string */ - char *val; /* Pointer to data item value string */ - int done; /* All class data read? */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* If the "values_ok" flag is set, this indicates that the values list - (at the current nesting level) has been filled by a previous - invocation of this function and has then been read by the - appropriate class loader. In this case, clear any entries which may - remain in the current values list. If any such entries are found, - they represent input data that were not read, so an error will - result. */ - if ( values_ok[ nest ] ) ClearValues( this, status ); - -/* If "values_class" is non-NULL, this indicates that the values list - (at the current nesting level) has been filled by a previous - invocation of this function, but that the values belong to a class - whose loader has not yet tried to read them. In this case, we must - continue to keep the values until they are needed, so we do not - read any more input data this time. */ - if ( values_class[ nest ] ) { - -/* If the class to which the previously saved values belong matches - the class we now want values for, set the "values_ok" flag. This - then allows the values to be accessed (by LookupValue). */ - values_ok[ nest ] = !strcmp( values_class[ nest ], class ); - -/* If the current values list is empty, we must read in values for the - next class that appears in the input data. However, first check - that the "end_of_object" flag has not been set. If it has, we have - already reached the end of this Object's data, so there is some - kind of problem with the order in which class loaders have been - invoked. This will probably never happen, but report an error if - necessary. */ - } else if ( end_of_object[ nest ] ) { - astError( AST__LDERR, - "astRead(%s): Invalid attempt to read further %s data " - "following an end of %s.", status, - astGetClass( this ), class, object_class[ nest ] ); - astError( AST__LDERR, - "Perhaps the wrong class loader has been invoked?" , status); - -/* If we need new values, loop to read input data items until the end - of the data for a class is reached. */ - } else { - done = 0; - while ( astOK && !done ) { - -/* Read the next input data item. */ - astGetNextData( this, 0, &name, &val ); - if ( astOK ) { - -/* Unexpected end of input. */ -/* ------------------------ */ -/* If no "name" value is returned, we have reached the end of the - input data stream without finding the required end of class - terminator, so report an error. */ - if ( !name ) { - astError( AST__EOCHN, - "astRead(%s): Unexpected end of input (missing end " - "of %s).", status, - astGetClass( this ), object_class[ nest ] ); - -/* "IsA" item. */ -/* ----------- */ -/* Otherwise, if an "IsA" item was read, it indicates the end of the - data for a class. Store the pointer to the name of this class in - "values_class" and note whether this is the class whose data we - wanted in "values_ok". If the data we have read do not belong to - the class we wanted, they will simply be kept until the right class - comes looking for them. */ - } else if ( !strcmp( name, "isa" ) ) { - values_class[ nest ] = val; - values_ok[ nest ] = !strcmp( val, class ); - -/* Free the memory holding the name string. */ - name = astFree( name ); - -/* Note we have finished reading class data. */ - done = 1; - -/* "End" item. */ -/* ----------- */ -/* If an "End" item was read, it indicates the end of the data both - for a class and for the current Object definition as a whole. Set - the "end_of_object" flag (for the current nesting level) which - prevents any further data being read for this Object. This flag is - also used (by Read) to check that an "End" item was actually - read. */ - } else if ( !strcmp( name, "end" ) ) { - end_of_object[ nest ] = 1; - -/* Check that the class name in the "End" item matches that of the - Object being built. If so, store the pointer to the name of this - class in "values_class" and note whether this is the class whose - data we wanted in "values_ok". If the data we have read do not - belong to the class we wanted, they will simply be kept until the - right class comes looking for them. */ - if ( !strcmp( val, object_class[ nest ] ) ) { - values_class[ nest ] = val; - values_ok[ nest ] = !strcmp( class, val ); - -/* If the "End" item contains the wrong class name (i.e. not matching - the corresponding "Begin" item), then report an error. */ - } else { - astError( AST__BADIN, - "astRead(%s): Bad class structure in input data.", status, - astGetClass( this ) ); - astError( AST__BADIN, - "End of %s read when expecting end of %s.", status, - val, object_class[ nest ] ); - -/* Free the memory used by the class string, which will not now be - used. */ - val = astFree( val ); - } - -/* Free the memory holding the name string. */ - name = astFree( name ); - -/* Note we have finished reading class data. */ - done = 1; - -/* String value. */ -/* ------------- */ -/* If any other name is obtained and "val" is not NULL, we have read a - non-Object value, encoded as a string. Allocate memory for a Value - structure to describe it. */ - } else if ( val ) { - value = astMalloc( sizeof( AstChannelValue ) ); - if ( astOK ) { - -/* Store pointers to the name and value string in the Value structure - and note this is not an Object value. */ - value->name = name; - value->ptr.string = val; - value->is_object = 0; - -/* Append the Value structure to the values list for the current - nesting level. */ - AppendValue( value, values_list + nest, status ); - -/* If an error occurred, free the memory holding the "name" and "val" - strings. */ - } else { - name = astFree( name ); - val = astFree( val ); - } - -/* Object value. */ -/* ------------- */ -/* If "val" is NULL, we have read an Object item, and the Object - definition should follow. Allocate memory for a Value structure to - describe it. */ - } else { - value = astMalloc( sizeof( AstChannelValue ) ); - -/* Invoke astRead to read the Object definition from subsequent data - items and to build the Object, returning a pointer to it. This will - result in recursive calls to the current function, but as these - will use higher nesting levels they will not interfere with the - current invocation. */ - astreadclassdata_msg = 0; - object = astRead( this ); - if ( astOK ) { - -/* Store pointers to the name and Object in the Value structure and - note this is an Object value. */ - value->name = name; - value->ptr.object = object; - value->is_object = 1; - -/* Append the Value structure to the values list for the current - nesting level. */ - AppendValue( value, values_list + nest, status ); - -/* If an error occurred, report a contextual error maessage and set - the "astreadclassdata_msg" flag (this prevents multiple messages if this function is - invoked recursively to deal with nested Objects). */ - } else { - if ( !astreadclassdata_msg ) { - astError( astStatus, - "Failed to read the \"%s\" Object value.", status, - name ); - astreadclassdata_msg = 1; - } - -/* Free the memory holding the "name" string and any Value structure - that was allocated. */ - name = astFree( name ); - value = astFree( value ); - } - } - } - } - } -} - -static double ReadDouble( AstChannel *this, const char *name, double def, int *status ) { -/* -*+ -* Name: -* astReadDouble - -* Purpose: -* Read a double value as part of loading a class. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* double astReadDouble( AstChannel *this, const char *name, double def ) - -* Class Membership: -* Channel method. - -* Description: -* This function searches the current values list of a Channel to -* identify a double value with a specified name. If such a value -* is found, it is returned, otherwise a default value is returned -* instead. -* -* This function should only be invoked from within the loader -* function associated with a class, in order to return a double -* value to be assigned to an instance variable. It must be -* preceded by a call to the astReadClassData function, which loads -* the values associated with the class into the current values -* list from the input data source. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated character string -* containing the name of the required value. This must be in -* lower case with no surrounding white space. Note that names -* longer than 6 characters will not match any value. -* def -* If no suitable value can be found (e.g. it is absent from the -* data stream being read), then this value will be returned -* instead. - -* Returned Value: -* The required value, or the default if the value was not found. - -* Notes: -* - A value of 0.0 will be returned if this function is invoked -* with the global error status set, or if it should fail for any -* reason. -*- -*/ - -/* Local Variables: */ - AstChannelValue *value; /* Pointer to required Value structure */ - double result; /* Value to be returned */ - int nc; /* Number of characters read by astSscanf */ - -/* Initialise. */ - result = 0.0; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Search for a Value structure with the required name in the current - values list.*/ - value = LookupValue( name, status ); - if ( astOK ) { - -/* If a Value was found, check that it describes a string (as opposed - to an Object). */ - if ( value ) { - if ( !value->is_object ) { - -/* If so, then attempt to decode the string to give a double value, - checking that the entire string is read (and checking for the magic string - used to represent bad values). If this fails, then the wrong name has - probably been given, or the input data are corrupt, so report an error. */ - nc = 0; - if ( ( 0 == astSscanf( value->ptr.string, " " BAD_STRING " %n", - &nc ) ) - && ( nc >= (int) strlen( value->ptr.string ) ) ) { - result = AST__BAD; - - } else if ( !( ( 1 == astSscanf( value->ptr.string, " %lf %n", - &result, &nc ) ) - && ( nc >= (int) strlen( value->ptr.string ) ) ) ) { - astError( AST__BADIN, - "astRead(%s): The value \"%s = %s\" cannot " - "be read as a double precision floating point " - "number.", status, astGetClass( this ), - value->name, value->ptr.string ); - - } else if( !astISFINITE( result ) ) { - astError( AST__BADIN, - "astRead(%s): Illegal double precision floating " - "point value \"%s\" read for \"%s\".", status, - astGetClass( this ), value->ptr.string, value->name ); - - } - -/* Report a similar error if the Value does not describe a string. */ - } else { - astError( AST__BADIN, - "astRead(%s): The Object \"%s = <%s>\" cannot " - "be read as a double precision floating point number.", status, - astGetClass( this ), - value->name, astGetClass( value->ptr.object ) ); - } - -/* Free the Value structure and the resources it points at. */ - value = FreeValue( value, status ); - -/* If no suitable Value structure was found, then use the default - value instead. */ - } else { - result = def; - } - } - -/* Return the result. */ - return result; -} - -static int ReadInt( AstChannel *this, const char *name, int def, int *status ) { -/* -*+ -* Name: -* astReadInt - -* Purpose: -* Read an int value as part of loading a class. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* int astReadInt( AstChannel *this, const char *name, int def ) - -* Class Membership: -* Channel method. - -* Description: -* This function searches the current values list of a Channel to -* identify an int value with a specified name. If such a value is -* found, it is returned, otherwise a default value is returned -* instead. -* -* This function should only be invoked from within the loader -* function associated with a class, in order to return an int -* value to be assigned to an instance variable. It must be -* preceded by a call to the astReadClassData function, which loads -* the values associated with the class into the current values -* list from the input data source. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated character string -* containing the name of the required value. This must be in -* lower case with no surrounding white space. Note that names -* longer than 6 characters will not match any value. -* def -* If no suitable value can be found (e.g. it is absent from the -* data stream being read), then this value will be returned -* instead. - -* Returned Value: -* The required value, or the default if the value was not found. - -* 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: */ - AstChannelValue *value; /* Pointer to required Value structure */ - int nc; /* Number of characters read by astSscanf */ - int result; /* Value to be returned */ - -/* Initialise. */ - result = 0; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Search for a Value structure with the required name in the current - values list.*/ - value = LookupValue( name, status ); - if ( astOK ) { - -/* If a Value was found, check that it describes a string (as opposed - to an Object). */ - if ( value ) { - if ( !value->is_object ) { - -/* If so, then attempt to decode the string to give an int value, - checking that the entire string is read. If this fails, then the - wrong name has probably been given, or the input data are corrupt, - so report an error. */ - nc = 0; - if ( !( ( 1 == astSscanf( value->ptr.string, " %d %n", - &result, &nc ) ) - && ( nc >= (int) strlen( value->ptr.string ) ) ) ) { - astError( AST__BADIN, - "astRead(%s): The value \"%s = %s\" cannot " - "be read as an integer.", status, astGetClass( this ), - value->name, value->ptr.string ); - } - -/* Report a similar error if the Value does not describe a string. */ - } else { - astError( AST__BADIN, - "astRead(%s): The Object \"%s = <%s>\" cannot " - "be read as an integer.", status, astGetClass( this ), - value->name, astGetClass( value->ptr.object ) ); - } - -/* Free the Value structure and the resources it points at. */ - value = FreeValue( value, status ); - -/* If no suitable Value structure was found, then use the default - value instead. */ - } else { - result = def; - } - } - -/* Return the result. */ - return result; -} - -static AstObject *ReadObject( AstChannel *this, const char *name, - AstObject *def, int *status ) { -/* -*+ -* Name: -* astReadObject - -* Purpose: -* Read a (sub)Object as part of loading a class. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* AstObject *astReadObject( AstChannel *this, const char *name, -* AstObject *def ) - -* Class Membership: -* Channel method. - -* Description: -* This function searches the current values list of a Channel to -* identify an Object with a specified name. If such an Object is -* found, a pointer to it is returned, otherwise a default pointer -* is returned instead. -* -* This function should only be invoked from within the loader -* function associated with a class, in order to return an Object -* pointer value to be assigned to an instance variable. It must be -* preceded by a call to the astReadClassData function, which loads -* the values associated with the class into the current values -* list from the input data source. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated character string -* containing the name of the required Object. This must be in -* lower case with no surrounding white space. Note that names -* longer than 6 characters will not match any Object. -* def -* If no suitable Object can be found (e.g. the Object is absent -* from the data stream being read), then a clone of this -* default Object pointer will be returned instead (or NULL if -* this default pointer is NULL). - -* Returned Value: -* A pointer to the Object, or a clone of the default pointer if -* the Object was not found. - -* 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: */ - AstObject *result; /* Pointer value to return */ - AstChannelValue *value; /* Pointer to required Value structure */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Search for a Value structure with the required name in the current - values list.*/ - value = LookupValue( name, status ); - if ( astOK ) { - -/* If a Value was found, check that it describes an Object (as opposed to - a string). */ - if ( value ) { - if ( value->is_object ) { - -/* If so, then extract the Object pointer, replacing it with NULL. */ - result = value->ptr.object; - value->ptr.object = NULL; - -/* If the Value does not describe an Object, then the wrong name has - probably been given, or the input data are corrupt, so report an - error. */ - } else { - astError( AST__BADIN, - "astRead(%s): The value \"%s = %s\" cannot be " - "read as an Object.", status, astGetClass( this ), - value->name, value->ptr.string ); - } - -/* Free the Value structure and the resources it points at. */ - value = FreeValue( value, status ); - -/* If no suitable Value structure was found, clone the default - pointer, if given. */ - } else if ( def ) { - result = astClone( def ); - } - } - -/* Return the result. */ - return result; -} - -static char *ReadString( AstChannel *this, const char *name, - const char *def, int *status ) { -/* -*+ -* Name: -* astReadString - -* Purpose: -* Read a string value as part of loading a class. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* char *astReadString( AstChannel *this, const char *name, -* const char *def ) - -* Class Membership: -* Channel method. - -* Description: -* This function searches the current values list of a Channel to -* identify a string value with a specified name. If such a value -* is found, a pointer to the string is returned, otherwise a -* pointer to a copy of a default string is returned instead. -* -* This function should only be invoked from within the loader -* function associated with a class, in order to return a string -* pointer value to be assigned to an instance variable. It must be -* preceded by a call to the astReadClassData function, which loads -* the values associated with the class into the current values -* list from the input data source. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated character string -* containing the name of the required value. This must be in -* lower case with no surrounding white space. Note that names -* longer than 6 characters will not match any value. -* def -* If no suitable string can be found (e.g. the value is absent -* from the data stream being read), then a dynamically -* allocated copy of the null-terminated string pointed at by -* "def" will be made, and a pointer to this copy will be -* returned instead (or NULL if this default pointer is NULL). - -* Returned Value: -* A pointer to a dynamically allocated null-terminated string -* containing the value required, or to a copy of the default -* string if the value was not found (or NULL if the "def" pointer -* was NULL). - -* Notes: -* - It is the caller's responsibility to arrange for the memory -* holding the returned string to be freed (using astFree) when it -* is no longer required. -* - 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: */ - AstChannelValue *value; /* Pointer to required Value structure */ - char *result; /* Pointer value to return */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Search for a Value structure with the required name in the current - values list.*/ - value = LookupValue( name, status ); - if ( astOK ) { - -/* If a Value was found, check that it describes a string (as opposed - to an Object). */ - if ( value ) { - if ( !value->is_object ) { - -/* If so, then extract the string pointer, replacing it with NULL. */ - result = value->ptr.string; - value->ptr.string = NULL; - -/* If the Value does not describe a string, then the wrong name has - probably been given, or the input data are corrupt, so report an - error. */ - } else { - astError( AST__BADIN, - "astRead(%s): The Object \"%s = <%s>\" cannot " - "be read as a string.", status, astGetClass( this ), - value->name, astGetClass( value->ptr.object ) ); - } - -/* Free the Value structure and the resources it points at. */ - value = FreeValue( value, status ); - -/* If no suitable Value structure was found, then make a dynamic copy - of the default string (if given) and return a pointer to this. */ - } else if ( def ) { - result = astStore( NULL, def, strlen( def ) + (size_t) 1 ); - } - } - -/* Return the result. */ - return result; -} - -static void RemoveValue( AstChannelValue *value, AstChannelValue **head, int *status ) { -/* -* Name: -* RemoveValue - -* Purpose: -* Remove a Value structure from a circular linked list. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void RemoveValue( AstChannelValue *value, AstChannelValue **head, int *status ); - -* Class Membership: -* Channel member function. - -* Description: -* This function removes a Value structure from a doubly linked -* circular list of such structures. The "head of list" pointer is -* updated to point at the element following the one removed. - -* Parameters: -* value -* Pointer to the structure to be removed (note that this must -* actually be in the list, although this function does not -* check). -* head -* Address of a pointer to the element at the head of the -* list. This pointer will be updated to point at the list -* element that follows the one removed. If the list becomes -* empty, the pointer will be set to NULL. -* status -* Pointer to the inherited status variable. - -* Notes: -* - This function does not perform error chacking and does not -* generate errors. -*/ - -/* Remove the Value structure from the list by re-establishing links - between the elements on either side of it. */ - value->blink->flink = value->flink; - value->flink->blink = value->blink; - -/* Update the head of list pointer to identify the following - element. */ - *head = value->flink; - -/* If the head of list identifies the removed element, then note that - the list is now empty. */ - if ( *head == value ) *head = NULL; - -/* Make the removed element point at itself. */ - value->flink = value; - value->blink = value; -} - -static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { -/* -* Name: -* SetAttrib - -* Purpose: -* Set an attribute value for a Channel. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void SetAttrib( AstObject *this, const char *setting ) - -* Class Membership: -* Channel member function (over-rides the astSetAttrib protected -* method inherited from the Object class). - -* Description: -* This function assigns an attribute value for a Channel, 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 Channel. -* setting -* Pointer to a null terminated string specifying the new attribute -* value. -*/ - -/* Local Variables: */ - AstChannel *this; /* Pointer to the Channel structure */ - int comment; /* Comment attribute value */ - int full; /* Full attribute value */ - int indent; /* Indent attribute value */ - int len; /* Length of setting string */ - int nc; /* Number of characters read by "astSscanf" */ - int report_level; /* Skip attribute value */ - int skip; /* Skip attribute value */ - int sourcefile; /* Offset of SourceFile string */ - int sinkfile; /* Offset of SinkFile string */ - int strict; /* Report errors instead of warnings? */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Obtain a pointer to the Channel structure. */ - this = (AstChannel *) 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. */ - -/* Comment. */ -/* ---------*/ - if ( nc = 0, - ( 1 == astSscanf( setting, "comment= %d %n", &comment, &nc ) ) - && ( nc >= len ) ) { - astSetComment( this, comment ); - -/* Full. */ -/* ----- */ - } else if ( nc = 0, - ( 1 == astSscanf( setting, "full= %d %n", &full, &nc ) ) - && ( nc >= len ) ) { - astSetFull( this, full ); - -/* Indent. */ -/* ------- */ - } else if ( nc = 0, - ( 1 == astSscanf( setting, "indent= %d %n", &indent, &nc ) ) - && ( nc >= len ) ) { - astSetIndent( this, indent ); - -/* ReportLavel. */ -/* ------------ */ - } else if ( nc = 0, - ( 1 == astSscanf( setting, "reportlevel= %d %n", &report_level, &nc ) ) - && ( nc >= len ) ) { - astSetReportLevel( this, report_level ); - -/* Skip. */ -/* ----- */ - } else if ( nc = 0, - ( 1 == astSscanf( setting, "skip= %d %n", &skip, &nc ) ) - && ( nc >= len ) ) { - astSetSkip( this, skip ); - -/* SinkFile. */ -/* --------- */ - } else if ( nc = 0, - ( 0 == astSscanf( setting, "sinkfile=%n%*[^\n]%n", &sinkfile, &nc ) ) - && ( nc >= len ) ) { - astSetSinkFile( this, setting + sinkfile ); - -/* SourceFile. */ -/* ----------- */ - } else if ( nc = 0, - ( 0 == astSscanf( setting, "sourcefile=%n%*[^\n]%n", &sourcefile, &nc ) ) - && ( nc >= len ) ) { - astSetSourceFile( this, setting + sourcefile ); - -/* Strict. */ -/* ------- */ - } else if ( nc = 0, - ( 1 == astSscanf( setting, "strict= %d %n", &strict, &nc ) ) - && ( nc >= len ) ) { - astSetStrict( this, strict ); - -/* 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 SinkWrap( void (* sink)( const char * ), const char *line, int *status ) { -/* -* Name: -* SinkWrap - -* Purpose: -* Wrapper function to invoke a C Channel sink function. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function invokes the sink function whose pointer is -* supplied in order to write an output line to an external data -* store. - -* Parameters: -* sink -* Pointer to a sink function, whose single parameter is a -* pointer to a const, null-terminated string containing the -* text to be written, and which returns void. This is the form -* of Channel sink function employed by the C language interface -* to the AST library. -* status -* Pointer to the inherited status variable. -*/ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Invoke the sink function. */ - ( *sink )( line ); -} - -static char *SourceWrap( const char *(* source)( void ), int *status ) { -/* -* Name: -* SourceWrap - -* Purpose: -* Wrapper function to invoke a C Channel source function. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* char *SourceWrap( const char *, int *status(* source)( void ) ) - -* Class Membership: -* Channel member function. - -* Description: -* This function invokes the source function whose pointer is -* supplied in order to read the next input line from an external -* data store. It then returns a pointer to a dynamic string -* containing a copy of the text that was read. - -* Parameters: -* source -* Pointer to a source function, with no parameters, that -* returns a pointer to a const, null-terminated string -* containing the text that it read. This is the form of Channel -* source function employed by the C language interface to the -* AST library. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* A pointer to a dynamically allocated, null terminated string -* containing a copy of the text that was read. This string must be -* freed by the caller (using astFree) when no longer required. -* -* A NULL pointer will be returned if there is no more input text -* to read. - -* Notes: -* - A NULL pointer value will be returned if this function is -* invoked with the global error status set or if it should fail -* for any reason. -*/ - -/* Local Variables: */ - char *result; /* Pointer value to return */ - const char *line; /* Pointer to input line */ - -/* Initialise. */ - result = NULL; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Invoke the source function to read the next input line and return a - pointer to the resulting string. */ - line = ( *source )(); - -/* If a string was obtained, make a dynamic copy of it and save the - resulting pointer. */ - if ( line ) result = astString( line, (int) strlen( line ) ); - -/* Return the result. */ - return result; -} - -void astStoreChannelData_( AstChannel *this, int *status ) { -/* -*+ -* Name: -* astStoreChannelData - -* Purpose: -* Store the Channel's channel-data pointer in a thread-specific -* global variable. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* astStoreChannelData( AstChannel *this ) - -* Class Membership: -* Channel method. - -* Description: -* This function stores the Channel's channel-data pointer (if any) -* established by the previous call to astPutChannelData, in a -* thread-specific global variable from where the astChannelData macro -* can access it. - -* Parameters: -* this -* Pointer to the Channel. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Store the pointer int he global variable. */ - channel_data = this->data; -} - -static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { -/* -* Name: -* TestAttrib - -* Purpose: -* Test if a specified attribute value is set for a Channel. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* int TestAttrib( AstObject *this, const char *attrib, int *status ) - -* Class Membership: -* Channel member function (over-rides the astTestAttrib protected -* method inherited from the Object class). - -* Description: -* This function returns a boolean result (0 or 1) to indicate whether -* a value has been set for one of a Channel's attributes. - -* Parameters: -* this -* Pointer to the Channel. -* 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: */ - AstChannel *this; /* Pointer to the Channel structure */ - int result; /* Result value to return */ - -/* Initialise. */ - result = 0; - -/* Check the global error status. */ - if ( !astOK ) return result; - -/* Obtain a pointer to the Channel structure. */ - this = (AstChannel *) this_object; - -/* Check the attribute name and test the appropriate attribute. */ - -/* Comment. */ -/* -------- */ - if ( !strcmp( attrib, "comment" ) ) { - result = astTestComment( this ); - -/* Full. */ -/* ----- */ - } else if ( !strcmp( attrib, "full" ) ) { - result = astTestFull( this ); - -/* Indent. */ -/* ------- */ - } else if ( !strcmp( attrib, "indent" ) ) { - result = astTestIndent( this ); - -/* ReportLevel. */ -/* ------------ */ - } else if ( !strcmp( attrib, "reportlevel" ) ) { - result = astTestReportLevel( this ); - -/* Skip. */ -/* ----- */ - } else if ( !strcmp( attrib, "skip" ) ) { - result = astTestSkip( this ); - -/* SourceFile. */ -/* ----------- */ - } else if ( !strcmp( attrib, "sourcefile" ) ) { - result = astTestSourceFile( this ); - -/* SinkFile. */ -/* ----------- */ - } else if ( !strcmp( attrib, "sinkfile" ) ) { - result = astTestSinkFile( this ); - -/* Strict. */ -/* ------- */ - } else if ( !strcmp( attrib, "strict" ) ) { - result = astTestStrict( 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 void Unquote( AstChannel *this, char *str, int *status ) { -/* -* Name: -* Unquote - -* Purpose: -* Remove quotes from a (possibly) quoted string. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* void Unquote( AstChannel *this, char *str, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function removes one layer of quote characters (") from a -* string which is possibly quoted. Any quotes within quotes (which -* should have been doubled when the string was originally quoted) -* are also converted back to single quotes again. -* -* The quotes need not start or end at the ends of the string, and -* there may be any number of quoted sections within the string. No -* error results if the string does not contain any quotes at all -* (it is simply returned unchanged), but an error results if any -* unmatched quotes are found. - -* Parameters: -* this -* Pointer to a Channel. This is only used for constructing error -* messages and has no influence on the string processing. -* str -* Pointer to the null-terminated string to be processed. This -* is modified in place. The new string starts at the same -* location as the original but has a new null character -* appended if necessary (it will usually be shorter than the -* original). -* status -* Pointer to the inherited status variable. -*/ - -/* Local Variables: */ - int i; /* Loop counter for "input" characters */ - int j; /* Counter for "output" characters */ - int quoted; /* Inside a quoted string? */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Loop to inspect each character in the string. */ - quoted = 0; - for ( i = j = 0; str[ i ]; i++ ) { - -/* Non-quote characters are simply copied to their new location in the - string. */ - if ( str[ i ] != '"' ) { - str[ j++ ] = str[ i ]; - -/* If a quote character '"' is encountered and we are not already in a - quoted string, then note the start of a quoted string (and discard - the quote). */ - } else if ( !quoted ) { - quoted = 1; - -/* If a quote character is encountered inside a quoted string, then - check if the next character is also a quote. If so, convert this - double quote to a single one. */ - } else if ( str[ i + 1 ] == '"' ) { - str[ j++ ] = '"'; - i++; - -/* If a single quote character is encountered inside a quoted string, - then note the end of the quoted string (and discard the quote). */ - } else { - quoted = 0; - } - } - -/* Append a null to terminate the processed string. */ - str[ j ] = '\0'; - -/* If the "quoted" flag is still set, then there were unmatched - quotes, so report an error. */ - if ( quoted ) { - astError( AST__UNMQT, - "astRead(%s): Unmatched quotes in input data: %s.", status, - astGetClass( this ), str ); - } -} - -static int Use( AstChannel *this, int set, int helpful, int *status ) { -/* -* Name: -* Use - -* Purpose: -* Decide whether to write a value to a data sink. - -* Type: -* Private function. - -* Synopsis: -* #include "channel.h" -* int Use( AstChannel *this, int set, int helpful, int *status ) - -* Class Membership: -* Channel member function. - -* Description: -* This function decides whether a value supplied by a class "Dump" -* function, via a call to one of the astWrite... protected -* methods, should actually be written to the data sink associated -* with a Channel. -* -* This decision is based on the settings of the "set" and -* "helpful" flags supplied to the astWrite... method, plus the -* attribute settings of the Channel. - -* Parameters: -* this -* A pointer to the Channel. -* set -* The "set" flag supplied. -* helpful -* The "helpful" value supplied. -* status -* Pointer to the inherited status variable. - -* Returned Value: -* One if the value should be written out, otherwise zero. - -* 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: */ - int full; /* Full attribute value */ - int result; /* Result value to be returned */ - -/* Check the global error status. */ - if ( !astOK ) return 0; - -/* If "set" is non-zero, then so is the result ("set" values must - always be written out). */ - result = ( set != 0 ); - -/* Otherwise, obtain the value of the Channel's Full attribute. */ - if ( !set ) { - full = astGetFull( this ); - -/* If Full is positive, display all values, if zero, display only - "helpful" values, if negative, display no (un-"set") values. */ - if ( astOK ) result = ( ( helpful && ( full > -1 ) ) || ( full > 0 ) ); - } - -/* Return the result. */ - return result; -} - -static int Write( AstChannel *this, AstObject *object, int *status ) { -/* -*++ -* Name: -c astWrite -f AST_WRITE - -* Purpose: -* Write an Object to a Channel. - -* Type: -* Public function. - -* Synopsis: -c #include "channel.h" -c int astWrite( AstChannel *this, AstObject *object ) -f RESULT = AST_WRITE( THIS, OBJECT, STATUS ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes an Object to a Channel, appending it to any -* previous Objects written to that Channel. - -* Parameters: -c this -f THIS = INTEGER (Given) -* Pointer to the Channel. -c object -f OBJECT = INTEGER (Given) -* Pointer to the Object which is to be written. -f STATUS = INTEGER (Given and Returned) -f The global status. - -* Returned Value: -c astWrite() -f AST_WRITE = INTEGER -* The number of Objects written to the Channel by this -c invocation of astWrite (normally, this will be one). -f invocation of AST_WRITE (normally, this will be one). - -* Applicability: -* FitsChan -* If the FitsChan uses a foreign encoding (e.g. FITS-WCS) rather -* than the native AST encoding, then storing values in the -* FitsChan for keywords NAXIS1, NAXIS2, etc., before invoking -c astWrite -f AST_WRITE -* can help to produce a successful write. - -* Notes: -* - A value of zero will be returned if this function is invoked -c with the AST error status set, or if it should fail for any -f with STATUS set to an error value, or if it should fail for any -* reason. -* - Invoking this function will usually cause the sink function -* associated with the channel to be called in order to transfer a -* textual description of the supplied object to some external data -* store. However, the FitsChan class behaves differently. Invoking -* this function on a FitsChan causes new FITS header cards to be -* added to an internal buffer (the sink function is not invoked). -* This buffer is written out through the sink function only when the -* FitsChan is deleted. -*-- -*/ - -/* Check the global error status. */ - if ( !astOK ) return 0; - -/* The work of this function is actually performed by the protected - astDump method of the Object. The fact that this is further - encapsulated within the astWrite method (which belongs to the - Channel) is simply a trick to allow it to be over-ridden either by - a derived Channel, or a derived Object (or both), and hence to - adapt to the nature of either argument. */ - astDump( object, this ); - -/* Return the number of Objects written. */ - return astOK ? 1 : 0; -} - -static void WriteBegin( AstChannel *this, const char *class, - const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteBegin - -* Purpose: -* Write a "Begin" data item to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteBegin( AstChannel *this, const char *class, -* const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes a "Begin" data item to the data sink -* associated with a Channel, so as to begin the output of a new -* Object definition. - -* Parameters: -* this -* Pointer to the Channel. -* class -* Pointer to a constant null-terminated string containing the -* name of the class to which the Object belongs. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the "Begin" -* item. Normally, this will describe the purpose of the Object. - -* Notes: -* - The comment supplied may not actually be used, depending on -* the nature of the Channel supplied. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - int i; /* Loop counter for indentation characters */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Start building a dynamic string with an initial space. Then add - further spaces to suit the current indentation level. */ - line = astAppendString( NULL, &nc, " " ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the "Begin" keyword followed by the class name. */ - line = astAppendString( line, &nc, "Begin " ); - line = astAppendString( line, &nc, class ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - -/* Increment the indentation level and clear the count of items written - for this Object. */ - current_indent += astGetIndent( this ); - items_written = 0; -} - -static void WriteDouble( AstChannel *this, const char *name, - int set, int helpful, - double value, const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteDouble - -* Purpose: -* Write a double value to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteDouble( AstChannel *this, const char *name, -* int set, int helpful, -* double value, const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes a named double value, representing the -* value of a class instance variable, to the data sink associated -* with a Channel. It is intended for use by class "Dump" functions -* when writing out class information which will subsequently be -* re-read. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated string containing the -* name to be used to identify the value in the external -* representation. This will form the key for identifying it -* again when it is re-read. The name supplied should be unique -* within its class. -* -* Mixed case may be used and will be preserved in the external -* representation (where possible) for cosmetic effect. However, -* case is not significant when re-reading values. -* -* It is recommended that a maximum of 6 alphanumeric characters -* (starting with an alphabetic character) be used. This permits -* maximum flexibility in adapting to standard external data -* representations (e.g. FITS). -* set -* If this is zero, it indicates that the value being written is -* a default value (or can be re-generated from other values) so -* need not necessarily be written out. Such values will -* typically be included in the external representation with -* (e.g.) a comment character so that they are available to -* human readers but will be ignored when re-read. They may also -* be completely omitted in some circumstances. -* -* If "set" is non-zero, the value will always be explicitly -* included in the external representation so that it can be -* re-read. -* helpful -* This flag provides a hint about whether a value whose "set" -* flag is zero (above) should actually appear at all in the -* external representaton. -* -* If the external representation allows values to be "commented -* out" then, by default, values will be included in this form -* only if their "helpful" flag is non-zero. Otherwise, they -* will be omitted entirely. When possible, omitting the more -* obscure values associated with a class is recommended in -* order to improve readability. -* -* This default behaviour may be further modified if the -* Channel's Full attribute is set - either to permit all values -* to be shown, or to suppress non-essential information -* entirely. -* value -* The value to be written. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the value. -* -* Note that this comment may not actually be used, depending on -* the nature of the Channel supplied and the setting of its -* Comment attribute. -*- -*/ - -/* Local Constants: */ -#define BUFF_LEN 100 /* Size of local formatting buffer */ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - char buff[ BUFF_LEN + 1 ]; /* Local formatting buffer */ - int i; /* Loop counter for indentation characters */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Use the "set" and "helpful" flags, along with the Channel's - attributes to decide whether this value should actually be - written. */ - if ( Use( this, set, helpful, status ) ) { - -/* Start building a dynamic string with an initial space, or a comment - character if "set" is zero. Then add further spaces to suit the - current indentation level. */ - line = astAppendString( NULL, &nc, set ? " " : "#" ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the name string followed by " = ". */ - line = astAppendString( line, &nc, name ); - line = astAppendString( line, &nc, " = " ); - -/* Format the value as a string and append this. Make sure "-0" isn't - produced. Use a magic string to represent bad values. */ - if( value != AST__BAD ) { - (void) sprintf( buff, "%.*g", AST__DBL_DIG, value ); - if ( !strcmp( buff, "-0" ) ) { - buff[ 0 ] = '0'; - buff[ 1 ] = '\0'; - } - } else { - strcpy( buff, BAD_STRING ); - } - line = astAppendString( line, &nc, buff ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - } - -/* Undefine macros local to this function. */ -#undef BUFF_LEN -} - -static void WriteEnd( AstChannel *this, const char *class, int *status ) { -/* -*+ -* Name: -* astWriteEnd - -* Purpose: -* Write an "End" data item to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteEnd( AstChannel *this, const char *class ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes an "End" data item to the data sink -* associated with a Channel. This item delimits the end of an -* Object definition. - -* Parameters: -* this -* Pointer to the Channel. -* class -* Pointer to a constant null-terminated string containing the -* class name of the Object whose definition is being terminated -* by the "End" item. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - int i; /* Loop counter for indentation characters */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Decrement the indentation level so that the "End" item matches the - corresponding "Begin" item. */ - current_indent -= astGetIndent( this ); - -/* Start building a dynamic string with an initial space. Then add - further spaces to suit the current indentation level. */ - line = astAppendString( NULL, &nc, " " ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the "End" keyword followed by the class name. */ - line = astAppendString( line, &nc, "End " ); - line = astAppendString( line, &nc, class ); - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); -} - -static void WriteInt( AstChannel *this, const char *name, int set, int helpful, - int value, const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteInt - -* Purpose: -* Write an integer value to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteInt( AstChannel *this, const char *name, -* int set, int helpful, -* int value, const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes a named integer value, representing the -* value of a class instance variable, to the data sink associated -* with a Channel. It is intended for use by class "Dump" functions -* when writing out class information which will subsequently be -* re-read. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated string containing the -* name to be used to identify the value in the external -* representation. This will form the key for identifying it -* again when it is re-read. The name supplied should be unique -* within its class. -* -* Mixed case may be used and will be preserved in the external -* representation (where possible) for cosmetic effect. However, -* case is not significant when re-reading values. -* -* It is recommended that a maximum of 6 alphanumeric characters -* (starting with an alphabetic character) be used. This permits -* maximum flexibility in adapting to standard external data -* representations (e.g. FITS). -* set -* If this is zero, it indicates that the value being written is -* a default value (or can be re-generated from other values) so -* need not necessarily be written out. Such values will -* typically be included in the external representation with -* (e.g.) a comment character so that they are available to -* human readers but will be ignored when re-read. They may also -* be completely omitted in some circumstances. -* -* If "set" is non-zero, the value will always be explicitly -* included in the external representation so that it can be -* re-read. -* helpful -* This flag provides a hint about whether a value whose "set" -* flag is zero (above) should actually appear at all in the -* external representaton. -* -* If the external representation allows values to be "commented -* out" then, by default, values will be included in this form -* only if their "helpful" flag is non-zero. Otherwise, they -* will be omitted entirely. When possible, omitting the more -* obscure values associated with a class is recommended in -* order to improve readability. -* -* This default behaviour may be further modified if the -* Channel's Full attribute is set - either to permit all values -* to be shown, or to suppress non-essential information -* entirely. -* value -* The value to be written. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the value. -* -* Note that this comment may not actually be used, depending on -* the nature of the Channel supplied and the setting of its -* Comment attribute. -*- -*/ - -/* Local Constants: */ -#define BUFF_LEN 50 /* Size of local formatting buffer */ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - char buff[ BUFF_LEN + 1 ]; /* Local formatting buffer */ - int i; /* Loop counter for indentation characters */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Use the "set" and "helpful" flags, along with the Channel's - attributes to decide whether this value should actually be - written. */ - if ( Use( this, set, helpful, status ) ) { - -/* Start building a dynamic string with an initial space, or a comment - character if "set" is zero. Then add further spaces to suit the - current indentation level. */ - line = astAppendString( NULL, &nc, set ? " " : "#" ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the name string followed by " = ". */ - line = astAppendString( line, &nc, name ); - line = astAppendString( line, &nc, " = " ); - -/* Format the value as a decimal string and append this. */ - (void) sprintf( buff, "%d", value ); - line = astAppendString( line, &nc, buff ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - } - -/* Undefine macros local to this function. */ -#undef BUFF_LEN -} - -int astWriteInvocations_( int *status ){ -/* -*+ -* Name: -* astWriteInvocations - -* Purpose: -* Returns the number of invocations of the astWrite method. - -* Type: -* Protected function. - -* Synopsis: -* #include "channel.h" -* int astWriteInvocations - -* Class Membership: -* Channel method. - -* Description: -* This function returns the number of invocations of astWrite which -* have been made so far, excluding those made from within the -* astWriteObject method. An example of its use is to allow a Dump -* function to determine if a sub-object has already been dumped -* during the current invocation of astWrite. See the Dump method for -* the AstUnit class as an example. -*- -*/ - astDECLARE_GLOBALS - astGET_GLOBALS(NULL); - return nwrite_invoc; -} - -static void WriteIsA( AstChannel *this, const char *class, - const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteIsA - -* Purpose: -* Write an "IsA" data item to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteIsA( AstChannel *this, const char *class, -* const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes an "IsA" data item to the data sink -* associated with a Channel. This item delimits the end of the -* data associated with the instance variables of a class, as part -* of an overall Object definition. - -* Parameters: -* this -* Pointer to the Channel. -* class -* Pointer to a constant null-terminated string containing the -* name of the class whose data are terminated by the "IsA" -* item. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the "IsA" -* item. Normally, this will describe the purpose of the class -* whose data are being terminated. - -* Notes: -* - The comment supplied may not actually be used, depending on -* the nature of the Channel supplied. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - int i; /* Loop counter for indentation characters */ - int indent_inc; /* Indentation increment */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Output an "IsA" item only if there has been at least one item - written since the last "Begin" or "IsA" item, or if the Full - attribute for the Channel is greater than zero (requesting maximum - information). */ - if ( items_written || astGetFull( this ) > 0 ) { - -/* Start building a dynamic string with an initial space. Then add - further spaces to suit the current indentation level, but reduced - by one to allow the "IsA" item to match the "Begin" and "End" items - which enclose it. */ - indent_inc = astGetIndent( this ); - line = astAppendString( NULL, &nc, " " ); - for ( i = 0; i < ( current_indent - indent_inc ); i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the "IsA" keyword followed by the class name. */ - line = astAppendString( line, &nc, "IsA " ); - line = astAppendString( line, &nc, class ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - -/* Clear the count of items written for this class. */ - items_written = 0; - } -} - -static void WriteObject( AstChannel *this, const char *name, - int set, int helpful, - AstObject *value, const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteObject - -* Purpose: -* Write an Object as a value to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteObject( AstChannel *this, const char *name, -* int set, int helpful, -* AstObject *value, const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes an Object as a named value, representing -* the value of a class instance variable, to the data sink -* associated with a Channel. It is intended for use by class -* "Dump" functions when writing out class information which will -* subsequently be re-read. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated string containing the -* name to be used to identify the value in the external -* representation. This will form the key for identifying it -* again when it is re-read. The name supplied should be unique -* within its class. -* -* Mixed case may be used and will be preserved in the external -* representation (where possible) for cosmetic effect. However, -* case is not significant when re-reading values. -* -* It is recommended that a maximum of 6 alphanumeric characters -* (starting with an alphabetic character) be used. This permits -* maximum flexibility in adapting to standard external data -* representations (e.g. FITS). -* set -* If this is zero, it indicates that the value being written is -* a default value (or can be re-generated from other values) so -* need not necessarily be written out. Such values will -* typically be included in the external representation with -* (e.g.) a comment character so that they are available to -* human readers but will be ignored when re-read. They may also -* be completely omitted in some circumstances. -* -* If "set" is non-zero, the value will always be explicitly -* included in the external representation so that it can be -* re-read. -* helpful -* This flag provides a hint about whether a value whose "set" -* flag is zero (above) should actually appear at all in the -* external representaton. -* -* If the external representation allows values to be "commented -* out" then, by default, values will be included in this form -* only if their "helpful" flag is non-zero. Otherwise, they -* will be omitted entirely. When possible, omitting the more -* obscure values associated with a class is recommended in -* order to improve readability. -* -* This default behaviour may be further modified if the -* Channel's Full attribute is set - either to permit all values -* to be shown, or to suppress non-essential information -* entirely. -* value -* A Pointer to the Object to be written. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the value. -* -* Note that this comment may not actually be used, depending on -* the nature of the Channel supplied and the setting of its -* Comment attribute. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - int i; /* Loop counter for indentation characters */ - int indent_inc; /* Indentation increment */ - int nc; /* Number of output characters */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Use the "set" and "helpful" flags, along with the Channel's - attributes to decide whether this value should actually be - written. */ - if ( Use( this, set, helpful, status ) ) { - -/* Start building a dynamic string with an initial space, or a comment - character if "set" is zero. Then add further spaces to suit the - current indentation level. */ - line = astAppendString( NULL, &nc, set ? " " : "#" ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the name string followed by " =". The absence of a value on - the right hand side indicates an Object value, whose definition - follows. */ - line = astAppendString( line, &nc, name ); - line = astAppendString( line, &nc, " =" ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - -/* If the value is not a default, write the Object to the Channel as - well, suitably indented (this is omitted if the value is commented - out). */ - if ( set ) { - indent_inc = astGetIndent( this ); - current_indent += indent_inc; - (void) astWrite( this, value ); - current_indent -= indent_inc; - } - } -} - -static void WriteString( AstChannel *this, const char *name, - int set, int helpful, - const char *value, const char *comment, int *status ) { -/* -*+ -* Name: -* astWriteString - -* Purpose: -* Write a string value to a data sink. - -* Type: -* Protected virtual function. - -* Synopsis: -* #include "channel.h" -* void astWriteString( AstChannel *this, const char *name, -* int set, int helpful, -* const char *value, const char *comment ) - -* Class Membership: -* Channel method. - -* Description: -* This function writes a named string value, representing the -* value of a class instance variable, to the data sink associated -* with a Channel. It is intended for use by class "Dump" functions -* when writing out class information which will subsequently be -* re-read. - -* Parameters: -* this -* Pointer to the Channel. -* name -* Pointer to a constant null-terminated string containing the -* name to be used to identify the value in the external -* representation. This will form the key for identifying it -* again when it is re-read. The name supplied should be unique -* within its class. -* -* Mixed case may be used and will be preserved in the external -* representation (where possible) for cosmetic effect. However, -* case is not significant when re-reading values. -* -* It is recommended that a maximum of 6 alphanumeric characters -* (starting with an alphabetic character) be used. This permits -* maximum flexibility in adapting to standard external data -* representations (e.g. FITS). -* set -* If this is zero, it indicates that the value being written is -* a default value (or can be re-generated from other values) so -* need not necessarily be written out. Such values will -* typically be included in the external representation with -* (e.g.) a comment character so that they are available to -* human readers but will be ignored when re-read. They may also -* be completely omitted in some circumstances. -* -* If "set" is non-zero, the value will always be explicitly -* included in the external representation so that it can be -* re-read. -* helpful -* This flag provides a hint about whether a value whose "set" -* flag is zero (above) should actually appear at all in the -* external representaton. -* -* If the external representation allows values to be "commented -* out" then, by default, values will be included in this form -* only if their "helpful" flag is non-zero. Otherwise, they -* will be omitted entirely. When possible, omitting the more -* obscure values associated with a class is recommended in -* order to improve readability. -* -* This default behaviour may be further modified if the -* Channel's Full attribute is set - either to permit all values -* to be shown, or to suppress non-essential information -* entirely. -* value -* Pointer to a constant null-terminated string containing the -* value to be written. -* comment -* Pointer to a constant null-terminated string containing a -* textual comment to be associated with the value. -* -* Note that this comment may not actually be used, depending on -* the nature of the Channel supplied and the setting of its -* Comment attribute. -*- -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - char *line; /* Pointer to dynamic output string */ - int i; /* Loop counter for characters */ - int nc; /* Number of output characters */ - int quote; /* Quote character found? */ - int size; /* Size of allocated memory */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Get a pointer to the structure holding thread-specific global data. */ - astGET_GLOBALS(this); - -/* Use the "set" and "helpful" flags, along with the Channel's - attributes to decide whether this value should actually be - written. */ - if ( Use( this, set, helpful, status ) ) { - -/* Start building a dynamic string with an initial space, or a comment - character if "set" is zero. Then add further spaces to suit the - current indentation level. */ - line = astAppendString( NULL, &nc, set ? " " : "#" ); - for ( i = 0; i < current_indent; i++ ) { - line = astAppendString( line, &nc, " " ); - } - -/* Append the name string followed by " = " and an opening quote - character (the string will be quoted to protect leading and - trailing spaces). */ - line = astAppendString( line, &nc, name ); - line = astAppendString( line, &nc, " = \"" ); - -/* We now append the value string, but must inspect each character so - that quotes (appearing inside quotes) can be doubled. Determine the - current size of memory allocated for the dynamic string. */ - size = (int) astSizeOf( line ); - -/* Loop to inspect each character and see if it is a quote. */ - for ( i = 0; value[ i ]; i++ ) { - quote = ( value[ i ] == '"' ); - -/* If more memory is required, extend the dynamic string (allowing for - doubling of quotes and the final null) and save its new size. */ - if ( nc + 2 + quote > size ) { - line = astGrow( line, nc + 2 + quote, sizeof( char ) ); - if ( astOK ) { - size = (int) astSizeOf( line ); - -/* Quit if an error occurs. */ - } else { - break; - } - } - -/* Append the value character to the dynamic string, duplicating each - quote character. */ - line[ nc++ ] = value[ i ]; - if ( quote ) line[ nc++ ] = '"'; - } - -/* Append the closing quote. */ - line = astAppendString( line, &nc, "\"" ); - -/* If required, also append the comment. */ - if ( astGetComment( this ) && *comment ) { - line = astAppendString( line, &nc, " \t# " ); - line = astAppendString( line, &nc, comment ); - } - -/* Write out the resulting line of text. */ - OutputTextItem( this, line, status ); - -/* Free the dynamic string. */ - line = astFree( line ); - } -} - -/* Functions which access class attributes. */ -/* ---------------------------------------- */ -/* Implement member functions to access the attributes associated with - this class using the macros defined for this purpose in the - "object.h" file. */ - -/* -*att++ -* Name: -* SourceFile - -* Purpose: -* Input file from which to read data. - -* Type: -* Public attribute. - -* Synopsis: -* String. - -* Description: -* This attribute specifies the name of a file from which the Channel -* should read data. If specified it is used in preference to any source -* function specified when the Channel was created. -* -* Assigning a new value to this attribute will cause any previously -* opened SourceFile to be closed. The first subsequent call to -c astRead -f AST_READ -* will attempt to open the new file (an error will be reported if the -* file cannot be opened), and read data from it. All subsequent call to -c astRead -f AST_READ -* will read data from the new file, until the SourceFile attribute is -* cleared or changed. -* -* Clearing the attribute causes any open SourceFile to be closed. All -* subsequent data reads will use the source function specified when the -* Channel was created, or will read from standard input if no source -* function was specified. -* -* If no value has been assigned to SourceFile, a null string will be -* returned if an attempt is made to get the attribute value. - -* Notes: -* - Any open SourceFile is closed when the Channel is deleted. -* - If the Channel is copied or dumped -c (using astCopy or astShow) -f (using AST_COPY or AST_SHOW) -* the SourceFile attribute is left in a cleared state in the output -* Channel (i.e. the value of the SourceFile attribute is not copied). - -* Applicability: -* FitsChan -* In the case of a FitsChan, the specified SourceFile supplements -* the source function specified when the FitsChan was created, -* rather than replacing the source function. The source file -* should be a text file (not a FITS file) containing one header per -* line. When a value is assigned to SourceFile, the file is opened -* and read immediately, and all headers read from the file are -* appended to the end of any header already in the FitsChan. The file -* is then closed. Clearing the SourceFile attribute has no further -* effect, other than nullifying the string (i.e. the file name) -* associated with the attribute. - -*att-- -*/ - -/* Clear the SourceFile value by closing any open file, freeing the - allocated memory and assigning a NULL pointer. */ -astMAKE_CLEAR(Channel,SourceFile,fn_in,((this->fd_in=(this->fd_in?(fclose(this->fd_in),NULL):NULL)),astFree(this->fn_in))) - -/* If the SourceFile value is not set, supply a default in the form of a - pointer to the constant string "". */ -astMAKE_GET(Channel,SourceFile,const char *,NULL,( this->fn_in ? this->fn_in : "" )) - -/* Set a SourceFile value by closing any open file, freeing any previously - allocated memory, allocating new memory, storing the string and saving - the pointer to the copy. */ -astMAKE_SET(Channel,SourceFile,const char *,fn_in,((this->fd_in=(this->fd_in?(fclose(this->fd_in),NULL):NULL)),astStore( this->fn_in, value, strlen( value ) + (size_t) 1 ))) - -/* The SourceFile value is set if the pointer to it is not NULL. */ -astMAKE_TEST(Channel,SourceFile,( this->fn_in != NULL )) - -/* -*att++ -* Name: -* SinkFile - -* Purpose: -* Output file to which to data should be written. - -* Type: -* Public attribute. - -* Synopsis: -* String. - -* Description: -* This attribute specifies the name of a file to which the Channel -* should write data. If specified it is used in preference to any sink -* function specified when the Channel was created. -* -* Assigning a new value to this attribute will cause any previously -* opened SinkFile to be closed. The first subsequent call to -c astWrite -f AST_WRITE -* will attempt to open the new file (an error will be reported if the -* file cannot be opened), and write data to it. All subsequent call to -c astWrite -f AST_WRITE -* will write data to the new file, until the SinkFile attribute is -* cleared or changed. -* -* Clearing the attribute causes any open SinkFile to be closed. All -* subsequent data writes will use the sink function specified when the -* Channel was created, or will write to standard output if no sink -* function was specified. -* -* If no value has been assigned to SinkFile, a null string will be -* returned if an attempt is made to get the attribute value. - -* Notes: -* - A new SinkFile will over-write any existing file with the same -* name unless the existing file is write protected, in which case an -* error will be reported. -* - Any open SinkFile is closed when the Channel is deleted. -* - If the Channel is copied or dumped -c (using astCopy or astShow) -f (using AST_COPY or AST_SHOW) -* the SinkFile attribute is left in a cleared state in the output -* Channel (i.e. the value of the SinkFile attribute is not copied). - -* Applicability: -* FitsChan -* When the FitsChan is destroyed, any headers in the FitsChan will be -* written out to the sink file, if one is specified (if not, the -* sink function used when the FitsChan was created is used). The -* sink file is a text file (not a FITS file) containing one header -* per line. - -*att-- -*/ - -/* Clear the SinkFile value by closing any open file, freeing the allocated - memory and assigning a NULL pointer. */ -astMAKE_CLEAR(Channel,SinkFile,fn_out,((this->fd_out=(this->fd_out?(fclose(this->fd_out),NULL):NULL)),astFree(this->fn_out))) - -/* If the SinkFile value is not set, supply a default in the form of a - pointer to the constant string "". */ -astMAKE_GET(Channel,SinkFile,const char *,NULL,( this->fn_out ? this->fn_out : "" )) - -/* Set a SinkFile value by closing any open file, freeing any previously - allocated memory, allocating new memory, storing the string and saving - the pointer to the copy. */ -astMAKE_SET(Channel,SinkFile,const char *,fn_out,((this->fd_out=(this->fd_out?(fclose(this->fd_out),NULL):NULL)),astStore( this->fn_out, value, strlen( value ) + (size_t) 1 ))) - -/* The SinkFile value is set if the pointer to it is not NULL. */ -astMAKE_TEST(Channel,SinkFile,( this->fn_out != NULL )) - - -/* -*att++ -* Name: -* Comment - -* Purpose: -* Include textual comments in output? - -* Type: -* Public attribute. - -* Synopsis: -* Integer (boolean). - -* Description: -* This is a boolean attribute which controls whether textual -* comments are to be included in the output generated by a -* Channel. If included, they will describe what each item of -* output represents. -* -* If Comment is non-zero, then comments will be included. If -* it is zero, comments will be omitted. - -* Applicability: -* Channel -* The default value is non-zero for a normal Channel. -* FitsChan -* The default value is non-zero for a FitsChan. -* XmlChan -* The default value is zero for an XmlChan. - -*att-- -*/ - -/* This is a boolean value (0 or 1) with a value of -INT_MAX when - undefined but yielding a default of one. */ -astMAKE_CLEAR(Channel,Comment,comment,-INT_MAX) -astMAKE_GET(Channel,Comment,int,0,( this->comment != -INT_MAX ? this->comment : 1 )) -astMAKE_SET(Channel,Comment,int,comment,( value != 0 )) -astMAKE_TEST(Channel,Comment,( this->comment != -INT_MAX )) - -/* -*att++ -* Name: -* Full - -* Purpose: -* Set level of output detail. - -* Type: -* Public attribute. - -* Synopsis: -* Integer. - -* Description: -* This attribute is a three-state flag and takes values of -1, 0 -* or +1. It controls the amount of information included in the -* output generated by a Channel. -* -* If Full is zero, then a modest amount of -* non-essential but useful information will be included in the -* output. If Full is negative, all non-essential information will -* be suppressed to minimise the amount of output, while if it is -* positive, the output will include the maximum amount of detailed -* information about the Object being written. - -* Applicability: -* Channel -* The default value is zero for a normal Channel. -* FitsChan -* The default value is zero for a FitsChan. -* XmlChan -* The default value is -1 for an XmlChan. -* StcsChan -* The default value is zero for an StcsChan. Set a positive value -* to cause default values to be included in STC-S descriptions. - -* Notes: -* - All positive values supplied for this attribute are converted -* to +1 and all negative values are converted to -1. -*att-- -*/ - -/* This ia a 3-state value (-1, 0 or +1) with a value of -INT_MAX when - undefined but yielding a default of zero. */ -astMAKE_CLEAR(Channel,Full,full,-INT_MAX) -astMAKE_GET(Channel,Full,int,0,( this->full != -INT_MAX ? this->full : 0 )) -astMAKE_SET(Channel,Full,int,full,( value > 0 ? 1 : ( value < 0 ? -1 : 0 ) )) -astMAKE_TEST(Channel,Full,( this->full != -INT_MAX )) - -/* -*att++ -* Name: -* Indent - -* Purpose: -* Specifies the indentation to use in text produced by a Channel. - -* Type: -* Public attribute. - -* Synopsis: -* Integer (boolean). - -* Description: -* This attribute controls the indentation within the output text produced by -f the AST_WRITE function. -c the astWrite function. -* It gives the increase in the indentation for each level in the object -* heirarchy. If it is set to zero, no indentation will be used. [3] - -* Applicability: -* Channel -* The default value is zero for a basic Channel. -* FitsChan -* The FitsChan class ignores this attribute. -* StcsChan -* The default value for an StcsChan is zero, which causes the entire -* STC-S description is written out by a single invocation of the sink -* function. The text supplied to the sink function will not contain -* any linefeed characters, and each pair of adjacent words will be -* separated by a single space. The text may thus be arbitrarily large -* and the StcsLength attribute is ignored. -* -* If Indent is non-zero, then the text is written out via multiple -* calls to the sink function, each call corresponding to a single -* "line" of text (although no line feed characters will be inserted -* by AST). The complete STC-S description is broken into lines so that: -* -* - the line length specified by attribute StcsLength is not exceeded -* - each sub-phrase (time, space, etc.) starts on a new line -* - each argument in a compound spatial region starts on a new line -* -* If this causes a sub-phrase to extend to two or more lines, then the -* second and subsequent lines will be indented by three spaces compared -* to the first line. In addition, lines within a compound spatial region -* will have extra indentation to highlight the nesting produced by the -* parentheses. Each new level of nesting will be indented by a further -* three spaces. -f -f Note, the default value of zero is unlikely to be appropriate when -f an StcsChan is used within Fortran code. In this case, Indent -f should usually be set non-zero, and the StcsLength attribute set to -f the size of the CHARACTER variable used to -f receive the text returned by AST_GETLINE within the sink function. -f This avoids the possibility of long lines being truncated invisibly -f within AST_GETLINE. -* XmlChan -* The default value for an XmlChan is zero, which results in no -* linefeeds or indentation strings being added to output text. -* If any non-zero value is assigned to Indent, then extra linefeed and -* space characters will be inserted as necessary to ensure that each -* XML tag starts on a new line, and each tag will be indented by -* a further 3 spaces to show its depth in the containment hierarchy. -*att-- -*/ - -/* This is an integer value with a value of -INT_MAX when undefined, - yielding a default of 3. Sub-classes may over-ride theis default. */ -astMAKE_CLEAR(Channel,Indent,indent,-INT_MAX) -astMAKE_GET(Channel,Indent,int,3,( this->indent != -INT_MAX ? this->indent : 3 )) -astMAKE_SET(Channel,Indent,int,indent,value) -astMAKE_TEST(Channel,Indent,( this->indent != -INT_MAX )) - -/* -*att++ -* Name: -* ReportLevel - -* Purpose: -* Determines which read/write conditions are reported. - -* Type: -* Public attribute. - -* Synopsis: -* Integer. - -* Description: -* This attribute determines which, if any, of the conditions that occur -* whilst reading or writing an Object should be reported. These -* conditions will generate either a fatal error or a warning, as -* determined by attribute Strict. ReportLevel can take any of the -* following values: -* -* 0 - Do not report any conditions. -* -* 1 - Report only conditions where significant information content has been -* changed. For instance, an unsupported time-scale has been replaced by a -* supported near-equivalent time-scale. Another example is if a basic -* Channel unexpected encounters data items that may have been introduced -* by later versions of AST. -* -* 2 - Report the above, and in addition report significant default -* values. For instance, if no time-scale was specified when reading an -* Object from an external data source, report the default time-scale -* that is being used. -* -* 3 - Report the above, and in addition report any other potentially -* interesting conditions that have no significant effect on the -* conversion. For instance, report if a time-scale of "TT" -* (terrestrial time) is used in place of "ET" (ephemeris time). This -* change has no signficiant effect because ET is the predecessor of, -* and is continuous with, TT. Synonyms such as "IAT" and "TAI" are -* another example. -* -* The default value is 1. Note, there are many other conditions that -* can occur whilst reading or writing an Object that completely -* prevent the conversion taking place. Such conditions will always -* generate errors, irrespective of the ReportLevel and Strict attributes. - -* Applicability: -* Channel -* All Channels have this attribute. -* FitsChan -* All the conditions selected by the FitsChan Warnings attribute are -* reported at level 1. -*att-- -*/ - -/* This is an integer value with a value of -INT_MAX when undefined, - yielding a default of one. */ -astMAKE_CLEAR(Channel,ReportLevel,report_level,-INT_MAX) -astMAKE_GET(Channel,ReportLevel,int,1,( this->report_level != -INT_MAX ? this->report_level : 1 )) -astMAKE_SET(Channel,ReportLevel,int,report_level,value) -astMAKE_TEST(Channel,ReportLevel,( this->report_level != -INT_MAX )) - -/* -*att++ -* Name: -* Skip - -* Purpose: -* Skip irrelevant data? - -* Type: -* Public attribute. - -* Synopsis: -* Integer (boolean). - -* Description: -* This is a boolean attribute which indicates whether the Object -* data being read through a Channel are inter-mixed with other, -* irrelevant, external data. -* -* If Skip is zero (the default), then the source of input data is -* expected to contain descriptions of AST Objects and comments and -* nothing else (if anything else is read, an error will -* result). If Skip is non-zero, then any non-Object data -* encountered between Objects will be ignored and simply skipped -* over in order to reach the next Object. - -* Applicability: -* Channel -* All Channels have this attribute. -* FitsChan -* The FitsChan class sets the default value of this attribute -* to 1, so that all irrelevant FITS headers will normally be -* ignored. -*att-- -*/ - -/* This ia a boolean value (0 or 1) with a value of -INT_MAX when - undefined but yielding a default of zero. */ -astMAKE_CLEAR(Channel,Skip,skip,-INT_MAX) -astMAKE_GET(Channel,Skip,int,0,( this->skip != -INT_MAX ? this->skip : 0 )) -astMAKE_SET(Channel,Skip,int,skip,( value != 0 )) -astMAKE_TEST(Channel,Skip,( this->skip != -INT_MAX )) - -/* -*att++ -* Name: -* Strict - -* Purpose: -* Report an error if any unexpeted data items are found? - -* Type: -* Public attribute. - -* Synopsis: -* Integer (boolean). - -* Description: -* This is a boolean attribute which indicates whether a warning -* rather than an error should be issed for insignificant conversion -* problems. If it is set non-zero, then fatal errors are issued -* instead of warnings, resulting in the -c AST error status being set. -f inherited STATUS variable being set to an error value. -* If Strict is zero (the default), then execution continues after minor -* conversion problems, and a warning message is added to the Channel -* structure. Such messages can be retrieved using the -c astWarnings -f AST_WARNINGS -* function. - -* Notes: -* - This attribute was introduced in AST version 5.0. Prior to this -* version of AST unexpected data items read by a basic Channel always -* caused an error to be reported. So applications linked against -* versions of AST prior to version 5.0 may not be able to read Object -* descriptions created by later versions of AST, if the Object's class -* description has changed. - -* Applicability: -* Channel -* All Channels have this attribute. -*att-- -*/ - -/* This ia a boolean value (0 or 1) with a value of -INT_MAX when - undefined but yielding a default of zero. */ -astMAKE_CLEAR(Channel,Strict,strict,-INT_MAX) -astMAKE_GET(Channel,Strict,int,0,( this->strict != -INT_MAX ? this->strict : 0 )) -astMAKE_SET(Channel,Strict,int,strict,( value != 0 )) -astMAKE_TEST(Channel,Strict,( this->strict != -INT_MAX )) - -/* Destructor. */ -/* ----------- */ -static void Delete( AstObject *obj, int *status ) { -/* -* Name: -* Delete - -* Purpose: -* Destructor for Channel objects. - -* Type: -* Private function. - -* Synopsis: -* void Delete( AstObject *obj, int *status ) - -* Description: -* This function implements the destructor for Channel objects. - -* Parameters: -* obj -* Pointer to the object to be deleted. -* status -* Pointer to the inherited status variable. - -* Notes: -* This function attempts to execute even if the global error status is -* set. -*/ - -/* Local Variables: */ - AstChannel *this; /* Pointer to Channel */ - -/* Obtain a pointer to the Channel structure. */ - this = (AstChannel *) obj; - -/* Free memory used to store warnings. */ - astAddWarning( this, 0, NULL, NULL, status ); - -/* Close any open input or output files. */ - if( this->fd_in ) fclose( this->fd_in ); - if( this->fd_out ) fclose( this->fd_out ); - -/* Free file name memory. */ - this->fn_in = astFree( this->fn_in ); - this->fn_out = astFree( this->fn_out ); -} - -/* Copy constructor. */ -/* ----------------- */ -static void Copy( const AstObject *objin, AstObject *objout, int *status ) { -/* -* Name: -* Copy - -* Purpose: -* Copy constructor for Channel objects. - -* Type: -* Private function. - -* Synopsis: -* void Copy( const AstObject *objin, AstObject *objout, int *status ) - -* Description: -* This function implements the copy constructor for Channel objects. - -* Parameters: -* objin -* Pointer to the object to be copied. -* objout -* Pointer to the object being constructed. -* status -* Pointer to the inherited status variable. - -* Notes: -* - This constructor makes a deep copy. -*/ - -/* Local Variables: */ - AstChannel *out; /* Pointer to output Channel */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Obtain pointers to the input and output Channels. */ - out = (AstChannel *) objout; - -/* Just clear any references to the input memory from the output Channel. */ - out->warnings = NULL; - out->nwarn = 0; - out->fd_in = NULL; - out->fn_in = NULL; - out->fd_out = NULL; - out->fn_out = NULL; -} - -/* Dump function. */ -/* -------------- */ -static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { -/* -* Name: -* Dump - -* Purpose: -* Dump function for Channel 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 Channel class to an output Channel. - -* Parameters: -* this -* Pointer to the Object 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: */ - AstChannel *this; /* Pointer to the Channel structure */ - const char *comment; /* Pointer to comment string */ - int ival; /* Integer value */ - int set; /* Attribute value set? */ - -/* Check the global error status. */ - if ( !astOK ) return; - -/* Obtain a pointer to the Channel structure. */ - this = (AstChannel *) this_object; - -/* Write out values representing the instance variables for the - Channel class. Accompany these with appropriate comment strings, - possibly depending on the values being written.*/ - -/* In the case of attributes, we first use the appropriate (private) - Test... member function to see if they are set. If so, we then use - the (private) Get... function to obtain the value to be written - out. - - For attributes which are not set, we use the astGet... method to - obtain the value instead. This will supply a default value - (possibly provided by a derived class which over-rides this method) - which is more useful to a human reader as it corresponds to the - actual default attribute value. Since "set" will be zero, these - values are for information only and will not be read back. */ - -/* Indent */ -/* ------------ */ - set = TestIndent( this, status ); - ival = set ? GetIndent( this, status ) : astGetIndent( this ); - astWriteInt( channel, "Indnt", set, 0, ival, "Indentation increment" ); - -/* ReportLevel. */ -/* ------------ */ - set = TestReportLevel( this, status ); - ival = set ? GetReportLevel( this, status ) : astGetReportLevel( this ); - astWriteInt( channel, "RpLev", set, 0, ival, "Error reporting level" ); - -/* Skip. */ -/* ----- */ - set = TestSkip( this, status ); - ival = set ? GetSkip( this, status ) : astGetSkip( this ); - astWriteInt( channel, "Skip", set, 0, ival, - ival ? "Ignore data between Objects" : - "No data allowed between Objects" ); - -/* Strict. */ -/* ------- */ - set = TestStrict( this, status ); - ival = set ? GetStrict( this, status ) : astGetStrict( this ); - astWriteInt( channel, "Strict", set, 0, ival, - ival ? "Report errors insead of warnings" : - "Report warnings instead of errors" ); - -/* Full. */ -/* ----- */ - set = TestFull( this, status ); - ival = set ? GetFull( this, status ) : astGetFull( this ); - if ( ival < 0 ) { - comment = "Suppress non-essential output"; - }else if ( ival == 0 ) { - comment = "Output standard information"; - } else { - comment = "Output maximum information"; - } - astWriteInt( channel, "Full", set, 0, ival, comment ); - -/* Comment. */ -/* -------- */ - set = TestComment( this, status ); - ival = set ? GetComment( this, status ) : astGetComment( this ); - astWriteInt( channel, "Comm", set, 0, ival, - ival ? "Display comments" : - "Omit comments" ); -} - -/* Standard class functions. */ -/* ========================= */ -/* Implement the astIsAChannel and astCheckChannel functions using the - macros defined for this purpose in the "object.h" header file. */ -astMAKE_ISA(Channel,Object) -astMAKE_CHECK(Channel) - -AstChannel *astChannel_( const char *(* source)( void ), - void (* sink)( const char * ), - const char *options, int *status, ...) { -/* -*+ -* Name: -* astChannel - -* Purpose: -* Create a Channel. - -* Type: -* Protected function. - -* Synopsis: -* #include "channel.h" -* AstChannel *astChannel( const char *(* source)( void ), -* void (* sink)( const char * ), -* const char *options, ..., int *status ) - -* Class Membership: -* Channel constructor. - -* Description: -* This function creates a new Channel and optionally initialises -* its attributes. -* -* A Channel implements low-level input/output for the AST library. -* Writing an Object to a Channel (using astWrite) will generate a -* textual representation of that Object, and reading from a -* Channel (using astRead) will create a new Object from its -* textual representation. -* -* Normally, when you use a Channel, you should provide "source" -* and "sink" functions which connect it to an external data store -* by reading and writing the resulting text. By default, however, -* a Channel will read from standard input and write to standard -* output. - -* Parameters: -* source -* Pointer to a "source" function that takes no arguments and -* returns a pointer to a null-terminated string. -* -* This function will be used by the Channel to obtain lines of -* input text. On each invocation, it should return a pointer to -* the next input line read from some external data store, and a -* NULL pointer when there are no more lines to read. -* -* If "source" is NULL, the Channel will read from standard -* input instead. -* sink -* Pointer to a "sink" function that takes a pointer to a -* null-terminated string as an argument and returns void. -* -* This function will be used by the Channel to deliver lines of -* output text. On each invocation, it should deliver the -* contents of the string supplied to some external data store. -* -* If "sink" is NULL, the Channel will write to standard output -* instead. -* options -* Pointer to a null-terminated string containing an optional -* comma-separated list of attribute assignments to be used for -* initialising the new Channel. The syntax used is identical to -* that for the astSet function and may include "printf" format -* specifiers identified by "%" symbols in the normal way. -* status -* Pointer to the inherited status variable. -* ... -* If the "options" string contains "%" format specifiers, then -* an optional list of additional arguments may follow it in -* order to supply values to be substituted for these -* specifiers. The rules for supplying these are identical to -* those for the astSet function (and for the C "printf" -* function). - -* Returned Value: -* astChannel() -* A pointer to the new Channel. - -* Notes: -* - A NULL pointer value will be returned if this function is -* invoked with the global error status set, or if it should fail -* for any reason. -*- - -* Implementation Notes: -* - This function implements the basic Channel constructor which -* is available via the protected interface to the Channel class. -* A public interface is provided by the astChannelId_ function. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - AstChannel *new; /* Pointer to new Channel */ - 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 Channel, allocating memory and initialising the - virtual function table as well if necessary. Supply pointers to - (local) wrapper functions that can invoke the source and sink - functions with appropriate arguments for the C language. */ - new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab, - "Channel", source, SourceWrap, sink, SinkWrap ); - -/* 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 - Channel'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 Channel. */ - return new; -} - -AstChannel *astChannelId_( const char *(* source)( void ), - void (* sink)( const char * ), - const char *options, ... ) { -/* -*++ -* Name: -c astChannel -f AST_CHANNEL - -* Purpose: -* Create a Channel. - -* Type: -* Public function. - -* Synopsis: -c #include "channel.h" -c AstChannel *astChannel( const char *(* source)( void ), -c void (* sink)( const char * ), -c const char *options, ... ) -f RESULT = AST_CHANNEL( SOURCE, SINK, OPTIONS, STATUS ) - -* Class Membership: -* Channel constructor. - -* Description: -* This function creates a new Channel and optionally initialises -* its attributes. -* -* A Channel implements low-level input/output for the AST library. -c Writing an Object to a Channel (using astWrite) will generate a -f Writing an Object to a Channel (using AST_WRITE) will generate a -* textual representation of that Object, and reading from a -c Channel (using astRead) will create a new Object from its -f Channel (using AST_READ) will create a new Object from its -* textual representation. -* -* Normally, when you use a Channel, you should provide "source" -c and "sink" functions which connect it to an external data store -f and "sink" routines which connect it to an external data store -* by reading and writing the resulting text. By default, however, -* a Channel will read from standard input and write to standard -* output. Alternatively, a Channel can be told to read or write from -* specific text files using the SinkFile and SourceFile attributes, -* in which case no sink or source function need be supplied. - -* Parameters: -c source -f SOURCE = SUBROUTINE (Given) -c Pointer to a source function that takes no arguments and -c returns a pointer to a null-terminated string. If no value -c has been set for the SourceFile attribute, this function -c will be used by the Channel to obtain lines of input text. On -c each invocation, it should return a pointer to the next input -c line read from some external data store, and a NULL pointer -c when there are no more lines to read. -c -c If "source" is NULL and no value has been set for the SourceFile -c attribute, the Channel will read from standard input instead. -f A source routine, which is a subroutine which takes a single -f integer error status argument. If no value has been set -f for the SourceFile attribute, this routine will be used by -f the Channel to obtain lines of input text. On each -f invocation, it should read the next input line from some -f external data store, and then return the resulting text to -f the AST library by calling AST_PUTLINE. It should supply a -f negative line length when there are no more lines to read. -f If an error occurs, it should set its own error status -f argument to an error value before returning. -f -f If the null routine AST_NULL is suppied as the SOURCE value, -f and no value has been set for the SourceFile attribute, -f the Channel will read from standard input instead. -c sink -f SINK = SUBROUTINE (Given) -c Pointer to a sink function that takes a pointer to a -c null-terminated string as an argument and returns void. -c If no value has been set for the SinkFile attribute, this -c function will be used by the Channel to deliver lines of -c output text. On each invocation, it should deliver the -c contents of the string supplied to some external data store. -c -c If "sink" is NULL, and no value has been set for the SinkFile -c attribute, the Channel will write to standard output instead. -f A sink routine, which is a subroutine which takes a single -f integer error status argument. If no value has been set -f for the SinkFile attribute, this routine will be used by -f the Channel to deliver lines of output text. On each -f invocation, it should obtain the next output line from the -f AST library by calling AST_GETLINE, and then deliver the -f resulting text to some external data store. If an error -f occurs, it should set its own error status argument to an -f error value before returning. -f -f If the null routine AST_NULL is suppied as the SINK value, -f and no value has been set for the SinkFile attribute, -f the Channel will write to standard output instead. -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 Channel. 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 Channel. 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 astChannel() -f AST_CHANNEL = INTEGER -* A pointer to the new Channel. - -* Notes: -c - Application code can pass arbitrary data (such as file -c descriptors, etc) to source and sink functions using the -c astPutChannelData function. The source or sink function should use -c the astChannelData macro to retrieve this data. -f - The names of the routines supplied for the SOURCE and SINK -f arguments should appear in EXTERNAL statements in the Fortran -f routine which invokes AST_CHANNEL. However, this is not generally -f necessary for the null routine AST_NULL (so long as the AST_PAR -f include file has been used). -* - 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. -f - Note that the null routine AST_NULL (one underscore) is -f different to AST__NULL (two underscores), which is the null Object -f pointer. -*-- - -* Implementation Notes: -* - This function implements the external (public) interface to -* the astChannel constructor function. It returns an ID value -* (instead of a true C pointer) to external users, and must be -* provided because astChannel_ 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 astChanel_ 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. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - AstChannel *new; /* Pointer to new Channel */ - 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 Channel, allocating memory and initialising the - virtual function table as well if necessary. Supply pointers to - (local) wrapper functions that can invoke the source and sink - functions with appropriate arguments for the C language. */ - new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab, - "Channel", source, SourceWrap, sink, SinkWrap ); - -/* 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 - Channel'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 Channel. */ - return astMakeId( new ); -} - -AstChannel *astChannelForId_( const char *(* source)( void ), - char *(* source_wrap)( const char *(*)( void ), int * ), - void (* sink)( const char * ), - void (* sink_wrap)( void (*)( const char * ), - const char *, int * ), - const char *options, ... ) { -/* -*+ -* Name: -* astChannelFor - -* Purpose: -* Initialise a Channel from a foreign language interface. - -* Type: -* Public function. - -* Synopsis: -* #include "channel.h" -* AstChannel *astChannelFor( const char *(* source)( void ), -* char *(* source_wrap)( const char *(*) -* ( void ), int * ), -* void (* sink)( const char * ), -* void (* sink_wrap)( void (*)( const char * ), -* const char *, int * ), -* const char *options, ... ) - -* Class Membership: -* Channel constructor. - -* Description: -* This function creates a new Channel from a foreign language -* interface and optionally initialises its attributes. -* -* A Channel implements low-level input/output for the AST library. -* Writing an Object to a Channel (using astWrite) will generate a -* textual representation of that Object, and reading from a -* Channel (using astRead) will create a new Object from its -* textual representation. -* -* Normally, when you use a Channel, you should provide "source" -* and "sink" functions which connect it to an external data store -* by reading and writing the resulting text. This function also -* requires you to provide "wrapper" functions which will invoke -* the source and sink functions. By default, however, a Channel -* will read from standard input and write to standard output. - -* Parameters: -* source -* Pointer to a "source" function which will be used to obtain -* lines of input text. Generally, this will be obtained by -* casting a pointer to a source function which is compatible -* with the "source_wrap" wrapper function (below). The pointer -* should later be cast back to its original type by the -* "source_wrap" function before the function is invoked. -* -* If "source" is NULL, the Channel will read from standard -* input instead. -* source_wrap -* Pointer to a function which can be used to invoke the -* "source" function supplied (above). This wrapper function is -* necessary in order to hide variations in the nature of the -* source function, such as may arise when it is supplied by a -* foreign (non-C) language interface. -* -* The single parameter of the "source_wrap" function is a -* pointer to the "source" function, and it should cast this -* function pointer (as necessary) and invoke the function with -* appropriate arguments to obtain the next line of input -* text. The "source_wrap" function should then return a pointer -* to a dynamically allocated, null terminated string containing -* the text that was read. The string will be freed (using -* astFree) when no longer required and the "source_wrap" -* function need not concern itself with this. A NULL pointer -* should be returned if there is no more input to read. -* -* If "source_wrap" is NULL, the Channel will read from standard -* input instead. -* sink -* Pointer to a "sink" function which will be used to deliver -* lines of output text. Generally, this will be obtained by -* casting a pointer to a sink function which is compatible with -* the "sink_wrap" wrapper function (below). The pointer should -* later be cast back to its original type by the "sink_wrap" -* function before the function is invoked. -* -* If "sink" is NULL, the Channel will write to standard output -* instead. -* sink_wrap -* Pointer to a function which can be used to invoke the "sink" -* function supplied (above). This wrapper function is necessary -* in order to hide variations in the nature of the sink -* function, such as may arise when it is supplied by a foreign -* (non-C) language interface. -* -* The first parameter of the "sink_wrap" function is a pointer -* to the "sink" function, and the second parameter is a pointer -* to a const, null-terminated character string containing the -* text to be written. The "sink_wrap" function should cast the -* "sink" function pointer (as necessary) and invoke the -* function with appropriate arguments to deliver the line of -* output text. The "sink_wrap" function then returns void. -* -* If "sink_wrap" is NULL, the Channel will write to standard -* output instead. -* options -* Pointer to a null-terminated string containing an optional -* comma-separated list of attribute assignments to be used for -* initialising the new Channel. The syntax used is identical to -* that for the astSet function and may include "printf" format -* specifiers identified by "%" symbols in the normal way. -* ... -* If the "options" string contains "%" format specifiers, then -* an optional list of additional arguments may follow it in -* order to supply values to be substituted for these -* specifiers. The rules for supplying these are identical to -* those for the astSet function (and for the C "printf" -* function). - -* Returned Value: -* astChannelFor() -* A pointer to the new Channel. - -* Notes: -* - A null Object pointer (AST__NULL) will be returned if this -* function is invoked with the global error status set, or if it -* should fail for any reason. -* - This function is only available through the public interface -* to the Channel class (not the protected interface) and is -* intended solely for use in implementing foreign language -* interfaces to this class. -*- - -* Implememtation Notes: -* - This function behaves exactly like astChannelId_, in that it -* returns ID values and not true C pointers, but it has two -* additional arguments. These are pointers to the "wrapper -* functions" which are needed to accommodate foreign language -* interfaces. -*/ - -/* Local Variables: */ - astDECLARE_GLOBALS /* Declare the thread specific global data */ - AstChannel *new; /* Pointer to new Channel */ - va_list args; /* Variable argument list */ - int *status; /* Pointer to inherited status value */ - -/* Get a pointer to the inherited status value. */ - status = astGetStatusPtr; - -/* Check the global status. */ - if ( !astOK ) return NULL; - -/* Get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(NULL); - -/* Initialise the Channel, allocating memory and initialising the - virtual function table as well if necessary. */ - new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab, - "Channel", source, source_wrap, sink, sink_wrap ); - -/* 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 - Channel'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 Channel. */ - return astMakeId( new ); -} - -AstChannel *astLoadChannel_( void *mem, size_t size, - AstChannelVtab *vtab, const char *name, - AstChannel *channel, int *status ) { -/* -*+ -* Name: -* astLoadChannel - -* Purpose: -* Load a Channel. - -* Type: -* Protected function. - -* Synopsis: -* #include "channel.h" -* AstChannel *astLoadChannel( void *mem, size_t size, -* AstChannelVtab *vtab, const char *name, -* AstChannel *channel ) - -* Class Membership: -* Channel loader. - -* Description: -* This function is provided to load a new Channel 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 -* Channel 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 Channel at the start of the memory -* passed via the "vtab" parameter. - - -* Parameters: -* mem -* A pointer to the memory into which the Channel is to be -* loaded. This must be of sufficient size to accommodate the -* Channel data (sizeof(Channel)) 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 Channel (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 Channel 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(AstChannel) is used instead. -* vtab -* Pointer to the start of the virtual function table to be -* associated with the new Channel. If this is NULL, a pointer -* to the (static) virtual function table for the Channel 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 "Channel" is used instead. - -* Returned Value: -* A pointer to the new Channel. - -* 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: */ - astDECLARE_GLOBALS /* Pointer to thread-specific global data */ - AstChannel *new; /* Pointer to the new Channel */ - -/* Initialise. */ - new = NULL; - -/* Check the global error status. */ - if ( !astOK ) return new; - -/* Get a pointer to the thread specific global data structure. */ - astGET_GLOBALS(channel); - -/* If a NULL virtual function table has been supplied, then this is - the first loader to be invoked for this Channel. In this case the - Channel belongs to this class, so supply appropriate values to be - passed to the parent class loader (and its parent, etc.). */ - if ( !vtab ) { - size = sizeof( AstChannel ); - vtab = &class_vtab; - name = "Channel"; - -/* If required, initialise the virtual function table for this class. */ - if ( !class_init ) { - astInitChannelVtab( 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 Channel. */ - new = astLoadObject( mem, size, (AstObjectVtab *) vtab, name, - channel ); - - if ( astOK ) { - -/* Read input data. */ -/* ================ */ -/* Request the input Channel to read all the input data appropriate to - this class into the internal "values list". */ - astReadClassData( channel, "Channel" ); - -/* Set the pointers to the source and sink functions, and their - wrapper functions, to NULL (we cannot restore these since they - refer to process-specific addresses). */ - new->source = NULL; - new->source_wrap = NULL; - new->sink = NULL; - new->sink_wrap = NULL; - -/* We do not have any data to pass to the source and sink functions. */ - new->data = NULL; - -/* No warnings yet. */ - new->warnings = NULL; - new->nwarn = 0; - -/* Indicate no input or output files have been associated with the - Channel. */ - new->fd_in = NULL; - new->fn_in = NULL; - new->fd_out = NULL; - new->fn_out = NULL; - -/* Now read each individual data item from this list and use it to - initialise the appropriate instance variable(s) for this class. */ - -/* In the case of attributes, we first read the "raw" input value, - supplying the "unset" value as the default. If a "set" value is - obtained, we then use the appropriate (private) Set... member - function to validate and set the value properly. */ - -/* Indent. */ -/* ------- */ - new->indent = astReadInt( channel, "indnt", -INT_MAX ); - if ( TestIndent( new, status ) ) SetIndent( new, new->indent, status ); - -/* ReportLevel. */ -/* ------------ */ - new->report_level = astReadInt( channel, "rplev", -INT_MAX ); - if ( TestReportLevel( new, status ) ) SetReportLevel( new, - new->report_level, - status ); - -/* Skip. */ -/* ----- */ - new->skip = astReadInt( channel, "skip", -INT_MAX ); - if ( TestSkip( new, status ) ) SetSkip( new, new->skip, status ); - -/* Strict. */ -/* ------- */ - new->strict = astReadInt( channel, "strict", -INT_MAX ); - if ( TestStrict( new, status ) ) SetStrict( new, new->strict, status ); - -/* Full. */ -/* ----- */ - new->full = astReadInt( channel, "full", -INT_MAX ); - if ( TestFull( new, status ) ) SetFull( new, new->full, status ); - -/* Comment. */ -/* -------- */ - new->comment = astReadInt( channel, "comm", -INT_MAX ); - if ( TestComment( new, status ) ) SetComment( new, new->comment, status ); - -/* If an error occurred, clean up by deleting the new Channel. */ - if ( !astOK ) new = astDelete( new ); - } - -/* Return the new Channel 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. */ -void astGetNextData_( AstChannel *this, int begin, char **name, char **val, int *status ) { - *name = NULL; - *val = NULL; - if ( !astOK ) return; - (**astMEMBER(this,Channel,GetNextData))( this, begin, name, val, status ); -} -char *astGetNextText_( AstChannel *this, int *status ) { - if ( !astOK ) return NULL; - return (**astMEMBER(this,Channel,GetNextText))( this, status ); -} -void astPutNextText_( AstChannel *this, const char *line, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,PutNextText))( this, line, status ); -} -AstObject *astRead_( AstChannel *this, int *status ) { - if ( !astOK ) return NULL; - astAddWarning( this, 0, NULL, NULL, status ); - return (**astMEMBER(this,Channel,Read))( this, status ); -} -void astReadClassData_( AstChannel *this, const char *class, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,ReadClassData))( this, class, status ); -} -double astReadDouble_( AstChannel *this, const char *name, double def, int *status ) { - if ( !astOK ) return 0.0; - return (**astMEMBER(this,Channel,ReadDouble))( this, name, def, status ); -} -int astReadInt_( AstChannel *this, const char *name, int def, int *status ) { - if ( !astOK ) return 0; - return (**astMEMBER(this,Channel,ReadInt))( this, name, def, status ); -} -AstObject *astReadObject_( AstChannel *this, const char *name, - AstObject *def, int *status ) { - if ( !astOK ) return NULL; - return (**astMEMBER(this,Channel,ReadObject))( this, name, def, status ); -} -char *astReadString_( AstChannel *this, const char *name, const char *def, int *status ) { - if ( !astOK ) return NULL; - return (**astMEMBER(this,Channel,ReadString))( this, name, def, status ); -} -void astWriteBegin_( AstChannel *this, const char *class, - const char *comment, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteBegin))( this, class, comment, status ); -} -void astWriteDouble_( AstChannel *this, const char *name, int set, int helpful, - double value, const char *comment, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteDouble))( this, name, set, helpful, value, - comment, status ); -} -void astWriteEnd_( AstChannel *this, const char *class, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteEnd))( this, class, status ); -} -void astWriteInt_( AstChannel *this, const char *name, int set, int helpful, - int value, const char *comment, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteInt))( this, name, set, helpful, value, - comment, status ); -} -void astWriteIsA_( AstChannel *this, const char *class, const char *comment, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteIsA))( this, class, comment, status ); -} -void astWriteString_( AstChannel *this, const char *name, int set, int helpful, - const char *value, const char *comment, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,WriteString))( this, name, set, helpful, value, - comment, status ); -} -void astPutChannelData_( AstChannel *this, void *data, int *status ) { - if ( !astOK ) return; - (**astMEMBER(this,Channel,PutChannelData))( this, data, status ); -} - -AstKeyMap *astWarnings_( AstChannel *this, int *status ){ - if( !astOK ) return NULL; - return (**astMEMBER(this,Channel,Warnings))( this, status ); -} - -/* Because of the variable argument list, we need to work a bit harder on - astAddWarning. Functions that provide implementations of the - astAddWarning method recieve the fully expanded message and so do not - need a variable argument list. */ - -void astAddWarning_( void *this_void, int level, const char *fmt, - const char *method, int *status, ... ) { - AstChannel *this; - char buff[ 201 ]; - va_list args; - int nc; - - this = astCheckChannel( this_void ); - - if( fmt ) { - if( astOK ) { - va_start( args, status ); - nc = vsprintf( buff, fmt, args ); - va_end( args ); - if( nc > 200 ) { - astError( AST__INTER, "astAddWarning(%s): Message buffer size " - "exceeded (internal AST programming error).", - status, astGetClass( this ) ); - } else { - (**astMEMBER(this,Channel,AddWarning))( this, level, buff, method, status ); - } - } - } else { - (**astMEMBER(this,Channel,AddWarning))( this, level, NULL, method, status ); - } -} - -/* Count the number of times astWrite is invoked (excluding invocations - made from within the astWriteObject method - see below). The count is - done here so that invocations of astWrite within a sub-class will be - included. */ -int astWrite_( AstChannel *this, AstObject *object, int *status ) { - astDECLARE_GLOBALS - if ( !astOK ) return 0; - astGET_GLOBALS(this); - nwrite_invoc++; - astAddWarning( this, 0, NULL, NULL, status ); - return (**astMEMBER(this,Channel,Write))( this, object, status ); -} - -/* We do not want to count invocations of astWrite made from within the - astWriteObject method. So decrement the number of invocations first - (this assumes that each invocation of astWriteObject will only invoke - astWrite once). */ -void astWriteObject_( AstChannel *this, const char *name, int set, - int helpful, AstObject *value, const char *comment, int *status ) { - astDECLARE_GLOBALS - if ( !astOK ) return; - astGET_GLOBALS(this); - nwrite_invoc--; - (**astMEMBER(this,Channel,WriteObject))( this, name, set, helpful, value, - comment, status ); -} - - - - - |