00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023
00024
00025
00026
00027
00028 #include <complex.h>
00029 #include <string.h>
00030 #include <assert.h>
00031 #include <stdlib.h>
00032 #include <limits.h>
00033 #include <sys/types.h>
00034 #include <regex.h>
00035 #include <ctype.h>
00036 #include "irplib_sdp_spectrum.h"
00037
00038 #ifdef IRPLIB_USE_FITS_UPDATE_CHECKSUM
00039 # include <fitsio2.h>
00040 #endif
00041
00042
00043
00044
00045
00046
00047 #ifndef cpl_error_set_regex
00048
00049 cpl_error_code
00050 cpl_error_set_regex_macro(const char *, cpl_error_code, int,
00051 const regex_t *, const char *,
00052 unsigned, const char *, ...) CPL_ATTR_PRINTF(7,8);
00053
00054 #define cpl_error_set_regex(code, regcode, preg, ...) \
00055 cpl_error_set_regex_macro(cpl_func, code, regcode, preg, \
00056 __FILE__, __LINE__, __VA_ARGS__)
00057
00058 #endif
00059
00060
00061 #define KEY_ARCFILE "ARCFILE"
00062 #define KEY_ORIGFILE "ORIGFILE"
00063 #define KEY_RA "RA"
00064 #define KEY_RA_COMMENT "[deg] Spectroscopic target position (J2000)"
00065 #define KEY_DEC "DEC"
00066 #define KEY_DEC_COMMENT "[deg] Spectroscopic target position (J2000)"
00067 #define KEY_EXPTIME "EXPTIME"
00068 #define KEY_EXPTIME_COMMENT "[s] Total integration time per pixel"
00069 #define KEY_TEXPTIME "TEXPTIME"
00070 #define KEY_TEXPTIME_COMMENT "[s] Total integration time of all exposures"
00071 #define KEY_TIMESYS "TIMESYS"
00072 #define KEY_TIMESYS_COMMENT "Time system used"
00073 #define KEY_MJDOBS "MJD-OBS"
00074 #define KEY_MJDOBS_COMMENT "[d] Start of observations (days)"
00075 #define KEY_MJDEND "MJD-END"
00076 #define KEY_MJDEND_COMMENT "[d] End of observations (days)"
00077 #define KEY_PRODLVL "PRODLVL"
00078 #define KEY_PRODLVL_VALUE 2
00079 #define KEY_PRODLVL_COMMENT "Phase 3 product level: 1-raw, 2-science grade, 3-advanced"
00080 #define KEY_PROCSOFT "PROCSOFT"
00081 #define KEY_PROCSOFT_COMMENT "ESO pipeline version"
00082 #define KEY_PRODCATG "PRODCATG"
00083 #define KEY_PRODCATG_COMMENT "Data product category"
00084 #define KEY_ORIGIN "ORIGIN"
00085 #define KEY_ORIGIN_VALUE "ESO"
00086 #define KEY_ORIGIN_COMMENT "European Southern Observatory"
00087 #define KEY_EXT_OBJ "EXT_OBJ"
00088 #define KEY_EXT_OBJ_COMMENT "TRUE if extended"
00089 #define KEY_DISPELEM "DISPELEM"
00090 #define KEY_DISPELEM_COMMENT "Dispersive element name"
00091 #define KEY_SPECSYS "SPECSYS"
00092 #define KEY_SPECSYS_VALUE "TOPOCENT"
00093 #define KEY_SPECSYS_COMMENT "Reference frame for spectral coordinates"
00094 #define KEY_PROG_ID "PROG_ID"
00095 #define KEY_PROG_ID_COMMENT "ESO programme identification"
00096 #define KEY_OBID "OBID"
00097 #define KEY_OBID_COMMENT "Observation block ID"
00098 #define KEY_M_EPOCH "M_EPOCH"
00099 #define KEY_M_EPOCH_COMMENT "TRUE if resulting from multiple epochs"
00100 #define KEY_OBSTECH "OBSTECH"
00101 #define KEY_OBSTECH_COMMENT "Technique for observation"
00102 #define KEY_FLUXCAL "FLUXCAL"
00103 #define KEY_FLUXCAL_COMMENT "Type of flux calibration (ABSOLUTE or UNCALIBRATED)"
00104 #define KEY_CONTNORM "CONTNORM"
00105 #define KEY_CONTNORM_COMMENT "TRUE if normalised to the continuum"
00106 #define KEY_WAVELMIN "WAVELMIN"
00107 #define KEY_WAVELMIN_COMMENT "[nm] Minimum wavelength"
00108 #define KEY_WAVELMAX "WAVELMAX"
00109 #define KEY_WAVELMAX_COMMENT "[nm] Maximum wavelength"
00110 #define KEY_SPEC_BIN "SPEC_BIN"
00111 #define KEY_SPEC_BIN_COMMENT "[nm] Wavelength bin size"
00112 #define KEY_TOT_FLUX "TOT_FLUX"
00113 #define KEY_TOT_FLUX_COMMENT "TRUE if photometric conditions and all source flux is captured"
00114 #define KEY_FLUXERR "FLUXERR"
00115 #define KEY_FLUXERR_VALUE -2
00116 #define KEY_FLUXERR_COMMENT "Uncertainty in flux scale (%)"
00117 #define KEY_REFERENC "REFERENC"
00118 #define KEY_REFERENC_VALUE " "
00119 #define KEY_REFERENC_COMMENT "Reference publication"
00120 #define KEY_SPEC_RES "SPEC_RES"
00121 #define KEY_SPEC_RES_COMMENT "Reference spectral resolving power"
00122 #define KEY_SPEC_ERR "SPEC_ERR"
00123 #define KEY_SPEC_ERR_COMMENT "[nm] Statistical error in spectral coordinate"
00124 #define KEY_SPEC_SYE "SPEC_SYE"
00125 #define KEY_SPEC_SYE_COMMENT "[nm] Systematic error in spectral coordinate"
00126 #define KEY_LAMNLIN "LAMNLIN"
00127 #define KEY_LAMNLIN_COMMENT "Number of arc lines used for the wavel. solution"
00128 #define KEY_LAMRMS "LAMRMS"
00129 #define KEY_LAMRMS_COMMENT "[nm] RMS of the residuals of the wavel. solution"
00130 #define KEY_GAIN "GAIN"
00131 #define KEY_GAIN_COMMENT "Conversion factor (e-/ADU) electrons per data unit"
00132 #define KEY_DETRON "DETRON"
00133 #define KEY_DETRON_COMMENT "Readout noise per output (e-)"
00134 #define KEY_EFFRON "EFFRON"
00135 #define KEY_EFFRON_COMMENT "Median effective readout noise (e-)"
00136 #define KEY_SNR "SNR"
00137 #define KEY_SNR_COMMENT "Median signal to noise ratio per order"
00138 #define KEY_NCOMBINE "NCOMBINE"
00139 #define KEY_NCOMBINE_COMMENT "No. of combined raw science data files"
00140 #define KEY_PROV "PROV"
00141 #define KEY_PROV_COMMENT "Originating raw science file"
00142 #define KEY_ASSON "ASSON"
00143 #define KEY_ASSON_COMMENT "Associated file name"
00144 #define KEY_ASSOC "ASSOC"
00145 #define KEY_ASSOC_COMMENT "Associated file category"
00146 #define KEY_ASSOM "ASSOM"
00147 #define KEY_ASSOM_COMMENT "Associated file md5sum"
00148 #define KEY_VOCLASS "VOCLASS"
00149 #define KEY_VOCLASS_VALUE "SPECTRUM V2.0"
00150 #define KEY_VOCLASS_COMMENT "VO Data Model"
00151 #define KEY_VOPUB "VOPUB"
00152 #define KEY_VOPUB_VALUE "ESO/SAF"
00153 #define KEY_VOPUB_COMMENT "VO Publishing Authority"
00154 #define KEY_TITLE "TITLE"
00155 #define KEY_TITLE_COMMENT "Dataset title"
00156 #define KEY_OBJECT "OBJECT"
00157 #define KEY_OBJECT_COMMENT "Target designation"
00158 #define KEY_OBJECT_PHDU_COMMENT "Original target."
00159 #define KEY_APERTURE "APERTURE"
00160 #define KEY_APERTURE_COMMENT "[deg] Aperture diameter"
00161 #define KEY_TELAPSE "TELAPSE"
00162 #define KEY_TELAPSE_COMMENT "[s] Total elapsed time"
00163 #define KEY_TMID "TMID"
00164 #define KEY_TMID_COMMENT "[d] MJD mid exposure"
00165 #define KEY_SPEC_VAL "SPEC_VAL"
00166 #define KEY_SPEC_VAL_COMMENT "[nm] Mean wavelength"
00167 #define KEY_SPEC_BW "SPEC_BW"
00168 #define KEY_SPEC_BW_COMMENT "[nm] Bandpass width = Wmax - Wmin"
00169 #define KEY_TDMIN(n) "TDMIN"#n
00170 #define KEY_TDMIN1_COMMENT "Start in spectral coordinate"
00171 #define KEY_TDMAX(n) "TDMAX"#n
00172 #define KEY_TDMAX1_COMMENT "Stop in spectral coordinate"
00173 #define KEY_TUTYP "TUTYP"
00174 #define KEY_TUTYP_COMMENT "IVOA data model element for field "
00175 #define KEY_TUCD "TUCD"
00176 #define KEY_TUCD_COMMENT "UCD for field "
00177 #define KEY_TCOMM "TCOMM"
00178 #define KEY_TCOMM_COMMENT "Description for field "
00179 #define KEY_NELEM "NELEM"
00180 #define KEY_NELEM_COMMENT "Length of the data arrays"
00181 #define KEY_EXTNAME "EXTNAME"
00182 #define KEY_EXTNAME_VALUE "SPECTRUM"
00183 #define KEY_EXTNAME_COMMENT "Extension name"
00184 #define KEY_INHERIT "INHERIT"
00185 #define KEY_INHERIT_VALUE CPL_TRUE
00186 #define KEY_INHERIT_COMMENT "Primary header keywords are inherited"
00187
00188
00189 #define ALL_KEYS_REGEXP \
00190 "^(" KEY_RA "|" \
00191 KEY_DEC "|" \
00192 KEY_EXPTIME "|" \
00193 KEY_TEXPTIME "|" \
00194 KEY_TIMESYS "|" \
00195 KEY_MJDOBS "|" \
00196 KEY_MJDEND "|" \
00197 KEY_PRODLVL "|" \
00198 KEY_PROCSOFT "|" \
00199 KEY_PRODCATG "|" \
00200 KEY_ORIGIN "|" \
00201 KEY_EXT_OBJ "|" \
00202 KEY_DISPELEM "|" \
00203 KEY_SPECSYS "|" \
00204 KEY_PROG_ID "|" \
00205 KEY_OBID "[0-9]+|" \
00206 KEY_M_EPOCH "|" \
00207 KEY_OBSTECH "|" \
00208 KEY_FLUXCAL "|" \
00209 KEY_CONTNORM "|" \
00210 KEY_WAVELMIN "|" \
00211 KEY_WAVELMAX "|" \
00212 KEY_SPEC_BIN "|" \
00213 KEY_TOT_FLUX "|" \
00214 KEY_FLUXERR "|" \
00215 KEY_REFERENC "|" \
00216 KEY_SPEC_RES "|" \
00217 KEY_SPEC_ERR "|" \
00218 KEY_SPEC_SYE "|" \
00219 KEY_LAMNLIN "|" \
00220 KEY_LAMRMS "|" \
00221 KEY_GAIN "|" \
00222 KEY_DETRON "|" \
00223 KEY_EFFRON "|" \
00224 KEY_SNR "|" \
00225 KEY_NCOMBINE "|" \
00226 KEY_PROV "[0-9]+|" \
00227 KEY_ASSON "[0-9]+|" \
00228 KEY_ASSOC "[0-9]+|" \
00229 KEY_ASSOM "[0-9]+|" \
00230 KEY_VOCLASS "|" \
00231 KEY_VOPUB "|" \
00232 KEY_TITLE "|" \
00233 KEY_OBJECT "|" \
00234 KEY_APERTURE "|" \
00235 KEY_TELAPSE "|" \
00236 KEY_TMID "|" \
00237 KEY_SPEC_VAL "|" \
00238 KEY_SPEC_BW "|" \
00239 KEY_TDMIN(1) "|" \
00240 KEY_TDMAX(1) "|" \
00241 KEY_TUTYP "[0-9]+|" \
00242 KEY_TUCD "[0-9]+|" \
00243 KEY_TCOMM "[0-9]+|" \
00244 KEY_NELEM "|" \
00245 KEY_EXTNAME "|" \
00246 KEY_INHERIT ")$"
00247
00248
00249
00250 #define PRIMARY_HDU_KEYS_REGEXP \
00251 "^(" KEY_RA "|" \
00252 KEY_DEC "|" \
00253 KEY_EXPTIME "|" \
00254 KEY_TEXPTIME "|" \
00255 KEY_TIMESYS "|" \
00256 KEY_MJDOBS "|" \
00257 KEY_MJDEND "|" \
00258 KEY_PRODLVL "|" \
00259 KEY_PROCSOFT "|" \
00260 KEY_PRODCATG "|" \
00261 KEY_ORIGIN "|" \
00262 KEY_EXT_OBJ "|" \
00263 KEY_DISPELEM "|" \
00264 KEY_SPECSYS "|" \
00265 KEY_PROG_ID "|" \
00266 KEY_OBID "[0-9]+|" \
00267 KEY_M_EPOCH "|" \
00268 KEY_OBSTECH "|" \
00269 KEY_FLUXCAL "|" \
00270 KEY_CONTNORM "|" \
00271 KEY_WAVELMIN "|" \
00272 KEY_WAVELMAX "|" \
00273 KEY_SPEC_BIN "|" \
00274 KEY_TOT_FLUX "|" \
00275 KEY_FLUXERR "|" \
00276 KEY_REFERENC "|" \
00277 KEY_SPEC_RES "|" \
00278 KEY_SPEC_ERR "|" \
00279 KEY_SPEC_SYE "|" \
00280 KEY_LAMNLIN "|" \
00281 KEY_LAMRMS "|" \
00282 KEY_GAIN "|" \
00283 KEY_DETRON "|" \
00284 KEY_EFFRON "|" \
00285 KEY_SNR "|" \
00286 KEY_NCOMBINE "|" \
00287 KEY_PROV "[0-9]+|" \
00288 KEY_ASSON "[0-9]+|" \
00289 KEY_ASSOC "[0-9]+|" \
00290 KEY_ASSOM "[0-9]+|" \
00291 KEY_OBJECT ")$"
00292
00293
00294
00295 #define EXTENSION_HDU_KEYS_REGEXP \
00296 "^(" KEY_RA "|" \
00297 KEY_DEC "|" \
00298 KEY_VOCLASS "|" \
00299 KEY_VOPUB "|" \
00300 KEY_TITLE "|" \
00301 KEY_OBJECT "|" \
00302 KEY_APERTURE "|" \
00303 KEY_TELAPSE "|" \
00304 KEY_TMID "|" \
00305 KEY_SPEC_VAL "|" \
00306 KEY_SPEC_BW "|" \
00307 KEY_TDMIN(1) "|" \
00308 KEY_TDMAX(1) "|" \
00309 KEY_TUTYP "[0-9]+|" \
00310 KEY_TUCD "[0-9]+|" \
00311 KEY_TCOMM "[0-9]+|" \
00312 KEY_NELEM "|" \
00313 KEY_EXTNAME "|" \
00314 KEY_INHERIT ")$"
00315
00316
00317 #define GET_SET_METHODS(param, keyname, type, rettype, defaultval, comment) \
00318 rettype irplib_sdp_spectrum_get_##param(const irplib_sdp_spectrum *self) \
00319 { \
00320 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, defaultval); \
00321 assert(self->proplist != NULL); \
00322 if (cpl_propertylist_has(self->proplist, keyname)) { \
00323 return cpl_propertylist_get_##type(self->proplist, keyname); \
00324 } else { \
00325 return defaultval; \
00326 } \
00327 } \
00328 cpl_error_code irplib_sdp_spectrum_reset_##param(irplib_sdp_spectrum *self) \
00329 { \
00330 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00331 assert(self->proplist != NULL); \
00332 (void) cpl_propertylist_erase(self->proplist, keyname); \
00333 return CPL_ERROR_NONE; \
00334 } \
00335 cpl_error_code irplib_sdp_spectrum_set_##param(irplib_sdp_spectrum *self, \
00336 rettype value) \
00337 { \
00338 cpl_error_code error; \
00339 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00340 assert(self->proplist != NULL); \
00341 if (cpl_propertylist_has(self->proplist, keyname)) { \
00342 error = cpl_propertylist_set_##type(self->proplist, keyname, value); \
00343 } else { \
00344 error = cpl_propertylist_append_##type(self->proplist, keyname, value); \
00345 if (! error) { \
00346 error = cpl_propertylist_set_comment(self->proplist, keyname, comment);\
00347 if (error) { \
00348 \
00349 \
00350 cpl_errorstate prestate = cpl_errorstate_get(); \
00351 (void) cpl_propertylist_erase(self->proplist, keyname); \
00352 cpl_errorstate_set(prestate); \
00353 } \
00354 } \
00355 } \
00356 return error; \
00357 } \
00358 cpl_error_code irplib_sdp_spectrum_copy_##param(irplib_sdp_spectrum *self, \
00359 const cpl_propertylist *plist, const char *name) \
00360 { \
00361 \
00362 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00363 assert(self->proplist != NULL); \
00364 if (cpl_propertylist_has(plist, name)) { \
00365 cpl_errorstate prestate = cpl_errorstate_get(); \
00366 rettype value = cpl_propertylist_get_##type(plist, name); \
00367 if (cpl_errorstate_is_equal(prestate)) { \
00368 return irplib_sdp_spectrum_set_##param(self, value); \
00369 } else { \
00370 return cpl_error_set_message(cpl_func, cpl_error_get_code(), \
00371 "Could not set '%s'. Likely the source '%s' keyword has a" \
00372 " different format or type.", keyname, name); \
00373 } \
00374 } else { \
00375 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, \
00376 "Could not set '%s' since the '%s' keyword was not found.", \
00377 keyname, name); \
00378 } \
00379 }
00380
00381 #define GET_SET_ARRAY_METHODS(param, keyname, type, rettype, defaultval, \
00382 comment) \
00383 rettype irplib_sdp_spectrum_get_##param(const irplib_sdp_spectrum *self, \
00384 cpl_size index) \
00385 { \
00386 char *name; \
00387 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, defaultval); \
00388 assert(self->proplist != NULL); \
00389 name = cpl_sprintf("%s%"CPL_SIZE_FORMAT, keyname, index); \
00390 rettype result = defaultval; \
00391 if (cpl_propertylist_has(self->proplist, name)) { \
00392 result = cpl_propertylist_get_##type(self->proplist, name); \
00393 } \
00394 cpl_free(name); \
00395 return result; \
00396 } \
00397 cpl_error_code irplib_sdp_spectrum_reset_##param(irplib_sdp_spectrum *self, \
00398 cpl_size index) \
00399 { \
00400 char *name; \
00401 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00402 assert(self->proplist != NULL); \
00403 name = cpl_sprintf("%s%"CPL_SIZE_FORMAT, keyname, index); \
00404 (void) cpl_propertylist_erase(self->proplist, name); \
00405 cpl_free(name); \
00406 return CPL_ERROR_NONE; \
00407 } \
00408 cpl_error_code irplib_sdp_spectrum_set_##param(irplib_sdp_spectrum *self, \
00409 cpl_size index, rettype value)\
00410 { \
00411 cpl_error_code error; \
00412 char *name; \
00413 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00414 assert(self->proplist != NULL); \
00415 name = cpl_sprintf("%s%"CPL_SIZE_FORMAT, keyname, index); \
00416 if (cpl_propertylist_has(self->proplist, name)) { \
00417 error = cpl_propertylist_set_##type(self->proplist, name, value); \
00418 } else { \
00419 error = cpl_propertylist_append_##type(self->proplist, name, value); \
00420 if (! error) { \
00421 error = cpl_propertylist_set_comment(self->proplist, name, comment);\
00422 if (error) { \
00423 \
00424 \
00425 cpl_errorstate prestate = cpl_errorstate_get(); \
00426 (void) cpl_propertylist_erase(self->proplist, name); \
00427 cpl_errorstate_set(prestate); \
00428 } \
00429 } \
00430 } \
00431 cpl_free(name); \
00432 return error; \
00433 } \
00434 cpl_error_code irplib_sdp_spectrum_copy_##param(\
00435 irplib_sdp_spectrum *self, cpl_size index, \
00436 const cpl_propertylist *plist, const char *name) \
00437 { \
00438 \
00439 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT); \
00440 assert(self->proplist != NULL); \
00441 if (cpl_propertylist_has(plist, name)) { \
00442 cpl_errorstate prestate = cpl_errorstate_get(); \
00443 rettype value = cpl_propertylist_get_##type(plist, name); \
00444 if (cpl_errorstate_is_equal(prestate)) { \
00445 return irplib_sdp_spectrum_set_##param(self, index, value); \
00446 } else { \
00447 return cpl_error_set_message(cpl_func, cpl_error_get_code(), \
00448 "Could not set '%s%"CPL_SIZE_FORMAT"'. Likely the source" \
00449 " '%s' keyword has a different format or type.", \
00450 keyname, index, name); \
00451 } \
00452 } else { \
00453 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND, \
00454 "Could not set '%s%"CPL_SIZE_FORMAT"' since the '%s'" \
00455 " keyword was not found.", keyname, index, name); \
00456 } \
00457 }
00458
00459
00460 #define GET_SET_METHODS_TYPE_BOOL(param, keyname, comment) \
00461 GET_SET_METHODS(param, keyname, bool, cpl_boolean, CPL_FALSE, comment)
00462
00463 #define GET_SET_METHODS_TYPE_DOUBLE(param, keyname, comment) \
00464 GET_SET_METHODS(param, keyname, double, double, NAN, comment)
00465
00466 #define GET_SET_METHODS_TYPE_INT(param, keyname, comment) \
00467 GET_SET_METHODS(param, keyname, int, int, -1, comment)
00468
00469 #define GET_SET_METHODS_TYPE_STRING(param, keyname, comment) \
00470 GET_SET_METHODS(param, keyname, string, const char *, NULL, comment)
00471
00472 #define GET_SET_ARRAY_METHODS_TYPE_INT(param, keyname, comment) \
00473 GET_SET_ARRAY_METHODS(param, keyname, int, int, -1, comment)
00474
00475 #define GET_SET_ARRAY_METHODS_TYPE_STRING(param, keyname, comment) \
00476 GET_SET_ARRAY_METHODS(param, keyname, string, const char *, NULL, comment)
00477
00478
00479 #define IRPLIB_TYPE_NELEM CPL_TYPE_LONG_LONG | CPL_TYPE_UNSPECIFIED
00480
00481
00488
00489
00492
00493
00494
00495
00500 struct _irplib_sdp_spectrum_ {
00501
00502 cpl_size nelem;
00503
00504
00505 cpl_propertylist *proplist;
00506
00507
00508 cpl_table *table;
00509 };
00510
00511
00516 typedef struct _irplib_keyword_record_ {
00517
00518 const char *name;
00519
00520
00521 const char *comment;
00522
00523
00524 cpl_type type;
00525
00526
00527 cpl_boolean is_array_key;
00528
00529 } irplib_keyword_record;
00530
00531
00532
00533
00534
00535 static cpl_boolean
00536 _irplib_property_equal(const cpl_property *a, const cpl_property *b);
00537
00538 static cpl_boolean
00539 _irplib_array_equal(const cpl_array *a, const cpl_array *b, cpl_size n);
00540
00541 static cpl_boolean
00542 _irplib_table_column_equal(const cpl_table *a, const cpl_table *b,
00543 const char *name, cpl_boolean only_intersect);
00544
00545 static cpl_error_code
00546 _irplib_sdp_spectrum_copy_column(irplib_sdp_spectrum *self, const char *to_name,
00547 const cpl_table* table, const char *from_name);
00548
00549 static cpl_size
00550 _irplib_sdp_spectrum_count_keywords(const irplib_sdp_spectrum *self,
00551 const char *regexp);
00552
00553 static cpl_size
00554 _irplib_sdp_spectrum_get_column_index(const irplib_sdp_spectrum *self,
00555 const char *name);
00556
00557 static const char *
00558 _irplib_sdp_spectrum_get_column_keyword(const irplib_sdp_spectrum *self,
00559 const char *name, const char *keyword);
00560
00561 static cpl_error_code
00562 _irplib_sdp_spectrum_set_column_keyword(irplib_sdp_spectrum *self,
00563 const char *name,
00564 const char *value,
00565 const char *keyword,
00566 const char *comment);
00567
00568 static void
00569 _irplib_sdp_spectrum_erase_column_keywords(irplib_sdp_spectrum *self,
00570 const char *name);
00571
00572 static char * _irplib_make_regexp(const cpl_propertylist *plist,
00573 const char *extra);
00574
00575 #ifndef NDEBUG
00576 static cpl_boolean _irplib_keyword_table_is_sorted(
00577 const irplib_keyword_record *table, size_t entries);
00578 #endif
00579
00580 static const irplib_keyword_record *
00581 _irplib_sdp_spectrum_get_keyword_record(const char *name);
00582
00583
00584
00585
00586
00587
00591
00592 irplib_sdp_spectrum * irplib_sdp_spectrum_new(void)
00593 {
00594 irplib_sdp_spectrum * obj = cpl_malloc(sizeof(irplib_sdp_spectrum));
00595 obj->nelem = 0;
00596 obj->proplist = cpl_propertylist_new();
00597 obj->table = cpl_table_new(1);
00598 return obj;
00599 }
00600
00601
00605
00606 irplib_sdp_spectrum *
00607 irplib_sdp_spectrum_duplicate(const irplib_sdp_spectrum *other)
00608 {
00609 irplib_sdp_spectrum * obj;
00610
00611 cpl_ensure(other != NULL, CPL_ERROR_NULL_INPUT, NULL);
00612
00613 assert(other->proplist != NULL);
00614 assert(other->table != NULL);
00615
00616 obj = cpl_malloc(sizeof(irplib_sdp_spectrum));
00617 obj->nelem = other->nelem;
00618 obj->proplist = cpl_propertylist_duplicate(other->proplist);
00619 obj->table = cpl_table_duplicate(other->table);
00620 return obj;
00621 }
00622
00623
00627
00628 void irplib_sdp_spectrum_delete(irplib_sdp_spectrum *self)
00629 {
00630 if (self != NULL) {
00631 assert(self->proplist != NULL);
00632 assert(self->table != NULL);
00633 cpl_propertylist_delete(self->proplist);
00634 cpl_table_delete(self->table);
00635 cpl_free(self);
00636 }
00637 }
00638
00639
00644
00645 static cpl_boolean
00646 _irplib_property_equal(const cpl_property *a, const cpl_property *b)
00647 {
00648 int value_not_equal;
00649 cpl_type type;
00650 const char *sa, *sb;
00651
00652 assert(a != NULL);
00653 assert(b != NULL);
00654
00655
00656 type = cpl_property_get_type(a);
00657 if (cpl_property_get_type(b) != type) return CPL_FALSE;
00658
00659
00660 switch (type) {
00661 case CPL_TYPE_CHAR:
00662 value_not_equal = cpl_property_get_char(a) != cpl_property_get_char(b);
00663 break;
00664 case CPL_TYPE_BOOL:
00665 value_not_equal = cpl_property_get_bool(a) != cpl_property_get_bool(b);
00666 break;
00667 case CPL_TYPE_INT:
00668 value_not_equal = cpl_property_get_int(a) != cpl_property_get_int(b);
00669 break;
00670 case CPL_TYPE_LONG:
00671 value_not_equal = cpl_property_get_long(a) != cpl_property_get_long(b);
00672 break;
00673 case CPL_TYPE_LONG_LONG:
00674 value_not_equal =
00675 cpl_property_get_long_long(a) != cpl_property_get_long_long(b);
00676 break;
00677 case CPL_TYPE_FLOAT:
00678 value_not_equal = cpl_property_get_float(a) != cpl_property_get_float(b);
00679 break;
00680 case CPL_TYPE_DOUBLE:
00681 value_not_equal = cpl_property_get_double(a) != cpl_property_get_double(b);
00682 break;
00683 case CPL_TYPE_STRING:
00684 sa = cpl_property_get_string(a);
00685 sb = cpl_property_get_string(b);
00686 if (sa == NULL && sb == NULL) {
00687 value_not_equal = 0;
00688 } else if (sa != NULL && sb != NULL) {
00689 value_not_equal = strcmp(sa, sb) != 0;
00690 } else {
00691 return CPL_FALSE;
00692 }
00693 break;
00694 #ifdef _Complex_I
00695 case CPL_TYPE_FLOAT_COMPLEX:
00696 value_not_equal =
00697 cpl_property_get_float_complex(a) != cpl_property_get_float_complex(b);
00698 break;
00699 case CPL_TYPE_DOUBLE_COMPLEX:
00700 value_not_equal =
00701 cpl_property_get_double_complex(a) != cpl_property_get_double_complex(b);
00702 break;
00703 #endif
00704 default:
00705 cpl_error_set_message(cpl_func, CPL_ERROR_INVALID_TYPE,
00706 "Unsupported data type found in property '%s'.",
00707 cpl_property_get_name(a));
00708 return CPL_FALSE;
00709 }
00710 if (value_not_equal) return CPL_FALSE;
00711
00712
00713 return CPL_TRUE;
00714 }
00715
00716
00717
00728
00729 static cpl_boolean
00730 _irplib_array_equal(const cpl_array *a, const cpl_array *b, cpl_size n)
00731 {
00732 cpl_type type;
00733
00734 assert(a != NULL);
00735 assert(b != NULL);
00736 assert(n <= cpl_array_get_size(a));
00737 assert(n <= cpl_array_get_size(b));
00738
00739 type = cpl_array_get_type(a);
00740 if (type != cpl_array_get_type(b)) return CPL_FALSE;
00741
00742 if (type == CPL_TYPE_STRING) {
00743
00744 cpl_size i;
00745 const char **stra = cpl_array_get_data_string_const(a);
00746 const char **strb = cpl_array_get_data_string_const(b);
00747 cpl_error_ensure(stra != NULL && strb != NULL, cpl_error_get_code(),
00748 return CPL_FALSE, "Failed to get %s data for array.",
00749 cpl_type_get_name(type));
00750 for (i = 0; i < n; ++i) {
00751 if (stra[i] == NULL && strb[i] == NULL) continue;
00752 if (stra[i] == NULL || strb[i] == NULL) return CPL_FALSE;
00753 if (strcmp(stra[i], strb[i]) != 0) return CPL_FALSE;
00754 }
00755
00756 } else {
00757
00758 cpl_size size, i;
00759 const void *va, *vb;
00760
00761 switch (type) {
00762 case CPL_TYPE_INT:
00763 size = sizeof(int);
00764 va = cpl_array_get_data_int_const(a);
00765 vb = cpl_array_get_data_int_const(b);
00766 break;
00767 case CPL_TYPE_LONG_LONG:
00768 size = sizeof(long long);
00769 va = cpl_array_get_data_long_long_const(a);
00770 vb = cpl_array_get_data_long_long_const(b);
00771 break;
00772 case CPL_TYPE_FLOAT:
00773 size = sizeof(float);
00774 va = cpl_array_get_data_float_const(a);
00775 vb = cpl_array_get_data_float_const(b);
00776 break;
00777 case CPL_TYPE_DOUBLE:
00778 size = sizeof(double);
00779 va = cpl_array_get_data_double_const(a);
00780 vb = cpl_array_get_data_double_const(b);
00781 break;
00782 #ifdef _Complex_I
00783 case CPL_TYPE_FLOAT_COMPLEX:
00784 size = sizeof(_Complex float);
00785 va = cpl_array_get_data_float_complex_const(a);
00786 vb = cpl_array_get_data_float_complex_const(b);
00787 break;
00788 case CPL_TYPE_DOUBLE_COMPLEX:
00789 size = sizeof(_Complex double);
00790 va = cpl_array_get_data_double_complex_const(a);
00791 vb = cpl_array_get_data_double_complex_const(b);
00792 break;
00793 #endif
00794 default:
00795 cpl_error_set_message(cpl_func, CPL_ERROR_INVALID_TYPE,
00796 "Unsupported data type.");
00797 return CPL_FALSE;
00798 }
00799 cpl_error_ensure(va != NULL && vb != NULL, cpl_error_get_code(),
00800 return CPL_FALSE, "Failed to get %s data for array.",
00801 cpl_type_get_name(type));
00802 for (i = 0; i < n; ++i) {
00803 int valid_a = cpl_array_is_valid(a, i);
00804 int valid_b = cpl_array_is_valid(b, i);
00805 if (! valid_a && ! valid_b) continue;
00806 if (! valid_a || ! valid_b) return CPL_FALSE;
00807 const void *vai = (const char *)va + (size * i);
00808 const void *vbi = (const char *)vb + (size * i);
00809 if (memcmp(vai, vbi, size) != 0) return CPL_FALSE;
00810 }
00811 }
00812
00813
00814 return TRUE;
00815 }
00816
00817
00830
00831 static cpl_boolean
00832 _irplib_table_column_equal(const cpl_table *a, const cpl_table *b,
00833 const char *name, cpl_boolean only_intersect)
00834 {
00835 cpl_type type;
00836 cpl_size nrows, na, nb, i;
00837 const char *sa, *sb;
00838
00839 assert(a != NULL);
00840 assert(b != NULL);
00841
00842 nrows = cpl_table_get_nrow(a);
00843 if (only_intersect) {
00844 cpl_size nrows2 = cpl_table_get_nrow(b);
00845 if (nrows2 < nrows) nrows = nrows2;
00846 } else {
00847 if (cpl_table_get_nrow(b) != nrows) return CPL_FALSE;
00848 }
00849
00850
00851 type = cpl_table_get_column_type(a, name);
00852 if (cpl_table_get_column_type(b, name) != type) return CPL_FALSE;
00853
00854
00855 na = cpl_table_get_column_dimensions(a, name);
00856 nb = cpl_table_get_column_dimensions(b, name);
00857 if (na != nb) return CPL_FALSE;
00858
00859
00860 sa = cpl_table_get_column_unit(a, name);
00861 sb = cpl_table_get_column_unit(b, name);
00862 cpl_error_ensure(sa != NULL && sb != NULL, cpl_error_get_code(),
00863 return CPL_FALSE,
00864 "Failed to get unit strings for column '%s'.", name);
00865 if (strcmp(sa, sb) != 0) return CPL_FALSE;
00866
00867
00868
00869 if (type & CPL_TYPE_POINTER) {
00870 cpl_errorstate prestate;
00871
00872 const cpl_array **va = cpl_table_get_data_array_const(a, name);
00873 const cpl_array **vb = cpl_table_get_data_array_const(b, name);
00874 cpl_error_ensure(va != NULL && vb != NULL,
00875 cpl_error_get_code(), return CPL_FALSE,
00876 "Failed to get %s data for column '%s'.",
00877 cpl_type_get_name(type), name);
00878 if (only_intersect) {
00879 for (i = 0; i < nrows; ++i) {
00880
00881
00882 if (va[i] == NULL && vb[i] == NULL) continue;
00883 if (va[i] == NULL || vb[i] == NULL) return CPL_FALSE;
00884 prestate = cpl_errorstate_get();
00885 cpl_size n1 = cpl_array_get_size(va[i]);
00886 cpl_size n2 = cpl_array_get_size(vb[i]);
00887 cpl_size n = n1 < n2 ? n1 : n2;
00888 if (! _irplib_array_equal(va[i], vb[i], n)) return CPL_FALSE;
00889 cpl_error_ensure(cpl_errorstate_is_equal(prestate),
00890 cpl_error_get_code(), return CPL_FALSE,
00891 "Failed when trying to match %s data for column '%s'.",
00892 cpl_type_get_name(type), name);
00893 }
00894 } else {
00895 for (i = 0; i < nrows; ++i) {
00896
00897
00898 if (va[i] == NULL && vb[i] == NULL) continue;
00899 if (va[i] == NULL || vb[i] == NULL) return CPL_FALSE;
00900 prestate = cpl_errorstate_get();
00901 cpl_size n = cpl_array_get_size(va[i]);
00902 if (n != cpl_array_get_size(vb[i])) return CPL_FALSE;
00903 if (! _irplib_array_equal(va[i], vb[i], n)) return CPL_FALSE;
00904 cpl_error_ensure(cpl_errorstate_is_equal(prestate),
00905 cpl_error_get_code(), return CPL_FALSE,
00906 "Failed when trying to match %s data for column '%s'.",
00907 cpl_type_get_name(type), name);
00908 }
00909 }
00910
00911 } else if (type == CPL_TYPE_STRING) {
00912
00913 const char **va = cpl_table_get_data_string_const(a, name);
00914 const char **vb = cpl_table_get_data_string_const(b, name);
00915 cpl_error_ensure(va != NULL && vb != NULL,
00916 cpl_error_get_code(), return CPL_FALSE,
00917 "Failed to get %s data for column '%s'.",
00918 cpl_type_get_name(type), name);
00919 if (only_intersect) {
00920 for (i = 0; i < nrows; ++i) {
00921 if (va[i] == NULL && vb[i] == NULL) continue;
00922 if (va[i] == NULL || vb[i] == NULL) return CPL_FALSE;
00923 size_t n1 = strlen(va[i]);
00924 size_t n2 = strlen(vb[i]);
00925 size_t n = n1 < n2 ? n1 : n2;
00926 if (strncmp(va[i], vb[i], (cpl_size)n) != 0) return CPL_FALSE;
00927 }
00928 } else {
00929 for (i = 0; i < nrows; ++i) {
00930 if (va[i] == NULL && vb[i] == NULL) continue;
00931 if (va[i] == NULL || vb[i] == NULL) return CPL_FALSE;
00932 if (strcmp(va[i], vb[i]) != 0) return CPL_FALSE;
00933 }
00934 }
00935
00936 } else {
00937
00938 cpl_size size;
00939 const void *va, *vb;
00940
00941 switch (type) {
00942 case CPL_TYPE_INT:
00943 size = sizeof(int);
00944 va = cpl_table_get_data_int_const(a, name);
00945 vb = cpl_table_get_data_int_const(b, name);
00946 break;
00947 case CPL_TYPE_LONG_LONG:
00948 size = sizeof(long long);
00949 va = cpl_table_get_data_long_long_const(a, name);
00950 vb = cpl_table_get_data_long_long_const(b, name);
00951 break;
00952 case CPL_TYPE_FLOAT:
00953 size = sizeof(float);
00954 va = cpl_table_get_data_float_const(a, name);
00955 vb = cpl_table_get_data_float_const(b, name);
00956 break;
00957 case CPL_TYPE_DOUBLE:
00958 size = sizeof(double);
00959 va = cpl_table_get_data_double_const(a, name);
00960 vb = cpl_table_get_data_double_const(b, name);
00961 break;
00962 #ifdef _Complex_I
00963 case CPL_TYPE_FLOAT_COMPLEX:
00964 size = sizeof(_Complex float);
00965 va = cpl_table_get_data_float_complex_const(a, name);
00966 vb = cpl_table_get_data_float_complex_const(b, name);
00967 break;
00968 case CPL_TYPE_DOUBLE_COMPLEX:
00969 size = sizeof(_Complex double);
00970 va = cpl_table_get_data_double_complex_const(a, name);
00971 vb = cpl_table_get_data_double_complex_const(b, name);
00972 break;
00973 #endif
00974 default:
00975 cpl_error_set_message(cpl_func, CPL_ERROR_INVALID_TYPE,
00976 "Unsupported data type found in column '%s'.", name);
00977 return CPL_FALSE;
00978 }
00979 cpl_error_ensure(va != NULL && vb != NULL,
00980 cpl_error_get_code(), return CPL_FALSE,
00981 "Failed to get %s data for column '%s'.",
00982 cpl_type_get_name(type), name);
00983 for (i = 0; i < nrows; ++i) {
00984 int valid_a = cpl_table_is_valid(a, name, i);
00985 int valid_b = cpl_table_is_valid(b, name, i);
00986 if (! valid_a && ! valid_b) continue;
00987 if (! valid_a || ! valid_b) return CPL_FALSE;
00988 const void *vai = (const char *)va + (size * i);
00989 const void *vbi = (const char *)vb + (size * i);
00990 if (memcmp(vai, vbi, size) != 0) return CPL_FALSE;
00991 }
00992 }
00993
00994
00995 return CPL_TRUE;
00996 }
00997
00998
01014
01015 cpl_boolean irplib_sdp_spectrum_equal(const irplib_sdp_spectrum *a,
01016 const irplib_sdp_spectrum *b,
01017 cpl_boolean only_intersect)
01018 {
01019 cpl_errorstate prestate;
01020 cpl_size na, i;
01021 cpl_boolean no_match = CPL_FALSE;
01022 cpl_array *names;
01023 const char *name;
01024 const cpl_property *pa, *pb;
01025
01026 cpl_ensure(a != NULL && b != NULL, CPL_ERROR_NULL_INPUT, CPL_FALSE);
01027
01028 assert(a->proplist != NULL);
01029 assert(a->table != NULL);
01030 assert(b->proplist != NULL);
01031 assert(b->table != NULL);
01032
01033 na = cpl_propertylist_get_size(a->proplist);
01034
01035 if (only_intersect) {
01036
01037
01038 for (i = 0; i < na; ++i) {
01039 pa = cpl_propertylist_get_const(a->proplist, i);
01040 cpl_error_ensure(pa != NULL, cpl_error_get_code(), return CPL_FALSE,
01041 "Failed to get property structure %"CPL_SIZE_FORMAT".", i);
01042 name = cpl_property_get_name(pa);
01043 cpl_error_ensure(name != NULL, cpl_error_get_code(), return CPL_FALSE,
01044 "Failed to get the name for property %"CPL_SIZE_FORMAT".", i);
01045 pb = cpl_propertylist_get_property_const(b->proplist, name);
01046 if (pb != NULL) {
01047 prestate = cpl_errorstate_get();
01048 if (! _irplib_property_equal(pa, pb)) return CPL_FALSE;
01049 if (! cpl_errorstate_is_equal(prestate)) return CPL_FALSE;
01050 }
01051 }
01052
01053
01054
01055 prestate = cpl_errorstate_get();
01056 na = cpl_table_get_ncol(a->table);
01057 names = cpl_table_get_column_names(a->table);
01058 for (i = 0; i < na; ++i) {
01059 name = cpl_array_get_string(names, i);
01060 cpl_error_ensure(name != NULL, cpl_error_get_code(), break,
01061 "Failed to get the name for column %"CPL_SIZE_FORMAT".", i);
01062 if (cpl_table_has_column(b->table, name)) {
01063 if (! _irplib_table_column_equal(a->table, b->table, name, CPL_TRUE)) {
01064 no_match = CPL_TRUE;
01065 break;
01066 }
01067 }
01068 }
01069 cpl_array_delete(names);
01070
01071 if (no_match || ! cpl_errorstate_is_equal(prestate)) return CPL_FALSE;
01072
01073 } else {
01074 cpl_size nb;
01075 if (a->nelem != b->nelem) return CPL_FALSE;
01076
01077
01078 nb = cpl_propertylist_get_size(b->proplist);
01079 if (na != nb) return CPL_FALSE;
01080 for (i = 0; i < na; ++i) {
01081 pa = cpl_propertylist_get_const(a->proplist, i);
01082 cpl_error_ensure(pa != NULL, cpl_error_get_code(), return CPL_FALSE,
01083 "Failed to get property structure %"CPL_SIZE_FORMAT".", i);
01084 name = cpl_property_get_name(pa);
01085 cpl_error_ensure(name != NULL, cpl_error_get_code(), return CPL_FALSE,
01086 "Failed to get the name for property %"CPL_SIZE_FORMAT".", i);
01087 pb = cpl_propertylist_get_property_const(b->proplist, name);
01088 if (pb == NULL) return CPL_FALSE;
01089 prestate = cpl_errorstate_get();
01090 if (! _irplib_property_equal(pa, pb)) return CPL_FALSE;
01091 if (! cpl_errorstate_is_equal(prestate)) return CPL_FALSE;
01092 }
01093
01094
01095 prestate = cpl_errorstate_get();
01096 na = cpl_table_get_ncol(a->table);
01097 nb = cpl_table_get_ncol(b->table);
01098 if (na != nb) return CPL_FALSE;
01099 names = cpl_table_get_column_names(a->table);
01100 for (i = 0; i < na; ++i) {
01101 name = cpl_array_get_string(names, i);
01102 cpl_error_ensure(name != NULL, cpl_error_get_code(), break,
01103 "Failed to get the name for column %"CPL_SIZE_FORMAT".", i);
01104 if (! cpl_table_has_column(b->table, name)
01105 || ! _irplib_table_column_equal(a->table, b->table, name, CPL_FALSE))
01106 {
01107 no_match = CPL_TRUE;
01108 break;
01109 }
01110 }
01111 cpl_array_delete(names);
01112
01113 if (no_match || ! cpl_errorstate_is_equal(prestate)) return CPL_FALSE;
01114 }
01115
01116
01117 return CPL_TRUE;
01118 }
01119
01120
01125
01126 static cpl_size
01127 _irplib_sdp_spectrum_count_keywords(const irplib_sdp_spectrum *self,
01128 const char *regexp)
01129 {
01130 cpl_error_code error;
01131 cpl_size result = 0;
01132 cpl_propertylist *list = cpl_propertylist_new();
01133
01134 assert(self != NULL);
01135 assert(self->proplist != NULL);
01136
01137 error = cpl_propertylist_copy_property_regexp(list, self->proplist, regexp,
01138 CPL_FALSE);
01139 if (! error) {
01140 result = cpl_propertylist_get_size(list);
01141 }
01142 cpl_propertylist_delete(list);
01143 return result;
01144 }
01145
01146
01147 cpl_size irplib_sdp_spectrum_count_obid(const irplib_sdp_spectrum *self)
01148 {
01149 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01150 return _irplib_sdp_spectrum_count_keywords(self, "^OBID[0-9]+$");
01151 }
01152
01153 cpl_size irplib_sdp_spectrum_count_prov(const irplib_sdp_spectrum *self)
01154 {
01155 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01156 return _irplib_sdp_spectrum_count_keywords(self, "^PROV[0-9]+$");
01157 }
01158
01159 cpl_size irplib_sdp_spectrum_count_asson(const irplib_sdp_spectrum *self)
01160 {
01161 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01162 return _irplib_sdp_spectrum_count_keywords(self, "^ASSON[0-9]+$");
01163 }
01164
01165 cpl_size irplib_sdp_spectrum_count_assoc(const irplib_sdp_spectrum *self)
01166 {
01167 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01168 return _irplib_sdp_spectrum_count_keywords(self, "^ASSOC[0-9]+$");
01169 }
01170
01171 cpl_size irplib_sdp_spectrum_count_assom(const irplib_sdp_spectrum *self)
01172 {
01173 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01174 return _irplib_sdp_spectrum_count_keywords(self, "^ASSOM[0-9]+$");
01175 }
01176
01177
01178 #ifndef NDEBUG
01179
01184 static cpl_boolean _irplib_keyword_table_is_sorted(
01185 const irplib_keyword_record *table, size_t entries)
01186 {
01187 size_t i;
01188 if (entries < 2) return CPL_TRUE;
01189 for (i = 0; i < entries-1; ++i) {
01190 if (strcmp(table[i].name, table[i+1].name) >= 0) {
01191 return CPL_FALSE;
01192 }
01193 }
01194 return CPL_TRUE;
01195 }
01196
01197 #endif
01198
01199
01200 static const irplib_keyword_record *
01201 _irplib_sdp_spectrum_get_keyword_record(const char *name)
01202 {
01203
01204
01205
01206 static const irplib_keyword_record keyword_table[] = {
01207
01208 {KEY_APERTURE, KEY_APERTURE_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01209 {KEY_ASSOC, KEY_ASSOC_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01210 {KEY_ASSOM, KEY_ASSOM_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01211 {KEY_ASSON, KEY_ASSON_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01212 {KEY_CONTNORM, KEY_CONTNORM_COMMENT, CPL_TYPE_BOOL, CPL_FALSE},
01213 {KEY_DEC, KEY_DEC_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01214 {KEY_DETRON, KEY_DETRON_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01215 {KEY_DISPELEM, KEY_DISPELEM_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01216 {KEY_EFFRON, KEY_EFFRON_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01217 {KEY_EXPTIME, KEY_EXPTIME_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01218 {KEY_EXTNAME, KEY_EXTNAME_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01219 {KEY_EXT_OBJ, KEY_EXT_OBJ_COMMENT, CPL_TYPE_BOOL, CPL_FALSE},
01220 {KEY_FLUXCAL, KEY_FLUXCAL_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01221 {KEY_FLUXERR, KEY_FLUXERR_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01222 {KEY_GAIN, KEY_GAIN_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01223 {KEY_INHERIT, KEY_INHERIT_COMMENT, CPL_TYPE_BOOL, CPL_FALSE},
01224 {KEY_LAMNLIN, KEY_LAMNLIN_COMMENT, CPL_TYPE_INT, CPL_FALSE},
01225 {KEY_LAMRMS, KEY_LAMRMS_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01226 {KEY_MJDEND, KEY_MJDEND_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01227 {KEY_MJDOBS, KEY_MJDOBS_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01228 {KEY_M_EPOCH, KEY_M_EPOCH_COMMENT, CPL_TYPE_BOOL, CPL_FALSE},
01229 {KEY_NCOMBINE, KEY_NCOMBINE_COMMENT, CPL_TYPE_INT, CPL_FALSE},
01230 {KEY_NELEM, KEY_NELEM_COMMENT, IRPLIB_TYPE_NELEM, CPL_FALSE},
01231 {KEY_OBID, KEY_OBID_COMMENT, CPL_TYPE_INT, CPL_TRUE},
01232 {KEY_OBJECT, KEY_OBJECT_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01233 {KEY_OBSTECH, KEY_OBSTECH_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01234 {KEY_ORIGIN, KEY_ORIGIN_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01235 {KEY_PROCSOFT, KEY_PROCSOFT_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01236 {KEY_PRODCATG, KEY_PRODCATG_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01237 {KEY_PRODLVL, KEY_PRODLVL_COMMENT, CPL_TYPE_INT, CPL_FALSE},
01238 {KEY_PROG_ID, KEY_PROG_ID_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01239 {KEY_PROV, KEY_PROV_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01240 {KEY_RA, KEY_RA_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01241 {KEY_REFERENC, KEY_REFERENC_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01242 {KEY_SNR, KEY_SNR_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01243 {KEY_SPECSYS, KEY_SPECSYS_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01244 {KEY_SPEC_BIN, KEY_SPEC_BIN_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01245 {KEY_SPEC_BW, KEY_SPEC_BW_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01246 {KEY_SPEC_ERR, KEY_SPEC_ERR_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01247 {KEY_SPEC_RES, KEY_SPEC_RES_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01248 {KEY_SPEC_SYE, KEY_SPEC_SYE_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01249 {KEY_SPEC_VAL, KEY_SPEC_VAL_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01250 {KEY_TCOMM, KEY_TCOMM_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01251 {KEY_TDMAX(1), KEY_TDMAX1_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01252 {KEY_TDMIN(1), KEY_TDMIN1_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01253 {KEY_TELAPSE, KEY_TELAPSE_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01254 {KEY_TEXPTIME, KEY_TEXPTIME_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01255 {KEY_TIMESYS, KEY_TIMESYS_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01256 {KEY_TITLE, KEY_TITLE_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01257 {KEY_TMID, KEY_TMID_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01258 {KEY_TOT_FLUX, KEY_TOT_FLUX_COMMENT, CPL_TYPE_BOOL, CPL_FALSE},
01259 {KEY_TUCD, KEY_TUCD_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01260 {KEY_TUTYP, KEY_TUTYP_COMMENT, CPL_TYPE_STRING, CPL_TRUE},
01261 {KEY_VOCLASS, KEY_VOCLASS_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01262 {KEY_VOPUB, KEY_VOPUB_COMMENT, CPL_TYPE_STRING, CPL_FALSE},
01263 {KEY_WAVELMAX, KEY_WAVELMAX_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE},
01264 {KEY_WAVELMIN, KEY_WAVELMIN_COMMENT, CPL_TYPE_DOUBLE, CPL_FALSE}
01265 };
01266
01267 static const size_t tablesize =
01268 sizeof(keyword_table) / sizeof(irplib_keyword_record);
01269 size_t low = 0;
01270 size_t high = tablesize-1;
01271 const irplib_keyword_record *record = NULL;
01272
01273 assert(_irplib_keyword_table_is_sorted(keyword_table, tablesize));
01274 assert(name != NULL);
01275
01276
01277
01278
01279
01280
01281 do {
01282 size_t mid = (low + high) >> 1;
01283 size_t keylen = strlen(keyword_table[mid].name);
01284 int result = strncmp(name, keyword_table[mid].name, keylen);
01285 if (result == 0) {
01286 record = &keyword_table[mid];
01287 break;
01288 } else if (result < 0) {
01289 if (mid >= 1) {
01290 high = mid - 1;
01291 } else {
01292 return NULL;
01293 }
01294 } else {
01295 low = mid + 1;
01296 if (low > high) return NULL;
01297 }
01298 } while (1);
01299
01300 assert(record != NULL);
01301
01302 if (strlen(record->name) != strlen(name)) {
01303 if (! record->is_array_key) return NULL;
01304
01305
01306 const char *c = name + strlen(record->name);
01307 while (*c != '\0') {
01308 if (! isdigit(*c)) return NULL;
01309 ++c;
01310 }
01311 }
01312
01313 return record;
01314 }
01315
01316
01317 cpl_error_code irplib_sdp_spectrum_copy_keyword(irplib_sdp_spectrum *self,
01318 const cpl_propertylist *plist,
01319 const char *name)
01320 {
01321 const irplib_keyword_record *key;
01322 cpl_errorstate prestate = cpl_errorstate_get();
01323 cpl_boolean spectrum_has_keyword;
01324
01325 cpl_ensure_code(self != NULL && plist != NULL && name != NULL,
01326 CPL_ERROR_NULL_INPUT);
01327
01328 assert(self->proplist != NULL);
01329
01330 if (! cpl_propertylist_has(plist, name)) {
01331 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
01332 "Could not set '%s' since the keyword was not found in the"
01333 " source list.", name);
01334 }
01335
01336 key = _irplib_sdp_spectrum_get_keyword_record(name);
01337 if (key == NULL) {
01338 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01339 "The keyword name '%s' is not valid for an SPD spectrum.",
01340 name);
01341 }
01342
01343 spectrum_has_keyword = cpl_propertylist_has(self->proplist, name);
01344
01345 switch ((int) key->type) {
01346 case CPL_TYPE_BOOL:
01347 {
01348
01349
01350
01351 cpl_boolean value = cpl_propertylist_get_bool(plist, name);
01352 cpl_propertylist_update_bool(self->proplist, name, value);
01353 }
01354 break;
01355 case CPL_TYPE_INT:
01356 {
01357 int value = cpl_propertylist_get_int(plist, name);
01358 cpl_propertylist_update_int(self->proplist, name, value);
01359 }
01360 break;
01361 case CPL_TYPE_DOUBLE:
01362 {
01363 double value = cpl_propertylist_get_double(plist, name);
01364 cpl_propertylist_update_double(self->proplist, name, value);
01365 }
01366 break;
01367 case CPL_TYPE_STRING:
01368 {
01369 const char *value = cpl_propertylist_get_string(plist, name);
01370 cpl_propertylist_update_string(self->proplist, name, value);
01371 }
01372 break;
01373 case IRPLIB_TYPE_NELEM:
01374 {
01375
01376 spectrum_has_keyword = CPL_TRUE;
01377 cpl_size value = (cpl_size) cpl_propertylist_get_long_long(plist, name);
01378 if (cpl_errorstate_is_equal(prestate)) {
01379 irplib_sdp_spectrum_set_nelem(self, value);
01380 }
01381 }
01382 break;
01383 default:
01384 return cpl_error_set_message(cpl_func, CPL_ERROR_INVALID_TYPE,
01385 "Cannot handle type '%s'.", cpl_type_get_name(key->type));
01386 }
01387
01388 if (! spectrum_has_keyword) {
01389 cpl_propertylist_set_comment(self->proplist, name, key->comment);
01390 }
01391
01392 if (! cpl_errorstate_is_equal(prestate)) {
01393 if (! spectrum_has_keyword) {
01394
01395
01396 prestate = cpl_errorstate_get();
01397 (void) cpl_propertylist_erase(self->proplist, name);
01398 cpl_errorstate_set(prestate);
01399 }
01400 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
01401 "Could not set '%s'. Likely the keyword from the source list"
01402 " has a different format or type.", name);
01403 }
01404
01405 return CPL_ERROR_NONE;
01406 }
01407
01408
01409 cpl_error_code irplib_sdp_spectrum_copy_property(irplib_sdp_spectrum *self,
01410 const cpl_property *prop)
01411 {
01412 const char *name;
01413 const irplib_keyword_record *key;
01414 cpl_errorstate prestate = cpl_errorstate_get();
01415 cpl_boolean spectrum_has_keyword;
01416
01417 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01418
01419 assert(self->proplist != NULL);
01420
01421 name = cpl_property_get_name(prop);
01422 if (name == NULL) return cpl_error_get_code();
01423
01424 key = _irplib_sdp_spectrum_get_keyword_record(name);
01425 if (key == NULL) {
01426 return cpl_error_set_message(cpl_func, CPL_ERROR_ILLEGAL_INPUT,
01427 "The keyword name '%s' is not valid for an SPD spectrum.",
01428 name);
01429 }
01430
01431 spectrum_has_keyword = cpl_propertylist_has(self->proplist, name);
01432
01433 switch ((int) key->type) {
01434 case CPL_TYPE_BOOL:
01435 {
01436 cpl_boolean value = cpl_property_get_bool(prop);
01437 cpl_propertylist_update_bool(self->proplist, name, value);
01438 }
01439 break;
01440 case CPL_TYPE_INT:
01441 {
01442 int value = cpl_property_get_int(prop);
01443 cpl_propertylist_update_int(self->proplist, name, value);
01444 }
01445 break;
01446 case CPL_TYPE_DOUBLE:
01447 {
01448 double value = cpl_property_get_double(prop);
01449 cpl_propertylist_update_double(self->proplist, name, value);
01450 }
01451 break;
01452 case CPL_TYPE_STRING:
01453 {
01454 const char *value = cpl_property_get_string(prop);
01455 cpl_propertylist_update_string(self->proplist, name, value);
01456 }
01457 break;
01458 case IRPLIB_TYPE_NELEM:
01459 {
01460
01461 spectrum_has_keyword = CPL_TRUE;
01462 cpl_size value = (cpl_size) cpl_property_get_long_long(prop);
01463 if (cpl_errorstate_is_equal(prestate)) {
01464 irplib_sdp_spectrum_set_nelem(self, value);
01465 }
01466 }
01467 break;
01468 default:
01469 return cpl_error_set_message(cpl_func, CPL_ERROR_INVALID_TYPE,
01470 "Cannot handle type '%s'.", cpl_type_get_name(key->type));
01471 }
01472
01473 if (! spectrum_has_keyword) {
01474 cpl_propertylist_set_comment(self->proplist, name, key->comment);
01475 }
01476
01477 if (! cpl_errorstate_is_equal(prestate)) {
01478 if (! spectrum_has_keyword) {
01479
01480
01481 prestate = cpl_errorstate_get();
01482 (void) cpl_propertylist_erase(self->proplist, name);
01483 cpl_errorstate_set(prestate);
01484 }
01485 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
01486 "Could not set '%s'. Likely the source property has a"
01487 " different format or type.", name);
01488 }
01489
01490 return CPL_ERROR_NONE;
01491 }
01492
01493
01494 cpl_error_code irplib_sdp_spectrum_copy_property_regexp(
01495 irplib_sdp_spectrum *self,
01496 const cpl_propertylist *plist,
01497 const char *regexp,
01498 int invert)
01499 {
01500 cpl_propertylist *sublist = NULL;
01501 cpl_propertylist *origlist = NULL;
01502 cpl_errorstate prestate = cpl_errorstate_get();
01503 cpl_size i;
01504
01505 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01506
01507 assert(self->proplist != NULL);
01508
01509 sublist = cpl_propertylist_new();
01510 origlist = cpl_propertylist_new();
01511 cpl_propertylist_copy_property_regexp(origlist, self->proplist, regexp,
01512 invert);
01513 cpl_propertylist_copy_property_regexp(sublist, plist, regexp, invert);
01514 if (cpl_propertylist_has(sublist, KEY_NELEM)) {
01515
01516
01517 cpl_propertylist_erase(sublist, KEY_NELEM);
01518 cpl_propertylist_copy_property(sublist, plist, KEY_NELEM);
01519 }
01520 if (! cpl_errorstate_is_equal(prestate)) goto cleanup;
01521
01522 for (i = 0; i < cpl_propertylist_get_size(sublist); ++i) {
01523 const cpl_property *p = cpl_propertylist_get_const(sublist, i);
01524 const char *name = cpl_property_get_name(p);
01525 irplib_sdp_spectrum_copy_keyword(self, sublist, name);
01526 if (! cpl_errorstate_is_equal(prestate)) goto cleanup;
01527 }
01528
01529 cpl_propertylist_delete(sublist);
01530 cpl_propertylist_delete(origlist);
01531 return CPL_ERROR_NONE;
01532
01533 cleanup:
01534
01535
01536 prestate = cpl_errorstate_get();
01537 (void) cpl_propertylist_copy_property_regexp(self->proplist, origlist,
01538 ".*", 0);
01539 cpl_errorstate_set(prestate);
01540 cpl_propertylist_delete(sublist);
01541 cpl_propertylist_delete(origlist);
01542 return cpl_error_get_code();
01543 }
01544
01545
01546 GET_SET_METHODS_TYPE_DOUBLE(ra, KEY_RA, KEY_RA_COMMENT)
01547 GET_SET_METHODS_TYPE_DOUBLE(dec, KEY_DEC, KEY_DEC_COMMENT)
01548 GET_SET_METHODS_TYPE_DOUBLE(exptime, KEY_EXPTIME, KEY_EXPTIME_COMMENT)
01549 GET_SET_METHODS_TYPE_DOUBLE(texptime, KEY_TEXPTIME, KEY_TEXPTIME_COMMENT)
01550 GET_SET_METHODS_TYPE_STRING(timesys, KEY_TIMESYS, KEY_TIMESYS_COMMENT)
01551 GET_SET_METHODS_TYPE_DOUBLE(mjdobs, KEY_MJDOBS, KEY_MJDOBS_COMMENT)
01552 GET_SET_METHODS_TYPE_DOUBLE(mjdend, KEY_MJDEND, KEY_MJDEND_COMMENT)
01553 GET_SET_METHODS_TYPE_INT(prodlvl, KEY_PRODLVL, KEY_PRODLVL_COMMENT)
01554 GET_SET_METHODS_TYPE_STRING(procsoft, KEY_PROCSOFT, KEY_PROCSOFT_COMMENT)
01555 GET_SET_METHODS_TYPE_STRING(prodcatg, KEY_PRODCATG, KEY_PRODCATG_COMMENT)
01556 GET_SET_METHODS_TYPE_STRING(origin, KEY_ORIGIN, KEY_ORIGIN_COMMENT)
01557 GET_SET_METHODS_TYPE_BOOL(extobj, KEY_EXT_OBJ, KEY_EXT_OBJ_COMMENT)
01558 GET_SET_METHODS_TYPE_STRING(dispelem, KEY_DISPELEM, KEY_DISPELEM_COMMENT)
01559 GET_SET_METHODS_TYPE_STRING(specsys, KEY_SPECSYS, KEY_SPECSYS_COMMENT)
01560 GET_SET_METHODS_TYPE_STRING(progid, KEY_PROG_ID, KEY_PROG_ID_COMMENT)
01561 GET_SET_ARRAY_METHODS_TYPE_INT(obid, KEY_OBID, KEY_OBID_COMMENT)
01562 GET_SET_METHODS_TYPE_BOOL(mepoch, KEY_M_EPOCH, KEY_M_EPOCH_COMMENT)
01563 GET_SET_METHODS_TYPE_STRING(obstech, KEY_OBSTECH, KEY_OBSTECH_COMMENT)
01564 GET_SET_METHODS_TYPE_STRING(fluxcal, KEY_FLUXCAL, KEY_FLUXCAL_COMMENT)
01565 GET_SET_METHODS_TYPE_BOOL(contnorm, KEY_CONTNORM, KEY_CONTNORM_COMMENT)
01566 GET_SET_METHODS_TYPE_DOUBLE(wavelmin, KEY_WAVELMIN, KEY_WAVELMIN_COMMENT)
01567 GET_SET_METHODS_TYPE_DOUBLE(wavelmax, KEY_WAVELMAX, KEY_WAVELMAX_COMMENT)
01568 GET_SET_METHODS_TYPE_DOUBLE(specbin, KEY_SPEC_BIN, KEY_SPEC_BIN_COMMENT)
01569 GET_SET_METHODS_TYPE_BOOL(totflux, KEY_TOT_FLUX, KEY_TOT_FLUX_COMMENT)
01570 GET_SET_METHODS_TYPE_DOUBLE(fluxerr, KEY_FLUXERR, KEY_FLUXERR_COMMENT)
01571 GET_SET_METHODS_TYPE_STRING(referenc, KEY_REFERENC, KEY_REFERENC_COMMENT)
01572 GET_SET_METHODS_TYPE_DOUBLE(specres, KEY_SPEC_RES, KEY_SPEC_RES_COMMENT)
01573 GET_SET_METHODS_TYPE_DOUBLE(specerr, KEY_SPEC_ERR, KEY_SPEC_ERR_COMMENT)
01574 GET_SET_METHODS_TYPE_DOUBLE(specsye, KEY_SPEC_SYE, KEY_SPEC_SYE_COMMENT)
01575 GET_SET_METHODS_TYPE_INT(lamnlin, KEY_LAMNLIN, KEY_LAMNLIN_COMMENT)
01576 GET_SET_METHODS_TYPE_DOUBLE(lamrms, KEY_LAMRMS, KEY_LAMRMS_COMMENT)
01577 GET_SET_METHODS_TYPE_DOUBLE(gain, KEY_GAIN, KEY_GAIN_COMMENT)
01578 GET_SET_METHODS_TYPE_DOUBLE(detron, KEY_DETRON, KEY_DETRON_COMMENT)
01579 GET_SET_METHODS_TYPE_DOUBLE(effron, KEY_EFFRON, KEY_EFFRON_COMMENT)
01580 GET_SET_METHODS_TYPE_DOUBLE(snr, KEY_SNR, KEY_SNR_COMMENT)
01581 GET_SET_METHODS_TYPE_INT(ncombine, KEY_NCOMBINE, KEY_NCOMBINE_COMMENT)
01582 GET_SET_ARRAY_METHODS_TYPE_STRING(prov, KEY_PROV, KEY_PROV_COMMENT)
01583 GET_SET_ARRAY_METHODS_TYPE_STRING(asson, KEY_ASSON, KEY_ASSON_COMMENT)
01584 GET_SET_ARRAY_METHODS_TYPE_STRING(assoc, KEY_ASSOC, KEY_ASSOC_COMMENT)
01585 GET_SET_ARRAY_METHODS_TYPE_STRING(assom, KEY_ASSOM, KEY_ASSOM_COMMENT)
01586 GET_SET_METHODS_TYPE_STRING(voclass, KEY_VOCLASS, KEY_VOCLASS_COMMENT)
01587 GET_SET_METHODS_TYPE_STRING(vopub, KEY_VOPUB, KEY_VOPUB_COMMENT)
01588 GET_SET_METHODS_TYPE_STRING(title, KEY_TITLE, KEY_TITLE_COMMENT)
01589 GET_SET_METHODS_TYPE_STRING(object, KEY_OBJECT, KEY_OBJECT_COMMENT)
01590 GET_SET_METHODS_TYPE_DOUBLE(aperture, KEY_APERTURE, KEY_APERTURE_COMMENT)
01591 GET_SET_METHODS_TYPE_DOUBLE(telapse, KEY_TELAPSE, KEY_TELAPSE_COMMENT)
01592 GET_SET_METHODS_TYPE_DOUBLE(tmid, KEY_TMID, KEY_TMID_COMMENT)
01593 GET_SET_METHODS_TYPE_DOUBLE(specval, KEY_SPEC_VAL, KEY_SPEC_VAL_COMMENT)
01594 GET_SET_METHODS_TYPE_DOUBLE(specbw, KEY_SPEC_BW, KEY_SPEC_BW_COMMENT)
01595 GET_SET_METHODS_TYPE_STRING(extname, KEY_EXTNAME, KEY_EXTNAME_COMMENT)
01596 GET_SET_METHODS_TYPE_BOOL(inherit, KEY_INHERIT, KEY_INHERIT_COMMENT)
01597 GET_SET_METHODS_TYPE_DOUBLE(tdmin, KEY_TDMIN(1), KEY_TDMIN1_COMMENT)
01598 GET_SET_METHODS_TYPE_DOUBLE(tdmax, KEY_TDMAX(1), KEY_TDMAX1_COMMENT)
01599
01600
01601 cpl_error_code irplib_sdp_spectrum_append_prov(irplib_sdp_spectrum *self,
01602 cpl_size firstindex,
01603 const cpl_frameset *frames)
01604 {
01605 cpl_frameset_iterator* iter = NULL;
01606 cpl_propertylist* keywords = NULL;
01607 const cpl_frame* frame;
01608 cpl_size index = firstindex;
01609
01610
01611 assert(self != NULL);
01612 assert(self->proplist != NULL);
01613
01614 iter = cpl_frameset_iterator_new(frames);
01615 frame = cpl_frameset_iterator_get_const(iter);
01616 while (frame != NULL) {
01617 cpl_error_code error;
01618 const char* value = NULL;
01619
01620
01621 const char* filename = cpl_frame_get_filename(frame);
01622 cpl_error_ensure(filename != NULL, cpl_error_get_code(), goto cleanup,
01623 "%s", cpl_error_get_message());
01624 keywords = cpl_propertylist_load(filename, 0);
01625 cpl_error_ensure(filename != NULL, cpl_error_get_code(), goto cleanup,
01626 "Could not load keywords from primary HDU in '%s'.",
01627 filename);
01628
01629
01630
01631 if (cpl_propertylist_has(keywords, KEY_ARCFILE)) {
01632 value = cpl_propertylist_get_string(keywords, KEY_ARCFILE);
01633 cpl_error_ensure(value != NULL, cpl_error_get_code(), goto cleanup,
01634 "Could not extract the '%s' keyword value from '%s'.",
01635 KEY_ARCFILE, filename);
01636 } else if (cpl_propertylist_has(keywords, KEY_ORIGFILE)) {
01637 value = cpl_propertylist_get_string(keywords, KEY_ORIGFILE);
01638 cpl_error_ensure(value != NULL, cpl_error_get_code(), goto cleanup,
01639 "Could not extract the '%s' keyword value from '%s'.",
01640 KEY_ORIGFILE, filename);
01641 } else {
01642 value = filename;
01643 }
01644
01645
01646 error = irplib_sdp_spectrum_set_prov(self, index, value);
01647 cpl_error_ensure(! error, error, goto cleanup,
01648 "%s", cpl_error_get_message());
01649 cpl_propertylist_delete(keywords);
01650 keywords = NULL;
01651
01652
01653 cpl_errorstate status = cpl_errorstate_get();
01654 cpl_frameset_iterator_advance(iter, 1);
01655 if (cpl_error_get_code() == CPL_ERROR_ACCESS_OUT_OF_RANGE) {
01656 cpl_errorstate_set(status);
01657 }
01658 frame = cpl_frameset_iterator_get_const(iter);
01659 ++index;
01660 }
01661
01662 cpl_frameset_iterator_delete(iter);
01663 return CPL_ERROR_NONE;
01664
01665 cleanup:
01666
01667 cpl_frameset_iterator_delete(iter);
01668 cpl_propertylist_delete(keywords);
01669 return cpl_error_get_code();
01670 }
01671
01672
01673 cpl_size irplib_sdp_spectrum_get_nelem(const irplib_sdp_spectrum *self)
01674 {
01675 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01676 return self->nelem;
01677 }
01678
01679
01680 cpl_error_code irplib_sdp_spectrum_reset_nelem(irplib_sdp_spectrum *self)
01681 {
01682 return irplib_sdp_spectrum_set_nelem(self, 0);
01683 }
01684
01685
01686 cpl_error_code irplib_sdp_spectrum_set_nelem(irplib_sdp_spectrum *self,
01687 cpl_size value)
01688 {
01689 cpl_size ncol;
01690 cpl_error_code error = CPL_ERROR_NONE;
01691
01692 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01693
01694 assert(self->table != NULL);
01695
01696 ncol = cpl_table_get_ncol(self->table);
01697 if (ncol > 0) {
01698
01699 cpl_size i;
01700 cpl_array *names = cpl_table_get_column_names(self->table);
01701 for (i = 0; i < ncol; ++i) {
01702 const char *name = cpl_array_get_string(names, i);
01703 error = cpl_table_set_column_depth(self->table, name, value);
01704 if (error) {
01705
01706
01707 cpl_size j;
01708 cpl_errorstate prestate = cpl_errorstate_get();
01709 for (j = 0; j < i; ++j) {
01710 (void) cpl_table_set_column_depth(self->table, name, self->nelem);
01711 }
01712 cpl_errorstate_set(prestate);
01713 break;
01714 }
01715 }
01716 cpl_array_delete(names);
01717 }
01718 if (! error) {
01719 self->nelem = value;
01720 }
01721 return error;
01722 }
01723
01724
01725 cpl_error_code irplib_sdp_spectrum_copy_nelem(irplib_sdp_spectrum *self,
01726 const cpl_propertylist *plist,
01727 const char *name)
01728 {
01729
01730 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01731
01732 assert(self->proplist != NULL);
01733
01734 if (cpl_propertylist_has(plist, name)) {
01735 cpl_errorstate prestate = cpl_errorstate_get();
01736 cpl_size value = (cpl_size) cpl_propertylist_get_long_long(plist, name);
01737 if (cpl_errorstate_is_equal(prestate)) {
01738 return irplib_sdp_spectrum_set_nelem(self, value);
01739 } else {
01740 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
01741 "Could not set '%s'. Likely the source '%s' keyword has a"
01742 " different format or type.", KEY_NELEM, name);
01743 }
01744 } else {
01745 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
01746 "Could not set '%s' since the '%s' keyword was not found.",
01747 KEY_NELEM, name);
01748 }
01749 }
01750
01751
01752 cpl_size irplib_sdp_spectrum_get_ncol(const irplib_sdp_spectrum *self)
01753 {
01754 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01755 assert(self->table != NULL);
01756 return cpl_table_get_ncol(self->table);
01757 }
01758
01759
01760 cpl_boolean irplib_sdp_spectrum_has_column(const irplib_sdp_spectrum *self,
01761 const char* name)
01762 {
01763 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, 0);
01764 assert(self->table != NULL);
01765 return cpl_table_has_column(self->table, name);
01766 }
01767
01768
01769 cpl_array *
01770 irplib_sdp_spectrum_get_column_names(const irplib_sdp_spectrum *self)
01771 {
01772 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
01773 assert(self->table != NULL);
01774 return cpl_table_get_column_names(self->table);
01775 }
01776
01777
01778 cpl_error_code
01779 irplib_sdp_spectrum_new_column(irplib_sdp_spectrum *self, const char *name,
01780 cpl_type type)
01781 {
01782 cpl_error_code error;
01783 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01784 assert(self->table != NULL);
01785 error = cpl_table_new_column_array(self->table, name, type, self->nelem);
01786 if (error) {
01787 cpl_error_set_message(cpl_func, cpl_error_get_code(),
01788 "Failed to create a new column called '%s'.", name);
01789 }
01790 return error;
01791 }
01792
01793
01794 cpl_error_code
01795 irplib_sdp_spectrum_add_column(irplib_sdp_spectrum *self, const char *name,
01796 cpl_type type, const char *unit,
01797 const char *format, const char *tutyp,
01798 const char *tucd, const cpl_array *data)
01799 {
01800 cpl_error_code error;
01801
01802
01803 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01804
01805 assert(self->table != NULL);
01806
01807
01808
01809 error = cpl_table_new_column_array(self->table, name, type, self->nelem);
01810 if (unit != NULL && *unit != '\0') {
01811 error |= cpl_table_set_column_unit(self->table, name, unit);
01812 } else {
01813 error |= cpl_table_set_column_unit(self->table, name, " ");
01814 }
01815 if (format != NULL) {
01816 error |= cpl_table_set_column_format(self->table, name, format);
01817 }
01818 if (tutyp != NULL) {
01819 error |= irplib_sdp_spectrum_set_column_tutyp(self, name, tutyp);
01820 } else {
01821 error |= irplib_sdp_spectrum_set_column_tutyp(self, name, "");
01822 }
01823 if (tucd != NULL) {
01824 error |= irplib_sdp_spectrum_set_column_tucd(self, name, tucd);
01825 } else {
01826 error |= irplib_sdp_spectrum_set_column_tucd(self, name, "");
01827 }
01828
01829
01830
01831 if (! error) {
01832 if (data != NULL) {
01833 error = cpl_table_set_array(self->table, name, 0, data);
01834 } else {
01835 cpl_array *array = cpl_array_new(self->nelem, type);
01836 if (array != NULL) {
01837 error = cpl_table_set_array(self->table, name, 0, array);
01838 cpl_array_delete(array);
01839 } else {
01840 error = cpl_error_get_code();
01841 }
01842 }
01843 }
01844
01845 if (error) {
01846
01847
01848
01849
01850 cpl_errorstate prestate = cpl_errorstate_get();
01851 _irplib_sdp_spectrum_erase_column_keywords(self, name);
01852 (void) cpl_table_erase_column(self->table, name);
01853 cpl_errorstate_set(prestate);
01854 error = cpl_error_set_message(cpl_func, cpl_error_get_code(),
01855 "Failed to create a new column called '%s'.", name);
01856 }
01857
01858 return error;
01859 }
01860
01861
01862 cpl_error_code
01863 irplib_sdp_spectrum_delete_column(irplib_sdp_spectrum *self, const char *name)
01864 {
01865 cpl_errorstate prestate = cpl_errorstate_get();
01866 cpl_error_code error = CPL_ERROR_NONE;
01867
01868 cpl_ensure_code(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT);
01869
01870 assert(self->table != NULL);
01871
01872 _irplib_sdp_spectrum_erase_column_keywords(self, name);
01873 if (! cpl_errorstate_is_equal(prestate)) {
01874 error |= cpl_error_get_code();
01875 }
01876 error |= cpl_table_erase_column(self->table, name);
01877 if (error) {
01878 return cpl_error_get_code();
01879 } else {
01880 return CPL_ERROR_NONE;
01881 }
01882 }
01883
01884
01885 static cpl_error_code
01886 _irplib_sdp_spectrum_copy_column(irplib_sdp_spectrum *self, const char *to_name,
01887 const cpl_table* table, const char *from_name)
01888 {
01889 cpl_error_code error;
01890
01891 assert(self != NULL);
01892 assert(self->table != NULL);
01893
01894 error = cpl_table_duplicate_column(self->table, to_name, table, from_name);
01895 if (error) return error;
01896 error |= irplib_sdp_spectrum_set_column_tutyp(self, to_name, "");
01897 error |= irplib_sdp_spectrum_set_column_tucd(self, to_name, "");
01898 if (error) {
01899
01900 cpl_errorstate prestate = cpl_errorstate_get();
01901 _irplib_sdp_spectrum_erase_column_keywords(self, to_name);
01902 (void) cpl_table_erase_column(self->table, to_name);
01903 cpl_errorstate_set(prestate);
01904 return cpl_error_get_code();
01905 }
01906 return CPL_ERROR_NONE;
01907 }
01908
01909
01910 cpl_error_code
01911 irplib_sdp_spectrum_copy_column(irplib_sdp_spectrum *self,
01912 const cpl_table* table, const char *name)
01913 {
01914
01915
01916 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
01917 return _irplib_sdp_spectrum_copy_column(self, name, table, name);
01918 }
01919
01920
01921 cpl_error_code
01922 irplib_sdp_spectrum_copy_column_regexp(irplib_sdp_spectrum *self,
01923 const cpl_table* table,
01924 const char *regexp, int invert)
01925 {
01926 regex_t re;
01927 cpl_array *names = NULL;
01928 cpl_size n, i;
01929 int reg_error_code;
01930
01931
01932 cpl_ensure_code(self != NULL && regexp != NULL, CPL_ERROR_NULL_INPUT);
01933
01934 assert(self->table != NULL);
01935
01936 reg_error_code = regcomp(&re, regexp, REG_EXTENDED | REG_NOSUB);
01937 if (reg_error_code != 0) {
01938 return cpl_error_set_regex(CPL_ERROR_ILLEGAL_INPUT, reg_error_code, &re,
01939 "regexp='%s', invert=%d", regexp, invert);
01940 }
01941
01942
01943
01944 names = cpl_table_get_column_names(table);
01945 n = cpl_array_get_size(names);
01946 for (i = 0; i < n; ++i) {
01947 int match;
01948 const char *namei = cpl_array_get_string(names, i);
01949 cpl_error_ensure(! cpl_table_has_column(self->table, namei),
01950 CPL_ERROR_ILLEGAL_OUTPUT, goto cleanup,
01951 "The column '%s' already exists in the spectrum.", namei);
01952 match = (regexec(&re, namei, 0, NULL, 0) == 0);
01953 if ((! match && ! invert) || (match && invert)) {
01954 cpl_array_set_invalid(names, i);
01955 }
01956 }
01957
01958 for (i = 0; i < n; ++i) {
01959 if (cpl_array_is_valid(names, i)) {
01960 const char *namei = cpl_array_get_string(names, i);
01961 cpl_error_code error = _irplib_sdp_spectrum_copy_column(self, namei,
01962 table, namei);
01963 if (error) {
01964 cpl_errorstate prestate;
01965 cpl_size j;
01966 cpl_error_set_message(cpl_func, error, "Could not copy column '%s'.",
01967 namei);
01968
01969
01970 prestate = cpl_errorstate_get();
01971 for (j = 0; j < i; ++j) {
01972 namei = cpl_array_get_string(names, i);
01973 _irplib_sdp_spectrum_erase_column_keywords(self, namei);
01974 (void) cpl_table_erase_column(self->table, namei);
01975 }
01976 cpl_errorstate_set(prestate);
01977 goto cleanup;
01978 }
01979 }
01980 }
01981 cpl_array_delete(names);
01982 regfree(&re);
01983 return CPL_ERROR_NONE;
01984
01985 cleanup:
01986
01987 cpl_array_delete(names);
01988 regfree(&re);
01989 return cpl_error_get_code();
01990 }
01991
01992
01993 cpl_error_code
01994 irplib_sdp_spectrum_update_column(irplib_sdp_spectrum *self, const char *name,
01995 const cpl_table* table, const char *colname,
01996 int flags)
01997 {
01998 char *orig_unit = NULL;
01999 char *orig_format = NULL;
02000 cpl_errorstate prestate = cpl_errorstate_get();
02001
02002
02003
02004 cpl_ensure_code(self != NULL && table != NULL, CPL_ERROR_NULL_INPUT);
02005
02006 assert(self->table != NULL);
02007
02008 if (! cpl_table_has_column(self->table, name)) {
02009
02010 return _irplib_sdp_spectrum_copy_column(self, name, table, colname);
02011 }
02012
02013
02014 if (! cpl_table_has_column(table, colname)) {
02015 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02016 "Column '%s' not found in table.", colname);
02017 }
02018
02019
02020
02021 if (flags & IRPLIB_COLUMN_UNIT) {
02022 const char* unit = cpl_table_get_column_unit(table, colname);
02023
02024
02025 if (unit != NULL && *unit == '\0') {
02026 unit = " ";
02027 }
02028 orig_unit = cpl_strdup(cpl_table_get_column_unit(self->table, name));
02029 cpl_table_set_column_unit(self->table, name, unit);
02030 if (! cpl_errorstate_is_equal(prestate)) goto cleanup;
02031 }
02032 if (flags & IRPLIB_COLUMN_FORMAT) {
02033 orig_format = cpl_strdup(cpl_table_get_column_format(self->table, name));
02034 cpl_table_set_column_format(self->table, name,
02035 cpl_table_get_column_format(table, colname));
02036 if (! cpl_errorstate_is_equal(prestate)) goto cleanup;
02037 }
02038
02039
02040
02041
02042 if (flags & IRPLIB_COLUMN_DATA) {
02043 if (cpl_table_get_column_type(self->table, name) !=
02044 cpl_table_get_column_type(table, colname)) {
02045 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
02046 "The table column '%s' and spectrum column '%s' do not"
02047 " have the same types.", colname, name);
02048 goto cleanup;
02049 }
02050 if (cpl_table_get_column_depth(self->table, name) !=
02051 cpl_table_get_column_depth(table, colname)) {
02052 cpl_error_set_message(cpl_func, CPL_ERROR_INCOMPATIBLE_INPUT,
02053 "The table column '%s' and spectrum column '%s' do not"
02054 " have the same dimensions.", colname, name);
02055 goto cleanup;
02056 }
02057 const cpl_array* data = cpl_table_get_array(table, colname, 0);
02058 if (data == NULL) goto cleanup;
02059 cpl_table_set_array(self->table, name, 0, data);
02060 if (! cpl_errorstate_is_equal(prestate)) goto cleanup;
02061 }
02062
02063 cpl_free(orig_unit);
02064 cpl_free(orig_format);
02065 return CPL_ERROR_NONE;
02066
02067 cleanup:
02068
02069 prestate = cpl_errorstate_get();
02070 if (orig_unit != NULL) {
02071 (void) cpl_table_set_column_unit(self->table, name, orig_unit);
02072 cpl_free(orig_unit);
02073 }
02074 if (orig_format != NULL) {
02075 (void) cpl_table_set_column_format(self->table, name, orig_format);
02076 cpl_free(orig_format);
02077 }
02078 cpl_errorstate_set(prestate);
02079 return cpl_error_get_code();
02080 }
02081
02082
02083 cpl_type irplib_sdp_spectrum_get_column_type(const irplib_sdp_spectrum *self,
02084 const char *name)
02085 {
02086 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, CPL_TYPE_INVALID);
02087 assert(self->table != NULL);
02088 return cpl_table_get_column_type(self->table, name);
02089 }
02090
02091
02092 const char *
02093 irplib_sdp_spectrum_get_column_unit(const irplib_sdp_spectrum *self,
02094 const char *name)
02095 {
02096 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
02097 assert(self->table != NULL);
02098 return cpl_table_get_column_unit(self->table, name);
02099 }
02100
02101
02116
02117 cpl_error_code
02118 irplib_sdp_spectrum_set_column_unit(irplib_sdp_spectrum *self,
02119 const char *name, const char *unit)
02120 {
02121 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02122 assert(self->table != NULL);
02123
02124
02125 if (unit != NULL && *unit == '\0') {
02126 unit = " ";
02127 }
02128 return cpl_table_set_column_unit(self->table, name, unit);
02129 }
02130
02131
02132 cpl_error_code
02133 irplib_sdp_spectrum_copy_column_unit(irplib_sdp_spectrum *self,
02134 const char *name,
02135 const cpl_propertylist *plist,
02136 const char *key)
02137 {
02138 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02139
02140 assert(self->table != NULL);
02141
02142 if (cpl_propertylist_has(plist, key)) {
02143 cpl_errorstate prestate = cpl_errorstate_get();
02144 const char *value = cpl_propertylist_get_string(plist, key);
02145 if (cpl_errorstate_is_equal(prestate)) {
02146
02147
02148 if (value != NULL && *value == '\0') {
02149 value = " ";
02150 }
02151 return cpl_table_set_column_unit(self->table, name, value);
02152 } else {
02153 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
02154 "Could not set the unit for column '%s'. Likely the source '%s'"
02155 " keyword is not a string.", name, key);
02156 }
02157 } else {
02158 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02159 "Could not set the unit for column '%s' since the '%s' keyword"
02160 " was not found.", name, key);
02161 }
02162 }
02163
02164
02165 const char *
02166 irplib_sdp_spectrum_get_column_format(const irplib_sdp_spectrum *self,
02167 const char *name)
02168 {
02169 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
02170 assert(self->table != NULL);
02171 return cpl_table_get_column_format(self->table, name);
02172 }
02173
02174
02175 cpl_error_code
02176 irplib_sdp_spectrum_set_column_format(irplib_sdp_spectrum *self,
02177 const char *name, const char *format)
02178 {
02179 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02180 assert(self->table != NULL);
02181 return cpl_table_set_column_format(self->table, name, format);
02182 }
02183
02184
02185 static cpl_size
02186 _irplib_sdp_spectrum_get_column_index(const irplib_sdp_spectrum *self,
02187 const char *name)
02188 {
02189 cpl_size i, n;
02190 cpl_array *names;
02191
02192 assert(self != NULL);
02193 assert(self->table != NULL);
02194 assert(name != NULL);
02195
02196
02197 names = cpl_table_get_column_names(self->table);
02198 n = cpl_array_get_size(names);
02199 for (i = 0; i < n; ++i) {
02200 const char *namei = cpl_array_get_string(names, i);
02201 if (strcmp(namei, name) == 0) {
02202 cpl_array_delete(names);
02203 return i;
02204 }
02205 }
02206 cpl_array_delete(names);
02207 return (cpl_size)-1;
02208 }
02209
02210
02211 static const char *
02212 _irplib_sdp_spectrum_get_column_keyword(const irplib_sdp_spectrum *self,
02213 const char *name, const char *keyword)
02214 {
02215 cpl_size index;
02216 const char *result = NULL;
02217
02218 assert(self != NULL);
02219 assert(self->proplist != NULL);
02220 assert(name != NULL);
02221 assert(keyword != NULL);
02222
02223 index = _irplib_sdp_spectrum_get_column_index(self, name);
02224 if (index != (cpl_size)-1) {
02225
02226 char *propname = cpl_sprintf("%s%"CPL_SIZE_FORMAT, keyword, index+1);
02227 if (cpl_propertylist_has(self->proplist, propname)) {
02228 result = cpl_propertylist_get_string(self->proplist, propname);
02229 }
02230 cpl_free(propname);
02231 } else {
02232 cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02233 "Could not find '%s' keyword for column '%s'.", keyword, name);
02234 }
02235 return result;
02236 }
02237
02238
02239 static cpl_error_code
02240 _irplib_sdp_spectrum_set_column_keyword(irplib_sdp_spectrum *self,
02241 const char *name,
02242 const char *value,
02243 const char *keyword,
02244 const char *comment)
02245 {
02246 cpl_size index;
02247 char *propname, *pcomment;
02248
02249 assert(self != NULL);
02250 assert(self->proplist != NULL);
02251 assert(name != NULL);
02252 assert(keyword != NULL);
02253 assert(comment != NULL);
02254
02255 index = _irplib_sdp_spectrum_get_column_index(self, name);
02256
02257 if (index == (cpl_size)-1) {
02258 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02259 "Could not find '%s' keyword for column '%s'.", keyword, name);
02260 }
02261
02262 cpl_error_code error = CPL_ERROR_NONE;
02263 propname = cpl_sprintf("%s%"CPL_SIZE_FORMAT, keyword, index+1);
02264 pcomment = cpl_sprintf("%s%"CPL_SIZE_FORMAT, comment, index+1);
02265 if (cpl_propertylist_has(self->proplist, propname)) {
02266 if (value != NULL) {
02267 error = cpl_propertylist_set_string(self->proplist, propname, value);
02268 } else {
02269 (void) cpl_propertylist_erase(self->proplist, propname);
02270 }
02271 } else if (value != NULL) {
02272 error = cpl_propertylist_append_string(self->proplist, propname, value);
02273 if (! error) {
02274 error = cpl_propertylist_set_comment(self->proplist, propname,
02275 pcomment);
02276 if (error) {
02277
02278
02279 cpl_errorstate prestate = cpl_errorstate_get();
02280 (void) cpl_propertylist_erase(self->proplist, propname);
02281 cpl_errorstate_set(prestate);
02282 }
02283 }
02284 }
02285 cpl_free(propname);
02286 cpl_free(pcomment);
02287 return error;
02288 }
02289
02290
02291 static void
02292 _irplib_sdp_spectrum_erase_column_keywords(irplib_sdp_spectrum *self,
02293 const char *name)
02294 {
02295 cpl_size index;
02296
02297 assert(self != NULL);
02298 assert(self->proplist != NULL);
02299 assert(name != NULL);
02300
02301 index = _irplib_sdp_spectrum_get_column_index(self, name);
02302 if (index != (cpl_size)-1) {
02303 char *propname = cpl_sprintf("%s%"CPL_SIZE_FORMAT, KEY_TUTYP, index+1);
02304 cpl_propertylist_erase(self->proplist, propname);
02305 cpl_free(propname);
02306 propname = cpl_sprintf("%s%"CPL_SIZE_FORMAT, KEY_TUCD, index+1);
02307 cpl_propertylist_erase(self->proplist, propname);
02308 cpl_free(propname);
02309 propname = cpl_sprintf("%s%"CPL_SIZE_FORMAT, KEY_TCOMM, index+1);
02310 cpl_propertylist_erase(self->proplist, propname);
02311 cpl_free(propname);
02312 }
02313 }
02314
02315
02316 const char *
02317 irplib_sdp_spectrum_get_column_tutyp(const irplib_sdp_spectrum *self,
02318 const char *name)
02319 {
02320 cpl_errorstate prestate = cpl_errorstate_get();
02321 const char *result;
02322 cpl_ensure(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT, NULL);
02323 result = _irplib_sdp_spectrum_get_column_keyword(self, name, KEY_TUTYP);
02324 if (! cpl_errorstate_is_equal(prestate)) {
02325 cpl_error_set_where(cpl_func);
02326 }
02327 return result;
02328 }
02329
02330
02331 cpl_error_code
02332 irplib_sdp_spectrum_set_column_tutyp(irplib_sdp_spectrum *self,
02333 const char *name, const char *tutyp)
02334 {
02335 cpl_error_code error;
02336 cpl_ensure_code(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT);
02337 error = _irplib_sdp_spectrum_set_column_keyword(self, name, tutyp,
02338 KEY_TUTYP, KEY_TUTYP_COMMENT);
02339 if (error) {
02340 cpl_error_set_where(cpl_func);
02341 }
02342 return error;
02343 }
02344
02345
02346 cpl_error_code
02347 irplib_sdp_spectrum_copy_column_tutyp(irplib_sdp_spectrum *self,
02348 const char *name,
02349 const cpl_propertylist *plist,
02350 const char *key)
02351 {
02352 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02353
02354 assert(self->table != NULL);
02355
02356 if (cpl_propertylist_has(plist, key)) {
02357 cpl_errorstate prestate = cpl_errorstate_get();
02358 const char *value = cpl_propertylist_get_string(plist, key);
02359 if (cpl_errorstate_is_equal(prestate)) {
02360 return irplib_sdp_spectrum_set_column_tutyp(self, name, value);
02361 } else {
02362 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02363 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
02364 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s'. Likely"
02365 " the source '%s' keyword is not a string.",
02366 KEY_TUTYP, index, name, key);
02367 }
02368 } else {
02369 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02370 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02371 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s' since the"
02372 " '%s' keyword was not found.", KEY_TUTYP, index, name, key);
02373 }
02374 }
02375
02376
02377 const char *
02378 irplib_sdp_spectrum_get_column_tucd(const irplib_sdp_spectrum *self,
02379 const char *name)
02380 {
02381 cpl_errorstate prestate = cpl_errorstate_get();
02382 const char *result;
02383 cpl_ensure(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT, NULL);
02384 result = _irplib_sdp_spectrum_get_column_keyword(self, name, KEY_TUCD);
02385 if (! cpl_errorstate_is_equal(prestate)) {
02386 cpl_error_set_where(cpl_func);
02387 }
02388 return result;
02389 }
02390
02391
02392 cpl_error_code
02393 irplib_sdp_spectrum_set_column_tucd(irplib_sdp_spectrum *self,
02394 const char *name, const char *tucd)
02395 {
02396 cpl_error_code error;
02397 cpl_ensure_code(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT);
02398 error = _irplib_sdp_spectrum_set_column_keyword(self, name, tucd,
02399 KEY_TUCD, KEY_TUCD_COMMENT);
02400 if (error) {
02401 cpl_error_set_where(cpl_func);
02402 }
02403 return error;
02404 }
02405
02406
02407 cpl_error_code
02408 irplib_sdp_spectrum_copy_column_tucd(irplib_sdp_spectrum *self,
02409 const char *name,
02410 const cpl_propertylist *plist,
02411 const char *key)
02412 {
02413 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02414
02415 assert(self->table != NULL);
02416
02417 if (cpl_propertylist_has(plist, key)) {
02418 cpl_errorstate prestate = cpl_errorstate_get();
02419 const char *value = cpl_propertylist_get_string(plist, key);
02420 if (cpl_errorstate_is_equal(prestate)) {
02421 return irplib_sdp_spectrum_set_column_tucd(self, name, value);
02422 } else {
02423 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02424 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
02425 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s'. Likely"
02426 " the source '%s' keyword is not a string.",
02427 KEY_TUCD, index, name, key);
02428 }
02429 } else {
02430 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02431 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02432 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s' since the"
02433 " '%s' keyword was not found.", KEY_TUCD, index, name, key);
02434 }
02435 }
02436
02437
02438 const char *
02439 irplib_sdp_spectrum_get_column_tcomm(const irplib_sdp_spectrum *self,
02440 const char *name)
02441 {
02442 cpl_errorstate prestate = cpl_errorstate_get();
02443 const char *result;
02444 cpl_ensure(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT, NULL);
02445 result = _irplib_sdp_spectrum_get_column_keyword(self, name, KEY_TCOMM);
02446 if (! cpl_errorstate_is_equal(prestate)) {
02447 cpl_error_set_where(cpl_func);
02448 }
02449 return result;
02450 }
02451
02452
02453 cpl_error_code
02454 irplib_sdp_spectrum_set_column_tcomm(irplib_sdp_spectrum *self,
02455 const char *name, const char *tcomm)
02456 {
02457 cpl_error_code error;
02458 cpl_ensure_code(self != NULL && name != NULL, CPL_ERROR_NULL_INPUT);
02459 error = _irplib_sdp_spectrum_set_column_keyword(self, name, tcomm,
02460 KEY_TCOMM, KEY_TCOMM_COMMENT);
02461 if (error) {
02462 cpl_error_set_where(cpl_func);
02463 }
02464 return error;
02465 }
02466
02467
02468 cpl_error_code
02469 irplib_sdp_spectrum_copy_column_tcomm(irplib_sdp_spectrum *self,
02470 const char *name,
02471 const cpl_propertylist *plist,
02472 const char *key)
02473 {
02474 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02475
02476 assert(self->table != NULL);
02477
02478 if (cpl_propertylist_has(plist, key)) {
02479 cpl_errorstate prestate = cpl_errorstate_get();
02480 const char *value = cpl_propertylist_get_string(plist, key);
02481 if (cpl_errorstate_is_equal(prestate)) {
02482 return irplib_sdp_spectrum_set_column_tcomm(self, name, value);
02483 } else {
02484 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02485 return cpl_error_set_message(cpl_func, cpl_error_get_code(),
02486 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s'. Likely"
02487 " the source '%s' keyword is not a string.",
02488 KEY_TCOMM, index, name, key);
02489 }
02490 } else {
02491 cpl_size index = _irplib_sdp_spectrum_get_column_index(self, name) + 1;
02492 return cpl_error_set_message(cpl_func, CPL_ERROR_DATA_NOT_FOUND,
02493 "Could not set '%s%"CPL_SIZE_FORMAT"' for column '%s' since the"
02494 " '%s' keyword was not found.", KEY_TCOMM, index, name, key);
02495 }
02496 }
02497
02498
02499 const cpl_array *
02500 irplib_sdp_spectrum_get_column_data(const irplib_sdp_spectrum *self,
02501 const char *name)
02502 {
02503 cpl_ensure(self != NULL, CPL_ERROR_NULL_INPUT, NULL);
02504 assert(self->table != NULL);
02505 return cpl_table_get_array(self->table, name, 0);
02506 }
02507
02508
02509 cpl_error_code
02510 irplib_sdp_spectrum_set_column_data(irplib_sdp_spectrum *self,
02511 const char *name, const cpl_array *array)
02512 {
02513 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02514 assert(self->table != NULL);
02515 return cpl_table_set_array(self->table, name, 0, array);
02516 }
02517
02518
02519 static char * _irplib_make_regexp(const cpl_propertylist *plist,
02520 const char *extra)
02521 {
02522
02523
02524 static const cpl_size min_chars_required = 6;
02525
02526
02527
02528 static const char *start_fragment = "^(";
02529 static const char *end_fragment = ")$";
02530 static const char *join_fragment = "|";
02531
02532 cpl_size extra_length = (extra != NULL ? (cpl_size) strlen(extra) : 0);
02533 cpl_size regexp_size, bytesleft, nkeys, i;
02534 char *writepos;
02535 char *regexp = NULL;
02536
02537 assert(plist != NULL);
02538
02539 nkeys = cpl_propertylist_get_size(plist);
02540 if (nkeys == 0) {
02541
02542 if (extra != NULL) {
02543 return cpl_sprintf("%s%s%s", start_fragment, extra, end_fragment);
02544 } else {
02545 return cpl_strdup("");
02546 }
02547 }
02548
02549
02550 regexp_size = nkeys * 80 + min_chars_required + extra_length;
02551 regexp = cpl_malloc(regexp_size);
02552
02553 bytesleft = regexp_size;
02554 writepos = regexp;
02555 for (i = 0; i < nkeys; ++i) {
02556 cpl_size name_length, fragment_length;
02557 const char *name, *fragment;
02558
02559
02560 const cpl_property *p = cpl_propertylist_get_const(plist, i);
02561 cpl_error_ensure(p != NULL, cpl_error_get_code(), goto cleanup,
02562 "Unexpected error accessing property structure %"CPL_SIZE_FORMAT".", i);
02563 name = cpl_property_get_name(p);
02564 cpl_error_ensure(name != NULL, cpl_error_get_code(), goto cleanup,
02565 "Unexpected error accessing the name of property %"CPL_SIZE_FORMAT".", i);
02566 name_length = (cpl_size) strlen(name);
02567
02568
02569 fragment = (i == 0) ? start_fragment : join_fragment;
02570 fragment_length = (cpl_size) strlen(fragment);
02571
02572 while (bytesleft <
02573 fragment_length + name_length + extra_length + min_chars_required)
02574 {
02575
02576
02577 bytesleft += regexp_size;
02578 regexp_size += regexp_size;
02579 regexp = cpl_realloc(regexp, regexp_size);
02580 writepos = regexp + (regexp_size - bytesleft);
02581 }
02582
02583
02584 strncpy(writepos, fragment, bytesleft);
02585 bytesleft -= fragment_length;
02586 writepos += fragment_length;
02587 strncpy(writepos, name, bytesleft);
02588 bytesleft -= name_length;
02589 writepos += name_length;
02590 }
02591
02592
02593 if (extra != NULL) {
02594 strncpy(writepos, join_fragment, bytesleft);
02595 bytesleft -= (cpl_size) strlen(join_fragment);
02596 writepos += (cpl_size) strlen(join_fragment);
02597 strncpy(writepos, extra, bytesleft);
02598 bytesleft -= extra_length;
02599 writepos += extra_length;
02600 }
02601 strncpy(writepos, end_fragment, bytesleft);
02602
02603 regexp[regexp_size-1] = '\0';
02604
02605 return regexp;
02606
02607 cleanup:
02608
02609 cpl_free(regexp);
02610 return NULL;
02611 }
02612
02613
02614 irplib_sdp_spectrum * irplib_sdp_spectrum_load(const char *filename)
02615 {
02616 cpl_error_code error;
02617 irplib_sdp_spectrum *obj;
02618 cpl_propertylist *plist = NULL;
02619 cpl_propertylist *tmpplist = NULL;
02620 cpl_table *table = NULL;
02621 cpl_array *names = NULL;
02622 cpl_array *emptyarray = NULL;
02623 cpl_size nelem, ext, i;
02624 char *regexp = NULL;
02625
02626 cpl_ensure(filename != NULL, CPL_ERROR_NULL_INPUT, NULL);
02627
02628
02629
02630
02631 plist = cpl_propertylist_load_regexp(filename, 0, ALL_KEYS_REGEXP, 0);
02632 cpl_error_ensure(plist != NULL, cpl_error_get_code(), goto cleanup,
02633 "Could not load property list from primary HDU when loading file '%s'.",
02634 filename);
02635
02636
02637
02638 regexp = _irplib_make_regexp(plist, NULL);
02639 cpl_error_ensure(regexp != NULL, cpl_error_get_code(), goto cleanup,
02640 "Could not create regular expression to filter keywords.");
02641
02642
02643
02644 ext = cpl_fits_find_extension(filename, KEY_EXTNAME_VALUE);
02645 cpl_error_ensure(ext != (cpl_size)-1, cpl_error_get_code(), goto cleanup,
02646 "Failed to get the extension '%s' from file '%s'.",
02647 KEY_EXTNAME_VALUE, filename);
02648 if (ext == 0) ext = 1;
02649
02650
02651 tmpplist = cpl_propertylist_load_regexp(filename, ext, ALL_KEYS_REGEXP, 0);
02652 cpl_error_ensure(tmpplist != NULL, cpl_error_get_code(), goto cleanup,
02653 "Could not load property list from extension %"
02654 CPL_SIZE_FORMAT" when loading file '%s'.", ext, filename);
02655
02656
02657 error = cpl_propertylist_copy_property_regexp(plist, tmpplist, regexp, 1);
02658 cpl_error_ensure(! error, error, goto cleanup,
02659 "Failed to append keywords from file '%s' extension %"
02660 CPL_SIZE_FORMAT".", filename, ext);
02661
02662
02663 cpl_propertylist_delete(tmpplist);
02664 tmpplist = NULL;
02665 cpl_free(regexp);
02666 regexp = NULL;
02667
02668 table = cpl_table_load(filename, (int)ext, CPL_TRUE);
02669 cpl_error_ensure(table != NULL, cpl_error_get_code(), goto cleanup,
02670 "Could not load the spectrum table from extension %"
02671 CPL_SIZE_FORMAT" when loading file '%s'.", ext, filename);
02672
02673
02674 if (cpl_propertylist_has(plist, KEY_NELEM)) {
02675 cpl_errorstate prestate = cpl_errorstate_get();
02676 nelem = (cpl_size) cpl_propertylist_get_long_long(plist, KEY_NELEM);
02677
02678 cpl_propertylist_erase(plist, KEY_NELEM);
02679 cpl_error_ensure(cpl_errorstate_is_equal(prestate), cpl_error_get_code(),
02680 goto cleanup, "Could not process the temporary '%s' keyword.",
02681 KEY_NELEM);
02682 } else {
02683 cpl_msg_warning(cpl_func,
02684 "Keyword '%s' not found in file '%s'. Possibly corrupted."
02685 " Will try find correct value from the table and continue.",
02686 KEY_NELEM, filename);
02687 nelem = 0;
02688 if (cpl_table_get_nrow(table) > 0) {
02689 names = cpl_table_get_column_names(table);
02690 if (names != NULL) {
02691 if (cpl_array_get_size(names) > 0) {
02692 const char *name = cpl_array_get_string(names, 0);
02693 nelem = cpl_table_get_column_depth(table, name);
02694 }
02695 cpl_array_delete(names);
02696 names = NULL;
02697 }
02698 }
02699 }
02700
02701 names = cpl_table_get_column_names(table);
02702 cpl_error_ensure(names != NULL, cpl_error_get_code(), goto cleanup,
02703 "Could not get table column names when loading file '%s'.", filename);
02704 for (i = 0; i < cpl_array_get_size(names); ++i) {
02705 int j;
02706 const char *name = cpl_array_get_string(names, 0);
02707 cpl_type type = cpl_table_get_column_type(table, name);
02708 if ((type & CPL_TYPE_POINTER) == 0) continue;
02709 for (j = 0; j < cpl_table_get_nrow(table); ++j) {
02710 if (cpl_table_get_array(table, name, j) != NULL) continue;
02711 emptyarray = cpl_array_new(nelem, type & (~CPL_TYPE_POINTER));
02712 cpl_error_ensure(emptyarray != NULL, cpl_error_get_code(), goto cleanup,
02713 "Could not create empty array when spectrum table from file '%s'.",
02714 filename);
02715 error = cpl_table_set_array(table, name, j, emptyarray);
02716 cpl_array_delete(emptyarray);
02717 emptyarray = NULL;
02718 }
02719 }
02720 cpl_array_delete(names);
02721
02722
02723 obj = cpl_malloc(sizeof(irplib_sdp_spectrum));
02724 obj->nelem = nelem;
02725 obj->proplist = plist;
02726 obj->table = table;
02727 return obj;
02728
02729 cleanup:
02730
02731
02732
02733 cpl_propertylist_delete(plist);
02734 cpl_propertylist_delete(tmpplist);
02735 cpl_table_delete(table);
02736 cpl_array_delete(names);
02737 cpl_array_delete(emptyarray);
02738 cpl_free(regexp);
02739 return NULL;
02740 }
02741
02742
02743 cpl_error_code irplib_sdp_spectrum_save(const irplib_sdp_spectrum *self,
02744 const char *filename,
02745 const cpl_propertylist *extra_pheader,
02746 const cpl_propertylist *extra_theader)
02747 {
02748 cpl_error_code error;
02749 cpl_propertylist *primarykeys = NULL;
02750 cpl_propertylist *tablekeys = NULL;
02751 char *regexp = NULL;
02752
02753 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
02754
02755 assert(self->proplist != NULL);
02756 assert(self->table != NULL);
02757
02758
02759
02760 regexp = _irplib_make_regexp(self->proplist, KEY_NELEM);
02761 cpl_error_ensure(regexp != NULL, cpl_error_get_code(), goto cleanup,
02762 "Could not create regular expression to filter keywords.");
02763
02764
02765
02766 primarykeys = cpl_propertylist_new();
02767 error = cpl_propertylist_copy_property_regexp(primarykeys, self->proplist,
02768 PRIMARY_HDU_KEYS_REGEXP, 0);
02769 cpl_error_ensure(! error, error, goto cleanup,
02770 "Failed to extract keywords for primary HDU.");
02771
02772
02773
02774 if (cpl_propertylist_has(primarykeys, KEY_OBJECT)) {
02775 error = cpl_propertylist_set_comment(primarykeys, KEY_OBJECT,
02776 KEY_OBJECT_PHDU_COMMENT);
02777 cpl_error_ensure(! error, error, goto cleanup,
02778 "Could not update comment for '%s' in primary HDU.", KEY_OBJECT);
02779 }
02780
02781
02782 if (extra_pheader != NULL) {
02783 error = cpl_propertylist_copy_property_regexp(primarykeys, extra_pheader,
02784 regexp, 1);
02785 cpl_error_ensure(! error, error, goto cleanup,
02786 "Could not add extra keywords for primary HDU.");
02787 }
02788
02789
02790 tablekeys = cpl_propertylist_new();
02791 error = cpl_propertylist_copy_property_regexp(tablekeys, self->proplist,
02792 EXTENSION_HDU_KEYS_REGEXP, 0);
02793 cpl_error_ensure(! error, error, goto cleanup,
02794 "Failed to extract keywords for extension HDU.");
02795
02796
02797 cpl_error_ensure(self->nelem <= INT_MAX, CPL_ERROR_INCOMPATIBLE_INPUT,
02798 goto cleanup,
02799 "The value for the keyword '%s' is too big (> %d).",
02800 KEY_NELEM, INT_MAX);
02801 error = cpl_propertylist_append_int(tablekeys, KEY_NELEM,
02802 (int) self->nelem);
02803 error |= cpl_propertylist_set_comment(tablekeys, KEY_NELEM,
02804 KEY_NELEM_COMMENT);
02805 cpl_error_ensure(! error, error, goto cleanup,
02806 "Could not add keyword '%s' to primary HDU or set the comment.",
02807 KEY_NELEM);
02808
02809
02810 if (extra_theader != NULL) {
02811 error = cpl_propertylist_copy_property_regexp(tablekeys, extra_theader,
02812 regexp, 1);
02813 cpl_error_ensure(! error, error, goto cleanup,
02814 "Could not add extra keywords for extension HDU.");
02815 }
02816
02817 cpl_free(regexp);
02818 regexp = NULL;
02819
02820
02821
02822
02823 error = CPL_ERROR_NONE;
02824 if (! cpl_propertylist_has(primarykeys, KEY_ORIGIN)) {
02825 error |= cpl_propertylist_append_string(primarykeys, KEY_ORIGIN,
02826 KEY_ORIGIN_VALUE);
02827 error |= cpl_propertylist_set_comment(primarykeys, KEY_ORIGIN,
02828 KEY_ORIGIN_COMMENT);
02829 }
02830 if (! cpl_propertylist_has(primarykeys, KEY_PRODLVL)) {
02831 error |= cpl_propertylist_append_int(primarykeys, KEY_PRODLVL,
02832 KEY_PRODLVL_VALUE);
02833 error |= cpl_propertylist_set_comment(primarykeys, KEY_PRODLVL,
02834 KEY_PRODLVL_COMMENT);
02835 }
02836 if (! cpl_propertylist_has(primarykeys, KEY_SPECSYS)) {
02837 error |= cpl_propertylist_append_string(primarykeys, KEY_SPECSYS,
02838 KEY_SPECSYS_VALUE);
02839 error |= cpl_propertylist_set_comment(primarykeys, KEY_SPECSYS,
02840 KEY_SPECSYS_COMMENT);
02841 }
02842 if (! cpl_propertylist_has(primarykeys, KEY_FLUXERR)) {
02843 error |= cpl_propertylist_append_int(primarykeys, KEY_FLUXERR,
02844 KEY_FLUXERR_VALUE);
02845 error |= cpl_propertylist_set_comment(primarykeys, KEY_FLUXERR,
02846 KEY_FLUXERR_COMMENT);
02847 }
02848 if (! cpl_propertylist_has(tablekeys, KEY_VOCLASS)) {
02849 error |= cpl_propertylist_append_string(tablekeys, KEY_VOCLASS,
02850 KEY_VOCLASS_VALUE);
02851 error |= cpl_propertylist_set_comment(tablekeys, KEY_VOCLASS,
02852 KEY_VOCLASS_COMMENT);
02853 }
02854 if (! cpl_propertylist_has(tablekeys, KEY_VOPUB)) {
02855 error |= cpl_propertylist_append_string(tablekeys, KEY_VOPUB,
02856 KEY_VOPUB_VALUE);
02857 error |= cpl_propertylist_set_comment(tablekeys, KEY_VOPUB,
02858 KEY_VOPUB_COMMENT);
02859 }
02860 if (! cpl_propertylist_has(tablekeys, KEY_EXTNAME)) {
02861 error |= cpl_propertylist_append_string(tablekeys, KEY_EXTNAME,
02862 KEY_EXTNAME_VALUE);
02863 error |= cpl_propertylist_set_comment(tablekeys, KEY_EXTNAME,
02864 KEY_EXTNAME_COMMENT);
02865 }
02866 if (! cpl_propertylist_has(tablekeys, KEY_INHERIT)) {
02867 error |= cpl_propertylist_append_bool(tablekeys, KEY_INHERIT,
02868 KEY_INHERIT_VALUE);
02869 error |= cpl_propertylist_set_comment(tablekeys, KEY_INHERIT,
02870 KEY_INHERIT_COMMENT);
02871 }
02872 cpl_error_ensure(! error, cpl_error_get_code(), goto cleanup,
02873 "Could not set default header keywords for file '%s'.",
02874 filename);
02875
02876 error = cpl_table_save(self->table, primarykeys, tablekeys, filename,
02877 CPL_IO_CREATE);
02878 cpl_error_ensure(! error, error, goto cleanup,
02879 "Could not save the spectrum table to file '%s'.", filename);
02880
02881 cpl_propertylist_delete(primarykeys);
02882 cpl_propertylist_delete(tablekeys);
02883
02884 return CPL_ERROR_NONE;
02885
02886 cleanup:
02887
02888
02889 cpl_propertylist_delete(primarykeys);
02890 cpl_propertylist_delete(tablekeys);
02891 cpl_free(regexp);
02892 return cpl_error_get_code();
02893 }
02894
02895
02896 cpl_error_code irplib_dfs_save_spectrum(cpl_frameset * allframes,
02897 cpl_propertylist * header,
02898 const cpl_parameterlist * parlist,
02899 const cpl_frameset * usedframes,
02900 const cpl_frame * inherit,
02901 const irplib_sdp_spectrum * spectrum,
02902 const char * recipe,
02903 const cpl_propertylist * applist,
02904 const cpl_propertylist * tablelist,
02905 const char * remregexp,
02906 const char * pipe_id,
02907 const char * dict_id,
02908 const char * filename)
02909 {
02910 const char * procat;
02911 cpl_propertylist * plist = NULL;
02912 cpl_frame * product_frame = NULL;
02913 cpl_error_code error;
02914
02915 cpl_ensure_code(allframes != NULL, CPL_ERROR_NULL_INPUT);
02916 cpl_ensure_code(parlist != NULL, CPL_ERROR_NULL_INPUT);
02917 cpl_ensure_code(usedframes != NULL, CPL_ERROR_NULL_INPUT);
02918 cpl_ensure_code(spectrum != NULL, CPL_ERROR_NULL_INPUT);
02919 cpl_ensure_code(recipe != NULL, CPL_ERROR_NULL_INPUT);
02920 cpl_ensure_code(applist != NULL, CPL_ERROR_NULL_INPUT);
02921 cpl_ensure_code(pipe_id != NULL, CPL_ERROR_NULL_INPUT);
02922 cpl_ensure_code(dict_id != NULL, CPL_ERROR_NULL_INPUT);
02923 cpl_ensure_code(filename != NULL, CPL_ERROR_NULL_INPUT);
02924
02925 procat = cpl_propertylist_get_string(applist, CPL_DFS_PRO_CATG);
02926 cpl_error_ensure(procat != NULL, cpl_error_get_code(), goto cleanup,
02927 "Could not find keyword '%s' in 'applist'.", CPL_DFS_PRO_CATG);
02928
02929
02930 product_frame = cpl_frame_new();
02931 error = cpl_frame_set_filename(product_frame, filename);
02932 error |= cpl_frame_set_tag(product_frame, procat);
02933 error |= cpl_frame_set_type(product_frame, CPL_FRAME_TYPE_TABLE);
02934 error |= cpl_frame_set_group(product_frame, CPL_FRAME_GROUP_PRODUCT);
02935 error |= cpl_frame_set_level(product_frame, CPL_FRAME_LEVEL_FINAL);
02936 cpl_error_ensure(! error, cpl_error_get_code(), goto cleanup,
02937 "Failed to setup the product frame.");
02938
02939
02940
02941 if (header != NULL) {
02942 cpl_propertylist_empty(header);
02943 plist = header;
02944 } else {
02945 plist = cpl_propertylist_new();
02946 }
02947
02948
02949 error = cpl_propertylist_append(plist, applist);
02950 cpl_error_ensure(! error, error, goto cleanup,
02951 "Could not append extra keywords when writing file '%s'.", filename);
02952
02953
02954 error = cpl_dfs_setup_product_header(plist, product_frame, usedframes,
02955 parlist, recipe, pipe_id, dict_id,
02956 inherit);
02957 cpl_error_ensure(! error, error, goto cleanup,
02958 "Failed to setup DFS keywords when writing file '%s'.", filename);
02959
02960
02961
02962
02963
02964
02965
02966 error = cpl_propertylist_copy_property_regexp(plist, applist, ".*", 0);
02967 cpl_error_ensure(! error, error, goto cleanup,
02968 "Could not update extra keywords when writing file '%s'.", filename);
02969
02970 if (remregexp != NULL) {
02971 cpl_errorstate prestate = cpl_errorstate_get();
02972 (void) cpl_propertylist_erase_regexp(plist, remregexp, 0);
02973 cpl_error_ensure(cpl_errorstate_is_equal(prestate), cpl_error_get_code(),
02974 goto cleanup,
02975 "Failed to filter keywords when writing file '%s'.",
02976 filename);
02977 }
02978
02979 error = irplib_sdp_spectrum_save(spectrum, filename, plist, tablelist);
02980 cpl_error_ensure(! error, error, goto cleanup,
02981 "Failed to save SPD spectrum to file '%s'.", filename);
02982
02983
02984 if (header != NULL) {
02985 error = cpl_propertylist_copy_property_regexp(header, spectrum->proplist,
02986 ".*", 0);
02987 cpl_error_ensure(! error, error, goto cleanup,
02988 "Could not return SDP keywords in header output.");
02989 }
02990
02991
02992 error = cpl_frameset_insert(allframes, product_frame);
02993 cpl_error_ensure(! error, error, goto cleanup,
02994 "Failed to insert new product frame when writing file '%s'.", filename);
02995
02996
02997 if (plist != header) cpl_propertylist_delete(plist);
02998
02999 return CPL_ERROR_NONE;
03000
03001 cleanup:
03002
03003
03004 if (header != NULL) {
03005 cpl_errorstate prestate = cpl_errorstate_get();
03006 (void) cpl_propertylist_empty(header);
03007 cpl_errorstate_set(prestate);
03008 } else {
03009 cpl_propertylist_delete(plist);
03010 }
03011 cpl_frame_delete(product_frame);
03012 return cpl_error_get_code();
03013 }
03014
03015
03016 void irplib_sdp_spectrum_dump(const irplib_sdp_spectrum *self, FILE *stream)
03017 {
03018 if (stream == NULL) {
03019 stream = stdout;
03020 }
03021 if (self == NULL) {
03022 fprintf(stream, "NULL SDP spectrum\n\n");
03023 return;
03024 }
03025
03026 assert(self->proplist != NULL);
03027 assert(self->table != NULL);
03028
03029 fprintf(stream, "SDP spectrum at address %p\n", (void*)self);
03030 fprintf(stream, "NELEM = %"CPL_SIZE_FORMAT"\n", self->nelem);
03031 cpl_propertylist_dump(self->proplist, stream);
03032 cpl_table_dump_structure(self->table, stream);
03033 cpl_table_dump(self->table, 0, cpl_table_get_nrow(self->table), stream);
03034 }
03035
03036
03037 #ifdef IRPLIB_USE_FITS_UPDATE_CHECKSUM
03038
03050 cpl_error_code irplib_fits_update_checksums(const char* filename)
03051 {
03052 fitsfile* filehandle;
03053 int error = 0;
03054
03055 if (fits_open_diskfile(&filehandle, filename, READWRITE, &error)) {
03056 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
03057 "Could not open file '%s' to update CHECKSUM keywords"
03058 " (error = %d).", filename, error);
03059 }
03060
03061 int i = 0;
03062 while (! fits_movabs_hdu(filehandle, ++i, NULL, &error)) {
03063 if (fits_write_chksum(filehandle, &error)) {
03064 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
03065 "Could not update the CHECKSUM keywords in '%s' HDU %d"
03066 " (error = %d).", filename, i, error);
03067 }
03068 }
03069
03070 if (error == END_OF_FILE) error = 0;
03071
03072 if (fits_close_file(filehandle, &error)) {
03073 return cpl_error_set_message(cpl_func, CPL_ERROR_FILE_IO,
03074 "There was a problem trying to close the file '%s'"
03075 " (error = %d).", filename, error);
03076 }
03077 return CPL_ERROR_NONE;
03078 }
03079
03080 #endif