1 /*
2 *class++
3 * Name:
4 * Channel
5
6 * Purpose:
7 * Basic (textual) I/O channel.
8
9 * Constructor Function:
10 c astChannel
11 f AST_CHANNEL
12
13 * Description:
14 * The Channel class implements low-level input/output for the AST
15 * library. Writing an Object to a Channel will generate a textual
16 * representation of that Object, and reading from a Channel will
17 * create a new Object from its textual representation.
18 *
19 * Normally, when you use a Channel, you should provide "source"
20 c and "sink" functions which connect it to an external data store
21 f and "sink" routines which connect it to an external data store
22 * by reading and writing the resulting text. By default, however,
23 * a Channel will read from standard input and write to standard
24 * output. Alternatively, a Channel can be told to read or write from
25 * specific text files using the SinkFile and SourceFile attributes,
26 * in which case no sink or source function need be supplied.
27
28 * Inheritance:
29 * The Channel class inherits from the Object class.
30
31 * Attributes:
32 * In addition to those attributes common to all Objects, every
33 * Channel also has the following attributes:
34 *
35 * - Comment: Include textual comments in output?
36 * - Full: Set level of output detail
37 * - Indent: Indentation increment between objects
38 * - ReportLevel: Selects the level of error reporting
39 * - SinkFile: The path to a file to which the Channel should write
40 * - Skip: Skip irrelevant data?
41 * - SourceFile: The path to a file from which the Channel should read
42 * - Strict: Generate errors instead of warnings?
43
44 * Functions:
45 c In addition to those functions applicable to all Objects, the
46 c following functions may also be applied to all Channels:
47 f In addition to those routines applicable to all Objects, the
48 f following routines may also be applied to all Channels:
49 *
50 c - astWarnings: Return warnings from the previous read or write
51 c - astPutChannelData: Store data to pass to source or sink functions
52 c - astRead: Read an Object from a Channel
53 c - astWrite: Write an Object to a Channel
54 f - AST_WARNINGS: Return warnings from the previous read or write
55 f - AST_READ: Read an Object from a Channel
56 f - AST_WRITE: Write an Object to a Channel
57
58 * Copyright:
59 * Copyright (C) 1997-2006 Council for the Central Laboratory of the
60 * Copyright (C) 2009 Science & Technology Facilities Council.
61 * All Rights Reserved.
62 * Research Councils
63
64 * Licence:
65 * This program is free software: you can redistribute it and/or
66 * modify it under the terms of the GNU Lesser General Public
67 * License as published by the Free Software Foundation, either
68 * version 3 of the License, or (at your option) any later
69 * version.
70 *
71 * This program is distributed in the hope that it will be useful,
72 * but WITHOUT ANY WARRANTY; without even the implied warranty of
73 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74 * GNU Lesser General Public License for more details.
75 *
76 * You should have received a copy of the GNU Lesser General
77 * License along with this program. If not, see
78 * <http://www.gnu.org/licenses/>.
79
80 * Authors:
81 * RFWS: R.F. Warren-Smith (Starlink)
82
83 * History:
84 * 12-AUG-1996 (RFWS):
85 * Original version.
86 * 6-SEP-1996:
87 * Finished initial implementation.
88 * 11-DEC-1996 (RFWS):
89 * Added support for foreign language source and sink functions.
90 * 28-APR-1997 (RFWS):
91 * Prevent "-0" being written (use "0" instead).
92 * 27-NOV-2002 (DSB):
93 * Added astWriteInvocations.
94 * 8-JAN-2003 (DSB):
95 * - Changed private InitVtab method to protected astInitChannelVtab
96 * method.
97 * - Modified to use protected Vtab initialisation methods when
98 * loading an Object.
99 * 1-NOV-2003 (DSB):
100 * Change the initialiser so that it accepts source and sink
101 * wrapper functions as arguments (for use by derived classes).
102 * 16-AUG-2006 (DSB):
103 * - Document non-destructive nature of unsuccessful astRead calls
104 * on a FitsChan.
105 * 3-OCT-2008 (DSB):
106 * Added "Strict" attribute.
107 * 11-DEC-2008 (DSB):
108 * Added astPutChannelData and astChannelData functions.
109 * 16-JAN-2009 (DSB):
110 * Added astAddWarning and astWarnings.
111 * 11-JUN-2009 (DSB):
112 * Enable astChannelData to be used from within astRead.
113 * 7-DEC-2009 (DSB):
114 * Added Indent attribute.
115 * 12-FEB-2010 (DSB):
116 * Represent AST__BAD externally using the string "<bad>".
117 * 23-JUN-2011 (DSB):
118 * Added attributes SinkFile and SourceFile.
119 * 2-OCT-2012 (DSB):
120 * Report an error if an Inf or NaN value is read from the external
121 * source.
122 *class--
123 */
124
125 /* Module Macros. */
126 /* ============== */
127 /* Set the name of the class we are implementing. This indicates to
128 the header files that define class interfaces that they should make
129 "protected" symbols available. */
130 #define astCLASS Channel
131
132 /* Define a string containing the maximum length of keywords used to
133 identify values in the external representation of data. This is
134 deliberately kept small so as to simplify integration with
135 standards such as FITS. */
136 #define MAX_NAME "8"
137
138 /* Max length of string returned by GetAttrib */
139 #define GETATTRIB_BUFF_LEN 50
140
141 /* String used to represent AST__BAD externally. */
142 #define BAD_STRING "<bad>"
143
144 /* Include files. */
145 /* ============== */
146 /* Interface definitions. */
147 /* ---------------------- */
148
149 #include "globals.h" /* Thread-safe global data access */
150 #include "error.h" /* Error reporting facilities */
151 #include "memory.h" /* Memory allocation facilities */
152 #include "object.h" /* Base Object class */
153 #include "channel.h" /* Interface definition for this class */
154 #include "loader.h" /* Interface to the global loader */
155 #include "keymap.h" /* Storing arbitrary data in an AST Object */
156 #include "pointset.h" /* For AST__BAD */
157
158 /* Error code definitions. */
159 /* ----------------------- */
160 #include "ast_err.h" /* AST error codes */
161
162 /* C header files. */
163 /* --------------- */
164 #include <ctype.h>
165 #include <errno.h>
166 #include <float.h>
167 #include <limits.h>
168 #include <stdarg.h>
169 #include <stddef.h>
170 #include <stdio.h>
171 #include <string.h>
172
173 /* Module Variables. */
174 /* ================= */
175
176 /* Address of this static variable is used as a unique identifier for
177 member of this class. */
178 static int class_check;
179
180 /* Pointers to parent class methods which are extended by this class. */
181 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
182 static int (* parent_testattrib)( AstObject *, const char *, int * );
183 static void (* parent_clearattrib)( AstObject *, const char *, int * );
184 static void (* parent_setattrib)( AstObject *, const char *, int * );
185
186 /* Define macros for accessing each item of thread specific global data. */
187 #ifdef THREAD_SAFE
188
189 /* Define how to initialise thread-specific globals. */
190 #define GLOBAL_inits \
191 globals->Class_Init = 0; \
192 globals->AstReadClassData_Msg = 0; \
193 globals->GetAttrib_Buff[ 0 ] = 0; \
194 globals->Items_Written = 0; \
195 globals->Current_Indent = 0; \
196 globals->Nest = -1; \
197 globals->Nwrite_Invoc = 0; \
198 globals->Object_Class = NULL; \
199 globals->Values_List = NULL; \
200 globals->Values_Class = NULL; \
201 globals->Values_OK = NULL; \
202 globals->End_Of_Object = NULL; \
203 globals->Channel_Data = NULL;
204
205 /* Create the function that initialises global data for this module. */
206 astMAKE_INITGLOBALS(Channel)
207
208 /* Define macros for accessing each item of thread specific global data. */
209 #define class_init astGLOBAL(Channel,Class_Init)
210 #define class_vtab astGLOBAL(Channel,Class_Vtab)
211 #define astreadclassdata_msg astGLOBAL(Channel,AstReadClassData_Msg)
212 #define getattrib_buff astGLOBAL(Channel,GetAttrib_Buff)
213 #define items_written astGLOBAL(Channel,Items_Written)
214 #define current_indent astGLOBAL(Channel,Current_Indent)
215 #define nest astGLOBAL(Channel,Nest)
216 #define nwrite_invoc astGLOBAL(Channel,Nwrite_Invoc)
217 #define object_class astGLOBAL(Channel,Object_Class)
218 #define values_list astGLOBAL(Channel,Values_List)
219 #define values_class astGLOBAL(Channel,Values_Class)
220 #define values_ok astGLOBAL(Channel,Values_OK)
221 #define end_of_object astGLOBAL(Channel,End_Of_Object)
222 #define channel_data astGLOBAL(Channel,Channel_Data)
223
224
225
226 static pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
227 #define LOCK_MUTEX2 pthread_mutex_lock( &mutex2 );
228 #define UNLOCK_MUTEX2 pthread_mutex_unlock( &mutex2 );
229
230 static pthread_mutex_t mutex3 = PTHREAD_MUTEX_INITIALIZER;
231 #define LOCK_MUTEX3 pthread_mutex_lock( &mutex3 );
232 #define UNLOCK_MUTEX3 pthread_mutex_unlock( &mutex3 );
233
234 /* If thread safety is not needed, declare and initialise globals at static
235 variables. */
236 #else
237
238 /* Contextual error message reported in astReadClassData? */
239 static int astreadclassdata_msg = 0;
240
241 /* Buffer returned by GetAttrib. */
242 static char getattrib_buff[ GETATTRIB_BUFF_LEN + 1 ];
243
244 /* Count of the number of output items written since the last "Begin"
245 or "IsA" item. */
246 static int items_written = 0;
247
248 /* Amount of indentation to be applied to the next output item. */
249 static int current_indent = 0;
250
251 /* Nesting level, used to keep track of data associated with building
252 Objects when they contain other Objects. */
253 static int nest = -1;
254
255 /* The number of times astWrite has been invoked. */
256 static int nwrite_invoc = 0;
257
258 /* Pointer to a user-supplied block of memory to be made available to
259 source or sink functions via the astChannelData function. */
260 static void *channel_data = NULL;
261
262 /***
263 The following items are all pointers to dynamically allocated
264 arrays (stacks) that grow as necessary to accommodate one element
265 for each level of nesting (one more than the value of "nest").
266 ***/
267
268 /* Stack of pointers to null-terminated character strings giving the
269 names of the classes of the Objects being built at each nesting
270 level. */
271 static char **object_class = NULL;
272
273 /* Stack of pointers to the elements designated as the "heads" of
274 circular, doubly linked lists of name-value associations. */
275 static AstChannelValue **values_list = NULL;
276
277 /* Stack of pointers to null-terminated character strings giving the
278 names of the classes for which the values held in the values lists
279 are intended. */
280 static char **values_class = NULL;
281
282 /* Stack of flags indicating whether the values held in the values
283 lists are intended for the class loaders currently executing to
284 build Objects at each nesting level. */
285 static int *values_ok = NULL;
286
287 /* Stack of flags indicating whether "End" items have been read for
288 the Objects being built at each nesting level. */
289 static int *end_of_object = NULL;
290
291
292 /* Define the class virtual function table and its initialisation flag
293 as static variables. */
294 static AstChannelVtab class_vtab; /* Virtual function table */
295 static int class_init = 0; /* Virtual function table initialised? */
296 #define LOCK_MUTEX2
297 #define UNLOCK_MUTEX2
298 #define LOCK_MUTEX3
299 #define UNLOCK_MUTEX3
300
301 #endif
302
303 /* External Interface Function Prototypes. */
304 /* ======================================= */
305 /* The following functions have public prototypes only (i.e. no
306 protected prototypes), so we must provide local prototypes for use
307 within this module. */
308 AstChannel *astChannelForId_( const char *(*)( void ),
309 char *(*)( const char *(*)( void ), int * ),
310 void (*)( const char * ),
311 void (*)( void (*)( const char * ),
312 const char *, int * ),
313 const char *, ... );
314 AstChannel *astChannelId_( const char *(*)( void ), void (*)( const char * ), const char *, ... );
315
316 /* Prototypes for Private Member Functions. */
317 /* ======================================== */
318 static AstObject *Read( AstChannel *, int * );
319 static AstObject *ReadObject( AstChannel *, const char *, AstObject *, int * );
320 static AstChannelValue *FreeValue( AstChannelValue *, int * );
321 static AstChannelValue *LookupValue( const char *, int * );
322 static AstKeyMap *Warnings( AstChannel *, int * );
323 static char *GetNextText( AstChannel *, int * );
324 static char *InputTextItem( AstChannel *, int * );
325 static char *ReadString( AstChannel *, const char *, const char *, int * );
326 static char *SourceWrap( const char *(*)( void ), int * );
327 static const char *GetAttrib( AstObject *, const char *, int * );
328 static double ReadDouble( AstChannel *, const char *, double, int * );
329 static int GetComment( AstChannel *, int * );
330 static int GetFull( AstChannel *, int * );
331 static int GetSkip( AstChannel *, int * );
332 static int GetStrict( AstChannel *, int * );
333 static int ReadInt( AstChannel *, const char *, int, int * );
334 static int TestAttrib( AstObject *, const char *, int * );
335 static int TestComment( AstChannel *, int * );
336 static int TestFull( AstChannel *, int * );
337 static int TestSkip( AstChannel *, int * );
338 static int TestStrict( AstChannel *, int * );
339 static int Use( AstChannel *, int, int, int * );
340 static int Write( AstChannel *, AstObject *, int * );
341 static void AddWarning( AstChannel *, int, const char *, const char *, int * );
342 static void AppendValue( AstChannelValue *, AstChannelValue **, int * );
343 static void ClearAttrib( AstObject *, const char *, int * );
344 static void ClearComment( AstChannel *, int * );
345 static void ClearFull( AstChannel *, int * );
346 static void ClearSkip( AstChannel *, int * );
347 static void ClearStrict( AstChannel *, int * );
348 static void ClearValues( AstChannel *, int * );
349 static void Copy( const AstObject *, AstObject *, int * );
350 static void Delete( AstObject *, int * );
351 static void Dump( AstObject *, AstChannel *, int * );
352 static void GetNextData( AstChannel *, int, char **, char **, int * );
353 static void OutputTextItem( AstChannel *, const char *, int * );
354 static void PutChannelData( AstChannel *, void *, int * );
355 static void PutNextText( AstChannel *, const char *, int * );
356 static void ReadClassData( AstChannel *, const char *, int * );
357 static void RemoveValue( AstChannelValue *, AstChannelValue **, int * );
358 static void SetAttrib( AstObject *, const char *, int * );
359 static void SetComment( AstChannel *, int, int * );
360 static void SetFull( AstChannel *, int, int * );
361 static void SetSkip( AstChannel *, int, int * );
362 static void SetStrict( AstChannel *, int, int * );
363 static void SinkWrap( void (*)( const char * ), const char *, int * );
364 static void Unquote( AstChannel *, char *, int * );
365 static void WriteBegin( AstChannel *, const char *, const char *, int * );
366 static void WriteDouble( AstChannel *, const char *, int, int, double, const char *, int * );
367 static void WriteEnd( AstChannel *, const char *, int * );
368 static void WriteInt( AstChannel *, const char *, int, int, int, const char *, int * );
369 static void WriteIsA( AstChannel *, const char *, const char *, int * );
370 static void WriteObject( AstChannel *, const char *, int, int, AstObject *, const char *, int * );
371 static void WriteString( AstChannel *, const char *, int, int, const char *, const char *, int * );
372
373 static int GetReportLevel( AstChannel *, int * );
374 static int TestReportLevel( AstChannel *, int * );
375 static void ClearReportLevel( AstChannel *, int * );
376 static void SetReportLevel( AstChannel *, int, int * );
377
378 static int GetIndent( AstChannel *, int * );
379 static int TestIndent( AstChannel *, int * );
380 static void ClearIndent( AstChannel *, int * );
381 static void SetIndent( AstChannel *, int, int * );
382
383 static const char *GetSourceFile( AstChannel *, int * );
384 static int TestSourceFile( AstChannel *, int * );
385 static void ClearSourceFile( AstChannel *, int * );
386 static void SetSourceFile( AstChannel *, const char *, int * );
387
388 static const char *GetSinkFile( AstChannel *, int * );
389 static int TestSinkFile( AstChannel *, int * );
390 static void ClearSinkFile( AstChannel *, int * );
391 static void SetSinkFile( AstChannel *, const char *, int * );
392
393 /* Member functions. */
394 /* ================= */
AddWarning(AstChannel * this,int level,const char * msg,const char * method,int * status)395 static void AddWarning( AstChannel *this, int level, const char *msg,
396 const char *method, int *status ) {
397 /*
398 *+
399 * Name:
400 * astAddWarning
401
402 * Purpose:
403 * Add a warning to a Channel.
404
405 * Type:
406 * Protected virtual function.
407
408 * Synopsis:
409 * #include "channel.h"
410 * void astAddWarning( AstChannel *this, int level, const char *msg,
411 * const char *method, int status, ... )
412
413 * Class Membership:
414 * Channel method.
415
416 * Description:
417 * This function stores a warning message inside a Channel. These
418 * messages can be retirieved using astWarnings.
419
420 * Parameters:
421 * this
422 * Pointer to the Channel.
423 * level
424 * Ignore the warning if the ReportLevel attribute value is less
425 * than "level".
426 * msg
427 * The wanting message to store. It may contain printf format
428 * specifiers. If a NULL pointer is supplied, all warnings
429 * currently stored in the Channel are removed.
430 * method
431 * The method name.
432 * status
433 * Inherited status value.
434 * ...
435 * Extra values to substitute into the message string as
436 * replacements for the printf format specifiers.
437 *-
438
439 * Note: The expansion of the printf format specifiers is done in the
440 * astAddWarning_ wrapper function. The AddWarning functions defined by
441 * each class receives the fully expanded message and does not have a
442 * variable argument list. The variable argument list is included in the
443 * above prologue in order to document the wrapper function.
444
445 */
446
447 /* Local Variables: */
448 int i; /* Message index */
449 char *a; /* Pointer to copy of message */
450
451 /* If a NULL pointer was supplied, free all warnings currently in the
452 Channel. Do this before checking the inherited status so that it works
453 even if an error has occurred. */
454 if( !msg ) {
455 for( i = 0; i < this->nwarn; i++ ) {
456 (this->warnings)[ i ] = astFree( (this->warnings)[ i ] );
457 }
458 this->warnings = astFree( this->warnings );
459 this->nwarn = 0;
460 return;
461 }
462
463 /* Check the global error status. */
464 if ( !astOK ) return;
465
466 /* Only proceed if the message level is sufficiently important. */
467 if( astGetReportLevel( this ) >= level ) {
468
469 /* If we are being strict, issue an error rather than a warning. */
470 if( astGetStrict( this ) ) {
471 if( astOK ) {
472 astError( AST__BADIN, "%s(%s): %s", status, method,
473 astGetClass( this ), msg );
474 }
475
476 /* Otherwise, we store a copy of the message in the Channel. */
477 } else {
478
479 /* Allocate memory and store a copy of th supplied string in it. */
480 a = astStore( NULL, msg, strlen( msg ) + 1 );
481
482 /* Expand the array of warning pointers in ther Channel structure. */
483 this->warnings = astGrow( this->warnings, this->nwarn + 1,
484 sizeof( char * ) );
485
486 /* If all is OK so far, store the new warning pointer, and increment the
487 number of warnings in the Channel. */
488 if( astOK ) {
489 (this->warnings)[ (this->nwarn)++ ] = a;
490
491 /* Otherwise, attempt to free the memory holding the copy of the warning. */
492 } else {
493 a = astFree( a );
494 }
495 }
496 }
497 }
498
AppendValue(AstChannelValue * value,AstChannelValue ** head,int * status)499 static void AppendValue( AstChannelValue *value, AstChannelValue **head, int *status ) {
500 /*
501 * Name:
502 * AppendValue
503
504 * Purpose:
505 * Append a Value structure to a list.
506
507 * Type:
508 * Private function.
509
510 * Synopsis:
511 * #include "channel.h"
512 * void AppendValue( AstChannelValue *value, AstChannelValue **head, int *status )
513
514 * Class Membership:
515 * Channel member function.
516
517 * Description:
518 * This function appends a Value structure to a doubly linked
519 * circular list of such structures. The new list element is
520 * inserted just in front of the element occupying the "head of
521 * list" position (i.e. it becomes the new last element in the
522 * list).
523
524 * Parameters:
525 * value
526 * Pointer to the new element. This must not already be in the
527 * list.
528 * head
529 * Address of a pointer to the element at the head of the list
530 * (this pointer should be NULL if the list is initially
531 * empty). This pointer will only be updated if a new element is
532 * being added to an empty list.
533 * status
534 * Pointer to the inherited status variable.
535
536 * Notes:
537 * - This function does not perform error chacking and does not
538 * generate errors.
539 */
540
541 /* If the list is initially empty, the sole new element points at
542 itself. */
543 if ( !*head ) {
544 value->flink = value;
545 value->blink = value;
546
547 /* Update the list head to identify the new element. */
548 *head = value;
549
550 /* Otherwise, insert the new element in front of the element at the
551 head of the list. */
552 } else {
553 value->flink = *head;
554 value->blink = ( *head )->blink;
555 ( *head )->blink = value;
556 value->blink->flink = value;
557 }
558 }
559
astChannelData_(void)560 void *astChannelData_( void ) {
561 /*
562 c++
563 * Name:
564 * astChannelData
565
566 * Purpose:
567 * Return a pointer to user-supplied data stored with a Channel.
568
569 * Type:
570 * Public macro.
571
572 * Synopsis:
573 * #include "channel.h"
574 * void *astChannelData
575
576 * Class Membership:
577 * Channel macro.
578
579 * Description:
580 * This macro is intended to be used within the source or sink
581 * functions associated with a Channel. It returns any pointer
582 * previously stored in the Channel (that is, the Channel that has
583 * invoked the source or sink function) using astPutChannelData.
584 *
585 * This mechanism is a thread-safe alternative to passing file
586 * descriptors, etc, via static global variables.
587
588 * Returned Value:
589 * astChannelData
590 * The pointer previously stored with the Channel using
591 * astPutChannelData. A NULL pointer will be returned if no such
592 * pointer has been stored with the Channel.
593
594 * Applicability:
595 * Channel
596 * This macro applies to all Channels.
597
598 * Notes:
599 * - This routine is not available in the Fortran 77 interface to
600 * the AST library.
601 c--
602 */
603 astDECLARE_GLOBALS
604 astGET_GLOBALS(NULL);
605 return channel_data;
606 }
607
ClearAttrib(AstObject * this_object,const char * attrib,int * status)608 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
609 /*
610 * Name:
611 * ClearAttrib
612
613 * Purpose:
614 * Clear an attribute value for a Channel.
615
616 * Type:
617 * Private function.
618
619 * Synopsis:
620 * #include "channel.h"
621 * void ClearAttrib( AstObject *this, const char *attrib, int *status )
622
623 * Class Membership:
624 * Channel member function (over-rides the astClearAttrib protected
625 * method inherited from the Object class).
626
627 * Description:
628 * This function clears the value of a specified attribute for a
629 * Channel, so that the default value will subsequently be used.
630
631 * Parameters:
632 * this
633 * Pointer to the Channel.
634 * attrib
635 * Pointer to a null terminated string specifying the attribute
636 * name. This should be in lower case with no surrounding white
637 * space.
638 * status
639 * Pointer to the inherited status variable.
640 */
641
642 /* Local Variables: */
643 AstChannel *this; /* Pointer to the Channel structure */
644
645 /* Check the global error status. */
646 if ( !astOK ) return;
647
648 /* Obtain a pointer to the Channel structure. */
649 this = (AstChannel *) this_object;
650
651 /* Check the attribute name and clear the appropriate attribute. */
652
653 /* Comment. */
654 /* -------- */
655 if ( !strcmp( attrib, "comment" ) ) {
656 astClearComment( this );
657
658 /* Full. */
659 /* ----- */
660 } else if ( !strcmp( attrib, "full" ) ) {
661 astClearFull( this );
662
663 /* Indent. */
664 /* ------- */
665 } else if ( !strcmp( attrib, "indent" ) ) {
666 astClearIndent( this );
667
668 /* ReportLevel. */
669 /* ------------ */
670 } else if ( !strcmp( attrib, "reportlevel" ) ) {
671 astClearReportLevel( this );
672
673 /* Skip. */
674 /* ----- */
675 } else if ( !strcmp( attrib, "skip" ) ) {
676 astClearSkip( this );
677
678 /* SourceFile. */
679 /* ----------- */
680 } else if ( !strcmp( attrib, "sourcefile" ) ) {
681 astClearSourceFile( this );
682
683 /* SinkFile. */
684 /* --------- */
685 } else if ( !strcmp( attrib, "sinkfile" ) ) {
686 astClearSinkFile( this );
687
688 /* Strict. */
689 /* ------- */
690 } else if ( !strcmp( attrib, "strict" ) ) {
691 astClearStrict( this );
692
693 /* If the attribute is still not recognised, pass it on to the parent
694 method for further interpretation. */
695 } else {
696 (*parent_clearattrib)( this_object, attrib, status );
697 }
698 }
699
ClearValues(AstChannel * this,int * status)700 static void ClearValues( AstChannel *this, int *status ) {
701 /*
702 * Name:
703 * ClearValues
704
705 * Purpose:
706 * Clear the current values list.
707
708 * Type:
709 * Private function.
710
711 * Synopsis:
712 * #include "channel.h"
713 * void ClearValues( AstChannel *this, int *status )
714
715 * Class Membership:
716 * Channel member function.
717
718 * Description:
719 * This function clears any (un-read) Value structures remaining in
720 * the current values list (i.e. at the current nesting level). It
721 * should be invoked after all required values have been read.
722 *
723 * If the values list has not been read, or if any remaining values
724 * are found (i.e. the list is not empty) then this indicates an
725 * unrecognised input class or an input value that has not been
726 * read by a class loader. This implies an error in the loader, or
727 * bad input data, so an error is reported.
728 *
729 * All resources used by any remaining Value structures are freed
730 * and the values list is left in an empty state.
731
732 * Parameters:
733 * this
734 * Pointer to the Channel being read. This is only used for
735 * constructing error messages. It must not be NULL.
736 * status
737 * Pointer to the inherited status variable.
738
739 * Notes:
740 * - This function attempts to execute even if the global error
741 * status is set on entry, although no further error report will be
742 * made if it subsequently fails under these circumstances.
743 */
744
745 /* Local Variables: */
746 astDECLARE_GLOBALS /* Declare the thread specific global data */
747 AstChannelValue **head; /* Address of pointer to values list */
748 AstChannelValue *value; /* Pointer to value list element */
749
750 /* Get a pointer to the structure holding thread-specific global data. */
751 astGET_GLOBALS(this);
752
753 /* If "values_class" is non-NULL, then the values list has previously
754 been filled with Values for a class. */
755 if ( values_class[ nest ] ) {
756
757 /* If "values_ok" is zero, however, then these Values have not yet
758 been read by a class loader. This must be due to a bad class name
759 associated with them or because the class data are not available in
760 the correct order. If we are using strict error reporting, then report
761 an error (unless the error status is already set). */
762 if ( astGetStrict( this ) && !values_ok[ nest ] && astOK ) {
763 astError( AST__BADIN,
764 "astRead(%s): Invalid class structure in input data.", status,
765 astGetClass( this ) );
766 astError( AST__BADIN,
767 "Class \"%s\" is invalid or out of order within a %s.", status,
768 values_class[ nest ], object_class[ nest ] );
769 }
770
771 /* Free the memory holding the class string. */
772 values_class[ nest ] = astFree( values_class[ nest ] );
773 }
774
775 /* Reset the "values_ok" flag. */
776 values_ok[ nest ] = 0;
777
778 /* Now clear any Values remaining in the values list. Obtain the
779 address of the pointer to the head of this list (at the current
780 nesting level) and loop to remove Values from the list while it is
781 not empty. */
782 head = values_list + nest;
783 while ( *head ) {
784
785 /* Obtain a pointer to the first element. */
786 value = *head;
787
788 /* Issue a warning. */
789 if ( value->is_object ) {
790 astAddWarning( this, 1, "The Object \"%s = <%s>\" was "
791 "not recognised as valid input.", "astRead", status,
792 value->name, astGetClass( value->ptr.object ) );
793 } else {
794 astAddWarning( this, 1, "The value \"%s = %s\" was not "
795 "recognised as valid input.", "astRead", status,
796 value->name, value->ptr.string );
797 }
798
799 /* Remove the Value structure from the list (which updates the head of
800 list pointer) and free its resources. */
801 RemoveValue( value, head, status );
802 value = FreeValue( value, status );
803 }
804 }
805
FreeValue(AstChannelValue * value,int * status)806 static AstChannelValue *FreeValue( AstChannelValue *value, int *status ) {
807 /*
808 * Name:
809 * FreeValue
810
811 * Purpose:
812 * Free a dynamically allocated Value structure.
813
814 * Type:
815 * Private function.
816
817 * Synopsis:
818 * #include "channel.h"
819 * AstChannelValue *FreeValue( AstChannelValue *value, int *status )
820
821 * Class Membership:
822 * Channel member function.
823
824 * Description:
825 * This function frees a dynamically allocated Value structure,
826 * releasing all resources used by it. The structure contents must
827 * have been correctly initialised.
828
829 * Parameters:
830 * value
831 * Pointer to the Value structure to be freed.
832 * status
833 * Pointer to the inherited status variable.
834
835 * Returned Value:
836 * A NULL pointer is always returned.
837
838 * Notes:
839 * - This function attempts to execute even if the global error
840 * status is set on entry, although no further error report will be
841 * made if it subsequently fails under these circumstances.
842 */
843
844 /* Check that a non-NULL pointer has been supplied. */
845 if ( value ) {
846
847 /* If the "name" component has been allocated, then free it. */
848 if ( value->name ) value->name = astFree( value->name );
849
850 /* If the "ptr" component identifies an Object, then annul the Object
851 pointer. */
852 if ( value->is_object ) {
853 if ( value->ptr.object ) {
854 value->ptr.object = astAnnul( value->ptr.object );
855 }
856
857 /* Otherwise, if it identifies a string, then free the string. */
858 } else {
859 if ( value->ptr.string ) {
860 value->ptr.string = astFree( value->ptr.string );
861 }
862 }
863
864 /* Free the Value structure itself. */
865 value = astFree( value );
866 }
867
868 /* Return a NULL pointer. */
869 return NULL;
870 }
871
GetAttrib(AstObject * this_object,const char * attrib,int * status)872 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
873 /*
874 * Name:
875 * GetAttrib
876
877 * Purpose:
878 * Get the value of a specified attribute for a Channel.
879
880 * Type:
881 * Private function.
882
883 * Synopsis:
884 * #include "channel.h"
885 * const char *GetAttrib( AstObject *this, const char *attrib, int *status )
886
887 * Class Membership:
888 * Channel member function (over-rides the protected astGetAttrib
889 * method inherited from the Object class).
890
891 * Description:
892 * This function returns a pointer to the value of a specified
893 * attribute for a Channel, formatted as a character string.
894
895 * Parameters:
896 * this
897 * Pointer to the Channel.
898 * attrib
899 * Pointer to a null terminated string containing the name of
900 * the attribute whose value is required. This name should be in
901 * lower case, with all white space removed.
902 * status
903 * Pointer to the inherited status variable.
904
905 * Returned Value:
906 * - Pointer to a null terminated string containing the attribute
907 * value.
908
909 * Notes:
910 * - The returned string pointer may point at memory allocated
911 * within the Channel, or at static memory. The contents of the
912 * string may be over-written or the pointer may become invalid
913 * following a further invocation of the same function or any
914 * modification of the Channel. A copy of the string should
915 * therefore be made if necessary.
916 * - A NULL pointer will be returned if this function is invoked
917 * with the global error status set, or if it should fail for any
918 * reason.
919 */
920
921 /* Local Variables: */
922 astDECLARE_GLOBALS /* Declare the thread specific global data */
923 AstChannel *this; /* Pointer to the Channel structure */
924 const char *result; /* Pointer value to return */
925 int comment; /* Comment attribute value */
926 int full; /* Full attribute value */
927 int indent; /* Indent attribute value */
928 int report_level; /* ReportLevel attribute value */
929 int skip; /* Skip attribute value */
930 int strict; /* Report errors insead of warnings? */
931
932 /* Initialise. */
933 result = NULL;
934
935 /* Check the global error status. */
936 if ( !astOK ) return result;
937
938 /* Get a pointer to the structure holding thread-specific global data. */
939 astGET_GLOBALS(this_object);
940
941 /* Obtain a pointer to the Channel structure. */
942 this = (AstChannel *) this_object;
943
944 /* Compare "attrib" with each recognised attribute name in turn,
945 obtaining the value of the required attribute. If necessary, write
946 the value into "getattrib_buff" as a null terminated string in an appropriate
947 format. Set "result" to point at the result string. */
948
949 /* Comment. */
950 /* -------- */
951 if ( !strcmp( attrib, "comment" ) ) {
952 comment = astGetComment( this );
953 if ( astOK ) {
954 (void) sprintf( getattrib_buff, "%d", comment );
955 result = getattrib_buff;
956 }
957
958 /* Full. */
959 /* ----- */
960 } else if ( !strcmp( attrib, "full" ) ) {
961 full = astGetFull( this );
962 if ( astOK ) {
963 (void) sprintf( getattrib_buff, "%d", full );
964 result = getattrib_buff;
965 }
966
967 /* Indent. */
968 /* ------- */
969 } else if ( !strcmp( attrib, "indent" ) ) {
970 indent = astGetIndent( this );
971 if ( astOK ) {
972 (void) sprintf( getattrib_buff, "%d", indent );
973 result = getattrib_buff;
974 }
975
976 /* ReportLevel. */
977 /* ------------ */
978 } else if ( !strcmp( attrib, "reportlevel" ) ) {
979 report_level = astGetReportLevel( this );
980 if ( astOK ) {
981 (void) sprintf( getattrib_buff, "%d", report_level );
982 result = getattrib_buff;
983 }
984
985 /* Skip. */
986 /* ----- */
987 } else if ( !strcmp( attrib, "skip" ) ) {
988 skip = astGetSkip( this );
989 if ( astOK ) {
990 (void) sprintf( getattrib_buff, "%d", skip );
991 result = getattrib_buff;
992 }
993
994 /* SourceFile. */
995 /* ----------- */
996 } else if ( !strcmp( attrib, "sourcefile" ) ) {
997 result = astGetSourceFile( this );
998
999 /* SinkFile. */
1000 /* --------- */
1001 } else if ( !strcmp( attrib, "sinkfile" ) ) {
1002 result = astGetSinkFile( this );
1003
1004 /* Strict. */
1005 /* ------- */
1006 } else if ( !strcmp( attrib, "strict" ) ) {
1007 strict = astGetStrict( this );
1008 if ( astOK ) {
1009 (void) sprintf( getattrib_buff, "%d", strict );
1010 result = getattrib_buff;
1011 }
1012
1013 /* If the attribute name was not recognised, pass it on to the parent
1014 method for further interpretation. */
1015 } else {
1016 result = (*parent_getattrib)( this_object, attrib, status );
1017 }
1018
1019 /* Return the result. */
1020 return result;
1021
1022 }
1023
GetNextData(AstChannel * this,int skip,char ** name,char ** val,int * status)1024 static void GetNextData( AstChannel *this, int skip, char **name,
1025 char **val, int *status ) {
1026 /*
1027 *+
1028 * Name:
1029 * astGetNextData
1030
1031 * Purpose:
1032 * Read the next item of data from a data source.
1033
1034 * Type:
1035 * Protected virtual function.
1036
1037 * Synopsis:
1038 * #include "channel.h"
1039 * void astGetNextData( AstChannel *this, int skip, char **name,
1040 * char **val )
1041
1042 * Class Membership:
1043 * Channel method.
1044
1045 * Description:
1046 * This function reads the next item of input data from a data
1047 * source associated with a Channel and returns the result.
1048 *
1049 * It is layered conceptually on the astGetNextText method, but
1050 * instead of returning the raw input text, it decodes it and
1051 * returns name/value pairs ready for use. Note that in some
1052 * derived classes, where the data are not stored as text, this
1053 * function may not actually use astGetNextText, but will access
1054 * the data directly.
1055
1056 * Parameters:
1057 * this
1058 * Pointer to the Channel.
1059 * skip
1060 * A non-zero value indicates that a new Object is to be read,
1061 * and that all input data up to the next "Begin" item are to be
1062 * skipped in order to locate it. This is useful if the data
1063 * source contains AST objects interspersed with other data (but
1064 * note that these other data cannot appear inside AST Objects,
1065 * only between them).
1066 *
1067 * A zero value indicates that all input data are significant
1068 * and the next item will therefore be read and an attempt made
1069 * to interpret it whatever it contains. Any other data
1070 * inter-mixed with AST Objects will then result in an error.
1071 * name
1072 * An address at which to store a pointer to a null-terminated
1073 * dynamically allocated string containing the name of the next
1074 * item in the input data stream. This name will be in lower
1075 * case with no surrounding white space. It is the callers
1076 * responsibilty to free the memory holding this string (using
1077 * astFree) when it is no longer required.
1078 *
1079 * A NULL pointer value will be returned (without error) to
1080 * indicate when there are no further input data items to be
1081 * read.
1082 * val
1083 * An address at which to store a pointer to a null-terminated
1084 * dynamically allocated string containing the value associated
1085 * with the next item in the input data stream. No case
1086 * conversion is performed on this string and all white space is
1087 * potentially significant. It is the callers responsibilty to
1088 * free the memory holding this string (using astFree) when it
1089 * is no longer required.
1090 *
1091 * The returned pointer will be NULL if an Object data item is
1092 * read (see the "Data Representation" section).
1093
1094 * Data Representation:
1095 * The returned data items fall into the following categories:
1096 *
1097 * - Begin: Identified by the name string "begin", this indicates
1098 * the start of an Object definition. The associated value string
1099 * gives the class name of the Object being defined.
1100 *
1101 * - IsA: Identified by the name string "isa", this indicates the
1102 * end of the data associated with a particular class structure
1103 * within the definiton of a larger Object. The associated value
1104 * string gives the name of the class whose data have just been
1105 * read.
1106 *
1107 * - End: Identified by the name string "end", this indicates the
1108 * end of the data associated with a complete Object
1109 * definition. The associated value string gives the class name of
1110 * the Object whose definition is being ended.
1111 *
1112 * - Non-Object: Identified by any other name string plus a
1113 * non-NULL "val" pointer, this gives the value of a non-Object
1114 * structure component (instance variable). The name identifies
1115 * which instance variable it is (within the context of the class
1116 * whose data are being read) and the value is encoded as a string.
1117 *
1118 * - Object: Identified by any other name string plus a NULL "val"
1119 * pointer, this identifies the value of an Object structure
1120 * component (instance variable). The name identifies which
1121 * instance variable it is (within the context of the class whose
1122 * data are being read) and the value is given by subsequent data
1123 * items (so the next item should be a "Begin" item).
1124
1125 * Notes:
1126 * - NULL pointer values will be returned if this function is
1127 * invoked with the global error status set, or if it should fail
1128 * for any reason.
1129 * - This method is provided primarily so that derived classes may
1130 * over-ride it in order to read from alternative data sources. It
1131 * provides a higher-level interface than astGetNextText, so is
1132 * suitable for classes that either need to read textual data in a
1133 * different format, or to read from non-textual data sources.
1134 *-
1135 */
1136
1137 /* Local Variables: */
1138 char *line; /* Pointer to input text line */
1139 int done; /* Data item read? */
1140 int i; /* Loop counter for string characters */
1141 int len; /* Length of input text line */
1142 int nc1; /* Offset to start of first field */
1143 int nc2; /* Offset to end of first field */
1144 int nc3; /* Offset to start of second field */
1145 int nc; /* Number of charaters read by "astSscanf" */
1146
1147 /* Initialise the returned values. */
1148 *name = NULL;
1149 *val = NULL;
1150
1151 /* Check the global error status. */
1152 if ( !astOK ) return;
1153
1154 /* Read the next input line as text (the loop is needed to allow
1155 initial lines to be skipped if the "skip" flag is set). */
1156 done = 0;
1157 while ( !done && ( line = InputTextItem( this, status ) ) && astOK ) {
1158
1159 /* If OK, determine the line length. */
1160 len = strlen( line );
1161
1162 /* Non-Object value. */
1163 /* ----------------- */
1164 /* Test for lines of the form " name = value" (or similar), where the
1165 name is no more than MAX_NAME characters long (the presence of a
1166 value on the right hand side indicates that this is a non-Object
1167 value, encoded as a string). Ignore these lines if the "skip" flag
1168 is set. */
1169 if ( nc = 0,
1170 ( !skip
1171 && ( 0 == astSscanf( line,
1172 " %n%*" MAX_NAME "[^ \t=]%n = %n%*[^\n]%n",
1173 &nc1, &nc2, &nc3, &nc ) )
1174 && ( nc >= len ) ) ) {
1175
1176 /* Note we have found a data item. */
1177 done = 1;
1178
1179 /* Extract the name and value fields. */
1180 *name = astString( line + nc1, nc2 - nc1 );
1181 *val = astString( line + nc3, len - nc3 );
1182
1183 /* If OK, truncate the value to remove any trailing white space. */
1184 if ( astOK ) {
1185 i = len - nc3 - 1;
1186 while ( ( i >= 0 ) && isspace( ( *val )[ i ] ) ) i--;
1187 ( *val )[ i + 1 ] = '\0';
1188
1189 /* Also remove any quotes from the string. */
1190 Unquote( this, *val, status );
1191 }
1192
1193 /* Object value. */
1194 /* ------------- */
1195 /* Test for lines of the form " name = " (or similar), where the name
1196 is no more than MAX_NAME characters long (the absence of a value on
1197 the right hand side indicates that this is an Object, whose
1198 definition follows on subsequent input lines). Ignore these lines
1199 if the "skip" flag is set. */
1200 } else if ( nc = 0,
1201 ( !skip
1202 && ( 0 == astSscanf( line,
1203 " %n%*" MAX_NAME "[^ \t=]%n = %n",
1204 &nc1, &nc2, &nc ) )
1205 && ( nc >= len ) ) ) {
1206
1207 /* Note we have found a data item. */
1208 done = 1;
1209
1210 /* Extract the name field but leave the value pointer as NULL. */
1211 *name = astString( line + nc1, nc2 - nc1 );
1212
1213 /* Begin. */
1214 /* ------ */
1215 /* Test for lines of the form " Begin Class " (or similar). */
1216 } else if ( nc = 0,
1217 ( ( 0 == astSscanf( line,
1218 " %*1[Bb]%*1[Ee]%*1[Gg]%*1[Ii]%*1[Nn] %n%*s%n %n",
1219 &nc1, &nc2, &nc ) )
1220 && ( nc >= len ) ) ) {
1221
1222 /* Note we have found a data item. */
1223 done = 1;
1224
1225 /* Set the returned name to "begin" and extract the associated class
1226 name for the value. Store both of these in dynamically allocated
1227 strings. */
1228 *name = astString( "begin", 5 );
1229 *val = astString( line + nc1, nc2 - nc1 );
1230
1231 /* IsA. */
1232 /* ---- */
1233 /* Test for lines of the form " IsA Class " (or similar). Ignore these
1234 lies if the "skip" flag is set. */
1235 } else if ( nc = 0,
1236 ( !skip
1237 && ( 0 == astSscanf( line,
1238 " %*1[Ii]%*1[Ss]%*1[Aa] %n%*s%n %n",
1239 &nc1, &nc2, &nc ) )
1240 && ( nc >= len ) ) ) {
1241
1242 /* Note we have found a data item. */
1243 done = 1;
1244
1245 /* Set the returned name to "isa" and extract the associated class
1246 name for the value. */
1247 *name = astString( "isa", 3 );
1248 *val = astString( line + nc1, nc2 - nc1 );
1249
1250 /* End. */
1251 /* ---- */
1252 /* Test for lines of the form " End Class " (or similar). Ignore these
1253 lines if the "skip" flag is set. */
1254 } else if ( nc = 0,
1255 ( !skip
1256 && ( 0 == astSscanf( line,
1257 " %*1[Ee]%*1[Nn]%*1[Dd] %n%*s%n %n",
1258 &nc1, &nc2, &nc ) )
1259 && ( nc >= len ) ) ) {
1260
1261 /* Note we have found a data item. */
1262 done = 1;
1263
1264 /* If found, set the returned name to "end" and extract the associated
1265 class name for the value. */
1266 *name = astString( "end", 3 );
1267 *val = astString( line + nc1, nc2 - nc1 );
1268
1269 /* If the input line didn't match any of the above and the "skip" flag
1270 is not set, then report an error. */
1271 } else if ( !skip ) {
1272 astError( AST__BADIN,
1273 "astRead(%s): Cannot interpret the input data: \"%s\".", status,
1274 astGetClass( this ), line );
1275 }
1276
1277 /* Free the memory holding the input data as text. */
1278 line = astFree( line );
1279 }
1280
1281 /* If successful, convert the name to lower case. */
1282 if ( astOK && *name ) {
1283 for ( i = 0; ( *name )[ i ]; i++ ) {
1284 ( *name )[ i ] = tolower( ( *name )[ i ] );
1285 }
1286 }
1287
1288 /* If an error occurred, ensure that any memory allocated is freed and
1289 that NULL pointer values are returned. */
1290 if ( !astOK ) {
1291 *name = astFree( *name );
1292 *val = astFree( *val );
1293 }
1294 }
1295
GetNextText(AstChannel * this,int * status)1296 static char *GetNextText( AstChannel *this, int *status ) {
1297 /*
1298 *+
1299 * Name:
1300 * GetNextText
1301
1302 * Purpose:
1303 * Read the next line of input text from a data source.
1304
1305 * Type:
1306 * Protected virtual function.
1307
1308 * Synopsis:
1309 * #include "channel.h"
1310 * char *astGetNextText( AstChannel *this )
1311
1312 * Class Membership:
1313 * Channel method.
1314
1315 * Description:
1316 * This function reads the next "raw" input line of text from the
1317 * data source associated with a Channel.
1318 *
1319 * Each line is returned as a pointer to a null-terminated string
1320 * held in dynamic memory, and it is the caller's responsibility to
1321 * free this memory (using astFree) when it is no longer
1322 * required. A NULL pointer is returned if there are no more input
1323 * lines to be read.
1324
1325 * Parameters:
1326 * this
1327 * Pointer to the Channel.
1328
1329 * Returned Value:
1330 * Pointer to a null-terminated string containing the input line
1331 * (held in dynamically allocated memory, which must be freed by
1332 * the caller when no longer required). A NULL pointer is returned
1333 * if there are no more input lines to be read.
1334
1335 * Notes:
1336 * - A NULL pointer will be returned if this function is invoked
1337 * with the global error status set, or if it should fail for any
1338 * reason.
1339 * - This method is provided primarily so that derived classes may
1340 * over-ride it in order to read from alternative (textual) data
1341 * sources.
1342 *-
1343 */
1344
1345 /* Local Constants: */
1346 #define MIN_CHARS 81 /* Initial size for allocating memory */
1347 #define ERRBUF_LEN 80
1348
1349 /* Local Variables: */
1350 FILE *fd; /* Input file descriptor */
1351 char *errstat; /* Pointer for system error message */
1352 char *line; /* Pointer to line data to be returned */
1353 char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */
1354 const char *sink_file; /* Path to output sink file */
1355 const char *source_file; /* Path to source file */
1356 int c; /* Input character */
1357 int len; /* Length of input line */
1358 int readstat; /* "errno" value set by "getchar" */
1359 int size; /* Size of allocated memory */
1360
1361 /* Initialise. */
1362 line = NULL;
1363
1364 /* Check the global error status. */
1365 if ( !astOK ) return line;
1366
1367 /* If the SourceFile attribute of the Channel specifies an input file,
1368 but no input file has yet been opened, open it now. Report an error if
1369 it is the same as the sink file. */
1370 if( astTestSourceFile( this ) && !this->fd_in ) {
1371 source_file = astGetSourceFile( this );
1372
1373 if( this->fd_out ) {
1374 sink_file = astGetSinkFile( this );
1375 if( astOK && !strcmp( sink_file, source_file ) ) {
1376 astError( AST__RDERR, "astRead(%s): Failed to open input "
1377 "SourceFile '%s' - the file is currently being used "
1378 "as the output SinkFile.", status, astGetClass( this ),
1379 source_file );
1380 }
1381 }
1382
1383 if( astOK ) {
1384 this->fd_in = fopen( source_file, "r" );
1385 if( !this->fd_in ) {
1386 if ( errno ) {
1387 #if HAVE_STRERROR_R
1388 strerror_r( errno, errbuf, ERRBUF_LEN );
1389 errstat = errbuf;
1390 #else
1391 errstat = strerror( errno );
1392 #endif
1393 astError( AST__RDERR, "astRead(%s): Failed to open input "
1394 "SourceFile '%s' - %s.", status, astGetClass( this ),
1395 source_file, errstat );
1396 } else {
1397 astError( AST__RDERR, "astRead(%s): Failed to open input "
1398 "SourceFile '%s'.", status, astGetClass( this ),
1399 source_file );
1400 }
1401 }
1402
1403 }
1404 }
1405
1406 /* Source function defined, but no input file. */
1407 /* ------------------------------------------- */
1408 /* If no active input file descriptor is stored in the Channel, but
1409 a source function (and its wrapper function) is defined for the
1410 Channel, use the wrapper function to invoke the source function to
1411 read a line of input text. This is returned in a dynamically
1412 allocated string. */
1413 if ( !this->fd_in && this->source && this->source_wrap ) {
1414
1415 /* About to call an externally supplied function which may not be
1416 thread-safe, so lock a mutex first. Also store the channel data
1417 pointer in a global variable so that it can be accessed in the source
1418 function using macro astChannelData. */
1419 astStoreChannelData( this );
1420 LOCK_MUTEX3;
1421 line = ( *this->source_wrap )( this->source, status );
1422 UNLOCK_MUTEX3;
1423
1424 /* Input file defined, or no source function. */
1425 /* ------------------------------------------ */
1426 /* Read the line from the input file or from standard input. */
1427 } else if( astOK ) {
1428 c = '\0';
1429 len = 0;
1430 size = 0;
1431
1432 /* Choose the file descriptor to use. */
1433 fd = this->fd_in ? this->fd_in : stdin;
1434
1435 /* Loop to read input characters, saving any "errno" value that may be
1436 set by "getchar" if an error occurs. Quit if an end of file (or
1437 error) occurs or if a newline character is read. */
1438 while ( errno = 0, c = getc( fd ), readstat = errno,
1439 ( c != EOF ) && ( c != '\n' ) ) {
1440
1441 /* If no memory has yet been allocated to hold the line, allocate some
1442 now, using MIN_CHARS as the initial line length. */
1443 if ( !line ) {
1444 line = astMalloc( sizeof( char ) * (size_t) MIN_CHARS );
1445 size = MIN_CHARS;
1446
1447 /* If memory has previously been allocated, extend it when necessary
1448 to hold the new input character (plus a terminating null) and note
1449 the new size. */
1450 } else if ( ( len + 2 ) > size ) {
1451 line = astGrow( line, len + 2, sizeof( char ) );
1452 if ( !astOK ) break;
1453 size = (int) astSizeOf( line );
1454 }
1455
1456 /* Store the character just read. */
1457 line[ len++ ] = c;
1458 }
1459
1460 /* If the above loop completed without setting the global error
1461 status, check the last character read and use "ferror" to see if a
1462 read error occurred. If so, report the error, using the saved
1463 "errno" value (but only if one was set). */
1464 if ( astOK && ( c == EOF ) && ferror( fd ) ) {
1465 if ( readstat ) {
1466 #if HAVE_STRERROR_R
1467 strerror_r( readstat, errbuf, ERRBUF_LEN );
1468 errstat = errbuf;
1469 #else
1470 errstat = strerror( readstat );
1471 #endif
1472 astError( AST__RDERR,
1473 "astRead(%s): Read error on standard input - %s.", status,
1474 astGetClass( this ), errstat );
1475 } else {
1476 astError( AST__RDERR,
1477 "astRead(%s): Read error on standard input.", status,
1478 astGetClass( this ) );
1479 }
1480 }
1481
1482 /* If an empty line has been read, allocate memory to hold an empty
1483 string. */
1484 if ( !line && ( c == '\n' ) ) {
1485 line = astMalloc( sizeof( char ) );
1486 }
1487
1488 /* If memory has been allocated and there has been no error,
1489 null-terminate the string of input characters. */
1490 if ( line ) {
1491 if ( astOK ) {
1492 line[ len ] = '\0';
1493
1494 /* If there has been an error, free the allocated memory. */
1495 } else {
1496 line = astFree( line );
1497 }
1498 }
1499 }
1500
1501
1502 /* Return the result pointer. */
1503 return line;
1504
1505 /* Undefine macros local to this function. */
1506 #undef MIN_CHARS
1507 #undef ERRBUF_LEN
1508 }
1509
Warnings(AstChannel * this,int * status)1510 static AstKeyMap *Warnings( AstChannel *this, int *status ){
1511 /*
1512 *++
1513 * Name:
1514 c astWarnings
1515 f AST_WARNINGS
1516
1517 * Purpose:
1518 * Returns any warnings issued by the previous read or write operation.
1519
1520 * Type:
1521 * Public virtual function.
1522
1523 * Synopsis:
1524 c #include "channel.h"
1525 c AstKeyMap *astWarnings( AstChannel *this )
1526 f RESULT = AST_WARNINGS( THIS, STATUS )
1527
1528 * Class Membership:
1529 * Channel member function.
1530
1531 * Description:
1532 * This function returns an AST KeyMap object holding the text of any
1533 * warnings issued as a result of the previous invocation of the
1534 c astRead or astWrite
1535 f AST_READ or AST_WRITE
1536 * function on the Channel. If no warnings were issued, a
1537 c a NULL value
1538 f AST__NULL
1539 * will be returned.
1540 *
1541 * Such warnings are non-fatal and will not prevent the
1542 * read or write operation succeeding. However, the converted object
1543 * may not be identical to the original object in all respects.
1544 * Differences which would usually be deemed as insignificant in most
1545 * usual cases will generate a warning, whereas more significant
1546 * differences will generate an error.
1547 *
1548 * The "Strict" attribute allows this warning facility to be switched
1549 * off, so that a fatal error is always reported for any conversion
1550 * error.
1551
1552 * Parameters:
1553 c this
1554 f THIS = INTEGER (Given)
1555 * Pointer to the Channel.
1556 f STATUS = INTEGER (Given and Returned)
1557 f The global status.
1558
1559 * Returned Value:
1560 c astWarnings()
1561 f AST_WARNINGS = INTEGER
1562 * A pointer to the KeyMap holding the warning messages, or
1563 c NULL
1564 f AST__NULL
1565 * if no warnings were issued during the previous read operation.
1566
1567 * Applicability:
1568 * Channel
1569 * The basic Channel class generates a warning when ever an
1570 * un-recognised item is encountered whilst reading an Object from
1571 * an external data source. If Strict is zero (the default), then
1572 * unexpected items in the Object description are simply ignored,
1573 * and any remaining items are used to construct the returned
1574 * Object. If Strict is non-zero, an error will be reported and a
1575 * NULL Object pointer returned if any unexpected items are
1576 * encountered.
1577 *
1578 * As AST continues to be developed, new attributes are added
1579 * occasionally to selected classes. If an older version of AST is
1580 * used to read external Object descriptions created by a more
1581 * recent version of AST, then the Channel class will, by default,
1582 * ignore the new attributes, using the remaining attributes to
1583 * construct the Object. This is usually a good thing. However,
1584 * since external Object descriptions are often stored in plain
1585 * text, it is possible to edit them using a text editor. This
1586 * gives rise to the possibility of genuine errors in the
1587 * description due to finger-slips, typos, or simple
1588 * mis-understanding. Such inappropriate attributes will be ignored
1589 * if Strict is left at its default zero value. This will cause the
1590 * mis-spelled attribute to revert to its default value,
1591 * potentially causing subtle changes in the behaviour of
1592 * application software. If such an effect is suspected, the Strict
1593 * attribute can be set non-zero, resulting in the erroneous
1594 * attribute being identified in an error message.
1595 * FitsChan
1596 * The returned KeyMap will contain warnings for all conditions
1597 * listed in the Warnings attribute.
1598 * XmlChan
1599 * Reports conversion errors that result in what are usally
1600 * insignificant changes.
1601
1602 * Notes:
1603 * - The returned KeyMap uses keys of the form "Warning_1",
1604 * "Warning_2", etc.
1605 * - A value of
1606 c NULL will be returned if this function is invoked with the AST
1607 c error status set,
1608 f AST__NULL will be returned if this function is invoked with STATUS
1609 f set to an error value,
1610 * or if it should fail for any reason.
1611 *--
1612 */
1613
1614 /* Local Variables: */
1615 AstKeyMap *result;
1616 char key[ 20 ];
1617 int i;
1618
1619 /* Check the global status, and supplied keyword name. */
1620 result = NULL;
1621 if( !astOK ) return result;
1622
1623 /* Check there are some warnings to return. */
1624 if( this->nwarn && this->warnings ) {
1625
1626 /* Create the KeyMap. */
1627 result = astKeyMap( "", status );
1628
1629 /* Loop round all warnings, adding them into the KeyMap. */
1630 for( i = 0; i < this->nwarn; i++ ){
1631 sprintf( key, "Warning_%d", i + 1 );
1632 astMapPut0C( result, key, (this->warnings)[ i ], " " );
1633 }
1634 }
1635
1636 /* Return the KeyMap. */
1637 return result;
1638 }
1639
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)1640 AstChannel *astInitChannel_( void *mem, size_t size, int init,
1641 AstChannelVtab *vtab, const char *name,
1642 const char *(* source)( void ),
1643 char *(* source_wrap)( const char *(*)( void ), int * ),
1644 void (* sink)( const char * ),
1645 void (* sink_wrap)( void (*)( const char * ),
1646 const char *, int * ), int *status ) {
1647 /*
1648 *+
1649 * Name:
1650 * astInitChannel
1651
1652 * Purpose:
1653 * Initialise a Channel.
1654
1655 * Type:
1656 * Protected function.
1657
1658 * Synopsis:
1659 * #include "channel.h"
1660 * AstChannel *astInitChannel( void *mem, size_t size, int init,
1661 * AstChannelVtab *vtab, const char *name,
1662 * const char *(* source)( void ),
1663 * char *(* source_wrap)( const char *(*)( void ), int * ),
1664 * void (* sink)( const char * ),
1665 * void (* sink_wrap)( void (*)( const char * ),
1666 * const char *, int * ) )
1667
1668 * Class Membership:
1669 * Channel initialiser.
1670
1671 * Description:
1672 * This function is provided for use by class implementations to
1673 * initialise a new Channel object. It allocates memory (if
1674 * necessary) to accommodate the Channel plus any additional data
1675 * associated with the derived class. It then initialises a
1676 * Channel structure at the start of this memory. If the "init"
1677 * flag is set, it also initialises the contents of a virtual
1678 * function table for a Channel at the start of the memory passed
1679 * via the "vtab" parameter.
1680
1681 * Parameters:
1682 * mem
1683 * A pointer to the memory in which the Channel is to be
1684 * initialised. This must be of sufficient size to accommodate
1685 * the Channel data (sizeof(Channel)) plus any data used by the
1686 * derived class. If a value of NULL is given, this function
1687 * will allocate the memory itself using the "size" parameter to
1688 * determine its size.
1689 * size
1690 * The amount of memory used by the Channel (plus derived class
1691 * data). This will be used to allocate memory if a value of
1692 * NULL is given for the "mem" parameter. This value is also
1693 * stored in the Channel structure, so a valid value must be
1694 * supplied even if not required for allocating memory.
1695 * init
1696 * A boolean flag indicating if the Channel's virtual function
1697 * table is to be initialised. If this value is non-zero, the
1698 * virtual function table will be initialised by this function.
1699 * vtab
1700 * Pointer to the start of the virtual function table to be
1701 * associated with the new Channel.
1702 * name
1703 * Pointer to a constant null-terminated character string which
1704 * contains the name of the class to which the new object
1705 * belongs (it is this pointer value that will subsequently be
1706 * returned by the astGetClass method).
1707 * source
1708 * Pointer to a "source" function which will be used to obtain
1709 * lines of input text. Generally, this will be obtained by
1710 * casting a pointer to a source function which is compatible
1711 * with the "source_wrap" wrapper function (below). The pointer
1712 * should later be cast back to its original type by the
1713 * "source_wrap" function before the function is invoked.
1714 *
1715 * If "source" is NULL, the Channel will read from standard
1716 * input instead.
1717 * source_wrap
1718 * Pointer to a function which can be used to invoke the
1719 * "source" function supplied (above). This wrapper function is
1720 * necessary in order to hide variations in the nature of the
1721 * source function, such as may arise when it is supplied by a
1722 * foreign (non-C) language interface.
1723 *
1724 * The single parameter of the "source_wrap" function is a
1725 * pointer to the "source" function, and it should cast this
1726 * function pointer (as necessary) and invoke the function with
1727 * appropriate arguments to obtain the next line of input
1728 * text. The "source_wrap" function should then return a pointer
1729 * to a dynamically allocated, null terminated string containing
1730 * the text that was read. The string will be freed (using
1731 * astFree) when no longer required and the "source_wrap"
1732 * function need not concern itself with this. A NULL pointer
1733 * should be returned if there is no more input to read.
1734 *
1735 * If "source_wrap" is NULL, the Channel will read from standard
1736 * input instead.
1737 * sink
1738 * Pointer to a "sink" function which will be used to deliver
1739 * lines of output text. Generally, this will be obtained by
1740 * casting a pointer to a sink function which is compatible with
1741 * the "sink_wrap" wrapper function (below). The pointer should
1742 * later be cast back to its original type by the "sink_wrap"
1743 * function before the function is invoked.
1744 *
1745 * If "sink" is NULL, the Channel will write to standard output
1746 * instead.
1747 * sink_wrap
1748 * Pointer to a function which can be used to invoke the "sink"
1749 * function supplied (above). This wrapper function is necessary
1750 * in order to hide variations in the nature of the sink
1751 * function, such as may arise when it is supplied by a foreign
1752 * (non-C) language interface.
1753 *
1754 * The first parameter of the "sink_wrap" function is a pointer
1755 * to the "sink" function, and the second parameter is a pointer
1756 * to a const, null-terminated character string containing the
1757 * text to be written. The "sink_wrap" function should cast the
1758 * "sink" function pointer (as necessary) and invoke the
1759 * function with appropriate arguments to deliver the line of
1760 * output text. The "sink_wrap" function then returns void.
1761 *
1762 * If "sink_wrap" is NULL, the Channel will write to standard
1763 * output instead.
1764
1765 * Returned Value:
1766 * A pointer to the new Channel.
1767
1768 * Notes:
1769 * - A null pointer will be returned if this function is invoked
1770 * with the global error status set, or if it should fail for any
1771 * reason.
1772 *-
1773 */
1774
1775 /* Local Variables: */
1776 AstChannel *new; /* Pointer to new Channel */
1777
1778 /* Check the global status. */
1779 if ( !astOK ) return NULL;
1780
1781 /* If necessary, initialise the virtual function table. */
1782 if ( init ) astInitChannelVtab( vtab, name );
1783
1784 /* Initialise an Object structure (the parent class) as the first
1785 component within the Channel structure, allocating memory if
1786 necessary. */
1787 new = (AstChannel *) astInitObject( mem, size, 0,
1788 (AstObjectVtab *) vtab, name );
1789
1790 if ( astOK ) {
1791
1792 /* Initialise the Channel data. */
1793 /* ---------------------------- */
1794 /* Save the pointers to the source and sink functions and the wrapper
1795 functions that invoke them. */
1796 new->source = source;
1797 new->source_wrap = source_wrap;
1798 new->sink = sink;
1799 new->sink_wrap = sink_wrap;
1800
1801 /* Indicate no input or output files have been associated with the
1802 Channel. */
1803 new->fd_in = NULL;
1804 new->fn_in = NULL;
1805 new->fd_out = NULL;
1806 new->fn_out = NULL;
1807
1808 /* Set all attributes to their undefined values. */
1809 new->comment = -INT_MAX;
1810 new->full = -INT_MAX;
1811 new->indent = -INT_MAX;
1812 new->report_level = -INT_MAX;
1813 new->skip = -INT_MAX;
1814 new->strict = -INT_MAX;
1815 new->data = NULL;
1816 new->warnings = NULL;
1817 new->nwarn = 0;
1818
1819 /* If an error occurred, clean up by deleting the new object. */
1820 if ( !astOK ) new = astDelete( new );
1821 }
1822
1823 /* Return a pointer to the new object. */
1824 return new;
1825 }
1826
astInitChannelVtab_(AstChannelVtab * vtab,const char * name,int * status)1827 void astInitChannelVtab_( AstChannelVtab *vtab, const char *name, int *status ) {
1828 /*
1829 *+
1830 * Name:
1831 * astInitChannelVtab
1832
1833 * Purpose:
1834 * Initialise a virtual function table for a Channel.
1835
1836 * Type:
1837 * Protected function.
1838
1839 * Synopsis:
1840 * #include "channel.h"
1841 * void astInitChannelVtab( AstChannelVtab *vtab, const char *name )
1842
1843 * Class Membership:
1844 * Channel vtab initialiser.
1845
1846 * Description:
1847 * This function initialises the component of a virtual function
1848 * table which is used by the Channel class.
1849
1850 * Parameters:
1851 * vtab
1852 * Pointer to the virtual function table. The components used by
1853 * all ancestral classes will be initialised if they have not already
1854 * been initialised.
1855 * name
1856 * Pointer to a constant null-terminated character string which contains
1857 * the name of the class to which the virtual function table belongs (it
1858 * is this pointer value that will subsequently be returned by the Object
1859 * astClass function).
1860 *-
1861 */
1862
1863 /* Local Variables: */
1864 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
1865 AstObjectVtab *object; /* Pointer to Object component of Vtab */
1866
1867 /* Check the local error status. */
1868 if ( !astOK ) return;
1869
1870 /* Get a pointer to the thread specific global data structure. */
1871 astGET_GLOBALS(NULL);
1872
1873 /* Initialize the component of the virtual function table used by the
1874 parent class. */
1875 astInitObjectVtab( (AstObjectVtab *) vtab, name );
1876
1877 /* Store a unique "magic" value in the virtual function table. This
1878 will be used (by astIsAChannel) to determine if an object belongs
1879 to this class. We can conveniently use the address of the (static)
1880 class_check variable to generate this unique value. */
1881 vtab->id.check = &class_check;
1882 vtab->id.parent = &(((AstObjectVtab *) vtab)->id);
1883
1884 /* Initialise member function pointers. */
1885 /* ------------------------------------ */
1886 /* Store pointers to the member functions (implemented here) that
1887 provide virtual methods for this class. */
1888 vtab->AddWarning = AddWarning;
1889 vtab->ClearComment = ClearComment;
1890 vtab->ClearFull = ClearFull;
1891 vtab->ClearSkip = ClearSkip;
1892 vtab->ClearStrict = ClearStrict;
1893 vtab->GetComment = GetComment;
1894 vtab->GetFull = GetFull;
1895 vtab->GetNextData = GetNextData;
1896 vtab->GetNextText = GetNextText;
1897 vtab->GetSkip = GetSkip;
1898 vtab->GetStrict = GetStrict;
1899 vtab->Warnings = Warnings;
1900 vtab->PutNextText = PutNextText;
1901 vtab->Read = Read;
1902 vtab->ReadClassData = ReadClassData;
1903 vtab->ReadDouble = ReadDouble;
1904 vtab->ReadInt = ReadInt;
1905 vtab->ReadObject = ReadObject;
1906 vtab->ReadString = ReadString;
1907 vtab->SetComment = SetComment;
1908 vtab->SetFull = SetFull;
1909 vtab->SetSkip = SetSkip;
1910 vtab->SetStrict = SetStrict;
1911 vtab->TestComment = TestComment;
1912 vtab->TestFull = TestFull;
1913 vtab->TestSkip = TestSkip;
1914 vtab->TestStrict = TestStrict;
1915 vtab->Write = Write;
1916 vtab->WriteBegin = WriteBegin;
1917 vtab->WriteDouble = WriteDouble;
1918 vtab->WriteEnd = WriteEnd;
1919 vtab->WriteInt = WriteInt;
1920 vtab->WriteIsA = WriteIsA;
1921 vtab->WriteObject = WriteObject;
1922 vtab->WriteString = WriteString;
1923 vtab->PutChannelData = PutChannelData;
1924
1925 vtab->ClearReportLevel = ClearReportLevel;
1926 vtab->GetReportLevel = GetReportLevel;
1927 vtab->SetReportLevel = SetReportLevel;
1928 vtab->TestReportLevel = TestReportLevel;
1929
1930 vtab->ClearIndent = ClearIndent;
1931 vtab->GetIndent = GetIndent;
1932 vtab->SetIndent = SetIndent;
1933 vtab->TestIndent = TestIndent;
1934
1935 vtab->ClearSourceFile = ClearSourceFile;
1936 vtab->GetSourceFile = GetSourceFile;
1937 vtab->SetSourceFile = SetSourceFile;
1938 vtab->TestSourceFile = TestSourceFile;
1939
1940 vtab->ClearSinkFile = ClearSinkFile;
1941 vtab->GetSinkFile = GetSinkFile;
1942 vtab->SetSinkFile = SetSinkFile;
1943 vtab->TestSinkFile = TestSinkFile;
1944
1945 /* Save the inherited pointers to methods that will be extended, and
1946 replace them with pointers to the new member functions. */
1947 object = (AstObjectVtab *) vtab;
1948
1949 parent_clearattrib = object->ClearAttrib;
1950 object->ClearAttrib = ClearAttrib;
1951 parent_getattrib = object->GetAttrib;
1952 object->GetAttrib = GetAttrib;
1953 parent_setattrib = object->SetAttrib;
1954 object->SetAttrib = SetAttrib;
1955 parent_testattrib = object->TestAttrib;
1956 object->TestAttrib = TestAttrib;
1957
1958 /* Declare the destructor and copy constructor. */
1959 astSetDelete( (AstObjectVtab *) vtab, Delete );
1960 astSetCopy( (AstObjectVtab *) vtab, Copy );
1961
1962 /* Declare the Dump function for this class. There is no destructor or
1963 copy constructor. */
1964 astSetDump( vtab, Dump, "Channel", "Basic I/O Channel" );
1965
1966 /* If we have just initialised the vtab for the current class, indicate
1967 that the vtab is now initialised, and store a pointer to the class
1968 identifier in the base "object" level of the vtab. */
1969 if( vtab == &class_vtab ) {
1970 class_init = 1;
1971 astSetVtabClassIdentifier( vtab, &(vtab->id) );
1972 }
1973 }
1974
InputTextItem(AstChannel * this,int * status)1975 static char *InputTextItem( AstChannel *this, int *status ) {
1976 /*
1977 * Name:
1978 * InputTextItem
1979
1980 * Purpose:
1981 * Read the next item from a data source as text.
1982
1983 * Type:
1984 * Private function.
1985
1986 * Synopsis:
1987 * #include "channel.h"
1988 * char *InputTextItem( AstChannel *this )
1989
1990 * Class Membership:
1991 * Channel member function.
1992
1993 * Description:
1994 * This function reads the next input data item as text from the
1995 * data source associated with a Channel. It is similar to the
1996 * astGetNextText method (which it invokes), except that it strips
1997 * off any comments along with leading and trailing white
1998 * space. Input lines which are empty or do not contain significant
1999 * characters (e.g. all comment) are skipped, so that only
2000 * significant lines are returned.
2001 *
2002 * Each line is returned as a pointer to a null-terminated string
2003 * held in dynamic memory, and it is the caller's responsibility to
2004 * free this memory (using astFree) when it is no longer
2005 * required. A NULL pointer is returned if there are no more input
2006 * lines to be read.
2007
2008 * Parameters:
2009 * this
2010 * Pointer to the Channel.
2011
2012 * Returned Value:
2013 * Pointer to a null-terminated string containing the input line
2014 * (held in dynamically allocated memory, which must be freed by
2015 * the caller when no longer required). A NULL pointer is returned
2016 * if there are no more input lines to be read.
2017
2018 * Notes:
2019 * - A NULL pointer will be returned if this function is invoked
2020 * with the global error status set, or if it should fail for any
2021 * reason.
2022 */
2023
2024 /* Local Variables: */
2025 char *line; /* Pointer to line data to be returned */
2026 int i; /* Loop counter for line characters */
2027 int j; /* Counter for characters */
2028 int len; /* Length of result line */
2029 int nonspace; /* Non-space character encountered? */
2030 int quoted; /* Character is inside quotes? */
2031
2032 /* Initialise. */
2033 line = NULL;
2034
2035 /* Check the global error status. */
2036 if ( !astOK ) return line;
2037
2038 /* Loop to read input lines until one is found which contains useful
2039 characters or end of file is reached (or a read error occurs). */
2040 while ( !line && ( line = astGetNextText( this ) ) && astOK ) {
2041
2042 /* Loop to remove comments and leading and trailing white space. */
2043 len = 0;
2044 nonspace = 0;
2045 quoted = 0;
2046 for ( i = j = 0; line[ i ]; i++ ) {
2047
2048 /* Note quote characters and ignore all text after the first unquoted
2049 comment character. */
2050 if ( line[ i ] == '"' ) quoted = !quoted;
2051 if ( ( line[ i ] == '#' ) && !quoted ) break;
2052
2053 /* Note the first non-space character and ignore everything before
2054 it. */
2055 if ( ( nonspace = nonspace || !isspace( line[ i ] ) ) ) {
2056
2057 /* Move each character to its new position in the string. */
2058 line[ j++ ] = line[ i ];
2059
2060 /* Note the final length of the string (ignoring trailing spaces). */
2061 if ( !isspace( line[ i ] ) ) len = j;
2062 }
2063 }
2064
2065 /* If the string is not empty, terminate it. */
2066 if ( len ) {
2067 line[ len ] = '\0';
2068
2069 /* Otherwise, free the memory used for the string so that another
2070 input line will be read. */
2071 } else {
2072 line = astFree( line );
2073 }
2074 }
2075
2076 /* Return the result pointer. */
2077 return line;
2078
2079 /* Undefine macros local to this function. */
2080 #undef MIN_CHARS
2081 }
2082
LookupValue(const char * name,int * status)2083 static AstChannelValue *LookupValue( const char *name, int *status ) {
2084 /*
2085 * Name:
2086 * LookupValue
2087
2088 * Purpose:
2089 * Look up a Value structure by name.
2090
2091 * Type:
2092 * Private function.
2093
2094 * Synopsis:
2095 * #include "channel.h"
2096 * AstChannelValue *LookupValue( const char *name )
2097
2098 * Class Membership:
2099 * Channel member function.
2100
2101 * Description:
2102 * This function searches the current values list (i.e. at the
2103 * current nesting level) to identify a Value structure with a
2104 * specified name. If one is found, it is removed from the list and
2105 * a pointer to it is returned. If no suitable Value can be found,
2106 * a NULL pointer is returned instead.
2107
2108 * Parameters:
2109 * name
2110 * Pointer to a constant null-terminated character string
2111 * containing the name of the required Value. This must be in
2112 * lower case with no surrounding white space. Note that names
2113 * longer than NAME_MAX characters will not match any Value.
2114
2115 * Returned value:
2116 * Pointer to the required Value structure, or NULL if no suitable
2117 * Value exists.
2118
2119 * Notes:
2120 * - The returned pointer refers to a dynamically allocated
2121 * structure and it is the callers responsibility to free this when
2122 * no longer required. The FreeValue function must be used for this
2123 * purpose.
2124 * - A NULL pointer will be returned if this function is invoked
2125 * with the global error status set, or if it should fail for any
2126 * reason.
2127 */
2128
2129 /* Local Variables: */
2130 astDECLARE_GLOBALS /* Declare the thread specific global data */
2131 AstChannelValue **head; /* Address of head of list pointer */
2132 AstChannelValue *result; /* Pointer value to return */
2133 AstChannelValue *value; /* Pointer to list element */
2134
2135 /* Initialise. */
2136 result = NULL;
2137
2138 /* Check the global error status. */
2139 if ( !astOK ) return result;
2140
2141 /* Get a pointer to the structure holding thread-specific global data. */
2142 astGET_GLOBALS(NULL);
2143
2144 /* Check that the "values_ok" flag is set. If not, the Values in the
2145 values list belong to a different class to that of the current
2146 class loader, so we cannot return any Value. */
2147 if ( values_ok[ nest ] ) {
2148
2149 /* Obtain the address of the current "head of list" pointer for the
2150 values list (at the current nesting level). */
2151 head = values_list + nest;
2152
2153 /* Obtain the head of list pointer itself and check the list is not
2154 empty. */
2155 if ( ( value = *head ) ) {
2156
2157 /* Loop to inspect each list element. */
2158 while ( 1 ) {
2159
2160 /* If a name match is found, remove the element from the list, return
2161 a pointer to it and quit searching. */
2162 if ( !strcmp( name, value->name ) ) {
2163 RemoveValue( value, head, status );
2164 result = value;
2165 break;
2166 }
2167
2168 /* Follow the list until we return to the head. */
2169 value = value->flink;
2170 if ( value == *head ) break;
2171 }
2172 }
2173 }
2174
2175 /* Return the result. */
2176 return result;
2177 }
2178
OutputTextItem(AstChannel * this,const char * line,int * status)2179 static void OutputTextItem( AstChannel *this, const char *line, int *status ) {
2180 /*
2181 * Name:
2182 * OutputTextItem
2183
2184 * Purpose:
2185 * Output a data item formatted as text.
2186
2187 * Type:
2188 * Private function.
2189
2190 * Synopsis:
2191 * #include "channel.h"
2192 * void OutputTextItem( AstChannel *this, const char *line, int *status )
2193
2194 * Class Membership:
2195 * Channel member function.
2196
2197 * Description:
2198 * This function outputs a data item formatted as a text string to
2199 * a data sink associated with a Channel. It keeps track of the
2200 * number of items written.
2201
2202 * Parameters:
2203 * this
2204 * Pointer to the Channel.
2205 * line
2206 * Pointer to a constant null-terminated string containing the
2207 * data item to be output (no newline character should be
2208 * appended).
2209 * status
2210 * Pointer to the inherited status variable.
2211 */
2212
2213 /* Local Variables: */
2214 astDECLARE_GLOBALS /* Declare the thread specific global data */
2215
2216 /* Check the global error status. */
2217 if ( !astOK ) return;
2218
2219 /* Get a pointer to the structure holding thread-specific global data. */
2220 astGET_GLOBALS(this);
2221
2222 /* Write out the line of text using the astPutNextText method (which
2223 may be over-ridden). */
2224 astPutNextText( this, line );
2225
2226 /* If successful, increment the count of items written. */
2227 if ( astOK ) items_written++;
2228 }
2229
PutChannelData(AstChannel * this,void * data,int * status)2230 static void PutChannelData( AstChannel *this, void *data, int *status ) {
2231 /*
2232 c++
2233 * Name:
2234 * astPutChannelData
2235
2236 * Purpose:
2237 * Store arbitrary data to be passed to a source or sink function.
2238
2239 * Type:
2240 * Public function.
2241
2242 * Synopsis:
2243 * #include "channel.h"
2244 * void astPutChannelData( AstChannel *this, void *data )
2245
2246 * Class Membership:
2247 * Channel method.
2248
2249 * Description:
2250 * This function stores a supplied arbitrary pointer in the Channel.
2251 * When a source or sink function is invoked by the Channel, the
2252 * invoked function can use the astChannelData macro to retrieve the
2253 * pointer. This provides a thread-safe alternative to passing file
2254 * descriptors, etc, via global static variables.
2255
2256 * Parameters:
2257 * this
2258 * Pointer to the Channel.
2259 * data
2260 * A pointer to be made available to the source and sink functions
2261 * via the astChannelData macro. May be NULL.
2262
2263 * Applicability:
2264 * Channel
2265 * All Channels have this function.
2266
2267 * Notes:
2268 * - This routine is not available in the Fortran 77 interface to
2269 * the AST library.
2270 c--
2271 */
2272
2273 /* Check the global error status. */
2274 if ( !astOK ) return;
2275
2276 /* Store the pointer. */
2277 this->data = data;
2278 }
2279
PutNextText(AstChannel * this,const char * line,int * status)2280 static void PutNextText( AstChannel *this, const char *line, int *status ) {
2281 /*
2282 *+
2283 * Name:
2284 * astPutNextText
2285
2286 * Purpose:
2287 * Write a line of output text to a data sink.
2288
2289 * Type:
2290 * Protected virtual function.
2291
2292 * Synopsis:
2293 * #include "channel.h"
2294 * void astPutNextText( AstChannel *this, const char *line )
2295
2296 * Class Membership:
2297 * Channel method.
2298
2299 * Description:
2300 * This function writes an output line of text to a data sink
2301 * associated with a Channel.
2302
2303 * Parameters:
2304 * this
2305 * Pointer to the Channel.
2306 * line
2307 * Pointer to a constant null-terminated string containing the
2308 * line of output text to be written (no newline character
2309 * should be appended).
2310
2311 * Notes:
2312 * - This method is provided primarily so that derived classes may
2313 * over-ride it in order to write to alternative (textual) data
2314 * sinks.
2315 *-
2316 */
2317
2318 /* Local Constants: */
2319 #define ERRBUF_LEN 80
2320
2321 /* Local Variables: */
2322 char *errstat; /* Pointer for system error message */
2323 char errbuf[ ERRBUF_LEN ]; /* Buffer for system error message */
2324 const char *sink_file; /* Path to output sink file */
2325 const char *source_file; /* Path to output source file */
2326
2327 /* Check the global error status. */
2328 if ( !astOK ) return;
2329
2330 /* If the SinkFile attribute of the Channel specifies an output file,
2331 but no output file has yet been opened, open it now. Report an error
2332 if it is the same as the source file. */
2333 if( astTestSinkFile( this ) && !this->fd_out ) {
2334 sink_file = astGetSinkFile( this );
2335
2336 if( this->fd_out ) {
2337 source_file = astGetSourceFile( this );
2338 if( astOK && !strcmp( sink_file, source_file ) ) {
2339 astError( AST__WRERR, "astWrite(%s): Failed to open output "
2340 "SinkFile '%s' - the file is currently being used "
2341 "as the input SourceFile.", status, astGetClass( this ),
2342 sink_file );
2343 }
2344 }
2345
2346 if( astOK ) {
2347 this->fd_out = fopen( sink_file, "w" );
2348 if( !this->fd_out ) {
2349 if ( errno ) {
2350 #if HAVE_STRERROR_R
2351 strerror_r( errno, errbuf, ERRBUF_LEN );
2352 errstat = errbuf;
2353 #else
2354 errstat = strerror( errno );
2355 #endif
2356 astError( AST__WRERR, "astWrite(%s): Failed to open output "
2357 "SinkFile '%s' - %s.", status, astGetClass( this ),
2358 sink_file, errstat );
2359 } else {
2360 astError( AST__WRERR, "astWrite(%s): Failed to open output "
2361 "SinkFile '%s'.", status, astGetClass( this ),
2362 sink_file );
2363 }
2364 }
2365 }
2366 }
2367
2368 /* Check no error occurred above. */
2369 if( astOK ) {
2370
2371 /* If an active output file descriptor is stored in the channel, write
2372 the text to it, with a newline appended. */
2373 if( this->fd_out ) {
2374 (void) fprintf( this->fd_out, "%s\n", line );
2375
2376 /* Otherwise, if a sink function (and its wrapper function) is defined for
2377 the Channel, use the wrapper function to invoke the sink function to
2378 output the text line. Since we are about to call an externally supplied
2379 function which may not be thread-safe, lock a mutex first. Also store
2380 the channel data pointer in a global variable so that it can be accessed
2381 in the source function using macro astChannelData. */
2382 } else if ( this->sink && this->sink_wrap ) {
2383 astStoreChannelData( this );
2384 LOCK_MUTEX2;
2385 ( *this->sink_wrap )( *this->sink, line, status );
2386 UNLOCK_MUTEX2;
2387
2388 /* Otherwise, simply write the text to standard output with a newline
2389 appended. */
2390 } else {
2391 (void) printf( "%s\n", line );
2392 }
2393 }
2394 }
2395
Read(AstChannel * this,int * status)2396 static AstObject *Read( AstChannel *this, int *status ) {
2397 /*
2398 *++
2399 * Name:
2400 c astRead
2401 f AST_READ
2402
2403 * Purpose:
2404 * Read an Object from a Channel.
2405
2406 * Type:
2407 * Public function.
2408
2409 * Synopsis:
2410 c #include "channel.h"
2411 c AstObject *astRead( AstChannel *this )
2412 f RESULT = AST_READ( THIS, STATUS )
2413
2414 * Class Membership:
2415 * Channel method.
2416
2417 * Description:
2418 * This function reads the next Object from a Channel and returns a
2419 * pointer to the new Object.
2420
2421 * Parameters:
2422 c this
2423 f THIS = INTEGER (Given)
2424 * Pointer to the Channel.
2425 f STATUS = INTEGER (Given and Returned)
2426 f The global status.
2427
2428 * Returned Value:
2429 c astRead()
2430 f AST_READ = INTEGER
2431 * A pointer to the new Object. The class to which this will
2432 * belong is determined by the input data, so is not known in
2433 * advance.
2434
2435 * Applicability:
2436 * FitsChan
2437 c All successful use of astRead on a FitsChan is destructive, so that
2438 f All successful use of AST_READ on a FitsChan is destructive, so that
2439 * FITS header cards are consumed in the process of reading an Object,
2440 * and are removed from the FitsChan (this deletion can be prevented
2441 * for specific cards by calling the FitsChan
2442 c astRetainFits function).
2443 f AST_RETAINFITS routine).
2444 * An unsuccessful call of
2445 c astRead
2446 f AST_READ
2447 * (for instance, caused by the FitsChan not containing the necessary
2448 * FITS headers cards needed to create an Object) results in the
2449 * contents of the FitsChan being left unchanged.
2450 * StcsChan
2451 * The AST Object returned by a successful use of
2452 c astRead
2453 f AST_READ
2454 * on an StcsChan, will be either a Region or a KeyMap, depending
2455 * on the values of the StcsArea, StcsCoords and StcsProps
2456 * attributes. See the documentation for these attributes for further
2457 * information.
2458
2459 * Notes:
2460 * - A null Object pointer (AST__NULL) will be returned, without
2461 * error, if the Channel contains no further Objects to be read.
2462 * - A null Object pointer will also be returned if this function
2463 c is invoked with the AST error status set, or if it should fail
2464 f is invoked with STATUS set to an error value, or if it should fail
2465 * for any reason.
2466 *--
2467 */
2468
2469 /* Local Variables: */
2470 astDECLARE_GLOBALS /* Declare the thread specific global data */
2471 AstLoaderType *loader; /* Pointer to loader for Object */
2472 AstObject *new; /* Pointer to new Object */
2473 char *class; /* Pointer to Object class name string */
2474 char *name; /* Pointer to data item name */
2475 int skip; /* Skip non-AST data? */
2476 int top; /* Reading top-level Object definition? */
2477
2478 /* Initialise. */
2479 new = NULL;
2480
2481 /* Check the global error status. */
2482 if ( !astOK ) return new;
2483
2484 /* Get a pointer to the structure holding thread-specific global data. */
2485 astGET_GLOBALS(this);
2486
2487 /* Determine if we are reading a top-level (i.e. user-level) Object
2488 definition, as opposed to the definition of an Object contained
2489 within another Object. This is indicated by the current nesting
2490 level. */
2491 top = ( nest == -1 );
2492
2493 /* If reading a top-level object, determine if data lying in between
2494 Object definitions in the input data stream are to be skipped. */
2495 skip = ( top && astGetSkip( this ) );
2496
2497 /* Read the next input data item. If we are reading a top-level Object
2498 definition, skip any unrelated data beforehand. Otherwise read the
2499 data strictly as it comes (there should be no unrelated data
2500 embedded within Object definitions themselves). */
2501 astGetNextData( this, skip, &name, &class );
2502
2503 /* If no suitable data item was found (and no error occurred), we have
2504 reached the end of data. For a top-level Object a NULL Object
2505 pointer is simply returned, but for a nested Object this indicates
2506 that part of the Object definition is missing, so report an
2507 error. */
2508 if ( astOK ) {
2509 if ( !name ) {
2510 if ( !top ) {
2511 astError( AST__EOCHN,
2512 "astRead(%s): End of input encountered while trying to "
2513 "read an AST Object.", status, astGetClass( this ) );
2514 }
2515
2516 /* If a data item was found, check it is a "Begin" item. If not, there
2517 is a data item missing, so report an error and free all memory. */
2518 } else if ( strcmp( name, "begin" ) ) {
2519 astError( AST__BADIN,
2520 "astRead(%s): Missing \"Begin\" when expecting an Object.", status,
2521 astGetClass( this ) );
2522 name = astFree( name );
2523 if ( class ) class = astFree( class );
2524
2525 /* If the required "Begin" item was found, free the memory used for the
2526 name string. */
2527 } else {
2528 name = astFree( name );
2529
2530 /* Use the associated class name to locate the loader for that
2531 class. This function will then be used to build the Object. */
2532 loader = astGetLoader( class, status );
2533
2534 /* Extend all necessary stack arrays to accommodate entries for the
2535 next nesting level (this allocates space if none has yet been
2536 allocated). */
2537 end_of_object = astGrow( end_of_object, nest + 2, sizeof( int ) );
2538 object_class = astGrow( object_class, nest + 2, sizeof( char * ) );
2539 values_class = astGrow( values_class, nest + 2, sizeof( char * ) );
2540 values_list = astGrow( values_list, nest + 2, sizeof( AstChannelValue * ) );
2541 values_ok = astGrow( values_ok, nest + 2, sizeof( int ) );
2542
2543 /* If an error occurred, free the memory used by the class string,
2544 which will not now be used. */
2545 if ( !astOK ) {
2546 class = astFree( class );
2547
2548 /* Otherwise, increment the nesting level and initialise the new stack
2549 elements for this new level. This includes clearing the
2550 "end_of_object" flag so that ReadClassData can read more data, and
2551 storing the class name of the object we are about to read. */
2552 } else {
2553 nest++;
2554 end_of_object[ nest ] = 0;
2555 object_class[ nest ] = class;
2556 values_class[ nest ] = NULL;
2557 values_list[ nest ] = NULL;
2558 values_ok[ nest ] = 0;
2559
2560 /* Invoke the loader, which reads the Object definition from the input
2561 data stream and builds the Object. Supply NULL/zero values to the
2562 loader so that it will substitute values appropriate to its own
2563 class. */
2564 new = (*loader)( NULL, (size_t) 0, NULL, NULL, this, status );
2565
2566 /* Clear the values list for the current nesting level. If the list
2567 has not been read or any Values remain in it, an error will
2568 result. */
2569 ClearValues( this, status );
2570
2571 /* If no error has yet occurred, check that the "end_of_object" flag
2572 has been set. If not, the input data were not correctly terminated,
2573 so report an error. */
2574 if ( astOK && !end_of_object[ nest ] ) {
2575 astError( AST__BADIN,
2576 "astRead(%s): Unexpected end of input (missing end "
2577 "of %s).", status,
2578 astGetClass( this ), object_class[ nest ] );
2579 }
2580
2581 /* If an error occurred, report contextual information. Only do this
2582 for top-level Objects to avoid multple messages. */
2583 if ( !astOK && top ) {
2584 astError( astStatus, "Error while reading a %s from a %s.", status,
2585 class, astGetClass( this ) );
2586 }
2587
2588 /* Clear the Object's class string, freeing the associated memory
2589 (note this is the memory allocated for the "class" string
2590 earlier). */
2591 object_class[ nest ] = astFree( object_class[ nest ] );
2592
2593 /* Restore the previous nesting level. */
2594 nest--;
2595 }
2596
2597 /* Once the top-level Object has been built, free the memory used by
2598 the stack arrays. */
2599 if ( top ) {
2600 end_of_object = astFree( end_of_object );
2601 object_class = astFree( object_class );
2602 values_class = astFree( values_class );
2603 values_list = astFree( values_list );
2604 values_ok = astFree( values_ok );
2605 }
2606 }
2607 }
2608
2609 /* If an error occurred, clean up by deleting the new Object and
2610 return a NULL pointer. */
2611 if ( !astOK ) new = astDelete( new );
2612
2613 /* Return the pointer to the new Object. */
2614 return new;
2615 }
2616
ReadClassData(AstChannel * this,const char * class,int * status)2617 static void ReadClassData( AstChannel *this, const char *class, int *status ) {
2618 /*
2619 *+
2620 * Name:
2621 * astReadClassData
2622
2623 * Purpose:
2624 * Read values from a data source for a class loader.
2625
2626 * Type:
2627 * Protected virtual function.
2628
2629 * Synopsis:
2630 * #include "channel.h"
2631 * void astReadClassData( AstChannel *this, const char *class )
2632
2633 * Class Membership:
2634 * Channel method.
2635
2636 * Description:
2637 * This function reads the data for a class from the data source
2638 * associated with a Channel, so as to provide values for
2639 * initialising the instance variables of that class as part of
2640 * building a complete Object. This function should be invoked by
2641 * the loader for each class immediately before it attempts to read
2642 * these values.
2643 *
2644 * The values read are placed into the current values list by this
2645 * function. They may then be read from this list by the class
2646 * loader making calls to astReadDouble, astReadInt, astReadObject
2647 * and astReadString. The order in which values are read by the
2648 * loader is unimportant (although using the same order for reading
2649 * as for writing will usually be more efficient) and values are
2650 * removed from the list as they are read.
2651
2652 * Parameters:
2653 * this
2654 * Pointer to the Channel.
2655 * class
2656 * A pointer to a constant null-terminated string containing the
2657 * name of the class whose loader is requesting the data (note
2658 * this is not usually the same as the class name of the Object
2659 * being built). This value allows the class structure of the
2660 * input data to be validated.
2661 *-
2662 */
2663
2664 /* Local Variables: */
2665 astDECLARE_GLOBALS /* Declare the thread specific global data */
2666 AstObject *object; /* Pointer to new Object */
2667 AstChannelValue *value; /* Pointer to Value structure */
2668 char *name; /* Pointer to data item name string */
2669 char *val; /* Pointer to data item value string */
2670 int done; /* All class data read? */
2671
2672 /* Check the global error status. */
2673 if ( !astOK ) return;
2674
2675 /* Get a pointer to the structure holding thread-specific global data. */
2676 astGET_GLOBALS(this);
2677
2678 /* If the "values_ok" flag is set, this indicates that the values list
2679 (at the current nesting level) has been filled by a previous
2680 invocation of this function and has then been read by the
2681 appropriate class loader. In this case, clear any entries which may
2682 remain in the current values list. If any such entries are found,
2683 they represent input data that were not read, so an error will
2684 result. */
2685 if ( values_ok[ nest ] ) ClearValues( this, status );
2686
2687 /* If "values_class" is non-NULL, this indicates that the values list
2688 (at the current nesting level) has been filled by a previous
2689 invocation of this function, but that the values belong to a class
2690 whose loader has not yet tried to read them. In this case, we must
2691 continue to keep the values until they are needed, so we do not
2692 read any more input data this time. */
2693 if ( values_class[ nest ] ) {
2694
2695 /* If the class to which the previously saved values belong matches
2696 the class we now want values for, set the "values_ok" flag. This
2697 then allows the values to be accessed (by LookupValue). */
2698 values_ok[ nest ] = !strcmp( values_class[ nest ], class );
2699
2700 /* If the current values list is empty, we must read in values for the
2701 next class that appears in the input data. However, first check
2702 that the "end_of_object" flag has not been set. If it has, we have
2703 already reached the end of this Object's data, so there is some
2704 kind of problem with the order in which class loaders have been
2705 invoked. This will probably never happen, but report an error if
2706 necessary. */
2707 } else if ( end_of_object[ nest ] ) {
2708 astError( AST__LDERR,
2709 "astRead(%s): Invalid attempt to read further %s data "
2710 "following an end of %s.", status,
2711 astGetClass( this ), class, object_class[ nest ] );
2712 astError( AST__LDERR,
2713 "Perhaps the wrong class loader has been invoked?" , status);
2714
2715 /* If we need new values, loop to read input data items until the end
2716 of the data for a class is reached. */
2717 } else {
2718 done = 0;
2719 while ( astOK && !done ) {
2720
2721 /* Read the next input data item. */
2722 astGetNextData( this, 0, &name, &val );
2723 if ( astOK ) {
2724
2725 /* Unexpected end of input. */
2726 /* ------------------------ */
2727 /* If no "name" value is returned, we have reached the end of the
2728 input data stream without finding the required end of class
2729 terminator, so report an error. */
2730 if ( !name ) {
2731 astError( AST__EOCHN,
2732 "astRead(%s): Unexpected end of input (missing end "
2733 "of %s).", status,
2734 astGetClass( this ), object_class[ nest ] );
2735
2736 /* "IsA" item. */
2737 /* ----------- */
2738 /* Otherwise, if an "IsA" item was read, it indicates the end of the
2739 data for a class. Store the pointer to the name of this class in
2740 "values_class" and note whether this is the class whose data we
2741 wanted in "values_ok". If the data we have read do not belong to
2742 the class we wanted, they will simply be kept until the right class
2743 comes looking for them. */
2744 } else if ( !strcmp( name, "isa" ) ) {
2745 values_class[ nest ] = val;
2746 values_ok[ nest ] = !strcmp( val, class );
2747
2748 /* Free the memory holding the name string. */
2749 name = astFree( name );
2750
2751 /* Note we have finished reading class data. */
2752 done = 1;
2753
2754 /* "End" item. */
2755 /* ----------- */
2756 /* If an "End" item was read, it indicates the end of the data both
2757 for a class and for the current Object definition as a whole. Set
2758 the "end_of_object" flag (for the current nesting level) which
2759 prevents any further data being read for this Object. This flag is
2760 also used (by Read) to check that an "End" item was actually
2761 read. */
2762 } else if ( !strcmp( name, "end" ) ) {
2763 end_of_object[ nest ] = 1;
2764
2765 /* Check that the class name in the "End" item matches that of the
2766 Object being built. If so, store the pointer to the name of this
2767 class in "values_class" and note whether this is the class whose
2768 data we wanted in "values_ok". If the data we have read do not
2769 belong to the class we wanted, they will simply be kept until the
2770 right class comes looking for them. */
2771 if ( !strcmp( val, object_class[ nest ] ) ) {
2772 values_class[ nest ] = val;
2773 values_ok[ nest ] = !strcmp( class, val );
2774
2775 /* If the "End" item contains the wrong class name (i.e. not matching
2776 the corresponding "Begin" item), then report an error. */
2777 } else {
2778 astError( AST__BADIN,
2779 "astRead(%s): Bad class structure in input data.", status,
2780 astGetClass( this ) );
2781 astError( AST__BADIN,
2782 "End of %s read when expecting end of %s.", status,
2783 val, object_class[ nest ] );
2784
2785 /* Free the memory used by the class string, which will not now be
2786 used. */
2787 val = astFree( val );
2788 }
2789
2790 /* Free the memory holding the name string. */
2791 name = astFree( name );
2792
2793 /* Note we have finished reading class data. */
2794 done = 1;
2795
2796 /* String value. */
2797 /* ------------- */
2798 /* If any other name is obtained and "val" is not NULL, we have read a
2799 non-Object value, encoded as a string. Allocate memory for a Value
2800 structure to describe it. */
2801 } else if ( val ) {
2802 value = astMalloc( sizeof( AstChannelValue ) );
2803 if ( astOK ) {
2804
2805 /* Store pointers to the name and value string in the Value structure
2806 and note this is not an Object value. */
2807 value->name = name;
2808 value->ptr.string = val;
2809 value->is_object = 0;
2810
2811 /* Append the Value structure to the values list for the current
2812 nesting level. */
2813 AppendValue( value, values_list + nest, status );
2814
2815 /* If an error occurred, free the memory holding the "name" and "val"
2816 strings. */
2817 } else {
2818 name = astFree( name );
2819 val = astFree( val );
2820 }
2821
2822 /* Object value. */
2823 /* ------------- */
2824 /* If "val" is NULL, we have read an Object item, and the Object
2825 definition should follow. Allocate memory for a Value structure to
2826 describe it. */
2827 } else {
2828 value = astMalloc( sizeof( AstChannelValue ) );
2829
2830 /* Invoke astRead to read the Object definition from subsequent data
2831 items and to build the Object, returning a pointer to it. This will
2832 result in recursive calls to the current function, but as these
2833 will use higher nesting levels they will not interfere with the
2834 current invocation. */
2835 astreadclassdata_msg = 0;
2836 object = astRead( this );
2837 if ( astOK ) {
2838
2839 /* Store pointers to the name and Object in the Value structure and
2840 note this is an Object value. */
2841 value->name = name;
2842 value->ptr.object = object;
2843 value->is_object = 1;
2844
2845 /* Append the Value structure to the values list for the current
2846 nesting level. */
2847 AppendValue( value, values_list + nest, status );
2848
2849 /* If an error occurred, report a contextual error maessage and set
2850 the "astreadclassdata_msg" flag (this prevents multiple messages if this function is
2851 invoked recursively to deal with nested Objects). */
2852 } else {
2853 if ( !astreadclassdata_msg ) {
2854 astError( astStatus,
2855 "Failed to read the \"%s\" Object value.", status,
2856 name );
2857 astreadclassdata_msg = 1;
2858 }
2859
2860 /* Free the memory holding the "name" string and any Value structure
2861 that was allocated. */
2862 name = astFree( name );
2863 value = astFree( value );
2864 }
2865 }
2866 }
2867 }
2868 }
2869 }
2870
ReadDouble(AstChannel * this,const char * name,double def,int * status)2871 static double ReadDouble( AstChannel *this, const char *name, double def, int *status ) {
2872 /*
2873 *+
2874 * Name:
2875 * astReadDouble
2876
2877 * Purpose:
2878 * Read a double value as part of loading a class.
2879
2880 * Type:
2881 * Protected virtual function.
2882
2883 * Synopsis:
2884 * #include "channel.h"
2885 * double astReadDouble( AstChannel *this, const char *name, double def )
2886
2887 * Class Membership:
2888 * Channel method.
2889
2890 * Description:
2891 * This function searches the current values list of a Channel to
2892 * identify a double value with a specified name. If such a value
2893 * is found, it is returned, otherwise a default value is returned
2894 * instead.
2895 *
2896 * This function should only be invoked from within the loader
2897 * function associated with a class, in order to return a double
2898 * value to be assigned to an instance variable. It must be
2899 * preceded by a call to the astReadClassData function, which loads
2900 * the values associated with the class into the current values
2901 * list from the input data source.
2902
2903 * Parameters:
2904 * this
2905 * Pointer to the Channel.
2906 * name
2907 * Pointer to a constant null-terminated character string
2908 * containing the name of the required value. This must be in
2909 * lower case with no surrounding white space. Note that names
2910 * longer than 6 characters will not match any value.
2911 * def
2912 * If no suitable value can be found (e.g. it is absent from the
2913 * data stream being read), then this value will be returned
2914 * instead.
2915
2916 * Returned Value:
2917 * The required value, or the default if the value was not found.
2918
2919 * Notes:
2920 * - A value of 0.0 will be returned if this function is invoked
2921 * with the global error status set, or if it should fail for any
2922 * reason.
2923 *-
2924 */
2925
2926 /* Local Variables: */
2927 AstChannelValue *value; /* Pointer to required Value structure */
2928 double result; /* Value to be returned */
2929 int nc; /* Number of characters read by astSscanf */
2930
2931 /* Initialise. */
2932 result = 0.0;
2933
2934 /* Check the global error status. */
2935 if ( !astOK ) return result;
2936
2937 /* Search for a Value structure with the required name in the current
2938 values list.*/
2939 value = LookupValue( name, status );
2940 if ( astOK ) {
2941
2942 /* If a Value was found, check that it describes a string (as opposed
2943 to an Object). */
2944 if ( value ) {
2945 if ( !value->is_object ) {
2946
2947 /* If so, then attempt to decode the string to give a double value,
2948 checking that the entire string is read (and checking for the magic string
2949 used to represent bad values). If this fails, then the wrong name has
2950 probably been given, or the input data are corrupt, so report an error. */
2951 nc = 0;
2952 if ( ( 0 == astSscanf( value->ptr.string, " " BAD_STRING " %n",
2953 &nc ) )
2954 && ( nc >= (int) strlen( value->ptr.string ) ) ) {
2955 result = AST__BAD;
2956
2957 } else if ( !( ( 1 == astSscanf( value->ptr.string, " %lf %n",
2958 &result, &nc ) )
2959 && ( nc >= (int) strlen( value->ptr.string ) ) ) ) {
2960 astError( AST__BADIN,
2961 "astRead(%s): The value \"%s = %s\" cannot "
2962 "be read as a double precision floating point "
2963 "number.", status, astGetClass( this ),
2964 value->name, value->ptr.string );
2965
2966 } else if( !astISFINITE( result ) ) {
2967 astError( AST__BADIN,
2968 "astRead(%s): Illegal double precision floating "
2969 "point value \"%s\" read for \"%s\".", status,
2970 astGetClass( this ), value->ptr.string, value->name );
2971
2972 }
2973
2974 /* Report a similar error if the Value does not describe a string. */
2975 } else {
2976 astError( AST__BADIN,
2977 "astRead(%s): The Object \"%s = <%s>\" cannot "
2978 "be read as a double precision floating point number.", status,
2979 astGetClass( this ),
2980 value->name, astGetClass( value->ptr.object ) );
2981 }
2982
2983 /* Free the Value structure and the resources it points at. */
2984 value = FreeValue( value, status );
2985
2986 /* If no suitable Value structure was found, then use the default
2987 value instead. */
2988 } else {
2989 result = def;
2990 }
2991 }
2992
2993 /* Return the result. */
2994 return result;
2995 }
2996
ReadInt(AstChannel * this,const char * name,int def,int * status)2997 static int ReadInt( AstChannel *this, const char *name, int def, int *status ) {
2998 /*
2999 *+
3000 * Name:
3001 * astReadInt
3002
3003 * Purpose:
3004 * Read an int value as part of loading a class.
3005
3006 * Type:
3007 * Protected virtual function.
3008
3009 * Synopsis:
3010 * #include "channel.h"
3011 * int astReadInt( AstChannel *this, const char *name, int def )
3012
3013 * Class Membership:
3014 * Channel method.
3015
3016 * Description:
3017 * This function searches the current values list of a Channel to
3018 * identify an int value with a specified name. If such a value is
3019 * found, it is returned, otherwise a default value is returned
3020 * instead.
3021 *
3022 * This function should only be invoked from within the loader
3023 * function associated with a class, in order to return an int
3024 * value to be assigned to an instance variable. It must be
3025 * preceded by a call to the astReadClassData function, which loads
3026 * the values associated with the class into the current values
3027 * list from the input data source.
3028
3029 * Parameters:
3030 * this
3031 * Pointer to the Channel.
3032 * name
3033 * Pointer to a constant null-terminated character string
3034 * containing the name of the required value. This must be in
3035 * lower case with no surrounding white space. Note that names
3036 * longer than 6 characters will not match any value.
3037 * def
3038 * If no suitable value can be found (e.g. it is absent from the
3039 * data stream being read), then this value will be returned
3040 * instead.
3041
3042 * Returned Value:
3043 * The required value, or the default if the value was not found.
3044
3045 * Notes:
3046 * - A value of zero will be returned if this function is invoked
3047 * with the global error status set, or if it should fail for any
3048 * reason.
3049 *-
3050 */
3051
3052 /* Local Variables: */
3053 AstChannelValue *value; /* Pointer to required Value structure */
3054 int nc; /* Number of characters read by astSscanf */
3055 int result; /* Value to be returned */
3056
3057 /* Initialise. */
3058 result = 0;
3059
3060 /* Check the global error status. */
3061 if ( !astOK ) return result;
3062
3063 /* Search for a Value structure with the required name in the current
3064 values list.*/
3065 value = LookupValue( name, status );
3066 if ( astOK ) {
3067
3068 /* If a Value was found, check that it describes a string (as opposed
3069 to an Object). */
3070 if ( value ) {
3071 if ( !value->is_object ) {
3072
3073 /* If so, then attempt to decode the string to give an int value,
3074 checking that the entire string is read. If this fails, then the
3075 wrong name has probably been given, or the input data are corrupt,
3076 so report an error. */
3077 nc = 0;
3078 if ( !( ( 1 == astSscanf( value->ptr.string, " %d %n",
3079 &result, &nc ) )
3080 && ( nc >= (int) strlen( value->ptr.string ) ) ) ) {
3081 astError( AST__BADIN,
3082 "astRead(%s): The value \"%s = %s\" cannot "
3083 "be read as an integer.", status, astGetClass( this ),
3084 value->name, value->ptr.string );
3085 }
3086
3087 /* Report a similar error if the Value does not describe a string. */
3088 } else {
3089 astError( AST__BADIN,
3090 "astRead(%s): The Object \"%s = <%s>\" cannot "
3091 "be read as an integer.", status, astGetClass( this ),
3092 value->name, astGetClass( value->ptr.object ) );
3093 }
3094
3095 /* Free the Value structure and the resources it points at. */
3096 value = FreeValue( value, status );
3097
3098 /* If no suitable Value structure was found, then use the default
3099 value instead. */
3100 } else {
3101 result = def;
3102 }
3103 }
3104
3105 /* Return the result. */
3106 return result;
3107 }
3108
ReadObject(AstChannel * this,const char * name,AstObject * def,int * status)3109 static AstObject *ReadObject( AstChannel *this, const char *name,
3110 AstObject *def, int *status ) {
3111 /*
3112 *+
3113 * Name:
3114 * astReadObject
3115
3116 * Purpose:
3117 * Read a (sub)Object as part of loading a class.
3118
3119 * Type:
3120 * Protected virtual function.
3121
3122 * Synopsis:
3123 * #include "channel.h"
3124 * AstObject *astReadObject( AstChannel *this, const char *name,
3125 * AstObject *def )
3126
3127 * Class Membership:
3128 * Channel method.
3129
3130 * Description:
3131 * This function searches the current values list of a Channel to
3132 * identify an Object with a specified name. If such an Object is
3133 * found, a pointer to it is returned, otherwise a default pointer
3134 * is returned instead.
3135 *
3136 * This function should only be invoked from within the loader
3137 * function associated with a class, in order to return an Object
3138 * pointer value to be assigned to an instance variable. It must be
3139 * preceded by a call to the astReadClassData function, which loads
3140 * the values associated with the class into the current values
3141 * list from the input data source.
3142
3143 * Parameters:
3144 * this
3145 * Pointer to the Channel.
3146 * name
3147 * Pointer to a constant null-terminated character string
3148 * containing the name of the required Object. This must be in
3149 * lower case with no surrounding white space. Note that names
3150 * longer than 6 characters will not match any Object.
3151 * def
3152 * If no suitable Object can be found (e.g. the Object is absent
3153 * from the data stream being read), then a clone of this
3154 * default Object pointer will be returned instead (or NULL if
3155 * this default pointer is NULL).
3156
3157 * Returned Value:
3158 * A pointer to the Object, or a clone of the default pointer if
3159 * the Object was not found.
3160
3161 * Notes:
3162 * - A NULL pointer will be returned if this function is invoked
3163 * with the global error status set, or if it should fail for any
3164 * reason.
3165 *-
3166 */
3167
3168 /* Local Variables: */
3169 AstObject *result; /* Pointer value to return */
3170 AstChannelValue *value; /* Pointer to required Value structure */
3171
3172 /* Initialise. */
3173 result = NULL;
3174
3175 /* Check the global error status. */
3176 if ( !astOK ) return result;
3177
3178 /* Search for a Value structure with the required name in the current
3179 values list.*/
3180 value = LookupValue( name, status );
3181 if ( astOK ) {
3182
3183 /* If a Value was found, check that it describes an Object (as opposed to
3184 a string). */
3185 if ( value ) {
3186 if ( value->is_object ) {
3187
3188 /* If so, then extract the Object pointer, replacing it with NULL. */
3189 result = value->ptr.object;
3190 value->ptr.object = NULL;
3191
3192 /* If the Value does not describe an Object, then the wrong name has
3193 probably been given, or the input data are corrupt, so report an
3194 error. */
3195 } else {
3196 astError( AST__BADIN,
3197 "astRead(%s): The value \"%s = %s\" cannot be "
3198 "read as an Object.", status, astGetClass( this ),
3199 value->name, value->ptr.string );
3200 }
3201
3202 /* Free the Value structure and the resources it points at. */
3203 value = FreeValue( value, status );
3204
3205 /* If no suitable Value structure was found, clone the default
3206 pointer, if given. */
3207 } else if ( def ) {
3208 result = astClone( def );
3209 }
3210 }
3211
3212 /* Return the result. */
3213 return result;
3214 }
3215
ReadString(AstChannel * this,const char * name,const char * def,int * status)3216 static char *ReadString( AstChannel *this, const char *name,
3217 const char *def, int *status ) {
3218 /*
3219 *+
3220 * Name:
3221 * astReadString
3222
3223 * Purpose:
3224 * Read a string value as part of loading a class.
3225
3226 * Type:
3227 * Protected virtual function.
3228
3229 * Synopsis:
3230 * #include "channel.h"
3231 * char *astReadString( AstChannel *this, const char *name,
3232 * const char *def )
3233
3234 * Class Membership:
3235 * Channel method.
3236
3237 * Description:
3238 * This function searches the current values list of a Channel to
3239 * identify a string value with a specified name. If such a value
3240 * is found, a pointer to the string is returned, otherwise a
3241 * pointer to a copy of a default string is returned instead.
3242 *
3243 * This function should only be invoked from within the loader
3244 * function associated with a class, in order to return a string
3245 * pointer value to be assigned to an instance variable. It must be
3246 * preceded by a call to the astReadClassData function, which loads
3247 * the values associated with the class into the current values
3248 * list from the input data source.
3249
3250 * Parameters:
3251 * this
3252 * Pointer to the Channel.
3253 * name
3254 * Pointer to a constant null-terminated character string
3255 * containing the name of the required value. This must be in
3256 * lower case with no surrounding white space. Note that names
3257 * longer than 6 characters will not match any value.
3258 * def
3259 * If no suitable string can be found (e.g. the value is absent
3260 * from the data stream being read), then a dynamically
3261 * allocated copy of the null-terminated string pointed at by
3262 * "def" will be made, and a pointer to this copy will be
3263 * returned instead (or NULL if this default pointer is NULL).
3264
3265 * Returned Value:
3266 * A pointer to a dynamically allocated null-terminated string
3267 * containing the value required, or to a copy of the default
3268 * string if the value was not found (or NULL if the "def" pointer
3269 * was NULL).
3270
3271 * Notes:
3272 * - It is the caller's responsibility to arrange for the memory
3273 * holding the returned string to be freed (using astFree) when it
3274 * is no longer required.
3275 * - A NULL pointer will be returned if this function is invoked
3276 * with the global error status set, or if it should fail for any
3277 * reason.
3278 *-
3279 */
3280
3281 /* Local Variables: */
3282 AstChannelValue *value; /* Pointer to required Value structure */
3283 char *result; /* Pointer value to return */
3284
3285 /* Initialise. */
3286 result = NULL;
3287
3288 /* Check the global error status. */
3289 if ( !astOK ) return result;
3290
3291 /* Search for a Value structure with the required name in the current
3292 values list.*/
3293 value = LookupValue( name, status );
3294 if ( astOK ) {
3295
3296 /* If a Value was found, check that it describes a string (as opposed
3297 to an Object). */
3298 if ( value ) {
3299 if ( !value->is_object ) {
3300
3301 /* If so, then extract the string pointer, replacing it with NULL. */
3302 result = value->ptr.string;
3303 value->ptr.string = NULL;
3304
3305 /* If the Value does not describe a string, then the wrong name has
3306 probably been given, or the input data are corrupt, so report an
3307 error. */
3308 } else {
3309 astError( AST__BADIN,
3310 "astRead(%s): The Object \"%s = <%s>\" cannot "
3311 "be read as a string.", status, astGetClass( this ),
3312 value->name, astGetClass( value->ptr.object ) );
3313 }
3314
3315 /* Free the Value structure and the resources it points at. */
3316 value = FreeValue( value, status );
3317
3318 /* If no suitable Value structure was found, then make a dynamic copy
3319 of the default string (if given) and return a pointer to this. */
3320 } else if ( def ) {
3321 result = astStore( NULL, def, strlen( def ) + (size_t) 1 );
3322 }
3323 }
3324
3325 /* Return the result. */
3326 return result;
3327 }
3328
RemoveValue(AstChannelValue * value,AstChannelValue ** head,int * status)3329 static void RemoveValue( AstChannelValue *value, AstChannelValue **head, int *status ) {
3330 /*
3331 * Name:
3332 * RemoveValue
3333
3334 * Purpose:
3335 * Remove a Value structure from a circular linked list.
3336
3337 * Type:
3338 * Private function.
3339
3340 * Synopsis:
3341 * #include "channel.h"
3342 * void RemoveValue( AstChannelValue *value, AstChannelValue **head, int *status );
3343
3344 * Class Membership:
3345 * Channel member function.
3346
3347 * Description:
3348 * This function removes a Value structure from a doubly linked
3349 * circular list of such structures. The "head of list" pointer is
3350 * updated to point at the element following the one removed.
3351
3352 * Parameters:
3353 * value
3354 * Pointer to the structure to be removed (note that this must
3355 * actually be in the list, although this function does not
3356 * check).
3357 * head
3358 * Address of a pointer to the element at the head of the
3359 * list. This pointer will be updated to point at the list
3360 * element that follows the one removed. If the list becomes
3361 * empty, the pointer will be set to NULL.
3362 * status
3363 * Pointer to the inherited status variable.
3364
3365 * Notes:
3366 * - This function does not perform error chacking and does not
3367 * generate errors.
3368 */
3369
3370 /* Remove the Value structure from the list by re-establishing links
3371 between the elements on either side of it. */
3372 value->blink->flink = value->flink;
3373 value->flink->blink = value->blink;
3374
3375 /* Update the head of list pointer to identify the following
3376 element. */
3377 *head = value->flink;
3378
3379 /* If the head of list identifies the removed element, then note that
3380 the list is now empty. */
3381 if ( *head == value ) *head = NULL;
3382
3383 /* Make the removed element point at itself. */
3384 value->flink = value;
3385 value->blink = value;
3386 }
3387
SetAttrib(AstObject * this_object,const char * setting,int * status)3388 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
3389 /*
3390 * Name:
3391 * SetAttrib
3392
3393 * Purpose:
3394 * Set an attribute value for a Channel.
3395
3396 * Type:
3397 * Private function.
3398
3399 * Synopsis:
3400 * #include "channel.h"
3401 * void SetAttrib( AstObject *this, const char *setting )
3402
3403 * Class Membership:
3404 * Channel member function (over-rides the astSetAttrib protected
3405 * method inherited from the Object class).
3406
3407 * Description:
3408 * This function assigns an attribute value for a Channel, the
3409 * attribute and its value being specified by means of a string of
3410 * the form:
3411 *
3412 * "attribute= value "
3413 *
3414 * Here, "attribute" specifies the attribute name and should be in
3415 * lower case with no white space present. The value to the right
3416 * of the "=" should be a suitable textual representation of the
3417 * value to be assigned and this will be interpreted according to
3418 * the attribute's data type. White space surrounding the value is
3419 * only significant for string attributes.
3420
3421 * Parameters:
3422 * this
3423 * Pointer to the Channel.
3424 * setting
3425 * Pointer to a null terminated string specifying the new attribute
3426 * value.
3427 */
3428
3429 /* Local Variables: */
3430 AstChannel *this; /* Pointer to the Channel structure */
3431 int comment; /* Comment attribute value */
3432 int full; /* Full attribute value */
3433 int indent; /* Indent attribute value */
3434 int len; /* Length of setting string */
3435 int nc; /* Number of characters read by "astSscanf" */
3436 int report_level; /* Skip attribute value */
3437 int skip; /* Skip attribute value */
3438 int sourcefile; /* Offset of SourceFile string */
3439 int sinkfile; /* Offset of SinkFile string */
3440 int strict; /* Report errors instead of warnings? */
3441
3442 /* Check the global error status. */
3443 if ( !astOK ) return;
3444
3445 /* Obtain a pointer to the Channel structure. */
3446 this = (AstChannel *) this_object;
3447
3448 /* Obtain the length of the setting string. */
3449 len = (int) strlen( setting );
3450
3451 /* Test for each recognised attribute in turn, using "astSscanf" to parse
3452 the setting string and extract the attribute value (or an offset to
3453 it in the case of string values). In each case, use the value set
3454 in "nc" to check that the entire string was matched. Once a value
3455 has been obtained, use the appropriate method to set it. */
3456
3457 /* Comment. */
3458 /* ---------*/
3459 if ( nc = 0,
3460 ( 1 == astSscanf( setting, "comment= %d %n", &comment, &nc ) )
3461 && ( nc >= len ) ) {
3462 astSetComment( this, comment );
3463
3464 /* Full. */
3465 /* ----- */
3466 } else if ( nc = 0,
3467 ( 1 == astSscanf( setting, "full= %d %n", &full, &nc ) )
3468 && ( nc >= len ) ) {
3469 astSetFull( this, full );
3470
3471 /* Indent. */
3472 /* ------- */
3473 } else if ( nc = 0,
3474 ( 1 == astSscanf( setting, "indent= %d %n", &indent, &nc ) )
3475 && ( nc >= len ) ) {
3476 astSetIndent( this, indent );
3477
3478 /* ReportLavel. */
3479 /* ------------ */
3480 } else if ( nc = 0,
3481 ( 1 == astSscanf( setting, "reportlevel= %d %n", &report_level, &nc ) )
3482 && ( nc >= len ) ) {
3483 astSetReportLevel( this, report_level );
3484
3485 /* Skip. */
3486 /* ----- */
3487 } else if ( nc = 0,
3488 ( 1 == astSscanf( setting, "skip= %d %n", &skip, &nc ) )
3489 && ( nc >= len ) ) {
3490 astSetSkip( this, skip );
3491
3492 /* SinkFile. */
3493 /* --------- */
3494 } else if ( nc = 0,
3495 ( 0 == astSscanf( setting, "sinkfile=%n%*[^\n]%n", &sinkfile, &nc ) )
3496 && ( nc >= len ) ) {
3497 astSetSinkFile( this, setting + sinkfile );
3498
3499 /* SourceFile. */
3500 /* ----------- */
3501 } else if ( nc = 0,
3502 ( 0 == astSscanf( setting, "sourcefile=%n%*[^\n]%n", &sourcefile, &nc ) )
3503 && ( nc >= len ) ) {
3504 astSetSourceFile( this, setting + sourcefile );
3505
3506 /* Strict. */
3507 /* ------- */
3508 } else if ( nc = 0,
3509 ( 1 == astSscanf( setting, "strict= %d %n", &strict, &nc ) )
3510 && ( nc >= len ) ) {
3511 astSetStrict( this, strict );
3512
3513 /* If the attribute is still not recognised, pass it on to the parent
3514 method for further interpretation. */
3515 } else {
3516 (*parent_setattrib)( this_object, setting, status );
3517 }
3518 }
3519
SinkWrap(void (* sink)(const char *),const char * line,int * status)3520 static void SinkWrap( void (* sink)( const char * ), const char *line, int *status ) {
3521 /*
3522 * Name:
3523 * SinkWrap
3524
3525 * Purpose:
3526 * Wrapper function to invoke a C Channel sink function.
3527
3528 * Type:
3529 * Private function.
3530
3531 * Synopsis:
3532 * #include "channel.h"
3533 * void SinkWrap( void (* sink)( const char * ), const char *line, int *status )
3534
3535 * Class Membership:
3536 * Channel member function.
3537
3538 * Description:
3539 * This function invokes the sink function whose pointer is
3540 * supplied in order to write an output line to an external data
3541 * store.
3542
3543 * Parameters:
3544 * sink
3545 * Pointer to a sink function, whose single parameter is a
3546 * pointer to a const, null-terminated string containing the
3547 * text to be written, and which returns void. This is the form
3548 * of Channel sink function employed by the C language interface
3549 * to the AST library.
3550 * status
3551 * Pointer to the inherited status variable.
3552 */
3553
3554 /* Check the global error status. */
3555 if ( !astOK ) return;
3556
3557 /* Invoke the sink function. */
3558 ( *sink )( line );
3559 }
3560
SourceWrap(const char * (* source)(void),int * status)3561 static char *SourceWrap( const char *(* source)( void ), int *status ) {
3562 /*
3563 * Name:
3564 * SourceWrap
3565
3566 * Purpose:
3567 * Wrapper function to invoke a C Channel source function.
3568
3569 * Type:
3570 * Private function.
3571
3572 * Synopsis:
3573 * #include "channel.h"
3574 * char *SourceWrap( const char *, int *status(* source)( void ) )
3575
3576 * Class Membership:
3577 * Channel member function.
3578
3579 * Description:
3580 * This function invokes the source function whose pointer is
3581 * supplied in order to read the next input line from an external
3582 * data store. It then returns a pointer to a dynamic string
3583 * containing a copy of the text that was read.
3584
3585 * Parameters:
3586 * source
3587 * Pointer to a source function, with no parameters, that
3588 * returns a pointer to a const, null-terminated string
3589 * containing the text that it read. This is the form of Channel
3590 * source function employed by the C language interface to the
3591 * AST library.
3592 * status
3593 * Pointer to the inherited status variable.
3594
3595 * Returned Value:
3596 * A pointer to a dynamically allocated, null terminated string
3597 * containing a copy of the text that was read. This string must be
3598 * freed by the caller (using astFree) when no longer required.
3599 *
3600 * A NULL pointer will be returned if there is no more input text
3601 * to read.
3602
3603 * Notes:
3604 * - A NULL pointer value will be returned if this function is
3605 * invoked with the global error status set or if it should fail
3606 * for any reason.
3607 */
3608
3609 /* Local Variables: */
3610 char *result; /* Pointer value to return */
3611 const char *line; /* Pointer to input line */
3612
3613 /* Initialise. */
3614 result = NULL;
3615
3616 /* Check the global error status. */
3617 if ( !astOK ) return result;
3618
3619 /* Invoke the source function to read the next input line and return a
3620 pointer to the resulting string. */
3621 line = ( *source )();
3622
3623 /* If a string was obtained, make a dynamic copy of it and save the
3624 resulting pointer. */
3625 if ( line ) result = astString( line, (int) strlen( line ) );
3626
3627 /* Return the result. */
3628 return result;
3629 }
3630
astStoreChannelData_(AstChannel * this,int * status)3631 void astStoreChannelData_( AstChannel *this, int *status ) {
3632 /*
3633 *+
3634 * Name:
3635 * astStoreChannelData
3636
3637 * Purpose:
3638 * Store the Channel's channel-data pointer in a thread-specific
3639 * global variable.
3640
3641 * Type:
3642 * Protected virtual function.
3643
3644 * Synopsis:
3645 * #include "channel.h"
3646 * astStoreChannelData( AstChannel *this )
3647
3648 * Class Membership:
3649 * Channel method.
3650
3651 * Description:
3652 * This function stores the Channel's channel-data pointer (if any)
3653 * established by the previous call to astPutChannelData, in a
3654 * thread-specific global variable from where the astChannelData macro
3655 * can access it.
3656
3657 * Parameters:
3658 * this
3659 * Pointer to the Channel.
3660 *-
3661 */
3662
3663 /* Local Variables: */
3664 astDECLARE_GLOBALS /* Declare the thread specific global data */
3665
3666 /* Check the global error status. */
3667 if ( !astOK ) return;
3668
3669 /* Get a pointer to the structure holding thread-specific global data. */
3670 astGET_GLOBALS(this);
3671
3672 /* Store the pointer int he global variable. */
3673 channel_data = this->data;
3674 }
3675
TestAttrib(AstObject * this_object,const char * attrib,int * status)3676 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
3677 /*
3678 * Name:
3679 * TestAttrib
3680
3681 * Purpose:
3682 * Test if a specified attribute value is set for a Channel.
3683
3684 * Type:
3685 * Private function.
3686
3687 * Synopsis:
3688 * #include "channel.h"
3689 * int TestAttrib( AstObject *this, const char *attrib, int *status )
3690
3691 * Class Membership:
3692 * Channel member function (over-rides the astTestAttrib protected
3693 * method inherited from the Object class).
3694
3695 * Description:
3696 * This function returns a boolean result (0 or 1) to indicate whether
3697 * a value has been set for one of a Channel's attributes.
3698
3699 * Parameters:
3700 * this
3701 * Pointer to the Channel.
3702 * attrib
3703 * Pointer to a null terminated string specifying the attribute
3704 * name. This should be in lower case with no surrounding white
3705 * space.
3706 * status
3707 * Pointer to the inherited status variable.
3708
3709 * Returned Value:
3710 * One if a value has been set, otherwise zero.
3711
3712 * Notes:
3713 * - A value of zero will be returned if this function is invoked
3714 * with the global status set, or if it should fail for any reason.
3715 */
3716
3717 /* Local Variables: */
3718 AstChannel *this; /* Pointer to the Channel structure */
3719 int result; /* Result value to return */
3720
3721 /* Initialise. */
3722 result = 0;
3723
3724 /* Check the global error status. */
3725 if ( !astOK ) return result;
3726
3727 /* Obtain a pointer to the Channel structure. */
3728 this = (AstChannel *) this_object;
3729
3730 /* Check the attribute name and test the appropriate attribute. */
3731
3732 /* Comment. */
3733 /* -------- */
3734 if ( !strcmp( attrib, "comment" ) ) {
3735 result = astTestComment( this );
3736
3737 /* Full. */
3738 /* ----- */
3739 } else if ( !strcmp( attrib, "full" ) ) {
3740 result = astTestFull( this );
3741
3742 /* Indent. */
3743 /* ------- */
3744 } else if ( !strcmp( attrib, "indent" ) ) {
3745 result = astTestIndent( this );
3746
3747 /* ReportLevel. */
3748 /* ------------ */
3749 } else if ( !strcmp( attrib, "reportlevel" ) ) {
3750 result = astTestReportLevel( this );
3751
3752 /* Skip. */
3753 /* ----- */
3754 } else if ( !strcmp( attrib, "skip" ) ) {
3755 result = astTestSkip( this );
3756
3757 /* SourceFile. */
3758 /* ----------- */
3759 } else if ( !strcmp( attrib, "sourcefile" ) ) {
3760 result = astTestSourceFile( this );
3761
3762 /* SinkFile. */
3763 /* ----------- */
3764 } else if ( !strcmp( attrib, "sinkfile" ) ) {
3765 result = astTestSinkFile( this );
3766
3767 /* Strict. */
3768 /* ------- */
3769 } else if ( !strcmp( attrib, "strict" ) ) {
3770 result = astTestStrict( this );
3771
3772 /* If the attribute is still not recognised, pass it on to the parent
3773 method for further interpretation. */
3774 } else {
3775 result = (*parent_testattrib)( this_object, attrib, status );
3776 }
3777
3778 /* Return the result, */
3779 return result;
3780 }
3781
Unquote(AstChannel * this,char * str,int * status)3782 static void Unquote( AstChannel *this, char *str, int *status ) {
3783 /*
3784 * Name:
3785 * Unquote
3786
3787 * Purpose:
3788 * Remove quotes from a (possibly) quoted string.
3789
3790 * Type:
3791 * Private function.
3792
3793 * Synopsis:
3794 * #include "channel.h"
3795 * void Unquote( AstChannel *this, char *str, int *status )
3796
3797 * Class Membership:
3798 * Channel member function.
3799
3800 * Description:
3801 * This function removes one layer of quote characters (") from a
3802 * string which is possibly quoted. Any quotes within quotes (which
3803 * should have been doubled when the string was originally quoted)
3804 * are also converted back to single quotes again.
3805 *
3806 * The quotes need not start or end at the ends of the string, and
3807 * there may be any number of quoted sections within the string. No
3808 * error results if the string does not contain any quotes at all
3809 * (it is simply returned unchanged), but an error results if any
3810 * unmatched quotes are found.
3811
3812 * Parameters:
3813 * this
3814 * Pointer to a Channel. This is only used for constructing error
3815 * messages and has no influence on the string processing.
3816 * str
3817 * Pointer to the null-terminated string to be processed. This
3818 * is modified in place. The new string starts at the same
3819 * location as the original but has a new null character
3820 * appended if necessary (it will usually be shorter than the
3821 * original).
3822 * status
3823 * Pointer to the inherited status variable.
3824 */
3825
3826 /* Local Variables: */
3827 int i; /* Loop counter for "input" characters */
3828 int j; /* Counter for "output" characters */
3829 int quoted; /* Inside a quoted string? */
3830
3831 /* Check the global error status. */
3832 if ( !astOK ) return;
3833
3834 /* Loop to inspect each character in the string. */
3835 quoted = 0;
3836 for ( i = j = 0; str[ i ]; i++ ) {
3837
3838 /* Non-quote characters are simply copied to their new location in the
3839 string. */
3840 if ( str[ i ] != '"' ) {
3841 str[ j++ ] = str[ i ];
3842
3843 /* If a quote character '"' is encountered and we are not already in a
3844 quoted string, then note the start of a quoted string (and discard
3845 the quote). */
3846 } else if ( !quoted ) {
3847 quoted = 1;
3848
3849 /* If a quote character is encountered inside a quoted string, then
3850 check if the next character is also a quote. If so, convert this
3851 double quote to a single one. */
3852 } else if ( str[ i + 1 ] == '"' ) {
3853 str[ j++ ] = '"';
3854 i++;
3855
3856 /* If a single quote character is encountered inside a quoted string,
3857 then note the end of the quoted string (and discard the quote). */
3858 } else {
3859 quoted = 0;
3860 }
3861 }
3862
3863 /* Append a null to terminate the processed string. */
3864 str[ j ] = '\0';
3865
3866 /* If the "quoted" flag is still set, then there were unmatched
3867 quotes, so report an error. */
3868 if ( quoted ) {
3869 astError( AST__UNMQT,
3870 "astRead(%s): Unmatched quotes in input data: %s.", status,
3871 astGetClass( this ), str );
3872 }
3873 }
3874
Use(AstChannel * this,int set,int helpful,int * status)3875 static int Use( AstChannel *this, int set, int helpful, int *status ) {
3876 /*
3877 * Name:
3878 * Use
3879
3880 * Purpose:
3881 * Decide whether to write a value to a data sink.
3882
3883 * Type:
3884 * Private function.
3885
3886 * Synopsis:
3887 * #include "channel.h"
3888 * int Use( AstChannel *this, int set, int helpful, int *status )
3889
3890 * Class Membership:
3891 * Channel member function.
3892
3893 * Description:
3894 * This function decides whether a value supplied by a class "Dump"
3895 * function, via a call to one of the astWrite... protected
3896 * methods, should actually be written to the data sink associated
3897 * with a Channel.
3898 *
3899 * This decision is based on the settings of the "set" and
3900 * "helpful" flags supplied to the astWrite... method, plus the
3901 * attribute settings of the Channel.
3902
3903 * Parameters:
3904 * this
3905 * A pointer to the Channel.
3906 * set
3907 * The "set" flag supplied.
3908 * helpful
3909 * The "helpful" value supplied.
3910 * status
3911 * Pointer to the inherited status variable.
3912
3913 * Returned Value:
3914 * One if the value should be written out, otherwise zero.
3915
3916 * Notes:
3917 * - A value of zero will be returned if this function is invoked
3918 * with the global error status set or if it should fail for any
3919 * reason.
3920 */
3921
3922 /* Local Variables: */
3923 int full; /* Full attribute value */
3924 int result; /* Result value to be returned */
3925
3926 /* Check the global error status. */
3927 if ( !astOK ) return 0;
3928
3929 /* If "set" is non-zero, then so is the result ("set" values must
3930 always be written out). */
3931 result = ( set != 0 );
3932
3933 /* Otherwise, obtain the value of the Channel's Full attribute. */
3934 if ( !set ) {
3935 full = astGetFull( this );
3936
3937 /* If Full is positive, display all values, if zero, display only
3938 "helpful" values, if negative, display no (un-"set") values. */
3939 if ( astOK ) result = ( ( helpful && ( full > -1 ) ) || ( full > 0 ) );
3940 }
3941
3942 /* Return the result. */
3943 return result;
3944 }
3945
Write(AstChannel * this,AstObject * object,int * status)3946 static int Write( AstChannel *this, AstObject *object, int *status ) {
3947 /*
3948 *++
3949 * Name:
3950 c astWrite
3951 f AST_WRITE
3952
3953 * Purpose:
3954 * Write an Object to a Channel.
3955
3956 * Type:
3957 * Public function.
3958
3959 * Synopsis:
3960 c #include "channel.h"
3961 c int astWrite( AstChannel *this, AstObject *object )
3962 f RESULT = AST_WRITE( THIS, OBJECT, STATUS )
3963
3964 * Class Membership:
3965 * Channel method.
3966
3967 * Description:
3968 * This function writes an Object to a Channel, appending it to any
3969 * previous Objects written to that Channel.
3970
3971 * Parameters:
3972 c this
3973 f THIS = INTEGER (Given)
3974 * Pointer to the Channel.
3975 c object
3976 f OBJECT = INTEGER (Given)
3977 * Pointer to the Object which is to be written.
3978 f STATUS = INTEGER (Given and Returned)
3979 f The global status.
3980
3981 * Returned Value:
3982 c astWrite()
3983 f AST_WRITE = INTEGER
3984 * The number of Objects written to the Channel by this
3985 c invocation of astWrite (normally, this will be one).
3986 f invocation of AST_WRITE (normally, this will be one).
3987
3988 * Applicability:
3989 * FitsChan
3990 * If the FitsChan uses a foreign encoding (e.g. FITS-WCS) rather
3991 * than the native AST encoding, then storing values in the
3992 * FitsChan for keywords NAXIS1, NAXIS2, etc., before invoking
3993 c astWrite
3994 f AST_WRITE
3995 * can help to produce a successful write.
3996
3997 * Notes:
3998 * - A value of zero will be returned if this function is invoked
3999 c with the AST error status set, or if it should fail for any
4000 f with STATUS set to an error value, or if it should fail for any
4001 * reason.
4002 * - Invoking this function will usually cause the sink function
4003 * associated with the channel to be called in order to transfer a
4004 * textual description of the supplied object to some external data
4005 * store. However, the FitsChan class behaves differently. Invoking
4006 * this function on a FitsChan causes new FITS header cards to be
4007 * added to an internal buffer (the sink function is not invoked).
4008 * This buffer is written out through the sink function only when the
4009 * FitsChan is deleted.
4010 *--
4011 */
4012
4013 /* Check the global error status. */
4014 if ( !astOK ) return 0;
4015
4016 /* The work of this function is actually performed by the protected
4017 astDump method of the Object. The fact that this is further
4018 encapsulated within the astWrite method (which belongs to the
4019 Channel) is simply a trick to allow it to be over-ridden either by
4020 a derived Channel, or a derived Object (or both), and hence to
4021 adapt to the nature of either argument. */
4022 astDump( object, this );
4023
4024 /* Return the number of Objects written. */
4025 return astOK ? 1 : 0;
4026 }
4027
WriteBegin(AstChannel * this,const char * class,const char * comment,int * status)4028 static void WriteBegin( AstChannel *this, const char *class,
4029 const char *comment, int *status ) {
4030 /*
4031 *+
4032 * Name:
4033 * astWriteBegin
4034
4035 * Purpose:
4036 * Write a "Begin" data item to a data sink.
4037
4038 * Type:
4039 * Protected virtual function.
4040
4041 * Synopsis:
4042 * #include "channel.h"
4043 * void astWriteBegin( AstChannel *this, const char *class,
4044 * const char *comment )
4045
4046 * Class Membership:
4047 * Channel method.
4048
4049 * Description:
4050 * This function writes a "Begin" data item to the data sink
4051 * associated with a Channel, so as to begin the output of a new
4052 * Object definition.
4053
4054 * Parameters:
4055 * this
4056 * Pointer to the Channel.
4057 * class
4058 * Pointer to a constant null-terminated string containing the
4059 * name of the class to which the Object belongs.
4060 * comment
4061 * Pointer to a constant null-terminated string containing a
4062 * textual comment to be associated with the "Begin"
4063 * item. Normally, this will describe the purpose of the Object.
4064
4065 * Notes:
4066 * - The comment supplied may not actually be used, depending on
4067 * the nature of the Channel supplied.
4068 *-
4069 */
4070
4071 /* Local Variables: */
4072 astDECLARE_GLOBALS /* Declare the thread specific global data */
4073 char *line; /* Pointer to dynamic output string */
4074 int i; /* Loop counter for indentation characters */
4075 int nc; /* Number of output characters */
4076
4077 /* Check the global error status. */
4078 if ( !astOK ) return;
4079
4080 /* Get a pointer to the structure holding thread-specific global data. */
4081 astGET_GLOBALS(this);
4082
4083 /* Start building a dynamic string with an initial space. Then add
4084 further spaces to suit the current indentation level. */
4085 line = astAppendString( NULL, &nc, " " );
4086 for ( i = 0; i < current_indent; i++ ) {
4087 line = astAppendString( line, &nc, " " );
4088 }
4089
4090 /* Append the "Begin" keyword followed by the class name. */
4091 line = astAppendString( line, &nc, "Begin " );
4092 line = astAppendString( line, &nc, class );
4093
4094 /* If required, also append the comment. */
4095 if ( astGetComment( this ) && *comment ) {
4096 line = astAppendString( line, &nc, " \t# " );
4097 line = astAppendString( line, &nc, comment );
4098 }
4099
4100 /* Write out the resulting line of text. */
4101 OutputTextItem( this, line, status );
4102
4103 /* Free the dynamic string. */
4104 line = astFree( line );
4105
4106 /* Increment the indentation level and clear the count of items written
4107 for this Object. */
4108 current_indent += astGetIndent( this );
4109 items_written = 0;
4110 }
4111
WriteDouble(AstChannel * this,const char * name,int set,int helpful,double value,const char * comment,int * status)4112 static void WriteDouble( AstChannel *this, const char *name,
4113 int set, int helpful,
4114 double value, const char *comment, int *status ) {
4115 /*
4116 *+
4117 * Name:
4118 * astWriteDouble
4119
4120 * Purpose:
4121 * Write a double value to a data sink.
4122
4123 * Type:
4124 * Protected virtual function.
4125
4126 * Synopsis:
4127 * #include "channel.h"
4128 * void astWriteDouble( AstChannel *this, const char *name,
4129 * int set, int helpful,
4130 * double value, const char *comment )
4131
4132 * Class Membership:
4133 * Channel method.
4134
4135 * Description:
4136 * This function writes a named double value, representing the
4137 * value of a class instance variable, to the data sink associated
4138 * with a Channel. It is intended for use by class "Dump" functions
4139 * when writing out class information which will subsequently be
4140 * re-read.
4141
4142 * Parameters:
4143 * this
4144 * Pointer to the Channel.
4145 * name
4146 * Pointer to a constant null-terminated string containing the
4147 * name to be used to identify the value in the external
4148 * representation. This will form the key for identifying it
4149 * again when it is re-read. The name supplied should be unique
4150 * within its class.
4151 *
4152 * Mixed case may be used and will be preserved in the external
4153 * representation (where possible) for cosmetic effect. However,
4154 * case is not significant when re-reading values.
4155 *
4156 * It is recommended that a maximum of 6 alphanumeric characters
4157 * (starting with an alphabetic character) be used. This permits
4158 * maximum flexibility in adapting to standard external data
4159 * representations (e.g. FITS).
4160 * set
4161 * If this is zero, it indicates that the value being written is
4162 * a default value (or can be re-generated from other values) so
4163 * need not necessarily be written out. Such values will
4164 * typically be included in the external representation with
4165 * (e.g.) a comment character so that they are available to
4166 * human readers but will be ignored when re-read. They may also
4167 * be completely omitted in some circumstances.
4168 *
4169 * If "set" is non-zero, the value will always be explicitly
4170 * included in the external representation so that it can be
4171 * re-read.
4172 * helpful
4173 * This flag provides a hint about whether a value whose "set"
4174 * flag is zero (above) should actually appear at all in the
4175 * external representaton.
4176 *
4177 * If the external representation allows values to be "commented
4178 * out" then, by default, values will be included in this form
4179 * only if their "helpful" flag is non-zero. Otherwise, they
4180 * will be omitted entirely. When possible, omitting the more
4181 * obscure values associated with a class is recommended in
4182 * order to improve readability.
4183 *
4184 * This default behaviour may be further modified if the
4185 * Channel's Full attribute is set - either to permit all values
4186 * to be shown, or to suppress non-essential information
4187 * entirely.
4188 * value
4189 * The value to be written.
4190 * comment
4191 * Pointer to a constant null-terminated string containing a
4192 * textual comment to be associated with the value.
4193 *
4194 * Note that this comment may not actually be used, depending on
4195 * the nature of the Channel supplied and the setting of its
4196 * Comment attribute.
4197 *-
4198 */
4199
4200 /* Local Constants: */
4201 #define BUFF_LEN 100 /* Size of local formatting buffer */
4202
4203 /* Local Variables: */
4204 astDECLARE_GLOBALS /* Declare the thread specific global data */
4205 char *line; /* Pointer to dynamic output string */
4206 char buff[ BUFF_LEN + 1 ]; /* Local formatting buffer */
4207 int i; /* Loop counter for indentation characters */
4208 int nc; /* Number of output characters */
4209
4210 /* Check the global error status. */
4211 if ( !astOK ) return;
4212
4213 /* Get a pointer to the structure holding thread-specific global data. */
4214 astGET_GLOBALS(this);
4215
4216 /* Use the "set" and "helpful" flags, along with the Channel's
4217 attributes to decide whether this value should actually be
4218 written. */
4219 if ( Use( this, set, helpful, status ) ) {
4220
4221 /* Start building a dynamic string with an initial space, or a comment
4222 character if "set" is zero. Then add further spaces to suit the
4223 current indentation level. */
4224 line = astAppendString( NULL, &nc, set ? " " : "#" );
4225 for ( i = 0; i < current_indent; i++ ) {
4226 line = astAppendString( line, &nc, " " );
4227 }
4228
4229 /* Append the name string followed by " = ". */
4230 line = astAppendString( line, &nc, name );
4231 line = astAppendString( line, &nc, " = " );
4232
4233 /* Format the value as a string and append this. Make sure "-0" isn't
4234 produced. Use a magic string to represent bad values. */
4235 if( value != AST__BAD ) {
4236 (void) sprintf( buff, "%.*g", DBL_DIG, value );
4237 if ( !strcmp( buff, "-0" ) ) {
4238 buff[ 0 ] = '0';
4239 buff[ 1 ] = '\0';
4240 }
4241 } else {
4242 strcpy( buff, BAD_STRING );
4243 }
4244 line = astAppendString( line, &nc, buff );
4245
4246 /* If required, also append the comment. */
4247 if ( astGetComment( this ) && *comment ) {
4248 line = astAppendString( line, &nc, " \t# " );
4249 line = astAppendString( line, &nc, comment );
4250 }
4251
4252 /* Write out the resulting line of text. */
4253 OutputTextItem( this, line, status );
4254
4255 /* Free the dynamic string. */
4256 line = astFree( line );
4257 }
4258
4259 /* Undefine macros local to this function. */
4260 #undef BUFF_LEN
4261 }
4262
WriteEnd(AstChannel * this,const char * class,int * status)4263 static void WriteEnd( AstChannel *this, const char *class, int *status ) {
4264 /*
4265 *+
4266 * Name:
4267 * astWriteEnd
4268
4269 * Purpose:
4270 * Write an "End" data item to a data sink.
4271
4272 * Type:
4273 * Protected virtual function.
4274
4275 * Synopsis:
4276 * #include "channel.h"
4277 * void astWriteEnd( AstChannel *this, const char *class )
4278
4279 * Class Membership:
4280 * Channel method.
4281
4282 * Description:
4283 * This function writes an "End" data item to the data sink
4284 * associated with a Channel. This item delimits the end of an
4285 * Object definition.
4286
4287 * Parameters:
4288 * this
4289 * Pointer to the Channel.
4290 * class
4291 * Pointer to a constant null-terminated string containing the
4292 * class name of the Object whose definition is being terminated
4293 * by the "End" item.
4294 *-
4295 */
4296
4297 /* Local Variables: */
4298 astDECLARE_GLOBALS /* Declare the thread specific global data */
4299 char *line; /* Pointer to dynamic output string */
4300 int i; /* Loop counter for indentation characters */
4301 int nc; /* Number of output characters */
4302
4303 /* Check the global error status. */
4304 if ( !astOK ) return;
4305
4306 /* Get a pointer to the structure holding thread-specific global data. */
4307 astGET_GLOBALS(this);
4308
4309 /* Decrement the indentation level so that the "End" item matches the
4310 corresponding "Begin" item. */
4311 current_indent -= astGetIndent( this );
4312
4313 /* Start building a dynamic string with an initial space. Then add
4314 further spaces to suit the current indentation level. */
4315 line = astAppendString( NULL, &nc, " " );
4316 for ( i = 0; i < current_indent; i++ ) {
4317 line = astAppendString( line, &nc, " " );
4318 }
4319
4320 /* Append the "End" keyword followed by the class name. */
4321 line = astAppendString( line, &nc, "End " );
4322 line = astAppendString( line, &nc, class );
4323
4324 /* Write out the resulting line of text. */
4325 OutputTextItem( this, line, status );
4326
4327 /* Free the dynamic string. */
4328 line = astFree( line );
4329 }
4330
WriteInt(AstChannel * this,const char * name,int set,int helpful,int value,const char * comment,int * status)4331 static void WriteInt( AstChannel *this, const char *name, int set, int helpful,
4332 int value, const char *comment, int *status ) {
4333 /*
4334 *+
4335 * Name:
4336 * astWriteInt
4337
4338 * Purpose:
4339 * Write an integer value to a data sink.
4340
4341 * Type:
4342 * Protected virtual function.
4343
4344 * Synopsis:
4345 * #include "channel.h"
4346 * void astWriteInt( AstChannel *this, const char *name,
4347 * int set, int helpful,
4348 * int value, const char *comment )
4349
4350 * Class Membership:
4351 * Channel method.
4352
4353 * Description:
4354 * This function writes a named integer value, representing the
4355 * value of a class instance variable, to the data sink associated
4356 * with a Channel. It is intended for use by class "Dump" functions
4357 * when writing out class information which will subsequently be
4358 * re-read.
4359
4360 * Parameters:
4361 * this
4362 * Pointer to the Channel.
4363 * name
4364 * Pointer to a constant null-terminated string containing the
4365 * name to be used to identify the value in the external
4366 * representation. This will form the key for identifying it
4367 * again when it is re-read. The name supplied should be unique
4368 * within its class.
4369 *
4370 * Mixed case may be used and will be preserved in the external
4371 * representation (where possible) for cosmetic effect. However,
4372 * case is not significant when re-reading values.
4373 *
4374 * It is recommended that a maximum of 6 alphanumeric characters
4375 * (starting with an alphabetic character) be used. This permits
4376 * maximum flexibility in adapting to standard external data
4377 * representations (e.g. FITS).
4378 * set
4379 * If this is zero, it indicates that the value being written is
4380 * a default value (or can be re-generated from other values) so
4381 * need not necessarily be written out. Such values will
4382 * typically be included in the external representation with
4383 * (e.g.) a comment character so that they are available to
4384 * human readers but will be ignored when re-read. They may also
4385 * be completely omitted in some circumstances.
4386 *
4387 * If "set" is non-zero, the value will always be explicitly
4388 * included in the external representation so that it can be
4389 * re-read.
4390 * helpful
4391 * This flag provides a hint about whether a value whose "set"
4392 * flag is zero (above) should actually appear at all in the
4393 * external representaton.
4394 *
4395 * If the external representation allows values to be "commented
4396 * out" then, by default, values will be included in this form
4397 * only if their "helpful" flag is non-zero. Otherwise, they
4398 * will be omitted entirely. When possible, omitting the more
4399 * obscure values associated with a class is recommended in
4400 * order to improve readability.
4401 *
4402 * This default behaviour may be further modified if the
4403 * Channel's Full attribute is set - either to permit all values
4404 * to be shown, or to suppress non-essential information
4405 * entirely.
4406 * value
4407 * The value to be written.
4408 * comment
4409 * Pointer to a constant null-terminated string containing a
4410 * textual comment to be associated with the value.
4411 *
4412 * Note that this comment may not actually be used, depending on
4413 * the nature of the Channel supplied and the setting of its
4414 * Comment attribute.
4415 *-
4416 */
4417
4418 /* Local Constants: */
4419 #define BUFF_LEN 50 /* Size of local formatting buffer */
4420
4421 /* Local Variables: */
4422 astDECLARE_GLOBALS /* Declare the thread specific global data */
4423 char *line; /* Pointer to dynamic output string */
4424 char buff[ BUFF_LEN + 1 ]; /* Local formatting buffer */
4425 int i; /* Loop counter for indentation characters */
4426 int nc; /* Number of output characters */
4427
4428 /* Check the global error status. */
4429 if ( !astOK ) return;
4430
4431 /* Get a pointer to the structure holding thread-specific global data. */
4432 astGET_GLOBALS(this);
4433
4434 /* Use the "set" and "helpful" flags, along with the Channel's
4435 attributes to decide whether this value should actually be
4436 written. */
4437 if ( Use( this, set, helpful, status ) ) {
4438
4439 /* Start building a dynamic string with an initial space, or a comment
4440 character if "set" is zero. Then add further spaces to suit the
4441 current indentation level. */
4442 line = astAppendString( NULL, &nc, set ? " " : "#" );
4443 for ( i = 0; i < current_indent; i++ ) {
4444 line = astAppendString( line, &nc, " " );
4445 }
4446
4447 /* Append the name string followed by " = ". */
4448 line = astAppendString( line, &nc, name );
4449 line = astAppendString( line, &nc, " = " );
4450
4451 /* Format the value as a decimal string and append this. */
4452 (void) sprintf( buff, "%d", value );
4453 line = astAppendString( line, &nc, buff );
4454
4455 /* If required, also append the comment. */
4456 if ( astGetComment( this ) && *comment ) {
4457 line = astAppendString( line, &nc, " \t# " );
4458 line = astAppendString( line, &nc, comment );
4459 }
4460
4461 /* Write out the resulting line of text. */
4462 OutputTextItem( this, line, status );
4463
4464 /* Free the dynamic string. */
4465 line = astFree( line );
4466 }
4467
4468 /* Undefine macros local to this function. */
4469 #undef BUFF_LEN
4470 }
4471
astWriteInvocations_(int * status)4472 int astWriteInvocations_( int *status ){
4473 /*
4474 *+
4475 * Name:
4476 * astWriteInvocations
4477
4478 * Purpose:
4479 * Returns the number of invocations of the astWrite method.
4480
4481 * Type:
4482 * Protected function.
4483
4484 * Synopsis:
4485 * #include "channel.h"
4486 * int astWriteInvocations
4487
4488 * Class Membership:
4489 * Channel method.
4490
4491 * Description:
4492 * This function returns the number of invocations of astWrite which
4493 * have been made so far, excluding those made from within the
4494 * astWriteObject method. An example of its use is to allow a Dump
4495 * function to determine if a sub-object has already been dumped
4496 * during the current invocation of astWrite. See the Dump method for
4497 * the AstUnit class as an example.
4498 *-
4499 */
4500 astDECLARE_GLOBALS
4501 astGET_GLOBALS(NULL);
4502 return nwrite_invoc;
4503 }
4504
WriteIsA(AstChannel * this,const char * class,const char * comment,int * status)4505 static void WriteIsA( AstChannel *this, const char *class,
4506 const char *comment, int *status ) {
4507 /*
4508 *+
4509 * Name:
4510 * astWriteIsA
4511
4512 * Purpose:
4513 * Write an "IsA" data item to a data sink.
4514
4515 * Type:
4516 * Protected virtual function.
4517
4518 * Synopsis:
4519 * #include "channel.h"
4520 * void astWriteIsA( AstChannel *this, const char *class,
4521 * const char *comment )
4522
4523 * Class Membership:
4524 * Channel method.
4525
4526 * Description:
4527 * This function writes an "IsA" data item to the data sink
4528 * associated with a Channel. This item delimits the end of the
4529 * data associated with the instance variables of a class, as part
4530 * of an overall Object definition.
4531
4532 * Parameters:
4533 * this
4534 * Pointer to the Channel.
4535 * class
4536 * Pointer to a constant null-terminated string containing the
4537 * name of the class whose data are terminated by the "IsA"
4538 * item.
4539 * comment
4540 * Pointer to a constant null-terminated string containing a
4541 * textual comment to be associated with the "IsA"
4542 * item. Normally, this will describe the purpose of the class
4543 * whose data are being terminated.
4544
4545 * Notes:
4546 * - The comment supplied may not actually be used, depending on
4547 * the nature of the Channel supplied.
4548 *-
4549 */
4550
4551 /* Local Variables: */
4552 astDECLARE_GLOBALS /* Declare the thread specific global data */
4553 char *line; /* Pointer to dynamic output string */
4554 int i; /* Loop counter for indentation characters */
4555 int indent_inc; /* Indentation increment */
4556 int nc; /* Number of output characters */
4557
4558 /* Check the global error status. */
4559 if ( !astOK ) return;
4560
4561 /* Get a pointer to the structure holding thread-specific global data. */
4562 astGET_GLOBALS(this);
4563
4564 /* Output an "IsA" item only if there has been at least one item
4565 written since the last "Begin" or "IsA" item, or if the Full
4566 attribute for the Channel is greater than zero (requesting maximum
4567 information). */
4568 if ( items_written || astGetFull( this ) > 0 ) {
4569
4570 /* Start building a dynamic string with an initial space. Then add
4571 further spaces to suit the current indentation level, but reduced
4572 by one to allow the "IsA" item to match the "Begin" and "End" items
4573 which enclose it. */
4574 indent_inc = astGetIndent( this );
4575 line = astAppendString( NULL, &nc, " " );
4576 for ( i = 0; i < ( current_indent - indent_inc ); i++ ) {
4577 line = astAppendString( line, &nc, " " );
4578 }
4579
4580 /* Append the "IsA" keyword followed by the class name. */
4581 line = astAppendString( line, &nc, "IsA " );
4582 line = astAppendString( line, &nc, class );
4583
4584 /* If required, also append the comment. */
4585 if ( astGetComment( this ) && *comment ) {
4586 line = astAppendString( line, &nc, " \t# " );
4587 line = astAppendString( line, &nc, comment );
4588 }
4589
4590 /* Write out the resulting line of text. */
4591 OutputTextItem( this, line, status );
4592
4593 /* Free the dynamic string. */
4594 line = astFree( line );
4595
4596 /* Clear the count of items written for this class. */
4597 items_written = 0;
4598 }
4599 }
4600
WriteObject(AstChannel * this,const char * name,int set,int helpful,AstObject * value,const char * comment,int * status)4601 static void WriteObject( AstChannel *this, const char *name,
4602 int set, int helpful,
4603 AstObject *value, const char *comment, int *status ) {
4604 /*
4605 *+
4606 * Name:
4607 * astWriteObject
4608
4609 * Purpose:
4610 * Write an Object as a value to a data sink.
4611
4612 * Type:
4613 * Protected virtual function.
4614
4615 * Synopsis:
4616 * #include "channel.h"
4617 * void astWriteObject( AstChannel *this, const char *name,
4618 * int set, int helpful,
4619 * AstObject *value, const char *comment )
4620
4621 * Class Membership:
4622 * Channel method.
4623
4624 * Description:
4625 * This function writes an Object as a named value, representing
4626 * the value of a class instance variable, to the data sink
4627 * associated with a Channel. It is intended for use by class
4628 * "Dump" functions when writing out class information which will
4629 * subsequently be re-read.
4630
4631 * Parameters:
4632 * this
4633 * Pointer to the Channel.
4634 * name
4635 * Pointer to a constant null-terminated string containing the
4636 * name to be used to identify the value in the external
4637 * representation. This will form the key for identifying it
4638 * again when it is re-read. The name supplied should be unique
4639 * within its class.
4640 *
4641 * Mixed case may be used and will be preserved in the external
4642 * representation (where possible) for cosmetic effect. However,
4643 * case is not significant when re-reading values.
4644 *
4645 * It is recommended that a maximum of 6 alphanumeric characters
4646 * (starting with an alphabetic character) be used. This permits
4647 * maximum flexibility in adapting to standard external data
4648 * representations (e.g. FITS).
4649 * set
4650 * If this is zero, it indicates that the value being written is
4651 * a default value (or can be re-generated from other values) so
4652 * need not necessarily be written out. Such values will
4653 * typically be included in the external representation with
4654 * (e.g.) a comment character so that they are available to
4655 * human readers but will be ignored when re-read. They may also
4656 * be completely omitted in some circumstances.
4657 *
4658 * If "set" is non-zero, the value will always be explicitly
4659 * included in the external representation so that it can be
4660 * re-read.
4661 * helpful
4662 * This flag provides a hint about whether a value whose "set"
4663 * flag is zero (above) should actually appear at all in the
4664 * external representaton.
4665 *
4666 * If the external representation allows values to be "commented
4667 * out" then, by default, values will be included in this form
4668 * only if their "helpful" flag is non-zero. Otherwise, they
4669 * will be omitted entirely. When possible, omitting the more
4670 * obscure values associated with a class is recommended in
4671 * order to improve readability.
4672 *
4673 * This default behaviour may be further modified if the
4674 * Channel's Full attribute is set - either to permit all values
4675 * to be shown, or to suppress non-essential information
4676 * entirely.
4677 * value
4678 * A Pointer to the Object to be written.
4679 * comment
4680 * Pointer to a constant null-terminated string containing a
4681 * textual comment to be associated with the value.
4682 *
4683 * Note that this comment may not actually be used, depending on
4684 * the nature of the Channel supplied and the setting of its
4685 * Comment attribute.
4686 *-
4687 */
4688
4689 /* Local Variables: */
4690 astDECLARE_GLOBALS /* Declare the thread specific global data */
4691 char *line; /* Pointer to dynamic output string */
4692 int i; /* Loop counter for indentation characters */
4693 int indent_inc; /* Indentation increment */
4694 int nc; /* Number of output characters */
4695
4696 /* Check the global error status. */
4697 if ( !astOK ) return;
4698
4699 /* Get a pointer to the structure holding thread-specific global data. */
4700 astGET_GLOBALS(this);
4701
4702 /* Use the "set" and "helpful" flags, along with the Channel's
4703 attributes to decide whether this value should actually be
4704 written. */
4705 if ( Use( this, set, helpful, status ) ) {
4706
4707 /* Start building a dynamic string with an initial space, or a comment
4708 character if "set" is zero. Then add further spaces to suit the
4709 current indentation level. */
4710 line = astAppendString( NULL, &nc, set ? " " : "#" );
4711 for ( i = 0; i < current_indent; i++ ) {
4712 line = astAppendString( line, &nc, " " );
4713 }
4714
4715 /* Append the name string followed by " =". The absence of a value on
4716 the right hand side indicates an Object value, whose definition
4717 follows. */
4718 line = astAppendString( line, &nc, name );
4719 line = astAppendString( line, &nc, " =" );
4720
4721 /* If required, also append the comment. */
4722 if ( astGetComment( this ) && *comment ) {
4723 line = astAppendString( line, &nc, " \t# " );
4724 line = astAppendString( line, &nc, comment );
4725 }
4726
4727 /* Write out the resulting line of text. */
4728 OutputTextItem( this, line, status );
4729
4730 /* Free the dynamic string. */
4731 line = astFree( line );
4732
4733 /* If the value is not a default, write the Object to the Channel as
4734 well, suitably indented (this is omitted if the value is commented
4735 out). */
4736 if ( set ) {
4737 indent_inc = astGetIndent( this );
4738 current_indent += indent_inc;
4739 (void) astWrite( this, value );
4740 current_indent -= indent_inc;
4741 }
4742 }
4743 }
4744
WriteString(AstChannel * this,const char * name,int set,int helpful,const char * value,const char * comment,int * status)4745 static void WriteString( AstChannel *this, const char *name,
4746 int set, int helpful,
4747 const char *value, const char *comment, int *status ) {
4748 /*
4749 *+
4750 * Name:
4751 * astWriteString
4752
4753 * Purpose:
4754 * Write a string value to a data sink.
4755
4756 * Type:
4757 * Protected virtual function.
4758
4759 * Synopsis:
4760 * #include "channel.h"
4761 * void astWriteString( AstChannel *this, const char *name,
4762 * int set, int helpful,
4763 * const char *value, const char *comment )
4764
4765 * Class Membership:
4766 * Channel method.
4767
4768 * Description:
4769 * This function writes a named string value, representing the
4770 * value of a class instance variable, to the data sink associated
4771 * with a Channel. It is intended for use by class "Dump" functions
4772 * when writing out class information which will subsequently be
4773 * re-read.
4774
4775 * Parameters:
4776 * this
4777 * Pointer to the Channel.
4778 * name
4779 * Pointer to a constant null-terminated string containing the
4780 * name to be used to identify the value in the external
4781 * representation. This will form the key for identifying it
4782 * again when it is re-read. The name supplied should be unique
4783 * within its class.
4784 *
4785 * Mixed case may be used and will be preserved in the external
4786 * representation (where possible) for cosmetic effect. However,
4787 * case is not significant when re-reading values.
4788 *
4789 * It is recommended that a maximum of 6 alphanumeric characters
4790 * (starting with an alphabetic character) be used. This permits
4791 * maximum flexibility in adapting to standard external data
4792 * representations (e.g. FITS).
4793 * set
4794 * If this is zero, it indicates that the value being written is
4795 * a default value (or can be re-generated from other values) so
4796 * need not necessarily be written out. Such values will
4797 * typically be included in the external representation with
4798 * (e.g.) a comment character so that they are available to
4799 * human readers but will be ignored when re-read. They may also
4800 * be completely omitted in some circumstances.
4801 *
4802 * If "set" is non-zero, the value will always be explicitly
4803 * included in the external representation so that it can be
4804 * re-read.
4805 * helpful
4806 * This flag provides a hint about whether a value whose "set"
4807 * flag is zero (above) should actually appear at all in the
4808 * external representaton.
4809 *
4810 * If the external representation allows values to be "commented
4811 * out" then, by default, values will be included in this form
4812 * only if their "helpful" flag is non-zero. Otherwise, they
4813 * will be omitted entirely. When possible, omitting the more
4814 * obscure values associated with a class is recommended in
4815 * order to improve readability.
4816 *
4817 * This default behaviour may be further modified if the
4818 * Channel's Full attribute is set - either to permit all values
4819 * to be shown, or to suppress non-essential information
4820 * entirely.
4821 * value
4822 * Pointer to a constant null-terminated string containing the
4823 * value to be written.
4824 * comment
4825 * Pointer to a constant null-terminated string containing a
4826 * textual comment to be associated with the value.
4827 *
4828 * Note that this comment may not actually be used, depending on
4829 * the nature of the Channel supplied and the setting of its
4830 * Comment attribute.
4831 *-
4832 */
4833
4834 /* Local Variables: */
4835 astDECLARE_GLOBALS /* Declare the thread specific global data */
4836 char *line; /* Pointer to dynamic output string */
4837 int i; /* Loop counter for characters */
4838 int nc; /* Number of output characters */
4839 int quote; /* Quote character found? */
4840 int size; /* Size of allocated memory */
4841
4842 /* Check the global error status. */
4843 if ( !astOK ) return;
4844
4845 /* Get a pointer to the structure holding thread-specific global data. */
4846 astGET_GLOBALS(this);
4847
4848 /* Use the "set" and "helpful" flags, along with the Channel's
4849 attributes to decide whether this value should actually be
4850 written. */
4851 if ( Use( this, set, helpful, status ) ) {
4852
4853 /* Start building a dynamic string with an initial space, or a comment
4854 character if "set" is zero. Then add further spaces to suit the
4855 current indentation level. */
4856 line = astAppendString( NULL, &nc, set ? " " : "#" );
4857 for ( i = 0; i < current_indent; i++ ) {
4858 line = astAppendString( line, &nc, " " );
4859 }
4860
4861 /* Append the name string followed by " = " and an opening quote
4862 character (the string will be quoted to protect leading and
4863 trailing spaces). */
4864 line = astAppendString( line, &nc, name );
4865 line = astAppendString( line, &nc, " = \"" );
4866
4867 /* We now append the value string, but must inspect each character so
4868 that quotes (appearing inside quotes) can be doubled. Determine the
4869 current size of memory allocated for the dynamic string. */
4870 size = (int) astSizeOf( line );
4871
4872 /* Loop to inspect each character and see if it is a quote. */
4873 for ( i = 0; value[ i ]; i++ ) {
4874 quote = ( value[ i ] == '"' );
4875
4876 /* If more memory is required, extend the dynamic string (allowing for
4877 doubling of quotes and the final null) and save its new size. */
4878 if ( nc + 2 + quote > size ) {
4879 line = astGrow( line, nc + 2 + quote, sizeof( char ) );
4880 if ( astOK ) {
4881 size = (int) astSizeOf( line );
4882
4883 /* Quit if an error occurs. */
4884 } else {
4885 break;
4886 }
4887 }
4888
4889 /* Append the value character to the dynamic string, duplicating each
4890 quote character. */
4891 line[ nc++ ] = value[ i ];
4892 if ( quote ) line[ nc++ ] = '"';
4893 }
4894
4895 /* Append the closing quote. */
4896 line = astAppendString( line, &nc, "\"" );
4897
4898 /* If required, also append the comment. */
4899 if ( astGetComment( this ) && *comment ) {
4900 line = astAppendString( line, &nc, " \t# " );
4901 line = astAppendString( line, &nc, comment );
4902 }
4903
4904 /* Write out the resulting line of text. */
4905 OutputTextItem( this, line, status );
4906
4907 /* Free the dynamic string. */
4908 line = astFree( line );
4909 }
4910 }
4911
4912 /* Functions which access class attributes. */
4913 /* ---------------------------------------- */
4914 /* Implement member functions to access the attributes associated with
4915 this class using the macros defined for this purpose in the
4916 "object.h" file. */
4917
4918 /*
4919 *att++
4920 * Name:
4921 * SourceFile
4922
4923 * Purpose:
4924 * Input file from which to read data.
4925
4926 * Type:
4927 * Public attribute.
4928
4929 * Synopsis:
4930 * String.
4931
4932 * Description:
4933 * This attribute specifies the name of a file from which the Channel
4934 * should read data. If specified it is used in preference to any source
4935 * function specified when the Channel was created.
4936 *
4937 * Assigning a new value to this attribute will cause any previously
4938 * opened SourceFile to be closed. The first subsequent call to
4939 c astRead
4940 f AST_READ
4941 * will attempt to open the new file (an error will be reported if the
4942 * file cannot be opened), and read data from it. All subsequent call to
4943 c astRead
4944 f AST_READ
4945 * will read data from the new file, until the SourceFile attribute is
4946 * cleared or changed.
4947 *
4948 * Clearing the attribute causes any open SourceFile to be closed. All
4949 * subsequent data reads will use the source function specified when the
4950 * Channel was created, or will read from standard input if no source
4951 * function was specified.
4952 *
4953 * If no value has been assigned to SourceFile, a null string will be
4954 * returned if an attempt is made to get the attribute value.
4955
4956 * Notes:
4957 * - Any open SourceFile is closed when the Channel is deleted.
4958 * - If the Channel is copied or dumped
4959 c (using astCopy or astShow)
4960 f (using AST_COPY or AST_SHOW)
4961 * the SourceFile attribute is left in a cleared state in the output
4962 * Channel (i.e. the value of the SourceFile attribute is not copied).
4963
4964 * Applicability:
4965 * FitsChan
4966 * In the case of a FitsChan, the specified SourceFile supplements
4967 * the source function specified when the FitsChan was created,
4968 * rather than replacing the source function. The source file
4969 * should be a text file (not a FITS file) containing one header per
4970 * line. When a value is assigned to SourceFile, the file is opened
4971 * and read immediately, and all headers read from the file are
4972 * appended to the end of any header already in the FitsChan. The file
4973 * is then closed. Clearing the SourceFile attribute has no further
4974 * effect, other than nullifying the string (i.e. the file name)
4975 * associated with the attribute.
4976
4977 *att--
4978 */
4979
4980 /* Clear the SourceFile value by closing any open file, freeing the
4981 allocated memory and assigning a NULL pointer. */
4982 astMAKE_CLEAR(Channel,SourceFile,fn_in,((this->fd_in=(this->fd_in?(fclose(this->fd_in),NULL):NULL)),astFree(this->fn_in)))
4983
4984 /* If the SourceFile value is not set, supply a default in the form of a
4985 pointer to the constant string "". */
4986 astMAKE_GET(Channel,SourceFile,const char *,NULL,( this->fn_in ? this->fn_in : "" ))
4987
4988 /* Set a SourceFile value by closing any open file, freeing any previously
4989 allocated memory, allocating new memory, storing the string and saving
4990 the pointer to the copy. */
4991 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 )))
4992
4993 /* The SourceFile value is set if the pointer to it is not NULL. */
4994 astMAKE_TEST(Channel,SourceFile,( this->fn_in != NULL ))
4995
4996 /*
4997 *att++
4998 * Name:
4999 * SinkFile
5000
5001 * Purpose:
5002 * Output file to which to data should be written.
5003
5004 * Type:
5005 * Public attribute.
5006
5007 * Synopsis:
5008 * String.
5009
5010 * Description:
5011 * This attribute specifies the name of a file to which the Channel
5012 * should write data. If specified it is used in preference to any sink
5013 * function specified when the Channel was created.
5014 *
5015 * Assigning a new value to this attribute will cause any previously
5016 * opened SinkFile to be closed. The first subsequent call to
5017 c astWrite
5018 f AST_WRITE
5019 * will attempt to open the new file (an error will be reported if the
5020 * file cannot be opened), and write data to it. All subsequent call to
5021 c astWrite
5022 f AST_WRITE
5023 * will write data to the new file, until the SinkFile attribute is
5024 * cleared or changed.
5025 *
5026 * Clearing the attribute causes any open SinkFile to be closed. All
5027 * subsequent data writes will use the sink function specified when the
5028 * Channel was created, or will write to standard output if no sink
5029 * function was specified.
5030 *
5031 * If no value has been assigned to SinkFile, a null string will be
5032 * returned if an attempt is made to get the attribute value.
5033
5034 * Notes:
5035 * - A new SinkFile will over-write any existing file with the same
5036 * name unless the existing file is write protected, in which case an
5037 * error will be reported.
5038 * - Any open SinkFile is closed when the Channel is deleted.
5039 * - If the Channel is copied or dumped
5040 c (using astCopy or astShow)
5041 f (using AST_COPY or AST_SHOW)
5042 * the SinkFile attribute is left in a cleared state in the output
5043 * Channel (i.e. the value of the SinkFile attribute is not copied).
5044
5045 * Applicability:
5046 * FitsChan
5047 * When the FitsChan is destroyed, any headers in the FitsChan will be
5048 * written out to the sink file, if one is specified (if not, the
5049 * sink function used when the FitsChan was created is used). The
5050 * sink file is a text file (not a FITS file) containing one header
5051 * per line.
5052
5053 *att--
5054 */
5055
5056 /* Clear the SinkFile value by closing any open file, freeing the allocated
5057 memory and assigning a NULL pointer. */
5058 astMAKE_CLEAR(Channel,SinkFile,fn_out,((this->fd_out=(this->fd_out?(fclose(this->fd_out),NULL):NULL)),astFree(this->fn_out)))
5059
5060 /* If the SinkFile value is not set, supply a default in the form of a
5061 pointer to the constant string "". */
5062 astMAKE_GET(Channel,SinkFile,const char *,NULL,( this->fn_out ? this->fn_out : "" ))
5063
5064 /* Set a SinkFile value by closing any open file, freeing any previously
5065 allocated memory, allocating new memory, storing the string and saving
5066 the pointer to the copy. */
5067 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 )))
5068
5069 /* The SinkFile value is set if the pointer to it is not NULL. */
5070 astMAKE_TEST(Channel,SinkFile,( this->fn_out != NULL ))
5071
5072
5073 /*
5074 *att++
5075 * Name:
5076 * Comment
5077
5078 * Purpose:
5079 * Include textual comments in output?
5080
5081 * Type:
5082 * Public attribute.
5083
5084 * Synopsis:
5085 * Integer (boolean).
5086
5087 * Description:
5088 * This is a boolean attribute which controls whether textual
5089 * comments are to be included in the output generated by a
5090 * Channel. If included, they will describe what each item of
5091 * output represents.
5092 *
5093 * If Comment is non-zero, then comments will be included. If
5094 * it is zero, comments will be omitted.
5095
5096 * Applicability:
5097 * Channel
5098 * The default value is non-zero for a normal Channel.
5099 * FitsChan
5100 * The default value is non-zero for a FitsChan.
5101 * XmlChan
5102 * The default value is zero for an XmlChan.
5103
5104 *att--
5105 */
5106
5107 /* This is a boolean value (0 or 1) with a value of -INT_MAX when
5108 undefined but yielding a default of one. */
5109 astMAKE_CLEAR(Channel,Comment,comment,-INT_MAX)
5110 astMAKE_GET(Channel,Comment,int,0,( this->comment != -INT_MAX ? this->comment : 1 ))
5111 astMAKE_SET(Channel,Comment,int,comment,( value != 0 ))
5112 astMAKE_TEST(Channel,Comment,( this->comment != -INT_MAX ))
5113
5114 /*
5115 *att++
5116 * Name:
5117 * Full
5118
5119 * Purpose:
5120 * Set level of output detail.
5121
5122 * Type:
5123 * Public attribute.
5124
5125 * Synopsis:
5126 * Integer.
5127
5128 * Description:
5129 * This attribute is a three-state flag and takes values of -1, 0
5130 * or +1. It controls the amount of information included in the
5131 * output generated by a Channel.
5132 *
5133 * If Full is zero, then a modest amount of
5134 * non-essential but useful information will be included in the
5135 * output. If Full is negative, all non-essential information will
5136 * be suppressed to minimise the amount of output, while if it is
5137 * positive, the output will include the maximum amount of detailed
5138 * information about the Object being written.
5139
5140 * Applicability:
5141 * Channel
5142 * The default value is zero for a normal Channel.
5143 * FitsChan
5144 * The default value is zero for a FitsChan.
5145 * XmlChan
5146 * The default value is -1 for an XmlChan.
5147 * StcsChan
5148 * The default value is zero for an StcsChan. Set a positive value
5149 * to cause default values to be included in STC-S descriptions.
5150
5151 * Notes:
5152 * - All positive values supplied for this attribute are converted
5153 * to +1 and all negative values are converted to -1.
5154 *att--
5155 */
5156
5157 /* This ia a 3-state value (-1, 0 or +1) with a value of -INT_MAX when
5158 undefined but yielding a default of zero. */
5159 astMAKE_CLEAR(Channel,Full,full,-INT_MAX)
5160 astMAKE_GET(Channel,Full,int,0,( this->full != -INT_MAX ? this->full : 0 ))
5161 astMAKE_SET(Channel,Full,int,full,( value > 0 ? 1 : ( value < 0 ? -1 : 0 ) ))
5162 astMAKE_TEST(Channel,Full,( this->full != -INT_MAX ))
5163
5164 /*
5165 *att++
5166 * Name:
5167 * Indent
5168
5169 * Purpose:
5170 * Specifies the indentation to use in text produced by a Channel.
5171
5172 * Type:
5173 * Public attribute.
5174
5175 * Synopsis:
5176 * Integer (boolean).
5177
5178 * Description:
5179 * This attribute controls the indentation within the output text produced by
5180 f the AST_WRITE function.
5181 c the astWrite function.
5182 * It gives the increase in the indentation for each level in the object
5183 * heirarchy. If it is set to zero, no indentation will be used. [3]
5184
5185 * Applicability:
5186 * Channel
5187 * The default value is zero for a basic Channel.
5188 * FitsChan
5189 * The FitsChan class ignores this attribute.
5190 * StcsChan
5191 * The default value for an StcsChan is zero, which causes the entire
5192 * STC-S description is written out by a single invocation of the sink
5193 * function. The text supplied to the sink function will not contain
5194 * any linefeed characters, and each pair of adjacent words will be
5195 * separated by a single space. The text may thus be arbitrarily large
5196 * and the StcsLength attribute is ignored.
5197 *
5198 * If Indent is non-zero, then the text is written out via multiple
5199 * calls to the sink function, each call corresponding to a single
5200 * "line" of text (although no line feed characters will be inserted
5201 * by AST). The complete STC-S description is broken into lines so that:
5202 *
5203 * - the line length specified by attribute StcsLength is not exceeded
5204 * - each sub-phrase (time, space, etc.) starts on a new line
5205 * - each argument in a compound spatial region starts on a new line
5206 *
5207 * If this causes a sub-phrase to extend to two or more lines, then the
5208 * second and subsequent lines will be indented by three spaces compared
5209 * to the first line. In addition, lines within a compound spatial region
5210 * will have extra indentation to highlight the nesting produced by the
5211 * parentheses. Each new level of nesting will be indented by a further
5212 * three spaces.
5213 f
5214 f Note, the default value of zero is unlikely to be appropriate when
5215 f an StcsChan is used within Fortran code. In this case, Indent
5216 f should usually be set non-zero, and the StcsLength attribute set to
5217 f the size of the CHARACTER variable used to
5218 f receive the text returned by AST_GETLINE within the sink function.
5219 f This avoids the possibility of long lines being truncated invisibly
5220 f within AST_GETLINE.
5221 * XmlChan
5222 * The default value for an XmlChan is zero, which results in no
5223 * linefeeds or indentation strings being added to output text.
5224 * If any non-zero value is assigned to Indent, then extra linefeed and
5225 * space characters will be inserted as necessary to ensure that each
5226 * XML tag starts on a new line, and each tag will be indented by
5227 * a further 3 spaces to show its depth in the containment hierarchy.
5228 *att--
5229 */
5230
5231 /* This is an integer value with a value of -INT_MAX when undefined,
5232 yielding a default of 3. Sub-classes may over-ride theis default. */
5233 astMAKE_CLEAR(Channel,Indent,indent,-INT_MAX)
5234 astMAKE_GET(Channel,Indent,int,3,( this->indent != -INT_MAX ? this->indent : 3 ))
astMAKE_SET(Channel,Indent,int,indent,value)5235 astMAKE_SET(Channel,Indent,int,indent,value)
5236 astMAKE_TEST(Channel,Indent,( this->indent != -INT_MAX ))
5237
5238 /*
5239 *att++
5240 * Name:
5241 * ReportLevel
5242
5243 * Purpose:
5244 * Determines which read/write conditions are reported.
5245
5246 * Type:
5247 * Public attribute.
5248
5249 * Synopsis:
5250 * Integer (boolean).
5251
5252 * Description:
5253 * This attribute determines which, if any, of the conditions that occur
5254 * whilst reading or writing an Object should be reported. These
5255 * conditions will generate either a fatal error or a warning, as
5256 * determined by attribute Strict. ReportLevel can take any of the
5257 * following values:
5258 *
5259 * 0 - Do not report any conditions.
5260 *
5261 * 1 - Report only conditions where significant information content has been
5262 * changed. For instance, an unsupported time-scale has been replaced by a
5263 * supported near-equivalent time-scale. Another example is if a basic
5264 * Channel unexpected encounters data items that may have been introduced
5265 * by later versions of AST.
5266 *
5267 * 2 - Report the above, and in addition report significant default
5268 * values. For instance, if no time-scale was specified when reading an
5269 * Object from an external data source, report the default time-scale
5270 * that is being used.
5271 *
5272 * 3 - Report the above, and in addition report any other potentially
5273 * interesting conditions that have no significant effect on the
5274 * conversion. For instance, report if a time-scale of "TT"
5275 * (terrestrial time) is used in place of "ET" (ephemeris time). This
5276 * change has no signficiant effect because ET is the predecessor of,
5277 * and is continuous with, TT. Synonyms such as "IAT" and "TAI" are
5278 * another example.
5279 *
5280 * The default value is 1. Note, there are many other conditions that
5281 * can occur whilst reading or writing an Object that completely
5282 * prevent the conversion taking place. Such conditions will always
5283 * generate errors, irrespective of the ReportLevel and Strict attributes.
5284
5285 * Applicability:
5286 * Channel
5287 * All Channels have this attribute.
5288 * FitsChan
5289 * All the conditions selected by the FitsChan Warnings attribute are
5290 * reported at level 1.
5291 *att--
5292 */
5293
5294 /* This is an integer value with a value of -INT_MAX when undefined,
5295 yielding a default of one. */
5296 astMAKE_CLEAR(Channel,ReportLevel,report_level,-INT_MAX)
5297 astMAKE_GET(Channel,ReportLevel,int,1,( this->report_level != -INT_MAX ? this->report_level : 1 ))
5298 astMAKE_SET(Channel,ReportLevel,int,report_level,value)
5299 astMAKE_TEST(Channel,ReportLevel,( this->report_level != -INT_MAX ))
5300
5301 /*
5302 *att++
5303 * Name:
5304 * Skip
5305
5306 * Purpose:
5307 * Skip irrelevant data?
5308
5309 * Type:
5310 * Public attribute.
5311
5312 * Synopsis:
5313 * Integer (boolean).
5314
5315 * Description:
5316 * This is a boolean attribute which indicates whether the Object
5317 * data being read through a Channel are inter-mixed with other,
5318 * irrelevant, external data.
5319 *
5320 * If Skip is zero (the default), then the source of input data is
5321 * expected to contain descriptions of AST Objects and comments and
5322 * nothing else (if anything else is read, an error will
5323 * result). If Skip is non-zero, then any non-Object data
5324 * encountered between Objects will be ignored and simply skipped
5325 * over in order to reach the next Object.
5326
5327 * Applicability:
5328 * Channel
5329 * All Channels have this attribute.
5330 * FitsChan
5331 * The FitsChan class sets the default value of this attribute
5332 * to 1, so that all irrelevant FITS headers will normally be
5333 * ignored.
5334 *att--
5335 */
5336
5337 /* This ia a boolean value (0 or 1) with a value of -INT_MAX when
5338 undefined but yielding a default of zero. */
5339 astMAKE_CLEAR(Channel,Skip,skip,-INT_MAX)
5340 astMAKE_GET(Channel,Skip,int,0,( this->skip != -INT_MAX ? this->skip : 0 ))
5341 astMAKE_SET(Channel,Skip,int,skip,( value != 0 ))
5342 astMAKE_TEST(Channel,Skip,( this->skip != -INT_MAX ))
5343
5344 /*
5345 *att++
5346 * Name:
5347 * Strict
5348
5349 * Purpose:
5350 * Report an error if any unexpeted data items are found?
5351
5352 * Type:
5353 * Public attribute.
5354
5355 * Synopsis:
5356 * Integer (boolean).
5357
5358 * Description:
5359 * This is a boolean attribute which indicates whether a warning
5360 * rather than an error should be issed for insignificant conversion
5361 * problems. If it is set non-zero, then fatal errors are issued
5362 * instead of warnings, resulting in the
5363 c AST error status being set.
5364 f inherited STATUS variable being set to an error value.
5365 * If Strict is zero (the default), then execution continues after minor
5366 * conversion problems, and a warning message is added to the Channel
5367 * structure. Such messages can be retrieved using the
5368 c astWarnings
5369 f AST_WARNINGS
5370 * function.
5371
5372 * Notes:
5373 * - This attribute was introduced in AST version 5.0. Prior to this
5374 * version of AST unexpected data items read by a basic Channel always
5375 * caused an error to be reported. So applications linked against
5376 * versions of AST prior to version 5.0 may not be able to read Object
5377 * descriptions created by later versions of AST, if the Object's class
5378 * description has changed.
5379
5380 * Applicability:
5381 * Channel
5382 * All Channels have this attribute.
5383 *att--
5384 */
5385
5386 /* This ia a boolean value (0 or 1) with a value of -INT_MAX when
5387 undefined but yielding a default of zero. */
5388 astMAKE_CLEAR(Channel,Strict,strict,-INT_MAX)
5389 astMAKE_GET(Channel,Strict,int,0,( this->strict != -INT_MAX ? this->strict : 0 ))
5390 astMAKE_SET(Channel,Strict,int,strict,( value != 0 ))
5391 astMAKE_TEST(Channel,Strict,( this->strict != -INT_MAX ))
5392
5393 /* Destructor. */
5394 /* ----------- */
5395 static void Delete( AstObject *obj, int *status ) {
5396 /*
5397 * Name:
5398 * Delete
5399
5400 * Purpose:
5401 * Destructor for Channel objects.
5402
5403 * Type:
5404 * Private function.
5405
5406 * Synopsis:
5407 * void Delete( AstObject *obj, int *status )
5408
5409 * Description:
5410 * This function implements the destructor for Channel objects.
5411
5412 * Parameters:
5413 * obj
5414 * Pointer to the object to be deleted.
5415 * status
5416 * Pointer to the inherited status variable.
5417
5418 * Notes:
5419 * This function attempts to execute even if the global error status is
5420 * set.
5421 */
5422
5423 /* Local Variables: */
5424 AstChannel *this; /* Pointer to Channel */
5425
5426 /* Obtain a pointer to the Channel structure. */
5427 this = (AstChannel *) obj;
5428
5429 /* Free memory used to store warnings. */
5430 astAddWarning( this, 0, NULL, NULL, status );
5431
5432 /* Close any open input or output files. */
5433 if( this->fd_in ) fclose( this->fd_in );
5434 if( this->fd_out ) fclose( this->fd_out );
5435
5436 /* Free file name memory. */
5437 this->fn_in = astFree( this->fn_in );
5438 this->fn_out = astFree( this->fn_out );
5439 }
5440
5441 /* Copy constructor. */
5442 /* ----------------- */
Copy(const AstObject * objin,AstObject * objout,int * status)5443 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
5444 /*
5445 * Name:
5446 * Copy
5447
5448 * Purpose:
5449 * Copy constructor for Channel objects.
5450
5451 * Type:
5452 * Private function.
5453
5454 * Synopsis:
5455 * void Copy( const AstObject *objin, AstObject *objout, int *status )
5456
5457 * Description:
5458 * This function implements the copy constructor for Channel objects.
5459
5460 * Parameters:
5461 * objin
5462 * Pointer to the object to be copied.
5463 * objout
5464 * Pointer to the object being constructed.
5465 * status
5466 * Pointer to the inherited status variable.
5467
5468 * Notes:
5469 * - This constructor makes a deep copy.
5470 */
5471
5472 /* Local Variables: */
5473 AstChannel *out; /* Pointer to output Channel */
5474
5475 /* Check the global error status. */
5476 if ( !astOK ) return;
5477
5478 /* Obtain pointers to the input and output Channels. */
5479 out = (AstChannel *) objout;
5480
5481 /* Just clear any references to the input memory from the output Channel. */
5482 out->warnings = NULL;
5483 out->nwarn = 0;
5484 out->fd_in = NULL;
5485 out->fn_in = NULL;
5486 out->fd_out = NULL;
5487 out->fn_out = NULL;
5488 }
5489
5490 /* Dump function. */
5491 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)5492 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
5493 /*
5494 * Name:
5495 * Dump
5496
5497 * Purpose:
5498 * Dump function for Channel objects.
5499
5500 * Type:
5501 * Private function.
5502
5503 * Synopsis:
5504 * void Dump( AstObject *this, AstChannel *channel, int *status )
5505
5506 * Description:
5507 * This function implements the Dump function which writes out data
5508 * for the Channel class to an output Channel.
5509
5510 * Parameters:
5511 * this
5512 * Pointer to the Object whose data are being written.
5513 * channel
5514 * Pointer to the Channel to which the data are being written.
5515 * status
5516 * Pointer to the inherited status variable.
5517 */
5518
5519 /* Local Variables: */
5520 AstChannel *this; /* Pointer to the Channel structure */
5521 const char *comment; /* Pointer to comment string */
5522 int ival; /* Integer value */
5523 int set; /* Attribute value set? */
5524
5525 /* Check the global error status. */
5526 if ( !astOK ) return;
5527
5528 /* Obtain a pointer to the Channel structure. */
5529 this = (AstChannel *) this_object;
5530
5531 /* Write out values representing the instance variables for the
5532 Channel class. Accompany these with appropriate comment strings,
5533 possibly depending on the values being written.*/
5534
5535 /* In the case of attributes, we first use the appropriate (private)
5536 Test... member function to see if they are set. If so, we then use
5537 the (private) Get... function to obtain the value to be written
5538 out.
5539
5540 For attributes which are not set, we use the astGet... method to
5541 obtain the value instead. This will supply a default value
5542 (possibly provided by a derived class which over-rides this method)
5543 which is more useful to a human reader as it corresponds to the
5544 actual default attribute value. Since "set" will be zero, these
5545 values are for information only and will not be read back. */
5546
5547 /* Indent */
5548 /* ------------ */
5549 set = TestIndent( this, status );
5550 ival = set ? GetIndent( this, status ) : astGetIndent( this );
5551 astWriteInt( channel, "Indnt", set, 0, ival, "Indentation increment" );
5552
5553 /* ReportLevel. */
5554 /* ------------ */
5555 set = TestReportLevel( this, status );
5556 ival = set ? GetReportLevel( this, status ) : astGetReportLevel( this );
5557 astWriteInt( channel, "RpLev", set, 0, ival, "Error reporting level" );
5558
5559 /* Skip. */
5560 /* ----- */
5561 set = TestSkip( this, status );
5562 ival = set ? GetSkip( this, status ) : astGetSkip( this );
5563 astWriteInt( channel, "Skip", set, 0, ival,
5564 ival ? "Ignore data between Objects" :
5565 "No data allowed between Objects" );
5566
5567 /* Strict. */
5568 /* ------- */
5569 set = TestStrict( this, status );
5570 ival = set ? GetStrict( this, status ) : astGetStrict( this );
5571 astWriteInt( channel, "Strict", set, 0, ival,
5572 ival ? "Report errors insead of warnings" :
5573 "Report warnings instead of errors" );
5574
5575 /* Full. */
5576 /* ----- */
5577 set = TestFull( this, status );
5578 ival = set ? GetFull( this, status ) : astGetFull( this );
5579 if ( ival < 0 ) {
5580 comment = "Suppress non-essential output";
5581 }else if ( ival == 0 ) {
5582 comment = "Output standard information";
5583 } else {
5584 comment = "Output maximum information";
5585 }
5586 astWriteInt( channel, "Full", set, 0, ival, comment );
5587
5588 /* Comment. */
5589 /* -------- */
5590 set = TestComment( this, status );
5591 ival = set ? GetComment( this, status ) : astGetComment( this );
5592 astWriteInt( channel, "Comm", set, 0, ival,
5593 ival ? "Display comments" :
5594 "Omit comments" );
5595 }
5596
5597 /* Standard class functions. */
5598 /* ========================= */
5599 /* Implement the astIsAChannel and astCheckChannel functions using the
5600 macros defined for this purpose in the "object.h" header file. */
astMAKE_ISA(Channel,Object)5601 astMAKE_ISA(Channel,Object)
5602 astMAKE_CHECK(Channel)
5603
5604 AstChannel *astChannel_( const char *(* source)( void ),
5605 void (* sink)( const char * ),
5606 const char *options, int *status, ...) {
5607 /*
5608 *+
5609 * Name:
5610 * astChannel
5611
5612 * Purpose:
5613 * Create a Channel.
5614
5615 * Type:
5616 * Protected function.
5617
5618 * Synopsis:
5619 * #include "channel.h"
5620 * AstChannel *astChannel( const char *(* source)( void ),
5621 * void (* sink)( const char * ),
5622 * const char *options, ..., int *status )
5623
5624 * Class Membership:
5625 * Channel constructor.
5626
5627 * Description:
5628 * This function creates a new Channel and optionally initialises
5629 * its attributes.
5630 *
5631 * A Channel implements low-level input/output for the AST library.
5632 * Writing an Object to a Channel (using astWrite) will generate a
5633 * textual representation of that Object, and reading from a
5634 * Channel (using astRead) will create a new Object from its
5635 * textual representation.
5636 *
5637 * Normally, when you use a Channel, you should provide "source"
5638 * and "sink" functions which connect it to an external data store
5639 * by reading and writing the resulting text. By default, however,
5640 * a Channel will read from standard input and write to standard
5641 * output.
5642
5643 * Parameters:
5644 * source
5645 * Pointer to a "source" function that takes no arguments and
5646 * returns a pointer to a null-terminated string.
5647 *
5648 * This function will be used by the Channel to obtain lines of
5649 * input text. On each invocation, it should return a pointer to
5650 * the next input line read from some external data store, and a
5651 * NULL pointer when there are no more lines to read.
5652 *
5653 * If "source" is NULL, the Channel will read from standard
5654 * input instead.
5655 * sink
5656 * Pointer to a "sink" function that takes a pointer to a
5657 * null-terminated string as an argument and returns void.
5658 *
5659 * This function will be used by the Channel to deliver lines of
5660 * output text. On each invocation, it should deliver the
5661 * contents of the string supplied to some external data store.
5662 *
5663 * If "sink" is NULL, the Channel will write to standard output
5664 * instead.
5665 * options
5666 * Pointer to a null-terminated string containing an optional
5667 * comma-separated list of attribute assignments to be used for
5668 * initialising the new Channel. The syntax used is identical to
5669 * that for the astSet function and may include "printf" format
5670 * specifiers identified by "%" symbols in the normal way.
5671 * status
5672 * Pointer to the inherited status variable.
5673 * ...
5674 * If the "options" string contains "%" format specifiers, then
5675 * an optional list of additional arguments may follow it in
5676 * order to supply values to be substituted for these
5677 * specifiers. The rules for supplying these are identical to
5678 * those for the astSet function (and for the C "printf"
5679 * function).
5680
5681 * Returned Value:
5682 * astChannel()
5683 * A pointer to the new Channel.
5684
5685 * Notes:
5686 * - A NULL pointer value will be returned if this function is
5687 * invoked with the global error status set, or if it should fail
5688 * for any reason.
5689 *-
5690
5691 * Implementation Notes:
5692 * - This function implements the basic Channel constructor which
5693 * is available via the protected interface to the Channel class.
5694 * A public interface is provided by the astChannelId_ function.
5695 */
5696
5697 /* Local Variables: */
5698 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
5699 AstChannel *new; /* Pointer to new Channel */
5700 va_list args; /* Variable argument list */
5701
5702 /* Get a pointer to the thread specific global data structure. */
5703 astGET_GLOBALS(NULL);
5704
5705 /* Check the global status. */
5706 if ( !astOK ) return NULL;
5707
5708 /* Initialise the Channel, allocating memory and initialising the
5709 virtual function table as well if necessary. Supply pointers to
5710 (local) wrapper functions that can invoke the source and sink
5711 functions with appropriate arguments for the C language. */
5712 new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab,
5713 "Channel", source, SourceWrap, sink, SinkWrap );
5714
5715 /* If successful, note that the virtual function table has been
5716 initialised. */
5717 if ( astOK ) {
5718 class_init = 1;
5719
5720 /* Obtain the variable argument list and pass it along with the
5721 options string to the astVSet method to initialise the new
5722 Channel's attributes. */
5723 va_start( args, status );
5724 astVSet( new, options, NULL, args );
5725 va_end( args );
5726
5727 /* If an error occurred, clean up by deleting the new object. */
5728 if ( !astOK ) new = astDelete( new );
5729 }
5730
5731 /* Return a pointer to the new Channel. */
5732 return new;
5733 }
5734
astChannelId_(const char * (* source)(void),void (* sink)(const char *),const char * options,...)5735 AstChannel *astChannelId_( const char *(* source)( void ),
5736 void (* sink)( const char * ),
5737 const char *options, ... ) {
5738 /*
5739 *++
5740 * Name:
5741 c astChannel
5742 f AST_CHANNEL
5743
5744 * Purpose:
5745 * Create a Channel.
5746
5747 * Type:
5748 * Public function.
5749
5750 * Synopsis:
5751 c #include "channel.h"
5752 c AstChannel *astChannel( const char *(* source)( void ),
5753 c void (* sink)( const char * ),
5754 c const char *options, ... )
5755 f RESULT = AST_CHANNEL( SOURCE, SINK, OPTIONS, STATUS )
5756
5757 * Class Membership:
5758 * Channel constructor.
5759
5760 * Description:
5761 * This function creates a new Channel and optionally initialises
5762 * its attributes.
5763 *
5764 * A Channel implements low-level input/output for the AST library.
5765 c Writing an Object to a Channel (using astWrite) will generate a
5766 f Writing an Object to a Channel (using AST_WRITE) will generate a
5767 * textual representation of that Object, and reading from a
5768 c Channel (using astRead) will create a new Object from its
5769 f Channel (using AST_READ) will create a new Object from its
5770 * textual representation.
5771 *
5772 * Normally, when you use a Channel, you should provide "source"
5773 c and "sink" functions which connect it to an external data store
5774 f and "sink" routines which connect it to an external data store
5775 * by reading and writing the resulting text. By default, however,
5776 * a Channel will read from standard input and write to standard
5777 * output. Alternatively, a Channel can be told to read or write from
5778 * specific text files using the SinkFile and SourceFile attributes,
5779 * in which case no sink or source function need be supplied.
5780
5781 * Parameters:
5782 c source
5783 f SOURCE = SUBROUTINE (Given)
5784 c Pointer to a source function that takes no arguments and
5785 c returns a pointer to a null-terminated string. If no value
5786 c has been set for the SourceFile attribute, this function
5787 c will be used by the Channel to obtain lines of input text. On
5788 c each invocation, it should return a pointer to the next input
5789 c line read from some external data store, and a NULL pointer
5790 c when there are no more lines to read.
5791 c
5792 c If "source" is NULL and no value has been set for the SourceFile
5793 c attribute, the Channel will read from standard input instead.
5794 f A source routine, which is a subroutine which takes a single
5795 f integer error status argument. If no value has been set
5796 f for the SourceFile attribute, this routine will be used by
5797 f the Channel to obtain lines of input text. On each
5798 f invocation, it should read the next input line from some
5799 f external data store, and then return the resulting text to
5800 f the AST library by calling AST_PUTLINE. It should supply a
5801 f negative line length when there are no more lines to read.
5802 f If an error occurs, it should set its own error status
5803 f argument to an error value before returning.
5804 f
5805 f If the null routine AST_NULL is suppied as the SOURCE value,
5806 f and no value has been set for the SourceFile attribute,
5807 f the Channel will read from standard input instead.
5808 c sink
5809 f SINK = SUBROUTINE (Given)
5810 c Pointer to a sink function that takes a pointer to a
5811 c null-terminated string as an argument and returns void.
5812 c If no value has been set for the SinkFile attribute, this
5813 c function will be used by the Channel to deliver lines of
5814 c output text. On each invocation, it should deliver the
5815 c contents of the string supplied to some external data store.
5816 c
5817 c If "sink" is NULL, and no value has been set for the SinkFile
5818 c attribute, the Channel will write to standard output instead.
5819 f A sink routine, which is a subroutine which takes a single
5820 f integer error status argument. If no value has been set
5821 f for the SinkFile attribute, this routine will be used by
5822 f the Channel to deliver lines of output text. On each
5823 f invocation, it should obtain the next output line from the
5824 f AST library by calling AST_GETLINE, and then deliver the
5825 f resulting text to some external data store. If an error
5826 f occurs, it should set its own error status argument to an
5827 f error value before returning.
5828 f
5829 f If the null routine AST_NULL is suppied as the SINK value,
5830 f and no value has been set for the SinkFile attribute,
5831 f the Channel will write to standard output instead.
5832 c options
5833 f OPTIONS = CHARACTER * ( * ) (Given)
5834 c Pointer to a null-terminated string containing an optional
5835 c comma-separated list of attribute assignments to be used for
5836 c initialising the new Channel. The syntax used is identical to
5837 c that for the astSet function and may include "printf" format
5838 c specifiers identified by "%" symbols in the normal way.
5839 f A character string containing an optional comma-separated
5840 f list of attribute assignments to be used for initialising the
5841 f new Channel. The syntax used is identical to that for the
5842 f AST_SET routine.
5843 c ...
5844 c If the "options" string contains "%" format specifiers, then
5845 c an optional list of additional arguments may follow it in
5846 c order to supply values to be substituted for these
5847 c specifiers. The rules for supplying these are identical to
5848 c those for the astSet function (and for the C "printf"
5849 c function).
5850 f STATUS = INTEGER (Given and Returned)
5851 f The global status.
5852
5853 * Returned Value:
5854 c astChannel()
5855 f AST_CHANNEL = INTEGER
5856 * A pointer to the new Channel.
5857
5858 * Notes:
5859 c - Application code can pass arbitrary data (such as file
5860 c descriptors, etc) to source and sink functions using the
5861 c astPutChannelData function. The source or sink function should use
5862 c the astChannelData macro to retrieve this data.
5863 f - The names of the routines supplied for the SOURCE and SINK
5864 f arguments should appear in EXTERNAL statements in the Fortran
5865 f routine which invokes AST_CHANNEL. However, this is not generally
5866 f necessary for the null routine AST_NULL (so long as the AST_PAR
5867 f include file has been used).
5868 * - A null Object pointer (AST__NULL) will be returned if this
5869 c function is invoked with the AST error status set, or if it
5870 f function is invoked with STATUS set to an error value, or if it
5871 * should fail for any reason.
5872 f - Note that the null routine AST_NULL (one underscore) is
5873 f different to AST__NULL (two underscores), which is the null Object
5874 f pointer.
5875 *--
5876
5877 * Implementation Notes:
5878 * - This function implements the external (public) interface to
5879 * the astChannel constructor function. It returns an ID value
5880 * (instead of a true C pointer) to external users, and must be
5881 * provided because astChannel_ has a variable argument list which
5882 * cannot be encapsulated in a macro (where this conversion would
5883 * otherwise occur).
5884 * - The variable argument list also prevents this function from
5885 * invoking astChanel_ directly, so it must be a re-implementation
5886 * of it in all respects, except for the final conversion of the
5887 * result to an ID value.
5888 */
5889
5890 /* Local Variables: */
5891 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
5892 AstChannel *new; /* Pointer to new Channel */
5893 va_list args; /* Variable argument list */
5894
5895 int *status; /* Pointer to inherited status value */
5896
5897 /* Get a pointer to the inherited status value. */
5898 status = astGetStatusPtr;
5899
5900 /* Get a pointer to the thread specific global data structure. */
5901 astGET_GLOBALS(NULL);
5902
5903 /* Check the global status. */
5904 if ( !astOK ) return NULL;
5905
5906 /* Initialise the Channel, allocating memory and initialising the
5907 virtual function table as well if necessary. Supply pointers to
5908 (local) wrapper functions that can invoke the source and sink
5909 functions with appropriate arguments for the C language. */
5910 new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab,
5911 "Channel", source, SourceWrap, sink, SinkWrap );
5912
5913 /* If successful, note that the virtual function table has been
5914 initialised. */
5915 if ( astOK ) {
5916 class_init = 1;
5917
5918 /* Obtain the variable argument list and pass it along with the
5919 options string to the astVSet method to initialise the new
5920 Channel's attributes. */
5921 va_start( args, options );
5922 astVSet( new, options, NULL, args );
5923 va_end( args );
5924
5925 /* If an error occurred, clean up by deleting the new object. */
5926 if ( !astOK ) new = astDelete( new );
5927 }
5928
5929 /* Return an ID value for the new Channel. */
5930 return astMakeId( new );
5931 }
5932
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,...)5933 AstChannel *astChannelForId_( const char *(* source)( void ),
5934 char *(* source_wrap)( const char *(*)( void ), int * ),
5935 void (* sink)( const char * ),
5936 void (* sink_wrap)( void (*)( const char * ),
5937 const char *, int * ),
5938 const char *options, ... ) {
5939 /*
5940 *+
5941 * Name:
5942 * astChannelFor
5943
5944 * Purpose:
5945 * Initialise a Channel from a foreign language interface.
5946
5947 * Type:
5948 * Public function.
5949
5950 * Synopsis:
5951 * #include "channel.h"
5952 * AstChannel *astChannelFor( const char *(* source)( void ),
5953 * char *(* source_wrap)( const char *(*)
5954 * ( void ), int * ),
5955 * void (* sink)( const char * ),
5956 * void (* sink_wrap)( void (*)( const char * ),
5957 * const char *, int * ),
5958 * const char *options, ... )
5959
5960 * Class Membership:
5961 * Channel constructor.
5962
5963 * Description:
5964 * This function creates a new Channel from a foreign language
5965 * interface and optionally initialises its attributes.
5966 *
5967 * A Channel implements low-level input/output for the AST library.
5968 * Writing an Object to a Channel (using astWrite) will generate a
5969 * textual representation of that Object, and reading from a
5970 * Channel (using astRead) will create a new Object from its
5971 * textual representation.
5972 *
5973 * Normally, when you use a Channel, you should provide "source"
5974 * and "sink" functions which connect it to an external data store
5975 * by reading and writing the resulting text. This function also
5976 * requires you to provide "wrapper" functions which will invoke
5977 * the source and sink functions. By default, however, a Channel
5978 * will read from standard input and write to standard output.
5979
5980 * Parameters:
5981 * source
5982 * Pointer to a "source" function which will be used to obtain
5983 * lines of input text. Generally, this will be obtained by
5984 * casting a pointer to a source function which is compatible
5985 * with the "source_wrap" wrapper function (below). The pointer
5986 * should later be cast back to its original type by the
5987 * "source_wrap" function before the function is invoked.
5988 *
5989 * If "source" is NULL, the Channel will read from standard
5990 * input instead.
5991 * source_wrap
5992 * Pointer to a function which can be used to invoke the
5993 * "source" function supplied (above). This wrapper function is
5994 * necessary in order to hide variations in the nature of the
5995 * source function, such as may arise when it is supplied by a
5996 * foreign (non-C) language interface.
5997 *
5998 * The single parameter of the "source_wrap" function is a
5999 * pointer to the "source" function, and it should cast this
6000 * function pointer (as necessary) and invoke the function with
6001 * appropriate arguments to obtain the next line of input
6002 * text. The "source_wrap" function should then return a pointer
6003 * to a dynamically allocated, null terminated string containing
6004 * the text that was read. The string will be freed (using
6005 * astFree) when no longer required and the "source_wrap"
6006 * function need not concern itself with this. A NULL pointer
6007 * should be returned if there is no more input to read.
6008 *
6009 * If "source_wrap" is NULL, the Channel will read from standard
6010 * input instead.
6011 * sink
6012 * Pointer to a "sink" function which will be used to deliver
6013 * lines of output text. Generally, this will be obtained by
6014 * casting a pointer to a sink function which is compatible with
6015 * the "sink_wrap" wrapper function (below). The pointer should
6016 * later be cast back to its original type by the "sink_wrap"
6017 * function before the function is invoked.
6018 *
6019 * If "sink" is NULL, the Channel will write to standard output
6020 * instead.
6021 * sink_wrap
6022 * Pointer to a function which can be used to invoke the "sink"
6023 * function supplied (above). This wrapper function is necessary
6024 * in order to hide variations in the nature of the sink
6025 * function, such as may arise when it is supplied by a foreign
6026 * (non-C) language interface.
6027 *
6028 * The first parameter of the "sink_wrap" function is a pointer
6029 * to the "sink" function, and the second parameter is a pointer
6030 * to a const, null-terminated character string containing the
6031 * text to be written. The "sink_wrap" function should cast the
6032 * "sink" function pointer (as necessary) and invoke the
6033 * function with appropriate arguments to deliver the line of
6034 * output text. The "sink_wrap" function then returns void.
6035 *
6036 * If "sink_wrap" is NULL, the Channel will write to standard
6037 * output instead.
6038 * options
6039 * Pointer to a null-terminated string containing an optional
6040 * comma-separated list of attribute assignments to be used for
6041 * initialising the new Channel. The syntax used is identical to
6042 * that for the astSet function and may include "printf" format
6043 * specifiers identified by "%" symbols in the normal way.
6044 * ...
6045 * If the "options" string contains "%" format specifiers, then
6046 * an optional list of additional arguments may follow it in
6047 * order to supply values to be substituted for these
6048 * specifiers. The rules for supplying these are identical to
6049 * those for the astSet function (and for the C "printf"
6050 * function).
6051
6052 * Returned Value:
6053 * astChannelFor()
6054 * A pointer to the new Channel.
6055
6056 * Notes:
6057 * - A null Object pointer (AST__NULL) will be returned if this
6058 * function is invoked with the global error status set, or if it
6059 * should fail for any reason.
6060 * - This function is only available through the public interface
6061 * to the Channel class (not the protected interface) and is
6062 * intended solely for use in implementing foreign language
6063 * interfaces to this class.
6064 *-
6065
6066 * Implememtation Notes:
6067 * - This function behaves exactly like astChannelId_, in that it
6068 * returns ID values and not true C pointers, but it has two
6069 * additional arguments. These are pointers to the "wrapper
6070 * functions" which are needed to accommodate foreign language
6071 * interfaces.
6072 */
6073
6074 /* Local Variables: */
6075 astDECLARE_GLOBALS /* Declare the thread specific global data */
6076 AstChannel *new; /* Pointer to new Channel */
6077 va_list args; /* Variable argument list */
6078 int *status; /* Pointer to inherited status value */
6079
6080 /* Get a pointer to the inherited status value. */
6081 status = astGetStatusPtr;
6082
6083 /* Check the global status. */
6084 if ( !astOK ) return NULL;
6085
6086 /* Get a pointer to the thread specific global data structure. */
6087 astGET_GLOBALS(NULL);
6088
6089 /* Initialise the Channel, allocating memory and initialising the
6090 virtual function table as well if necessary. */
6091 new = astInitChannel( NULL, sizeof( AstChannel ), !class_init, &class_vtab,
6092 "Channel", source, source_wrap, sink, sink_wrap );
6093
6094 /* If successful, note that the virtual function table has been
6095 initialised. */
6096 if ( astOK ) {
6097 class_init = 1;
6098
6099 /* Obtain the variable argument list and pass it along with the
6100 options string to the astVSet method to initialise the new
6101 Channel's attributes. */
6102 va_start( args, options );
6103 astVSet( new, options, NULL, args );
6104 va_end( args );
6105
6106 /* If an error occurred, clean up by deleting the new object. */
6107 if ( !astOK ) new = astDelete( new );
6108 }
6109
6110 /* Return an ID value for the new Channel. */
6111 return astMakeId( new );
6112 }
6113
astLoadChannel_(void * mem,size_t size,AstChannelVtab * vtab,const char * name,AstChannel * channel,int * status)6114 AstChannel *astLoadChannel_( void *mem, size_t size,
6115 AstChannelVtab *vtab, const char *name,
6116 AstChannel *channel, int *status ) {
6117 /*
6118 *+
6119 * Name:
6120 * astLoadChannel
6121
6122 * Purpose:
6123 * Load a Channel.
6124
6125 * Type:
6126 * Protected function.
6127
6128 * Synopsis:
6129 * #include "channel.h"
6130 * AstChannel *astLoadChannel( void *mem, size_t size,
6131 * AstChannelVtab *vtab, const char *name,
6132 * AstChannel *channel )
6133
6134 * Class Membership:
6135 * Channel loader.
6136
6137 * Description:
6138 * This function is provided to load a new Channel using data read
6139 * from a Channel. It first loads the data used by the parent class
6140 * (which allocates memory if necessary) and then initialises a
6141 * Channel structure in this memory, using data read from the input
6142 * Channel.
6143 *
6144 * If the "init" flag is set, it also initialises the contents of a
6145 * virtual function table for a Channel at the start of the memory
6146 * passed via the "vtab" parameter.
6147
6148
6149 * Parameters:
6150 * mem
6151 * A pointer to the memory into which the Channel is to be
6152 * loaded. This must be of sufficient size to accommodate the
6153 * Channel data (sizeof(Channel)) plus any data used by derived
6154 * classes. If a value of NULL is given, this function will
6155 * allocate the memory itself using the "size" parameter to
6156 * determine its size.
6157 * size
6158 * The amount of memory used by the Channel (plus derived class
6159 * data). This will be used to allocate memory if a value of
6160 * NULL is given for the "mem" parameter. This value is also
6161 * stored in the Channel structure, so a valid value must be
6162 * supplied even if not required for allocating memory.
6163 *
6164 * If the "vtab" parameter is NULL, the "size" value is ignored
6165 * and sizeof(AstChannel) is used instead.
6166 * vtab
6167 * Pointer to the start of the virtual function table to be
6168 * associated with the new Channel. If this is NULL, a pointer
6169 * to the (static) virtual function table for the Channel class
6170 * is used instead.
6171 * name
6172 * Pointer to a constant null-terminated character string which
6173 * contains the name of the class to which the new object
6174 * belongs (it is this pointer value that will subsequently be
6175 * returned by the astGetClass method).
6176 *
6177 * If the "vtab" parameter is NULL, the "name" value is ignored
6178 * and a pointer to the string "Channel" is used instead.
6179
6180 * Returned Value:
6181 * A pointer to the new Channel.
6182
6183 * Notes:
6184 * - A null pointer will be returned if this function is invoked
6185 * with the global error status set, or if it should fail for any
6186 * reason.
6187 *-
6188 */
6189
6190 /* Local Variables: */
6191 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
6192 AstChannel *new; /* Pointer to the new Channel */
6193
6194 /* Initialise. */
6195 new = NULL;
6196
6197 /* Check the global error status. */
6198 if ( !astOK ) return new;
6199
6200 /* Get a pointer to the thread specific global data structure. */
6201 astGET_GLOBALS(channel);
6202
6203 /* If a NULL virtual function table has been supplied, then this is
6204 the first loader to be invoked for this Channel. In this case the
6205 Channel belongs to this class, so supply appropriate values to be
6206 passed to the parent class loader (and its parent, etc.). */
6207 if ( !vtab ) {
6208 size = sizeof( AstChannel );
6209 vtab = &class_vtab;
6210 name = "Channel";
6211
6212 /* If required, initialise the virtual function table for this class. */
6213 if ( !class_init ) {
6214 astInitChannelVtab( vtab, name );
6215 class_init = 1;
6216 }
6217 }
6218
6219 /* Invoke the parent class loader to load data for all the ancestral
6220 classes of the current one, returning a pointer to the resulting
6221 partly-built Channel. */
6222 new = astLoadObject( mem, size, (AstObjectVtab *) vtab, name,
6223 channel );
6224
6225 if ( astOK ) {
6226
6227 /* Read input data. */
6228 /* ================ */
6229 /* Request the input Channel to read all the input data appropriate to
6230 this class into the internal "values list". */
6231 astReadClassData( channel, "Channel" );
6232
6233 /* Set the pointers to the source and sink functions, and their
6234 wrapper functions, to NULL (we cannot restore these since they
6235 refer to process-specific addresses). */
6236 new->source = NULL;
6237 new->source_wrap = NULL;
6238 new->sink = NULL;
6239 new->sink_wrap = NULL;
6240
6241 /* We do not have any data to pass to the source and sink functions. */
6242 new->data = NULL;
6243
6244 /* No warnings yet. */
6245 new->warnings = NULL;
6246 new->nwarn = 0;
6247
6248 /* Indicate no input or output files have been associated with the
6249 Channel. */
6250 new->fd_in = NULL;
6251 new->fn_in = NULL;
6252 new->fd_out = NULL;
6253 new->fn_out = NULL;
6254
6255 /* Now read each individual data item from this list and use it to
6256 initialise the appropriate instance variable(s) for this class. */
6257
6258 /* In the case of attributes, we first read the "raw" input value,
6259 supplying the "unset" value as the default. If a "set" value is
6260 obtained, we then use the appropriate (private) Set... member
6261 function to validate and set the value properly. */
6262
6263 /* Indent. */
6264 /* ------- */
6265 new->indent = astReadInt( channel, "indnt", -INT_MAX );
6266 if ( TestIndent( new, status ) ) SetIndent( new, new->indent, status );
6267
6268 /* ReportLevel. */
6269 /* ------------ */
6270 new->report_level = astReadInt( channel, "rplev", -INT_MAX );
6271 if ( TestReportLevel( new, status ) ) SetReportLevel( new,
6272 new->report_level,
6273 status );
6274
6275 /* Skip. */
6276 /* ----- */
6277 new->skip = astReadInt( channel, "skip", -INT_MAX );
6278 if ( TestSkip( new, status ) ) SetSkip( new, new->skip, status );
6279
6280 /* Strict. */
6281 /* ------- */
6282 new->strict = astReadInt( channel, "strict", -INT_MAX );
6283 if ( TestStrict( new, status ) ) SetStrict( new, new->strict, status );
6284
6285 /* Full. */
6286 /* ----- */
6287 new->full = astReadInt( channel, "full", -INT_MAX );
6288 if ( TestFull( new, status ) ) SetFull( new, new->full, status );
6289
6290 /* Comment. */
6291 /* -------- */
6292 new->comment = astReadInt( channel, "comm", -INT_MAX );
6293 if ( TestComment( new, status ) ) SetComment( new, new->comment, status );
6294
6295 /* If an error occurred, clean up by deleting the new Channel. */
6296 if ( !astOK ) new = astDelete( new );
6297 }
6298
6299 /* Return the new Channel pointer. */
6300 return new;
6301 }
6302
6303 /* Virtual function interfaces. */
6304 /* ============================ */
6305 /* These provide the external interface to the virtual functions
6306 defined by this class. Each simply checks the global error status
6307 and then locates and executes the appropriate member function,
6308 using the function pointer stored in the object's virtual function
6309 table (this pointer is located using the astMEMBER macro defined in
6310 "object.h").
6311
6312 Note that the member function may not be the one defined here, as
6313 it may have been over-ridden by a derived class. However, it should
6314 still have the same interface. */
astGetNextData_(AstChannel * this,int begin,char ** name,char ** val,int * status)6315 void astGetNextData_( AstChannel *this, int begin, char **name, char **val, int *status ) {
6316 *name = NULL;
6317 *val = NULL;
6318 if ( !astOK ) return;
6319 (**astMEMBER(this,Channel,GetNextData))( this, begin, name, val, status );
6320 }
astGetNextText_(AstChannel * this,int * status)6321 char *astGetNextText_( AstChannel *this, int *status ) {
6322 if ( !astOK ) return NULL;
6323 return (**astMEMBER(this,Channel,GetNextText))( this, status );
6324 }
astPutNextText_(AstChannel * this,const char * line,int * status)6325 void astPutNextText_( AstChannel *this, const char *line, int *status ) {
6326 if ( !astOK ) return;
6327 (**astMEMBER(this,Channel,PutNextText))( this, line, status );
6328 }
astRead_(AstChannel * this,int * status)6329 AstObject *astRead_( AstChannel *this, int *status ) {
6330 if ( !astOK ) return NULL;
6331 astAddWarning( this, 0, NULL, NULL, status );
6332 return (**astMEMBER(this,Channel,Read))( this, status );
6333 }
astReadClassData_(AstChannel * this,const char * class,int * status)6334 void astReadClassData_( AstChannel *this, const char *class, int *status ) {
6335 if ( !astOK ) return;
6336 (**astMEMBER(this,Channel,ReadClassData))( this, class, status );
6337 }
astReadDouble_(AstChannel * this,const char * name,double def,int * status)6338 double astReadDouble_( AstChannel *this, const char *name, double def, int *status ) {
6339 if ( !astOK ) return 0.0;
6340 return (**astMEMBER(this,Channel,ReadDouble))( this, name, def, status );
6341 }
astReadInt_(AstChannel * this,const char * name,int def,int * status)6342 int astReadInt_( AstChannel *this, const char *name, int def, int *status ) {
6343 if ( !astOK ) return 0;
6344 return (**astMEMBER(this,Channel,ReadInt))( this, name, def, status );
6345 }
astReadObject_(AstChannel * this,const char * name,AstObject * def,int * status)6346 AstObject *astReadObject_( AstChannel *this, const char *name,
6347 AstObject *def, int *status ) {
6348 if ( !astOK ) return NULL;
6349 return (**astMEMBER(this,Channel,ReadObject))( this, name, def, status );
6350 }
astReadString_(AstChannel * this,const char * name,const char * def,int * status)6351 char *astReadString_( AstChannel *this, const char *name, const char *def, int *status ) {
6352 if ( !astOK ) return NULL;
6353 return (**astMEMBER(this,Channel,ReadString))( this, name, def, status );
6354 }
astWriteBegin_(AstChannel * this,const char * class,const char * comment,int * status)6355 void astWriteBegin_( AstChannel *this, const char *class,
6356 const char *comment, int *status ) {
6357 if ( !astOK ) return;
6358 (**astMEMBER(this,Channel,WriteBegin))( this, class, comment, status );
6359 }
astWriteDouble_(AstChannel * this,const char * name,int set,int helpful,double value,const char * comment,int * status)6360 void astWriteDouble_( AstChannel *this, const char *name, int set, int helpful,
6361 double value, const char *comment, int *status ) {
6362 if ( !astOK ) return;
6363 (**astMEMBER(this,Channel,WriteDouble))( this, name, set, helpful, value,
6364 comment, status );
6365 }
astWriteEnd_(AstChannel * this,const char * class,int * status)6366 void astWriteEnd_( AstChannel *this, const char *class, int *status ) {
6367 if ( !astOK ) return;
6368 (**astMEMBER(this,Channel,WriteEnd))( this, class, status );
6369 }
astWriteInt_(AstChannel * this,const char * name,int set,int helpful,int value,const char * comment,int * status)6370 void astWriteInt_( AstChannel *this, const char *name, int set, int helpful,
6371 int value, const char *comment, int *status ) {
6372 if ( !astOK ) return;
6373 (**astMEMBER(this,Channel,WriteInt))( this, name, set, helpful, value,
6374 comment, status );
6375 }
astWriteIsA_(AstChannel * this,const char * class,const char * comment,int * status)6376 void astWriteIsA_( AstChannel *this, const char *class, const char *comment, int *status ) {
6377 if ( !astOK ) return;
6378 (**astMEMBER(this,Channel,WriteIsA))( this, class, comment, status );
6379 }
astWriteString_(AstChannel * this,const char * name,int set,int helpful,const char * value,const char * comment,int * status)6380 void astWriteString_( AstChannel *this, const char *name, int set, int helpful,
6381 const char *value, const char *comment, int *status ) {
6382 if ( !astOK ) return;
6383 (**astMEMBER(this,Channel,WriteString))( this, name, set, helpful, value,
6384 comment, status );
6385 }
astPutChannelData_(AstChannel * this,void * data,int * status)6386 void astPutChannelData_( AstChannel *this, void *data, int *status ) {
6387 if ( !astOK ) return;
6388 (**astMEMBER(this,Channel,PutChannelData))( this, data, status );
6389 }
6390
astWarnings_(AstChannel * this,int * status)6391 AstKeyMap *astWarnings_( AstChannel *this, int *status ){
6392 if( !astOK ) return NULL;
6393 return (**astMEMBER(this,Channel,Warnings))( this, status );
6394 }
6395
6396 /* Because of the variable argument list, we need to work a bit harder on
6397 astAddWarning. Functions that provide implementations of the
6398 astAddWarning method recieve the fully expanded message and so do not
6399 need a variable argument list. */
6400
astAddWarning_(void * this_void,int level,const char * fmt,const char * method,int * status,...)6401 void astAddWarning_( void *this_void, int level, const char *fmt,
6402 const char *method, int *status, ... ) {
6403 AstChannel *this;
6404 char buff[ 201 ];
6405 va_list args;
6406 int nc;
6407
6408 this = astCheckChannel( this_void );
6409
6410 if( fmt ) {
6411 if( astOK ) {
6412 va_start( args, status );
6413 nc = vsprintf( buff, fmt, args );
6414 va_end( args );
6415 if( nc > 200 ) {
6416 astError( AST__INTER, "astAddWarning(%s): Message buffer size "
6417 "exceeded (internal AST programming error).",
6418 status, astGetClass( this ) );
6419 } else {
6420 (**astMEMBER(this,Channel,AddWarning))( this, level, buff, method, status );
6421 }
6422 }
6423 } else {
6424 (**astMEMBER(this,Channel,AddWarning))( this, level, NULL, method, status );
6425 }
6426 }
6427
6428 /* Count the number of times astWrite is invoked (excluding invocations
6429 made from within the astWriteObject method - see below). The count is
6430 done here so that invocations of astWrite within a sub-class will be
6431 included. */
astWrite_(AstChannel * this,AstObject * object,int * status)6432 int astWrite_( AstChannel *this, AstObject *object, int *status ) {
6433 astDECLARE_GLOBALS
6434 if ( !astOK ) return 0;
6435 astGET_GLOBALS(this);
6436 nwrite_invoc++;
6437 astAddWarning( this, 0, NULL, NULL, status );
6438 return (**astMEMBER(this,Channel,Write))( this, object, status );
6439 }
6440
6441 /* We do not want to count invocations of astWrite made from within the
6442 astWriteObject method. So decrement the number of invocations first
6443 (this assumes that each invocation of astWriteObject will only invoke
6444 astWrite once). */
astWriteObject_(AstChannel * this,const char * name,int set,int helpful,AstObject * value,const char * comment,int * status)6445 void astWriteObject_( AstChannel *this, const char *name, int set,
6446 int helpful, AstObject *value, const char *comment, int *status ) {
6447 astDECLARE_GLOBALS
6448 if ( !astOK ) return;
6449 astGET_GLOBALS(this);
6450 nwrite_invoc--;
6451 (**astMEMBER(this,Channel,WriteObject))( this, name, set, helpful, value,
6452 comment, status );
6453 }
6454
6455
6456
6457
6458
6459