irplib_utils.h
00001 /* $Id: irplib_utils.h,v 1.2.2.1 2008/06/10 14:09:33 rpalsa Exp $ 00002 * 00003 * This file is part of the irplib package 00004 * Copyright (C) 2002,2003 European Southern Observatory 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA 00019 */ 00020 00021 /* 00022 * $Author: rpalsa $ 00023 * $Date: 2008/06/10 14:09:33 $ 00024 * $Revision: 1.2.2.1 $ 00025 * $Name: giraffe-2_5_3 $ 00026 */ 00027 00028 #ifndef IRPLIB_UTILS_H 00029 #define IRPLIB_UTILS_H 00030 00031 /*----------------------------------------------------------------------------- 00032 Includes 00033 -----------------------------------------------------------------------------*/ 00034 00035 #include <stdarg.h> 00036 00037 #include <cpl.h> 00038 00039 /*----------------------------------------------------------------------------- 00040 Define 00041 -----------------------------------------------------------------------------*/ 00042 00043 #define IRPLIB_XSTRINGIFY(TOSTRING) #TOSTRING 00044 #define IRPLIB_STRINGIFY(TOSTRING) IRPLIB_XSTRINGIFY(TOSTRING) 00045 00046 /* FIXME: Remove when no longer used by any irplib-based pipelines */ 00047 #define irplib_vsprintf cpl_vsprintf 00048 #define irplib_sprintf cpl_sprintf 00049 00050 /* FIXME: Remove when no longer used by any irplib-based pipelines */ 00051 /* Useful for debugging */ 00052 #define irplib_trace() do if (cpl_error_get_code()) { \ 00053 cpl_msg_debug(cpl_func, __FILE__ " at line %d: ERROR '%s' at %s", \ 00054 __LINE__, cpl_error_get_message(), cpl_error_get_where()); \ 00055 } else { \ 00056 cpl_msg_debug(cpl_func, __FILE__ " at line %d: OK", __LINE__); \ 00057 } while (0) 00058 00059 #define irplib_error_recover(ESTATE, ...) \ 00060 do if (!cpl_errorstate_is_equal(ESTATE)) { \ 00061 cpl_msg_warning(cpl_func, __VA_ARGS__); \ 00062 cpl_msg_indent_more(); \ 00063 cpl_errorstate_dump(ESTATE, CPL_FALSE, irplib_errorstate_warning); \ 00064 cpl_msg_indent_less(); \ 00065 cpl_errorstate_set(ESTATE); \ 00066 } while (0) 00067 00068 00069 /*----------------------------------------------------------------------------*/ 00070 /* 00071 @brief Conditional skip to the (unqiue) return point of the function 00072 @param CONDITION The condition to check 00073 @see cpl_error_ensure() 00074 00075 skip_if() takes one argument, which is a logical expression. 00076 If the logical expression is false skip_if() takes no action and 00077 program execution continues. 00078 If the logical expression is true this indicates an error. In this case 00079 skip_if() will set the location of the error to the point where it 00080 was invoked in the recipe code (unless the error location is already in the 00081 recipe code). If no error code had been set, then skip_if() will set one. 00082 Finally, skip_if() causes program execution to skip to the macro 'end_skip'. 00083 The macro end_skip is located towards the end of the function, after 00084 which all resource deallocation and the function return is located. 00085 00086 The use of skip_if() assumes the following coding practice: 00087 1) Pointers used for dynamically allocated memory that they "own" shall always 00088 point to either NULL or to allocated memory (including CPL-objects). 00089 2) Such pointers may not be reused to point to memory whose deallocation 00090 requires calls to different functions. 00091 3) Pointers of type FILE should be set NULL when not pointing to an open 00092 stream and their closing calls (fclose(), freopen(), etc.) following the 00093 'end_skip' should be guarded against such NULL pointers. 00094 00095 Error checking with skip_if() is encouraged due to the following advantages: 00096 1) It ensures that a CPL-error code is set. 00097 2) It ensures that the location of the error in the _recipe_ code is noted. 00098 3) The error checking may be confined to a single concise line. 00099 4) It is not necessary to replicate memory deallocation for every error 00100 condition. 00101 5) If more extensive error reporting/handling is required it is not precluded 00102 by the use of skip_if(). 00103 6) It allows for a single point of function return. 00104 7) It allows for optional, uniformly formatted debugging/tracing information 00105 at each macro invocation. 00106 00107 The implementation of skip_if() uses a goto/label construction. 00108 According to Kerningham & Ritchie, The C Programming Language, 2nd edition, 00109 Section 3.8: 00110 "This organization is handy if the error-handling code is non-trivial, 00111 and if errors can occur in several places." 00112 00113 The use of goto for any other purpose should be avoided. 00114 00115 */ 00116 /*----------------------------------------------------------------------------*/ 00117 #define skip_if(CONDITION) \ 00118 do { \ 00119 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \ 00120 goto cleanup, "Propagating a pre-existing error"); \ 00121 cpl_error_ensure(!(CONDITION), cpl_error_get_code(), \ 00122 goto cleanup, "Propagating error");\ 00123 } while (0) 00124 00125 /*----------------------------------------------------------------------------*/ 00126 /* 00127 @brief Skip if A < B 00128 @param A The 1st double to compare 00129 @param B The 2nd double to compare 00130 @param MSG The message to use on failure 00131 @see skip_if() 00132 @note A and B are evaluated exactly once 00133 */ 00134 /*----------------------------------------------------------------------------*/ 00135 #define skip_if_lt(A, B, MSG) \ 00136 do { \ 00137 const double tmpa = (double)(A); \ 00138 const double tmpb = (double)(B); \ 00139 \ 00140 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \ 00141 goto cleanup, "Propagating a pre-existing error"); \ 00142 cpl_error_ensure(tmpa >= tmpb, CPL_ERROR_DATA_NOT_FOUND, \ 00143 goto cleanup, "Need at least %g (not %g) %s", \ 00144 tmpb, tmpa, MSG); \ 00145 } while (0) 00146 00147 /*----------------------------------------------------------------------------*/ 00148 /* 00149 @brief Conditional skip on coding bug 00150 @param CONDITION The condition to check 00151 @see skip_if() 00152 @note unlike assert() this check cannot be disabled 00153 */ 00154 /*----------------------------------------------------------------------------*/ 00155 #define bug_if(CONDITION) \ 00156 do { \ 00157 cpl_error_ensure(!cpl_error_get_code(), cpl_error_get_code(), \ 00158 goto cleanup, "Propagating an unexpected error, " \ 00159 "please report to " PACKAGE_BUGREPORT); \ 00160 cpl_error_ensure(!(CONDITION), CPL_ERROR_UNSPECIFIED, \ 00161 goto cleanup, "Internal error, please report to " \ 00162 PACKAGE_BUGREPORT); \ 00163 } while (0) 00164 00165 /*----------------------------------------------------------------------------*/ 00166 /* 00167 @brief Conditional skip with error creation 00168 @param CONDITION The condition to check 00169 @param ERROR The error code to set 00170 @param MSG A printf-style error message. As a matter of 00171 user-friendliness the message should mention any 00172 value that caused the @em CONDITION to fail. 00173 @see skip_if() 00174 @note unlike assert() this check cannot be disabled 00175 */ 00176 /*----------------------------------------------------------------------------*/ 00177 #define error_if(CONDITION, ERROR, ...) \ 00178 do { \ 00179 cpl_error_ensure(cpl_error_get_code() == CPL_ERROR_NONE && \ 00180 !(CONDITION), ERROR, goto cleanup, __VA_ARGS__); \ 00181 } while (0) 00182 00183 /*----------------------------------------------------------------------------*/ 00184 /* 00185 @brief Define the single point of resource deallocation and return 00186 @see skip_if() 00187 @note end_skip should be used exactly once in functions that use skip_if() etc 00188 */ 00189 /*----------------------------------------------------------------------------*/ 00190 #define end_skip \ 00191 do { \ 00192 cleanup: \ 00193 if (cpl_error_get_code()) \ 00194 cpl_msg_debug(cpl_func, "Cleanup in " __FILE__ " line %u with " \ 00195 "error '%s' at %s", __LINE__, \ 00196 cpl_error_get_message(), cpl_error_get_where()); \ 00197 else \ 00198 cpl_msg_debug(cpl_func, "Cleanup in " __FILE__ " line %u", \ 00199 __LINE__); \ 00200 } while (0) 00201 00202 00203 /*----------------------------------------------------------------------------*/ 00215 /*----------------------------------------------------------------------------*/ 00216 #define irplib_ensure(CONDITION, ec, ...) \ 00217 cpl_error_ensure(CONDITION, ec, goto cleanup, __VA_ARGS__) 00218 00219 /*----------------------------------------------------------------------------*/ 00249 /*----------------------------------------------------------------------------*/ 00250 00251 #define irplib_check(COMMAND, ...) \ 00252 do { \ 00253 cpl_errorstate irplib_check_prestate = cpl_errorstate_get(); \ 00254 skip_if(0); \ 00255 COMMAND; \ 00256 irplib_trace(); \ 00257 irplib_ensure(cpl_errorstate_is_equal(irplib_check_prestate), \ 00258 cpl_error_get_code(), __VA_ARGS__); \ 00259 irplib_trace(); \ 00260 } while (0) 00261 00262 /*----------------------------------------------------------------------------- 00263 Function prototypes 00264 -----------------------------------------------------------------------------*/ 00265 00266 void irplib_reset(void); 00267 int irplib_compare_tags(cpl_frame *, cpl_frame *); 00268 const char * irplib_frameset_find_file(const cpl_frameset *, const char *); 00269 cpl_frame * irplib_frameset_get_first_from_group(const cpl_frameset *, 00270 cpl_frame_group); 00271 00272 cpl_error_code irplib_apertures_find_max_flux(const cpl_apertures *, int *, 00273 int); 00274 00275 int irplib_isinf(double value); 00276 int irplib_isnan(double value); 00277 00278 void irplib_errorstate_warning(unsigned, unsigned, unsigned); 00279 00280 #endif
