| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Astro::FITS::Header::Item; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | Astro::FITS::Header::Item - A card image from a FITS header | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | $item = new Astro::FITS::Header::Item( Card => $card ); | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | $item = new Astro::FITS::Header::Item( Keyword => $keyword, | 
| 12 |  |  |  |  |  |  | Value => $value, | 
| 13 |  |  |  |  |  |  | Comment => $comment, | 
| 14 |  |  |  |  |  |  | Type => 'int' | 
| 15 |  |  |  |  |  |  | ); | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | $value = $item->value(); | 
| 18 |  |  |  |  |  |  | $comment = $item->comment(); | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | $card = $item->card(); | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | $card = "$item"; | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | Stores information about a FITS header item (in the FITS standard these | 
| 28 |  |  |  |  |  |  | are called B). FITS Card Images can be parsed and broken | 
| 29 |  |  |  |  |  |  | into their component keyword, values and comments. Card Images can also | 
| 30 |  |  |  |  |  |  | be created from its components keyword, value and comment. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | =cut | 
| 33 |  |  |  |  |  |  |  | 
| 34 | 12 |  |  | 12 |  | 890823 | use strict; | 
|  | 12 |  |  |  |  | 32 |  | 
|  | 12 |  |  |  |  | 614 |  | 
| 35 |  |  |  |  |  |  | use overload ( | 
| 36 | 12 |  |  |  |  | 301 | '""'       =>   'overload_kluge' | 
| 37 | 12 |  |  | 12 |  | 1387 | ); | 
|  | 12 |  |  |  |  | 1088 |  | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 12 |  |  | 12 |  | 1354 | use vars qw/ $VERSION /; | 
|  | 12 |  |  |  |  | 122 |  | 
|  | 12 |  |  |  |  | 733 |  | 
| 40 | 12 |  |  | 12 |  | 111 | use Carp; | 
|  | 12 |  |  |  |  | 43 |  | 
|  | 12 |  |  |  |  | 40033 |  | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | $VERSION = '3.09'; | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | =head1 METHODS | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | =head2 Constructor | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | =over 4 | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | =item B | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  | Create a new instance. Optionally can be given a hash containing | 
| 53 |  |  |  |  |  |  | information from a header item or the card image itself. | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | $item = new Astro::FITS::Header::Item( Card => $card ); | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | $item = new Astro::FITS::Header::Item( Keyword => $keyword, | 
| 58 |  |  |  |  |  |  | Value => $value ); | 
| 59 |  |  |  |  |  |  |  | 
| 60 |  |  |  |  |  |  | The list of allowed hash keys is documented in the | 
| 61 |  |  |  |  |  |  | B method. | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | Returns C if the information supplied was insufficient | 
| 64 |  |  |  |  |  |  | to generate a valid header item. | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | =cut | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | sub new { | 
| 69 | 1353 |  |  | 1353 | 1 | 24705 | my $proto = shift; | 
| 70 | 1353 |  | 33 |  |  | 3582 | my $class = ref($proto) || $proto; | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 1353 |  |  |  |  | 4811 | my $item = { | 
| 73 |  |  |  |  |  |  | Keyword => undef, | 
| 74 |  |  |  |  |  |  | Comment => undef, | 
| 75 |  |  |  |  |  |  | Value => undef, | 
| 76 |  |  |  |  |  |  | Type => undef, | 
| 77 |  |  |  |  |  |  | Card => undef,  # a cache | 
| 78 |  |  |  |  |  |  | }; | 
| 79 |  |  |  |  |  |  |  | 
| 80 | 1353 |  |  |  |  | 2266 | bless $item, $class; | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | # If we have arguments configure the object | 
| 83 | 1353 | 50 |  |  |  | 3857 | $item->configure( @_ ) if @_; | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 1353 |  |  |  |  | 3454 | return $item; | 
| 86 |  |  |  |  |  |  | } | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =item B | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | Make a copy of an Astro::FITS::Header::Item object. | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | $newitem = $item->copy; | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | =cut | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | sub copy { | 
| 97 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 98 | 0 |  |  |  |  | 0 | my %copy = %$self; | 
| 99 | 0 |  |  |  |  | 0 | return bless \%copy, ref( $self ); | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | =back | 
| 103 |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | =head2 Accessor Methods | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | =over 4 | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | =item B | 
| 109 |  |  |  |  |  |  |  | 
| 110 |  |  |  |  |  |  | Return (or set) the value of the keyword associated with | 
| 111 |  |  |  |  |  |  | the FITS card. | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | $keyword = $item->keyword(); | 
| 114 |  |  |  |  |  |  | $item->keyword( $key ); | 
| 115 |  |  |  |  |  |  |  | 
| 116 |  |  |  |  |  |  | When a new value is supplied any C in the cache is invalidated. | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | Supplied value is always upper-cased. | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | =cut | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | sub keyword { | 
| 123 | 6809 |  |  | 6809 | 1 | 17341 | my $self = shift; | 
| 124 | 6809 | 100 |  |  |  | 16156 | if (@_) { | 
| 125 | 1158 |  |  |  |  | 3047 | $self->{Keyword} = uc(shift); | 
| 126 | 1158 |  |  |  |  | 1786 | $self->{Card} = undef; | 
| 127 |  |  |  |  |  |  | } | 
| 128 | 6809 |  |  |  |  | 14164 | return $self->{Keyword}; | 
| 129 |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | =item B | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | Return (or set) the value of the value associated with | 
| 134 |  |  |  |  |  |  | the FITS card. | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | $value = $item->value(); | 
| 137 |  |  |  |  |  |  | $item->value( $val ); | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | When a new value is supplied any C in the cache is invalidated. | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | If the value is an C object, the type is automatically | 
| 142 |  |  |  |  |  |  | set to "HEADER". | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | =cut | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | sub value { | 
| 147 | 2052 |  |  | 2052 | 1 | 7237 | my $self = shift; | 
| 148 | 2052 | 100 |  |  |  | 3886 | if (@_) { | 
| 149 | 1114 |  |  |  |  | 2825 | my $value = shift; | 
| 150 | 1114 |  |  |  |  | 2128 | $self->{Value} = $value; | 
| 151 | 1114 |  |  |  |  | 1600 | $self->{Card} = undef; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 1114 | 100 | 66 |  |  | 3912 | if (UNIVERSAL::isa($value,"Astro::FITS::Header" )) { | 
|  |  | 50 |  |  |  |  |  | 
| 154 | 5 |  |  |  |  | 10 | $self->type( "HEADER" ); | 
| 155 |  |  |  |  |  |  | } elsif (defined $self->type && $self->type eq 'HEADER') { | 
| 156 |  |  |  |  |  |  | # HEADER is only valid if we really are a HEADER | 
| 157 | 0 |  |  |  |  | 0 | $self->type(undef); | 
| 158 |  |  |  |  |  |  | } | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | } | 
| 161 | 2052 |  |  |  |  | 4391 | return $self->{Value}; | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | =item B | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | Return (or set) the value of the comment associated with | 
| 167 |  |  |  |  |  |  | the FITS card. | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | $comment = $item->comment(); | 
| 170 |  |  |  |  |  |  | $item->comment( $comment ); | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | When a new value is supplied any C in the cache is invalidated. | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | =cut | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | sub comment { | 
| 177 | 1763 |  |  | 1763 | 1 | 8308 | my $self = shift; | 
| 178 | 1763 | 100 |  |  |  | 3137 | if (@_) { | 
| 179 | 1130 |  |  |  |  | 1834 | $self->{Comment} = shift; | 
| 180 | 1130 |  |  |  |  | 1677 | $self->{Card} = undef; | 
| 181 |  |  |  |  |  |  | } | 
| 182 | 1763 |  |  |  |  | 2920 | return $self->{Comment}; | 
| 183 |  |  |  |  |  |  | } | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | =item B | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | Return (or set) the value of the variable type associated with | 
| 189 |  |  |  |  |  |  | the FITS card. | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | $type = $item->type(); | 
| 192 |  |  |  |  |  |  | $item->type( "INT" ); | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | Allowed types are "LOGICAL", "INT", "FLOAT", "STRING", "COMMENT", | 
| 195 |  |  |  |  |  |  | "HEADER" and "UNDEF". | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | The special type, "HEADER", is used to specify that this item refers to | 
| 198 |  |  |  |  |  |  | a subsidiary header (eg a header in an MEFITS file or a header in an | 
| 199 |  |  |  |  |  |  | NDF in an HDS container). See also the C method in | 
| 200 |  |  |  |  |  |  | C for an alternative way of specifying a | 
| 201 |  |  |  |  |  |  | sub-header. | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | The type is case-insensitive, but will always be returned up-cased. | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | =cut | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | sub type { | 
| 208 | 4796 |  |  | 4796 | 1 | 14189 | my $self = shift; | 
| 209 | 4796 | 100 |  |  |  | 8255 | if (@_) { | 
| 210 | 1179 |  |  |  |  | 1741 | my $type = shift; | 
| 211 | 1179 | 100 |  |  |  | 2425 | $type = uc($type) if defined $type; | 
| 212 | 1179 |  |  |  |  | 2128 | $self->{Type} = $type; | 
| 213 |  |  |  |  |  |  | } | 
| 214 | 4796 |  |  |  |  | 11377 | return $self->{Type}; | 
| 215 |  |  |  |  |  |  | } | 
| 216 |  |  |  |  |  |  |  | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | =item B | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | Return (or set) the 80 character header card associated with this | 
| 221 |  |  |  |  |  |  | object.  It is created if there is no cached version. | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | $card = $item->card(); | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | If a new card is supplied it will only be accepted if it is 80 | 
| 226 |  |  |  |  |  |  | characters long or fewer.  The string is padded with spaces if it is too | 
| 227 |  |  |  |  |  |  | short. No attempt (yet) )is made to shorten the string if it is too | 
| 228 |  |  |  |  |  |  | long since that may require a check to see if the value is a string | 
| 229 |  |  |  |  |  |  | that must be shortened with a closing single quote.  Returns C | 
| 230 |  |  |  |  |  |  | on assignment failure (else returns the supplied string). | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | $status = $item->card( $card ); | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | C is returned if there is insufficient information in the object | 
| 235 |  |  |  |  |  |  | to create a new card. Can assign C to clear the cache. | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | This method is called automatically when attempting to stringify | 
| 238 |  |  |  |  |  |  | the object. | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | $card = "$item"; | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | =cut | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | # This is required because overloaded methods are called with | 
| 245 |  |  |  |  |  |  | # extra arguments and card() can not tell the difference between | 
| 246 |  |  |  |  |  |  | # an undef value and a stringify request | 
| 247 |  |  |  |  |  |  | sub overload_kluge { | 
| 248 | 760 |  |  | 760 | 0 | 9925 | my $self = shift; | 
| 249 | 760 |  |  |  |  | 1460 | return $self->card; | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub card { | 
| 253 | 2007 |  |  | 2007 | 1 | 3104 | my $self = shift; | 
| 254 | 2007 | 100 |  |  |  | 3723 | if (@_) { | 
| 255 | 1214 |  |  |  |  | 1713 | my $card = shift; | 
| 256 | 1214 | 100 |  |  |  | 2133 | if (defined $card) { | 
| 257 | 1091 |  |  |  |  | 1498 | my $clen = length($card); | 
| 258 |  |  |  |  |  |  | # force to 80 characters | 
| 259 | 1091 | 100 |  |  |  | 2339 | if ($clen < 80) { | 
|  |  | 50 |  |  |  |  |  | 
| 260 | 249 |  |  |  |  | 730 | $card = $card . (" "x(80-$clen)); | 
| 261 |  |  |  |  |  |  | } elsif ($clen > 80) { | 
| 262 | 0 |  |  |  |  | 0 | $card = substr($card, 0, 80); | 
| 263 |  |  |  |  |  |  | } | 
| 264 |  |  |  |  |  |  | } | 
| 265 |  |  |  |  |  |  | # can assign undef to clear | 
| 266 | 1214 |  |  |  |  | 2065 | $self->{Card} = $card; | 
| 267 |  |  |  |  |  |  | } | 
| 268 |  |  |  |  |  |  | # We are returning a value. Create if not present | 
| 269 |  |  |  |  |  |  | # Since we are being called by stringify to set the object | 
| 270 |  |  |  |  |  |  | # we need to make sure we don't get into an endless loop | 
| 271 |  |  |  |  |  |  | # trying to create the string but not having the correct info | 
| 272 |  |  |  |  |  |  | # Especially important since stringify calls card(). | 
| 273 | 2007 | 100 |  |  |  | 4402 | $self->{Card} = $self->_stringify unless defined $self->{Card}; | 
| 274 | 2007 |  |  |  |  | 5023 | return $self->{Card}; | 
| 275 |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | =back | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | =head2 General Methods | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | =over 4 | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | =item B | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | Configures the object from multiple pieces of information. | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | $item->configure( %options ); | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | Takes a hash as argument with the following keywords: | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | =over 8 | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | =item B | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | If supplied, the value is assumed to be a standard 80 character | 
| 297 |  |  |  |  |  |  | FITS header card. This is sent to the C method directly. | 
| 298 |  |  |  |  |  |  | Takes priority over any other key. | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | If it is an C it will be copied rather | 
| 301 |  |  |  |  |  |  | than parsed. | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | =item B | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | Used to specify the keyword associated with this object. | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | =item B | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | Used to specify the value associated with this FITS item. | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | =item B | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | Used to specify the comment associated with this FITS item. | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | =item B | 
| 316 |  |  |  |  |  |  |  | 
| 317 |  |  |  |  |  |  | Used to specify the variable type. See the C method | 
| 318 |  |  |  |  |  |  | for more details. A type will be guessed if one is not supplied. | 
| 319 |  |  |  |  |  |  | The guess may well be wrong. | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | =back | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | Does nothing if these keys are not supplied. | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | =cut | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | sub configure { | 
| 328 | 1353 |  |  | 1353 | 1 | 1912 | my $self = shift; | 
| 329 | 1353 |  |  |  |  | 2912 | my %hash = @_; | 
| 330 |  |  |  |  |  |  |  | 
| 331 | 1353 | 100 |  |  |  | 2556 | if (exists $hash{'Card'}) { | 
| 332 | 1298 | 100 | 66 |  |  | 3132 | if (ref($hash{Card}) && $hash{Card}->isa("Astro::FITS::Header::Item")) { | 
| 333 |  |  |  |  |  |  | # low level populate - can not use copy since we already have a copy | 
| 334 | 207 |  |  |  |  | 293 | for my $k (keys %{$hash{Card}}) { | 
|  | 207 |  |  |  |  | 608 |  | 
| 335 | 1035 |  |  |  |  | 1870 | $self->{$k} = $hash{Card}->{$k}; | 
| 336 |  |  |  |  |  |  | } | 
| 337 |  |  |  |  |  |  | } else { | 
| 338 | 1091 |  |  |  |  | 2096 | $self->parse_card( $hash{'Card'}); | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  | } else { | 
| 341 |  |  |  |  |  |  | # Loop over the allowed keys storing the values | 
| 342 |  |  |  |  |  |  | # in the object if they exist | 
| 343 | 55 |  |  |  |  | 117 | for my $key (qw/Keyword Type Comment Value/) { | 
| 344 | 220 |  |  |  |  | 343 | my $method = lc($key); | 
| 345 | 220 | 100 |  |  |  | 642 | $self->$method( $hash{$key}) if exists $hash{$key}; | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  |  | 
| 348 |  |  |  |  |  |  | # only set type if we have not been given a type | 
| 349 | 55 | 100 |  |  |  | 125 | if (!$self->type) { | 
| 350 | 22 | 50 | 33 |  |  | 54 | if (!$self->keyword && !$self->value) { | 
|  |  | 100 | 66 |  |  |  |  | 
| 351 |  |  |  |  |  |  | # completely blank | 
| 352 | 0 |  |  |  |  | 0 | $self->type("BLANK"); | 
| 353 |  |  |  |  |  |  | } elsif (!$self->keyword || $self->keyword =~ /^(COMMENT|HISTORY)$/) { | 
| 354 |  |  |  |  |  |  | # COMMENT, HISTORY, and blank cards are special | 
| 355 | 2 |  |  |  |  | 6 | $self->type('COMMENT') | 
| 356 |  |  |  |  |  |  | } else { | 
| 357 | 20 |  |  |  |  | 56 | my $type = $self->guess_type( $self->value ); | 
| 358 | 20 | 50 |  |  |  | 57 | $self->type( $type ) if defined $type; | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  | # End cards are special, need only do a Keyword => 'END' to configure | 
| 363 | 55 | 100 |  |  |  | 110 | $self->type('END') if $self->keyword() eq 'END'; | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  | } | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | =item B | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | Method to return a blessed reference to the object so that we can store | 
| 370 |  |  |  |  |  |  | ths object on disk using Data::Dumper module. | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | =cut | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | sub freeze { | 
| 375 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 376 | 0 |  |  |  |  | 0 | return bless $self, 'Astro::FITS::Header::Item'; | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | =item B | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  | Parse a FITS card image and store the keyword, value and comment | 
| 382 |  |  |  |  |  |  | into the object. | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  | ($key, $val, $com) = $item->parse_card( $card ); | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | Returns an empty list on error. | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | =cut | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # Fits standard specifies | 
| 391 |  |  |  |  |  |  | # Characters 1:8  KEYWORD (trailing spaces)  Comment cards: COMMENT, | 
| 392 |  |  |  |  |  |  | #                 HISTORY, blank, and HIERARCH are special. | 
| 393 |  |  |  |  |  |  | #            9:10 "= "  for a valid value (unless comment keyword) | 
| 394 |  |  |  |  |  |  | #            11:80 The Value   "/" used to indicate a comment | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | # HIERARCH keywords | 
| 397 |  |  |  |  |  |  | #      This is a comment but used to store values in an extended, | 
| 398 |  |  |  |  |  |  | #      hierarchical name space.  The keyword is the string before | 
| 399 |  |  |  |  |  |  | #      the equals sign and ignoring trailing spaces.  The value | 
| 400 |  |  |  |  |  |  | #      follows the first equals sign.  The comment is delimited by a | 
| 401 |  |  |  |  |  |  | #      solidus following a string or a single value.   The HIERARCH | 
| 402 |  |  |  |  |  |  | #      keyword may follow a blank keyword in columns 1:8.. | 
| 403 |  |  |  |  |  |  | # | 
| 404 |  |  |  |  |  |  | # The value can contain: | 
| 405 |  |  |  |  |  |  | #  STRINGS: | 
| 406 |  |  |  |  |  |  | #      '  starting at position 12 | 
| 407 |  |  |  |  |  |  | #      A single quote represented as '' | 
| 408 |  |  |  |  |  |  | #      Closing quote must be at position 20 or greater (max 80) | 
| 409 |  |  |  |  |  |  | #      Trailing blanks are removed. Leading spaces in the quotes | 
| 410 |  |  |  |  |  |  | #      are significant | 
| 411 |  |  |  |  |  |  | #  LOGICAL | 
| 412 |  |  |  |  |  |  | #      T or F in column 30. Translated to 1 or 0 | 
| 413 |  |  |  |  |  |  | #  Numbers | 
| 414 |  |  |  |  |  |  | #      D is an allowed exponent as well as E | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | sub parse_card { | 
| 417 | 1091 |  |  | 1091 | 1 | 1532 | my $self = shift; | 
| 418 | 1091 | 50 |  |  |  | 1981 | return () unless @_; | 
| 419 |  |  |  |  |  |  |  | 
| 420 | 1091 |  |  |  |  | 1531 | my $card = shift; | 
| 421 | 1091 |  |  |  |  | 1377 | my $equals_col = 8; | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | # Remove new line and pad card to 80 characters | 
| 424 | 1091 |  |  |  |  | 1676 | chomp($card); | 
| 425 |  |  |  |  |  |  | #  $card = sprintf("%-80s", $card); | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | # Value is only present if an = is found in position 9 | 
| 428 | 1091 |  |  |  |  | 1795 | my ($value, $comment) = ('', ''); | 
| 429 | 1091 |  |  |  |  | 2102 | my $keyword = uc(substr($card, 0, $equals_col)); | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | # HIERARCH special case.  It's a comment, but want to treat it as | 
| 432 |  |  |  |  |  |  | # a multi-word keyword followed by a value and/or comment. | 
| 433 | 1091 | 100 | 66 |  |  | 3530 | if ( $keyword eq 'HIERARCH' || $card =~ /^\s+HIERARCH/ ) { | 
| 434 | 328 |  |  |  |  | 531 | $equals_col = index( $card, "=" ); | 
| 435 | 328 |  |  |  |  | 635 | $keyword = uc(substr($card, 0, $equals_col )); | 
| 436 |  |  |  |  |  |  | } | 
| 437 |  |  |  |  |  |  | # Remove leading and trailing spaces, and replace interior spaces | 
| 438 |  |  |  |  |  |  | # between the keywords with a single . | 
| 439 | 1091 | 50 |  |  |  | 2310 | $keyword =~ s/^\s+// if ( $card =~ /^\s+HIERARCH/ ); | 
| 440 | 1091 |  |  |  |  | 3842 | $keyword =~ s/\s+$//; | 
| 441 | 1091 |  |  |  |  | 2900 | $keyword =~ s/\s+/./g; | 
| 442 |  |  |  |  |  |  |  | 
| 443 |  |  |  |  |  |  | # update object | 
| 444 | 1091 |  |  |  |  | 2625 | $self->keyword( $keyword ); | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | # END cards are special | 
| 447 | 1091 | 100 |  |  |  | 2050 | if ($keyword eq 'END') { | 
| 448 | 9 |  |  |  |  | 40 | $self->comment(undef); | 
| 449 | 9 |  |  |  |  | 34 | $self->value(undef); | 
| 450 | 9 |  |  |  |  | 26 | $self->type( "END" ); | 
| 451 | 9 |  |  |  |  | 28 | $self->card( $card ); # store it after storing indiv components | 
| 452 | 9 |  |  |  |  | 25 | return("END", undef, undef); | 
| 453 |  |  |  |  |  |  | } | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | # This will be a blank line but will not trigger here if we | 
| 456 |  |  |  |  |  |  | # are padding to 80 characters | 
| 457 | 1082 | 50 |  |  |  | 1996 | if (length($card) == 0) { | 
| 458 | 0 |  |  |  |  | 0 | $self->type( "BLANK" ); | 
| 459 | 0 |  |  |  |  | 0 | return( undef, undef, undef); | 
| 460 |  |  |  |  |  |  | } | 
| 461 |  |  |  |  |  |  |  | 
| 462 |  |  |  |  |  |  | # Check for comment or HISTORY | 
| 463 |  |  |  |  |  |  | # If the card is not padded this may trigger a warning on the | 
| 464 |  |  |  |  |  |  | # substr going out of bounds | 
| 465 | 1082 | 100 | 100 |  |  | 5166 | if ($keyword eq 'COMMENT' || $keyword eq 'HISTORY' || | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 466 |  |  |  |  |  |  | (substr($card,8,2) ne "= " && $keyword !~ /^HIERARCH/)) { | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | # Store the type | 
| 469 | 42 |  |  |  |  | 151 | $self->type( "COMMENT" ); | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # We have comments | 
| 472 | 42 | 50 |  |  |  | 100 | unless ( length( $card) <= 8 ) { | 
| 473 | 42 |  |  |  |  | 88 | $comment = substr($card,8); | 
| 474 | 42 |  |  |  |  | 232 | $comment =~ s/\s+$//;  # Trailing spaces | 
| 475 |  |  |  |  |  |  | } else { | 
| 476 | 0 |  |  |  |  | 0 | $comment = ""; | 
| 477 |  |  |  |  |  |  | } | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | # Alasdair wanted to store this as a value | 
| 480 | 42 |  |  |  |  | 129 | $self->comment( $comment ); | 
| 481 |  |  |  |  |  |  |  | 
| 482 | 42 |  |  |  |  | 104 | $self->card( $card ); # store it after storing indiv components | 
| 483 | 42 |  |  |  |  | 118 | return ($keyword, undef, $comment); | 
| 484 |  |  |  |  |  |  | } | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | # We must have a value after '= ' | 
| 487 | 1040 |  |  |  |  | 2165 | my $rest = substr($card, $equals_col+1); | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | # Remove leading spaces | 
| 490 | 1040 |  |  |  |  | 3252 | $rest =~ s/^\s+//; | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | # Check to see if we have a string | 
| 493 | 1040 | 100 |  |  |  | 2256 | if (substr($rest,0,1) eq "'") { | 
| 494 |  |  |  |  |  |  |  | 
| 495 | 276 |  |  |  |  | 720 | $self->type( "STRING" ); | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | # Check for empty (null) string '' | 
| 498 | 276 | 100 |  |  |  | 546 | if (substr($rest,1,1) eq "'") { | 
| 499 | 1 |  |  |  |  | 2 | $value = ''; | 
| 500 | 1 |  |  |  |  | 2 | $comment = substr($rest,2); | 
| 501 | 1 |  |  |  |  | 5 | $comment =~ s/^\s+\///;  # Delete everything before the first slash | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | } else { | 
| 504 |  |  |  |  |  |  | # '' needs to be treated as an escaped ' when inside the string | 
| 505 |  |  |  |  |  |  | # Use index to search for an isolated single quote | 
| 506 | 275 |  |  |  |  | 404 | my $pos = 1; | 
| 507 | 275 |  |  |  |  | 366 | my $end = -1; | 
| 508 | 275 |  |  |  |  | 657 | while ($pos = index $rest, "'", $pos) { | 
| 509 | 276 | 50 |  |  |  | 490 | last if $pos == -1; # could not find a close quote | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | # Check for the position after this and if it is a ' | 
| 512 |  |  |  |  |  |  | # increment and loop again | 
| 513 | 276 | 100 |  |  |  | 540 | if (substr($rest, $pos+1, 1) eq "'") { | 
| 514 | 1 |  |  |  |  | 2 | $pos += 2; # Skip past next one | 
| 515 | 1 |  |  |  |  | 3 | next; | 
| 516 |  |  |  |  |  |  | } | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | # Isolated ' so this is the end of the string | 
| 519 | 275 |  |  |  |  | 368 | $end = $pos; | 
| 520 | 275 |  |  |  |  | 374 | last; | 
| 521 |  |  |  |  |  |  |  | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  |  | 
| 524 |  |  |  |  |  |  | # At this point we should have the end of the string or the | 
| 525 |  |  |  |  |  |  | # position of the last quote | 
| 526 | 275 | 50 |  |  |  | 486 | if ($end != -1) { | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | # Value | 
| 529 | 275 |  |  |  |  | 517 | $value = substr($rest,1, $pos-1); | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | # Replace '' with ' | 
| 532 | 275 |  |  |  |  | 465 | $value =~ s/''/'/; #; ' | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | # Special case a blank string | 
| 535 | 275 | 100 |  |  |  | 689 | if ($value =~ /^\s+$/) { | 
| 536 | 5 |  |  |  |  | 8 | $value = " "; | 
| 537 |  |  |  |  |  |  | } else { | 
| 538 |  |  |  |  |  |  | # Trim | 
| 539 | 270 |  |  |  |  | 672 | $value =~ s/\s+$//; | 
| 540 |  |  |  |  |  |  | } | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | # Comment | 
| 543 | 275 |  |  |  |  | 582 | $comment = substr($rest,$pos+1); # Extract post string | 
| 544 | 275 |  |  |  |  | 880 | $comment =~ s/^\s+\///;  # Delete everything before the first slash | 
| 545 | 275 |  |  |  |  | 557 | $comment =~ s/\///;  # In case there was no space before the slash | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | } else { | 
| 548 |  |  |  |  |  |  | # Never found the end so include all of it | 
| 549 | 0 |  |  |  |  | 0 | $value = substr($rest,1); | 
| 550 |  |  |  |  |  |  | # Trim | 
| 551 | 0 |  |  |  |  | 0 | $value =~ s/\s+$//; | 
| 552 |  |  |  |  |  |  |  | 
| 553 | 0 |  |  |  |  | 0 | $comment = ''; | 
| 554 |  |  |  |  |  |  | } | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | } | 
| 557 |  |  |  |  |  |  |  | 
| 558 |  |  |  |  |  |  | } else { | 
| 559 |  |  |  |  |  |  | # Non string - simply read the first thing before a slash | 
| 560 | 764 |  |  |  |  | 1340 | my $pos = index($rest, "/"); | 
| 561 | 764 | 100 |  |  |  | 1594 | if ($pos == 0) { | 
|  |  | 100 |  |  |  |  |  | 
| 562 |  |  |  |  |  |  |  | 
| 563 |  |  |  |  |  |  | # No value at all | 
| 564 | 3 |  |  |  |  | 6 | $value  = undef; | 
| 565 | 3 |  |  |  |  | 11 | $comment = substr($rest, $pos+2); | 
| 566 | 3 |  |  |  |  | 7 | $self->type("UNDEF"); | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | } elsif ($pos != -1) { | 
| 569 |  |  |  |  |  |  | # Found value and comment | 
| 570 | 757 |  |  |  |  | 1311 | $value = substr($rest, 0, $pos); | 
| 571 | 757 |  |  |  |  | 2150 | $value =~ s/\s+$//; # remove any gap to the comment | 
| 572 |  |  |  |  |  |  |  | 
| 573 |  |  |  |  |  |  | # Check for case where / is last character | 
| 574 | 757 | 50 |  |  |  | 1532 | if (length($rest) > ($pos + 1)) { | 
| 575 | 757 |  |  |  |  | 1385 | $comment = substr($rest, $pos+2); | 
| 576 | 757 |  |  |  |  | 2448 | $comment =~ s/\s+$//; | 
| 577 |  |  |  |  |  |  | } else { | 
| 578 | 0 |  |  |  |  | 0 | $comment = undef; | 
| 579 |  |  |  |  |  |  | } | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | } else { | 
| 582 |  |  |  |  |  |  | # Only found a value | 
| 583 | 4 |  |  |  |  | 22 | $value = $rest; | 
| 584 | 4 |  |  |  |  | 10 | $comment = undef; | 
| 585 |  |  |  |  |  |  | } | 
| 586 |  |  |  |  |  |  |  | 
| 587 | 764 | 100 |  |  |  | 1569 | if (defined $value) { | 
| 588 |  |  |  |  |  |  |  | 
| 589 |  |  |  |  |  |  | # Replace D or E with and e - D is not allowed as an exponent in perl | 
| 590 | 761 |  |  |  |  | 1242 | $value =~ tr/DE/ee/; | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | # Need to work out the numeric type | 
| 593 | 761 | 100 |  |  |  | 2965 | if ($value eq 'T') { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 594 | 24 |  |  |  |  | 75 | $value = 1; | 
| 595 | 24 |  |  |  |  | 66 | $self->type('LOGICAL'); | 
| 596 |  |  |  |  |  |  | } elsif ($value eq 'F') { | 
| 597 | 17 |  |  |  |  | 66 | $value = 0; | 
| 598 | 17 |  |  |  |  | 106 | $self->type('LOGICAL'); | 
| 599 |  |  |  |  |  |  | } elsif ($value =~ /\.|e/) { | 
| 600 |  |  |  |  |  |  | # float | 
| 601 | 372 |  |  |  |  | 839 | $self->type("FLOAT"); | 
| 602 |  |  |  |  |  |  | } else { | 
| 603 | 348 |  |  |  |  | 784 | $self->type("INT"); | 
| 604 |  |  |  |  |  |  | } | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | # Remove trailing spaces | 
| 607 | 761 |  |  |  |  | 2168 | $value =~ s/\s+$//; | 
| 608 |  |  |  |  |  |  | } | 
| 609 |  |  |  |  |  |  | } | 
| 610 |  |  |  |  |  |  |  | 
| 611 |  |  |  |  |  |  | # Tidy up comment | 
| 612 | 1040 | 100 |  |  |  | 1891 | if (defined $comment) { | 
| 613 | 1036 | 50 |  |  |  | 2337 | if ($comment =~ /^\s+$/) { | 
| 614 | 0 |  |  |  |  | 0 | $comment  = ' '; | 
| 615 |  |  |  |  |  |  | } else { | 
| 616 |  |  |  |  |  |  | # Trim it | 
| 617 | 1036 |  |  |  |  | 2453 | $comment =~ s/\s+$//; | 
| 618 | 1036 |  |  |  |  | 1891 | $comment =~ s/^\s+//; | 
| 619 |  |  |  |  |  |  | } | 
| 620 |  |  |  |  |  |  | } | 
| 621 |  |  |  |  |  |  |  | 
| 622 |  |  |  |  |  |  | # Store in the object | 
| 623 | 1040 |  |  |  |  | 2501 | $self->value( $value ); | 
| 624 | 1040 |  |  |  |  | 2222 | $self->comment( $comment ); | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | # Store the original card | 
| 627 |  |  |  |  |  |  | # Must be done after storing val, comm etc | 
| 628 | 1040 |  |  |  |  | 2261 | $self->card( $card ); | 
| 629 |  |  |  |  |  |  |  | 
| 630 |  |  |  |  |  |  | # Value is allowed to be '' | 
| 631 | 1040 |  |  |  |  | 2360 | return($keyword, $value, $comment); | 
| 632 |  |  |  |  |  |  |  | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  |  | 
| 635 |  |  |  |  |  |  | =item B | 
| 636 |  |  |  |  |  |  |  | 
| 637 |  |  |  |  |  |  | Compares this Item with another and returns true if the keyword, | 
| 638 |  |  |  |  |  |  | value, type and comment are all equal. | 
| 639 |  |  |  |  |  |  |  | 
| 640 |  |  |  |  |  |  | $isident = $item->equals( $item2 ); | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | =cut | 
| 643 |  |  |  |  |  |  |  | 
| 644 |  |  |  |  |  |  | sub equals { | 
| 645 | 221 |  |  | 221 | 1 | 342 | my $self = shift; | 
| 646 | 221 |  |  |  |  | 287 | my $ref = shift; | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | # Loop over the string keywords | 
| 649 | 221 |  |  |  |  | 360 | for my $method (qw/ keyword type comment /) { | 
| 650 | 663 |  |  |  |  | 1287 | my $val1 = $self->$method; | 
| 651 | 663 |  |  |  |  | 1274 | my $val2 = $ref->$method; | 
| 652 |  |  |  |  |  |  |  | 
| 653 | 663 | 100 | 66 |  |  | 1838 | if (defined $val1 && defined $val2) { | 
|  |  | 50 | 33 |  |  |  |  | 
| 654 |  |  |  |  |  |  | # These are all string comparisons | 
| 655 | 661 | 50 |  |  |  | 1375 | if ($val1 ne $val2) { | 
| 656 | 0 |  |  |  |  | 0 | return 0; | 
| 657 |  |  |  |  |  |  | } | 
| 658 |  |  |  |  |  |  | } elsif (!defined $val1 && !defined $val2) { | 
| 659 |  |  |  |  |  |  | # both undef so equal | 
| 660 |  |  |  |  |  |  | } else { | 
| 661 |  |  |  |  |  |  | # one undef, the other defined | 
| 662 | 0 |  |  |  |  | 0 | return 0; | 
| 663 |  |  |  |  |  |  | } | 
| 664 |  |  |  |  |  |  | } | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | # value comparison will depend on type | 
| 667 |  |  |  |  |  |  | # we know the types are the same | 
| 668 | 221 |  |  |  |  | 394 | my $val1 = $self->value; | 
| 669 | 221 |  |  |  |  | 378 | my $val2 = $ref->value; | 
| 670 | 221 |  |  |  |  | 356 | my $type = $self->type; | 
| 671 |  |  |  |  |  |  |  | 
| 672 | 221 | 50 | 66 |  |  | 1054 | return 0 if ((defined $val1 && !defined $val2) || | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 673 |  |  |  |  |  |  | (defined $val2 && !defined $val1)); | 
| 674 | 221 | 50 | 66 |  |  | 534 | return 1 if (!defined $val1 && !defined $val2); | 
| 675 |  |  |  |  |  |  |  | 
| 676 | 195 | 100 | 100 |  |  | 552 | if ($type eq 'FLOAT' || $type eq 'INT') { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 677 | 174 |  |  |  |  | 660 | return ( $val1 == $val2 ); | 
| 678 |  |  |  |  |  |  | } elsif ($type eq 'STRING') { | 
| 679 | 14 |  |  |  |  | 63 | return ( $val1 eq $val2 ); | 
| 680 |  |  |  |  |  |  | } elsif ($type eq 'LOGICAL') { | 
| 681 | 7 | 50 | 33 |  |  | 48 | if (($val1 && $val2) || (!$val1 && !$val2)) { | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
| 682 | 7 |  |  |  |  | 23 | return 1; | 
| 683 |  |  |  |  |  |  | } else { | 
| 684 | 0 |  |  |  |  | 0 | return 0; | 
| 685 |  |  |  |  |  |  | } | 
| 686 |  |  |  |  |  |  | } elsif ($type eq 'COMMENT') { | 
| 687 |  |  |  |  |  |  | # if we get to here we have a defined value so we should | 
| 688 |  |  |  |  |  |  | # check it even if COMMENT is meant to use COMMENT | 
| 689 | 0 |  |  |  |  | 0 | return ($val1 eq $val2); | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | } elsif ($type eq 'HEADER') { | 
| 692 | 0 |  |  |  |  | 0 | my @items1 = $val1->allitems; | 
| 693 | 0 |  |  |  |  | 0 | my @items2 = $val2->allitems; | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | # count the items | 
| 696 | 0 | 0 |  |  |  | 0 | return 0 if @items1 != @items2; | 
| 697 |  |  |  |  |  |  |  | 
| 698 | 0 |  |  |  |  | 0 | for my $i (0..$#items1) { | 
| 699 | 0 | 0 |  |  |  | 0 | return 0 if ! $items1[$i]->equals( $items2[$i] ); | 
| 700 |  |  |  |  |  |  | } | 
| 701 | 0 |  |  |  |  | 0 | return 1; | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | } elsif ($type eq 'UNDEF') { | 
| 704 |  |  |  |  |  |  | # both are undef... | 
| 705 | 0 |  |  |  |  | 0 | return 1; | 
| 706 |  |  |  |  |  |  | } else { | 
| 707 | 0 |  |  |  |  | 0 | croak "Unable to compare items of type '$type'\n"; | 
| 708 |  |  |  |  |  |  | } | 
| 709 |  |  |  |  |  |  |  | 
| 710 |  |  |  |  |  |  | # somehow we got to the end | 
| 711 | 0 |  |  |  |  | 0 | return 0; | 
| 712 |  |  |  |  |  |  | } | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | =begin __private | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | =item B<_stringify> | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | Internal routine to generate a FITS header card using the contents of | 
| 720 |  |  |  |  |  |  | the object. This rouinte should not be called directly. Use the | 
| 721 |  |  |  |  |  |  | C method to retrieve the contents. | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | $card = $item->_stringify; | 
| 724 |  |  |  |  |  |  |  | 
| 725 |  |  |  |  |  |  | The object state is not updated by this routine. | 
| 726 |  |  |  |  |  |  |  | 
| 727 |  |  |  |  |  |  | This routine is only called if the card cache has been cleared. | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | If this item points to a sub-header the stringification returns | 
| 730 |  |  |  |  |  |  | a comment indicating that we have a sub header. In the future | 
| 731 |  |  |  |  |  |  | this behaviour may change (either to return nothing, or | 
| 732 |  |  |  |  |  |  | to return the stringified header itself). | 
| 733 |  |  |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | =cut | 
| 735 |  |  |  |  |  |  |  | 
| 736 |  |  |  |  |  |  | sub _stringify { | 
| 737 | 154 |  |  | 154 |  | 222 | my $self = shift; | 
| 738 |  |  |  |  |  |  |  | 
| 739 |  |  |  |  |  |  | # Get the components | 
| 740 | 154 |  |  |  |  | 337 | my $keyword = $self->keyword; | 
| 741 | 154 |  |  |  |  | 299 | my $value = $self->value; | 
| 742 | 154 |  |  |  |  | 293 | my $comment = $self->comment; | 
| 743 | 154 |  |  |  |  | 288 | my $type = $self->type; | 
| 744 |  |  |  |  |  |  |  | 
| 745 |  |  |  |  |  |  | # Special case for HEADER type | 
| 746 | 154 | 50 | 33 |  |  | 1053 | if (defined $type && $type eq 'HEADER') { | 
| 747 | 0 |  |  |  |  | 0 | $type = "COMMENT"; | 
| 748 | 0 |  |  |  |  | 0 | $comment = "Contains a subsidiary header"; | 
| 749 |  |  |  |  |  |  | } | 
| 750 |  |  |  |  |  |  |  | 
| 751 |  |  |  |  |  |  | # Sort out the keyword. This always uses up the first 8 characters | 
| 752 | 154 |  |  |  |  | 556 | my $card = sprintf("%-8s", $keyword); | 
| 753 |  |  |  |  |  |  |  | 
| 754 |  |  |  |  |  |  | # End card and Comments first | 
| 755 | 154 | 100 | 66 |  |  | 1114 | if (defined $type && $type eq 'END' ) { | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  | 50 | 0 |  |  |  |  | 
| 756 | 5 |  |  |  |  | 16 | $card = sprintf("%-10s%-70s", $card, ""); | 
| 757 |  |  |  |  |  |  |  | 
| 758 |  |  |  |  |  |  | } elsif (defined $type && $type eq 'BLANK') { | 
| 759 | 0 |  |  |  |  | 0 | $card = " " x 80; | 
| 760 |  |  |  |  |  |  | } elsif (defined $type && $type eq 'COMMENT') { | 
| 761 |  |  |  |  |  |  |  | 
| 762 |  |  |  |  |  |  | # Comments are from character 9 - 80 | 
| 763 | 10 | 50 |  |  |  | 48 | $card = sprintf("%-8s%-72s", $card, (defined $comment ? $comment : '')); | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  | } elsif (!defined $type && !defined $value && !defined $comment) { | 
| 766 |  |  |  |  |  |  |  | 
| 767 |  |  |  |  |  |  | # This is a blank line | 
| 768 | 0 |  |  |  |  | 0 | $card = " " x 80; | 
| 769 |  |  |  |  |  |  |  | 
| 770 |  |  |  |  |  |  | } else { | 
| 771 |  |  |  |  |  |  | # A real keyword/value so add the "= " | 
| 772 | 139 |  |  |  |  | 334 | $card .= "= "; | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  | # Try to sort out the type if we havent got one | 
| 775 |  |  |  |  |  |  | # We can not find LOGICAL this way since we can't | 
| 776 |  |  |  |  |  |  | # tell the difference between 'F' and F | 
| 777 |  |  |  |  |  |  | # an undefined value is typeless | 
| 778 | 139 | 50 |  |  |  | 236 | unless (defined $type) { | 
| 779 | 0 |  |  |  |  | 0 | $type = $self->guess_type( $value ); | 
| 780 |  |  |  |  |  |  | } | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | # Numbers behave identically whether they are float or int | 
| 783 |  |  |  |  |  |  | # Logical is a number formatted as a "T" or "F" | 
| 784 | 139 | 100 | 100 |  |  | 563 | if ($type eq 'INT' or $type eq 'FLOAT' or $type eq 'LOGICAL' or | 
|  |  | 50 | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 785 |  |  |  |  |  |  | $type eq 'UNDEF') { | 
| 786 |  |  |  |  |  |  |  | 
| 787 |  |  |  |  |  |  | # Change the value for logical | 
| 788 | 106 | 100 |  |  |  | 190 | if ($type eq 'LOGICAL') { | 
| 789 | 7 | 100 | 66 |  |  | 26 | $value = ( ($value && ($value ne 'F')) ? 'T' : 'F' ); | 
| 790 |  |  |  |  |  |  | } | 
| 791 |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  | # An undefined value should simply propogate as an empty | 
| 793 | 106 | 100 |  |  |  | 193 | $value = '' unless defined $value; | 
| 794 |  |  |  |  |  |  |  | 
| 795 |  |  |  |  |  |  | # A number can only be up to 67 characters long but | 
| 796 |  |  |  |  |  |  | # Should we raise an error if it is longer? We should | 
| 797 |  |  |  |  |  |  | # not truncate | 
| 798 | 106 |  |  |  |  | 238 | $value = substr($value,0,67); | 
| 799 |  |  |  |  |  |  |  | 
| 800 | 106 |  |  |  |  | 275 | $value = (' 'x(20-length($value))).$value; | 
| 801 |  |  |  |  |  |  |  | 
| 802 |  |  |  |  |  |  | # Translate lower case e to upper | 
| 803 |  |  |  |  |  |  | # Probably should test length of exponent to decide | 
| 804 |  |  |  |  |  |  | # whether we should be using D instead of E | 
| 805 |  |  |  |  |  |  | # [depends whether the argument is stringified or not] | 
| 806 | 106 |  |  |  |  | 275 | $value =~ tr /ed/ED/; | 
| 807 |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  | } elsif ($type eq 'STRING') { | 
| 809 |  |  |  |  |  |  |  | 
| 810 |  |  |  |  |  |  | # Check that a value is there | 
| 811 |  |  |  |  |  |  | # There is a distinction between '''' and nothing '' | 
| 812 | 33 | 50 |  |  |  | 65 | if (defined $value) { | 
| 813 |  |  |  |  |  |  |  | 
| 814 |  |  |  |  |  |  | # Escape single quotes | 
| 815 | 33 |  |  |  |  | 94 | $value =~ s/'/''/g;  #'; | 
| 816 |  |  |  |  |  |  |  | 
| 817 |  |  |  |  |  |  | # chop to 65 characters | 
| 818 | 33 |  |  |  |  | 70 | $value = substr($value,0, 65); | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | # if the string has less than 8 characters pad it to put the | 
| 821 |  |  |  |  |  |  | # closing quote at CHAR 20 | 
| 822 | 33 | 100 |  |  |  | 73 | if (length($value) < 8 ) { | 
| 823 | 20 | 100 |  |  |  | 63 | $value = $value.(' 'x(8-length($value))) unless length($value) == 0; | 
| 824 |  |  |  |  |  |  | } | 
| 825 | 33 |  |  |  |  | 69 | $value = "'$value'"; | 
| 826 |  |  |  |  |  |  |  | 
| 827 |  |  |  |  |  |  | } else { | 
| 828 | 0 |  |  |  |  | 0 | $value = ''; # undef is an empty FITS string | 
| 829 |  |  |  |  |  |  | } | 
| 830 |  |  |  |  |  |  |  | 
| 831 |  |  |  |  |  |  | # Pad goes reverse way to a number | 
| 832 | 33 |  |  |  |  | 286 | $value = $value.(' 'x(20-length($value))); | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | } else { | 
| 835 | 0 |  |  |  |  | 0 | carp("Type '$type' is not a recognized type. Header creation may be incorrect"); | 
| 836 |  |  |  |  |  |  | } | 
| 837 |  |  |  |  |  |  |  | 
| 838 |  |  |  |  |  |  | # Add the comment | 
| 839 | 139 | 100 | 66 |  |  | 448 | if (defined $comment && length($comment) > 0) { | 
| 840 | 138 |  |  |  |  | 320 | $card .= $value . ' / ' . $comment; | 
| 841 |  |  |  |  |  |  | } else { | 
| 842 | 1 |  |  |  |  | 3 | $card .= $value; | 
| 843 |  |  |  |  |  |  | } | 
| 844 |  |  |  |  |  |  |  | 
| 845 |  |  |  |  |  |  | # Fix at 80 characters | 
| 846 | 139 |  |  |  |  | 249 | $card = substr($card,0,80); | 
| 847 | 139 |  |  |  |  | 295 | $card .= ' 'x(80-length($card)); | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  | } | 
| 850 |  |  |  |  |  |  |  | 
| 851 |  |  |  |  |  |  | # Return the result | 
| 852 | 154 |  |  |  |  | 350 | return $card; | 
| 853 |  |  |  |  |  |  |  | 
| 854 |  |  |  |  |  |  | } | 
| 855 |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  | =item B | 
| 857 |  |  |  |  |  |  |  | 
| 858 |  |  |  |  |  |  | This class method can be used to guess the data type of a supplied value. | 
| 859 |  |  |  |  |  |  | It is private but can be used by other classes in the Astro::FITS::Header | 
| 860 |  |  |  |  |  |  | hierarchy. | 
| 861 |  |  |  |  |  |  |  | 
| 862 |  |  |  |  |  |  | $type = Astro::FITS::Header::Item->guess_type( $value ); | 
| 863 |  |  |  |  |  |  |  | 
| 864 |  |  |  |  |  |  | Can not distinguish a string F from a LOGICAL F so will always guess | 
| 865 |  |  |  |  |  |  | "string". Returns "string" if a type could not be determined. | 
| 866 |  |  |  |  |  |  |  | 
| 867 |  |  |  |  |  |  | =cut | 
| 868 |  |  |  |  |  |  |  | 
| 869 |  |  |  |  |  |  | sub guess_type { | 
| 870 | 20 |  |  | 20 | 1 | 34 | my $self = shift; | 
| 871 | 20 |  |  |  |  | 26 | my $value = shift; | 
| 872 | 20 |  |  |  |  | 31 | my $type; | 
| 873 | 20 | 100 |  |  |  | 61 | if (!defined $value) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 874 | 17 |  |  |  |  | 31 | $type = "UNDEF"; | 
| 875 |  |  |  |  |  |  | } elsif ($value =~ /^\d+$/) { | 
| 876 | 3 |  |  |  |  | 5 | $type = "INT"; | 
| 877 |  |  |  |  |  |  | } elsif ($value =~ /^(-?)(\d*)(\.?)(\d*)([EeDd][-\+]?\d+)?$/) { | 
| 878 | 0 |  |  |  |  | 0 | $type = "FLOAT"; | 
| 879 |  |  |  |  |  |  | } else { | 
| 880 | 0 |  |  |  |  | 0 | $type = "STRING"; | 
| 881 |  |  |  |  |  |  | } | 
| 882 | 20 |  |  |  |  | 37 | return $type; | 
| 883 |  |  |  |  |  |  | } | 
| 884 |  |  |  |  |  |  |  | 
| 885 |  |  |  |  |  |  | =end __private | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | =back | 
| 888 |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 890 |  |  |  |  |  |  |  | 
| 891 |  |  |  |  |  |  | C | 
| 892 |  |  |  |  |  |  |  | 
| 893 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 894 |  |  |  |  |  |  |  | 
| 895 |  |  |  |  |  |  | Copyright (C) 2008-2009 Science and Technology Facilities Council. | 
| 896 |  |  |  |  |  |  | Copyright (C) 2001-2007 Particle Physics and Astronomy Research Council. | 
| 897 |  |  |  |  |  |  | All Rights Reserved. | 
| 898 |  |  |  |  |  |  |  | 
| 899 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it under | 
| 900 |  |  |  |  |  |  | the terms of the GNU General Public License as published by the Free Software | 
| 901 |  |  |  |  |  |  | Foundation; either version 3 of the License, or (at your option) any later | 
| 902 |  |  |  |  |  |  | version. | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | This program is distributed in the hope that it will be useful,but WITHOUT ANY | 
| 905 |  |  |  |  |  |  | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | 
| 906 |  |  |  |  |  |  | PARTICULAR PURPOSE. See the GNU General Public License for more details. | 
| 907 |  |  |  |  |  |  |  | 
| 908 |  |  |  |  |  |  | You should have received a copy of the GNU General Public License along with | 
| 909 |  |  |  |  |  |  | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
| 910 |  |  |  |  |  |  | Place,Suite 330, Boston, MA  02111-1307, USA | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | =head1 AUTHORS | 
| 913 |  |  |  |  |  |  |  | 
| 914 |  |  |  |  |  |  | Tim Jenness Et.jenness@jach.hawaii.eduE, | 
| 915 |  |  |  |  |  |  | Alasdair Allan Eaa@astro.ex.ac.ukE | 
| 916 |  |  |  |  |  |  |  | 
| 917 |  |  |  |  |  |  | =cut | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | 1; |