LCOV - code coverage report
Current view: top level - include/ioutils/fits - fitsHeaderCard.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 563 563
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 80 80

            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
        

Generated by: LCOV version 2.0-1