1 /*
2 *class++
3 *  Name:
4 *     Axis
5 
6 *  Purpose:
7 *     Store axis information.
8 
9 *  Constructor Function:
10 *     None.
11 
12 *  Description:
13 *     The Axis class is used to store information associated with a
14 *     particular axis of a Frame. It is used internally by the AST
15 *     library and has no constructor function. You should encounter it
16 c     only within textual output (e.g. from astWrite).
17 f     only within textual output (e.g. from AST_WRITE).
18 
19 *  Inheritance:
20 *     The Axis class inherits from the Object class.
21 
22 *  Copyright:
23 *     Copyright (C) 1997-2006 Council for the Central Laboratory of the
24 *     Research Councils
25 
26 *  Licence:
27 *     This program is free software: you can redistribute it and/or
28 *     modify it under the terms of the GNU Lesser General Public
29 *     License as published by the Free Software Foundation, either
30 *     version 3 of the License, or (at your option) any later
31 *     version.
32 *
33 *     This program is distributed in the hope that it will be useful,
34 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
35 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36 *     GNU Lesser General Public License for more details.
37 *
38 *     You should have received a copy of the GNU Lesser General
39 *     License along with this program.  If not, see
40 *     <http://www.gnu.org/licenses/>.
41 
42 *  Authors:
43 *     RFWS: R.F. Warren-Smith (Starlink)
44 *     DSB: B.S. Berry (Starlink)
45 
46 *  History:
47 *     1-MAR-1996 (RFWS):
48 *        Original version.
49 *     10-SEP-1996 (RFWS):
50 *        Added I/O facilities.
51 *     11-SEP-1996 (RFWS):
52 *        Added astAxisGap (written by DSB).
53 *     25-FEB-1998 (RFWS):
54 *        Added astAxisUnformat.
55 *     29-AUG-2001 (DSB):
56 *        Added AxisDistance and AxisOffset.
57 *     20-OCT-2002 (DSB):
58 *        Added Top and Bottom attributes.
59 *     8-JAN-2003 (DSB):
60 *        - Changed private InitVtab method to protected astInitAxisVtab
61 *        method.
62 *        - Include descriptive label for units string within a Dump.
63 *     24-JAN-2004 (DSB):
64 *        - Added astAxisFields.
65 *        - Added argument "fmt" to definition of AxisAbbrev.
66 *     3-FEB-2004 (DSB):
67 *        - Added "log" formatting using the "&" flag character in the
68 *        Format string.
69 *     15-SEP-2004 (DSB):
70 *        - If a format string is set which includes a wildcard precision
71 *        value (".*"), then use the Digits value to determine the precision
72 *        to be used.
73 *        - If the conversion code is of integer type (e.g. "%d") cast value
74 *        to integer before printing.
75 *     2-FEB-2005 (DSB):
76 *        - Avoid using astStore to allocate more storage than is supplied
77 *        in the "data" pointer. This can cause access violations since
78 *        astStore will then read beyond the end of the "data" area.
79 *     15-MAR-2005 (DSB):
80 *        - Avoid exponents in log format labels which are close to zero but
81 *        not quite zero.
82 *     14-FEB-2006 (DSB):
83 *        Override astGetObjSize.
84 *     30-JUN-2006 (DSB):
85 *        Guard against a null "str1" value in AxisAbbrev.
86 *class--
87 */
88 
89 /* Module Macros. */
90 /* ============== */
91 /* Set the name of the class we are implementing. This indicates to
92    the header files that define class interfaces that they should make
93    "protected" symbols available. */
94 #define astCLASS Axis
95 
96 
97 /* Header files. */
98 /* ============= */
99 #include "ast_err.h"             /* Error code definitions */
100 
101 /* Interface definitions. */
102 /* ---------------------- */
103 
104 #include "globals.h"             /* Thread-safe global data access */
105 #include "error.h"               /* Error reporting facilities */
106 #include "memory.h"              /* Memory allocation facilities */
107 #include "object.h"              /* Object interface (parent class) */
108 #include "pointset.h"            /* Sets of coordinates (for AST__BAD) */
109 #include "channel.h"             /* I/O channels */
110 #include "axis.h"                /* Interface definition for this class */
111 #include "unit.h"                /* Definitions of physical units */
112 #include "globals.h"             /* Thread-safe global data access */
113 
114 /* C header files. */
115 /* --------------- */
116 #include <ctype.h>
117 #include <errno.h>
118 #include <float.h>
119 #include <limits.h>
120 #include <math.h>
121 #include <stdarg.h>
122 #include <stddef.h>
123 #include <stdio.h>
124 #include <stdlib.h>
125 #include <string.h>
126 
127 /* Module Variables. */
128 /* ================= */
129 
130 /* Address of this static variable is used as a unique identifier for
131    member of this class. */
132 static int class_check;
133 
134 /* Pointers to parent class methods which are extended by this class. */
135 static int (* parent_getobjsize)( AstObject *, int * );
136 static const char *(* parent_getattrib)( AstObject *, const char *, int * );
137 static int (* parent_testattrib)( AstObject *, const char *, int * );
138 static void (* parent_clearattrib)( AstObject *, const char *, int * );
139 static void (* parent_setattrib)( AstObject *, const char *, int * );
140 
141 /* Plain text equivalents. */
142 static const char *log_txt  = "10^";
143 
144 /* Define macros for accessing each item of thread specific global data. */
145 #ifdef THREAD_SAFE
146 
147 /* Define how to initialise thread-specific globals. */
148 #define GLOBAL_inits \
149    globals->Class_Init = 0; \
150    globals->GetDefaultFormat_Buff[ 0 ] = 0; \
151    globals->AxisFormat_Buff[ 0 ] = 0; \
152    globals->GetAxisNormUnit_Buff[ 0 ] = 0; \
153    globals->GetAttrib_Buff[ 0 ] = 0;
154 
155 /* Create the function that initialises global data for this module. */
156 astMAKE_INITGLOBALS(Axis)
157 
158 /* Define macros for accessing each item of thread specific global data. */
159 #define class_init astGLOBAL(Axis,Class_Init)
160 #define class_vtab astGLOBAL(Axis,Class_Vtab)
161 #define getdefaultformat_buff astGLOBAL(Axis,GetDefaultFormat_Buff)
162 #define axisformat_buff astGLOBAL(Axis,AxisFormat_Buff)
163 #define getaxisnormunit_buff astGLOBAL(Axis,GetAxisNormUnit_Buff)
164 #define getattrib_buff astGLOBAL(Axis,GetAttrib_Buff)
165 
166 
167 
168 /* If thread safety is not needed, declare and initialise globals at static
169    variables. */
170 #else
171 
172 static char getdefaultformat_buff[ AST__AXIS_GETDEFAULTFORMAT_BUFF_LEN + 1 ];
173 static char axisformat_buff[ AST__AXIS_GETDEFAULTFORMAT_BUFF_LEN + 1 ];
174 static char getaxisnormunit_buff[ AST__AXIS_GETAXISNORMUNIT_BUFF_LEN + 1 ];
175 static char getattrib_buff[ AST__AXIS_GETATTRIB_BUFF_LEN + 1 ];
176 
177 
178 /* Define the class virtual function table and its initialisation flag
179    as static variables. */
180 static AstAxisVtab class_vtab;   /* Virtual function table */
181 static int class_init = 0;       /* Virtual function table initialised? */
182 
183 #endif
184 
185 /* External Interface Function Prototypes. */
186 /* ======================================= */
187 /* The following functions have public prototypes only (i.e. no
188    protected prototypes), so we must provide local prototypes for use
189    within this module. */
190 AstAxis *astAxisId_( const char *, ... );
191 
192 /* Prototypes for Private Member Functions. */
193 /* ======================================== */
194 static const char *AxisAbbrev( AstAxis *, const char *, const char *, const char *, int * );
195 static const char *AxisFormat( AstAxis *, double, int * );
196 static int GetObjSize( AstObject *, int * );
197 static const char *GetAttrib( AstObject *, const char *, int * );
198 static const char *GetAxisFormat( AstAxis *, int * );
199 static const char *GetAxisLabel( AstAxis *, int * );
200 static const char *GetAxisSymbol( AstAxis *, int * );
201 static const char *GetAxisUnit( AstAxis *, int * );
202 static const char *GetAxisNormUnit( AstAxis *, int * );
203 static const char *GetDefaultFormat( AstAxis *, int * );
204 static char *ParseAxisFormat( const char *, int, int *, int *, int *, int *, int * );
205 static double AxisDistance( AstAxis *, double, double, int * );
206 static double AxisGap( AstAxis *, double, int *, int * );
207 static double AxisOffset( AstAxis *, double, double, int * );
208 static int AxisFields( AstAxis *, const char *, const char *, int, char **, int *, double *, int * );
209 static int AxisIn( AstAxis *, double, double, double, int, int * );
210 static int AxisUnformat( AstAxis *, const char *, double *, int * );
211 static int GetAxisDigits( AstAxis *, int * );
212 static int GetAxisDirection( AstAxis *, int * );
213 static int TestAttrib( AstObject *, const char *, int * );
214 static int TestAxisDigits( AstAxis *, int * );
215 static int TestAxisDirection( AstAxis *, int * );
216 static int TestAxisFormat( AstAxis *, int * );
217 static int TestAxisLabel( AstAxis *, int * );
218 static int TestAxisSymbol( AstAxis *, int * );
219 static int TestAxisUnit( AstAxis *, int * );
220 static int TestAxisNormUnit( AstAxis *, int * );
221 static void AxisNorm( AstAxis *, double *, int * );
222 static void AxisOverlay( AstAxis *, AstAxis *, int * );
223 static void ClearAttrib( AstObject *, const char *, int * );
224 static void ClearAxisDigits( AstAxis *, int * );
225 static void ClearAxisDirection( AstAxis *, int * );
226 static void ClearAxisFormat( AstAxis *, int * );
227 static void ClearAxisLabel( AstAxis *, int * );
228 static void ClearAxisSymbol( AstAxis *, int * );
229 static void ClearAxisUnit( AstAxis *, int * );
230 static void Copy( const AstObject *, AstObject *, int * );
231 static void Delete( AstObject *, int * );
232 static void Dump( AstObject *, AstChannel *, int * );
233 static void SetAttrib( AstObject *, const char *, int * );
234 static void SetAxisDigits( AstAxis *, int, int * );
235 static void SetAxisDirection( AstAxis *, int, int * );
236 static void SetAxisFormat( AstAxis *, const char *, int * );
237 static void SetAxisLabel( AstAxis *, const char *, int * );
238 static void SetAxisSymbol( AstAxis *, const char *, int * );
239 static void SetAxisUnit( AstAxis *, const char *, int * );
240 
241 static double GetAxisTop( AstAxis *, int * );
242 static int TestAxisTop( AstAxis *, int * );
243 static void ClearAxisTop( AstAxis *, int * );
244 static void SetAxisTop( AstAxis *, double, int * );
245 
246 static double GetAxisBottom( AstAxis *, int * );
247 static int TestAxisBottom( AstAxis *, int * );
248 static void ClearAxisBottom( AstAxis *, int * );
249 static void SetAxisBottom( AstAxis *, double, int * );
250 
251 
252 /* Member functions. */
253 /* ================= */
AxisAbbrev(AstAxis * this,const char * fmt,const char * str1,const char * str2,int * status)254 static const char *AxisAbbrev( AstAxis *this, const char *fmt,
255                                const char *str1, const char *str2, int *status ) {
256 /*
257 *+
258 *  Name:
259 *     astAxisAbbrev
260 
261 *  Purpose:
262 *     Abbreviate a formatted Axis value by skipping leading fields.
263 
264 *  Type:
265 *     Protected virtual function.
266 
267 *  Synopsis:
268 *     #include "axis.h"
269 *     const char *astAxisAbbrev( AstAxis *this, const char *fmt,
270 *                                const char *str1, const char *str2 )
271 
272 *  Class Membership:
273 *     Axis method.
274 
275 *  Description:
276 *     This function compares two Axis values that have been formatted
277 *     (using astAxisFormat) and determines if they have any redundant
278 *     leading fields (i.e. leading fields in common which can be
279 *     suppressed when tabulating the values or plotting them on the
280 *     axis of a graph).
281 
282 *  Parameters:
283 *     this
284 *        Pointer to the Axis.
285 *     fmt
286 *        Pointer to a constant null-terminated string containing the
287 *        format specifier used to format the two values.
288 *     str1
289 *        Pointer to a constant null-terminated string containing the
290 *        first formatted value. If this is null, the returned pointer
291 *        points to the start of the final field in str2.
292 *     str2
293 *        Pointer to a constant null-terminated string containing the
294 *        second formatted value.
295 
296 *  Returned Value:
297 *     A pointer into the "str2" string which locates the first
298 *     character in the first field that differs between the two
299 *     formatted values.
300 *
301 *     If the two values have no leading fields in common, the returned
302 *     value will point at the start of string "str2". If the two
303 *     values are equal, it will point at the terminating null at the
304 *     end of this string.
305 
306 *  Notes:
307 *     - This function assumes that the format specification used was
308 *     the same when both values were formatted.
309 *     - A pointer to the start of "str2" will be returned if this
310 *     function is invoked with the global error status set, or if it
311 *     should fail for any reason.
312 *-
313 */
314 
315 /* Local Variables: */
316    const char *result;           /* Result pointer to return */
317 
318 /* Initialise. */
319    result = str2;
320 
321 /* Check the global error status. */
322    if ( !astOK ) return result;
323 
324 /* In the Axis class, there is only one field in a formatted value.
325    We return the value of "str2", unless the two strings are
326    identical, in which case we return a pointer to the final null in
327    "str2". */
328    if( str1 && !strcmp( str1, str2 ) ) result += strlen( str2 );
329 
330 /* Return the result. */
331    return result;
332 }
333 
AxisDistance(AstAxis * this,double v1,double v2,int * status)334 static double AxisDistance( AstAxis *this, double v1, double v2, int *status ) {
335 /*
336 *+
337 *  Name:
338 *     astAxisDistance
339 
340 *  Purpose:
341 *     Find the distance between two axis values.
342 
343 *  Type:
344 *     Protected virtual function.
345 
346 *  Synopsis:
347 *     #include "axis.h"
348 *     AxisDistance( AstAxis *this, double v1, double v2 )
349 
350 *  Class Membership:
351 *     Axis method.
352 
353 *  Description:
354 *     This function returns a signed value representing the axis increment
355 *     from axis value v1 to axis value v2.
356 *
357 *     For a simple Axis, this is a trivial operation. But for other
358 *     derived classes of Axis (such as a SkyAxis) this is not the case.
359 
360 *  Parameters:
361 *     this
362 *        Pointer to the Axis.
363 *     v1
364 *        The first axis value
365 *     v2
366 *        The second axis value
367 
368 *  Returned Value:
369 *     The axis increment from v1 to v2.
370 
371 *  Notes:
372 *     - A value of AST__BAD is returned if either axis value is AST__BAD.
373 *     - A value of AST__BAD will be returned if this function is invoked
374 *     with the global error status set, or if it should fail for any
375 *     reason.
376 *-
377 */
378 
379 /* Local Variables: */
380    double result;                /* Returned gap size */
381 
382 /* Initialise. */
383    result = AST__BAD;
384 
385 /* Check the global error status. */
386    if ( !astOK ) return result;
387 
388 /* Check both axis values are OK, and form the returned increment. */
389    if( v1 != AST__BAD && v2 != AST__BAD ) result = v2 - v1;
390 
391 /* Return the result. */
392    return result;
393 }
394 
AxisFields(AstAxis * this,const char * fmt0,const char * str,int maxfld,char ** fields,int * nc,double * val,int * status)395 static int AxisFields( AstAxis *this, const char *fmt0, const char *str,
396                        int maxfld, char **fields, int *nc, double *val, int *status ) {
397 /*
398 *+
399 *  Name:
400 *     astAxisFields
401 
402 *  Purpose:
403 *     Identify numerical fields within a formatted Axis value.
404 
405 *  Type:
406 *     Protected virtual function.
407 
408 *  Synopsis:
409 *     #include "axis.h"
410 *     int astAxisFields( AstAxis *this, const char *fmt0, const char *str,
411 *                        int maxfld, char **fields, int *nc, double *val )
412 
413 *  Class Membership:
414 *     Axis member function.
415 
416 *  Description:
417 *     This function identifies the numerical fields within an Axis value
418 *     that have been formatted using astAxisFormat. It assumes that the
419 *     value was formatted using the supplied format string. It also
420 *     returns the equivalent floating point value.
421 
422 *  Parameters:
423 *     this
424 *        Pointer to the Axis.
425 *     fmt0
426 *        Pointer to a constant null-terminated string containing the
427 *        format used when creating "str".
428 *     str
429 *        Pointer to a constant null-terminated string containing the
430 *        formatted value.
431 *     maxfld
432 *        The maximum number of fields to identify within "str".
433 *     fields
434 *        A pointer to an array of at least "maxfld" character pointers.
435 *        Each element is returned holding a pointer to the start of the
436 *        corresponding field  in "str" (in the order in which they occur
437 *        within "str"), or NULL if no corresponding field can be found.
438 *     nc
439 *        A pointer to an array of at least "maxfld" integers. Each
440 *        element is returned holding the number of characters in the
441 *        corresponding field, or zero if no corresponding field can be
442 *        found.
443 *     val
444 *        Pointer to a location at which to store the value
445 *        equivalent to the returned field values. If this is NULL,
446 *        it is ignored.
447 
448 *  Returned Value:
449 *     The number of fields succesfully identified and returned.
450 
451 *  Notes:
452 *     - Leading and trailing spaces are ignored.
453 *     - If the formatted value is not consistent with the supplied format
454 *     string, then a value of zero will be returned, "fields" will be
455 *     returned holding NULLs, "nc" will be returned holding zeros, and
456 *     "val" is returned holding VAL__BAD.
457 *     - Fields are counted from the start of the formatted string. If the
458 *     string contains more than "maxfld" fields, then trailing fields are
459 *     ignored.
460 *     - If this function is invoked with the global error status set, or
461 *     if it should fail for any reason, then a value of zero will be returned
462 *     as the function value, and "fields", "nc" and "val"  will be returned
463 *     holding their supplied values
464 *-
465 */
466 
467 /* Local Variables: */
468    char log_esc[ 50 ];           /* Buffer for graphical delimiter string */
469    const char *fmt;              /* Pointer to parsed Format string */
470    const char *log_del;          /* Pointer to delimiter string */
471    const char *p;                /* Pointer to next character */
472    double value;                 /* Equivalent radians value */
473    int ifld;                     /* Field index */
474    int integ;                    /* Cast axis value to integer before printing? */
475    int len;                      /* Length of formatted string */
476    int log;                      /* Format as "10**x"? */
477    int n;                        /* Number of characters read */
478    int neg;                      /* Negate final value? */
479    int result;                   /* Result fields count to return */
480    int sign;                     /* Include leading sign in front of "10**x"? */
481    int space;                    /* Include leading space in front of "10**x"? */
482 
483 /* Check the global error status. */
484    if ( !astOK ) return 0;
485 
486 /* Initialise. */
487    result = 0;
488    for( ifld = 0; ifld < maxfld; ifld++ ) {
489       fields[ ifld ] = NULL;
490       nc[ ifld ] = 0;
491    }
492    if( val ) *val = AST__BAD;
493 
494 /* Parse the Format string. This returns a collection of flags indicating
495    if any AST specific formatting features are specified in the Format
496    string. It also returns a pointer to a new Format string which is a
497    standard C printf format specifier. Currently the only flags are "log"
498    which indicates if the value should be formatted as "10**x" using
499    the graphical escape sequences defined within the Plot class to produce
500    "x" as a superscript of "10", "sign" which is used with log to indicate
501    if a sign should always be included infront of the "10", and "space"
502    which indicates if a leading space should be included infronyt of "10" if
503    no sign is included. */
504    fmt = ParseAxisFormat( fmt0, astGetAxisDigits( this ), &log, &sign,
505                           &space, &integ, status );
506    fmt = astFree( (void *) fmt );
507 
508    if( astOK ) {
509 
510 /* Obtain the length of the formatted string. */
511       len = (int) strlen( str );
512 
513 /* First deal with "log" format. */
514       if( log ) {
515 
516 /* We need room for at least 2 fields. */
517          if( maxfld > 1 ) {
518 
519 /* Return a pointer to the first non-blank character. */
520             p = str;
521             while( *p == ' ' ) p++;
522             fields[ 0 ] = (char *) p;
523 
524 /* If the first non-blank character is a minus sign, note it and skip it. */
525             neg = 0;
526             if( *p == '-' ) {
527                neg = 1;
528                p++;
529 
530 /* If the first non-blank character is a plus sign, and skip it. */
531             } else if( *p == '+' ) {
532                p++;
533             }
534 
535 /* Select the delimter.*/
536             if(  astEscapes( -1 ) ) {
537                astTuneC( "exdel", NULL, log_esc, sizeof( log_esc ) );
538                log_del = log_esc;
539             } else {
540                log_del = log_txt;
541             }
542 
543 /* Check the remaining string starts with the correct delimiter. If
544    so, store the number of characters in the first field and skip over the
545    delimiter. */
546             n = 0;
547             if( strstr( p, log_del ) == p ) {
548                nc[ 0 ] = p + 2  - fields[ 0 ];
549                p += strlen( log_del );
550 
551 /* Attempt to read a floating point value from the start of the remaining
552    string. */
553                if( 1 == sscanf( p, "%lg%n", &value, &n ) ) {
554 
555 /* If succesfull, store the returned values. */
556                   result = 2;
557                   fields[ 1 ] = (char *) p;
558                   nc[ 1 ] = n;
559                   if( val ) {
560                      *val = pow( 10.0, value );
561                      if( neg ) *val = -(*val);
562                   }
563 
564 /* Otherwise, see if the string starts with <bad> */
565                } else if( strstr( p, "<bad>" ) == p ) {
566 
567 /* If succesfull, store the returned values. */
568                   result = 2;
569                   fields[ 1 ] = (char *) p;
570                   nc[ 1 ] = 5;
571                   if( val ) *val = 0.0;
572                }
573 
574 /* Zero is never formatted as an exponent. If the string starts with zero,
575    return a single zero field. */
576             } else if( 1 == sscanf( p, "%lg%n", &value, &n ) ) {
577                if( value == 0.0 ) {
578                   result = 1;
579                   nc[ 0 ] = p + n  - fields[ 0 ];
580                   if( val ) *val = 0.0;
581                }
582             }
583          }
584 
585 /* Now deal with normal decimal format */
586       } else {
587 
588 /* Attempt to read a floating point value from the formatted string. */
589          if ( n = 0,
590               ( 1 == sscanf( str, "%lg %n", &value, &n ) )
591               && ( n >= len ) && maxfld > 0 ) {
592 
593 /* If succesful, return a pointer to the first non-blank character. */
594             p = str;
595             while( *p == ' ' ) p++;
596             fields[ 0 ] = (char *) p;
597 
598 /* Find the last non-blank character. */
599             p += len;
600             while( p[ -1 ] == ' ' ) p--;
601 
602 /* Return the number of characters in the field. */
603             nc[ 0 ] = p - fields[ 0 ];
604 
605 /* Return the field value. */
606             if( val ) *val = value;
607 
608 /* Indicate that we are returning one field. */
609             result = 1;
610          }
611       }
612    }
613 
614 /* Return the result. */
615    return result;
616 }
617 
AxisFormat(AstAxis * this,double value,int * status)618 static const char *AxisFormat( AstAxis *this, double value, int *status ) {
619 /*
620 *+
621 *  Name:
622 *     astAxisFormat
623 
624 *  Purpose:
625 *     Format a coordinate value for an Axis.
626 
627 *  Type:
628 *     Public virtual function.
629 
630 *  Synopsis:
631 *     #include "axis.h"
632 *     const char *astAxisFormat( AstAxis *this, double value )
633 
634 *  Class Membership:
635 *     Axis method.
636 
637 *  Description:
638 *     This function returns a pointer to a string containing the formatted
639 *     (character) version of a coordinate value for an Axis. The formatting
640 *     applied is that specified by a previous invocation of the
641 *     astSetAxisFormat method. A suitable default format is applied if
642 *     necessary.
643 
644 *  Parameters:
645 *     this
646 *        Pointer to the Axis.
647 *     value
648 *        The coordinate value to be formatted.
649 
650 *  Returned Value:
651 *     A pointer to a null-terminated string containing the formatted value.
652 
653 *  Notes:
654 *     -  The returned string pointer may point at memory allocated within
655 *     the Axis object, or at static memory. The contents of the string may be
656 *     over-written or the pointer may become invalid following a further
657 *     invocation of the same function or deletion of the Axis. A copy of the
658 *     string should therefore be made if necessary.
659 *     -  A NULL pointer will be returned if this function is invoked with the
660 *     global error status set, or if it should fail for any reason.
661 *-
662 */
663 
664 /* Local Constants: */
665 #define ERRBUF_LEN 80
666 
667 /* Local Variables: */
668    astDECLARE_GLOBALS           /* Pointer to thread-specific global data */
669    char *errstat;               /* Pointer for system error message */
670    char errbuf[ ERRBUF_LEN ];   /* Buffer for system error message */
671    char log_esc[ 50 ];          /* Buffer for graphical delimiter string */
672    const char *fmt0;            /* Pointer to original Format string */
673    const char *fmt;             /* Pointer to parsed Format string */
674    const char *log_del;         /* Pointer to delimiter string */
675    const char *result;          /* Pointer to formatted value */
676    double x;                    /* The value to be formatted by sprintf */
677    int integ;                   /* Cast axis value to integer before printing? */
678    int log;                     /* Format as "10**x"? */
679    int nc;                      /* Total number of characters written */
680    int ncc;                     /* Number of characters written */
681    int sign;                    /* Include leading sign in front of "10**x"? */
682    int space;                   /* Include leading space in front of "10**x"? */
683    int stat;                    /* Value of errno after error */
684 
685 /* Check the global error status. */
686    if ( !astOK ) return NULL;
687 
688 /* Get a pointer to the thread specific global data structure. */
689    astGET_GLOBALS(this);
690 
691 /* Initialise. */
692    result = NULL;
693    nc = 0;
694    x = value;
695 
696 /* Check if a bad coordinate value was supplied and return a pointer to an
697    appropriate string if necessary. */
698    if ( value == AST__BAD ) {
699       result = "<bad>";
700 
701 /* Otherwise, obtain a pointer to the Format string. Note a private member
702    function is used here in preference to an object method. This is because the
703    syntax of the Format string may be extended by derived classes and we do not
704    want to obtain a string that we cannot interpret here (where we are
705    restricted to C format specifiers capable of formatting double values).
706    Classes that extend the syntax should provide their own astAxisFormat method
707    and may need to store the string in a separate location. The original
708    location should not be re-used as the string it contains may be needed by
709    the Axis astOverlay method when overlaying attributes on to another Axis
710    object. */
711    } else {
712       fmt0 = GetAxisFormat( this, status );
713 
714 /* Parse the Format string. This returns a collection of flags indicating
715    if any AST specific formatting features are specified in the Format
716    string. It also returns a pointer to a new Format string which is a
717    standard C printf format specifier. Currently the only flags are "log"
718    which indicates if the value should be formatted as "10**x" using
719    the graphical escape sequences defined within the Plot class to produce
720    "x" as a superscript of "10", "sign" which is used with log to indicate
721    if a sign should always be included infront of the "10", and "space"
722    which indicates if a leading space should be included infronyt of "10"
723    if no sign is included. It also modifies ".*" precision fields by
724    replacing the "*" by the current vale of the Digits attribute. */
725       fmt = ParseAxisFormat( fmt0, astGetAxisDigits( this ), &log, &sign,
726                              &space, &integ, status );
727       if( astOK ) {
728 
729 /* Format zero normally. */
730          if( value == 0.0 ) log = 0;
731 
732 /* If log format is required, find the value of the exponent "x", and
733    initialise the returned string to hold the exponent and the graphical
734    escape sequence which produces a superscript. Otherwise just format the
735    supplied value. */
736          if( log ) {
737 
738             if( sign ) {
739                axisformat_buff[ 0 ] ='+';
740                nc = 1;
741 
742             } else if( space ) {
743                axisformat_buff[ 0 ] =' ';
744                nc = 1;
745             }
746 
747             if( value > 0 ) {
748                x = log10( integ ? (int) value : value );
749 
750             } else {
751                x = log10( integ ? (int) -value : -value );
752                axisformat_buff[ 0 ] ='-';
753                nc = 1;
754             }
755 
756             if(  astEscapes( -1 ) ) {
757                astTuneC( "exdel", NULL, log_esc, sizeof( log_esc ) );
758                log_del = log_esc;
759             } else {
760                log_del = log_txt;
761             }
762 
763             nc += sprintf( axisformat_buff + nc, "%s", log_del );
764 
765 /* Round small exponents to zero. */
766             if( fabs( x ) < 1.0E-10 ) x = 0.0;
767          }
768       }
769 
770 /* Clear errno and attempt to format the value as if the Format string were
771    a standard "sprintf" format. */
772       if ( astOK ) {
773          errno = 0;
774          if( integ ) {
775             ncc = sprintf( axisformat_buff + nc, fmt, (int) x );
776          } else {
777             ncc = sprintf( axisformat_buff + nc, fmt, x );
778          }
779          nc += ncc;
780 
781 /* If log format is being used, terminate the string with an escape
782    sequence which resets the graphical attributes to what they were at the
783    start of the string. */
784          if( log ) nc += sprintf( axisformat_buff + nc, "%%+" );
785 
786 /* The possibilities for error detection are limited here, but check if an
787    error value was returned and report an error. Include information from
788    errno if it was set. */
789          if ( ncc < 0 ) {
790             stat = errno;
791             if( stat ) {
792 #if HAVE_STRERROR_R
793                strerror_r( stat, errbuf, ERRBUF_LEN );
794                errstat = errbuf;
795 #else
796                errstat = strerror( stat );
797 #endif
798             } else {
799                *errbuf = 0;
800                errstat = errbuf;
801             }
802             astError( AST__FMTER, "astAxisFormat(%s): Error formatting a "
803                       "coordinate value of %1.*G%s%s.", status, astGetClass( this ),
804                       DBL_DIG, value, stat? " - " : "", errstat );
805             astError( AST__FMTER, "The format string was \"%s\".", status, fmt );
806 
807 /* Also check that the result buffer did not overflow. If it did, memory will
808    probably have been corrupted but this cannot be prevented with "sprintf".
809    Report the error and abort. */
810          } else if ( nc > AST__AXIS_AXISFORMAT_BUFF_LEN ) {
811             astError( AST__FMTER, "astAxisFormat(%s): Internal buffer "
812                       "overflow while formatting a coordinate value of %1.*G "
813                       "- result exceeds %d characters.", status, astGetClass( this ),
814                       DBL_DIG, value, AST__AXIS_AXISFORMAT_BUFF_LEN );
815             astError( AST__FMTER, "The format string was \"%s\".", status, fmt );
816 
817 /* If succesfull, return a pointer to the buffer. */
818          } else {
819             result = axisformat_buff;
820          }
821       }
822 
823 /* Free resources. */
824       fmt = astFree( (void *) fmt );
825 
826    }
827 
828 /* Return the result. */
829    return result;
830 
831 }
832 #undef ERRBUF_LEN
833 
AxisGap(AstAxis * this,double gap,int * ntick,int * status)834 static double AxisGap( AstAxis *this, double gap, int *ntick, int *status ) {
835 /*
836 *+
837 *  Name:
838 *     astAxisGap
839 
840 *  Purpose:
841 *     Find a "nice" gap for tabulating Axis values.
842 
843 *  Type:
844 *     Protected virtual function.
845 
846 *  Synopsis:
847 *     #include "axis.h"
848 *     double astAxisGap( AstAxis *this, double gap, int *ntick )
849 
850 *  Class Membership:
851 *     Axis method.
852 
853 *  Description:
854 *     This function returns a gap size which produces a nicely spaced
855 *     series of formatted Axis values, the returned gap size being as
856 *     close as possible to the supplied target gap size. It also
857 *     returns a convenient number of divisions into which the gap can
858 *     be divided.
859 
860 *  Parameters:
861 *     this
862 *        Pointer to the Axis.
863 *     gap
864 *        The target gap size.
865 *     ntick
866 *        Address of an int in which to return a convenient number of
867 *        divisions into which the gap can be divided.
868 
869 *  Returned Value:
870 *     The nice gap size.
871 
872 *  Notes:
873 *     - A value of zero is returned if the supplied gap size is zero.
874 *     - A negative gap size is returned if the supplied gap size is negative.
875 *     - A value of zero will be returned if this function is invoked
876 *     with the global error status set, or if it should fail for any
877 *     reason.
878 *-
879 */
880 
881 /* Local Variables: */
882    double absgap;                /* Absolute supplied gap size */
883    double b;                     /* Decimal step size */
884    double result;                /* Returned gap size */
885    int index;                    /* Index into tables */
886    int positive;                 /* Value is positive (or zero)? */
887 
888 /* Local Data: */
889    static double table1[ 10 ] =  /* Table of nice decimal gaps */
890             { 1.0, 2.0, 2.0, 5.0, 5.0, 5.0, 5.0, 10.0, 10.0, 10.0 };
891    static int table2[ 10 ] =     /* Table giving number of divisions */
892             {   5,   4,   4,   5,   5,   5,   5,    5,    5,    5 };
893 
894 /* Initialise. */
895    result = 0.0;
896 
897 /* Check the global error status. */
898    if ( !astOK ) return result;
899 
900 /* Check that the supplied gap size is not zero. */
901    if ( gap != 0.0 ) {
902 
903 /* Determine if the supplied gap size is positive and obtain its
904    absolute value. */
905       positive = ( gap >= 0.0 );
906       absgap = positive ? gap : -gap;
907 
908 /* Obtain a value which has a 1 at the position of the most
909    significant decimal digit in the target gap size and zeros at all
910    other positions. */
911       b = pow( 10.0, floor( log10( absgap ) ) );
912 
913 /* This value is the basic "step size". Find the nearest whole number
914    of steps in the supplied gap, and then use the look-up-table in
915    "table1" to find the closest acceptable gap size. Convert this gap
916    size back to an absolute value by multiplying by the step size. */
917       index = (int) ( absgap / b + 0.5 ) - 1;
918       result = b * table1[ index ];
919 
920 /* If the target gap was negative, negate the result. */
921       if( !positive ) result = -result;
922 
923 /* Store the number of divisions in the gap. */
924       if ( ntick ) *ntick = table2[ index ];
925    }
926 
927 /* Return the result. */
928    return result;
929 }
930 
AxisIn(AstAxis * this,double lo,double hi,double val,int closed,int * status)931 static int AxisIn( AstAxis *this, double lo, double hi, double val, int closed, int *status ){
932 /*
933 *+
934 *  Name:
935 *     astAxisIn
936 
937 *  Purpose:
938 *     Test if an axis value lies within a given interval.
939 
940 *  Type:
941 *     Protected virtual function.
942 
943 *  Synopsis:
944 *     #include "axis.h"
945 *     int AxisIn( AstAxis *this, double lo, double hi, double val, int closed )
946 
947 *  Class Membership:
948 *     Axis member function.
949 
950 *  Description:
951 *     This function returns non-zero if a given axis values lies within a
952 *     given axis interval.
953 
954 *  Parameters:
955 *     this
956 *        Pointer to the Axis.
957 *     lo
958 *        The lower axis limit of the interval.
959 *     hi
960 *        The upper axis limit of the interval.
961 *     val
962 *        The axis value to be tested.
963 *     closed
964 *        If non-zero, then the lo and hi axis values are themselves
965 *        considered to be within the interval. Otherwise they are outside.
966 
967 *  Returned Value:
968 *     Non-zero if the test value is inside the interval.
969 
970 *  Class Applicability:
971 *     Axis
972 *        Uses simple Euclidean test
973 *     SkyAxis
974 *        All angles which are numerically between "lo" and "hi" are within
975 *        the interval. Angle outside this range are also within the interval
976 *        if they can be brought into the range by addition or subtraction
977 *        of a multiple of 2.PI.
978 *-
979 */
980 
981 /* For speed, omit the astOK check since no pointers are being used. */
982    if( closed ) {
983       return ( lo <= val && val <= hi );
984    } else {
985       return ( lo < val && val < hi );
986    }
987 }
988 
AxisNorm(AstAxis * this,double * value,int * status)989 static void AxisNorm( AstAxis *this, double *value, int *status ) {
990 /*
991 *+
992 *  Name:
993 *     astAxisNorm
994 
995 *  Purpose:
996 *     Normalise an Axis coordinate value.
997 
998 *  Type:
999 *     Public virtual function.
1000 
1001 *  Synopsis:
1002 *     #include "axis.h"
1003 *     void astAxisNorm( AstAxis *this, double *value )
1004 
1005 *  Class Membership:
1006 *     Axis method.
1007 
1008 *  Description:
1009 *     This function converts an Axis coordinate value which might
1010 *     potentially be unsuitable for display to a user (for instance,
1011 *     may lie outside the expected range of values) into an acceptable
1012 *     alternative value suitable for display.
1013 *
1014 *     Typically, for axes that represent cyclic values such as angles,
1015 *     this function wraps an arbitrary coordinate value so that it
1016 *     lies within the first cycle (say zero to 2*pi). For an ordinary
1017 *     linear Axis, without constraints, this function will typically
1018 *     return the original value unchanged.
1019 
1020 *  Parameters:
1021 *     this
1022 *        Pointer to the Axis.
1023 *     value
1024 *        Pointer to the coordinate value to be normalised, which will
1025 *        be modified in place.
1026 *-
1027 */
1028 
1029 /* In the Axis class there are no constraints, so simply return
1030    without action. */
1031    return;
1032 }
1033 
AxisOffset(AstAxis * this,double v1,double dist,int * status)1034 static double AxisOffset( AstAxis *this, double v1, double dist, int *status ) {
1035 /*
1036 *+
1037 *  Name:
1038 *     astAxisOffset
1039 
1040 *  Purpose:
1041 *     Add an increment onto a supplied axis value.
1042 
1043 *  Type:
1044 *     Protected virtual function.
1045 
1046 *  Synopsis:
1047 *     #include "axis.h"
1048 *     AxisOffset( AstAxis *this, double v1, double dist )
1049 
1050 *  Class Membership:
1051 *     Axis method.
1052 
1053 *  Description:
1054 *     This function returns an axis value formed by adding a signed axis
1055 *     increment onto a supplied axis value.
1056 *
1057 *     For a simple Axis, this is a trivial operation. But for other
1058 *     derived classes of Axis (such as a SkyAxis) this is not the case.
1059 
1060 *  Parameters:
1061 *     this
1062 *        Pointer to the Axis.
1063 *     v1
1064 *        The supplied axis value
1065 *     dist
1066 *        The axis increment
1067 
1068 *  Returned Value:
1069 *     The axis value which is the specified increment away from v1.
1070 
1071 *  Notes:
1072 *     - A value of AST__BAD is returned if either axis value is AST__BAD.
1073 *     - A value of AST__BAD will be returned if this function is invoked
1074 *     with the global error status set, or if it should fail for any
1075 *     reason.
1076 *-
1077 */
1078 
1079 /* Local Variables: */
1080    double result;                /* Returned gap size */
1081 
1082 /* Initialise. */
1083    result = AST__BAD;
1084 
1085 /* Check the global error status. */
1086    if ( !astOK ) return result;
1087 
1088 /* Check both axis values are OK, and form the returned axis value. */
1089    if( v1 != AST__BAD && dist != AST__BAD ) result = v1 + dist;
1090 
1091 /* Return the result. */
1092    return result;
1093 }
1094 
AxisOverlay(AstAxis * template,AstAxis * result,int * status)1095 static void AxisOverlay( AstAxis *template, AstAxis *result, int *status ) {
1096 /*
1097 *+
1098 *  Name:
1099 *     astAxisOverlay
1100 
1101 *  Purpose:
1102 *     Overlay the attributes of a template Axis on to another Axis.
1103 
1104 *  Type:
1105 *     Protected virtual function.
1106 
1107 *  Synopsis:
1108 *     #include "axis.h"
1109 *     void astAxisOverlay( AstAxis *template, AstAxis *result )
1110 
1111 *  Class Membership:
1112 *     Axis method.
1113 
1114 *  Description:
1115 *     This function overlays attributes of one Axis (the "template") on to
1116 *     another Axis, so as to over-ride selected attributes of that second
1117 *     Axis. Normally only those attributes which have been specifically set
1118 *     in the template will be transferred. This implements a form of
1119 *     defaulting, in which an Axis acquires attributes from the template, but
1120 *     retains its original attributes (as the default) if new values have not
1121 *     previously been explicitly set in the template.
1122 
1123 *  Parameters:
1124 *     template
1125 *        Pointer to the template Axis, for which values should have been
1126 *        explicitly set for any attribute which is to be transferred.
1127 *     result
1128 *        Pointer to the Axis which is to receive the new attribute values.
1129 
1130 *  Returned Value:
1131 *     void
1132 *-
1133 */
1134 
1135 /* Check the global error status. */
1136    if ( !astOK ) return;
1137 
1138 /* Define a macro to overlay a single attribute. This tests if the attribute
1139    is set in the template Axis. If it is, its value is obtained and set in the
1140    result Axis also. */
1141 #define OVERLAY(par) \
1142    if ( astTestAxis##par( template ) ) { \
1143       astSetAxis##par( result, astGetAxis##par( template ) ); \
1144    }
1145 /* Overlay each Axis attribute in turn. */
1146    OVERLAY(Digits);
1147    OVERLAY(Direction);
1148    OVERLAY(Label);
1149    OVERLAY(Symbol);
1150    OVERLAY(Unit);
1151 
1152 /* Handle the Format string slightly differently by using a private member
1153    function to obtain it. This is necessary in case derived classes have
1154    extended the string syntax (see the AxisFormat function for more
1155    details). */
1156    if ( TestAxisFormat( template, status ) ) {
1157       SetAxisFormat( result, GetAxisFormat( template, status ), status );
1158    }
1159 
1160 /* Undefine macros local to this function. */
1161 #undef OVERLAY
1162 }
1163 
AxisUnformat(AstAxis * this,const char * string,double * value,int * status)1164 static int AxisUnformat( AstAxis *this, const char *string, double *value, int *status ) {
1165 /*
1166 *+
1167 *  Name:
1168 *     astAxisUnformat
1169 
1170 *  Purpose:
1171 *     Read a formatted coordinate value for an Axis.
1172 
1173 *  Type:
1174 *     Public virtual function.
1175 
1176 *  Synopsis:
1177 *     #include "axis.h"
1178 *     int astAxisUnformat( AstAxis *this, const char *string, double *value )
1179 
1180 *  Class Membership:
1181 *     Axis method.
1182 
1183 *  Description:
1184 *     This function reads a formatted coordinate value for an Axis
1185 *     (supplied as a string) and returns the equivalent numerical
1186 *     value as a double. It also returns the number of characters read
1187 *     from the string.
1188 
1189 *  Parameters:
1190 *     this
1191 *        Pointer to the Axis.
1192 *     string
1193 *        Pointer to a constant null-terminated string containing the
1194 *        formatted coordinate value.
1195 *     value
1196 *        Pointer to a double in which the coordinate value read will be
1197 *        returned.
1198 
1199 *  Returned Value:
1200 *     The number of characters read from the string to obtain the
1201 *     coordinate value.
1202 
1203 *  Notes:
1204 *     - Any white space at the beginning of the string will be
1205 *     skipped, as also will any trailing white space following the
1206 *     coordinate value read. The function's return value will reflect
1207 *     this.
1208 *     - A function value of zero (and no coordinate value) will be
1209 *     returned, without error, if the string supplied does not contain
1210 *     a suitably formatted value.
1211 *     - The string "<bad>" is recognised as a special case and will
1212 *     generate the value AST__BAD, without error. The test for this
1213 *     string is case-insensitive and permits embedded white space.
1214 *     - A function result of zero will be returned and no coordinate
1215 *     value will be returned via the "value" pointer if this function
1216 *     is invoked with the global error status set, or if it should
1217 *     fail for any reason.
1218 *-
1219 */
1220 
1221 /* Local Variables: */
1222    double coord;                 /* Coordinate value read */
1223    int nc;                       /* Number of characters read */
1224 
1225 /* Initialise. */
1226    nc = 0;
1227 
1228 /* Check the global error status. */
1229    if ( !astOK ) return nc;
1230 
1231 /* See if the string can be read as a floating point number. If so,
1232    return its value. Also obtain the number of characters read,
1233    including any leading and trailing white space. */
1234    if ( 1 == astSscanf( string, "%lf %n", &coord, &nc ) ) {
1235       *value = coord;
1236 
1237 /* Otherwise, see if the string starts with "<bad>", allowing mixed
1238    case and leading, embedded and trailing white space. If so, return
1239    the value AST__BAD. */
1240    } else if ( nc = 0,
1241                ( 0 == astSscanf( string, " < %*1[Bb] %*1[Aa] %*1[Dd] > %n", &nc )
1242                && ( nc > 0 ) ) ) {
1243       *value = AST__BAD;
1244 
1245 /* If the string cannot be read, return a function result of zero. */
1246    } else {
1247       nc = 0;
1248    }
1249 
1250 /* Return the number of characters read. */
1251    return nc;
1252 }
1253 
ClearAttrib(AstObject * this_object,const char * attrib,int * status)1254 static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) {
1255 /*
1256 *  Name:
1257 *     ClearAttrib
1258 
1259 *  Purpose:
1260 *     Clear an attribute value for an Axis.
1261 
1262 *  Type:
1263 *     Private function.
1264 
1265 *  Synopsis:
1266 *     #include "axis.h"
1267 *     void ClearAttrib( AstObject *this, const char *attrib, int *status )
1268 
1269 *  Class Membership:
1270 *     Axis member function (over-rides the astClearAttrib protected
1271 *     method inherited from the Object class).
1272 
1273 *  Description:
1274 *     This function clears the value of a specified attribute for an
1275 *     Axis, so that the default value will subsequently be used.
1276 
1277 *  Parameters:
1278 *     this
1279 *        Pointer to the Axis.
1280 *     attrib
1281 *        Pointer to a null-terminated string specifying the attribute
1282 *        name.  This should be in lower case with no surrounding white
1283 *        space.
1284 *     status
1285 *        Pointer to the inherited status variable.
1286 */
1287 
1288 /* Local Variables: */
1289    AstAxis *this;                /* Pointer to the Axis structure */
1290 
1291 /* Check the global error status. */
1292    if ( !astOK ) return;
1293 
1294 /* Obtain a pointer to the Axis structure. */
1295    this = (AstAxis *) this_object;
1296 
1297 /* Check the attribute name and clear the appropriate attribute. */
1298 
1299 /* Digits. */
1300 /* ------- */
1301    if ( !strcmp( attrib, "digits" ) ) {
1302       astClearAxisDigits( this );
1303 
1304 /* Direction. */
1305 /* ---------- */
1306    } else if ( !strcmp( attrib, "direction" ) ) {
1307       astClearAxisDirection( this );
1308 
1309 /* Format. */
1310 /* ------- */
1311    } else if ( !strcmp( attrib, "format" ) ) {
1312       astClearAxisFormat( this );
1313 
1314 /* Label. */
1315 /* ------ */
1316    } else if ( !strcmp( attrib, "label" ) ) {
1317       astClearAxisLabel( this );
1318 
1319 /* Top. */
1320 /* ---- */
1321    } else if ( !strcmp( attrib, "top" ) ) {
1322       astClearAxisTop( this );
1323 
1324 /* Bottom. */
1325 /* ------- */
1326    } else if ( !strcmp( attrib, "bottom" ) ) {
1327       astClearAxisBottom( this );
1328 
1329 /* Symbol. */
1330 /* ------- */
1331    } else if ( !strcmp( attrib, "symbol" ) ) {
1332       astClearAxisSymbol( this );
1333 
1334 /* Unit. */
1335 /* ----- */
1336    } else if ( !strcmp( attrib, "unit" ) ) {
1337       astClearAxisUnit( this );
1338 
1339 /* Read-only attributes. */
1340 /* --------------------- */
1341 /* Test if the attribute name matches any of the read-only attributes
1342    of this class. If it does, then report an error. */
1343    } else if ( !strcmp( attrib, "normunit" ) ) {
1344       astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" "
1345                 "value for a %s.", status, attrib, astGetClass( this ) );
1346       astError( AST__NOWRT, "This is a read-only attribute." , status);
1347 
1348 /* If the attribute is still not recognised, pass it on to the parent
1349    method for further interpretation. */
1350    } else {
1351       (*parent_clearattrib)( this_object, attrib, status );
1352    }
1353 }
1354 
GetAxisNormUnit(AstAxis * this,int * status)1355 static const char *GetAxisNormUnit( AstAxis *this, int *status ){
1356 /*
1357 *+
1358 *  Name:
1359 *     astGetAxisNormUnit
1360 
1361 *  Purpose:
1362 *     Return the normalised Unit attribute for an Axis.
1363 
1364 *  Type:
1365 *     Protected virtual function.
1366 
1367 *  Synopsis:
1368 *     #include "axis.h"
1369 *     const char *astGetAxisNormUnit( AstAxis *this ){
1370 
1371 *  Class Membership:
1372 *     Axis method.
1373 
1374 *  Description:
1375 *     This function normalised and returns the axis Unit attribute.
1376 *     Normalisation refers to transformations such as "s*(m/s)" -> "m".
1377 
1378 *  Parameters:
1379 *     this
1380 *        Pointer to the Axis.
1381 
1382 *  Returned Value:
1383 *     - Pointer to a null-terminated string containing the normalised
1384 *     unit string.
1385 
1386 *  Notes:
1387 *     - The returned pointer points to a static memory buffer. The
1388 *     contents of this buffer will be over-written on each invocation of
1389 *     this function. A copy of the returned string should therefore be
1390 *     taken if it will be needed later.
1391 *     - A NULL pointer will be returned if this function is invoked
1392 *     with the global error status set, or if it should fail for any
1393 *     reason.
1394 *-
1395 */
1396 
1397 /* Local Variables: */
1398    astDECLARE_GLOBALS        /* Pointer to thread-specific global data */
1399    const char *result;       /* Pointer to dynamic memory holding returned text */
1400    int nc;                   /* Length of normalised Unit string */
1401 
1402 /* Check the global error status. */
1403    if ( !astOK ) return NULL;
1404 
1405 /* Get a pointer to the thread specific global data structure. */
1406    astGET_GLOBALS(this);
1407 
1408 /* Get the Axis Unit attrribute and normalise it. */
1409    result = astUnitNormaliser( astGetAxisUnit( this ) );
1410 
1411 /* If successful, check that the resulting string will fit in the buffer.
1412    If not, report an error. */
1413    if( result ) {
1414       nc = strlen( result );
1415       if( nc > AST__AXIS_GETAXISNORMUNIT_BUFF_LEN ) {
1416          astError( AST__FMTER, "astGetAxisNormUnit(%s): Internal buffer "
1417                       "overflow while normalising the units string '%s' "
1418                       "- result exceeds %d characters.", status, astGetClass( this ),
1419                       result, AST__AXIS_GETAXISNORMUNIT_BUFF_LEN );
1420          result = astFree( (void *) result );
1421 
1422 /* If so, copy it into the static buffer and free the dynamic memory returned
1423    by astUnitNormaliser. */
1424       } else {
1425          strcpy( getaxisnormunit_buff, result );
1426       }
1427       astFree( (void *) result );
1428 
1429       result = getaxisnormunit_buff;
1430    }
1431 
1432 /* Return the answer. */
1433    return result;
1434 }
1435 
GetObjSize(AstObject * this_object,int * status)1436 static int GetObjSize( AstObject *this_object, int *status ) {
1437 /*
1438 *  Name:
1439 *     GetObjSize
1440 
1441 *  Purpose:
1442 *     Return the in-memory size of an Object.
1443 
1444 *  Type:
1445 *     Private function.
1446 
1447 *  Synopsis:
1448 *     #include "axis.h"
1449 *     int GetObjSize( AstObject *this, int *status )
1450 
1451 *  Class Membership:
1452 *     Axis member function (over-rides the astGetObjSize protected
1453 *     method inherited from the parent class).
1454 
1455 *  Description:
1456 *     This function returns the in-memory size of the supplied Axis,
1457 *     in bytes.
1458 
1459 *  Parameters:
1460 *     this
1461 *        Pointer to the Axis.
1462 *     status
1463 *        Pointer to the inherited status variable.
1464 
1465 *  Returned Value:
1466 *     The Object size, in bytes.
1467 
1468 *  Notes:
1469 *     - A value of zero will be returned if this function is invoked
1470 *     with the global status set, or if it should fail for any reason.
1471 */
1472 
1473 /* Local Variables: */
1474    AstAxis *this;             /* Pointer to Axis structure */
1475    int result;                /* Result value to return */
1476 
1477 /* Initialise. */
1478    result = 0;
1479 
1480 /* Check the global error status. */
1481    if ( !astOK ) return result;
1482 
1483 /* Obtain a pointers to the Axis structure. */
1484    this = (AstAxis *) this_object;
1485 
1486 /* Invoke the GetObjSize method inherited from the parent class, and then
1487    add on any components of the class structure defined by thsi class
1488    which are stored in dynamically allocated memory. */
1489    result = (*parent_getobjsize)( this_object, status );
1490 
1491    result += astTSizeOf( this->label );
1492    result += astTSizeOf( this->format );
1493    result += astTSizeOf( this->symbol );
1494    result += astTSizeOf( this->unit );
1495 
1496 /* If an error occurred, clear the result value. */
1497    if ( !astOK ) result = 0;
1498 
1499 /* Return the result, */
1500    return result;
1501 }
1502 
GetAttrib(AstObject * this_object,const char * attrib,int * status)1503 static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) {
1504 /*
1505 *  Name:
1506 *     GetAttrib
1507 
1508 *  Purpose:
1509 *     Get the value of a specified attribute for an Axis.
1510 
1511 *  Type:
1512 *     Private function.
1513 
1514 *  Synopsis:
1515 *     #include "axis.h"
1516 *     const char *GetAttrib( AstObject *this, const char *attrib, int *status )
1517 
1518 *  Class Membership:
1519 *     Axis member function (over-rides the protected astGetAttrib
1520 *     method inherited from the Object class).
1521 
1522 *  Description:
1523 *     This function returns a pointer to the value of a specified
1524 *     attribute for an Axis, formatted as a character string.
1525 
1526 *  Parameters:
1527 *     this
1528 *        Pointer to the Axis.
1529 *     attrib
1530 *        Pointer to a null-terminated string containing the name of
1531 *        the attribute whose value is required. This name should be in
1532 *        lower case, with all white space removed.
1533 *     status
1534 *        Pointer to the inherited status variable.
1535 
1536 *  Returned Value:
1537 *     - Pointer to a null-terminated string containing the attribute
1538 *     value.
1539 
1540 *  Notes:
1541 *     - The returned string pointer may point at memory allocated
1542 *     within the Axis, or at static memory. The contents of the string
1543 *     may be over-written or the pointer may become invalid following
1544 *     a further invocation of the same function or any modification of
1545 *     the Axis. A copy of the string should therefore be made if
1546 *     necessary.
1547 *     - A NULL pointer will be returned if this function is invoked
1548 *     with the global error status set, or if it should fail for any
1549 *     reason.
1550 */
1551 
1552 /* Local Variables: */
1553    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1554    AstAxis*this;                 /* Pointer to the Axis structure */
1555    const char *result;           /* Pointer value to return */
1556    double dval;                  /* Double attribute value */
1557    int digits;                   /* Digits attribute value */
1558    int direction;                /* Direction attribute value */
1559 
1560 /* Initialise. */
1561    result = NULL;
1562 
1563 /* Check the global error status. */
1564    if ( !astOK ) return result;
1565 
1566 /* Get a pointer to the thread specific global data structure. */
1567    astGET_GLOBALS(this_object);
1568 
1569 /* Obtain a pointer to the Axis structure. */
1570    this = (AstAxis *) this_object;
1571 
1572 /* Compare "attrib" with each recognised attribute name in turn,
1573    obtaining the value of the required attribute. If necessary, write
1574    the value into "getattrib_buff" as a null-terminated string in an
1575    appropriate format.  Set "result" to point at the result string. */
1576 
1577 /* Digits. */
1578 /* ------- */
1579    if ( !strcmp( attrib, "digits" ) ) {
1580       digits = astGetAxisDigits( this );
1581       if ( astOK ) {
1582          (void) sprintf( getattrib_buff, "%d", digits );
1583          result = getattrib_buff;
1584       }
1585 
1586 /* Direction. */
1587 /* ---------- */
1588    } else if ( !strcmp( attrib, "direction" ) ) {
1589       direction = astGetAxisDirection( this );
1590       if ( astOK ) {
1591          (void) sprintf( getattrib_buff, "%d", direction );
1592          result = getattrib_buff;
1593       }
1594 
1595 /* Top. */
1596 /* ---- */
1597    } else if ( !strcmp( attrib, "top" ) ) {
1598       dval = astGetAxisTop( this );
1599       if ( astOK ) {
1600          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1601          result = getattrib_buff;
1602       }
1603 
1604 /* Bottom. */
1605 /* ------- */
1606    } else if ( !strcmp( attrib, "bottom" ) ) {
1607       dval = astGetAxisBottom( this );
1608       if ( astOK ) {
1609          (void) sprintf( getattrib_buff, "%.*g", DBL_DIG, dval );
1610          result = getattrib_buff;
1611       }
1612 
1613 /* Format. */
1614 /* ------- */
1615    } else if ( !strcmp( attrib, "format" ) ) {
1616       result = astGetAxisFormat( this );
1617 
1618 /* Label. */
1619 /* ------ */
1620    } else if ( !strcmp( attrib, "label" ) ) {
1621       result = astGetAxisLabel( this );
1622 
1623 /* Symbol. */
1624 /* ------- */
1625    } else if ( !strcmp( attrib, "symbol" ) ) {
1626       result = astGetAxisSymbol( this );
1627 
1628 /* Unit. */
1629 /* ----- */
1630    } else if ( !strcmp( attrib, "unit" ) ) {
1631       result = astGetAxisUnit( this );
1632 
1633 /* NormUnit. */
1634 /* --------- */
1635    } else if ( !strcmp( attrib, "normunit" ) ) {
1636       result = astGetAxisNormUnit( this );
1637 
1638 /* If the attribute name was not recognised, pass it on to the parent
1639    method for further interpretation. */
1640    } else {
1641       result = (*parent_getattrib)( this_object, attrib, status );
1642    }
1643 
1644 /* Return the result. */
1645    return result;
1646 
1647 }
1648 
GetDefaultFormat(AstAxis * this,int * status)1649 static const char *GetDefaultFormat( AstAxis *this, int *status ){
1650 /*
1651 *  Name:
1652 *     GetDefaultFormat
1653 
1654 *  Purpose:
1655 *     Return a pointer to a string holding the default Format value.
1656 
1657 *  Type:
1658 *     Private function.
1659 
1660 *  Synopsis:
1661 *     #include "axis.h"
1662 *     const char *GetDefaultFormat( AstAxis *this, int *status )
1663 
1664 *  Class Membership:
1665 *     Axis member function
1666 
1667 *  Description:
1668 *     This function returns a pointer to a string holding the default
1669 *     Format value, which is based on the current Digits value.
1670 
1671 *  Parameters:
1672 *     this
1673 *        A pointer to the Axis structure.
1674 *     status
1675 *        Pointer to the inherited status variable.
1676 
1677 *  Returned Value:
1678 *     - Pointer to a static null-terminated character string containing
1679 *     the default Format string.
1680 
1681 *  Notes:
1682 *     - A null string will be returned if this function is invoked
1683 *     with the global error status set, or if it should fail for any
1684 *     reason.
1685 */
1686 
1687 /* Local Variables: */
1688    astDECLARE_GLOBALS         /* Pointer to thread-specific global data */
1689 
1690 /* Check the global error status. */
1691    if ( !astOK ) return "";
1692 
1693 /* Get a pointer to the thread specific global data structure. */
1694    astGET_GLOBALS(this);
1695 
1696 /* Create the default format value and store it in the "format_buff"
1697    static variable. */
1698    (void) sprintf( getdefaultformat_buff, "%%1.%dG", astGetAxisDigits( this ) );
1699 
1700 /* Return a pointer to the "format_buff" static variable. */
1701    return getdefaultformat_buff;
1702 }
1703 
astInitAxisVtab_(AstAxisVtab * vtab,const char * name,int * status)1704 void astInitAxisVtab_(  AstAxisVtab *vtab, const char *name, int *status ) {
1705 /*
1706 *+
1707 *  Name:
1708 *     astInitAxisVtab
1709 
1710 *  Purpose:
1711 *     Initialise a virtual function table for an Axis.
1712 
1713 *  Type:
1714 *     Protected function.
1715 
1716 *  Synopsis:
1717 *     #include "axis.h"
1718 *     void astInitAxisVtab( AstAxisVtab *vtab, const char *name )
1719 
1720 *  Class Membership:
1721 *     Axis vtab initialiser.
1722 
1723 *  Description:
1724 *     This function initialises the component of a virtual function
1725 *     table which is used by the Axis class.
1726 
1727 *  Parameters:
1728 *     vtab
1729 *        Pointer to the virtual function table. The components used by
1730 *        all ancestral classes will be initialised if they have not already
1731 *        been initialised.
1732 *     name
1733 *        Pointer to a constant null-terminated character string which contains
1734 *        the name of the class to which the virtual function table belongs (it
1735 *        is this pointer value that will subsequently be returned by the Object
1736 *        astClass function).
1737 *-
1738 */
1739 
1740 /* Local Variables: */
1741    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
1742    AstObjectVtab *object;        /* Pointer to Object component of Vtab */
1743 
1744 /* Check the local error status. */
1745    if ( !astOK ) return;
1746 
1747 /* Get a pointer to the thread specific global data structure. */
1748    astGET_GLOBALS(NULL);
1749 
1750 /* Initialize the component of the virtual function table used by the
1751    parent class. */
1752    astInitObjectVtab( (AstObjectVtab *) vtab, name );
1753 
1754 /* Store a unique "magic" value in the virtual function table. This
1755    will be used (by astIsAAxis) to determine if an object belongs
1756    to this class.  We can conveniently use the address of the (static)
1757    class_check variable to generate this unique value. */
1758    vtab->id.check = &class_check;
1759    vtab->id.parent = &(((AstObjectVtab *) vtab)->id);
1760 
1761 /* Initialise member function pointers. */
1762 /* ------------------------------------ */
1763 /* Store pointers to the member functions (implemented here) that provide
1764    virtual methods for this class. */
1765    vtab->AxisAbbrev = AxisAbbrev;
1766    vtab->AxisFields = AxisFields;
1767    vtab->AxisFormat = AxisFormat;
1768    vtab->AxisDistance = AxisDistance;
1769    vtab->AxisOffset = AxisOffset;
1770    vtab->AxisGap = AxisGap;
1771    vtab->AxisIn = AxisIn;
1772    vtab->AxisNorm = AxisNorm;
1773    vtab->AxisOverlay = AxisOverlay;
1774    vtab->AxisUnformat = AxisUnformat;
1775    vtab->ClearAxisDigits = ClearAxisDigits;
1776    vtab->ClearAxisDirection = ClearAxisDirection;
1777    vtab->ClearAxisFormat = ClearAxisFormat;
1778    vtab->ClearAxisLabel = ClearAxisLabel;
1779    vtab->ClearAxisSymbol = ClearAxisSymbol;
1780    vtab->ClearAxisUnit = ClearAxisUnit;
1781    vtab->GetAxisDigits = GetAxisDigits;
1782    vtab->GetAxisDirection = GetAxisDirection;
1783    vtab->GetAxisFormat = GetAxisFormat;
1784    vtab->GetAxisLabel = GetAxisLabel;
1785    vtab->GetAxisSymbol = GetAxisSymbol;
1786    vtab->GetAxisUnit = GetAxisUnit;
1787    vtab->GetAxisNormUnit = GetAxisNormUnit;
1788    vtab->SetAxisDigits = SetAxisDigits;
1789    vtab->SetAxisDirection = SetAxisDirection;
1790    vtab->SetAxisFormat = SetAxisFormat;
1791    vtab->SetAxisLabel = SetAxisLabel;
1792    vtab->SetAxisSymbol = SetAxisSymbol;
1793    vtab->SetAxisUnit = SetAxisUnit;
1794    vtab->TestAxisDigits = TestAxisDigits;
1795    vtab->TestAxisDirection = TestAxisDirection;
1796    vtab->TestAxisFormat = TestAxisFormat;
1797    vtab->TestAxisLabel = TestAxisLabel;
1798    vtab->TestAxisSymbol = TestAxisSymbol;
1799    vtab->TestAxisUnit = TestAxisUnit;
1800    vtab->TestAxisNormUnit = TestAxisNormUnit;
1801 
1802    vtab->ClearAxisTop = ClearAxisTop;
1803    vtab->GetAxisTop = GetAxisTop;
1804    vtab->SetAxisTop = SetAxisTop;
1805    vtab->TestAxisTop = TestAxisTop;
1806 
1807    vtab->ClearAxisBottom = ClearAxisBottom;
1808    vtab->GetAxisBottom = GetAxisBottom;
1809    vtab->SetAxisBottom = SetAxisBottom;
1810    vtab->TestAxisBottom = TestAxisBottom;
1811 
1812 /* Save the inherited pointers to methods that will be extended, and replace
1813    them with pointers to the new member functions. */
1814    object = (AstObjectVtab *) vtab;
1815 
1816    parent_clearattrib = object->ClearAttrib;
1817    parent_getobjsize = object->GetObjSize;
1818    object->GetObjSize = GetObjSize;
1819    object->ClearAttrib = ClearAttrib;
1820    parent_getattrib = object->GetAttrib;
1821    object->GetAttrib = GetAttrib;
1822    parent_setattrib = object->SetAttrib;
1823    object->SetAttrib = SetAttrib;
1824    parent_testattrib = object->TestAttrib;
1825    object->TestAttrib = TestAttrib;
1826 
1827 /* Declare the destructor, copy constructor and dump function. */
1828    astSetDelete( vtab, Delete );
1829    astSetCopy( vtab, Copy );
1830    astSetDump( vtab, Dump, "Axis", "Coordinate axis" );
1831 
1832 /* If we have just initialised the vtab for the current class, indicate
1833    that the vtab is now initialised, and store a pointer to the class
1834    identifier in the base "object" level of the vtab. */
1835    if( vtab == &class_vtab ) {
1836       class_init = 1;
1837       astSetVtabClassIdentifier( vtab, &(vtab->id) );
1838    }
1839 }
1840 
ParseAxisFormat(const char * fmt0,int digs,int * log,int * sign,int * lspace,int * integ,int * status)1841 static char *ParseAxisFormat( const char *fmt0, int digs, int *log, int *sign,
1842                               int *lspace, int *integ, int *status ){
1843 /*
1844 *  Name:
1845 *     ParseAxisFormat
1846 
1847 *  Purpose:
1848 *     Parse the Format string for an Axis.
1849 
1850 *  Type:
1851 *     Private function.
1852 
1853 *  Synopsis:
1854 *     #include "axis.h"
1855 *     char *ParseAxisFormat( const char *fmt0, int digs, int *log, int *sign,
1856 *                            int *lspace, int *integ, int *status )
1857 
1858 *  Class Membership:
1859 *     Axis member function
1860 
1861 *  Description:
1862 *     This function returns a collection of flags indicating if any AST
1863 *     specific formatting features are specified in the supplied Format
1864 *     string. It also returns a pointer to a new Format string which is a
1865 *     standard C printf format specifier.
1866 
1867 *  Parameters:
1868 *     fmt0
1869 *        The value of the Format attribute.
1870 *     digs
1871 *        The default number of digits of precision to use. This is used
1872 *        if the given format specifier includes a wildcard precision (".*").
1873 *        In this case, the returned format specifier will be modified to
1874 *        include an explicit precision value equal to the supplied value
1875 *        of "digs".
1876 *     log
1877 *        Pointer to an integer in which to store a flag indicating if the
1878 *        if the axis value should be formatted as "10**x" using the graphical
1879 *        escape sequences defined within the Plot class to produce "x" as a
1880 *        superscript of "10". A non-zero value will be returned if the
1881 *        supplied Format string has a '&' character in its printf <flags>
1882 *        field (that is, between the leading '%' sign and the optional
1883 *        printf field width).
1884 *     sign
1885 *        Pointer to an integer in which to store a flag indicating if a
1886 *        sign character ('+' or '-') should always be included in front
1887 *        of the "10" if "log" is returned non-zero. If "log" is returned
1888 *        zero, then "sign" will also be zero. If "log" is non-zero, then
1889 *        a non-zero value for "sign" will be returned if the supplied Format
1890 *        string has a '+' character in its printf <flags> field (that is,
1891 *        between the leading '%' sign and the optional printf field width).
1892 *     lspace
1893 *        Pointer to an integer in which to store a flag indicating if a
1894 *        leading space should be included in front of the "10" if "log" is
1895 *        returned non-zero and "sign" is returned zero. Otherwise, "lspace"
1896 *        will also be zero. If "log" is non-zero, then a non-zero value for
1897 *        "lspace" will be returned if the supplied Format string has a ' '
1898 *        character in its printf <flags> field (that is, between the leading
1899 *        '%' sign and the optional printf field width).
1900 *     integ
1901 *        Pointer to an integer in which to store a flag indicating if the
1902 *        returned format specifier includes an integer conversion code
1903 *        (e.g. %d) or floating point conversion code (e.g. "%.7G").
1904 *     status
1905 *        Pointer to the inherited status variable.
1906 
1907 *  Returned Value:
1908 *     - Pointer to a dynamically allocated null-terminated string containing
1909 *     the modified Format string. This will be a copy of the supplied
1910 *     Format string, but with any '&' flag removed. Any '+' or ' ' flag will
1911 *     also be removed if "log" is returned as non-zero. An explicit
1912 *     precision field will be included if the supplied format includes a
1913 *     ".*" precision field.
1914 
1915 *  Notes:
1916 *     - A NULL pointer will be returned if this function is invoked
1917 *     with the global error status set, or if it should fail for any
1918 *     reason.
1919 */
1920 
1921 /* Local Variables: */
1922    char *a;             /* Pointer to next char read from original format */
1923    char *b;             /* Pointer to next char to write to new format */
1924    char *c;             /* Pointer to next char read from original format */
1925    char *new;           /* Pointer to new returned string */
1926    char *perc;          /* Pointer to percent sign */
1927    char *result;        /* Pointer to the returned string */
1928    int hash;            /* Was a '#' flag found? */
1929    int len;             /* Used length of format string */
1930    int minus;           /* Was a '-' flag found? */
1931    int plus;            /* Was a '+' flag found? */
1932    int rlen;            /* Length of result */
1933    int space;           /* Was a ' ' flag found? */
1934 
1935 /* Initialise. */
1936    result = NULL;
1937    *log = 0;
1938    *sign = 0;
1939    *lspace = 0;
1940    *integ = 0;
1941 
1942 /* Check the global error status. */
1943    if ( !astOK ) return result;
1944 
1945 /* Take a copy of the supplied string. Check the pointer can be used
1946    safely. */
1947    len = astChrLen( fmt0 );
1948    result = astStore( NULL, fmt0, len + 1 );
1949    if( astOK ) {
1950       result[ len ] = 0;
1951 
1952 /* Find the first percent sign. Do nothing if none is found. */
1953       perc = strchr( result, '%' );
1954       if( perc ) {
1955 
1956 /* Check each character following the percent sign until one is found
1957    which is not a legal printf flag, or a legal AST extension flag. Note
1958    which ones are present. */
1959          minus = 0;
1960          plus = 0;
1961          space = 0;
1962          hash = 0;
1963 
1964          a = perc;
1965          while( ++a ){
1966             if( *a == '-' ){
1967                minus = 1;
1968             } else if( *a == '+' ){
1969                plus = 1;
1970             } else if( *a == ' ' ){
1971                space = 1;
1972             } else if( *a == '#' ){
1973                hash = 1;
1974             } else if( *a == '&' ){
1975                *log = 1;
1976             } else {
1977                break;
1978             }
1979          }
1980 
1981 /* If no '&' flag was found just return the unaltered copy of the
1982    supplied Format string. Otherwise, remove any '+' or ' ' flag. */
1983          if( *log ) {
1984             if( plus ) *sign = 1;
1985             if( space ) *lspace = 1;
1986 
1987 /* Append any remaining flag characters to the output string. */
1988             perc++;
1989             if( minus ) *(perc++) = '-';
1990             if( hash ) *(perc++) = '#';
1991 
1992 /* Copy the remaining characters down to fill up the gap left by the
1993    removed flags. */
1994             while( *a ) *(perc++) = *(a++);
1995 
1996 /* Terminate the returned string. */
1997             *perc = 0;
1998 
1999          }
2000       }
2001    }
2002 
2003 /* If the format specifier being returned does include a ".*" precision,
2004    replace the "*" with the value of the Digits attribute. */
2005    if( result ) {
2006 
2007 /* Find the first percent sign. Do nothing if none is found. */
2008       a = strchr( result, '%' );
2009       if( a ) {
2010 
2011 /* Check each character following the percent sign until one is found
2012    which is not a legal printf flag. */
2013          while( ++a ){
2014             if( *a != '-' && *a != '+' && *a != ' ' && *a != '#' ) break;
2015          }
2016 
2017 /* Skip any field width (a decimal integer) following the flags. */
2018          a--;
2019          while( ++a ) {
2020             if( !isdigit( *a ) ) break;
2021          }
2022 
2023 /* Get a pointer to the next alphabetic character. This will be the
2024    conversion code. If it an integer code, return *integ non-zero. */
2025          c = a - 1;
2026          while( ++c ) {
2027             if( isalpha( *c ) ) {
2028                if( *c == 'd' || *c == 'i' || *c == 'u' || *c == 'o' ||
2029                    *c == 'x' || *c == 'X' || *c == 'c' ) *integ = 1;
2030                break;
2031             }
2032          }
2033 
2034 /* Go back to the end of the field width. If the next two characters are
2035    "." and "*", change the asterisk to the supplied "digs" value. */
2036          if( a[ 0 ] == '.' && a[ 1 ] == '*' ) {
2037 
2038 /* Allocate memory to hold the extended format string (allowing 20
2039    characters for formatting the digs value - just in case something like
2040    INT_MAX is supplied by mistake), and store the existing string in it. */
2041             rlen = strlen( result );
2042             new = astMalloc( rlen + 22 );
2043             if( new ) memcpy( new, result, rlen + 1 );
2044 
2045 /* Put the precision into the new string, following the field width. */
2046             b = new + ( a - result );
2047             b += sprintf( b, ".%d", digs );
2048 
2049 /* Copy the remainder of the original format string to the new format
2050    string. */
2051             if( a[ 2 ] != 0 ) strcpy( b, a + 2 );
2052 
2053 /* Use the new format string in place of the old.*/
2054             astFree( result );
2055             result = new;
2056          }
2057       }
2058    }
2059 
2060 /* Return the result. */
2061    return result;
2062 
2063 }
2064 
SetAttrib(AstObject * this_object,const char * setting,int * status)2065 static void SetAttrib( AstObject *this_object, const char *setting, int *status ) {
2066 /*
2067 *  Name:
2068 *     SetAttrib
2069 
2070 *  Purpose:
2071 *     Set an attribute value for an Axis.
2072 
2073 *  Type:
2074 *     Private function.
2075 
2076 *  Synopsis:
2077 *     #include "axis.h"
2078 *     void SetAttrib( AstObject *this, const char *setting, int *status )
2079 
2080 *  Class Membership:
2081 *     Axis member function (over-rides the protected astSetAttrib
2082 *     method inherited from the Object class).
2083 
2084 *  Description:
2085 *     This function assigns an attribute value for an Axis, the
2086 *     attribute and its value being specified by means of a string of
2087 *     the form:
2088 *
2089 *        "attribute= value "
2090 *
2091 *     Here, "attribute" specifies the attribute name and should be in
2092 *     lower case with no white space present. The value to the right
2093 *     of the "=" should be a suitable textual representation of the
2094 *     value to be assigned and this will be interpreted according to
2095 *     the attribute's data type.  White space surrounding the value is
2096 *     only significant for string attributes.
2097 
2098 *  Parameters:
2099 *     this
2100 *        Pointer to the Axis.
2101 *     setting
2102 *        Pointer to a null terminated string specifying the new
2103 *        attribute value.
2104 *     status
2105 *        Pointer to the inherited status variable.
2106 */
2107 
2108 /* Local Variables: */
2109    AstAxis *this;                /* Pointer to Axis structure */
2110    double dval;                  /* Double attribute value */
2111    int digits;                   /* Number of digits of precision */
2112    int direction;                /* Plot axis in normal direction? */
2113    int format;                   /* Offset of Format string */
2114    int label;                    /* Offset of Label string */
2115    int len;                      /* Length of setting string */
2116    int nc;                       /* Number of characters read from setting */
2117    int symbol;                   /* Offset of Symbol string */
2118    int unit;                     /* Offset of Unit string */
2119 
2120 /* Check the global error status. */
2121    if ( !astOK ) return;
2122 
2123 /* Obtain a pointer to the Axis structure. */
2124    this = (AstAxis *) this_object;
2125 
2126 /* Obtain the length of the setting string. */
2127    len = (int) strlen( setting );
2128 
2129 /* Test for each recognised attribute in turn, using "astSscanf" to parse
2130    the setting string and extract the attribute value (or an offset to
2131    it in the case of string values). In each case, use the value set
2132    in "nc" to check that the entire string was matched. Once a value
2133    has been obtained, use the appropriate method to set it. */
2134 
2135 /* Digits. */
2136 /* ------- */
2137    if ( nc = 0,
2138         ( 1 == astSscanf( setting, "digits= %d %n", &digits, &nc ) )
2139         && ( nc >= len ) ) {
2140       astSetAxisDigits( this, digits );
2141 
2142 /* Direction. */
2143 /* ---------- */
2144    } else if ( nc = 0,
2145         ( 1 == astSscanf( setting, "direction= %d %n", &direction, &nc ) )
2146         && ( nc >= len ) ) {
2147       astSetAxisDirection( this, direction );
2148 
2149 /* Top. */
2150 /* ---- */
2151    } else if ( nc = 0,
2152         ( 1 == astSscanf( setting, "top= %lg %n", &dval, &nc ) )
2153         && ( nc >= len ) ) {
2154       astSetAxisTop( this, dval );
2155 
2156 /* Bottom. */
2157 /* ------- */
2158    } else if ( nc = 0,
2159         ( 1 == astSscanf( setting, "bottom= %lg %n", &dval, &nc ) )
2160         && ( nc >= len ) ) {
2161       astSetAxisBottom( this, dval );
2162 
2163 /* Format. */
2164 /* ------- */
2165    } else if ( nc = 0,
2166         ( 0 == astSscanf( setting, "format=%n%*[^\n]%n", &format, &nc ) )
2167         && ( nc >= len ) ) {
2168       astSetAxisFormat( this, setting + format );
2169 
2170 /* Label. */
2171 /* ------ */
2172    } else if ( nc = 0,
2173         ( 0 == astSscanf( setting, "label=%n%*[^\n]%n", &label, &nc ) )
2174         && ( nc >= len ) ) {
2175       astSetAxisLabel( this, setting + label );
2176 
2177 /* Symbol. */
2178 /* ------- */
2179    } else if ( nc = 0,
2180         ( 0 == astSscanf( setting, "symbol=%n%*[^\n]%n", &symbol, &nc ) )
2181         && ( nc >= len ) ) {
2182       astSetAxisSymbol( this, setting + symbol );
2183 
2184 /* Unit. */
2185 /* ----- */
2186    } else if ( nc = 0,
2187         ( 0 == astSscanf( setting, "unit=%n%*[^\n]%n", &unit, &nc ) )
2188         && ( nc >= len ) ) {
2189       astSetAxisUnit( this, setting + unit );
2190 
2191 /* Read-only attributes. */
2192 /* --------------------- */
2193 /* Define a macro to see if the setting string matches any of the
2194    read-only attributes of this class. */
2195 #define MATCH(attrib) \
2196         ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \
2197                   ( nc >= len ) )
2198 
2199 /* Use this macro to report an error if a read-only attribute has been
2200    specified. */
2201    } else if ( MATCH( "normunit" ) ) {
2202       astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status,
2203                 setting, astGetClass( this ) );
2204       astError( AST__NOWRT, "This is a read-only attribute." , status);
2205 
2206 /* Pass any unrecognised attribute setting to the parent method for further
2207    interpretation. */
2208    } else {
2209       (*parent_setattrib)( this_object, setting, status );
2210    }
2211 
2212 /* Undefine macros local to this function. */
2213 #undef MATCH
2214 }
2215 
TestAttrib(AstObject * this_object,const char * attrib,int * status)2216 static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) {
2217 /*
2218 *  Name:
2219 *     TestAttrib
2220 
2221 *  Purpose:
2222 *     Test if a specified attribute value is set for an Axis.
2223 
2224 *  Type:
2225 *     Private function.
2226 
2227 *  Synopsis:
2228 *     #include "axis.h"
2229 *     int TestAttrib( AstObject *this, const char *attrib, int *status )
2230 
2231 *  Class Membership:
2232 *     Axis member function (over-rides the astTestAttrib protected
2233 *     method inherited from the Object class).
2234 
2235 *  Description:
2236 *     This function returns a boolean result (0 or 1) to indicate
2237 *     whether a value has been set for one of an Axis' attributes.
2238 
2239 *  Parameters:
2240 *     this
2241 *        Pointer to the Axis.
2242 *     attrib
2243 *        Pointer to a null-terminated string specifying the attribute
2244 *        name.  This should be in lower case with no surrounding white
2245 *        space.
2246 *     status
2247 *        Pointer to the inherited status variable.
2248 
2249 *  Returned Value:
2250 *     One if a value has been set, otherwise zero.
2251 
2252 *  Notes:
2253 *     - A value of zero will be returned if this function is invoked
2254 *     with the global status set, or if it should fail for any reason.
2255 */
2256 
2257 /* Local Variables: */
2258    AstAxis *this;                /* Pointer to the Axis structure */
2259    int result;                   /* Result value to return */
2260 
2261 /* Initialise. */
2262    result = 0;
2263 
2264 /* Check the global error status. */
2265    if ( !astOK ) return result;
2266 
2267 /* Obtain a pointer to the Axis structure. */
2268    this = (AstAxis *) this_object;
2269 
2270 /* Check the attribute name and test the appropriate attribute. */
2271 
2272 /* Digits. */
2273 /* ------- */
2274    if ( !strcmp( attrib, "digits" ) ) {
2275       result = astTestAxisDigits( this );
2276 
2277 /* Direction. */
2278 /* ---------- */
2279    } else if ( !strcmp( attrib, "direction" ) ) {
2280       result = astTestAxisDirection( this );
2281 
2282 /* Top. */
2283 /* ---- */
2284    } else if ( !strcmp( attrib, "top" ) ) {
2285       result = astTestAxisTop( this );
2286 
2287 /* Bottom. */
2288 /* ------- */
2289    } else if ( !strcmp( attrib, "bottom" ) ) {
2290       result = astTestAxisBottom( this );
2291 
2292 /* Format. */
2293 /* ------- */
2294    } else if ( !strcmp( attrib, "format" ) ) {
2295       result = astTestAxisFormat( this );
2296 
2297 /* Label. */
2298 /* ------ */
2299    } else if ( !strcmp( attrib, "label" ) ) {
2300       result = astTestAxisLabel( this );
2301 
2302 /* Symbol. */
2303 /* ------- */
2304    } else if ( !strcmp( attrib, "symbol" ) ) {
2305       result = astTestAxisSymbol( this );
2306 
2307 /* Unit. */
2308 /* ----- */
2309    } else if ( !strcmp( attrib, "unit" ) ) {
2310       result = astTestAxisUnit( this );
2311 
2312 /* NormUnit. */
2313 /* --------- */
2314    } else if ( !strcmp( attrib, "normunit" ) ) {
2315       result = astTestAxisNormUnit( this );
2316 
2317 /* If the attribute is still not recognised, pass it on to the parent
2318    method for further interpretation. */
2319    } else {
2320       result = (*parent_testattrib)( this_object, attrib, status );
2321    }
2322 
2323 /* Return the result, */
2324    return result;
2325 }
2326 
TestAxisNormUnit(AstAxis * this,int * status)2327 static int TestAxisNormUnit( AstAxis *this, int *status ){
2328 /*
2329 *  Name:
2330 *     TestAxisNormUnit
2331 
2332 *  Purpose:
2333 *     Test if a NormUnit attribute value is set for an Axis.
2334 
2335 *  Type:
2336 *     Private function.
2337 
2338 *  Synopsis:
2339 *     #include "axis.h"
2340 *     int TestAxisNormUnit( AstAxis *this, int *status )
2341 
2342 *  Class Membership:
2343 *     Axis member function
2344 
2345 *  Description:
2346 *     This function returns a boolean result (0 or 1) to indicate
2347 *     whether a value has been set for the NormUnit string.
2348 
2349 *  Parameters:
2350 *     this
2351 *        Pointer to the Axis.
2352 *     status
2353 *        Pointer to the inherited status variable.
2354 
2355 *  Returned Value:
2356 *     One if a value has been set, otherwise zero.
2357 
2358 *  Notes:
2359 *     - A value of zero will be returned if this function is invoked
2360 *     with the global status set, or if it should fail for any reason.
2361 */
2362 
2363    return astTestAxisUnit( this );
2364 }
2365 
2366 
2367 /* Functions which access class attributes. */
2368 /* ---------------------------------------- */
2369 /* Implement member functions to access the attributes associated with this
2370    class using the macros defined for this purpose in the "object.h" file. For
2371    a description of each attribute, see the class interface (in the associated
2372    .h file). */
2373 
2374 /* Digits. */
2375 /* ------- */
2376 /* Clear the Digits value by setting it to -INT_MAX. */
2377 astMAKE_CLEAR(Axis,AxisDigits,digits,-INT_MAX)
2378 
2379 /* Supply a default of 7 digits if no value has been set. */
2380 astMAKE_GET(Axis,AxisDigits,int,0,( this->digits != -INT_MAX ?
2381                                     this->digits : 7 ))
2382 
2383 /* Constrain the Digits value being set to be at least 1. */
2384 astMAKE_SET(Axis,AxisDigits,int,digits,( value > 1 ? value : 1 ))
2385 
2386 /* The Digits value is set if it is not -INT_MAX. */
2387 astMAKE_TEST(Axis,AxisDigits,( this->digits != -INT_MAX ))
2388 
2389 /* Direction. */
2390 /* ---------- */
2391 /* Clear the Direction value by setting it to -INT_MAX. */
2392 astMAKE_CLEAR(Axis,AxisDirection,direction,-INT_MAX)
2393 
2394 /* Supply a default value of 1 if the Direction value is not set. */
2395 astMAKE_GET(Axis,AxisDirection,int,0,( this->direction != -INT_MAX ?
2396                                        this->direction : 1 ))
2397 
2398 /* Set a Direction value of 1 if any non-zero value is supplied. */
2399 astMAKE_SET(Axis,AxisDirection,int,direction,( value != 0 ))
2400 
2401 /* The Direction value is set if it is not -INT_MAX. */
2402 astMAKE_TEST(Axis,AxisDirection,( this->direction != -INT_MAX ))
2403 
2404 /* Top. */
2405 /* -----*/
2406 /* Clear the Top Direction value by setting it to AST__BAD. */
astMAKE_CLEAR(Axis,AxisTop,top,AST__BAD)2407 astMAKE_CLEAR(Axis,AxisTop,top,AST__BAD)
2408 
2409 /* Supply a default value of DBL_MAX if the Top value is not set.*/
2410 astMAKE_GET(Axis,AxisTop,double,0,( this->top != AST__BAD ? this->top : DBL_MAX))
2411 
2412 /* Set the Top value. */
2413 astMAKE_SET(Axis,AxisTop,double,top,(value))
2414 
2415 /* The Top value is set if it is not AST__BAD. */
2416 astMAKE_TEST(Axis,AxisTop,( this->top != AST__BAD ))
2417 
2418 /* Bottom. */
2419 /* --------*/
2420 /* Clear the Bottom Direction value by setting it to AST__BAD. */
2421 astMAKE_CLEAR(Axis,AxisBottom,bottom,AST__BAD)
2422 
2423 /* Supply a default value of -DBL_MAX if the Bottom value is not set.*/
2424 astMAKE_GET(Axis,AxisBottom,double,0.0,( this->bottom != AST__BAD ? this->bottom : -DBL_MAX))
2425 
2426 /* Set the Bottom value. */
2427 astMAKE_SET(Axis,AxisBottom,double,bottom,(value))
2428 
2429 /* The Bottom value is set if it is not AST__BAD. */
2430 astMAKE_TEST(Axis,AxisBottom,( this->bottom != AST__BAD ))
2431 
2432 /* Format. */
2433 /* ------- */
2434 /* Clear the Format value by freeing the allocated memory and assigning a NULL
2435    pointer. */
2436 astMAKE_CLEAR(Axis,AxisFormat,format,astFree( this->format ))
2437 
2438 /* If the Format value is not set, return a pointer to a default Format
2439    string. */
2440 astMAKE_GET(Axis,AxisFormat,const char *,NULL,( this->format ? this->format :
2441             GetDefaultFormat( this, status ) ) )
2442 
2443 /* Set a Format value by freeing any previously allocated memory, allocating
2444    new memory, storing the string and saving the pointer to the copy. */
2445 astMAKE_SET(Axis,AxisFormat,const char *,format,astStore( this->format, value,
2446                                                 strlen( value ) + (size_t) 1 ))
2447 
2448 /* The Format value is set if the pointer to it is not NULL. */
2449 astMAKE_TEST(Axis,AxisFormat,( this->format != NULL ))
2450 
2451 /* Label. */
2452 /* ------ */
2453 /* Clear the Label value by freeing the allocated memory and assigning a NULL
2454    pointer. */
2455 astMAKE_CLEAR(Axis,AxisLabel,label,astFree( this->label ))
2456 
2457 /* If the Label value is not set, supply a default value by way of a pointer
2458    to the constant string "Coordinate Axis". */
2459 astMAKE_GET(Axis,AxisLabel,const char *,NULL,( this->label ? this->label :
2460                                                "Coordinate axis" ))
2461 
2462 /* Set a Label value by freeing any previously allocated memory, allocating
2463    new memory, storing the string and saving the pointer to the copy. */
2464 astMAKE_SET(Axis,AxisLabel,const char *,label,astStore( this->label, value,
2465                                               strlen( value ) + (size_t) 1 ))
2466 
2467 /* The Label value is set if the pointer to it is not NULL. */
2468 astMAKE_TEST(Axis,AxisLabel,( this->label != NULL ))
2469 
2470 /* Symbol. */
2471 /* ------- */
2472 /* Clear the Symbol value by freeing the allocated memory and assigning a NULL
2473    pointer. */
2474 astMAKE_CLEAR(Axis,AxisSymbol,symbol,astFree( this->symbol ))
2475 
2476 /* If the Symbol value is not set, supply a default value by way of a pointer
2477    to the constant string "x". */
2478 astMAKE_GET(Axis,AxisSymbol,const char *,NULL,( this->symbol ? this->symbol :
2479                                                                "x" ))
2480 
2481 /* Set a Symbol value by freeing any previously allocated memory, allocating
2482    new memory, storing the string and saving the pointer to the copy. */
2483 astMAKE_SET(Axis,AxisSymbol,const char *,symbol,astStore( this->symbol, value,
2484                                                 strlen( value ) + (size_t) 1 ))
2485 
2486 /* The Symbol value is set if the pointer to it is not NULL. */
2487 astMAKE_TEST(Axis,AxisSymbol,( this->symbol != NULL ))
2488 
2489 /* Unit. */
2490 /* ----- */
2491 /* Clear the Unit value by freeing the allocated memory and assigning a NULL
2492    pointer. */
2493 astMAKE_CLEAR(Axis,AxisUnit,unit,astFree( this->unit ))
2494 
2495 /* If the Unit value is not set, supply a default value by way of a pointer
2496    to the constant string "". */
2497 astMAKE_GET(Axis,AxisUnit,const char *,NULL,( this->unit ? this->unit : "" ))
2498 
2499 /* Set a Unit value by freeing any previously allocated memory, allocating
2500    new memory, storing the string and saving the pointer to the copy. */
2501 astMAKE_SET(Axis,AxisUnit,const char *,unit,astStore( this->unit, value,
2502                                             strlen( value ) + (size_t) 1 ))
2503 
2504 /* The Unit value is set if the pointer to it is not NULL. */
2505 astMAKE_TEST(Axis,AxisUnit,( this->unit != NULL ))
2506 
2507 /* Copy constructor. */
2508 /* ----------------- */
2509 static void Copy( const AstObject *objin, AstObject *objout, int *status ) {
2510 /*
2511 *  Name:
2512 *     Copy
2513 
2514 *  Purpose:
2515 *     Copy constructor for Axis objects.
2516 
2517 *  Type:
2518 *     Private function.
2519 
2520 *  Synopsis:
2521 *     void Copy( const AstObject *objin, AstObject *objout, int *status )
2522 
2523 *  Description:
2524 *     This function implements the copy constructor for Axis objects.
2525 
2526 *  Parameters:
2527 *     objin
2528 *        Pointer to the object to be copied.
2529 *     objout
2530 *        Pointer to the object being constructed.
2531 *     status
2532 *        Pointer to the inherited status variable.
2533 
2534 *  Returned Value:
2535 *     void
2536 
2537 *  Notes:
2538 *     -  This constructor makes a deep copy.
2539 */
2540 
2541 /* Local Variables: */
2542    AstAxis *in;                  /* Pointer to input Axis */
2543    AstAxis *out;                 /* Pointer to output Axis */
2544 
2545 /* Check the global error status. */
2546    if ( !astOK ) return;
2547 
2548 /* Obtain pointers to the input and output Axis structures. */
2549    in = (AstAxis *) objin;
2550    out = (AstAxis *) objout;
2551 
2552 /* For safety, first clear any references to the input memory from
2553    the output Axis. */
2554    out->format = NULL;
2555    out->label = NULL;
2556    out->symbol = NULL;
2557    out->unit = NULL;
2558 
2559 /* Make copies of the allocated strings and Objects. */
2560    if ( in->label ) out->label = astStore( NULL, in->label,
2561                                  strlen( in->label ) + (size_t) 1 );
2562    if ( in->format ) out->format = astStore( NULL, in->format,
2563                                    strlen( in->format ) + (size_t) 1 );
2564    if ( in->symbol ) out->symbol = astStore( NULL, in->symbol,
2565                                    strlen( in->symbol ) + (size_t) 1 );
2566    if ( in->unit ) out->unit = astStore( NULL, in->unit,
2567                                strlen( in->unit ) + (size_t) 1 );
2568 
2569 /* If an error occurred, clean up by freeing all memory allocated above. */
2570    if ( !astOK ) {
2571       out->format = astFree( out->format );
2572       out->label = astFree( out->label );
2573       out->symbol = astFree( out->symbol );
2574       out->unit = astFree( out->unit );
2575    }
2576 }
2577 
2578 /* Destructor. */
2579 /* ----------- */
Delete(AstObject * obj,int * status)2580 static void Delete( AstObject *obj, int *status ) {
2581 /*
2582 *  Name:
2583 *     Delete
2584 
2585 *  Purpose:
2586 *     Destructor for Axis objects.
2587 
2588 *  Type:
2589 *     Private function.
2590 
2591 *  Synopsis:
2592 *     void Delete( AstObject *obj, int *status )
2593 
2594 *  Description:
2595 *     This function implements the destructor for Axis objects.
2596 
2597 *  Parameters:
2598 *     obj
2599 *        Pointer to the object to be deleted.
2600 *     status
2601 *        Pointer to the inherited status variable.
2602 
2603 *  Returned Value:
2604 *     void
2605 
2606 *  Notes:
2607 *     This function attempts to execute even if the global error status is
2608 *     set.
2609 */
2610 
2611 /* Local Variables: */
2612    AstAxis *this;                /* Pointer to Axis */
2613 
2614 /* Obtain a pointer to the Axis structure. */
2615    this = (AstAxis *) obj;
2616 
2617 /* Free all allocated memory. */
2618    this->format = astFree( this->format );
2619    this->label = astFree( this->label );
2620    this->symbol = astFree( this->symbol );
2621    this->unit = astFree( this->unit );
2622 }
2623 
2624 /* Dump function. */
2625 /* -------------- */
Dump(AstObject * this_object,AstChannel * channel,int * status)2626 static void Dump( AstObject *this_object, AstChannel *channel, int *status ) {
2627 /*
2628 *  Name:
2629 *     Dump
2630 
2631 *  Purpose:
2632 *     Dump function for Axis objects.
2633 
2634 *  Type:
2635 *     Private function.
2636 
2637 *  Synopsis:
2638 *     void Dump( AstObject *this, AstChannel *channel, int *status )
2639 
2640 *  Description:
2641 *     This function implements the Dump function which writes out data
2642 *     for the Axis class to an output Channel.
2643 
2644 *  Parameters:
2645 *     this
2646 *        Pointer to the Axis whose data are being written.
2647 *     channel
2648 *        Pointer to the Channel to which the data are being written.
2649 *     status
2650 *        Pointer to the inherited status variable.
2651 */
2652 
2653 /* Local Variables: */
2654    AstAxis *this;                /* Pointer to the Axis structure */
2655    char comment[ 80 ];           /* Buffer for comment string */
2656    const char *sval;             /* Pointer to string value */
2657    const char *lab;              /* Pointer to unit label */
2658    double dval;                  /* Double value */
2659    int ival;                     /* Integer value */
2660    int set;                      /* Attribute value set? */
2661 
2662 /* Check the global error status. */
2663    if ( !astOK ) return;
2664 
2665 /* Obtain a pointer to the Axis structure. */
2666    this = (AstAxis *) this_object;
2667 
2668 /* Write out values representing the instance variables for the
2669    Axis class.  Accompany these with appropriate comment strings,
2670    possibly depending on the values being written.*/
2671 
2672 /* In the case of attributes, we first use the appropriate (private)
2673    Test...  member function to see if they are set. If so, we then use
2674    the (private) Get... function to obtain the value to be written
2675    out.
2676 
2677    For attributes which are not set, we use the astGet... method to
2678    obtain the value instead. This will supply a default value
2679    (possibly provided by a derived class which over-rides this method)
2680    which is more useful to a human reader as it corresponds to the
2681    actual default attribute value.  Since "set" will be zero, these
2682    values are for information only and will not be read back. */
2683 
2684 /* Label. */
2685 /* ------ */
2686    set = TestAxisLabel( this, status );
2687    sval = set ? GetAxisLabel( this, status ) : astGetAxisLabel( this );
2688    astWriteString( channel, "Label", set, 1, sval, "Axis Label" );
2689 
2690 /* Symbol. */
2691 /* ------- */
2692    set = TestAxisSymbol( this, status );
2693    sval = set ? GetAxisSymbol( this, status ) : astGetAxisSymbol( this );
2694    astWriteString( channel, "Symbol", set, 1, sval, "Axis symbol" );
2695 
2696 /* Unit. */
2697 /* ----- */
2698    set = TestAxisUnit( this, status );
2699    sval = set ? GetAxisUnit( this, status ) : astGetAxisUnit( this );
2700 
2701 /* Get any label associated with the unit string. */
2702    lab = astUnitLabel( sval );
2703 
2704 /* Construct a comment including the above label (but only if it is not
2705    the same as the unit string) . */
2706    if( lab && strcmp( lab, sval ) ) {
2707       (void) sprintf( comment, "Axis units (%s)", lab );
2708    } else {
2709       (void) sprintf( comment, "Axis units" );
2710    }
2711 
2712 /* Write out the Unit value. */
2713    astWriteString( channel, "Unit", set, 0, sval, comment );
2714 
2715 /* Digits. */
2716 /* ------- */
2717    set = TestAxisDigits( this, status );
2718    ival = set ? GetAxisDigits( this, status ) : astGetAxisDigits( this );
2719    astWriteInt( channel, "Digits", set, 0, ival,
2720                 "Default formatting precision" );
2721 
2722 /* Format. */
2723 /* ------- */
2724    set = TestAxisFormat( this, status );
2725    sval = set ? GetAxisFormat( this, status ) : astGetAxisFormat( this );
2726    astWriteString( channel, "Format", set, 0, sval, "Format specifier" );
2727 
2728 /* Direction. */
2729 /* ---------- */
2730    set = TestAxisDirection( this, status );
2731    ival = set ? GetAxisDirection( this, status ) : astGetAxisDirection( this );
2732    astWriteInt( channel, "Dirn", set, 0, ival,
2733                 ival ? "Plot in conventional direction (hint)" :
2734                        "Plot in reverse direction (hint)" );
2735 /* Top. */
2736 /* ---- */
2737    set = TestAxisTop( this, status );
2738    dval = set ? GetAxisTop( this, status ) : astGetAxisTop( this );
2739    astWriteDouble( channel, "Top", set, 0, dval, "Maximum legal axis value" );
2740 
2741 /* Bottom. */
2742 /* ------- */
2743    set = TestAxisBottom( this, status );
2744    dval = set ? GetAxisBottom( this, status ) : astGetAxisBottom( this );
2745    astWriteDouble( channel, "Bottom", set, 0, dval, "Minimum legal axis value" );
2746 }
2747 
2748 /* Standard class functions. */
2749 /* ========================= */
2750 /* Implement the astIsAAxis and astCheckAxis functions using the macros
2751    defined for this purpose in the "object.h" header file. */
astMAKE_ISA(Axis,Object)2752 astMAKE_ISA(Axis,Object)
2753 astMAKE_CHECK(Axis)
2754 
2755 AstAxis *astAxis_( const char *options, int *status, ...) {
2756 /*
2757 *+
2758 *  Name:
2759 *     astAxis
2760 
2761 *  Purpose:
2762 *     Create an Axis.
2763 
2764 *  Type:
2765 *     Public function.
2766 
2767 *  Synopsis:
2768 *     #include "axis.h"
2769 *     AstAxis *astAxis( const char *options, int *status, ... )
2770 
2771 *  Class Membership:
2772 *     Axis constructor.
2773 
2774 *  Description:
2775 *     This function creates a new Axis and optionally initialises its
2776 *     attributes.
2777 
2778 *  Parameters:
2779 *     options
2780 *        Pointer to a null terminated string containing an optional
2781 *        comma-separated list of attribute assignments to be used for
2782 *        initialising the new Axis. The syntax used is the same as for the
2783 *        astSet method and may include "printf" format specifiers identified
2784 *        by "%" symbols in the normal way.
2785 *     status
2786 *        Pointer to the inherited status variable.
2787 *     ...
2788 *        If the "options" string contains "%" format specifiers, then an
2789 *        optional list of arguments may follow it in order to supply values to
2790 *        be substituted for these specifiers. The rules for supplying these
2791 *        are identical to those for the astSet method (and for the C "printf"
2792 *        function).
2793 
2794 *  Returned Value:
2795 *     A pointer to the new Axis.
2796 
2797 *  Notes:
2798 *     -  A NULL pointer will be returned if this function is invoked with the
2799 *     global error status set, or if it should fail for any reason.
2800 *-
2801 */
2802 
2803 /* Local Variables: */
2804    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2805    AstAxis *new;                 /* Pointer to new Axis */
2806    va_list args;                 /* Variable argument list */
2807 
2808 /* Get a pointer to the thread specific global data structure. */
2809    astGET_GLOBALS(NULL);
2810 
2811 /* Check the global error status. */
2812    if ( !astOK ) return NULL;
2813 
2814 /* Initialise the Axis, allocating memory and initialising the virtual
2815    function table as well if necessary. */
2816    new = astInitAxis( NULL, sizeof( AstAxis ), !class_init, &class_vtab,
2817                       "Axis" );
2818 
2819 /* If successful, note that the virtual function table has been
2820    initialised. */
2821    if ( astOK ) {
2822       class_init = 1;
2823 
2824 /* Obtain the variable argument list and pass it along with the
2825    options string to the astVSet method to initialise the new Axis'
2826    attributes. */
2827       va_start( args, status );
2828       astVSet( new, options, NULL, args );
2829       va_end( args );
2830 
2831 /* If an error occurred, clean up by deleting the new object. */
2832       if ( !astOK ) new = astDelete( new );
2833    }
2834 
2835 /* Return a pointer to the new Axis. */
2836    return new;
2837 }
2838 
astAxisId_(const char * options,...)2839 AstAxis *astAxisId_( const char *options, ... ) {
2840 /*
2841 *  Name:
2842 *     astAxisId_
2843 
2844 *  Purpose:
2845 *     Create an Axis.
2846 
2847 *  Type:
2848 *     Private function.
2849 
2850 *  Synopsis:
2851 *     #include "axis.h"
2852 *     AstAxis *astAxisId_( const char *options, ... );
2853 
2854 *  Class Membership:
2855 *     Axis constructor.
2856 
2857 *  Description:
2858 *     This function implements the external (public) interface to the
2859 *     astAxis constructor function. It returns an ID value (instead of
2860 *     a true C pointer) to external users, and must be provided
2861 *     because astAxis_ has a variable argument list which cannot be
2862 *     encapsulated in a macro (where this conversion would otherwise
2863 *     occur).
2864 *
2865 *     The variable argument list also prevents this function from
2866 *     invoking astAxis_ directly, so it must be a re-implementation of
2867 *     it in all respects, except for the final conversion of the
2868 *     result to an ID value.
2869 
2870 *  Parameters:
2871 *     As for astAxis_.
2872 
2873 *  Returned Value:
2874 *     The ID value associated with the new Axis.
2875 */
2876 
2877 /* Local Variables: */
2878    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
2879    AstAxis *new;                 /* Pointer to new Axis */
2880    va_list args;                 /* Variable argument list */
2881 
2882    int *status;                  /* Pointer to inherited status value */
2883 
2884 /* Get a pointer to the inherited status value. */
2885    status = astGetStatusPtr;
2886 
2887 /* Get a pointer to the thread specific global data structure. */
2888    astGET_GLOBALS(NULL);
2889 
2890 /* Check the global error status. */
2891    if ( !astOK ) return NULL;
2892 
2893 /* Initialise the Axis, allocating memory and initialising the virtual
2894    function table as well if necessary. */
2895    new = astInitAxis( NULL, sizeof( AstAxis ), !class_init, &class_vtab,
2896                       "Axis" );
2897 
2898 /* If successful, note that the virtual function table has been
2899    initialised. */
2900    if ( astOK ) {
2901       class_init = 1;
2902 
2903 /* Obtain the variable argument list and pass it along with the
2904    options string to the astVSet method to initialise the new Axis'
2905    attributes. */
2906       va_start( args, options );
2907       astVSet( new, options, NULL, args );
2908       va_end( args );
2909 
2910 /* If an error occurred, clean up by deleting the new object. */
2911       if ( !astOK ) new = astDelete( new );
2912    }
2913 
2914 /* Return an ID value for the new Axis. */
2915    return astMakeId( new );
2916 }
2917 
astInitAxis_(void * mem,size_t size,int init,AstAxisVtab * vtab,const char * name,int * status)2918 AstAxis *astInitAxis_( void *mem, size_t size, int init,
2919                        AstAxisVtab *vtab, const char *name, int *status ) {
2920 /*
2921 *+
2922 *  Name:
2923 *     astInitAxis
2924 
2925 *  Purpose:
2926 *     Initialise an Axis.
2927 
2928 *  Type:
2929 *     Protected function.
2930 
2931 *  Synopsis:
2932 *     #include "axis.h"
2933 *     AstAxis *astInitAxis( void *mem, size_t size, int init,
2934 *                           AstAxisVtab *vtab, const char *name )
2935 
2936 *  Class Membership:
2937 *     Axis initialiser.
2938 
2939 *  Description:
2940 *     This function is provided for use by class implementations to initialise
2941 *     a new Axis object. It allocates memory (if necessary) to accommodate
2942 *     the Axis plus any additional data associated with the derived class.
2943 *     It then initialises an Axis structure at the start of this memory. If
2944 *     the "init" flag is set, it also initialises the contents of a virtual
2945 *     function table for an Axis at the start of the memory passed via the
2946 *     "vtab" parameter.
2947 
2948 *  Parameters:
2949 *     mem
2950 *        A pointer to the memory in which the Axis is to be created. This
2951 *        must be of sufficient size to accommodate the Axis data
2952 *        (sizeof(Axis)) plus any data used by the derived class. If a value
2953 *        of NULL is given, this function will allocate the memory itself using
2954 *        the "size" parameter to determine its size.
2955 *     size
2956 *        The amount of memory used by the Axis (plus derived class data).
2957 *        This will be used to allocate memory if a value of NULL is given for
2958 *        the "mem" parameter. This value is also stored in the Axis
2959 *        structure, so a valid value must be supplied even if not required for
2960 *        allocating memory.
2961 *     init
2962 *        A logical flag indicating if the Axis's virtual function table is
2963 *        to be initialised. If this value is non-zero, the virtual function
2964 *        table will be initialised by this function.
2965 *     vtab
2966 *        Pointer to the start of the virtual function table to be associated
2967 *        with the new Axis.
2968 *     name
2969 *        Pointer to a constant null-terminated character string which contains
2970 *        the name of the class to which the new object belongs (it is this
2971 *        pointer value that will subsequently be returned by the astClass
2972 *        method).
2973 
2974 *  Returned Value:
2975 *     A pointer to the new Axis.
2976 
2977 *  Notes:
2978 *     -  A NULL pointer will be returned if this function is invoked with the
2979 *     global error status set, or if it should fail for any reason.
2980 *-
2981 */
2982 
2983 /* Local Variables: */
2984    AstAxis *new;                 /* Pointer to new Axis */
2985 
2986 /* Check the global status. */
2987    if ( !astOK ) return NULL;
2988 
2989 /* If necessary, initialise the virtual function table. */
2990    if ( init ) astInitAxisVtab( vtab, name );
2991 
2992 /* Initialise an Object structure (the parent class) as the first component
2993    within the Axis structure, allocating memory if necessary. */
2994    new = (AstAxis *) astInitObject( mem, size, 0, (AstObjectVtab *) vtab,
2995                                     name );
2996 
2997    if ( astOK ) {
2998 
2999 /* Initialise the Axis data. */
3000 /* ------------------------- */
3001 /* Initialise all attributes to their "undefined" values. */
3002       new->digits = -INT_MAX;
3003       new->direction = -INT_MAX;
3004       new->format = NULL;
3005       new->label = NULL;
3006       new->symbol = NULL;
3007       new->unit = NULL;
3008       new->top = AST__BAD;
3009       new->bottom = AST__BAD;
3010 
3011 /* If an error occurred, clean up by deleting the new Axis. */
3012       if ( !astOK ) new = astDelete( new );
3013    }
3014 
3015 /* Return a pointer to the new Axis. */
3016    return new;
3017 }
3018 
astLoadAxis_(void * mem,size_t size,AstAxisVtab * vtab,const char * name,AstChannel * channel,int * status)3019 AstAxis *astLoadAxis_( void *mem, size_t size,
3020                        AstAxisVtab *vtab, const char *name,
3021                        AstChannel *channel, int *status ) {
3022 /*
3023 *+
3024 *  Name:
3025 *     astLoadAxis
3026 
3027 *  Purpose:
3028 *     Load an Axis.
3029 
3030 *  Type:
3031 *     Protected function.
3032 
3033 *  Synopsis:
3034 *     #include "axis.h"
3035 *     AstAxis *astLoadAxis( void *mem, size_t size,
3036 *                           AstAxisVtab *vtab, const char *name,
3037 *                           AstChannel *channel )
3038 
3039 *  Class Membership:
3040 *     Axis loader.
3041 
3042 *  Description:
3043 *     This function is provided to load a new Axis using data read
3044 *     from a Channel. It first loads the data used by the parent class
3045 *     (which allocates memory if necessary) and then initialises a
3046 *     Axis structure in this memory, using data read from the input
3047 *     Channel.
3048 *
3049 *     If the "init" flag is set, it also initialises the contents of a
3050 *     virtual function table for a Axis at the start of the memory
3051 *     passed via the "vtab" parameter.
3052 
3053 
3054 *  Parameters:
3055 *     mem
3056 *        A pointer to the memory into which the Axis is to be
3057 *        loaded.  This must be of sufficient size to accommodate the
3058 *        Axis data (sizeof(Axis)) plus any data used by derived
3059 *        classes. If a value of NULL is given, this function will
3060 *        allocate the memory itself using the "size" parameter to
3061 *        determine its size.
3062 *     size
3063 *        The amount of memory used by the Axis (plus derived class
3064 *        data).  This will be used to allocate memory if a value of
3065 *        NULL is given for the "mem" parameter. This value is also
3066 *        stored in the Axis structure, so a valid value must be
3067 *        supplied even if not required for allocating memory.
3068 *
3069 *        If the "vtab" parameter is NULL, the "size" value is ignored
3070 *        and sizeof(AstAxis) is used instead.
3071 *     vtab
3072 *        Pointer to the start of the virtual function table to be
3073 *        associated with the new Axis. If this is NULL, a pointer
3074 *        to the (static) virtual function table for the Axis class
3075 *        is used instead.
3076 *     name
3077 *        Pointer to a constant null-terminated character string which
3078 *        contains the name of the class to which the new object
3079 *        belongs (it is this pointer value that will subsequently be
3080 *        returned by the astGetClass method).
3081 *
3082 *        If the "vtab" parameter is NULL, the "name" value is ignored
3083 *        and a pointer to the string "Axis" is used instead.
3084 
3085 *  Returned Value:
3086 *     A pointer to the new Axis.
3087 
3088 *  Notes:
3089 *     - A null pointer will be returned if this function is invoked
3090 *     with the global error status set, or if it should fail for any
3091 *     reason.
3092 *-
3093 */
3094 
3095 /* Local Variables: */
3096    astDECLARE_GLOBALS            /* Pointer to thread-specific global data */
3097    AstAxis *new;                 /* Pointer to the new Axis */
3098 
3099 /* Initialise. */
3100    new = NULL;
3101 
3102 /* Check the global error status. */
3103    if ( !astOK ) return new;
3104 
3105 /* Get a pointer to the thread specific global data structure. */
3106    astGET_GLOBALS(channel);
3107 
3108 /* If a NULL virtual function table has been supplied, then this is
3109    the first loader to be invoked for this Axis. In this case the
3110    Axis belongs to this class, so supply appropriate values to be
3111    passed to the parent class loader (and its parent, etc.). */
3112    if ( !vtab ) {
3113       size = sizeof( AstAxis );
3114       vtab = &class_vtab;
3115       name = "Axis";
3116 
3117 /* If required, initialise the virtual function table for this class. */
3118       if ( !class_init ) {
3119          astInitAxisVtab( vtab, name );
3120          class_init = 1;
3121       }
3122    }
3123 
3124 /* Invoke the parent class loader to load data for all the ancestral
3125    classes of the current one, returning a pointer to the resulting
3126    partly-built Axis. */
3127    new = astLoadObject( mem, size, (AstObjectVtab *) vtab, name,
3128                         channel );
3129 
3130    if ( astOK ) {
3131 
3132 /* Read input data. */
3133 /* ================ */
3134 /* Request the input Channel to read all the input data appropriate to
3135    this class into the internal "values list". */
3136       astReadClassData( channel, "Axis" );
3137 
3138 /* Now read each individual data item from this list and use it to
3139    initialise the appropriate instance variable(s) for this class. */
3140 
3141 /* In the case of attributes, we first read the "raw" input value,
3142    supplying the "unset" value as the default. If a "set" value is
3143    obtained, we then use the appropriate (private) Set... member
3144    function to validate and set the value properly. */
3145 
3146 /* Label. */
3147 /* ------ */
3148 /* Note that string values do not require any additional processing. */
3149       new->label = astReadString( channel, "label", NULL );
3150 
3151 /* Symbol. */
3152 /* ------- */
3153       new->symbol = astReadString( channel, "symbol", NULL );
3154 
3155 /* Unit. */
3156 /* ----- */
3157       new->unit = astReadString( channel, "unit", NULL );
3158 
3159 /* Digits. */
3160 /* ------- */
3161       new->digits = astReadInt( channel, "digits", -INT_MAX );
3162       if ( TestAxisDigits( new, status ) ) SetAxisDigits( new, new->digits, status );
3163 
3164 /* Format. */
3165 /* ------- */
3166       new->format = astReadString( channel, "format", NULL );
3167 
3168 /* Direction. */
3169 /* ---------- */
3170       new->direction = astReadInt( channel, "dirn", -INT_MAX );
3171       if ( TestAxisDirection( new, status ) ) SetAxisDirection( new, new->direction, status );
3172 
3173 /* Top. */
3174 /* ---- */
3175       new->top = astReadDouble( channel, "top", AST__BAD );
3176       if ( TestAxisTop( new, status ) ) SetAxisTop( new, new->top, status );
3177 
3178 /* Bottom. */
3179 /* ---- */
3180       new->bottom = astReadDouble( channel, "bottom", AST__BAD );
3181       if ( TestAxisBottom( new, status ) ) SetAxisBottom( new, new->bottom, status );
3182 
3183 /* If an error occurred, clean up by deleting the new Axis. */
3184       if ( !astOK ) new = astDelete( new );
3185    }
3186 
3187 /* Return the new Axis pointer. */
3188    return new;
3189 }
3190 
3191 /* Virtual function interfaces. */
3192 /* ============================ */
3193 /* These provide the external interface to the virtual functions defined by
3194    this class. Each simply checks the global error status and then locates and
3195    executes the appropriate member function, using the function pointer stored
3196    in the object's virtual function table (this pointer is located using the
3197    astMEMBER macro defined in "object.h").
3198 
3199    Note that the member function may not be the one defined here, as it may
3200    have been over-ridden by a derived class. However, it should still have the
3201    same interface. */
3202 
3203 /* External interfaces for the attribute access functions are generated
3204    automatically by the macros that implement the access functions themselves.
3205    Hence, we need only provide external interfaces for a few additional
3206    functions here. */
astAxisAbbrev_(AstAxis * this,const char * fmt,const char * str1,const char * str2,int * status)3207 const char *astAxisAbbrev_( AstAxis *this, const char *fmt,
3208                             const char *str1, const char *str2, int *status ) {
3209    if ( !astOK ) return str2;
3210    return (**astMEMBER(this,Axis,AxisAbbrev))( this, fmt, str1, str2, status );
3211 }
astAxisFormat_(AstAxis * this,double value,int * status)3212 const char *astAxisFormat_( AstAxis *this, double value, int *status ) {
3213    if ( !astOK ) return NULL;
3214    return (**astMEMBER(this,Axis,AxisFormat))( this, value, status );
3215 }
astAxisDistance_(AstAxis * this,double v1,double v2,int * status)3216 double astAxisDistance_( AstAxis *this, double v1, double v2, int *status ) {
3217    if ( !astOK ) return AST__BAD;
3218    return (**astMEMBER(this,Axis,AxisDistance))( this, v1, v2, status );
3219 }
astAxisOffset_(AstAxis * this,double v1,double dist,int * status)3220 double astAxisOffset_( AstAxis *this, double v1, double dist, int *status ) {
3221    if ( !astOK ) return AST__BAD;
3222    return (**astMEMBER(this,Axis,AxisOffset))( this, v1, dist, status );
3223 }
astAxisGap_(AstAxis * this,double gap,int * ntick,int * status)3224 double astAxisGap_( AstAxis *this, double gap, int *ntick, int *status ) {
3225    if ( !astOK ) return 0.0;
3226    return (**astMEMBER(this,Axis,AxisGap))( this, gap, ntick, status );
3227 }
astAxisNorm_(AstAxis * this,double * value,int * status)3228 void astAxisNorm_( AstAxis *this, double *value, int *status ) {
3229    if ( !astOK ) return;
3230    (**astMEMBER(this,Axis,AxisNorm))( this, value, status );
3231 }
astAxisOverlay_(AstAxis * template,AstAxis * result,int * status)3232 void astAxisOverlay_( AstAxis *template, AstAxis *result, int *status ) {
3233    if ( !astOK ) return;
3234    (**astMEMBER(template,Axis,AxisOverlay))( template, result, status );
3235 }
astAxisUnformat_(AstAxis * this,const char * string,double * value,int * status)3236 int astAxisUnformat_( AstAxis *this, const char *string, double *value, int *status ) {
3237    if ( !astOK ) return 0;
3238    return (**astMEMBER(this,Axis,AxisUnformat))( this, string, value, status );
3239 }
astAxisFields_(AstAxis * this,const char * fmt,const char * str,int maxfld,char ** fields,int * nc,double * val,int * status)3240 int astAxisFields_( AstAxis *this, const char *fmt, const char *str,
3241                     int maxfld, char **fields, int *nc, double *val, int *status ) {
3242    if ( !astOK ) return 0;
3243    return (**astMEMBER(this,Axis,AxisFields))( this, fmt, str, maxfld, fields, nc, val, status );
3244 }
astAxisIn_(AstAxis * this,double lo,double hi,double val,int closed,int * status)3245 int astAxisIn_( AstAxis *this, double lo, double hi, double val, int closed, int *status ){
3246    if ( !astOK ) return 0;
3247    return (**astMEMBER(this,Axis,AxisIn))( this, lo, hi, val, closed, status );
3248 }
astGetAxisNormUnit_(AstAxis * this,int * status)3249 const char *astGetAxisNormUnit_( AstAxis *this, int *status ) {
3250    if ( !astOK ) return NULL;
3251    return (**astMEMBER(this,Axis,GetAxisNormUnit))( this, status );
3252 }
astTestAxisNormUnit_(AstAxis * this,int * status)3253 int astTestAxisNormUnit_( AstAxis *this, int *status ) {
3254    if ( !astOK ) return 0;
3255    return (**astMEMBER(this,Axis,TestAxisNormUnit))( this, status );
3256 }
3257 
3258 
3259 
3260 
3261 
3262 
3263 
3264 
3265 
3266