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