casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
fits.h
Go to the documentation of this file.
00001 //# fits.h:
00002 //# Copyright (C) 1993,1994,1995,1996,1997,1999,2000,2001,2003,2004
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //# 
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //# 
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //# 
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //# 
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id: fits.h 20493 2009-01-16 10:51:43Z gervandiepen $
00027 
00028 # if !defined(AIPS_FITS)
00029 # define AIPS_FITS
00030 
00031 //# Note that aips.h has to come first for the correct definition of off_t.
00032 # include <casa/aips.h>
00033 # include <stdlib.h>
00034 # include <ctype.h>
00035 # include <casa/iostream.h>
00036 # include <casa/BasicSL/Complex.h>
00037 # include <casa/BasicSL/IComplex.h>
00038 # include <fits/FITS/FITSError.h>
00039 
00040 namespace casa { //# NAMESPACE CASA - BEGIN
00041 
00042 //# All FITS code seems to assume longs are 4 bytes. To take care of machines 
00043 //# for which this isn't true use FitsLong instead of Long in the FITS code
00044 //# where it matters.
00045 # if (defined(__alpha) || defined(__sgi) || defined(__x86_64__))
00046     typedef Int FitsLong;
00047 # else
00048     typedef Long FitsLong;
00049 # endif 
00050 // recovered by GYL
00051 
00052 class ReservedFitsKeywordCollection; // Forward declarations
00053 class FitsNameResult;
00054 class FitsValueResult;
00055 class FitsKeyword;
00056 class FitsParse;
00057 
00058 //<summary> FITS templated helper class </summary>
00059 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00060 // </reviewed>
00061 //<synopsis>
00062 // NoConvert is a template class that is not intended for
00063 // general use, it is used internally.
00064 //</synopsis>
00065 
00066 template <class TYPE>
00067 class NoConvert {
00068     public:
00069         NoConvert() { }
00070         void operator = (int) {; }
00071 };
00072 
00073 //<summary> FITS helper class </summary>
00074 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00075 // </reviewed>
00076 //<synopsis>
00077 // FitsLogical is a helper class that is not intended for
00078 // general use. 
00079 //</synopsis>
00080 //<example>
00081 // Here is an example of the FitsLogical class. 
00082 //<srcblock>
00083 //      FitsLogical x;
00084 //      FitsLogical y(True);
00085 //      FitsLogical z = x;
00086 //      ...
00087 //      x = y; y = False; x.undefine();
00088 //      Bool b;
00089 //      if (x.isdefined())
00090 //              b = x;
00091 //      b = y;  If y is undefined, b will be false.
00092 //</srcblock>
00093 //</example>
00094 class FitsLogical {
00095         friend ostream & operator << (ostream &o, const FitsLogical &);
00096     public:
00097         FitsLogical() : v('\0') { }
00098         FitsLogical(Bool x) { v = (x == True ? 'T' : 'F'); }
00099         FitsLogical(const FitsLogical &x) : v(x.v) { }
00100         FitsLogical & operator = (const FitsLogical &x) { 
00101                 v = x.v; return *this; }
00102         FitsLogical & operator = (Bool x) { 
00103                 v = (x == True ? 'T' : 'F'); return *this; }
00104         Bool isdefined() const { return v == '\0' ? True : False; }
00105         void undefine() { v = '\0'; }
00106         operator Bool() { return (v == 'T' ? True : False); }
00107     protected:
00108         char v;
00109 };
00110 
00111 //<summary> helper class for FITS Binary Tables </summary>
00112 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00113 // </reviewed>
00114 //<synopsis>
00115 // This class is not intended for general use.  It only has meaning
00116 // in the context of FITS Binary tables.  There its use is incorporated
00117 // into the concept of a FitsField, where FitsBit is given a specialized
00118 // interpretation.
00119 //</synopsis>
00120 
00121 class FitsBit {
00122     public:
00123         FitsBit() : bit_array(0) { }
00124         FitsBit(unsigned char x) : bit_array(x) { }
00125         FitsBit(const FitsBit &x) : bit_array(x.bit_array) { }
00126         FitsBit & operator = (const FitsBit &x) { 
00127                 bit_array = x.bit_array; return *this; }
00128         FitsBit & operator = (unsigned char x) { bit_array = x; return *this; }
00129         operator unsigned char() { return bit_array; }
00130     protected:
00131         unsigned char bit_array;
00132 };
00133 
00134 //<summary>  Variable Length Array Descriptor </summary>
00135 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00136 // </reviewed>
00137 
00138 class FitsVADesc { 
00139         friend ostream & operator << (ostream &o, const FitsVADesc &);
00140     public:
00141         FitsVADesc() : no_elements(0), rel_offset(0) { }
00142         FitsVADesc(const FitsVADesc &x) :
00143                 no_elements(x.no_elements), rel_offset(x.rel_offset) { }
00144         FitsVADesc & operator = (const FitsVADesc &x) {
00145                 no_elements= x.no_elements;
00146                 rel_offset = x.rel_offset; return *this; }
00147         FitsVADesc(int n, int o) : no_elements(n), rel_offset(o) { }
00148         void set(int n, int o) { no_elements = n; rel_offset = o; }
00149         int num() const         { return no_elements; }
00150         int offset() const      { return rel_offset; }
00151     protected:
00152         int no_elements;
00153         int rel_offset;
00154 };
00155 
00156 //<summary> static functions and enumerations </summary>
00157 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00158 // </reviewed>
00159 //<synopsis>
00160 // Many of the static functions are utility functions used internally in the
00161 // implementation of the member functions of the FITS classes. They are placed
00162 // in a single class to encapsulate them and to avoid adding many names to the 
00163 // global name space. More important, from the user's perspective, are the
00164 // enumerations. They form the basic vocabulary of a FITS application. For example,
00165 // instead of referring to the FITS <src>NAXIS</src> keyword, 
00166 // <src>FITS::NAXIS</src> should be used
00167 //</synopsis>
00168 
00169 class FITS {
00170     public:
00171 
00172     // FITS I/O Error message types
00173 
00174         // Basic FITS Data Types for keywords and data
00175         enum ValueType {
00176             NOVALUE = 0, LOGICAL = 1, BIT = 2, CHAR = 3, BYTE = 4, 
00177             SHORT = 5, LONG = 6, FLOAT = 7, DOUBLE = 8, COMPLEX = 9, 
00178             ICOMPLEX = 10, DCOMPLEX = 11, VADESC = 12,
00179             STRING, FSTRING, REAL
00180         }; // REAL means either FLOAT or DOUBLE
00181            // STRING and FSTRING are used internally in parsing keywords
00182 
00183         static  FITS::ValueType getfitstype(NoConvert<FitsLogical> x) {
00184                 x=0; return FITS::LOGICAL; }
00185         static  FITS::ValueType getfitstype(NoConvert<FitsBit> x) {
00186                 x=0; return FITS::BIT; }
00187         static  FITS::ValueType getfitstype(NoConvert<char> x) {
00188                 x=0; return FITS::CHAR; }
00189         static  FITS::ValueType getfitstype(NoConvert<unsigned char> x) {
00190                 x=0; return FITS::BYTE; }
00191         static  FITS::ValueType getfitstype(NoConvert<short> x) {
00192                 x=0; return FITS::SHORT; }
00193         static  FITS::ValueType getfitstype(NoConvert<Int> x) {
00194                 x=0; return FITS::LONG; }
00195         static  FITS::ValueType getfitstype(NoConvert<long> x) {
00196                 x=0; return FITS::LONG; }
00197         static  FITS::ValueType getfitstype(NoConvert<float> x) {
00198                 x=0; return FITS::FLOAT; }
00199         static  FITS::ValueType getfitstype(NoConvert<double> x) {
00200                 x=0; return FITS::DOUBLE; }
00201         static  FITS::ValueType getfitstype(NoConvert<Complex> x) {
00202                 x=0; return FITS::COMPLEX; }
00203         static  FITS::ValueType getfitstype(NoConvert<IComplex> x) {
00204                 x=0; return FITS::ICOMPLEX; }   
00205         static  FITS::ValueType getfitstype(NoConvert<DComplex> x) {
00206                 x=0; return FITS::DCOMPLEX; }
00207         static  FITS::ValueType getfitstype(NoConvert<FitsVADesc> x) {
00208                 x=0; return FITS::VADESC; }
00209 
00210         static  int fitssize(FITS::ValueType t);
00211         static  int localsize(FITS::ValueType t);
00212 
00213         // data conversion routines: FITS - local
00214         static void f2l(FitsLogical *,void *,int);
00215         static void l2f(void *,FitsLogical *,int);
00216         static void f2l(FitsBit *,void *,int);
00217         static void l2f(void *,FitsBit *,int);
00218         static void f2l(char *,void *,int);
00219         static void l2f(void *,char *,int);
00220         static void f2l(unsigned char *,void *,int);
00221         static void l2f(void *,unsigned char *,int);
00222         static void f2l(short *,void *,int);
00223         static void l2f(void *,short *,int);
00224         static void f2l(Int *,void *,int);
00225         static void l2f(void *,Int *,int);
00226         static void f2l(long *,void *,int);
00227         static void l2f(void *,long *,int);
00228         static void f2l(float *,void *,int);
00229         static void l2f(void *,float *,int);
00230         static void f2l(double *,void *,int);
00231         static void l2f(void *,double *,int);
00232         static void f2l(Complex *,void *,int);
00233         static void l2f(void *,Complex *,int);
00234         static void f2l(IComplex *,void *,int);
00235         static void l2f(void *,IComplex *,int);
00236         static void f2l(DComplex *,void *,int);
00237         static void l2f(void *,DComplex *,int);
00238         static void f2l(FitsVADesc *,void *,int);
00239         static void l2f(void *,FitsVADesc *,int);
00240         static void swap2(void *, void *, int);
00241         static void swap4(void *, void *, int);
00242         static void swap8(void *, void *, int);
00243 
00244         // FITS Reserved Names. PZERO is named strangely because it can conflict with
00245         // a standard #define in sys/param.h.
00246         enum ReservedName {
00247             USER_DEF, AUTHOR,   BITPIX,   BLANK,    BLOCKED,  BSCALE,
00248             BUNIT,    BZERO,    CDELT,    COMMENT,  CROTA,    CRPIX,
00249             CRVAL,    CTYPE,    DATAMAX,  DATAMIN,  DATE,     DATE_OBS,
00250             END,      EPOCH,    EQUINOX,  EXTEND,   EXTLEVEL, EXTNAME,
00251             EXTVER,   GCOUNT,   GROUPS,   HISTORY,  INSTRUME, NAXIS,
00252             OBJECT,   OBSERVER, ORIGIN,   PCOUNT,   PSCAL,    PTYPE,
00253             PZERO_FITS,    REFERENC, SIMPLE,   SPACES,   TBCOL,    TDIM,
00254             TDISP,    TELESCOP, TFIELDS,  TFORM,    THEAP,    TNULL,
00255             TSCAL,    TTYPE,    TUNIT,    TZERO,    XTENSION, ERRWORD,
00256             ALTRPIX, DATE_MAP
00257         };
00258 
00259         // Types of FITS Records
00260         enum FitsRecType { 
00261             InitialState, BadBeginningRecord, HDURecord,
00262             UnrecognizableRecord, SpecialRecord, EndOfFile 
00263         };
00264 
00265         // Supported FITS Physical Devices
00266         enum FitsDevice { 
00267             Disk, Std, Tape9
00268         };
00269 
00270         // Types of FITS Header-Data Units
00271         enum HDUType {
00272             NotAHDU, PrimaryArrayHDU, PrimaryGroupHDU, AsciiTableHDU,
00273             BinaryTableHDU, ImageExtensionHDU, UnknownExtensionHDU,
00274             PrimaryTableHDU
00275         };
00276 
00277         // Options on FITS array manipulations
00278         enum FitsArrayOption { NoOpt = 0, CtoF = 1, FtoC = 2};
00279 
00280         static ReservedFitsKeywordCollection &ResWord;
00281         static void valstr(ostream &o, const ValueType &ty, const void *val);
00282         static Bool isa_digit(char c);
00283         static int digit2bin(char c);
00284         static Bool isa_text(char c);
00285         static Bool isa_letter(char);
00286         static int letter2bin(char);
00287         static void fstr2str(char *, const char *, int);
00288         static int str2fstr(char *, const char *, int);
00289         static void get_name(const char *s, int len, FitsNameResult &result);
00290         static int get_value_id(const char *s, int l, int &pos);
00291         static void get_value(const char *s, int len, FitsValueResult &result);
00292         static int trim_comment(const char *s, int len);
00293         static int chk_comment(const char *s, int len);
00294         static int get_comment(const char *s, int len, int &begpos);
00295         static void get_numeric(const char *s, int len, FitsValueResult &result);
00296     // utility function to parse the binary table variable array
00297     // column (i.e. uses the heap) of the form nPt(dddd) where n
00298     // is either 0 or 1, t is one of the standard FITS binary table
00299     // column types and dddd is the maximum number of elements used
00300     // by this column.  If there is a format error in the input
00301     // string (*s), then valType will have the value NOVALUE and
00302     // maxelem will be -1.
00303         static void parse_vatform(const char *s, FITS::ValueType &valType,
00304                                   int &maxelem);
00305         static const Int minInt;
00306         static const Int maxInt;
00307         static const float minfloat;
00308         static const float maxfloat;
00309         static const double mindouble;
00310         static const double maxdouble;
00311 
00312     private:
00313         FITS();
00314         static double tenpowerD[309];
00315         static float tenpowerF[39];
00316         static const int minfltexp;
00317         static const int maxfltexp;
00318         static const int mindblexp;
00319         static const int maxdblexp;
00320         static const int maxsigdigits;
00321         static const int maxdigl; // max digits in a long
00322         static const int maxexpdig; // max digits in an exponent
00323         static double tenD(Int, int);
00324         static float tenF(Int, int);
00325         static int ckaccum(double &, Int, int);
00326         static int ckaccum(float &, Int, int);
00327 };
00328 
00329 inline FITS::FITS() { } // just a dummy function to prevent instantiation
00330 inline Bool FITS::isa_digit(char c) { return isdigit(c) ? True : False; }
00331 inline int FITS::digit2bin(char c) { return c - '0'; }
00332 inline Bool FITS::isa_text(char c) { return isprint(c) ? True : False; }
00333 inline Bool FITS::isa_letter(char c) { return isupper(c) ? True : False; }
00334 inline int FITS::letter2bin(char c) { return c - 'A'; }
00335 
00336 ostream & operator << (ostream &, const FITS::ValueType &);
00337 
00338 inline double FITS::tenD(Int numb, int pow) {
00339         return (pow > 0) ? (((double)numb) * tenpowerD[pow]) :
00340             ((pow < 0) ? (((double)numb) / tenpowerD[-pow]) : ((double)numb));
00341 }
00342 inline float FITS::tenF(Int numb, int pow) {
00343         return (pow > 0) ? (((float)numb) * tenpowerF[pow]) :
00344             ((pow < 0) ? (((float)numb) / tenpowerF[-pow]) : ((float)numb));
00345 }
00346 
00347 //<summary> reserved FITS keyword </summary>
00348 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00349 // </reviewed>
00350 
00351 class ReservedFitsKeyword {
00352     public:
00353         const char *aname() const;
00354         FITS::ReservedName name() const;
00355         int namesize() const;
00356         FITS::ValueType type() const;
00357         Bool isindexed() const;
00358         Bool isessential() const;
00359 # if defined(TURBOCPP)
00360         // It is best for the following to be private, but 
00361         // C-Front won't allow an initializer list if they are private.
00362         // This issue isn't that crucial since functions in 
00363         // ReservedFitsKeywordCollection always return const items.
00364     private:
00365 # endif
00366         FITS::ReservedName name_;
00367         const char *aname_;
00368         int namesize_;
00369         FITS::ValueType type_;
00370         Bool isindexed_; // 0 = NOT INDEXED, 1 = INDEXED
00371         Bool isessential_; // 0 = NO, 1 = YES
00372 };
00373 
00374 inline const char *ReservedFitsKeyword::aname() const { return aname_; }
00375 inline int ReservedFitsKeyword::namesize() const { return namesize_; }
00376 inline FITS::ValueType ReservedFitsKeyword::type() const { return type_; }
00377 inline Bool ReservedFitsKeyword::isindexed() const { return isindexed_; }
00378 inline Bool ReservedFitsKeyword::isessential() const { 
00379         return isessential_; }
00380 
00381 //<summary> collection of reserved FITS keywords </summary>
00382 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00383 // </reviewed>
00384 
00385 class ReservedFitsKeywordCollection {
00386     public:
00387         const ReservedFitsKeyword & operator [] (int i) const;
00388         int no() const;
00389         const ReservedFitsKeyword &get(FITS::ReservedName, Bool, FITS::ValueType,
00390                 const void *, int, const char *&) const;
00391         const ReservedFitsKeyword &get(const char *, int, Bool, FITS::ValueType,
00392                 const void *, int, const char *&) const;
00393         const char *aname(FITS::ReservedName) const;
00394         int essential_name(const char *, int) const;
00395         const ReservedFitsKeyword &get_essential(int, Bool, FITS::ValueType,
00396                 const void *, int, const char *&) const;
00397         int isreserved(const char *, int) const;
00398         Bool isunique(int) const;
00399         Bool requires_value(int) const;
00400         const ReservedFitsKeyword &userdef_item() const;
00401         const ReservedFitsKeyword &err_item() const;
00402         const ReservedFitsKeyword &end_item() const;
00403         const ReservedFitsKeyword &spaces() const;
00404         const ReservedFitsKeyword &comment() const;
00405         const ReservedFitsKeyword &history() const;
00406         int rules(const ReservedFitsKeyword &, const char *, int, Bool,
00407                 FITS::ValueType, const void *, int, const char *&) const;
00408     private:
00409         static const int no_items; // number of entries in the table
00410         static const ReservedFitsKeyword &user_def_item; // user-defined keyword
00411         static const ReservedFitsKeyword &error_item; // error in keyword
00412         static const ReservedFitsKeyword &end__item;
00413         static const ReservedFitsKeyword &spaces_item;
00414         static const ReservedFitsKeyword &comment_item;
00415         static const ReservedFitsKeyword &history_item;
00416         static const ReservedFitsKeyword resword[]; // table of reserved words
00417         static const int resalpha[26]; // alphabetic index to table
00418         const ReservedFitsKeyword &match(int, const char *, int, Bool,
00419                 FITS::ValueType, const void *, int, const char *&) const;
00420 
00421 };
00422 
00423 inline const ReservedFitsKeyword & ReservedFitsKeywordCollection::
00424 	operator [] (int i) const { return resword[i]; }
00425 inline int ReservedFitsKeywordCollection::no() const { return no_items; }
00426 inline Bool ReservedFitsKeywordCollection::isunique(int i) const {
00427         return (Bool)(resword[i + 1].name() != resword[i].name()); }
00428 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::userdef_item()
00429         const { return user_def_item; }
00430 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::err_item() 
00431         const { return error_item; }
00432 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::end_item()
00433         const { return end__item; }
00434 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::spaces()
00435         const { return spaces_item; }
00436 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::comment()
00437         const { return comment_item; }
00438 inline const ReservedFitsKeyword &ReservedFitsKeywordCollection::history()
00439         const { return history_item; }
00440 
00441 //<summary> analyse the name of a header card </summary>
00442 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00443 // </reviewed>
00444 //<synopsis>
00445 // Analyse the name of a header card
00446 //</synopsis>
00447 
00448 class FitsNameResult {
00449     public:
00450         Bool isaname;   // 1 if there is a name present, otherwise 0
00451         int begpos;     // beginning position of name
00452         int endpos;     // ending position of name
00453         Bool isaindex;  // whether an index is present or not
00454         int index;      // index if present
00455         int len;        // length of name without index
00456         enum ErrMsg { OK = 0, NO_0_NDX };
00457         ErrMsg err;
00458 };
00459 
00460 //<summary> analyse the value of a header card </summary>
00461 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00462 // </reviewed>
00463 //<synopsis>
00464 // Analyse the value of a header card
00465 //</synopsis>
00466 
00467 class FitsValueResult {
00468     public:
00469         FITS::ValueType type;
00470         union {
00471             Bool b;
00472             int s[2];   // for strings, s[0] is offset, s[1] length
00473             Int l;
00474             float f;
00475             double d;
00476         };
00477         Complex c;
00478         IComplex lc;
00479         DComplex dc;
00480         int begpos;             // beginning position of value
00481         int endpos;             // ending position of value
00482         Bool isa_point;         // 1 if a point, otherwise 0
00483         int pointpos;           // position of point, if any
00484         int no_sig;             // number of significant digits
00485         const char *errmsg;     // error message, if any
00486 };
00487 
00488 //<summary> parse a header card </summary>
00489 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00490 // </reviewed>
00491 //<synopsis> 
00492 //  parse a header card 
00493 //</synopsis>
00494 
00495 class FitsParse {
00496         friend class FitsKeywordList;
00497     public:
00498         FitsKeyword &parse(const char *, int); // Parsing one string
00499         int no_errs() const;
00500         const char *err(int) const;
00501     private:
00502         FitsParse(int = 10);
00503         ~FitsParse();
00504         int no_errs_;
00505         const int max_errs;
00506         const char **err_;
00507         int seterr(const char *);
00508         FitsKeyword &mkerr(const char *s, int len);
00509 };
00510 
00511 inline FitsParse::~FitsParse() { delete [] err_; }
00512 inline int FitsParse::no_errs() const { return no_errs_; }
00513 inline const char *FitsParse::err(int i) const { return err_[i]; }
00514 inline int FitsParse::seterr(const char *s) {
00515         return no_errs_ < max_errs ? ( err_[no_errs_++] = s, 0) : -1; }
00516 
00517 //<summary> FITS keyword </summary>
00518 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00519 // </reviewed>
00520 //<synopsis>
00521 // A FITS keyword contains a name, a value and a comment.
00522 //</synopsis>
00523 class FitsKeyword {
00524         friend class FitsKeywordList;
00525         friend class FitsParse;
00526         // A word about friends:  FitsKeywordList accesses the next and prev
00527         // pointers and the FitsKeyword constructors. 
00528         // FitsParse only accesses the FitsKeyword constructors.
00529 
00530     public:
00531 
00532         FitsKeyword(const FitsKeyword &);
00533         FitsKeyword & operator = (const FitsKeyword &);
00534         ~FitsKeyword();
00535 
00536         //<group>
00537         // get info about the name
00538         const char *name() const;
00539         int namelen() const;
00540         Bool isreserved() const;
00541         Bool isindexed() const;
00542         const ReservedFitsKeyword &kw() const;
00543         int index() const;
00544         //</group>
00545 
00546         //<group>
00547         // access the keyword comment
00548         const char *comm() const;
00549         int commlen() const;
00550         //</group>
00551 
00552         // access the error status
00553         int err() const;
00554 
00555         // the datatype of the keyword
00556         FITS::ValueType type() const;
00557 
00558         // access the value of the keyword
00559         //<group>
00560         Bool asBool() const;
00561         const char *asString() const;
00562         int valStrlen() const;
00563         Int asInt() const;
00564         float asFloat() const;
00565         double asDouble() const;
00566         IComplex asIComplex() const;
00567         Complex asComplex() const;
00568         DComplex asDComplex() const;
00569         const void *value() const;
00570         //</group>
00571 
00572         // change the value of the keyword
00573         //<group>
00574         FitsKeyword & operator = (Bool);
00575         FitsKeyword & operator = (const char *);
00576         FitsKeyword & operator = (Int);
00577         FitsKeyword & operator = (float);
00578         FitsKeyword & operator = (double);
00579         FitsKeyword & operator = (IComplex);
00580         FitsKeyword & operator = (Complex);
00581         FitsKeyword & operator = (DComplex);
00582         //</group>
00583 
00584         // change the comment of the keyword
00585         void comm(const char *);
00586 
00587         // change the name of the keyword
00588         void name(const char *);
00589 
00590     private:
00591         FitsKeyword *next_;
00592         FitsKeyword *prev_;
00593 
00594         //<group>
00595         // the keyword name
00596         // if name_ is 0, keyword is not a user defined name
00597         // if ndx is 0, there is no index
00598         char *name_;
00599         const ReservedFitsKeyword *kw_;
00600         int ndx;
00601         short namelen_;
00602         //</group>
00603 
00604         //<group>
00605         // the keyword comment
00606         // if comm_ is 0, there is no comment
00607         char *comm_;
00608         short commlen_;
00609         //</group>
00610 
00611 
00612         //<group>
00613         // the keyword value
00614         FITS::ValueType type_;
00615         union {
00616             Bool bval;
00617             Int ival;
00618             float fval;
00619             double dval;
00620         };
00621         void *val; // pointer to allocated value, if any
00622         short vallen; // only used for string data
00623         void del_val(); // does an appropriate delete based on type
00624         //</group>
00625 
00626         void init(const FitsKeyword &);
00627         void setval(const FITS::ValueType &, const void *, int);
00628         void setcomm(const char *, int);
00629         static void err(const char *, const FITS::ValueType &, const void *,
00630                  const char *);
00631         static void memchk(void *);
00632 
00633         //<group>
00634         // private constructors for use by friends
00635 
00636         // constructs user-defined keywords
00637         // parms: name, namelen, type, val, vallen, comm, commlen
00638         FitsKeyword(const char *, int , 
00639                 FITS::ValueType, const void *, int, const char *, int);
00640         // constructs reserved keywords
00641         // parms: resword, index, val, vallen, comm, commlen
00642         FitsKeyword(const ReservedFitsKeyword *, int,
00643                 FITS::ValueType, const void *, int, const char *, int);
00644         //</group>
00645 
00646 
00647 };
00648 
00649 ostream & operator << (ostream &, const FitsKeyword &);
00650 
00651 inline FitsKeyword::FitsKeyword(const FitsKeyword &k) : next_(0), prev_(0),
00652         name_(0), kw_(0), comm_(0), val(0)  { init(k); }
00653 inline FitsKeyword & FitsKeyword::operator = (const FitsKeyword &k) { 
00654         delete [] name_; delete [] comm_; del_val(); init(k); return *this; }
00655 inline FitsKeyword::~FitsKeyword() { 
00656         delete [] name_; 
00657         delete [] comm_; 
00658         del_val(); 
00659 }
00660 
00661 inline const ReservedFitsKeyword &FitsKeyword::kw() const { return *kw_; }
00662 inline Bool FitsKeyword::isreserved() const { return 
00663         (kw().name() != FITS::ERRWORD && kw().name() != FITS::USER_DEF)
00664                  ? True : False; }
00665 inline const char *FitsKeyword::name() const {
00666         return isreserved() ? kw().aname() : (namelen_ ? name_ : ""); }
00667 inline int FitsKeyword::namelen() const { return namelen_; }
00668 inline Bool FitsKeyword::isindexed() const {return ndx > 0 ? True : False;}
00669 inline int FitsKeyword::index() const { return ndx; }
00670 
00671 inline const char *FitsKeyword::comm() const {
00672     return comm_ ? comm_  : ""; }
00673 inline int FitsKeyword::commlen() const { return commlen_; }
00674 inline int FitsKeyword::err() const { return (kw().name() == FITS::ERRWORD); }
00675 inline FITS::ValueType FitsKeyword::type() const { return type_; }
00676 
00677 inline Bool FitsKeyword::asBool() const { return bval; }
00678 inline const char *FitsKeyword::asString() const {
00679         return vallen ? (const char *)val : ""; }
00680 inline int FitsKeyword::valStrlen() const { return vallen; }
00681 inline Int FitsKeyword::asInt() const { 
00682         if( type() != FITS::LONG ) {
00683                 cerr << "Unexpected keyword type in FitsKeyword::asInt()\n";
00684                 exit(1);
00685         }
00686         return ival;
00687 }
00688 inline float FitsKeyword::asFloat() const { 
00689         switch( type() ) { 
00690                 case FITS::BYTE:
00691                 case FITS::SHORT:
00692                 case FITS::LONG: return (float)ival;
00693                 case FITS::FLOAT: return fval;
00694                 case FITS::DOUBLE: return (float)dval;
00695                 default:
00696                         cerr << "Unexpected keyword type in asFloat()\n";
00697                         exit(1);
00698         }
00699         return 0.0;
00700 }
00701 inline double FitsKeyword::asDouble() const { 
00702         switch( type() ) { 
00703                 case FITS::BYTE:
00704                 case FITS::SHORT:
00705                 case FITS::LONG: return (double)ival;
00706                 case FITS::FLOAT: return (double)fval;
00707                 case FITS::DOUBLE: return dval;
00708                 default:
00709                         cerr << "Unexpected keyword type in asDouble()\n";
00710                         exit(1);
00711         }
00712         return 0.0;
00713 }
00714 inline IComplex FitsKeyword::asIComplex() const {
00715         return *((IComplex *)val); }
00716 inline Complex FitsKeyword::asComplex() const {
00717         return *((Complex *)val); }
00718 inline DComplex FitsKeyword::asDComplex() const {
00719         return *((DComplex *)val); }
00720 
00721 inline FitsKeyword & FitsKeyword::operator = (Bool x) {
00722         bval = x; type_ = FITS::LOGICAL; return *this; }
00723 inline FitsKeyword & FitsKeyword::operator = (Int x) {
00724         ival = x; type_ = FITS::LONG; return *this; }
00725 inline FitsKeyword & FitsKeyword::operator = (float x) {
00726         fval = x; type_ = FITS::FLOAT; return *this; }
00727 inline FitsKeyword & FitsKeyword::operator = (double x) {
00728         dval = x; type_ = FITS::DOUBLE; return *this; }
00729 inline FitsKeyword & FitsKeyword::operator = (IComplex x) {
00730         *((IComplex *)val) = x; type_ = FITS::ICOMPLEX; return *this; }
00731 inline FitsKeyword & FitsKeyword::operator = (Complex x) {
00732         *((Complex *)val) = x; type_ = FITS::COMPLEX; return *this; }
00733 inline FitsKeyword & FitsKeyword::operator = (DComplex x) {
00734         *((DComplex *)val) = x; type_ = FITS::DCOMPLEX; return *this; }
00735 
00736 class ConstFitsKeywordList; // forward declaration
00737 
00738 //<summary> linked list of FITS keywords </summary>
00739 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00740 // </reviewed>
00741 //<synopsis>
00742 // A linked list of FITS keywords.
00743 //</synopsis>
00744 
00745 class FitsKeywordList {
00746     public:
00747         FitsKeywordList();
00748         ~FitsKeywordList();
00749         FitsKeywordList(const FitsKeywordList &);
00750         FitsKeywordList(ConstFitsKeywordList &);
00751         FitsKeywordList & operator = (const FitsKeywordList &);
00752 
00753         // delete the current keyword (the thing returned by curr()) from the list
00754         void del();
00755 
00756         // Add (make) a reserved keyword with the given value and optional comment
00757         // The comment will be truncated if necessary to fit the available space.
00758         // String values must be less than 69 characters.  String values longer than
00759         // that will result in an ERROR keyword instead of the desired keyword.
00760         // <group>
00761         void mk(FITS::ReservedName k, Bool v, const char *c = 0);
00762         void mk(FITS::ReservedName k, const char *v = 0, const char *c = 0);
00763         void mk(FITS::ReservedName k, Int v, const char *c = 0);
00764         void mk(FITS::ReservedName k, long v, const char *c = 0);
00765         void mk(FITS::ReservedName k, double v, const char *c = 0);
00766         // </group>
00767 
00768         // Add (make) an indexed reserved keyword with the given value and optional comment
00769         // The comment will be truncated if necessary to fit the available space.
00770         // String values must be less than 69 characters.  String values longer than
00771         // that will result in an ERROR keyword instead of the desired keyword.
00772         // <group>
00773         void mk(int n, FITS::ReservedName k, Bool v, const char *c = 0);
00774         void mk(int n, FITS::ReservedName k, const char *v, const char *c = 0);
00775         void mk(int n, FITS::ReservedName k, Int v, const char *c = 0);
00776         void mk(int n, FITS::ReservedName k, long v, const char *c = 0);
00777         void mk(int n, FITS::ReservedName k, double v, const char *c = 0);
00778         // </group>
00779 
00780         // Add (make) a user defined keyword with the given name, value and optional comment.
00781         // The comment will be truncated if necessary to fit the available space.
00782         // The name must be no longer than 8 characters.  Names longer than that will 
00783         // result in an ERROR keyword instead of the desired keyword.
00784         // String values must no longer than 69 characters.  String values longer than
00785         // that will result in an ERROR keyword instead of the desired keyword.
00786         // <group>
00787         void mk(const char *n, Bool v, const char *c = 0);
00788         void mk(const char *n, const char *v = 0, const char *c = 0);
00789         void mk(const char *n, Int v, const char *c = 0);
00790         void mk(const char *n, long v, const char *c = 0);
00791         void mk(const char *n, float v, const char *c = 0);
00792         void mk(const char *n, double v, const char *c = 0);
00793         void mk(const char *n, Int r, Int i, const char *c = 0);
00794         void mk(const char *n, float r, float i, const char *c = 0);
00795         void mk(const char *n, double r, double i, const char *c = 0);
00796         // </group>
00797 
00798         // add a spaces line
00799         void spaces(const char *n = 0, const char *c = 0);
00800 
00801         // add a comment card
00802         void comment(const char *n = 0, const char *c = 0);
00803 
00804         // add a history card
00805         void history(const char *c = 0);
00806 
00807         // add the end card.  This must be at the end of the list.
00808         void end();
00809         
00810         // Retrieve specific keywords -- these also set the current mark
00811         //<group>
00812         // return the i-th keyword -- keyword numbering starts with 0
00813         FitsKeyword * operator () (int);
00814         // return first and next non-indexed reserved keyword
00815         FitsKeyword * operator () (const FITS::ReservedName &);
00816         FitsKeyword * next(const FITS::ReservedName &);
00817         // return first and next indexed reserved keyword
00818         FitsKeyword * operator () (const FITS::ReservedName &, int);
00819         FitsKeyword * next(const FITS::ReservedName &, int);
00820         // return first and next user-defined keyword
00821         FitsKeyword * operator () (const char *);
00822         FitsKeyword * next(const char *);
00823         //</group>
00824 
00825         //<group>
00826         Bool isempty() const;
00827         void     first();
00828         void     last();
00829         FitsKeyword *next();
00830         FitsKeyword *prev();
00831         FitsKeyword *curr();
00832         //</group>
00833 
00834         //<group>
00835         void delete_all(); 
00836         int rules(FitsKeyword &, 
00837                   FITSErrorHandler errhandler = FITSError::defaultHandler);
00838         int rules(FITSErrorHandler errhandler = FITSError::defaultHandler);
00839         Bool basic_rules();
00840         //</group>
00841 
00842         //<group>
00843         // For parsing a single string
00844         void parse(const char *, int); 
00845         int no_parse_errs() const;
00846         const char *parse_err(int) const;
00847         //</group>
00848 
00849         void insert(FitsKeyword &);
00850     private:
00851         FitsKeyword *beg_;
00852         FitsKeyword *end_;
00853         FitsKeyword *pos;
00854         int total;
00855         int cursor;
00856         FitsKeyword &make(const char *nm,
00857                 FITS::ValueType t, const void *v, const char *c);
00858         FitsKeyword &make(FITS::ReservedName nm,
00859                 FITS::ValueType t, const void *v, const char *c);
00860         FitsKeyword &make(int ind, FITS::ReservedName nm,
00861                 FITS::ValueType t, const void *v, const char *c);
00862         // construct an error keyword - this happens when a name is invalid (NULL
00863         // or more than 8 characters) or a string value is too long (more than
00864         // 69 characters).  It is the responsibility of the caller to the 
00865         // several mk functions to ensure that that doesn't happen.  By the time
00866         // it gets here, it is assumed that such problems are true errors.
00867         // This is used by the private make functions.
00868         FitsKeyword &makeErrKeyword(const char *name, FITS::ValueType type, 
00869                                     const void *val, const char *errmsg);
00870         FitsParse card;
00871 };
00872 
00873 ostream & operator << (ostream &o, FitsKeywordList &); // print the entire list
00874 
00875 inline FitsKeywordList::FitsKeywordList() : beg_(0), end_(0), pos(0), 
00876         total(0), cursor(0) { }
00877 inline FitsKeywordList::~FitsKeywordList() { delete_all(); }
00878 inline Bool FitsKeywordList::isempty() const { return total == 0 ? True : False; }
00879 inline void FitsKeywordList::first() { cursor = 0; pos = beg_; }
00880 inline void FitsKeywordList::last() { cursor = total; pos = end_; }
00881 inline FitsKeyword *FitsKeywordList::curr() { return pos; }
00882 inline FitsKeyword *FitsKeywordList::operator () (const FITS::ReservedName &n) {
00883         first(); return next(n); }
00884 inline FitsKeyword *FitsKeywordList::operator () (const FITS::ReservedName &n,
00885         int ndx) { first(); return next(n,ndx); }
00886 inline FitsKeyword *FitsKeywordList::operator () (const char *w) {
00887         first(); return next(w); }
00888 inline void FitsKeywordList::parse(const char *s, int l) {
00889         insert(card.parse(s,l)); }
00890 inline int FitsKeywordList::no_parse_errs() const { return card.no_errs();}
00891 inline const char *FitsKeywordList::parse_err(int n) const { 
00892         return card.err(n); }
00893 
00894 // FitsKeyword constructors for non-indexed Reserved keywords
00895 inline void FitsKeywordList::mk(FITS::ReservedName k, Bool v, const char *c) {
00896         insert(make(k,FITS::LOGICAL,&v,c)); }
00897 inline void FitsKeywordList::mk(FITS::ReservedName k, const char *v, 
00898         const char *c) { insert(make(k,FITS::STRING,v,c)); }
00899 inline void FitsKeywordList::mk(FITS::ReservedName k, Int v, const char *c) {
00900         insert(make(k,FITS::LONG,&v,c)); }
00901 inline void FitsKeywordList::mk(FITS::ReservedName k, long v, const char *c) {
00902         insert(make(k,FITS::LONG,&v,c)); }
00903 inline void FitsKeywordList::mk(FITS::ReservedName k, double v, const char *c) {
00904         insert(make(k,FITS::DOUBLE,&v,c)); }
00905 // FitsKeyword constructors for indexed Reserved keywords
00906 inline void FitsKeywordList::mk(int n, FITS::ReservedName k, Bool v, 
00907         const char *c) { 
00908         Bool tmp; tmp = v; insert(make(n,k,FITS::LOGICAL,&tmp,c)); }
00909 inline void FitsKeywordList::mk(int n, FITS::ReservedName k, const char *v, 
00910         const char *c) { insert(make(n,k,FITS::STRING,v,c)); }
00911 inline void FitsKeywordList::mk(int n, FITS::ReservedName k, Int v, 
00912         const char *c) { insert(make(n,k,FITS::LONG,&v,c)); }
00913 inline void FitsKeywordList::mk(int n, FITS::ReservedName k, long v, 
00914         const char *c) { insert(make(n,k,FITS::LONG,&v,c)); }
00915 inline void FitsKeywordList::mk(int n, FITS::ReservedName k, double v, 
00916         const char *c) { insert(make(n,k,FITS::DOUBLE,&v,c)); }
00917 // FitsKeyword constructors for User-Defined keywords
00918 inline void FitsKeywordList::mk(const char *n, Bool v, const char *c) {
00919         Bool tmp; tmp = v; insert(make(n,FITS::LOGICAL,&tmp,c)); }
00920 inline void FitsKeywordList::mk(const char *n, const char *v, const char *c) {
00921         insert(make(n,FITS::STRING,v,c)); }
00922 inline void FitsKeywordList::mk(const char *n, Int v, const char *c) {
00923         insert(make(n,FITS::LONG,&v,c)); }
00924 inline void FitsKeywordList::mk(const char *n, long v, const char *c) {
00925         insert(make(n,FITS::LONG,&v,c)); }
00926 inline void FitsKeywordList::mk(const char *n, float v, const char *c) {
00927         insert(make(n,FITS::FLOAT,&v,c)); }
00928 inline void FitsKeywordList::mk(const char *n, double v, const char *c) {
00929         insert(make(n,FITS::DOUBLE,&v,c)); }
00930 inline void FitsKeywordList::mk(const char *n, Int r, Int i, const char *c) {
00931         IComplex v(r,i);
00932         insert(make(n,FITS::ICOMPLEX,&v,c)); }
00933 inline void FitsKeywordList::mk(const char *n, float r, float i, const char *c)
00934         { Complex v(r,i); insert(make(n,FITS::COMPLEX,&v,c)); }
00935 inline void FitsKeywordList::mk(const char *n, double r, double i, 
00936         const char *c) { DComplex v(r,i);
00937         insert(make(n,FITS::DCOMPLEX,&v,c)); }
00938 // Additional keyword constructors for commentary, etc.
00939 inline void FitsKeywordList::spaces(const char *n, const char *c) {
00940         insert((n == 0 ? make(FITS::SPACES,FITS::NOVALUE,0,c) :
00941                (c == 0 ? make(FITS::SPACES,FITS::NOVALUE,0,n) : 
00942                           make(n,FITS::NOVALUE,0,c)))); }
00943 inline void FitsKeywordList::comment(const char *n, const char *c) {
00944         insert((n == 0 ? make(FITS::COMMENT,FITS::NOVALUE,0,c) :
00945                (c == 0 ? make(FITS::COMMENT,FITS::NOVALUE,0,n) :
00946                           make(n,FITS::NOVALUE,0,c)))); }
00947 inline void FitsKeywordList::history(const char *c) {
00948         insert(make(FITS::HISTORY,FITS::NOVALUE,0,c)); }
00949 inline void FitsKeywordList::end() {
00950         insert(make(FITS::END,FITS::NOVALUE,0,0)); }
00951 
00952 //<summary> list of read-only FITS keywords </summary>
00953 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00954 // </reviewed>
00955 
00956 class ConstFitsKeywordList {
00957     public:
00958         ConstFitsKeywordList(FitsKeywordList &x) : kw(x) { }
00959 
00960         const FitsKeyword * operator () (int n) { return kw(n); }
00961         const FitsKeyword * operator () (const FITS::ReservedName &x) {
00962                 return kw(x); }
00963         const FitsKeyword * next(const FITS::ReservedName &x) {
00964                 return kw.next(x); }
00965         const FitsKeyword * operator () (const FITS::ReservedName &x, int n) {
00966                 return kw(x,n); }
00967         const FitsKeyword * next(const FITS::ReservedName &x, int n) {
00968                 return kw.next(x,n); }
00969         const FitsKeyword * operator () (const char *x) { return kw(x); }
00970         const FitsKeyword * next(const char *x) { return kw.next(x); }
00971 
00972         Bool isempty() const            { return kw.isempty(); }
00973         void     first()                { kw.first(); }
00974         void     last()                 { kw.last(); }
00975         const FitsKeyword *next()       { return kw.next(); }
00976         const FitsKeyword *prev()       { return kw.prev(); }
00977         const FitsKeyword *curr()       { return kw.curr(); }
00978 
00979     private:
00980         FitsKeywordList &kw;
00981 };
00982 
00983 //<summary> translator between Keyword lists and fixed FITS cars </summary>
00984 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
00985 // </reviewed>
00986 //<synopsis> 
00987 // also contains the parser ???
00988 //</synopsis> 
00989 
00990 class FitsKeyCardTranslator {
00991     public:
00992         FitsKeyCardTranslator(int = 100);
00993         ~FitsKeyCardTranslator();
00994         FitsKeywordList & parse(const char *, 
00995                 FitsKeywordList &, int, FITSErrorHandler, Bool);
00996         int build(char *, FitsKeywordList &);
00997         int no_errs() const;
00998         const char *err(int) const;
00999         int err_cardno(int) const;
01000     private:
01001         int cardno;             // the current card number within record
01002         const int FitsCardSize;
01003         const int FitsMaxCard;
01004         const int FitsRecSize;
01005         int max_errs;
01006         int no_errs_;
01007         const char **err_;
01008         int *err_cardno_;
01009         void fmtcard(char *, const FitsKeyword &);
01010         char *blanks;
01011 };
01012 
01013 inline FitsKeyCardTranslator::~FitsKeyCardTranslator() {
01014         delete [] err_; delete [] err_cardno_; delete [] blanks; }
01015 inline int FitsKeyCardTranslator::no_errs() const { return no_errs_; }
01016 inline const char *FitsKeyCardTranslator::err(int i) const { return err_[i]; }
01017 inline int FitsKeyCardTranslator::err_cardno(int i) const {
01018         return err_cardno_[i]; }
01019 
01020 // <summary>Utility functions for floating point values</summary>
01021 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="" demos="">
01022 // </reviewed>
01023 class FitsFPUtil
01024 {
01025 public:
01026     // These functions are useful to tell if some type is a floating point type.
01027     // This is useful in a templated function, where the processing can vary
01028     // depending on whether the type is FP or not (e.g. blank handling).
01029     // <group>
01030     static Bool isFP(const float *);
01031     static Bool isFP(const double *);
01032     static Bool isFP(const void *);
01033     // </group>
01034 
01035     // For blanking purposes, we need to be able to get a NaN. The NaN we set
01036     // is all bits on.
01037     // <group>
01038     static void setNaN(double &val);
01039     static void setNaN(float &val);
01040     // </group>
01041 };
01042 
01043 
01044 } //# NAMESPACE CASA - END
01045 
01046 # endif