Line data Source code
1 : /** \file fitsHeaderCard.hpp
2 : * \brief A class to work with a FITS header card
3 : * \ingroup fits_processing_files
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : */
7 :
8 : //***********************************************************************//
9 : // Copyright 2015-2025 Jared R. Males (jaredmales@gmail.com)
10 : //
11 : // This file is part of mxlib.
12 : //
13 : // mxlib is free software: you can redistribute it and/or modify
14 : // it under the terms of the GNU General Public License as published by
15 : // the Free Software Foundation, either version 3 of the License, or
16 : // (at your option) any later version.
17 : //
18 : // mxlib is distributed in the hope that it will be useful,
19 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : // GNU General Public License for more details.
22 : //
23 : // You should have received a copy of the GNU General Public License
24 : // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 : //***********************************************************************//
26 :
27 : #ifndef ioutils_fits_fitsHeaderCard_hpp
28 : #define ioutils_fits_fitsHeaderCard_hpp
29 :
30 : #include <format>
31 :
32 : #include "../../mxlib.hpp"
33 :
34 : #include "../../meta/tagT.hpp"
35 : #include "fitsUtils.hpp"
36 :
37 : namespace mx
38 : {
39 : namespace fits
40 : {
41 :
42 : /// \cond
43 : // strip leading and trailing whitespace and then opening and closing ''. leaves spaces between ''.
44 181 : inline void stripApostWS( std::string &str )
45 : {
46 181 : if( str.size() == 0 )
47 : {
48 14 : return;
49 : }
50 :
51 167 : if( str[0] != '\'' && str[0] != ' ' && str.back() != ' ' ) // get out fast if we can
52 : {
53 146 : return;
54 : }
55 :
56 : // strip white space at front
57 21 : size_t ns = str.find_first_not_of( " \t\r\n" );
58 21 : if( ns != std::string::npos && ns != 0 )
59 : {
60 2 : str.erase( 0, ns );
61 : }
62 19 : else if( ns == std::string::npos ) // the rare all spaces
63 : {
64 1 : str = "";
65 1 : return;
66 : }
67 :
68 : // strip white space at back
69 20 : ns = str.find_last_not_of( " \t\r\n" );
70 20 : if( ns != std::string::npos && ns != str.size() - 1 )
71 : {
72 7 : str.erase( ns + 1 );
73 : }
74 :
75 20 : if( str[0] == '\'' && str.back() == '\'' )
76 : {
77 18 : if( str.size() == 1 || str.size() == 2 )
78 : {
79 2 : str = "";
80 2 : return;
81 : }
82 16 : str.erase( str.size() - 1, 1 );
83 16 : str.erase( 0, 1 );
84 : }
85 : }
86 : /// \endcond
87 :
88 : /// Class to manage the three components of a FITS header card
89 : /** Since FITS does not provide the type in keyword=value pairs in a FITS header, it is up to the user
90 : * to determine the type. Furthermore, since we want to read values from files, type conversions must
91 : * be done at runtime. The result is that we must be able to accept a string, which is converted
92 : * to a given type on demand as determined at runtime.
93 : *
94 : * Conversion from string to native type, or vice versa, only occurs when needed. So if you set the value to,
95 : * say, a double, the value is not converted to string format unless specifically requested. If the write function is
96 : * called when in this state, the cfitsio routine is called directly. This conversion only on demand is most important
97 : * for values read from a file, then written to another file. In this case, no conversion to its double (etc)
98 : * representation occurs.
99 : *
100 : * Note that because of the checks to determine the type and appropriate return values, accessing the value in a card
101 : * is possibly slower than accessing a variable due to various if statements and error checking.
102 : * This means that you should typically do
103 : * so once and use a local variable for repeated use.
104 : *
105 : * \ingroup fits_processing
106 : */
107 : template <class verboseT = verbose::d>
108 : class fitsHeaderCard
109 : {
110 :
111 : protected:
112 : /// The keyword
113 : std::string m_keyword;
114 :
115 : /// The FITS type of the value, and indicates which member of m_values to access.
116 : int m_type{ fitsType<fitsUnknownType>() };
117 :
118 : /// The native type is held in a union.
119 : union values
120 : {
121 : bool Bool; ///< the bool value
122 : char Char; ///< the char value
123 : unsigned char UChar; ///< the unsigned char value
124 : short Short; ///< the short value
125 : unsigned short UShort; ///< the unsigned short value
126 : int Int; ///< the int value
127 : unsigned int UInt; ///< the unsigned int value
128 : long Long; ///< the long value
129 : unsigned long ULong; ///< the unsigned long value
130 : long long LongLong; ///< the long long value
131 : unsigned long long ULongLong; ///< the unsigned long long value
132 : float Float; ///< the float value
133 : std::complex<float> complexFloat; ///< the std::complex<float> value
134 : double Double; ///< the double value
135 : std::complex<double> complexDouble; ///< the std::complex<double> value
136 : long double LongDouble; ///< the long double value
137 : std::complex<long double> complexLongDouble; ///< the std::complex<long double> value
138 :
139 : // clang-format off
140 : #ifdef HAS_QUAD
141 : __float128 Quad; ///< the float128 value
142 : std::complex<__float128> complexQuad; ///< the std::complex<__float128> value
143 : #endif
144 : // clang-format on
145 :
146 : /// c'tor. have to specify due to inclusion of std::complex types.
147 791 : values()
148 : {
149 791 : return;
150 : }
151 :
152 3 : bool &member( meta::tagT<bool> )
153 : {
154 3 : return Bool;
155 : }
156 :
157 11 : char &member( meta::tagT<char> )
158 : {
159 11 : return Char;
160 : }
161 :
162 7 : unsigned char &member( meta::tagT<unsigned char> )
163 : {
164 7 : return UChar;
165 : }
166 :
167 7 : short &member( meta::tagT<short> )
168 : {
169 7 : return Short;
170 : }
171 :
172 7 : unsigned short &member( meta::tagT<unsigned short> )
173 : {
174 7 : return UShort;
175 : }
176 :
177 166 : int &member( meta::tagT<int> )
178 : {
179 166 : return Int;
180 : }
181 :
182 7 : unsigned int &member( meta::tagT<unsigned int> )
183 : {
184 7 : return UInt;
185 : }
186 :
187 7 : long &member( meta::tagT<long> )
188 : {
189 7 : return Long;
190 : }
191 :
192 7 : unsigned long &member( meta::tagT<unsigned long> )
193 : {
194 7 : return ULong;
195 : }
196 :
197 7 : long long &member( meta::tagT<long long> )
198 : {
199 7 : return LongLong;
200 : }
201 :
202 9 : unsigned long long &member( meta::tagT<unsigned long long> )
203 : {
204 9 : return ULongLong;
205 : }
206 :
207 84 : float &member( meta::tagT<float> )
208 : {
209 84 : return Float;
210 : }
211 :
212 2 : std::complex<float> &member( meta::tagT<std::complex<float>> )
213 : {
214 2 : return complexFloat;
215 : }
216 :
217 25 : double &member( meta::tagT<double> )
218 : {
219 25 : return Double;
220 : }
221 :
222 1 : std::complex<double> &member( meta::tagT<std::complex<double>> )
223 : {
224 1 : return complexDouble;
225 : }
226 :
227 1 : long double &member( meta::tagT<long double> )
228 : {
229 1 : return LongDouble;
230 : }
231 :
232 1 : std::complex<long double> &member( meta::tagT<std::complex<long double>> )
233 : {
234 1 : return complexLongDouble;
235 : }
236 :
237 : // clang-format off
238 : #ifdef HAS_QUAD
239 1 : __float128 &member( meta::tagT<__float128> )
240 : {
241 1 : return Quad;
242 : }
243 :
244 1 : std::complex<__float128> &member( meta::tagT<std::complex<__float128>> )
245 : {
246 1 : return complexQuad;
247 : }
248 : #endif
249 : // clang-format on
250 :
251 : template <typename typeT>
252 354 : typeT &member()
253 : {
254 354 : return member( meta::tagT<typeT>() );
255 : }
256 :
257 : } m_value;
258 :
259 : /// The value in string form
260 : std::stringstream m_valueStr;
261 :
262 : bool m_valueGood{ false }; ///< Flag indicating if the value is valid
263 : bool m_valueStrGood{ false }; ///< Flag indicating if the value string is valid
264 :
265 : /// The comment
266 : std::string m_comment;
267 :
268 : public:
269 : /// \name Constructors
270 : /**
271 : */
272 : //@{
273 :
274 : /// Basic c'tor
275 : fitsHeaderCard();
276 :
277 : /// Construct from the three components for a value of string type
278 : /**
279 : */
280 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
281 : const std::string &v, ///< [in] the value string
282 : const std::string &c = "" ///< [in] the comment
283 : );
284 :
285 : /// Construct from the three components for a value of string type
286 : /** Have to provide overload for char * to avoid template version
287 : */
288 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
289 : char *v, ///< [in] the value string
290 : const std::string &c = "" ///< [in] the comment
291 : );
292 :
293 : /// Construct from the three components for a value of string type
294 : /** Have to provide overload for const char * to avoid template version
295 : */
296 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
297 : const char *v, ///< [in] the value string
298 : const std::string &c = "" ///< [in] the comment
299 : );
300 :
301 : /// Construct from the three components, when already in a string format
302 : /** Use this when the value is not a string
303 : */
304 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
305 : const std::string &v, ///< [in] the value string
306 : const int &type, ///< [in] the type of the value
307 45 : const std::string &c = "" ///< [in] the comment
308 : );
309 :
310 : /// Construct from the three components, when it's really a comment card
311 : /** This overload is provided to facilitate handling of comments when re-writing the file.
312 : *
313 : */
314 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
315 : fitsCommentType v, ///< [in] an object of type fitsCommentType
316 : const std::string &c ///< [in] the comment
317 : );
318 :
319 : /// Construct from the three components, when it's really a history card
320 : /** This overload is provided to facilitate handling of history when re-writing the file.
321 : *
322 : */
323 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
324 : fitsHistoryType v, ///< [in] an object of type fitsHistoryType
325 : const std::string &c ///< [in] the comment
326 : );
327 :
328 : /// Construct from just keyword, when value's type is unknown
329 : /**
330 : */
331 : explicit fitsHeaderCard( const std::string &k /**< [in] the keyword*/ );
332 :
333 : /// Construct from just keyword, when value's type known
334 : /**
335 : */
336 : fitsHeaderCard( const std::string &k, ///< [in] the keyword
337 : const int type ///< [in] the type
338 : );
339 :
340 : /// Construct from the three components for a char.
341 : /**
342 : */
343 : template <typename typeT>
344 : fitsHeaderCard( const std::string &k, ///< [in] they keyword
345 : const typeT v, ///< [in] the value
346 : const std::string &c = "" ///< [in] the comment
347 : );
348 :
349 : /// Copy constructor
350 : fitsHeaderCard( const fitsHeaderCard &card );
351 :
352 : //@}
353 :
354 : /// Assignment
355 : fitsHeaderCard &operator=( const fitsHeaderCard &card );
356 :
357 : protected:
358 : ///\name Converters
359 : /** @{
360 : */
361 :
362 : /// Convert from the type to a string.
363 : /** This populates m_valueStr and sets m_valueStrGood so that this conversion
364 : * only occurs once.
365 : */
366 : mx::error_t convertToString();
367 :
368 : /// Convert from string to the type
369 : /** This populates the appropriate union field and sets m_valueGood so that
370 : * this conversion only occurs once.
371 : */
372 : template <typename typeT>
373 : error_t convertFromString();
374 :
375 : /// Get the value from its type converted to a different type.
376 : template <typename typeT>
377 : error_t convertedValue( typeT &cval /**< [out] the converted value */ );
378 :
379 : /// Convert the value from its type to a different type.
380 : error_t convertValue( int newtype /**< [in] the new type */ );
381 :
382 : ///@}
383 :
384 : public:
385 : ///\name Accessors
386 : /** @{
387 : */
388 :
389 : /// Get the keyword
390 : /**
391 : * \returns a const reference to m_keyword
392 : */
393 : const std::string &keyword() const;
394 :
395 : /// Set the keyword
396 : /**
397 : * \returns error_t::noerror on success
398 : */
399 : error_t keyword( const std::string &kw /**< [in] the new keyword */ );
400 :
401 : /// Get the type
402 : /**
403 : * \returns the value of m_type
404 : */
405 : int type() const;
406 :
407 : /// Set the type
408 : /** If this is a change in type and the native type is set in m_value (indicated by m_valueGood == true)
409 : * then it is converted to the new type. Otherwise, no conversion occurs.
410 : *
411 : * \returns error_t::noerror on success
412 : */
413 : error_t type( const int &t /**< [in] the new type */ );
414 :
415 : protected:
416 : /** \name tag dispatching for getting value
417 : * @{
418 : */
419 :
420 : /// Get value for anything not a string
421 : template <typename typeT>
422 : typeT valueNonString( mx::error_t &errc );
423 :
424 : /// Get value tag dispatcher for std::string
425 : /**
426 : */
427 : std::string value( meta::tagT<std::string>, mx::error_t &errc );
428 :
429 : /// Get value tag dispatcher for char
430 : /** Calls valueNonString
431 : */
432 : char value( meta::tagT<char>, mx::error_t &errc );
433 :
434 : /// Get value tag dispatcher for unsigned char
435 : /** Calls valueNonString
436 : */
437 : unsigned char value( meta::tagT<unsigned char>, mx::error_t &errc );
438 :
439 : /// Get value tag dispatcher for short
440 : /** Calls valueNonString
441 : */
442 : short value( meta::tagT<short>, mx::error_t &errc );
443 :
444 : /// Get value tag dispatcher for unsigned short
445 : /** Calls valueNonString
446 : */
447 : unsigned short value( meta::tagT<unsigned short>, mx::error_t &errc );
448 :
449 : /// Get value tag dispatcher for int
450 : /** Calls valueNonString
451 : */
452 : int value( meta::tagT<int>, mx::error_t &errc );
453 :
454 : /// Get value tag dispatcher for unsigned int
455 : /** Calls valueNonString
456 : */
457 : unsigned int value( meta::tagT<unsigned int>, mx::error_t &errc );
458 :
459 : /// Get value tag dispatcher for long
460 : /** Calls valueNonString
461 : */
462 : long value( meta::tagT<long>, mx::error_t &errc );
463 :
464 : /// Get value tag dispatcher for unsigned long
465 : /** Calls valueNonString
466 : */
467 : unsigned long value( meta::tagT<unsigned long>, mx::error_t &errc );
468 :
469 : /// Get value tag dispatcher for long long
470 : /** Calls valueNonString
471 : */
472 : long long value( meta::tagT<long long>, mx::error_t &errc );
473 :
474 : /// Get value tag dispatcher for unsigned long long
475 : /** Calls valueNonString
476 : */
477 : unsigned long long value( meta::tagT<unsigned long long>, mx::error_t &errc );
478 :
479 : /// Get value tag dispatcher for float
480 : /** Calls valueNonString
481 : */
482 : float value( meta::tagT<float>, mx::error_t &errc );
483 :
484 : /// Get value tag dispatcher for double
485 : /** Calls valueNonString
486 : */
487 : double value( meta::tagT<double>, mx::error_t &errc );
488 :
489 : ///@}
490 :
491 : public:
492 : /// Get the value
493 : /** Returns the value as typeT. Conversions occur
494 : * automatically if necessary.
495 : *
496 : * \returns the value converted to typeT as necessary
497 : *
498 : * \b Errors
499 : * - mx::error_t::noerror on success
500 : * - other errors possible due to conversions
501 : *
502 : */
503 : template <typename typeT>
504 : typeT value( mx::error_t *errc = nullptr /**< [in] [optional] error code */ );
505 :
506 : /// Get the value as a string
507 : /** This calls value<string>().
508 : *
509 : * \returns the value converted to string as necessary
510 : *
511 : */
512 : std::string String( error_t *errc = nullptr /**< [in] [optional] error code */ );
513 :
514 : /// Get the value as a char
515 : /** This calls value<char>().
516 : *
517 : * \returns the value converted to char as necessary
518 : *
519 : */
520 : char Char( error_t *errc = nullptr /**< [in] [optional] error code */ );
521 :
522 : /// Get the value as an unsigned char
523 : /** This calls value<unsigned char>().
524 : *
525 : * \returns the value converted to unsigned char as necessary
526 : *
527 : */
528 : unsigned char UChar( error_t *errc = nullptr /**< [in] [optional] error code */ );
529 :
530 : /// Get the value as a short
531 : /** This calls value<short>().
532 : *
533 : * \returns the value converted to short as necessary
534 : *
535 : */
536 : short Short( error_t *errc = nullptr /**< [in] [optional] error code */ );
537 :
538 : /// Get the value as an unsigned short
539 : /** This calls value<unsigned short>().
540 : *
541 : * \returns the value converted to unsigned short as necessary
542 : *
543 : */
544 : unsigned short UShort( error_t *errc = nullptr /**< [in] [optional] error code */ );
545 :
546 : /// Get the value as a int
547 : /** This calls value<int>().
548 : *
549 : * \returns the value converted to int as necessary
550 : *
551 : */
552 : int Int( error_t *errc = nullptr /**< [in] [optional] error code */ );
553 :
554 : /// Get the value as an unsigned int
555 : /** This calls value<unsigned int>().
556 : *
557 : * \returns the value converted to unsigned int as necessary
558 : *
559 : */
560 : unsigned int UInt( error_t *errc = nullptr /**< [in] [optional] error code */ );
561 :
562 : /// Get the value as a long
563 : /** This calls value<long>().
564 : *
565 : * \returns the value converted to long as necessary
566 : *
567 : */
568 : long Long( error_t *errc = nullptr /**< [in] [optional] error code */ );
569 :
570 : /// Get the value as an unsigned long
571 : /** This calls value<unsigned long>().
572 : *
573 : * \returns the value converted to unsigned long as necessary
574 : *
575 : */
576 : unsigned long ULong( error_t *errc = nullptr /**< [in] [optional] error code */ );
577 :
578 : /// Get the value as a long long
579 : /** This calls value<long long>().
580 : *
581 : * \returns the value converted to long long as necessary
582 : *
583 : */
584 : long long LongLong( error_t *errc = nullptr /**< [in] [optional] error code */ );
585 :
586 : /// Get the value as an unsigned long long
587 : /** This calls value<unsigned long long>().
588 : *
589 : * \returns the value converted to unsigned long long as necessaryvalue(
590 : *
591 : */
592 : unsigned long long ULongLong( error_t *errc = nullptr /**< [in] [optional] error code */ );
593 :
594 : /// Get the value as a float
595 : /** This calls value<float>().
596 : *
597 : * \returns the value converted to float as necessary
598 : *
599 : */
600 : float Float( error_t *errc = nullptr /**< [in] [optional] error code */ );
601 :
602 : /// Get the value as a std::complex<float>
603 : /** This calls value<std::complex<float>>().
604 : *
605 : * \returns the value converted to std::complex<float> as necessary
606 : *
607 : */
608 : std::complex<float> complexFloat( error_t *errc = nullptr /**< [in] [optional] error code */ );
609 :
610 : /// Get the value as a double
611 : /** This calls value<double>().
612 : *
613 : * \returns the value converted to double as necessary
614 : *
615 : */
616 : double Double( error_t *errc = nullptr /**< [in] [optional] error code */ );
617 :
618 : /// Get the value as a std::complex<double>
619 : /** This calls value<std::complex<double>>().
620 : *
621 : * \returns the value converted to std::complex<double> as necessary
622 : *
623 : */
624 : std::complex<double> complexDouble( error_t *errc = nullptr /**< [in] [optional] error code */ );
625 :
626 : /// Set the value to a char * string
627 : error_t value( const char *v /**< [in] a character string*/ );
628 :
629 : /// Set the value to a std::string
630 : /**
631 : */
632 : error_t value( const std::string &v /**< [in] a std::string*/ );
633 :
634 : /// Set the value for a non-string type
635 : template <typename typeT>
636 : mx::error_t value( const typeT &v /**< [in] the value to set */ );
637 :
638 : /// Get the current value string
639 : /**
640 : * \returns m_valueStr;
641 : */
642 : std::string valueStr();
643 :
644 : /// Get the current value good flag
645 : /**
646 : * \returns m_valueGood;
647 : */
648 : bool valueGood();
649 :
650 : /// Get the current value string good flag
651 : /**
652 : * \returns m_valueStrGood;
653 : */
654 : bool valueStrGood();
655 :
656 : /// Get the comment
657 : /** \returns the value of m_comment
658 : */
659 : const std::string &comment();
660 :
661 : /// Set the comment
662 : /**
663 : * \returns error_t::noerror on success
664 : */
665 : error_t comment( const std::string &c /**< [in] the new comment */ );
666 :
667 : //@}
668 :
669 : error_t appendContinue( const fitsHeaderCard &card );
670 :
671 : ///\name Output
672 : /**
673 : */
674 : //@{
675 :
676 : /// Writes this card to a FITS file using \ref mx::fits::fits_write_key "fits_write_key".
677 : /**
678 : */
679 : mx::error_t write( fitsfile *fptr );
680 :
681 : //@}
682 :
683 : }; // fitsHeaderCard
684 :
685 : template <class verboseT>
686 119 : fitsHeaderCard<verboseT>::fitsHeaderCard()
687 : {
688 119 : }
689 :
690 : template <class verboseT>
691 1 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const std::string &v, const std::string &c )
692 : {
693 1 : m_keyword = k;
694 :
695 1 : std::string str = v;
696 1 : stripApostWS( str );
697 1 : m_valueStr.str( str );
698 1 : m_valueGood = false;
699 1 : m_valueStrGood = true;
700 1 : m_type = fitsType<std::string>();
701 1 : m_comment = c;
702 1 : }
703 :
704 : template <class verboseT>
705 1 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, char *v, const std::string &c )
706 : {
707 1 : m_keyword = k;
708 1 : std::string str = v;
709 1 : stripApostWS( str );
710 1 : m_valueStr.str( str );
711 1 : m_valueGood = false;
712 1 : m_valueStrGood = true;
713 1 : m_type = fitsType<std::string>();
714 1 : m_comment = c;
715 1 : }
716 :
717 : template <class verboseT>
718 111 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const char *v, const std::string &c )
719 : {
720 111 : m_keyword = k;
721 111 : std::string str = v;
722 111 : stripApostWS( str );
723 111 : m_valueStr.str( str );
724 111 : m_valueGood = false;
725 111 : m_valueStrGood = true;
726 111 : m_type = fitsType<std::string>();
727 111 : m_comment = c;
728 111 : }
729 :
730 : template <class verboseT>
731 18 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k,
732 : const std::string &v,
733 : const int &type,
734 18 : const std::string &c )
735 : {
736 18 : m_keyword = k;
737 18 : std::string str = v;
738 18 : stripApostWS( str );
739 18 : m_valueStr.str( str );
740 18 : m_valueGood = false;
741 18 : m_valueStrGood = true;
742 18 : m_type = type;
743 18 : m_comment = c;
744 18 : }
745 :
746 : template <class verboseT>
747 32 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, fitsCommentType v, const std::string &c )
748 : {
749 32 : m_keyword = k;
750 32 : m_valueGood = false;
751 32 : m_valueStrGood = false;
752 32 : m_type = fitsType<fitsCommentType>();
753 32 : m_comment = c;
754 32 : }
755 :
756 : template <class verboseT>
757 11 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, fitsHistoryType v, const std::string &c )
758 : {
759 11 : m_keyword = k;
760 11 : m_valueGood = false;
761 11 : m_valueStrGood = false;
762 11 : m_type = fitsType<fitsHistoryType>();
763 11 : m_comment = c;
764 11 : }
765 :
766 : template <class verboseT>
767 31 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k )
768 : {
769 31 : m_keyword = k;
770 31 : }
771 :
772 : template <class verboseT>
773 1 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const int type )
774 : {
775 1 : m_keyword = k;
776 1 : m_type = type;
777 1 : }
778 :
779 : template <class verboseT>
780 : template <typename typeT>
781 180 : fitsHeaderCard<verboseT>::fitsHeaderCard( const std::string &k, const typeT v, const std::string &c )
782 : {
783 180 : m_keyword = k;
784 180 : value( v );
785 180 : m_comment = c;
786 180 : }
787 :
788 : template <class verboseT>
789 286 : fitsHeaderCard<verboseT>::fitsHeaderCard( const fitsHeaderCard &card )
790 : {
791 286 : m_keyword = card.m_keyword;
792 286 : m_type = card.m_type;
793 286 : memcpy( &m_value, &card.m_value, sizeof( values ) );
794 286 : m_valueStr.str( card.m_valueStr.str() );
795 286 : m_valueGood = card.m_valueGood;
796 286 : m_valueStrGood = card.m_valueStrGood;
797 286 : m_comment = card.m_comment;
798 286 : }
799 :
800 : template <class verboseT>
801 3 : fitsHeaderCard<verboseT> &fitsHeaderCard<verboseT>::operator=( const fitsHeaderCard &card )
802 : {
803 3 : if( this == &card )
804 : {
805 1 : return *this;
806 : }
807 :
808 2 : m_keyword = card.m_keyword;
809 2 : m_type = card.m_type;
810 2 : memcpy( &m_value, &card.m_value, sizeof( values ) );
811 2 : m_valueStr.str( card.m_valueStr.str() );
812 2 : m_valueGood = card.m_valueGood;
813 2 : m_valueStrGood = card.m_valueStrGood;
814 2 : m_comment = card.m_comment;
815 :
816 2 : return *this;
817 : }
818 :
819 : template <class verboseT>
820 24 : mx::error_t fitsHeaderCard<verboseT>::convertToString()
821 : {
822 24 : if( !m_valueGood )
823 : {
824 1 : return mx::error_t::paramnotset;
825 : }
826 :
827 23 : if( m_type == fitsType<char *>() || m_type == fitsType<std::string>() )
828 : {
829 1 : m_valueStrGood = true; // It should be hard to get here, but just in case.
830 1 : return mx::error_t::noerror;
831 : }
832 :
833 44 : m_valueStr.str( "" );
834 22 : m_valueStr.precision( 10 );
835 :
836 22 : switch( m_type )
837 : {
838 2 : case fitsType<char>():
839 2 : m_valueStr << static_cast<int>( m_value.Char );
840 2 : break;
841 1 : case fitsType<unsigned char>():
842 1 : m_valueStr << static_cast<int>( m_value.UChar );
843 1 : break;
844 1 : case fitsType<short>():
845 1 : m_valueStr << m_value.Short;
846 1 : break;
847 1 : case fitsType<unsigned short>():
848 1 : m_valueStr << m_value.UShort;
849 1 : break;
850 4 : case fitsType<int>():
851 4 : m_valueStr << m_value.Int;
852 4 : break;
853 1 : case fitsType<unsigned int>():
854 1 : m_valueStr << m_value.UInt;
855 1 : break;
856 1 : case fitsType<long>():
857 1 : m_valueStr << m_value.Long;
858 1 : break;
859 1 : case fitsType<unsigned long>():
860 1 : m_valueStr << m_value.ULong;
861 1 : break;
862 1 : case fitsType<long long>():
863 1 : m_valueStr << m_value.LongLong;
864 1 : break;
865 1 : case fitsType<unsigned long long>():
866 1 : m_valueStr << m_value.ULongLong;
867 1 : break;
868 1 : case fitsType<float>():
869 1 : m_valueStr << m_value.Float;
870 1 : break;
871 1 : case fitsType<std::complex<float>>():
872 1 : m_valueStr << m_value.complexFloat;
873 1 : break;
874 1 : case fitsType<double>():
875 1 : m_valueStr << m_value.Double;
876 1 : break;
877 1 : case fitsType<std::complex<double>>():
878 1 : m_valueStr << m_value.complexDouble;
879 1 : break;
880 1 : case fitsType<fitsCommentType>():
881 1 : return mx::error_t::noerror;
882 1 : case fitsType<fitsHistoryType>():
883 1 : return mx::error_t::noerror;
884 1 : case fitsType<fitsContinueType>():
885 1 : return mx::error_t::noerror;
886 1 : default:
887 1 : return internal::mxlib_error_report<verboseT>( mx::error_t::invalidarg,
888 2 : "Unknown FITS type for " + m_keyword );
889 : }
890 :
891 18 : m_valueStrGood = true;
892 18 : return mx::error_t::noerror;
893 : }
894 :
895 : template <class verboseT>
896 : template <typename typeT>
897 52 : error_t fitsHeaderCard<verboseT>::convertFromString()
898 : {
899 52 : m_type = fitsType<typeT>();
900 :
901 : error_t errc;
902 :
903 52 : m_value.template member<typeT>() = ioutils::stoT<typeT>( m_valueStr.str(), &errc );
904 :
905 52 : if( errc != mx::error_t::noerror )
906 : {
907 5 : m_valueGood = false;
908 5 : return errc;
909 : }
910 :
911 47 : m_valueGood = true;
912 :
913 47 : return error_t::noerror;
914 : }
915 :
916 : template <class verboseT>
917 : template <typename typeT>
918 36 : error_t fitsHeaderCard<verboseT>::convertedValue( typeT &cval )
919 : {
920 36 : switch( m_type )
921 : {
922 2 : case fitsType<unsigned char>():
923 : {
924 2 : cval = m_value.UChar;
925 2 : return error_t::noerror;
926 : }
927 6 : case fitsType<char>():
928 : {
929 6 : cval = m_value.Char;
930 6 : return error_t::noerror;
931 : }
932 2 : case fitsType<short>():
933 : {
934 2 : cval = m_value.Short;
935 2 : return error_t::noerror;
936 : }
937 2 : case fitsType<unsigned short>():
938 : {
939 2 : cval = m_value.UShort;
940 2 : return error_t::noerror;
941 : }
942 3 : case fitsType<int>():
943 : {
944 3 : cval = m_value.Int;
945 3 : return error_t::noerror;
946 : }
947 2 : case fitsType<unsigned int>():
948 : {
949 2 : cval = m_value.UInt;
950 2 : return error_t::noerror;
951 : }
952 2 : case fitsType<long>():
953 : {
954 2 : cval = m_value.Long;
955 2 : return error_t::noerror;
956 : }
957 2 : case fitsType<unsigned long>():
958 : {
959 2 : cval = m_value.ULong;
960 2 : return error_t::noerror;
961 : }
962 2 : case fitsType<long long>():
963 : {
964 2 : cval = m_value.LongLong;
965 2 : return error_t::noerror;
966 : }
967 2 : case fitsType<unsigned long long>():
968 : {
969 2 : cval = m_value.ULongLong;
970 2 : return error_t::noerror;
971 : }
972 2 : case fitsType<float>():
973 : {
974 2 : cval = m_value.Float;
975 2 : return error_t::noerror;
976 : }
977 2 : case fitsType<std::complex<float>>():
978 : {
979 2 : return internal::mxlib_error_report<verboseT>( error_t::notimpl,
980 4 : "can't convert complex type for " + m_keyword );
981 : }
982 1 : case fitsType<double>():
983 : {
984 1 : cval = m_value.Double;
985 1 : return error_t::noerror;
986 : }
987 1 : case fitsType<std::complex<double>>():
988 : {
989 1 : return internal::mxlib_error_report<verboseT>( error_t::notimpl,
990 2 : "can't convert complex type for " + m_keyword );
991 : }
992 1 : case fitsType<fitsCommentType>():
993 : {
994 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
995 2 : "cannot convert comment to numeric type for " + m_keyword );
996 : }
997 1 : case fitsType<fitsHistoryType>():
998 : {
999 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1000 2 : "cannot convert history to numeric type for " + m_keyword );
1001 : }
1002 1 : case fitsType<fitsContinueType>():
1003 : {
1004 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1005 2 : "cannot convert continue to numeric type for " + m_keyword );
1006 : }
1007 1 : case TSTRING:
1008 : {
1009 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1010 2 : "cannot convert string to numeric type for " + m_keyword );
1011 : }
1012 1 : default:
1013 : {
1014 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1015 2 : "invalid FITS type conversion for " + m_keyword );
1016 : }
1017 : }
1018 : }
1019 :
1020 : template <class verboseT>
1021 22 : error_t fitsHeaderCard<verboseT>::convertValue( int newtype )
1022 : {
1023 : mx::error_t errc;
1024 22 : switch( newtype )
1025 : {
1026 1 : case fitsType<unsigned char>():
1027 : {
1028 1 : errc = convertedValue<unsigned char>( m_value.UChar );
1029 1 : break;
1030 : }
1031 1 : case fitsType<char>():
1032 : {
1033 1 : errc = convertedValue<char>( m_value.Char );
1034 1 : break;
1035 : }
1036 1 : case fitsType<short>():
1037 : {
1038 1 : errc = convertedValue<short>( m_value.Short );
1039 1 : break;
1040 : }
1041 1 : case fitsType<unsigned short>():
1042 : {
1043 1 : errc = convertedValue<unsigned short>( m_value.UShort );
1044 1 : break;
1045 : }
1046 4 : case fitsType<int>():
1047 : {
1048 4 : errc = convertedValue<int>( m_value.Int );
1049 4 : break;
1050 : }
1051 1 : case fitsType<unsigned int>():
1052 : {
1053 1 : errc = convertedValue<unsigned int>( m_value.UInt );
1054 1 : break;
1055 : }
1056 1 : case fitsType<long>():
1057 : {
1058 1 : errc = convertedValue<long>( m_value.Long );
1059 1 : break;
1060 : }
1061 1 : case fitsType<unsigned long>():
1062 : {
1063 1 : errc = convertedValue<unsigned long>( m_value.ULong );
1064 1 : break;
1065 : }
1066 1 : case fitsType<long long>():
1067 : {
1068 1 : errc = convertedValue<long long>( m_value.LongLong );
1069 1 : break;
1070 : }
1071 1 : case fitsType<unsigned long long>():
1072 : {
1073 1 : errc = convertedValue<unsigned long long>( m_value.ULongLong );
1074 1 : break;
1075 : }
1076 1 : case fitsType<float>():
1077 : {
1078 1 : errc = convertedValue<float>( m_value.Float );
1079 1 : break;
1080 : }
1081 1 : case fitsType<std::complex<float>>():
1082 : {
1083 1 : return internal::mxlib_error_report<verboseT>( error_t::notimpl,
1084 2 : "can't convert complex type for " + m_keyword );
1085 : }
1086 1 : case fitsType<double>():
1087 : {
1088 1 : errc = convertedValue<double>( m_value.Double );
1089 1 : break;
1090 : }
1091 1 : case fitsType<std::complex<double>>():
1092 : {
1093 1 : return internal::mxlib_error_report<verboseT>( error_t::notimpl,
1094 2 : "can't convert complex type for " + m_keyword );
1095 : }
1096 1 : case fitsType<fitsCommentType>():
1097 : {
1098 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1099 2 : "cannot convert comment to numeric type for " + m_keyword );
1100 : }
1101 1 : case fitsType<fitsHistoryType>():
1102 : {
1103 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1104 2 : "cannot convert history to numeric type for " + m_keyword );
1105 : }
1106 1 : case fitsType<fitsContinueType>():
1107 : {
1108 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1109 2 : "cannot convert continue to numeric type for " + m_keyword );
1110 : }
1111 1 : case TSTRING:
1112 : {
1113 1 : convertToString();
1114 1 : m_type = newtype;
1115 1 : m_valueGood = false;
1116 1 : return error_t::noerror;
1117 : }
1118 1 : default:
1119 : {
1120 1 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg,
1121 2 : "invalid FITS type conversion for " + m_keyword );
1122 : }
1123 : }
1124 :
1125 15 : if( !!errc )
1126 : {
1127 1 : return errc;
1128 : }
1129 :
1130 14 : m_type = newtype;
1131 14 : m_valueGood = true;
1132 :
1133 14 : return error_t::noerror;
1134 : }
1135 :
1136 : template <class verboseT>
1137 1229 : const std::string &fitsHeaderCard<verboseT>::keyword() const
1138 : {
1139 1229 : return m_keyword;
1140 : }
1141 :
1142 : template <class verboseT>
1143 5 : error_t fitsHeaderCard<verboseT>::keyword( const std::string &kw )
1144 : {
1145 5 : m_keyword = kw;
1146 5 : return error_t::noerror;
1147 : }
1148 :
1149 : template <class verboseT>
1150 63 : int fitsHeaderCard<verboseT>::type() const
1151 : {
1152 63 : return m_type;
1153 : }
1154 :
1155 : template <class verboseT>
1156 25 : error_t fitsHeaderCard<verboseT>::type( const int &t )
1157 : {
1158 25 : if( t == m_type )
1159 : {
1160 1 : return error_t::noerror;
1161 : }
1162 :
1163 24 : if( m_valueGood )
1164 : {
1165 22 : error_t errc = convertValue( t );
1166 22 : if( errc != error_t::noerror )
1167 : {
1168 7 : return errc;
1169 : }
1170 : }
1171 : else
1172 : {
1173 2 : m_type = t;
1174 : }
1175 :
1176 : // Need to reconvert, always favor the actual value.
1177 17 : if( m_valueGood && m_valueStrGood )
1178 : {
1179 2 : m_valueStrGood = false;
1180 : }
1181 :
1182 17 : return error_t::noerror;
1183 : }
1184 :
1185 : template <class verboseT>
1186 : template <typename typeT>
1187 127 : typeT fitsHeaderCard<verboseT>::valueNonString( mx::error_t &errc )
1188 : {
1189 127 : errc = mx::error_t::noerror; // to be changed if needed
1190 :
1191 127 : if( m_valueGood == false )
1192 : {
1193 52 : errc = convertFromString<typeT>();
1194 52 : if( errc != error_t::noerror )
1195 : {
1196 5 : return typeT{};
1197 : }
1198 : }
1199 :
1200 122 : if( m_type != fitsType<typeT>() )
1201 : {
1202 21 : typeT val{};
1203 21 : errc = convertedValue<typeT>( val );
1204 21 : return val;
1205 : }
1206 :
1207 101 : return m_value.template member<typeT>();
1208 : }
1209 :
1210 : template <class verboseT>
1211 39 : std::string fitsHeaderCard<verboseT>::value( meta::tagT<std::string>, mx::error_t &errc )
1212 : {
1213 39 : errc = mx::error_t::noerror;
1214 :
1215 39 : if( m_valueStrGood == false )
1216 : {
1217 6 : errc = convertToString();
1218 6 : if( !!errc )
1219 : {
1220 4 : return "";
1221 : }
1222 : }
1223 :
1224 : // Strip ' from beginning and end if present
1225 37 : std::string str = m_valueStr.str();
1226 :
1227 : // Reload it so it's there for next time:
1228 37 : m_valueStr.str( str );
1229 :
1230 37 : return str;
1231 37 : }
1232 :
1233 : template <class verboseT>
1234 5 : char fitsHeaderCard<verboseT>::value( meta::tagT<char>, mx::error_t &errc )
1235 : {
1236 5 : return valueNonString<char>( errc );
1237 : }
1238 :
1239 : template <class verboseT>
1240 3 : unsigned char fitsHeaderCard<verboseT>::value( meta::tagT<unsigned char>, mx::error_t &errc )
1241 : {
1242 3 : return valueNonString<unsigned char>( errc );
1243 : }
1244 :
1245 : template <class verboseT>
1246 3 : short fitsHeaderCard<verboseT>::value( meta::tagT<short>, mx::error_t &errc )
1247 : {
1248 3 : return valueNonString<short>( errc );
1249 : }
1250 :
1251 : template <class verboseT>
1252 3 : unsigned short fitsHeaderCard<verboseT>::value( meta::tagT<unsigned short>, mx::error_t &errc )
1253 : {
1254 3 : return valueNonString<unsigned short>( errc );
1255 : }
1256 :
1257 : template <class verboseT>
1258 43 : int fitsHeaderCard<verboseT>::value( meta::tagT<int>, mx::error_t &errc )
1259 : {
1260 43 : return valueNonString<int>( errc );
1261 : }
1262 :
1263 : template <class verboseT>
1264 3 : unsigned int fitsHeaderCard<verboseT>::value( meta::tagT<unsigned int>, mx::error_t &errc )
1265 : {
1266 3 : return valueNonString<unsigned int>( errc );
1267 : }
1268 :
1269 : template <class verboseT>
1270 3 : long fitsHeaderCard<verboseT>::value( meta::tagT<long>, mx::error_t &errc )
1271 : {
1272 3 : return valueNonString<long>( errc );
1273 : }
1274 :
1275 : template <class verboseT>
1276 3 : unsigned long fitsHeaderCard<verboseT>::value( meta::tagT<unsigned long>, mx::error_t &errc )
1277 : {
1278 3 : return valueNonString<unsigned long>( errc );
1279 : }
1280 :
1281 : template <class verboseT>
1282 3 : long long fitsHeaderCard<verboseT>::value( meta::tagT<long long>, mx::error_t &errc )
1283 : {
1284 3 : return valueNonString<long long>( errc );
1285 : }
1286 :
1287 : template <class verboseT>
1288 5 : unsigned long long fitsHeaderCard<verboseT>::value( meta::tagT<unsigned long long>, mx::error_t &errc )
1289 : {
1290 5 : return valueNonString<unsigned long long>( errc );
1291 : }
1292 :
1293 : template <class verboseT>
1294 31 : float fitsHeaderCard<verboseT>::value( meta::tagT<float>, mx::error_t &errc )
1295 : {
1296 31 : return valueNonString<float>( errc );
1297 : }
1298 :
1299 : template <class verboseT>
1300 22 : double fitsHeaderCard<verboseT>::value( meta::tagT<double>, mx::error_t &errc )
1301 : {
1302 22 : return valueNonString<double>( errc );
1303 : }
1304 :
1305 : template <class verboseT>
1306 : template <typename typeT>
1307 166 : typeT fitsHeaderCard<verboseT>::value( mx::error_t *errc )
1308 : {
1309 : mx::error_t _errc;
1310 :
1311 166 : typeT val = value( meta::tagT<typeT>(), _errc );
1312 :
1313 166 : if( errc )
1314 : {
1315 38 : *errc = _errc;
1316 : }
1317 :
1318 166 : if( _errc != mx::error_t::noerror )
1319 : {
1320 14 : internal::mxlib_error_report<verboseT>( _errc, "getting value for " + m_keyword );
1321 : }
1322 :
1323 166 : return val;
1324 : } // LCOV_EXCL_LINE
1325 :
1326 : template <class verboseT>
1327 39 : std::string fitsHeaderCard<verboseT>::String( error_t *errc )
1328 : {
1329 39 : return value<std::string>( errc );
1330 : }
1331 :
1332 : template <class verboseT>
1333 3 : char fitsHeaderCard<verboseT>::Char( error_t *errc )
1334 : {
1335 3 : return value<char>( errc );
1336 : }
1337 :
1338 : template <class verboseT>
1339 3 : unsigned char fitsHeaderCard<verboseT>::UChar( error_t *errc )
1340 : {
1341 3 : return value<unsigned char>( errc );
1342 : }
1343 :
1344 : template <class verboseT>
1345 3 : short fitsHeaderCard<verboseT>::Short( error_t *errc )
1346 : {
1347 3 : return value<short>( errc );
1348 : }
1349 :
1350 : template <class verboseT>
1351 3 : unsigned short fitsHeaderCard<verboseT>::UShort( error_t *errc )
1352 : {
1353 3 : return value<unsigned short>( errc );
1354 : }
1355 :
1356 : template <class verboseT>
1357 29 : int fitsHeaderCard<verboseT>::Int( error_t *errc )
1358 : {
1359 29 : return value<int>( errc );
1360 : }
1361 :
1362 : template <class verboseT>
1363 3 : unsigned int fitsHeaderCard<verboseT>::UInt( error_t *errc )
1364 : {
1365 3 : return value<unsigned int>( errc );
1366 : }
1367 :
1368 : template <class verboseT>
1369 3 : long fitsHeaderCard<verboseT>::Long( error_t *errc )
1370 : {
1371 3 : return value<long>( errc );
1372 : }
1373 :
1374 : template <class verboseT>
1375 3 : unsigned long fitsHeaderCard<verboseT>::ULong( error_t *errc )
1376 : {
1377 3 : return value<unsigned long>( errc );
1378 : }
1379 :
1380 : template <class verboseT>
1381 3 : long long fitsHeaderCard<verboseT>::LongLong( error_t *errc )
1382 : {
1383 3 : return value<long long>( errc );
1384 : }
1385 :
1386 : template <class verboseT>
1387 5 : unsigned long long fitsHeaderCard<verboseT>::ULongLong( error_t *errc )
1388 : {
1389 5 : return value<unsigned long long>( errc );
1390 : }
1391 :
1392 : template <class verboseT>
1393 18 : float fitsHeaderCard<verboseT>::Float( error_t *errc )
1394 : {
1395 18 : return value<float>( errc );
1396 : }
1397 :
1398 : /*template <class verboseT>
1399 : std::complex<float> fitsHeaderCard<verboseT>::complexFloat()
1400 : {
1401 : return value<std::complex<float>>();
1402 : }*/
1403 :
1404 : template <class verboseT>
1405 15 : double fitsHeaderCard<verboseT>::Double( error_t *errc )
1406 : {
1407 15 : return value<double>( errc );
1408 : }
1409 :
1410 : /*
1411 : template <class verboseT>
1412 : std::complex<double> fitsHeaderCard<verboseT>::complexDouble()
1413 : {
1414 : return value<std::complex<double>>();
1415 : }*/
1416 :
1417 : template <class verboseT>
1418 46 : mx::error_t fitsHeaderCard<verboseT>::value( const char *v )
1419 : {
1420 46 : std::string str = v;
1421 :
1422 92 : return value( str );
1423 46 : }
1424 :
1425 : template <class verboseT>
1426 46 : mx::error_t fitsHeaderCard<verboseT>::value( const std::string &v )
1427 : {
1428 : // Strip ' from beginning and end if present
1429 46 : std::string str = v;
1430 :
1431 46 : stripApostWS( str );
1432 :
1433 : // Reload it so it's there for next time:
1434 46 : m_valueStr.str( str );
1435 46 : m_valueGood = false;
1436 46 : m_valueStrGood = true;
1437 46 : m_type = fitsType<std::string>();
1438 :
1439 46 : return mx::error_t::noerror;
1440 46 : }
1441 :
1442 : template <class verboseT>
1443 : template <typename typeT>
1444 201 : mx::error_t fitsHeaderCard<verboseT>::value( const typeT &v )
1445 : {
1446 201 : m_type = fitsType<typeT>();
1447 201 : m_value.template member<typeT>() = v;
1448 201 : m_valueGood = true;
1449 201 : m_valueStrGood = false;
1450 :
1451 201 : return mx::error_t::noerror;
1452 : }
1453 :
1454 : template <class verboseT>
1455 18 : std::string fitsHeaderCard<verboseT>::valueStr()
1456 : {
1457 18 : if( !m_valueStrGood )
1458 : {
1459 17 : convertToString();
1460 : }
1461 :
1462 18 : std::string s = m_valueStr.str();
1463 18 : return s;
1464 : }
1465 :
1466 : template <class verboseT>
1467 24 : bool fitsHeaderCard<verboseT>::valueGood()
1468 : {
1469 24 : return m_valueGood;
1470 : }
1471 :
1472 : template <class verboseT>
1473 12 : bool fitsHeaderCard<verboseT>::valueStrGood()
1474 : {
1475 12 : return m_valueStrGood;
1476 : }
1477 :
1478 : template <class verboseT>
1479 26 : const std::string &fitsHeaderCard<verboseT>::comment()
1480 : {
1481 26 : return m_comment;
1482 : }
1483 :
1484 : template <class verboseT>
1485 43 : error_t fitsHeaderCard<verboseT>::comment( const std::string &c )
1486 : {
1487 43 : m_comment = c;
1488 43 : return error_t::noerror;
1489 : }
1490 :
1491 : template <class verboseT>
1492 6 : error_t fitsHeaderCard<verboseT>::appendContinue( const fitsHeaderCard<verboseT> &card )
1493 : {
1494 : // Check if m_type is string
1495 6 : if( m_type != fitsType<char *>() && m_type != fitsType<std::string>() )
1496 : {
1497 3 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "attempt to continue a non-string card" );
1498 : }
1499 :
1500 : // Check if m_valueStrGood is true
1501 5 : if( !m_valueStrGood )
1502 : {
1503 2 : return internal::mxlib_error_report<verboseT>( error_t::invalidconfig,
1504 3 : "attempt to continue a card with no value" );
1505 : }
1506 :
1507 4 : std::string newstr = card.m_comment;
1508 :
1509 : // Check if this is the last one
1510 4 : size_t slash = newstr.find_last_of( '\'' );
1511 4 : if( slash != std::string::npos )
1512 : {
1513 4 : slash = newstr.find_first_of( '/', slash );
1514 :
1515 4 : if( slash != std::string::npos )
1516 : {
1517 : // extract comment
1518 4 : size_t comm = newstr.find_first_not_of( ' ', slash + 1 );
1519 4 : if( comm != std::string::npos )
1520 : {
1521 4 : m_comment = newstr.substr( comm );
1522 : }
1523 :
1524 : // and then erase it
1525 4 : newstr.erase( slash );
1526 : }
1527 : }
1528 4 : stripApostWS( newstr );
1529 :
1530 : // have to remove & if needed
1531 4 : std::string vstr = m_valueStr.str();
1532 4 : if( !vstr.empty() && vstr.back() == '&' )
1533 : {
1534 4 : vstr.erase( vstr.size() - 1 );
1535 : }
1536 :
1537 4 : m_valueStr.str( vstr + newstr );
1538 :
1539 4 : return error_t::noerror;
1540 4 : }
1541 :
1542 : template <class verboseT>
1543 87 : mx::error_t fitsHeaderCard<verboseT>::write( fitsfile *fptr )
1544 : {
1545 87 : if( m_type == fitsType<char *>() || m_type == fitsType<std::string>() )
1546 : {
1547 1 : return fits_write_key<char *>( fptr,
1548 1 : (char *)m_keyword.c_str(),
1549 2 : (void *)m_valueStr.str().c_str(),
1550 2 : (char *)m_comment.c_str() );
1551 : }
1552 :
1553 : // If the string is good, meaning already converted.
1554 86 : if( m_valueStrGood == true )
1555 : {
1556 : // This populates the card directly.
1557 1 : return fits_write_key<fitsUnknownType>( fptr,
1558 1 : (char *)m_keyword.c_str(),
1559 2 : (void *)m_valueStr.str().c_str(),
1560 2 : (char *)m_comment.c_str() );
1561 : }
1562 :
1563 : // Ok, now we write the type directly using fitsio routines because it hasn't been converted.
1564 85 : switch( m_type )
1565 : {
1566 4 : case fitsType<bool>():
1567 : {
1568 4 : return fits_write_key<bool>( fptr, (char *)m_keyword.c_str(), &m_value.Bool, (char *)m_comment.c_str() );
1569 : }
1570 1 : case fitsType<char>():
1571 : {
1572 1 : return fits_write_key<char>( fptr, (char *)m_keyword.c_str(), &m_value.Char, (char *)m_comment.c_str() );
1573 : }
1574 1 : case fitsType<unsigned char>():
1575 : {
1576 1 : return fits_write_key<unsigned char>( fptr,
1577 1 : (char *)m_keyword.c_str(),
1578 1 : &m_value.UChar,
1579 2 : (char *)m_comment.c_str() );
1580 : }
1581 1 : case fitsType<short>():
1582 : {
1583 1 : return fits_write_key<short>( fptr, (char *)m_keyword.c_str(), &m_value.Short, (char *)m_comment.c_str() );
1584 : }
1585 1 : case fitsType<unsigned short>():
1586 : {
1587 1 : return fits_write_key<unsigned short>( fptr,
1588 1 : (char *)m_keyword.c_str(),
1589 1 : &m_value.UShort,
1590 2 : (char *)m_comment.c_str() );
1591 : }
1592 35 : case fitsType<int>():
1593 : {
1594 35 : return fits_write_key<int>( fptr, (char *)m_keyword.c_str(), &m_value.Int, (char *)m_comment.c_str() );
1595 : }
1596 1 : case fitsType<unsigned int>():
1597 : {
1598 1 : return fits_write_key<unsigned int>( fptr,
1599 1 : (char *)m_keyword.c_str(),
1600 1 : &m_value.UInt,
1601 2 : (char *)m_comment.c_str() );
1602 : }
1603 1 : case fitsType<long>():
1604 : {
1605 1 : return fits_write_key<long>( fptr, (char *)m_keyword.c_str(), &m_value.Long, (char *)m_comment.c_str() );
1606 : }
1607 1 : case fitsType<unsigned long>():
1608 : {
1609 1 : return fits_write_key<unsigned long>( fptr,
1610 1 : (char *)m_keyword.c_str(),
1611 1 : &m_value.ULong,
1612 2 : (char *)m_comment.c_str() );
1613 : }
1614 1 : case fitsType<long long>():
1615 : {
1616 1 : return fits_write_key<long long>( fptr,
1617 1 : (char *)m_keyword.c_str(),
1618 1 : &m_value.LongLong,
1619 2 : (char *)m_comment.c_str() );
1620 : }
1621 1 : case fitsType<unsigned long long>():
1622 : {
1623 1 : return fits_write_key<unsigned long long>( fptr,
1624 1 : (char *)m_keyword.c_str(),
1625 1 : &m_value.ULongLong,
1626 2 : (char *)m_comment.c_str() );
1627 : }
1628 25 : case fitsType<float>():
1629 : {
1630 25 : return fits_write_key<float>( fptr, (char *)m_keyword.c_str(), &m_value.Float, (char *)m_comment.c_str() );
1631 : }
1632 1 : case fitsType<double>():
1633 : {
1634 1 : return fits_write_key<double>( fptr,
1635 1 : (char *)m_keyword.c_str(),
1636 1 : &m_value.Double,
1637 2 : (char *)m_comment.c_str() );
1638 : }
1639 4 : case fitsType<fitsCommentType>():
1640 : {
1641 4 : return fits_write_comment( fptr, (char *)m_comment.c_str() );
1642 : }
1643 4 : case fitsType<fitsHistoryType>():
1644 : {
1645 4 : return fits_write_history( fptr, (char *)m_comment.c_str() );
1646 : }
1647 3 : default:
1648 : {
1649 3 : return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "invalid FITS type for " + m_keyword );
1650 : }
1651 : }
1652 : }
1653 :
1654 : extern template class fitsHeaderCard<verbose::d>;
1655 :
1656 : } // namespace fits
1657 : } // namespace mx
1658 :
1659 : #endif // ioutils_fits_fitsHeaderCard_hpp
|