LCOV - code coverage report
Current view: top level - ioutils/fits - fitsHeaderCard.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 90.0 % 20 18
Test Date: 2026-02-19 16:58:26 Functions: 100.0 % 4 4

            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
        

Generated by: LCOV version 2.0-1