1 /*
2 * Name:
3 * error.c
4
5 * Purpose:
6 * Implement error handling functions.
7
8 * Description:
9 * This file implements the Error module which provides functions
10 * for handling error conditions in the AST library. For a
11 * description of the module and its interface, see the .h file of
12 * the same name.
13 *
14 * Since its initial release, AST has used a global status variable
15 * rather than adding an explicit status parameter to the argument
16 * list of each AST function. This caused problems for the thread-safe
17 * version of AST since each thread needs its own status value. Whilst
18 * it would have been possible for each function to access a global
19 * status value via the pthreads "thread speific data key" mechanism,
20 * the huge number of status checks performed within AST caused this
21 * option to be slow. Instead AST has been modified so that every
22 * function has an explicit status pointer parameter. This though
23 * causes problems in that we cannot change the public interface to
24 * AST because doing so would break large amounts of external software.
25 * To get round this, the macros that define the public interface to
26 * AST have been modified so that they provide a status pointer
27 * automatically to the function that is being invoked. This is how
28 * the system works...
29 *
30 * All AST functions have an integer inherited status pointer parameter
31 * called "status". This parameter is "hidden" in AST functions that
32 * are invoked via macros (typically public and protected functions).
33 * This means that whilst "int *status" appears explicitly at the end
34 * of the function argument list (in both prototype and definition), it
35 * is not included in the prologue documentation, and is not included
36 * explicitly in the argument list when invoking the function. Instead,
37 * the macro that is used to invoke the function adds in the required
38 * status parameter to the function invocation.
39 *
40 * Macros which are invoked within AST (the protected interface) expand
41 * to include ", status" at the end of the function parameter list. For
42 * backward compatability with previous versions of AST, macros which
43 * are invoked from outside AST (the public interface) expand to include
44 * ", astGetStatusPtr" at the end of the function parameter list. The
45 * astGetStatusPtr function returns a pointer to the interbal AST
46 * status variable or to the external variable specified via astWatch.
47 *
48 * Parameter lists for functions that have variable argument lists
49 * (such as astError) cannot be handled in this way, since macros cannot
50 * have variable numbers of arguments. Instead, separate public and
51 * protected implementations of such functions are provided within AST.
52 * Protected implementations include an explicit, documented status
53 * pointer parameter that must be given explicitly when invoking the
54 * function. Public implementations do not have a status pointer
55 * parameter. Instead they obtain the status pointer internally using
56 * astGetStatusPtr.
57 *
58 * Private functions are called directly rather than via macros, and so
59 * they have a documented status pointer parameter that should be
60 * included explicitly in the parameter list when invoking the
61 * function.
62
63 * Copyright:
64 * Copyright (C) 1997-2006 Council for the Central Laboratory of the
65 * Research Councils
66 * Copyright (C) 2008-2009 Science & Technology Facilities Council.
67 * All Rights Reserved.
68
69 * Licence:
70 * This program is free software: you can redistribute it and/or
71 * modify it under the terms of the GNU Lesser General Public
72 * License as published by the Free Software Foundation, either
73 * version 3 of the License, or (at your option) any later
74 * version.
75 *
76 * This program is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
79 * GNU Lesser General Public License for more details.
80 *
81 * You should have received a copy of the GNU Lesser General
82 * License along with this program. If not, see
83 * <http://www.gnu.org/licenses/>.
84
85 * Authors:
86 * RFWS: R.F. Warren-Smith (Starlink)
87 * DSB: David S. Berry (Starlink)
88
89 * History:
90 * 2-JAN-1996 (RFWS):
91 * Original version.
92 * 8-JAN-1996 (RFWS):
93 * Tidied up.
94 * 26-JAN-1996 (RFWS):
95 * Incorporated changes to prologue style.
96 * 14-JUN-1996 (RFWS):
97 * Added astAt.
98 * 20-JUN-1996 (RFWS):
99 * Added astSetStatus.
100 * 15-JUL-1996 (RFWS):
101 * Sorted out the public interface.
102 * 16-JUL-1996 (RFWS):
103 * Added astWatch.
104 * 18-MAR-1998 (RFWS):
105 * Added notes about functions being available for writing
106 * foreign language and graphics interfaces, etc.
107 * 27-NOV-2002 (DSB):
108 * Added suppression of error reporting using astReporting.
109 * 11-MAR-2004 (DSB):
110 * Add facility to astAt to allow astAt to be called from public
111 * interface without private interface settings over-riding the
112 * public interface settings.
113 * 30-MAR-2005 (DSB):
114 * Added facility to report deferred messages when reporting is
115 * switched back on.
116 * 16-FEB-2006 (DSB):
117 * Improve efficiency by replacing the astOK_ function with a macro
118 * which tests the value of status variable. The pointer which points
119 * to the AST status variable are now global rather than static.
120 * 19-SEP-2008 (DSB):
121 * Big changes for the thread-safe version of AST.
122 * 3-FEB-2009 (DSB):
123 * Added astBacktrace.
124 */
125
126 /* Define the astCLASS macro (even although this is not a class
127 implementation) to obtain access to protected interfaces. */
128 #define astCLASS
129
130 /* Include files. */
131 /* ============== */
132 /* Interface definitions. */
133 /* ---------------------- */
134 #include "err.h" /* Interface to the err module */
135 #include "error.h" /* Interface to this module */
136 #include "globals.h" /* Thread-safe global data access */
137
138 /* C header files. */
139 /* --------------- */
140 #include <stdarg.h>
141 #include <stdio.h>
142 #include <stdlib.h>
143 #include <string.h>
144
145 /* Configuration results. */
146 /* ---------------------- */
147 #if HAVE_CONFIG_H
148 #include <config.h>
149 #endif
150
151 /* Select the appropriate memory management functions. These will be the
152 system's malloc, free and realloc unless AST was configured with the
153 "--with-starmem" option, in which case they will be the starmem
154 malloc, free and realloc. */
155 #ifdef HAVE_STAR_MEM_H
156 # include <star/mem.h>
157 # define MALLOC starMalloc
158 # define FREE starFree
159 # define REALLOC starRealloc
160 #else
161 # define MALLOC malloc
162 # define FREE free
163 # define REALLOC realloc
164 #endif
165
166 /* Include execinfo.h if the backtrace function is available */
167 #if HAVE_EXECINFO_H
168 #include <execinfo.h>
169 #endif
170
171
172
173 /* Module Variables. */
174 /* ================= */
175
176 /* Define macros for accessing all items of thread-safe global data
177 used by this module. */
178 #ifdef THREAD_SAFE
179
180 #define reporting astGLOBAL(Error,Reporting)
181 #define current_file astGLOBAL(Error,Current_File)
182 #define current_routine astGLOBAL(Error,Current_Routine)
183 #define current_line astGLOBAL(Error,Current_Line)
184 #define foreign_set astGLOBAL(Error,Foreign_Set)
185 #define message_stack astGLOBAL(Error,Message_Stack)
186 #define mstack_size astGLOBAL(Error,Mstack_Size)
187
188 /* Since the external astPutErr function may not be thread safe, we need
189 to ensure that it cannot be invoked simultaneously from two different
190 threads. So we lock a mutex before each call to astPutErr. */
191 static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
192
193 #define INVOKE_ASTPUTERR( status, buff ) \
194 ( pthread_mutex_lock( &mutex1 ), \
195 astPutErr( (status), (buff) ), \
196 (void) pthread_mutex_unlock( &mutex1 ) )
197
198 /* Define the initial values for the global data for this module. */
199 #define GLOBAL_inits \
200 globals->Reporting = 1; \
201 globals->Current_File = NULL; \
202 globals->Current_Routine = NULL; \
203 globals->Current_Line = 0; \
204 globals->Foreign_Set = 0; \
205 globals->Mstack_Size = 0; \
206
207 /* Create the global initialisation function. */
208 astMAKE_INITGLOBALS(Error)
209
210
211 /* If thread safety is not needed, declare globals at static variables. */
212 /* -------------------------------------------------------------------- */
213 #else
214
215 /* Status variable. */
216 static int internal_status = 0; /* Internal error status */
217 int *starlink_ast_status_ptr = &internal_status; /* Pointer to status variable */
218
219 /* Reporting flag: delivery of message is supressed if zero. */
220 static int reporting = 1;
221
222 /* Error context. */
223 static const char *current_file = NULL; /* Current file name pointer */
224 static const char *current_routine = NULL; /* Current routine name pointer */
225 static int current_line = 0; /* Current line number */
226 static int foreign_set = 0; /* Have foreign values been set? */
227
228 /* Un-reported message stack */
229 static char *message_stack[ AST__ERROR_MSTACK_SIZE ];
230 static int mstack_size = 0;
231
232 /* If thread-safety is not needed, we can invoke the external astPutErr
233 function directly. */
234 #define INVOKE_ASTPUTERR( status, buff ) \
235 astPutErr( (status), (buff) );
236
237 #endif
238
239
240 /* Function prototypes. */
241 /* ==================== */
242 static void EmptyStack( int, int * );
243
244 /* Function implementations. */
245 /* ========================= */
astAt_(const char * routine,const char * file,int line,int forn,int * status)246 void astAt_( const char *routine, const char *file, int line, int forn,
247 int *status) {
248 /*
249 *+
250 * Name:
251 * astAt
252
253 * Purpose:
254 * Store a routine, file and line number context in case of error.
255
256 * Type:
257 * Protected function.
258
259 * Synopsis:
260 * #include "error.h"
261 * void astAt( const char *routine, const char *file, int line, int forn)
262
263 * Description:
264 * This function stores a pointer to two strings containing the
265 * names of a routine and a file, together with an integer line
266 * number. These values are retained for subsequent use in
267 * reporting the context of any error that may arise.
268
269 * Parameters:
270 * routine
271 * Pointer to a null terminated C string containing a routine
272 * name (which should reside in static memory).
273 * file
274 * Pointer to a null terminated C string containing a file name
275 * (which should reside in static memory).
276 * line
277 * The line number in the file.
278 * for
279 * Is this call being made from a foreign language interface?
280 * If so any values supplied will take precedence of the values
281 * set by the C interface.
282
283 * Notes:
284 * - This function returns without action (i.e. without changing
285 * the stored values) if the global error status is set. It
286 * performs no other error checking.
287 * - Any (or all) of the arguments may be omitted by supplying a
288 * NULL or zero value (as appropriate) and will then not be included
289 * in any error report.
290 * - This function is documented as protected because it should not
291 * be invoked by external code. However, it is available via the
292 * external C interface so that it may be used when writing (e.g.)
293 * foreign language or graphics interfaces.
294 *-
295 */
296
297 /* Local Variables: */
298 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
299
300 /* Check the global error status. */
301 if ( !astOK ) return;
302
303 /* If needed, get a pointer to the thread specific global data structure. */
304 astGET_GLOBALS(NULL);
305
306 /* If the values refer to a foreign interface, or if no foreign values
307 have yet been set, store the supplied values. */
308 if( forn|| !foreign_set ) {
309 current_routine = routine;
310 current_file = file;
311 current_line = line;
312 }
313
314 /* If the values relate to a foreign interface, set a flag which prevents
315 local values set later replacing them. */
316 foreign_set = forn;
317 }
318
astBacktrace_(int * status)319 void astBacktrace_( int *status ) {
320 /*
321 c+
322 * Name:
323 * astBacktrace
324
325 * Purpose:
326 * Display a backtrace on standard output.
327
328 * Type:
329 * Protected macro.
330
331 * Synopsis:
332 * #include "error.h"
333 * astBacktrace;
334
335 * Description:
336 * This macro displays a set of messages on standard output that
337 * give a backtrace of the caller. It can be useful for debugging AST
338 * code in situations when it is not easy or possible to use a
339 * debugger (for instance, when debugging JNIAST).
340
341 * Notes:
342 * - Only non-static function names are included in the backtrace.
343 * - This function requires the GNU C library. When called, it will
344 * just issue a warning if the GNU 'backtrace' function was not
345 * available when AST was configured.
346 c-
347 */
348 #if HAVE_BACKTRACE
349
350 #define MAX_ADDR 100
351
352 /* Local Variables: */
353 char **strings; /* Pointer to array of formated strings */
354 char buf[ 120 ]; /* Output line buffer */
355 int j; /* String index */
356 int np; /* Number of used return addresses */
357 void *buffer[ MAX_ADDR ]; /* Array of return addresses */
358
359 /* Get the array of return addresses. */
360 np = backtrace( buffer, MAX_ADDR );
361
362 /* Convert them into strings. */
363 strings = backtrace_symbols( buffer, np );
364
365 /* If succesful, display them and then free the array. Note we skip the
366 first one since that will refer to this function. */
367 if( strings ) {
368 INVOKE_ASTPUTERR( astStatus, " " );
369 for( j = 1; j < np; j++ ) {
370 sprintf( buf, "%d: %s", j, strings[j] );
371 INVOKE_ASTPUTERR( astStatus, buf );
372 }
373 free( strings );
374 INVOKE_ASTPUTERR( astStatus, " " );
375
376 /* If not succesful, issue a warning. */
377 } else {
378 INVOKE_ASTPUTERR( astStatus, "Cannot convert backtrace addresses into formatted strings" );
379 }
380
381 #else
382 INVOKE_ASTPUTERR( astStatus, "Backtrace functionality is not available "
383 "on the current operating system." );
384 #endif
385 }
386
astClearStatus_(int * status)387 void astClearStatus_( int *status ) {
388 /*
389 c++
390 * Name:
391 * astClearStatus
392
393 * Purpose:
394 * Clear the AST error status.
395
396 * Type:
397 * Public macro.
398
399 * Synopsis:
400 * #include "error.h"
401 * void astClearStatus
402
403 * Description:
404 * This macro resets the AST error status to an OK value,
405 * indicating that an error condition (if any) has been cleared.
406
407 * Notes:
408 * - If the AST error status is set to an error value (after an
409 * error), most AST functions will not execute and will simply
410 * return without action. Using astClearStatus will restore normal
411 * behaviour.
412 c--
413 */
414
415 /* Empty the deferred error stack without displaying the messages on the
416 stack. */
417 EmptyStack( 0, status );
418
419 /* Reset the error status value. */
420 *status = 0;
421 }
422
EmptyStack(int display,int * status)423 static void EmptyStack( int display, int *status ) {
424 /*
425 * Name:
426 * EmptyStack
427
428 * Purpose:
429 * Empty the stack of deferred error messages, optionally displaying
430 * them.
431
432 * Type:
433 * Private function.
434
435 * Synopsis:
436 * #include "error.h"
437 * void EmptyStack( int display, int *status )
438
439 * Description:
440 * This function removes all messages from the stack of deferred error
441 * messages. If "display" is non-zero it reports them using astPutErr
442 * before deleting them.
443
444 * Parameters:
445 * display
446 * Report messages before deleting them?
447 * status
448 * Pointer to the integer holding the inherited status value.
449
450 */
451
452 /* Local variables; */
453 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
454 int i;
455
456 /* If needed, get a pointer to the thread specific global data structure. */
457 astGET_GLOBALS(NULL);
458
459 /* Loop round all messages on the stack. */
460 for( i = 0; i < mstack_size; i++ ) {
461
462 /* Display the message if required. */
463 if( display ) INVOKE_ASTPUTERR( astStatus, message_stack[ i ] );
464
465 /* Free the memory used to hold the message. */
466 FREE( message_stack[ i ] );
467 message_stack[ i ] = NULL;
468 }
469
470 /* Reset the stack size to zero. */
471 mstack_size = 0;
472
473 }
474
astErrorPublic_(int status_value,const char * fmt,...)475 void astErrorPublic_( int status_value, const char *fmt, ... ) {
476 /*
477 *+
478 * Name:
479 * astError
480
481 * Purpose:
482 * Set the AST error status and report an error message.
483
484 * Type:
485 * Protected function.
486
487 * Synopsis:
488 * #include "error.h"
489 * void astError( int status_value, const char *fmt, ... )
490
491 * Description:
492 * This function sets the AST error status to a specified value and
493 * reports an associated error message.
494
495 * Parameters:
496 * status_value
497 * The new error status value to be set.
498 * fmt
499 * Pointer to a null-terminated character string containing the
500 * format specification for the error message, in the same way
501 * as for a call to the C "printf" family of functions.
502 * ...
503 * Additional optional arguments (as used by e.g. "printf")
504 * which specify values which are to appear in the error
505 * message.
506
507 * Notes:
508 * This function operates just like "printf", except that:
509 * - The first argument is an error status.
510 * - The return value is void.
511 * - A newline is automatically appended to the error message
512 * (there is no need to add one).
513 * - This function is documented as protected because it should not
514 * be invoked by external code. However, it is available via the
515 * external C interface so that it may be used when writing (e.g.)
516 * foreign language or graphics interfaces.
517 *-
518
519 * This is the public implementation of astError. It does not have an
520 status pointer parameter, but instead obtains the status pointer
521 explicitly using the astGetStatusPtr function. This is different to
522 other public functions, which typically have a status pointer parameter
523 that is supplied via a call to astGetStatusPtr within the associated
524 interface macro. The benefit of doing it the usual way is that the
525 public and protected implementations are the same, with the
526 differences between public and protecte dinterfaces wrapped up in the
527 associated interface macro. We cannot do this with this function
528 because of the variale argument list. The prologue for the astError_
529 function defines the interface for use internally within AST.
530
531 */
532
533 /* Local Constants: */
534 #define BUFF_LEN 1023 /* Max. length of an error message */
535
536 /* Local Variables: */
537 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
538 char buff[ BUFF_LEN + 1 ]; /* Message buffer */
539 int *status; /* Pointer to inherited status value */
540 int imess; /* Index into deferred message stack */
541 int nc; /* Number of characters written */
542 va_list args; /* Variable argument list pointer */
543
544 /* Initialise the variable argument list pointer. */
545 va_start( args, fmt );
546
547 /* If needed, get a pointer to the thread specific global data structure. */
548 astGET_GLOBALS(NULL);
549
550 /* Get a pointer to the integer holding the inherited status value. */
551 status = astGetStatusPtr;
552
553 /* If this is the first report of an error (the global status has not
554 previously been set) and error context information is available,
555 then construct an error context message. */
556 if ( astOK &&
557 ( current_routine || current_file || current_line ) ) {
558 nc = sprintf( buff, "AST: Error" );
559 if ( current_routine ) {
560 nc += sprintf( buff + nc, " in routine %s", current_routine );
561 }
562 if ( current_line ) {
563 nc += sprintf( buff + nc, " at line %d", current_line );
564 }
565 if ( current_file ) {
566 nc += sprintf( buff + nc, " in file %s", current_file );
567 }
568 nc += sprintf( buff + nc, "." );
569
570 /* Deliver the error message unless reporting has been switched off using
571 astReporting. In which case store them in a static array. */
572 if( reporting ) {
573 INVOKE_ASTPUTERR( status_value, buff );
574 } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){
575 imess = mstack_size++;
576 message_stack[ imess ] = MALLOC( strlen( buff ) + 1 );
577 if( message_stack[ imess ] ) {
578 strcpy( message_stack[ imess ], buff );
579 }
580 }
581
582 /* Set the global status. */
583 astSetStatus( status_value );
584 }
585
586 /* Write the error message supplied to the formatting buffer. */
587 nc = vsprintf( buff, fmt, args );
588
589 /* Tidy up the argument pointer. */
590 va_end( args );
591
592 /* Deliver the error message unless reporting has been switched off using
593 astReporting. */
594 if( reporting ) {
595 INVOKE_ASTPUTERR( status_value, buff );
596 } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){
597 imess = mstack_size++;
598 message_stack[ imess ] = MALLOC( strlen( buff ) + 1 );
599 if( message_stack[ imess ] ) {
600 strcpy( message_stack[ imess ], buff );
601 }
602 }
603
604 /* Set the error status value. */
605 astSetStatus( status_value );
606
607 /* Undefine macros local to this function. */
608 #undef BUFF_LEN
609 }
610
astError_(int status_value,const char * fmt,int * status,...)611 void astError_( int status_value, const char *fmt, int *status, ... ) {
612 /*
613 *+
614 * Name:
615 * astError
616
617 * Purpose:
618 * Set the AST error status and report an error message.
619
620 * Type:
621 * Protected function.
622
623 * Synopsis:
624 * #include "error.h"
625 * void astError( int status_value, const char *fmt, int *status, ... )
626
627 * Description:
628 * This function sets the AST error status to a specified value and
629 * reports an associated error message.
630
631 * Parameters:
632 * status_value
633 * The error status value to be set.
634 * fmt
635 * Pointer to a null-terminated character string containing the
636 * format specification for the error message, in the same way
637 * as for a call to the C "printf" family of functions.
638 * status
639 * Pointer to the integer holding the inherited status value.
640 * ...
641 * Additional optional arguments (as used by e.g. "printf")
642 * which specify values which are to appear in the error
643 * message.
644
645 * Notes:
646 * This function operates just like "printf", except that:
647 * - The first argument is an error status.
648 * - The return value is void.
649 * - A newline is automatically appended to the error message
650 * (there is no need to add one).
651 * - This function is documented as protected because it should not
652 * be invoked by external code. However, it is available via the
653 * external C interface so that it may be used when writing (e.g.)
654 * foreign language or graphics interfaces.
655 *-
656
657 * This is the protected implementation of astError. It has a status
658 pointer parameter that is not present in the public form. Different
659 implementations for protected and public interfaces are required
660 because of the variable argument list.
661
662 */
663
664 /* Local Constants: */
665 #define BUFF_LEN 1023 /* Max. length of an error message */
666
667 /* Local Variables: */
668 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
669 char buff[ BUFF_LEN + 1 ]; /* Message buffer */
670 int imess; /* Index into deferred message stack */
671 int nc; /* Number of characters written */
672 va_list args; /* Variable argument list pointer */
673
674 /* Initialise the variable argument list pointer. */
675 va_start( args, status );
676
677 /* If needed, get a pointer to the thread specific global data structure. */
678 astGET_GLOBALS(NULL);
679
680 /* If this is the first report of an error (the global status has not
681 previously been set) and error context information is available,
682 then construct an error context message. */
683 if ( astOK &&
684 ( current_routine || current_file || current_line ) ) {
685 nc = sprintf( buff, "AST: Error" );
686 if ( current_routine ) {
687 nc += sprintf( buff + nc, " in routine %s", current_routine );
688 }
689 if ( current_line ) {
690 nc += sprintf( buff + nc, " at line %d", current_line );
691 }
692 if ( current_file ) {
693 nc += sprintf( buff + nc, " in file %s", current_file );
694 }
695 nc += sprintf( buff + nc, "." );
696
697 /* Deliver the error message unless reporting has been switched off using
698 astReporting. In which case store them in a static array. */
699 if( reporting ) {
700 INVOKE_ASTPUTERR( status_value, buff );
701 } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){
702 imess = mstack_size++;
703 message_stack[ imess ] = MALLOC( strlen( buff ) + 1 );
704 if( message_stack[ imess ] ) {
705 strcpy( message_stack[ imess ], buff );
706 }
707 }
708
709 /* Set the global status. */
710 astSetStatus( status_value );
711 }
712
713 /* Write the error message supplied to the formatting buffer. */
714 nc = vsprintf( buff, fmt, args );
715
716 /* Tidy up the argument pointer. */
717 va_end( args );
718
719 /* Deliver the error message unless reporting has been switched off using
720 astReporting. */
721 if( reporting ) {
722 INVOKE_ASTPUTERR( status_value, buff );
723 } else if( mstack_size < AST__ERROR_MSTACK_SIZE ){
724 imess = mstack_size++;
725 message_stack[ imess ] = MALLOC( strlen( buff ) + 1 );
726 if( message_stack[ imess ] ) {
727 strcpy( message_stack[ imess ], buff );
728 }
729 }
730
731 /* Set the error status value. */
732 astSetStatus( status_value );
733
734 /* Undefine macros local to this function. */
735 #undef BUFF_LEN
736 }
737
astGetStatusPtr_()738 int *astGetStatusPtr_(){
739 /*
740 *+
741 * Name:
742 * astGetStatusPtr
743
744 * Purpose:
745 * Return a pointer to the integer holding the inherited status value.
746
747 * Type:
748 * Protected function.
749
750 * Synopsis:
751 * #include "error.h"
752 * int *astGetStatusPtr;
753
754 * Description:
755 * This macro returns a pointer to the integer holding the inherited
756 * status pointer. This will either be an internal global integer
757 * (possibly stored as thread specific data), or an ineger specified
758 * via the astWatch function.
759
760 * Returned Value:
761 * A pointer to the integer holding the inherited status value.
762
763 *-
764 */
765
766 /* The thread-safe version of AST stores the status pointer in thread
767 specific data, using the key stored in the global variable
768 "starlink_ast_status_key". */
769 #if defined(THREAD_SAFE)
770 astDECLARE_GLOBALS
771 AstStatusBlock *sb;
772
773 astGET_GLOBALS(NULL);
774 sb = (AstStatusBlock *) pthread_getspecific(starlink_ast_status_key);
775 return sb->status_ptr;
776
777 /* The non thread-safe version of AST stores the status pointer in the
778 global variable "starlink_ast_status_ptr". */
779 #else
780 return starlink_ast_status_ptr;
781 #endif
782 }
783
784 /*
785 c++
786 * Name:
787 * astOK
788
789 * Purpose:
790 * Test whether AST functions have been successful.
791
792 * Type:
793 * Public macro.
794
795 * Synopsis:
796 * #include "error.h"
797 * int astOK
798
799 * Description:
800 * This macro returns a boolean value (0 or 1) to indicate if
801 * preceding AST functions have completed successfully
802 * (i.e. without setting the AST error status). If the error status
803 * is set to an error value, a value of zero is returned, otherwise
804 * the result is one.
805
806 * Returned Value:
807 * astOK
808 * One if the AST error status is OK, otherwise zero.
809
810 * Notes:
811 * - If the AST error status is set to an error value (after an
812 * error), most AST functions will not execute and will simply
813 * return without action. To clear the error status and restore
814 * normal behaviour, use astClearStatus.
815 c--
816 */
817
818
astReporting_(int report,int * status)819 int astReporting_( int report, int *status ) {
820 /*
821 c+
822 * Name:
823 * astReporting
824
825 * Purpose:
826 * Controls the reporting of error messages.
827
828 * Type:
829 * Protected function.
830
831 * Synopsis:
832 * #include "error.h"
833 * int astReporting( int report )
834
835 * Description:
836 * Error messages supplied to astError will only be delivered to the
837 * underlying error system if the "Reporting" flag is set to a
838 * non-zero value. Setting this flag to zero suppresses the reporting
839 * of error messages (the value of the AST error status however is
840 * unaffected). Instead, the reports are saved in an internal message
841 * stack. When reporting is switched back on again, any messages on this
842 * stack of deferred messages will be reported (and the stack emptied)
843 * if the AST error status is not astOK. Also the stack is emptied each
844 * time astClearStatus is called (the stacked messages are not displayed
845 * in this case).
846
847 * Parameters:
848 * report
849 * The new value for the Reporting flag.
850
851 * Returned Value:
852 * The original value of the Reporting flag.
853
854 * Notes:
855 * - The Reporting flag is initially set to 1.
856 c-
857 */
858
859 /* Local Variables: */
860 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
861 int oldval; /* Original "reporting" value */
862
863 /* If needed, get a pointer to the thread specific global data structure. */
864 astGET_GLOBALS(NULL);
865
866 /* Save the original reporting value, and then store the new value. */
867 oldval = reporting;
868 reporting = report;
869
870 /* If we are now reporting errors, flush any messages on the error stack.
871 This causes the messages to be displayed and the stack emptied. */
872 if( reporting ) EmptyStack( 1, status );
873
874 /* Return the original reporting value. */
875 return oldval;
876 }
877
878 /*
879 c++
880 * Name:
881 * astSetStatus
882
883 * Purpose:
884 * Set the AST error status to an explicit value.
885
886 * Type:
887 * Public function.
888
889 * Synopsis:
890 * #include "error.h"
891 * void astSetStatus( int status_value )
892
893 * Description:
894 * This function sets the AST error status to the value supplied.
895 * It does not cause any error message to be produced and should
896 * not be used as part of normal error reporting. Its purpose is
897 * simply to communicate to AST that an error has occurred in some
898 * other item of software.
899 *
900 * For example, a source or sink function supplied as an argument
901 * to astChannel or astFitsChan might use this to signal that an
902 * input/output error has occurred. AST could then respond by
903 * terminating the current read or write operation.
904
905 * Parameters:
906 * status_value
907 * The new error status value to be set.
908
909 * Notes:
910 * - If the AST error status is set to an error value, most AST
911 * functions will not execute and will simply return without
912 * action. To clear the error status and restore normal behaviour,
913 * use astClearStatus.
914 c--
915 */
916
917 /*
918 c++
919 * Name:
920 * astStatus
921
922 * Purpose:
923 * Obtain the current AST error status value.
924
925 * Type:
926 * Public function.
927
928 * Synopsis:
929 * #include "error.h"
930 * int astStatus
931
932 * Description:
933 * This function returns the current value of the AST error status.
934
935 * Returned Value:
936 * astStatus
937 * The AST error status value.
938
939 * Notes:
940 * - If the AST error status is set to an error value (after an
941 * error), most AST functions will not execute and will simply
942 * return without action. To clear the error status and restore
943 * normal behaviour, use astClearStatus.
944 c--
945 */
946
astWatch_(int * status_ptr)947 int *astWatch_( int *status_ptr ) {
948 /*
949 c++
950 * Name:
951 * astWatch
952
953 * Purpose:
954 * Identify a new error status variable for the AST library.
955
956 * Type:
957 * Public function.
958
959 * Synopsis:
960 * #include "error.h"
961 * int *astWatch( int *status_ptr )
962
963 * Description:
964 * This function allows a new error status variable to be accessed
965 * by the AST library when checking for and reporting error
966 * conditions.
967 *
968 * By default, the library uses an internal integer error status
969 * which is set to an error value if an error occurs. Use of
970 * astWatch allows the internal error status to be replaced by an
971 * integer variable of your choosing, so that the AST library can
972 * share its error status directly with other code which uses the
973 * same error detection convention.
974 *
975 * If an alternative error status variable is supplied, it is used
976 * by all related AST functions and macros (e.g. astOK, astStatus
977 * and astClearStatus).
978
979 * Parameters:
980 * status_ptr
981 * Pointer to an int whose value is to be used subsequently as
982 * the AST inherited status value. If a NULL pointer is supplied,
983 * the AST library will revert to using its own internal error status.
984
985 * Returned Value:
986 * astWatch()
987 * Address of the previous error status variable. This may later
988 * be passed back to astWatch to restore the previous behaviour
989 * of the library. (Note that on the first invocation of
990 * astWatch the returned value will be the address of the
991 * internal error status variable.)
992
993 * Notes:
994 * - This function is not available in the FORTRAN 77 interface to
995 * the AST library.
996 c--
997 */
998
999 /* Local Variables: */
1000 int *result; /* Value to be returned */
1001 astDECLARE_GLOBALS /* Pointer to thread-specific global data */
1002
1003 #if defined(THREAD_SAFE)
1004 AstStatusBlock *sb = NULL;
1005 #endif
1006
1007 /* Ensure that the thread-specific status block has been created and
1008 ininitialised. */
1009 astGET_GLOBALS(NULL);
1010
1011 #if defined(THREAD_SAFE)
1012 sb = (AstStatusBlock *) pthread_getspecific( starlink_ast_status_key );
1013 result = sb->status_ptr;
1014 sb->status_ptr = status_ptr ? status_ptr : &(sb->internal_status);
1015 #else
1016 result = starlink_ast_status_ptr;
1017 starlink_ast_status_ptr = status_ptr ? status_ptr : &internal_status;
1018 #endif
1019
1020 /* Return the old address. */
1021 return result;
1022 }
1023
1024
1025