| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Astro::FITS::Header; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # --------------------------------------------------------------------------- | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | =head1 NAME | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | Astro::FITS::Header - Object Orientated interface to FITS HDUs | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | $header = new Astro::FITS::Header( Cards => \@array ); | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | Stores information about a FITS header block in an object. Takes an hash | 
| 16 |  |  |  |  |  |  | with an array reference as an argument. The array should contain a list | 
| 17 |  |  |  |  |  |  | of FITS header cards as input. | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | =cut | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | # L O A D   M O D U L E S -------------------------------------------------- | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 10 |  |  | 10 |  | 114416 | use strict; | 
|  | 10 |  |  |  |  | 41 |  | 
|  | 10 |  |  |  |  | 377 |  | 
| 24 | 10 |  |  | 10 |  | 68 | use vars qw/ $VERSION /; | 
|  | 10 |  |  |  |  | 45 |  | 
|  | 10 |  |  |  |  | 555 |  | 
| 25 | 10 |  |  | 10 |  | 55 | use Carp; | 
|  | 10 |  |  |  |  | 26 |  | 
|  | 10 |  |  |  |  | 871 |  | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 10 |  |  | 10 |  | 4051 | use Astro::FITS::Header::Item; | 
|  | 10 |  |  |  |  | 66 |  | 
|  | 10 |  |  |  |  | 425 |  | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | $VERSION = '3.09'; | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | # Operator overloads | 
| 32 | 10 |  |  |  |  | 44 | use overload '""' => "stringify", | 
| 33 | 10 |  |  | 10 |  | 73 | fallback => 1; | 
|  | 10 |  |  |  |  | 24 |  | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | # C O N S T R U C T O R ---------------------------------------------------- | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | =head1 METHODS | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | =head2 Constructor | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | =over 4 | 
| 42 |  |  |  |  |  |  |  | 
| 43 |  |  |  |  |  |  | =item B | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | Create a new instance from an array of FITS header cards. | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | $item = new Astro::FITS::Header( Cards => \@header ); | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | returns a reference to a Header object.  If you pass in no cards, | 
| 50 |  |  |  |  |  |  | you get the (required) first SIMPLE card for free. | 
| 51 |  |  |  |  |  |  |  | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | =cut | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | sub new { | 
| 56 | 41 |  |  | 41 | 1 | 5502 | my $proto = shift; | 
| 57 | 41 |  | 66 |  |  | 643 | my $class = ref($proto) || $proto; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | # bless the header block into the class | 
| 60 | 41 |  |  |  |  | 203 | my $block = bless { HEADER => [], | 
| 61 |  |  |  |  |  |  | LOOKUP  => {}, | 
| 62 |  |  |  |  |  |  | LASTKEY => undef, | 
| 63 |  |  |  |  |  |  | TieRetRef => 0, | 
| 64 |  |  |  |  |  |  | SUBHDRS => [], | 
| 65 |  |  |  |  |  |  | }, $class; | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | # Configure the object, even with no arguments since configure | 
| 68 |  |  |  |  |  |  | # still puts the minimum SIMPLE card in. | 
| 69 | 41 |  |  |  |  | 131 | $block->configure( @_ ); | 
| 70 |  |  |  |  |  |  |  | 
| 71 | 41 |  |  |  |  | 151 | return $block; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  |  | 
| 75 |  |  |  |  |  |  | # I T E M ------------------------------------------------------------------ | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | =back | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | =head2 Accessor Methods | 
| 80 |  |  |  |  |  |  |  | 
| 81 |  |  |  |  |  |  | =over 4 | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | =item B | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | Indicates whether the tied object should return multiple values | 
| 86 |  |  |  |  |  |  | as a single string joined by newline characters (false) or | 
| 87 |  |  |  |  |  |  | it should return a reference to an array containing all the values. | 
| 88 |  |  |  |  |  |  |  | 
| 89 |  |  |  |  |  |  | Only affects the tied interface. | 
| 90 |  |  |  |  |  |  |  | 
| 91 |  |  |  |  |  |  | tie %keywords, "Astro::FITS::Header", $header, tiereturnsref => 1; | 
| 92 |  |  |  |  |  |  | $ref = $keywords{COMMENT}; | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | Defaults to returning a single string in all cases (for backwards | 
| 95 |  |  |  |  |  |  | compatibility) | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | =cut | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | sub tiereturnsref { | 
| 100 | 356 |  |  | 356 | 1 | 3129 | my $self = shift; | 
| 101 | 356 | 100 |  |  |  | 732 | if (@_) { | 
| 102 | 4 |  |  |  |  | 9 | $self->{TieRetRef} = shift; | 
| 103 |  |  |  |  |  |  | } | 
| 104 | 356 |  |  |  |  | 938 | return $self->{TieRetRef}; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | =item B | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | Set or return the subheaders for a Header object. Arguments must be | 
| 110 |  |  |  |  |  |  | given as C objects. | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | $header->subhdrs(@hdrs); | 
| 113 |  |  |  |  |  |  | @hdrs = $header->subhdrs; | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | This method should be used when you have additional header components | 
| 116 |  |  |  |  |  |  | that should be associated with the primary header but they are not | 
| 117 |  |  |  |  |  |  | associated with a particular name, just an ordering. | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | FITS headers that are associated with a name can be stored directly | 
| 120 |  |  |  |  |  |  | in the header using an C of type 'HEADER'. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | =cut | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | sub subhdrs { | 
| 125 | 22 |  |  | 22 | 1 | 53 | my $self = shift; | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 22 | 100 |  |  |  | 61 | if (@_) { | 
| 128 |  |  |  |  |  |  | # verify the class | 
| 129 | 2 |  |  |  |  | 14 | my $i; | 
| 130 | 2 |  |  |  |  | 38 | for my $h (@_) { | 
| 131 | 4 | 50 |  |  |  | 16 | croak "Argument $i supplied to subhdrs method is not a Astro::FITS::Header object\n" | 
| 132 |  |  |  |  |  |  | unless UNIVERSAL::isa( $h, "Astro::FITS::Header" ); | 
| 133 | 4 |  |  |  |  | 8 | $i++; | 
| 134 |  |  |  |  |  |  | } | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | # store them | 
| 137 | 2 |  |  |  |  | 19 | @{$self->{SUBHDRS}} = @_; | 
|  | 2 |  |  |  |  | 6 |  | 
| 138 |  |  |  |  |  |  | } | 
| 139 | 22 | 100 |  |  |  | 48 | if (wantarray()) { | 
| 140 | 1 |  |  |  |  | 1 | return @{$self->{SUBHDRS}}; | 
|  | 1 |  |  |  |  | 4 |  | 
| 141 |  |  |  |  |  |  | } else { | 
| 142 | 21 |  |  |  |  | 118 | return $self->{SUBHDRS}; | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | =item B   | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | Returns a FITS::Header:Item object referenced by index, C if it | 
| 149 |  |  |  |  |  |  | does not exist. | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | $item = $header->item($index); | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =cut | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | sub item { | 
| 156 | 539 |  |  | 539 | 1 | 323940 | my ( $self, $index ) = @_; | 
| 157 |  |  |  |  |  |  |  | 
| 158 | 539 | 50 |  |  |  | 1371 | return undef unless defined $index; | 
| 159 | 539 | 50 |  |  |  | 777 | return undef unless exists ${$self->{HEADER}}[$index]; | 
|  | 539 |  |  |  |  | 1385 |  | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # grab and return the Header::Item at $index | 
| 162 | 539 |  |  |  |  | 789 | return ${$self->{HEADER}}[$index]; | 
|  | 539 |  |  |  |  | 1297 |  | 
| 163 |  |  |  |  |  |  | } | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | =item B | 
| 167 |  |  |  |  |  |  |  | 
| 168 |  |  |  |  |  |  | Returns a Starlink::AST FrameSet object representing the WCS of the | 
| 169 |  |  |  |  |  |  | FITS Header. | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | $ast = $header->get_wcs(); | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | =cut | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | sub get_wcs { | 
| 176 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 0 |  |  |  |  | 0 | require Starlink::AST; | 
| 179 | 0 |  |  |  |  | 0 | my $fchan = Starlink::AST::FitsChan->new(); | 
| 180 | 0 |  |  |  |  | 0 | for my $i ( $self->cards() ) { | 
| 181 | 0 |  |  |  |  | 0 | $fchan->PutFits( $i, 0); | 
| 182 |  |  |  |  |  |  | } | 
| 183 | 0 |  |  |  |  | 0 | $fchan->Clear( "Card" ); | 
| 184 | 0 |  |  |  |  | 0 | return $fchan->Read(); | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | # K E Y W O R D ------------------------------------------------------------ | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | =item B | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | Returns keyword referenced by index, C if it does not exist. | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | $keyword = $header->keyword($index); | 
| 196 |  |  |  |  |  |  |  | 
| 197 |  |  |  |  |  |  | =cut | 
| 198 |  |  |  |  |  |  |  | 
| 199 |  |  |  |  |  |  | sub keyword { | 
| 200 | 249 |  |  | 249 | 1 | 94153 | my ( $self, $index ) = @_; | 
| 201 |  |  |  |  |  |  |  | 
| 202 | 249 | 50 |  |  |  | 568 | return undef unless defined $index; | 
| 203 | 249 | 100 |  |  |  | 350 | return undef unless exists ${$self->{HEADER}}[$index]; | 
|  | 249 |  |  |  |  | 696 |  | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | # grab and return the keyword at $index | 
| 206 | 247 |  |  |  |  | 388 | return ${$self->{HEADER}}[$index]->keyword(); | 
|  | 247 |  |  |  |  | 658 |  | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | # I T E M   B Y   N A M E  ------------------------------------------------- | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | =item B | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | Returns an array of Header::Items for the requested keyword if called | 
| 214 |  |  |  |  |  |  | in list context, or the first matching Header::Item if called in scalar | 
| 215 |  |  |  |  |  |  | context. Returns C if the keyword does not exist.  The keyword | 
| 216 |  |  |  |  |  |  | may be a regular expression created with the C operator. | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | @items = $header->itembyname($keyword); | 
| 219 |  |  |  |  |  |  | $item = $header->itembyname($keyword); | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | =cut | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | sub itembyname { | 
| 226 | 60 |  |  | 60 | 1 | 867 | my ( $self, $keyword ) = @_; | 
| 227 |  |  |  |  |  |  |  | 
| 228 | 60 |  |  |  |  | 155 | my @items = @{$self->{HEADER}}[$self->index($keyword)]; | 
|  | 60 |  |  |  |  | 164 |  | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 60 | 100 |  |  |  | 238 | return wantarray ?  @items : @items ? $items[0] : undef; | 
|  |  | 100 |  |  |  |  |  | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | } | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | # I T E M   B Y   T Y P E  ------------------------------------------------- | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | =item B | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | Returns an array of Header::Items for the requested type if called in | 
| 239 |  |  |  |  |  |  | list context, or the first matching Header::Item if called in scalar | 
| 240 |  |  |  |  |  |  | context. See C for a list of allowed types. | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | @items = $header->itembytype( "COMMENT" ); | 
| 243 |  |  |  |  |  |  | @items = $header->itembytype( "HEADER" ); | 
| 244 |  |  |  |  |  |  | $item = $header->itembytype( "INT" ); | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | =cut | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | sub itembytype { | 
| 249 | 1 |  |  | 1 | 1 | 678 | my ( $self, $type ) = @_; | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 1 | 50 |  |  |  | 15 | return () unless defined $type; | 
| 252 |  |  |  |  |  |  |  | 
| 253 | 1 |  |  |  |  | 7 | $type = uc($type); | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | # No optimised lookup so brute force it | 
| 256 | 1 |  |  |  |  | 2 | my @items = grep { $_->type eq $type } @{ $self->{HEADER} }; | 
|  | 123 |  |  |  |  | 222 |  | 
|  | 1 |  |  |  |  | 4 |  | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 1 | 0 |  |  |  | 10 | return wantarray ?  @items : @items ? $items[0] : undef; | 
|  |  | 50 |  |  |  |  |  | 
| 259 |  |  |  |  |  |  |  | 
| 260 |  |  |  |  |  |  | } | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | # I N D E X   -------------------------------------------------------------- | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | =item B | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | Returns an array of indices for the requested keyword if called in | 
| 267 |  |  |  |  |  |  | list context, or an empty array if it does not exist.  The keyword may | 
| 268 |  |  |  |  |  |  | be a regular expression created with the C operator. | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | @index = $header->index($keyword); | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | If called in scalar context it returns the first item in the array, or | 
| 273 |  |  |  |  |  |  | C if the keyword does not exist. | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | $index = $header->index($keyword); | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | =cut | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | sub index { | 
| 280 | 385 |  |  | 385 | 1 | 1294 | my ( $self, $keyword ) = @_; | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | # grab the index array from lookup table | 
| 283 | 385 |  |  |  |  | 597 | my @index; | 
| 284 |  |  |  |  |  |  |  | 
| 285 | 385 | 100 |  |  |  | 782 | if ( 'Regexp' eq ref $keyword ) { | 
| 286 | 13 |  |  |  |  | 27 | push @index, @{$self->{LOOKUP}{$_}} | 
| 287 | 2 |  |  |  |  | 6 | foreach grep { /$keyword/ && | 
| 288 | 233 | 100 |  |  |  | 661 | defined $self->{LOOKUP}{$_} } keys %{$self->{LOOKUP}}; | 
|  | 2 |  |  |  |  | 44 |  | 
| 289 | 2 |  |  |  |  | 45 | @index = sort @index; | 
| 290 |  |  |  |  |  |  | } else { | 
| 291 | 360 |  |  |  |  | 506 | @index = @{${$self->{LOOKUP}}{$keyword}} | 
|  | 360 |  |  |  |  | 874 |  | 
| 292 | 383 |  |  |  |  | 1184 | if ( exists ${$self->{LOOKUP}}{$keyword} && | 
| 293 | 383 | 100 | 66 |  |  | 538 | defined ${$self->{LOOKUP}}{$keyword} ); | 
|  | 360 |  |  |  |  | 1175 |  | 
| 294 |  |  |  |  |  |  | } | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | # return the values array | 
| 297 | 385 | 50 |  |  |  | 1179 | return wantarray ? @index : @index ? $index[0] : undef; | 
|  |  | 100 |  |  |  |  |  | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | } | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | # V A L U E  --------------------------------------------------------------- | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | =item B | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | Returns an array of values for the requested keyword if called in list | 
| 306 |  |  |  |  |  |  | context, or an empty array if it does not exist.  The keyword may be | 
| 307 |  |  |  |  |  |  | a regular expression created with the C operator. | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | @value = $header->value($keyword); | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | If called in scalar context it returns the first item in the array, or | 
| 312 |  |  |  |  |  |  | C if the keyword does not exist. | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | =cut | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | sub value { | 
| 317 | 295 |  |  | 295 | 1 | 2069 | my ( $self, $keyword ) = @_; | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | # resolve the values from the index array from lookup table | 
| 320 | 295 |  |  |  |  | 673 | my @values = map { ${$self->{HEADER}}[$_]->value() } $self->index($keyword); | 
|  | 302 |  |  |  |  | 439 |  | 
|  | 302 |  |  |  |  | 906 |  | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | # loop over the indices and grab the values | 
| 323 | 295 | 50 |  |  |  | 929 | return wantarray ? @values : @values ? $values[0] : undef; | 
|  |  | 100 |  |  |  |  |  | 
| 324 |  |  |  |  |  |  |  | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | # C O M M E N T ------------------------------------------------------------- | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | =item B | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | Returns an array of comments for the requested keyword if called | 
| 332 |  |  |  |  |  |  | in list context, or an empty array if it does not exist.  The keyword | 
| 333 |  |  |  |  |  |  | may be a regular expression created with the C operator. | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | @comment = $header->comment($keyword); | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | If called in scalar context it returns the first item in the array, or | 
| 338 |  |  |  |  |  |  | C if the keyword does not exist. | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | $comment = $header->comment($keyword); | 
| 341 |  |  |  |  |  |  |  | 
| 342 |  |  |  |  |  |  | =cut | 
| 343 |  |  |  |  |  |  |  | 
| 344 |  |  |  |  |  |  | sub comment { | 
| 345 | 14 |  |  | 14 | 1 | 1526 | my ( $self, $keyword ) = @_; | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | # resolve the comments from the index array from lookup table | 
| 348 |  |  |  |  |  |  | my @comments = | 
| 349 | 14 |  |  |  |  | 27 | map { ${$self->{HEADER}}[$_]->comment() } $self->index($keyword); | 
|  | 26 |  |  |  |  | 35 |  | 
|  | 26 |  |  |  |  | 62 |  | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | # loop over the indices and grab the comments | 
| 352 | 14 | 0 |  |  |  | 46 | return wantarray ?  @comments : @comments ? $comments[0] : undef; | 
|  |  | 50 |  |  |  |  |  | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | # I N S E R T ------------------------------------------------------------- | 
| 356 |  |  |  |  |  |  |  | 
| 357 |  |  |  |  |  |  | =item B | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | Inserts a FITS header card object at position $index | 
| 360 |  |  |  |  |  |  |  | 
| 361 |  |  |  |  |  |  | $header->insert($index, $item); | 
| 362 |  |  |  |  |  |  |  | 
| 363 |  |  |  |  |  |  | the object $item is not copied, multiple inserts of the same object mean | 
| 364 |  |  |  |  |  |  | that future modifications to the one instance of the inserted object will | 
| 365 |  |  |  |  |  |  | modify all inserted copies. | 
| 366 |  |  |  |  |  |  |  | 
| 367 |  |  |  |  |  |  | The insert position can be negative. | 
| 368 |  |  |  |  |  |  |  | 
| 369 |  |  |  |  |  |  | =cut | 
| 370 |  |  |  |  |  |  |  | 
| 371 |  |  |  |  |  |  | sub insert{ | 
| 372 | 22 |  |  | 22 | 1 | 4192 | my ($self, $index, $item) = @_; | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # splice the new FITS header card into the array | 
| 375 |  |  |  |  |  |  | # Splice automatically triggers a lookup table rebuild | 
| 376 | 22 |  |  |  |  | 66 | $self->splice($index, 0, $item); | 
| 377 |  |  |  |  |  |  |  | 
| 378 | 22 |  |  |  |  | 41 | return; | 
| 379 |  |  |  |  |  |  | } | 
| 380 |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  |  | 
| 382 |  |  |  |  |  |  | # R E P L A C E ------------------------------------------------------------- | 
| 383 |  |  |  |  |  |  |  | 
| 384 |  |  |  |  |  |  | =item B | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | Replace FITS header card at index $index with card $item | 
| 387 |  |  |  |  |  |  |  | 
| 388 |  |  |  |  |  |  | $card = $header->replace($index, $item); | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | returns the replaced card. | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | =cut | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  | sub replace{ | 
| 395 | 1 |  |  | 1 | 1 | 4 | my ($self, $index, $item) = @_; | 
| 396 |  |  |  |  |  |  | # remove the specified item and replace with $item | 
| 397 |  |  |  |  |  |  | # Splice triggers a rebuild so we do not have to | 
| 398 | 1 |  |  |  |  | 7 | return $self->splice( $index, 1, $item); | 
| 399 |  |  |  |  |  |  | } | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | # R E M O V E ------------------------------------------------------------- | 
| 402 |  |  |  |  |  |  |  | 
| 403 |  |  |  |  |  |  | =item B | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | Removes a FITS header card object at position $index | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | $card = $header->remove($index); | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | returns the removed card. | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | =cut | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | sub remove{ | 
| 414 | 4 |  |  | 4 | 1 | 659 | my ($self, $index) = @_; | 
| 415 |  |  |  |  |  |  | # remove the  FITS header card from the array | 
| 416 |  |  |  |  |  |  | # Splice always triggers a lookup table rebuild so we don't have to | 
| 417 | 4 |  |  |  |  | 13 | return $self->splice( $index, 1); | 
| 418 |  |  |  |  |  |  | } | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | # R E P L A C E  B Y  N A M E --------------------------------------------- | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | =item B | 
| 423 |  |  |  |  |  |  |  | 
| 424 |  |  |  |  |  |  | Replace FITS header cards with keyword $keyword with card $item | 
| 425 |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  | $card = $header->replacebyname($keyword, $item); | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | returns the replaced card. The keyword may be a regular expression | 
| 429 |  |  |  |  |  |  | created with the C operator. | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | =cut | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | sub replacebyname{ | 
| 434 | 1 |  |  | 1 | 1 | 655 | my ($self, $keyword, $item) = @_; | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | # grab the index array from lookup table | 
| 437 | 1 |  |  |  |  | 6 | my @index = $self->index($keyword); | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | # loop over the keywords | 
| 440 |  |  |  |  |  |  | # We use a real splice rather than the class splice for efficiency | 
| 441 |  |  |  |  |  |  | # in order to prevent an index rebuild for each index | 
| 442 | 1 |  |  |  |  | 10 | my @cards = map { splice @{$self->{HEADER}}, $_, 1, $item;} @index; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | # force rebuild | 
| 445 | 1 |  |  |  |  | 8 | $self->_rebuild_lookup; | 
| 446 |  |  |  |  |  |  |  | 
| 447 |  |  |  |  |  |  | # return removed items | 
| 448 | 1 | 50 |  |  |  | 7 | return wantarray ? @cards : $cards[scalar(@cards)-1]; | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | } | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | # R E M O V E  B Y   N A M E ----------------------------------------------- | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | =item B | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | Removes a FITS header card object by name | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | @card = $header->removebyname($keyword); | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | returns the removed cards.  The keyword may be a regular expression | 
| 461 |  |  |  |  |  |  | created with the C operator. | 
| 462 |  |  |  |  |  |  |  | 
| 463 |  |  |  |  |  |  | =cut | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | sub removebyname{ | 
| 466 | 6 |  |  | 6 | 1 | 48 | my ($self, $keyword) = @_; | 
| 467 |  |  |  |  |  |  |  | 
| 468 |  |  |  |  |  |  | # grab the index array from lookup table | 
| 469 | 6 |  |  |  |  | 17 | my @index = $self->index($keyword); | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # loop over the keywords | 
| 472 |  |  |  |  |  |  | # We use a real splice rather than the class splice for efficiency | 
| 473 |  |  |  |  |  |  | # in order to prevent an index rebuild for each index. The ugly code | 
| 474 |  |  |  |  |  |  | # is needed in case we have multiple indices returned, which can | 
| 475 |  |  |  |  |  |  | # happen if we have a regular expression passed in as a keyword. | 
| 476 | 6 |  |  |  |  | 25 | my $i = -1; | 
| 477 | 6 |  |  |  |  | 25 | my @cards = map { $i++; splice @{$self->{HEADER}}, ( $_ - $i ), 1; } sort @index; | 
|  | 11 |  |  |  |  | 18 |  | 
|  | 11 |  |  |  |  | 16 |  | 
|  | 11 |  |  |  |  | 33 |  | 
| 478 |  |  |  |  |  |  |  | 
| 479 |  |  |  |  |  |  | # force rebuild | 
| 480 | 6 |  |  |  |  | 26 | $self->_rebuild_lookup; | 
| 481 |  |  |  |  |  |  |  | 
| 482 |  |  |  |  |  |  | # return removed items | 
| 483 | 6 | 50 |  |  |  | 49 | return wantarray ? @cards : $cards[scalar(@cards)-1]; | 
| 484 |  |  |  |  |  |  | } | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | # S P L I C E -------------------------------------------------------------- | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | =item B | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | Implements a standard splice operation for FITS headers | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | @cards = $header->splice($offset [,$length [, @list]]); | 
| 493 |  |  |  |  |  |  | $last_card = $header->splice($offset [,$length [, @list]]); | 
| 494 |  |  |  |  |  |  |  | 
| 495 |  |  |  |  |  |  | Removes the FITS header cards from the header designated by $offset and | 
| 496 |  |  |  |  |  |  | $length, and replaces them with @list (if specified) which must be an | 
| 497 |  |  |  |  |  |  | array of FITS::Header::Item objects. Returns the cards removed. If offset | 
| 498 |  |  |  |  |  |  | is negative, counts from the end of the FITS header. | 
| 499 |  |  |  |  |  |  |  | 
| 500 |  |  |  |  |  |  | =cut | 
| 501 |  |  |  |  |  |  |  | 
| 502 |  |  |  |  |  |  | sub splice { | 
| 503 | 29 |  |  | 29 | 1 | 46 | my $self = shift; | 
| 504 | 29 |  |  |  |  | 57 | my ($offset, $length, @list) = @_; | 
| 505 |  |  |  |  |  |  |  | 
| 506 |  |  |  |  |  |  | # If the array is empty and we get a negative offset we | 
| 507 |  |  |  |  |  |  | # must convert it to an offset of 0 to prevent a: | 
| 508 |  |  |  |  |  |  | #   Modification of non-creatable array value attempted, subscript -1 | 
| 509 |  |  |  |  |  |  | # fatal error | 
| 510 |  |  |  |  |  |  | # This can occur with a tied hash and the %{$tieref} = %new | 
| 511 |  |  |  |  |  |  | # construct | 
| 512 | 29 | 50 |  |  |  | 78 | if (defined $offset) { | 
| 513 | 29 | 100 | 66 |  |  | 39 | $offset = 0 if (@{$self->{HEADER}} == 0 && $offset < 0); | 
|  | 29 |  |  |  |  | 92 |  | 
| 514 |  |  |  |  |  |  | } | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | # the removed cards | 
| 517 | 29 |  |  |  |  | 49 | my @cards; | 
| 518 |  |  |  |  |  |  |  | 
| 519 | 29 | 100 |  |  |  | 64 | if (@list) { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 520 |  |  |  |  |  |  | # all arguments supplied | 
| 521 | 24 |  |  |  |  | 38 | my $n = 0; | 
| 522 | 24 |  |  |  |  | 40 | for my $i (@list) { | 
| 523 | 24 | 50 |  |  |  | 87 | croak "Argument $n to splice must be Astro::FITS::Header::Item objects" | 
| 524 |  |  |  |  |  |  | unless UNIVERSAL::isa($i, "Astro::FITS::Header::Item"); | 
| 525 | 24 |  |  |  |  | 47 | $n++; | 
| 526 |  |  |  |  |  |  | } | 
| 527 | 24 |  |  |  |  | 31 | @cards = splice @{$self->{HEADER}}, $offset, $length, @list; | 
|  | 24 |  |  |  |  | 77 |  | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | } elsif (defined $length) { | 
| 530 |  |  |  |  |  |  | # length and (presumably) offset | 
| 531 | 5 |  |  |  |  | 9 | @cards = splice @{$self->{HEADER}}, $offset, $length; | 
|  | 5 |  |  |  |  | 17 |  | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | } elsif (defined $offset) { | 
| 534 |  |  |  |  |  |  | # offset only | 
| 535 | 0 |  |  |  |  | 0 | @cards = splice @{$self->{HEADER}}, $offset; | 
|  | 0 |  |  |  |  | 0 |  | 
| 536 |  |  |  |  |  |  | } else { | 
| 537 |  |  |  |  |  |  | # none | 
| 538 | 0 |  |  |  |  | 0 | @cards = splice @{$self->{HEADER}}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 539 |  |  |  |  |  |  | } | 
| 540 |  |  |  |  |  |  |  | 
| 541 |  |  |  |  |  |  | # update the internal lookup table and return | 
| 542 | 29 |  |  |  |  | 87 | $self->_rebuild_lookup(); | 
| 543 | 29 | 100 |  |  |  | 94 | return wantarray ? @cards : $cards[scalar(@cards)-1]; | 
| 544 |  |  |  |  |  |  | } | 
| 545 |  |  |  |  |  |  |  | 
| 546 |  |  |  |  |  |  | # C A R D S -------------------------------------------------------------- | 
| 547 |  |  |  |  |  |  |  | 
| 548 |  |  |  |  |  |  | =item B | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | Return the object contents as an array of FITS cards. | 
| 551 |  |  |  |  |  |  |  | 
| 552 |  |  |  |  |  |  | @array = $header->cards; | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | =cut | 
| 555 |  |  |  |  |  |  |  | 
| 556 |  |  |  |  |  |  | sub cards { | 
| 557 | 7 |  |  | 7 | 1 | 377 | my $self = shift; | 
| 558 | 7 |  |  |  |  | 24 | return map { "$_" } @{$self->{HEADER}}; | 
|  | 160 |  |  |  |  | 342 |  | 
|  | 7 |  |  |  |  | 25 |  | 
| 559 |  |  |  |  |  |  | } | 
| 560 |  |  |  |  |  |  |  | 
| 561 |  |  |  |  |  |  | =item B | 
| 562 |  |  |  |  |  |  |  | 
| 563 |  |  |  |  |  |  | Returns the highest index in use in the FITS header. | 
| 564 |  |  |  |  |  |  | To get the total number of header items, add 1. | 
| 565 |  |  |  |  |  |  |  | 
| 566 |  |  |  |  |  |  | $number = $header->sizeof; | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | =cut | 
| 569 |  |  |  |  |  |  |  | 
| 570 |  |  |  |  |  |  | sub sizeof { | 
| 571 | 13 |  |  | 13 | 1 | 1570 | my $self = shift; | 
| 572 | 13 |  |  |  |  | 23 | return $#{$self->{HEADER}}; | 
|  | 13 |  |  |  |  | 82 |  | 
| 573 |  |  |  |  |  |  | } | 
| 574 |  |  |  |  |  |  |  | 
| 575 |  |  |  |  |  |  | # A L L I T E M S --------------------------------------------------------- | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | =item B | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  | Returns the header as an array of FITS::Header:Item objects. | 
| 580 |  |  |  |  |  |  |  | 
| 581 |  |  |  |  |  |  | @items = $header->allitems(); | 
| 582 |  |  |  |  |  |  |  | 
| 583 |  |  |  |  |  |  | =cut | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | sub allitems { | 
| 586 | 19 |  |  | 19 | 1 | 36 | my $self = shift; | 
| 587 | 19 |  |  |  |  | 28 | return map { $_ } @{$self->{HEADER}}; | 
|  | 750 |  |  |  |  | 1049 |  | 
|  | 19 |  |  |  |  | 46 |  | 
| 588 |  |  |  |  |  |  | } | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | # C O N F I G U R E ------------------------------------------------------- | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | =back | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | =head2 General Methods | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | =over 4 | 
| 597 |  |  |  |  |  |  |  | 
| 598 |  |  |  |  |  |  | =item B | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | Configures the object, takes an array of FITS header cards, | 
| 601 |  |  |  |  |  |  | an array of Astro::FITS::Header::Item objects or a simple hash as input. | 
| 602 |  |  |  |  |  |  | If you feed in nothing at all, it uses a default array containing | 
| 603 |  |  |  |  |  |  | just the SIMPLE card required at the top of all FITS files. | 
| 604 |  |  |  |  |  |  |  | 
| 605 |  |  |  |  |  |  | $header->configure( Cards => \@array ); | 
| 606 |  |  |  |  |  |  | $header->configure( Items => \@array ); | 
| 607 |  |  |  |  |  |  | $header->configure( Hash => \%hash ); | 
| 608 |  |  |  |  |  |  |  | 
| 609 |  |  |  |  |  |  | Does nothing if the array is not supplied. If the hash scheme is used | 
| 610 |  |  |  |  |  |  | and the hash contains the special key of SUBHEADERS pointing to an | 
| 611 |  |  |  |  |  |  | array of hashes, these will be read as proper sub headers. All other | 
| 612 |  |  |  |  |  |  | references in the hash will be ignored. Note that the default key | 
| 613 |  |  |  |  |  |  | order will be retained in the object created via the hash. | 
| 614 |  |  |  |  |  |  |  | 
| 615 |  |  |  |  |  |  | =cut | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | sub configure { | 
| 618 | 42 |  |  | 42 | 1 | 80 | my $self = shift; | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | # grab the argument list | 
| 621 | 42 |  |  |  |  | 101 | my %args = @_; | 
| 622 |  |  |  |  |  |  |  | 
| 623 | 42 | 100 | 66 |  |  | 183 | if (exists $args{Cards} && defined $args{Cards}) { | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | # First translate each incoming card into a Item object | 
| 626 |  |  |  |  |  |  | # Any existing cards are removed | 
| 627 | 40 |  |  |  |  | 383 | @{$self->{HEADER}} = map { | 
| 628 | 1284 |  |  |  |  | 2802 | new Astro::FITS::Header::Item( Card => $_ ); | 
| 629 | 40 |  |  |  |  | 57 | } @{ $args{Cards} }; | 
|  | 40 |  |  |  |  | 86 |  | 
| 630 |  |  |  |  |  |  |  | 
| 631 |  |  |  |  |  |  | # Now build the lookup table. There would be a slight efficiency | 
| 632 |  |  |  |  |  |  | # gain to include this in a loop over the cards but prefer | 
| 633 |  |  |  |  |  |  | # to reuse the method for this rather than repeating code | 
| 634 | 40 |  |  |  |  | 132 | $self->_rebuild_lookup; | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | } elsif (exists $args{Items} && defined $args{Items}) { | 
| 637 |  |  |  |  |  |  | # We have an array of Astro::FITS::Header::Items | 
| 638 | 0 |  |  |  |  | 0 | @{$self->{HEADER}} = @{ $args{Items} }; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 639 | 0 |  |  |  |  | 0 | $self->_rebuild_lookup; | 
| 640 |  |  |  |  |  |  | } elsif (exists $args{Hash} && defined $args{Hash} ) { | 
| 641 |  |  |  |  |  |  | # we have a hash so convert to Item objects and store | 
| 642 |  |  |  |  |  |  | # use a For loop instead of map since we want to | 
| 643 |  |  |  |  |  |  | # skip some items | 
| 644 |  |  |  |  |  |  | croak "Hash constructor requested but not given a hash reference" | 
| 645 | 2 | 50 |  |  |  | 6 | unless ref($args{Hash}) eq 'HASH'; | 
| 646 | 2 |  |  |  |  | 3 | my @items; | 
| 647 |  |  |  |  |  |  | my @subheaders; | 
| 648 | 2 |  |  |  |  | 3 | for my $k (keys %{$args{Hash}}) { | 
|  | 2 |  |  |  |  | 8 |  | 
| 649 | 2 | 50 | 33 |  |  | 9 | if ($k eq 'SUBHEADERS' | 
|  |  | 50 | 33 |  |  |  |  | 
| 650 |  |  |  |  |  |  | && ref($args{Hash}->{$k}) eq 'ARRAY' | 
| 651 |  |  |  |  |  |  | && ref($args{Hash}->{$k}->[0]) eq 'HASH') { | 
| 652 |  |  |  |  |  |  | # special case | 
| 653 | 0 |  |  |  |  | 0 | @subheaders = map { $self->new( Hash => $_ ) } @{$args{Hash}->{$k}}; | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 654 |  |  |  |  |  |  | } elsif (not ref($args{Hash}->{$k})) { | 
| 655 |  |  |  |  |  |  | # if we have new lines in the value, we should duplicate the item | 
| 656 |  |  |  |  |  |  | # so split on new lines | 
| 657 | 2 |  |  |  |  | 4 | my $value = $args{Hash}->{$k}; | 
| 658 | 2 | 50 |  |  |  | 4 | $value = '' unless defined $value; | 
| 659 | 2 |  |  |  |  | 6 | my @lines = split(/^/m,$value); | 
| 660 | 2 |  |  |  |  | 4 | chomp(@lines);          # remove the newlines | 
| 661 |  |  |  |  |  |  |  | 
| 662 | 2 |  |  |  |  | 4 | push(@items, map { new Astro::FITS::Header::Item( Keyword => $k, | 
|  | 2 |  |  |  |  | 5 |  | 
| 663 |  |  |  |  |  |  | Value => $_ ) } | 
| 664 |  |  |  |  |  |  | @lines); | 
| 665 |  |  |  |  |  |  | } | 
| 666 |  |  |  |  |  |  | } | 
| 667 | 2 |  |  |  |  | 3 | @{$self->{HEADER}} = @items; | 
|  | 2 |  |  |  |  | 5 |  | 
| 668 | 2 |  |  |  |  | 7 | $self->_rebuild_lookup; | 
| 669 | 2 | 50 |  |  |  | 7 | $self->subhdrs(@subheaders) if @subheaders; | 
| 670 |  |  |  |  |  |  | } elsif ( !defined($self->{HEADER}) ||  !@{$self->{HEADER}} ) { | 
| 671 | 0 |  |  |  |  | 0 | @{$self->{HEADER}} = ( | 
|  | 0 |  |  |  |  | 0 |  | 
| 672 |  |  |  |  |  |  | new Astro::FITS::Header::Item( Card=> "SIMPLE  =  T"), | 
| 673 |  |  |  |  |  |  | new Astro::FITS::Header::Item( Card=> "END", Type=>"END" ) | 
| 674 |  |  |  |  |  |  | ); | 
| 675 | 0 |  |  |  |  | 0 | $self->_rebuild_lookup; | 
| 676 |  |  |  |  |  |  | } | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  |  | 
| 679 |  |  |  |  |  |  | =item B | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | Given the current header and a set of C objects, | 
| 682 |  |  |  |  |  |  | return a merged FITS header (with the cards that have the same value | 
| 683 |  |  |  |  |  |  | and comment across all headers) along with, for each input, header | 
| 684 |  |  |  |  |  |  | objects containing all the header items that differ (including, by | 
| 685 |  |  |  |  |  |  | default, keys that are not present in all headers). Only the primary | 
| 686 |  |  |  |  |  |  | headers are merged, subheaders are ignored. | 
| 687 |  |  |  |  |  |  |  | 
| 688 |  |  |  |  |  |  | ($clone) = $headerr->merge_primary(); | 
| 689 |  |  |  |  |  |  | ($same, @different) = $header->merge_primary( $fits1, $fits2, ...); | 
| 690 |  |  |  |  |  |  | ($same, @different) = $header->merge_primary( \%options, $fits1, $fits2 ); | 
| 691 |  |  |  |  |  |  |  | 
| 692 |  |  |  |  |  |  | @different can be empty if all headers match (but see the | 
| 693 |  |  |  |  |  |  | C option) but if any headers are different there | 
| 694 |  |  |  |  |  |  | will always be the same number of headers in @different as supplied to | 
| 695 |  |  |  |  |  |  | the function (including the reference header). A clone of the input header | 
| 696 |  |  |  |  |  |  | (stripped of any subheaders) is returned if no comparison headers are | 
| 697 |  |  |  |  |  |  | supplied. | 
| 698 |  |  |  |  |  |  |  | 
| 699 |  |  |  |  |  |  | In scalar context, just returns the merged header. | 
| 700 |  |  |  |  |  |  |  | 
| 701 |  |  |  |  |  |  | $merged = $header->merge_primary( @hdrs ); | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | The options hash is itself optional. It contains the following keys: | 
| 704 |  |  |  |  |  |  |  | 
| 705 |  |  |  |  |  |  | merge_unique - if an item is identical across multiple headers and only | 
| 706 |  |  |  |  |  |  | exists in those headers, propagate to the merged header rather | 
| 707 |  |  |  |  |  |  | than storing it in the difference headers. | 
| 708 |  |  |  |  |  |  |  | 
| 709 |  |  |  |  |  |  | force_return_diffs - return an empty difference object per input header | 
| 710 |  |  |  |  |  |  | even if there are no diffs | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | =cut | 
| 713 |  |  |  |  |  |  |  | 
| 714 |  |  |  |  |  |  | sub merge_primary { | 
| 715 | 8 |  |  | 8 | 1 | 1772 | my $self = shift; | 
| 716 |  |  |  |  |  |  |  | 
| 717 |  |  |  |  |  |  | # optional options handling | 
| 718 | 8 |  |  |  |  | 25 | my %opt = ( merge_unique => 0, | 
| 719 |  |  |  |  |  |  | force_return_diffs => 0, | 
| 720 |  |  |  |  |  |  | ); | 
| 721 | 8 | 100 |  |  |  | 26 | if (ref($_[0]) eq 'HASH') { | 
| 722 | 3 |  |  |  |  | 7 | my $o = shift; | 
| 723 | 3 |  |  |  |  | 15 | %opt = ( %opt, %$o ); | 
| 724 |  |  |  |  |  |  | } | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | # everything else is fits headers | 
| 727 |  |  |  |  |  |  | # If we do not get any additional headers we still process the full header | 
| 728 |  |  |  |  |  |  | # rather than shortcircuiting the logic. This is so that we can strip | 
| 729 |  |  |  |  |  |  | # HEADER items without having to write duplicate logic. Clearly not | 
| 730 |  |  |  |  |  |  | # very efficient but we do not really expect people to use this method | 
| 731 |  |  |  |  |  |  | # to clone a FITS header.... | 
| 732 | 8 |  |  |  |  | 26 | my @fits = @_; | 
| 733 |  |  |  |  |  |  |  | 
| 734 |  |  |  |  |  |  | # Number of output diff arrays | 
| 735 |  |  |  |  |  |  | # Include this object | 
| 736 | 8 |  |  |  |  | 19 | my $nhdr = @fits + 1; | 
| 737 |  |  |  |  |  |  |  | 
| 738 |  |  |  |  |  |  | # Go through all the items building up a hash indexed | 
| 739 |  |  |  |  |  |  | # by KEYWORD pointing to an array of items with that keyword | 
| 740 |  |  |  |  |  |  | # and an array of unique keywords in the original order they | 
| 741 |  |  |  |  |  |  | # appeared first. COMMENT items are stored in the | 
| 742 |  |  |  |  |  |  | # hash as complete cards. | 
| 743 |  |  |  |  |  |  | # HEADER items are currently dropped on the floor. | 
| 744 | 8 |  |  |  |  | 13 | my @order; | 
| 745 |  |  |  |  |  |  | my %items; | 
| 746 | 8 |  |  |  |  | 14 | my $hnum = 0; | 
| 747 | 8 |  |  |  |  | 19 | for my $hdr ($self, @fits) { | 
| 748 | 17 |  |  |  |  | 37 | for my $item ($hdr->allitems) { | 
| 749 | 373 |  |  |  |  | 506 | my $key; | 
| 750 | 373 |  |  |  |  | 691 | my $type = $item->type; | 
| 751 | 373 | 50 | 33 |  |  | 1245 | if (!defined $type || $type eq 'BLANK') { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 752 |  |  |  |  |  |  | # blank line so skip it | 
| 753 | 0 |  |  |  |  | 0 | next; | 
| 754 |  |  |  |  |  |  | } elsif ($type eq 'COMMENT') { | 
| 755 | 30 |  |  |  |  | 63 | $key = $item->card; | 
| 756 |  |  |  |  |  |  | } elsif ($type eq 'HEADER') { | 
| 757 | 0 |  |  |  |  | 0 | next; | 
| 758 |  |  |  |  |  |  | } else { | 
| 759 | 343 |  |  |  |  | 1949 | $key = $item->keyword; | 
| 760 |  |  |  |  |  |  | } | 
| 761 |  |  |  |  |  |  |  | 
| 762 | 373 | 100 |  |  |  | 692 | if (exists $items{$key}) { | 
| 763 |  |  |  |  |  |  | # Store the item, but in a hash with key corresponding | 
| 764 |  |  |  |  |  |  | # to the input header number | 
| 765 | 197 |  |  |  |  | 251 | push( @{ $items{$key}}, { item => $item, hnum => $hnum } ); | 
|  | 197 |  |  |  |  | 605 |  | 
| 766 |  |  |  |  |  |  | } else { | 
| 767 | 176 |  |  |  |  | 461 | $items{$key} = [ { item => $item, hnum => $hnum } ]; | 
| 768 | 176 |  |  |  |  | 359 | push(@order, $key); | 
| 769 |  |  |  |  |  |  | } | 
| 770 |  |  |  |  |  |  | } | 
| 771 | 17 |  |  |  |  | 62 | $hnum++; | 
| 772 |  |  |  |  |  |  | } | 
| 773 |  |  |  |  |  |  |  | 
| 774 |  |  |  |  |  |  | # create merged and difference arrays | 
| 775 | 8 |  |  |  |  | 17 | my @merged; | 
| 776 | 8 |  |  |  |  | 23 | my @difference = map { [] } (1..$nhdr); | 
|  | 17 |  |  |  |  | 37 |  | 
| 777 |  |  |  |  |  |  |  | 
| 778 |  |  |  |  |  |  | # Now loop over all of the unique keywords (taking care to | 
| 779 |  |  |  |  |  |  | # spot comments) | 
| 780 | 8 |  |  |  |  | 17 | for my $key (@order) { | 
| 781 | 176 |  |  |  |  | 243 | my @items = @{$items{$key}}; | 
|  | 176 |  |  |  |  | 332 |  | 
| 782 |  |  |  |  |  |  |  | 
| 783 |  |  |  |  |  |  | # compare each Item with the first. This will work even if we only have | 
| 784 |  |  |  |  |  |  | # one Item in the array. | 
| 785 |  |  |  |  |  |  | # Note that $match == 1 to start with because it always matches itself | 
| 786 |  |  |  |  |  |  | # but we do not bother doing the with-itself comparison. | 
| 787 | 176 |  |  |  |  | 232 | my $match = 1; | 
| 788 | 176 |  |  |  |  | 317 | for my $i (@items[1..$#items]) { | 
| 789 |  |  |  |  |  |  | # Ask the Items to compare using the equals() method | 
| 790 | 197 | 100 |  |  |  | 437 | if ($items[0]->{item}->equals( $i->{item} )) { | 
| 791 | 184 |  |  |  |  | 377 | $match++; | 
| 792 |  |  |  |  |  |  | } | 
| 793 |  |  |  |  |  |  | } | 
| 794 |  |  |  |  |  |  |  | 
| 795 |  |  |  |  |  |  | # if we matched all the items and are merging unique OR if we | 
| 796 |  |  |  |  |  |  | # matched all the items and that was all the available headers | 
| 797 |  |  |  |  |  |  | # we store in the merged array. Else we store in the differences | 
| 798 |  |  |  |  |  |  | # array | 
| 799 | 176 | 100 | 100 |  |  | 567 | if ($match == @items && ($match == $nhdr || $opt{merge_unique})) { | 
|  |  |  | 100 |  |  |  |  | 
| 800 |  |  |  |  |  |  | # Matched all the headers or merging matching unique headers | 
| 801 |  |  |  |  |  |  | # only need to store one | 
| 802 | 165 |  |  |  |  | 339 | push(@merged, $items[0]->{item}); | 
| 803 |  |  |  |  |  |  |  | 
| 804 |  |  |  |  |  |  | } else { | 
| 805 |  |  |  |  |  |  | # Not enough of the items matched. Store to the relevant difference | 
| 806 |  |  |  |  |  |  | # arrays. | 
| 807 | 11 |  |  |  |  | 33 | for my $i (@items) { | 
| 808 | 26 |  |  |  |  | 45 | push(@{ $difference[$i->{hnum}] }, $i->{item}); | 
|  | 26 |  |  |  |  | 90 |  | 
| 809 |  |  |  |  |  |  | } | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | } | 
| 812 |  |  |  |  |  |  |  | 
| 813 |  |  |  |  |  |  | } | 
| 814 |  |  |  |  |  |  |  | 
| 815 |  |  |  |  |  |  | # and clear @difference in the special case where none have any headers | 
| 816 | 8 | 100 |  |  |  | 19 | if (!$opt{force_return_diffs}) { | 
| 817 | 7 | 100 |  |  |  | 15 | @difference = () unless grep { @$_ != 0 } @difference; | 
|  | 15 |  |  |  |  | 45 |  | 
| 818 |  |  |  |  |  |  | } | 
| 819 |  |  |  |  |  |  |  | 
| 820 |  |  |  |  |  |  | # unshift @merged onto the front of @difference in preparation | 
| 821 |  |  |  |  |  |  | # for returning it | 
| 822 | 8 |  |  |  |  | 20 | unshift(@difference, \@merged ); | 
| 823 |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  | # convert back to FITS object, Construct using the Items directly | 
| 825 |  |  |  |  |  |  | # - they will be copied without strinfication. | 
| 826 | 8 |  |  |  |  | 17 | for my $d (@difference) { | 
| 827 | 21 |  |  |  |  | 41 | $d = $self->new( Cards => $d ); | 
| 828 |  |  |  |  |  |  | } | 
| 829 |  |  |  |  |  |  |  | 
| 830 |  |  |  |  |  |  | # remembering that the merged array is on the front | 
| 831 | 8 | 100 |  |  |  | 197 | return (wantarray ? @difference : $difference[0]); | 
| 832 |  |  |  |  |  |  | } | 
| 833 |  |  |  |  |  |  |  | 
| 834 |  |  |  |  |  |  | =item B | 
| 835 |  |  |  |  |  |  |  | 
| 836 |  |  |  |  |  |  | Method to return a blessed reference to the object so that we can store | 
| 837 |  |  |  |  |  |  | ths object on disk using Data::Dumper module. | 
| 838 |  |  |  |  |  |  |  | 
| 839 |  |  |  |  |  |  | =cut | 
| 840 |  |  |  |  |  |  |  | 
| 841 |  |  |  |  |  |  | sub freeze { | 
| 842 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 843 | 0 |  |  |  |  | 0 | return bless $self, 'Astro::FITS::Header'; | 
| 844 |  |  |  |  |  |  | } | 
| 845 |  |  |  |  |  |  |  | 
| 846 |  |  |  |  |  |  | =item B | 
| 847 |  |  |  |  |  |  |  | 
| 848 |  |  |  |  |  |  | Append or update a card. | 
| 849 |  |  |  |  |  |  |  | 
| 850 |  |  |  |  |  |  | $header->append( $card ); | 
| 851 |  |  |  |  |  |  |  | 
| 852 |  |  |  |  |  |  | This method can take either an Astro::FITS::Header::Item object, an | 
| 853 |  |  |  |  |  |  | Astro::FITS::Header object, or a reference to an array of | 
| 854 |  |  |  |  |  |  | Astro::FITS::Header::Item objects. | 
| 855 |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  | In all cases, if the given Astro::FITS::Header::Item keyword exists in | 
| 857 |  |  |  |  |  |  | the header, then the value will be overwritten with the one passed to | 
| 858 |  |  |  |  |  |  | the method. Otherwise, the card will be appended to the end of the | 
| 859 |  |  |  |  |  |  | header. | 
| 860 |  |  |  |  |  |  |  | 
| 861 |  |  |  |  |  |  | Nothing is returned. | 
| 862 |  |  |  |  |  |  |  | 
| 863 |  |  |  |  |  |  | =cut | 
| 864 |  |  |  |  |  |  |  | 
| 865 |  |  |  |  |  |  | sub append { | 
| 866 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 867 | 0 |  |  |  |  | 0 | my $thing = shift; | 
| 868 |  |  |  |  |  |  |  | 
| 869 | 0 |  |  |  |  | 0 | my @cards; | 
| 870 | 0 | 0 |  |  |  | 0 | if ( UNIVERSAL::isa( $thing, "Astro::FITS::Header::Item" ) ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 871 | 0 |  |  |  |  | 0 | push @cards, $thing; | 
| 872 |  |  |  |  |  |  | } elsif ( UNIVERSAL::isa( $thing, "Astro::FITS::Header" ) ) { | 
| 873 | 0 |  |  |  |  | 0 | @cards = $thing->allitems; | 
| 874 |  |  |  |  |  |  | } elsif ( ref( $thing ) eq 'ARRAY' ) { | 
| 875 | 0 |  |  |  |  | 0 | @cards = @$thing; | 
| 876 |  |  |  |  |  |  | } | 
| 877 |  |  |  |  |  |  |  | 
| 878 | 0 |  |  |  |  | 0 | foreach my $card ( @cards ) { | 
| 879 | 0 |  |  |  |  | 0 | my $item = $self->itembyname( $card->keyword ); | 
| 880 | 0 | 0 |  |  |  | 0 | if ( defined( $item ) ) { | 
| 881 |  |  |  |  |  |  |  | 
| 882 |  |  |  |  |  |  | # Update the given card. | 
| 883 | 0 |  |  |  |  | 0 | $self->replacebyname( $card->keyword, $card ) | 
| 884 |  |  |  |  |  |  |  | 
| 885 |  |  |  |  |  |  | } else { | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | # Don't append a SIMPLE header as that can lead to disaster and | 
| 888 |  |  |  |  |  |  | # strife and gnashing of teeth (and violates the FITS standard). | 
| 889 | 0 | 0 |  |  |  | 0 | next if ( uc( $card->keyword ) eq 'SIMPLE' ); | 
| 890 |  |  |  |  |  |  |  | 
| 891 |  |  |  |  |  |  | # Retrieve the index of the END card, and insert this card | 
| 892 |  |  |  |  |  |  | # before that one, but only if the END header actually exists. | 
| 893 | 0 |  |  |  |  | 0 | my $index = $self->index( 'END' ); | 
| 894 | 0 | 0 |  |  |  | 0 | $index = ( defined( $index ) ? $index : -1 ); | 
| 895 | 0 |  |  |  |  | 0 | $self->insert( $index, $card ); | 
| 896 |  |  |  |  |  |  | } | 
| 897 |  |  |  |  |  |  | } | 
| 898 |  |  |  |  |  |  |  | 
| 899 | 0 |  |  |  |  | 0 | $self->_rebuild_lookup; | 
| 900 |  |  |  |  |  |  | } | 
| 901 |  |  |  |  |  |  |  | 
| 902 |  |  |  |  |  |  | # P R I V A T  E   M E T H O D S ------------------------------------------ | 
| 903 |  |  |  |  |  |  |  | 
| 904 |  |  |  |  |  |  | =back | 
| 905 |  |  |  |  |  |  |  | 
| 906 |  |  |  |  |  |  | =head2 Operator Overloading | 
| 907 |  |  |  |  |  |  |  | 
| 908 |  |  |  |  |  |  | These operators are overloaded: | 
| 909 |  |  |  |  |  |  |  | 
| 910 |  |  |  |  |  |  | =over 4 | 
| 911 |  |  |  |  |  |  |  | 
| 912 |  |  |  |  |  |  | =item B<""> | 
| 913 |  |  |  |  |  |  |  | 
| 914 |  |  |  |  |  |  | When the object is used in a string context the FITS header | 
| 915 |  |  |  |  |  |  | block is returned as a single string. | 
| 916 |  |  |  |  |  |  |  | 
| 917 |  |  |  |  |  |  | =cut | 
| 918 |  |  |  |  |  |  |  | 
| 919 |  |  |  |  |  |  | sub stringify { | 
| 920 | 5 |  |  | 5 | 0 | 25 | my $self = shift; | 
| 921 | 5 |  |  |  |  | 16 | return join("\n", $self->cards )."\n"; | 
| 922 |  |  |  |  |  |  | } | 
| 923 |  |  |  |  |  |  |  | 
| 924 |  |  |  |  |  |  | =back | 
| 925 |  |  |  |  |  |  |  | 
| 926 |  |  |  |  |  |  | =head2 Private methods | 
| 927 |  |  |  |  |  |  |  | 
| 928 |  |  |  |  |  |  | These methods are for internal use only. | 
| 929 |  |  |  |  |  |  |  | 
| 930 |  |  |  |  |  |  | =over 4 | 
| 931 |  |  |  |  |  |  |  | 
| 932 |  |  |  |  |  |  | =item B<_rebuild_lookup> | 
| 933 |  |  |  |  |  |  |  | 
| 934 |  |  |  |  |  |  | Private function used to rebuild the lookup table after modifying the | 
| 935 |  |  |  |  |  |  | header block, its easier to do it this way than go through and add one | 
| 936 |  |  |  |  |  |  | to the indices of all header cards following the modified card. | 
| 937 |  |  |  |  |  |  |  | 
| 938 |  |  |  |  |  |  | =cut | 
| 939 |  |  |  |  |  |  |  | 
| 940 |  |  |  |  |  |  | sub _rebuild_lookup { | 
| 941 | 78 |  |  | 78 |  | 131 | my $self = shift; | 
| 942 |  |  |  |  |  |  |  | 
| 943 |  |  |  |  |  |  | # rebuild the lookup table | 
| 944 |  |  |  |  |  |  |  | 
| 945 |  |  |  |  |  |  | # empty the hash | 
| 946 | 78 |  |  |  |  | 566 | $self->{LOOKUP} = { }; | 
| 947 |  |  |  |  |  |  |  | 
| 948 |  |  |  |  |  |  | # loop over the existing header array | 
| 949 | 78 |  |  |  |  | 149 | for my $j (0 .. $#{$self->{HEADER}}) { | 
|  | 78 |  |  |  |  | 242 |  | 
| 950 |  |  |  |  |  |  |  | 
| 951 |  |  |  |  |  |  | # grab the keyword from each header item; | 
| 952 | 3538 |  |  |  |  | 4557 | my $key = ${$self->{HEADER}}[$j]->keyword(); | 
|  | 3538 |  |  |  |  | 7341 |  | 
| 953 |  |  |  |  |  |  |  | 
| 954 |  |  |  |  |  |  | # need to account to repeated keywords (e.g. COMMENT) | 
| 955 | 3538 | 100 | 66 |  |  | 4590 | unless ( exists ${$self->{LOOKUP}}{$key} && | 
|  | 3538 |  |  |  |  | 7613 |  | 
| 956 | 84 |  |  |  |  | 236 | defined ${$self->{LOOKUP}}{$key} ) { | 
| 957 |  |  |  |  |  |  | # new keyword | 
| 958 | 3454 |  |  |  |  | 5315 | ${$self->{LOOKUP}}{$key} = [ $j ]; | 
|  | 3454 |  |  |  |  | 7631 |  | 
| 959 |  |  |  |  |  |  | } else { | 
| 960 |  |  |  |  |  |  | # keyword exists, push the current index into the array | 
| 961 | 84 |  |  |  |  | 112 | push( @{${$self->{LOOKUP}}{$key}}, $j ); | 
|  | 84 |  |  |  |  | 109 |  | 
|  | 84 |  |  |  |  | 226 |  | 
| 962 |  |  |  |  |  |  | } | 
| 963 |  |  |  |  |  |  | } | 
| 964 |  |  |  |  |  |  |  | 
| 965 |  |  |  |  |  |  | } | 
| 966 |  |  |  |  |  |  |  | 
| 967 |  |  |  |  |  |  | # T I E D   I N T E R F A C E ----------------------------------------------- | 
| 968 |  |  |  |  |  |  |  | 
| 969 |  |  |  |  |  |  | =back | 
| 970 |  |  |  |  |  |  |  | 
| 971 |  |  |  |  |  |  | =head1 TIED INTERFACE | 
| 972 |  |  |  |  |  |  |  | 
| 973 |  |  |  |  |  |  | The C object can also be tied to a hash: | 
| 974 |  |  |  |  |  |  |  | 
| 975 |  |  |  |  |  |  | use Astro::FITS::Header; | 
| 976 |  |  |  |  |  |  |  | 
| 977 |  |  |  |  |  |  | $header = new Astro::FITS::Header( Cards => \@array ); | 
| 978 |  |  |  |  |  |  | tie %hash, "Astro::FITS::Header", $header | 
| 979 |  |  |  |  |  |  |  | 
| 980 |  |  |  |  |  |  | $value = $hash{$keyword}; | 
| 981 |  |  |  |  |  |  | $hash{$keyword} = $value; | 
| 982 |  |  |  |  |  |  |  | 
| 983 |  |  |  |  |  |  | print "keyword $keyword is present" if exists $hash{$keyword}; | 
| 984 |  |  |  |  |  |  |  | 
| 985 |  |  |  |  |  |  | foreach my $key (keys %hash) { | 
| 986 |  |  |  |  |  |  | print "$key = $hash{$key}\n"; | 
| 987 |  |  |  |  |  |  | } | 
| 988 |  |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  | =head2 Basic hash translation | 
| 990 |  |  |  |  |  |  |  | 
| 991 |  |  |  |  |  |  | Header value type is determined on-the-fly by parsing of the input values. | 
| 992 |  |  |  |  |  |  | Anything that parses as a number or a logical is converted to that before | 
| 993 |  |  |  |  |  |  | being put in a card (but see below). | 
| 994 |  |  |  |  |  |  |  | 
| 995 |  |  |  |  |  |  | Per-card comment fields can be accessed using the tied interface by specifying | 
| 996 |  |  |  |  |  |  | a key name of "key_COMMENT". This works because in general "_COMMENT" is too | 
| 997 |  |  |  |  |  |  | long to be confused with a normal key name. | 
| 998 |  |  |  |  |  |  |  | 
| 999 |  |  |  |  |  |  | $comment = $hdr{CRPIX1_COMMENT}; | 
| 1000 |  |  |  |  |  |  |  | 
| 1001 |  |  |  |  |  |  | will return the comment associated with CRPIX1 header item. The comment | 
| 1002 |  |  |  |  |  |  | can be modified in the same way: | 
| 1003 |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  | $hdr{CRPIX1_COMMENT} = "An axis"; | 
| 1005 |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  | You can also modify the comment by slash-delimiting it when setting the | 
| 1007 |  |  |  |  |  |  | associated keyword: | 
| 1008 |  |  |  |  |  |  |  | 
| 1009 |  |  |  |  |  |  | $hdr{CRPIX1} = "34 / Set this field manually"; | 
| 1010 |  |  |  |  |  |  |  | 
| 1011 |  |  |  |  |  |  | If you want an actual slash character in your string field you must escape | 
| 1012 |  |  |  |  |  |  | it with a backslash.  (If you're in double quotes you have to use a double | 
| 1013 |  |  |  |  |  |  | backslash): | 
| 1014 |  |  |  |  |  |  |  | 
| 1015 |  |  |  |  |  |  | $hdr{SLASHSTR} = 'foo\/bar / field contains "foo/bar"'; | 
| 1016 |  |  |  |  |  |  |  | 
| 1017 |  |  |  |  |  |  | Keywords are CaSE-inNSEnSiTIvE, unlike normal hash keywords.  All | 
| 1018 |  |  |  |  |  |  | keywords are translated to upper case internally, per the FITS standard. | 
| 1019 |  |  |  |  |  |  |  | 
| 1020 |  |  |  |  |  |  | Aside from the SIMPLE and END keywords, which are automagically placed at | 
| 1021 |  |  |  |  |  |  | the beginning and end of the header respectively, keywords are included | 
| 1022 |  |  |  |  |  |  | in the header in the order received.  This gives you a modicum of control | 
| 1023 |  |  |  |  |  |  | over card order, but if you actually care what order they're in, you | 
| 1024 |  |  |  |  |  |  | probably don't want the tied interface. | 
| 1025 |  |  |  |  |  |  |  | 
| 1026 |  |  |  |  |  |  | =head2 Comment cards | 
| 1027 |  |  |  |  |  |  |  | 
| 1028 |  |  |  |  |  |  | Comment cards are a special case because they have no normal value and | 
| 1029 |  |  |  |  |  |  | their comment field is treated as the hash value.  The keywords | 
| 1030 |  |  |  |  |  |  | "COMMENT" and "HISTORY" are magic and refer to comment cards; nearly all other | 
| 1031 |  |  |  |  |  |  | keywords create normal valued cards.  (see "SIMPLE and END cards", below). | 
| 1032 |  |  |  |  |  |  |  | 
| 1033 |  |  |  |  |  |  | =head2 Multi-card values | 
| 1034 |  |  |  |  |  |  |  | 
| 1035 |  |  |  |  |  |  | Multiline string values are broken up, one card per line in the | 
| 1036 |  |  |  |  |  |  | string.  Extra-long string values are handled gracefully: they get | 
| 1037 |  |  |  |  |  |  | split among multiple cards, with a backslash at the end of each card | 
| 1038 |  |  |  |  |  |  | image.  They're transparently reassembled when you access the data, so | 
| 1039 |  |  |  |  |  |  | that there is a strong analogy between multiline string values and multiple | 
| 1040 |  |  |  |  |  |  | cards. | 
| 1041 |  |  |  |  |  |  |  | 
| 1042 |  |  |  |  |  |  | In general, appending to hash entries that look like strings does what | 
| 1043 |  |  |  |  |  |  | you think it should.  In particular, comment cards have a newline | 
| 1044 |  |  |  |  |  |  | appended automatically on FETCH, so that | 
| 1045 |  |  |  |  |  |  |  | 
| 1046 |  |  |  |  |  |  | $hash{HISTORY} .= "Added multi-line string support"; | 
| 1047 |  |  |  |  |  |  |  | 
| 1048 |  |  |  |  |  |  | adds a new HISTORY comment card, while | 
| 1049 |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  | $hash{TELESCOP} .= " dome B"; | 
| 1051 |  |  |  |  |  |  |  | 
| 1052 |  |  |  |  |  |  | only modifies an existing TELESCOP card. | 
| 1053 |  |  |  |  |  |  |  | 
| 1054 |  |  |  |  |  |  | You can make multi-line values by feeding in newline-delimited | 
| 1055 |  |  |  |  |  |  | strings, or by assigning from an array ref.  If you ask for a tag that | 
| 1056 |  |  |  |  |  |  | has a multiline value it's always expanded to a multiline string, even | 
| 1057 |  |  |  |  |  |  | if you fed in an array ref to start with.  That's by design: multiline | 
| 1058 |  |  |  |  |  |  | string expansion often acts as though you are getting just the first | 
| 1059 |  |  |  |  |  |  | value back out, because perl string-to-number conversion stops at the | 
| 1060 |  |  |  |  |  |  | first newline.  So: | 
| 1061 |  |  |  |  |  |  |  | 
| 1062 |  |  |  |  |  |  | $hash{CDELT1} = [3,4,5]; | 
| 1063 |  |  |  |  |  |  | print $hash{CDELT1} + 99,"\n$hash{CDELT1}"; | 
| 1064 |  |  |  |  |  |  |  | 
| 1065 |  |  |  |  |  |  | prints "102\n3\n4\n5", and then | 
| 1066 |  |  |  |  |  |  |  | 
| 1067 |  |  |  |  |  |  | $hash{CDELT1}++; | 
| 1068 |  |  |  |  |  |  | print $hash{CDELT1}; | 
| 1069 |  |  |  |  |  |  |  | 
| 1070 |  |  |  |  |  |  | prints "4". | 
| 1071 |  |  |  |  |  |  |  | 
| 1072 |  |  |  |  |  |  | In short, most of the time you get what you want.  But you can always fall | 
| 1073 |  |  |  |  |  |  | back on the non-tied interface by calling methods like so: | 
| 1074 |  |  |  |  |  |  |  | 
| 1075 |  |  |  |  |  |  | ((tied $hash)->method()) | 
| 1076 |  |  |  |  |  |  |  | 
| 1077 |  |  |  |  |  |  | If you prefer to have multi-valued items automagically become array | 
| 1078 |  |  |  |  |  |  | refs, then you can get that behavior using the C method: | 
| 1079 |  |  |  |  |  |  |  | 
| 1080 |  |  |  |  |  |  | tie %keywords, "Astro::FITS::Header", $header, tiereturnsref => 1; | 
| 1081 |  |  |  |  |  |  |  | 
| 1082 |  |  |  |  |  |  | When tiereturnsref is true, multi-valued items will be returned via a | 
| 1083 |  |  |  |  |  |  | reference to an array (ties do not respect calling context). Note that | 
| 1084 |  |  |  |  |  |  | if this is configured you will have to test each return value to see | 
| 1085 |  |  |  |  |  |  | whether it is returning a real value or a reference to an array if you | 
| 1086 |  |  |  |  |  |  | are not sure whether there will be more than one card with a duplicate | 
| 1087 |  |  |  |  |  |  | name. | 
| 1088 |  |  |  |  |  |  |  | 
| 1089 |  |  |  |  |  |  | =head2 Type forcing | 
| 1090 |  |  |  |  |  |  |  | 
| 1091 |  |  |  |  |  |  | Because perl uses behind-the-scenes typing, there is an ambiguity | 
| 1092 |  |  |  |  |  |  | between strings and numeric and/or logical values: sometimes you want | 
| 1093 |  |  |  |  |  |  | to create a STRING card whose value could parse as a number or as a | 
| 1094 |  |  |  |  |  |  | logical value, and perl kindly parses it into a number for you.  To | 
| 1095 |  |  |  |  |  |  | force string evaluation, feed in a trivial array ref: | 
| 1096 |  |  |  |  |  |  |  | 
| 1097 |  |  |  |  |  |  | $hash{NUMSTR} = 123;     # generates an INT card containing 123. | 
| 1098 |  |  |  |  |  |  | $hash{NUMSTR} = "123";   # generates an INT card containing 123. | 
| 1099 |  |  |  |  |  |  | $hash{NUMSTR} = ["123"]; # generates a STRING card containing "123". | 
| 1100 |  |  |  |  |  |  | $hash{NUMSTR} = [123];   # generates a STRING card containing "123". | 
| 1101 |  |  |  |  |  |  |  | 
| 1102 |  |  |  |  |  |  | $hash{ALPHA} = "T";      # generates a LOGICAL card containing T. | 
| 1103 |  |  |  |  |  |  | $hash{ALPHA} = ["T"];    # generates a STRING card containing "T". | 
| 1104 |  |  |  |  |  |  |  | 
| 1105 |  |  |  |  |  |  | Calls to keys() or each() will, by default, return the keywords in the order | 
| 1106 |  |  |  |  |  |  | in which they appear in the header. | 
| 1107 |  |  |  |  |  |  |  | 
| 1108 |  |  |  |  |  |  | =head2 Sub-headers | 
| 1109 |  |  |  |  |  |  |  | 
| 1110 |  |  |  |  |  |  | When the key refers to a subheader entry (ie an item of type | 
| 1111 |  |  |  |  |  |  | "HEADER"), a hash reference is returned.  If a hash reference is | 
| 1112 |  |  |  |  |  |  | stored in a value it is converted to a C object. | 
| 1113 |  |  |  |  |  |  |  | 
| 1114 |  |  |  |  |  |  | If the special key "SUBHEADERS" is used, it will return the array of | 
| 1115 |  |  |  |  |  |  | subheaders, (as stored using the C method) each of which will | 
| 1116 |  |  |  |  |  |  | be tied to a hash. Subheaders can be stored using normal array operations. | 
| 1117 |  |  |  |  |  |  |  | 
| 1118 |  |  |  |  |  |  | =head2 SIMPLE and END cards | 
| 1119 |  |  |  |  |  |  |  | 
| 1120 |  |  |  |  |  |  | No FITS interface would becomplete without special cases. | 
| 1121 |  |  |  |  |  |  |  | 
| 1122 |  |  |  |  |  |  | When you assign to SIMPLE or END, the tied interface ensures that they | 
| 1123 |  |  |  |  |  |  | are first or last, respectively, in the deck -- as the FITS standard | 
| 1124 |  |  |  |  |  |  | requires.  Other cards are inserted in between the first and last | 
| 1125 |  |  |  |  |  |  | elements, in the order that you define them. | 
| 1126 |  |  |  |  |  |  |  | 
| 1127 |  |  |  |  |  |  | The SIMPLE card is forced to FITS LOGICAL (boolean) type.  The FITS | 
| 1128 |  |  |  |  |  |  | standard forbids you from setting it to F, but you can if you want -- | 
| 1129 |  |  |  |  |  |  | we're not the FITS police. | 
| 1130 |  |  |  |  |  |  |  | 
| 1131 |  |  |  |  |  |  | The END card is forced to a null type, so any value you assign to it | 
| 1132 |  |  |  |  |  |  | will fall on the floor.  If present in the deck, the END keyword | 
| 1133 |  |  |  |  |  |  | always contains the value " ", which is both more-or-less invisible | 
| 1134 |  |  |  |  |  |  | when printed and also true -- so you can test the return value to see | 
| 1135 |  |  |  |  |  |  | if an END card is present. | 
| 1136 |  |  |  |  |  |  |  | 
| 1137 |  |  |  |  |  |  | SIMPLE and END come pre-defined from the constructor.  If for some | 
| 1138 |  |  |  |  |  |  | nefarious reason you want to remove them you must explicitly do so | 
| 1139 |  |  |  |  |  |  | with "delete" or the appropriate method call from the object | 
| 1140 |  |  |  |  |  |  | interface. | 
| 1141 |  |  |  |  |  |  |  | 
| 1142 |  |  |  |  |  |  | =cut | 
| 1143 |  |  |  |  |  |  |  | 
| 1144 |  |  |  |  |  |  | # List of known comment-type fields | 
| 1145 |  |  |  |  |  |  | %Astro::FITS::Header::COMMENT_FIELD = ( | 
| 1146 |  |  |  |  |  |  | "COMMENT"=>1, | 
| 1147 |  |  |  |  |  |  | "HISTORY"=>1 | 
| 1148 |  |  |  |  |  |  | ); | 
| 1149 |  |  |  |  |  |  |  | 
| 1150 |  |  |  |  |  |  |  | 
| 1151 |  |  |  |  |  |  | # constructor | 
| 1152 |  |  |  |  |  |  | sub TIEHASH { | 
| 1153 | 25 |  |  | 25 |  | 851 | my ( $class, $obj, %options ) = @_; | 
| 1154 | 25 |  |  |  |  | 44 | my $newobj = bless $obj, $class; | 
| 1155 |  |  |  |  |  |  |  | 
| 1156 |  |  |  |  |  |  | # Process options | 
| 1157 | 25 |  |  |  |  | 58 | for my $key (keys %options) { | 
| 1158 | 2 |  |  |  |  | 5 | my $method = lc($key); | 
| 1159 | 2 | 50 |  |  |  | 14 | if ($newobj->can($method)) { | 
| 1160 | 2 |  |  |  |  | 16 | $newobj->$method( $options{$key}); | 
| 1161 |  |  |  |  |  |  | } | 
| 1162 |  |  |  |  |  |  | } | 
| 1163 |  |  |  |  |  |  |  | 
| 1164 | 25 |  |  |  |  | 77 | return $newobj; | 
| 1165 |  |  |  |  |  |  | } | 
| 1166 |  |  |  |  |  |  |  | 
| 1167 |  |  |  |  |  |  | # fetch key and value pair | 
| 1168 |  |  |  |  |  |  | # MUST return undef if the key is missing else autovivification of | 
| 1169 |  |  |  |  |  |  | # sub header will fail | 
| 1170 |  |  |  |  |  |  |  | 
| 1171 |  |  |  |  |  |  | sub FETCH { | 
| 1172 | 180 |  |  | 180 |  | 17080 | my ($self, $key) = @_; | 
| 1173 |  |  |  |  |  |  |  | 
| 1174 | 180 |  |  |  |  | 372 | $key = uc($key); | 
| 1175 |  |  |  |  |  |  |  | 
| 1176 |  |  |  |  |  |  | # if the key is called SUBHEADERS we should tie to an array | 
| 1177 | 180 | 100 |  |  |  | 458 | if ($key eq 'SUBHEADERS') { | 
| 1178 | 2 |  |  |  |  | 4 | my @dummy; | 
| 1179 | 2 |  |  |  |  | 9 | tie @dummy, "Astro::FITS::HeaderCollection", scalar $self->subhdrs; | 
| 1180 | 2 |  |  |  |  | 11 | return \@dummy; | 
| 1181 |  |  |  |  |  |  | } | 
| 1182 |  |  |  |  |  |  |  | 
| 1183 |  |  |  |  |  |  | # If the key has a _COMMENT suffix we are looking for a comment | 
| 1184 | 178 |  |  |  |  | 298 | my $wantvalue = 1; | 
| 1185 | 178 |  |  |  |  | 244 | my $wantcomment = 0; | 
| 1186 | 178 | 100 |  |  |  | 429 | if ($key =~ /_COMMENT$/) { | 
| 1187 | 6 |  |  |  |  | 11 | $wantvalue = 0; | 
| 1188 | 6 |  |  |  |  | 8 | $wantcomment = 1; | 
| 1189 |  |  |  |  |  |  | # Remove suffix | 
| 1190 | 6 |  |  |  |  | 22 | $key =~ s/_COMMENT$//; | 
| 1191 |  |  |  |  |  |  | } | 
| 1192 |  |  |  |  |  |  |  | 
| 1193 |  |  |  |  |  |  | # if we are of type COMMENT we want to retrieve the comment only | 
| 1194 |  |  |  |  |  |  | # if they're asking for $key_COMMENT. | 
| 1195 | 178 |  |  |  |  | 319 | my $item; | 
| 1196 |  |  |  |  |  |  | my $t_ok; | 
| 1197 | 178 | 100 | 100 |  |  | 1098 | if ( $wantcomment || $key =~ /^(COMMENT)|(HISTORY)$/ || $key =~ /^END$/) { | 
|  |  |  | 100 |  |  |  |  | 
| 1198 | 15 |  |  |  |  | 41 | $item = ($self->itembyname($key))[0]; | 
| 1199 | 15 |  | 100 |  |  | 57 | $t_ok = (defined $item) && (defined $item->type); | 
| 1200 | 15 | 100 | 100 |  |  | 45 | $wantvalue = 0 if ($t_ok && ($item->type eq 'COMMENT')); | 
| 1201 |  |  |  |  |  |  | } | 
| 1202 |  |  |  |  |  |  |  | 
| 1203 |  |  |  |  |  |  | # The END card is a special case.  We always return " " for the value, | 
| 1204 |  |  |  |  |  |  | # and undef for the comment. | 
| 1205 | 178 | 50 | 100 |  |  | 739 | return ($wantvalue ? " " : undef) | 
|  |  | 100 | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 1206 |  |  |  |  |  |  | if ( ($t_ok && ($item->type eq 'END')) || | 
| 1207 |  |  |  |  |  |  | ((defined $item) && ($key eq 'END')) ); | 
| 1208 |  |  |  |  |  |  |  | 
| 1209 |  |  |  |  |  |  | # Retrieve all the values/comments. Note that we go through the entire | 
| 1210 |  |  |  |  |  |  | # header for this in case of multiple matches | 
| 1211 | 176 | 100 |  |  |  | 572 | my @values = ($wantvalue ? $self->value( $key ) : $self->comment($key) ); | 
| 1212 |  |  |  |  |  |  |  | 
| 1213 |  |  |  |  |  |  | # Return value depends on return context. If we have one value it does not | 
| 1214 |  |  |  |  |  |  | # matter, just return it. In list context want all the values, in scalar | 
| 1215 |  |  |  |  |  |  | # context join them all with a \n | 
| 1216 |  |  |  |  |  |  | # Note that in a TIED hash we do not have access to the calling context | 
| 1217 |  |  |  |  |  |  | # we are ALWAYS in scalar context. | 
| 1218 | 176 |  |  |  |  | 260 | my @out; | 
| 1219 |  |  |  |  |  |  |  | 
| 1220 |  |  |  |  |  |  | # Sometimes we want the array to remain an array | 
| 1221 | 176 | 100 |  |  |  | 378 | if ($self->tiereturnsref) { | 
| 1222 | 4 |  |  |  |  | 10 | @out = @values; | 
| 1223 |  |  |  |  |  |  | } else { | 
| 1224 |  |  |  |  |  |  |  | 
| 1225 |  |  |  |  |  |  | # Join everything together with a newline | 
| 1226 |  |  |  |  |  |  | # BUT we are careful here to prevent stringification of references | 
| 1227 |  |  |  |  |  |  | # at least for the case where we only have one value. We also must | 
| 1228 |  |  |  |  |  |  | # handle the case where we have no value to return (without turning | 
| 1229 |  |  |  |  |  |  | # it into a null string since that ruins autovivification of sub headers) | 
| 1230 | 172 | 100 |  |  |  | 350 | if (scalar(@values) <= 1) { | 
| 1231 | 166 |  |  |  |  | 329 | @out = @values; | 
| 1232 |  |  |  |  |  |  | } else { | 
| 1233 |  |  |  |  |  |  |  | 
| 1234 |  |  |  |  |  |  | # Multi values so join [protecting warnings from undef] | 
| 1235 | 6 | 50 |  |  |  | 13 | @out = ( join("\n", map { defined $_ ? $_ : '' } @values) ); | 
|  | 17 |  |  |  |  | 49 |  | 
| 1236 |  |  |  |  |  |  |  | 
| 1237 |  |  |  |  |  |  | # This is a hangover from the STORE (where we add a \ continuation | 
| 1238 |  |  |  |  |  |  | # character to multiline strings) | 
| 1239 | 6 | 50 |  |  |  | 22 | $out[0] =~ s/\\\n//gs if (defined($out[0])); | 
| 1240 |  |  |  |  |  |  | } | 
| 1241 |  |  |  |  |  |  | } | 
| 1242 |  |  |  |  |  |  |  | 
| 1243 |  |  |  |  |  |  | # COMMENT cards get a newline appended. | 
| 1244 |  |  |  |  |  |  | # (Whether this should happen is controversial, but it supports | 
| 1245 |  |  |  |  |  |  | # the "just append a string to get a new COMMENT card" behavior | 
| 1246 |  |  |  |  |  |  | # described in the documentation). | 
| 1247 | 176 | 100 | 100 |  |  | 437 | if ($t_ok && ($item->type eq 'COMMENT')) { | 
| 1248 | 7 |  |  |  |  | 18 | @out = map { $_ . "\n" } @out; | 
|  | 12 |  |  |  |  | 36 |  | 
| 1249 |  |  |  |  |  |  | } | 
| 1250 |  |  |  |  |  |  |  | 
| 1251 |  |  |  |  |  |  | # If we have a header we need to tie it to another hash | 
| 1252 | 176 |  | 66 |  |  | 376 | my $ishdr = ($t_ok && $item->type eq 'HEADER'); | 
| 1253 | 176 |  |  |  |  | 318 | for my $hdr (@out) { | 
| 1254 | 177 | 100 | 66 |  |  | 1085 | if ((UNIVERSAL::isa($hdr, "Astro::FITS::Header")) || $ishdr) { | 
| 1255 | 11 |  |  |  |  | 15 | my %header; | 
| 1256 | 11 |  |  |  |  | 44 | tie %header, ref($hdr), $hdr; | 
| 1257 |  |  |  |  |  |  | # Change in place | 
| 1258 | 11 |  |  |  |  | 28 | $hdr = \%header; | 
| 1259 |  |  |  |  |  |  | } | 
| 1260 |  |  |  |  |  |  | } | 
| 1261 |  |  |  |  |  |  |  | 
| 1262 |  |  |  |  |  |  | # Can only return a scalar | 
| 1263 |  |  |  |  |  |  | # So return the first value if tiereturnsref is false. | 
| 1264 |  |  |  |  |  |  | # (by this point, all the values should be joined together into the | 
| 1265 |  |  |  |  |  |  | # first element anyway.) | 
| 1266 | 176 |  |  |  |  | 272 | my $out; | 
| 1267 | 176 | 100 | 100 |  |  | 317 | if ($self->tiereturnsref && scalar(@out) > 1) { | 
| 1268 | 2 |  |  |  |  | 4 | $out = \@out; | 
| 1269 |  |  |  |  |  |  | } else { | 
| 1270 | 174 |  |  |  |  | 299 | $out = $out[0]; | 
| 1271 |  |  |  |  |  |  | } | 
| 1272 |  |  |  |  |  |  |  | 
| 1273 | 176 |  |  |  |  | 774 | return $out; | 
| 1274 |  |  |  |  |  |  | } | 
| 1275 |  |  |  |  |  |  |  | 
| 1276 |  |  |  |  |  |  | # store key and value pair | 
| 1277 |  |  |  |  |  |  | # | 
| 1278 |  |  |  |  |  |  | # Multiple-line kludges (CED): | 
| 1279 |  |  |  |  |  |  | # | 
| 1280 |  |  |  |  |  |  | #    * Array refs get handled gracefully by being put in as multiple cards. | 
| 1281 |  |  |  |  |  |  | # | 
| 1282 |  |  |  |  |  |  | #    * Multiline strings get broken up and put in as multiple cards. | 
| 1283 |  |  |  |  |  |  | # | 
| 1284 |  |  |  |  |  |  | #    * Extra-long strings get broken up and put in as multiple cards, with | 
| 1285 |  |  |  |  |  |  | #      an extra backslash at the end so that they transparently get put back | 
| 1286 |  |  |  |  |  |  | #      together upon retrieval. | 
| 1287 |  |  |  |  |  |  | # | 
| 1288 |  |  |  |  |  |  |  | 
| 1289 |  |  |  |  |  |  | sub STORE { | 
| 1290 | 22 |  |  | 22 |  | 7087 | my ($self, $keyword, $value) = @_; | 
| 1291 | 22 |  |  |  |  | 38 | my @values; | 
| 1292 |  |  |  |  |  |  |  | 
| 1293 |  |  |  |  |  |  | # Recognize slash-delimited comments in value keywords.  This is done | 
| 1294 |  |  |  |  |  |  | # cheesily via recursion -- would be more efficient, but less readable, | 
| 1295 |  |  |  |  |  |  | # to propagate the comment through the code... | 
| 1296 |  |  |  |  |  |  |  | 
| 1297 |  |  |  |  |  |  | # I think this is fundamentally flawed. If I store a string "foo/bar" | 
| 1298 |  |  |  |  |  |  | # in a hash and then read it back I expect to get "foo/bar" not "foo". | 
| 1299 |  |  |  |  |  |  | # I can not be expected to know that this hash happens to be tied to | 
| 1300 |  |  |  |  |  |  | # a FITS header that is trying to spot FITS item formatting. - TJ | 
| 1301 |  |  |  |  |  |  |  | 
| 1302 |  |  |  |  |  |  | # Make sure that we do not stringify reference arguments by mistake | 
| 1303 |  |  |  |  |  |  | # when looking from slashes | 
| 1304 |  |  |  |  |  |  |  | 
| 1305 | 22 | 100 | 66 |  |  | 200 | if (defined $value && !ref($value) && $keyword !~ m/(_COMMENT$)|(^(COMMENT|HISTORY)$)/ and | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 1306 |  |  |  |  |  |  | $value =~ s:\s*(? | 
| 1307 |  |  |  |  |  |  | ) { | 
| 1308 | 2 |  |  |  |  | 7 | my $comment = $1; | 
| 1309 |  |  |  |  |  |  |  | 
| 1310 |  |  |  |  |  |  | # Recurse to store the comment.  This is a direct (non-method) call to | 
| 1311 |  |  |  |  |  |  | # keep this method monolithic.  --CED 27-Jun-2003 | 
| 1312 | 2 |  |  |  |  | 13 | STORE($self,$keyword."_COMMENT",$comment); | 
| 1313 |  |  |  |  |  |  |  | 
| 1314 |  |  |  |  |  |  | } | 
| 1315 |  |  |  |  |  |  |  | 
| 1316 |  |  |  |  |  |  | # unescape (unless we are blessed) | 
| 1317 | 22 | 100 | 66 |  |  | 80 | if (defined $value && !ref($value)) { | 
| 1318 | 17 |  |  |  |  | 32 | $value =~ s:\\\\:\\:g; | 
| 1319 | 17 |  |  |  |  | 31 | $value =~ s:\\\/:\/:g; | 
| 1320 |  |  |  |  |  |  | } | 
| 1321 |  |  |  |  |  |  |  | 
| 1322 |  |  |  |  |  |  | # skip the shenanigans for the normal case | 
| 1323 |  |  |  |  |  |  | # or if we have an Astro::FITS::Header | 
| 1324 | 22 | 50 | 66 |  |  | 189 | if (!defined $value) { | 
|  |  | 100 | 100 |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 1325 | 0 |  |  |  |  | 0 | @values = ($value); | 
| 1326 |  |  |  |  |  |  |  | 
| 1327 |  |  |  |  |  |  | } elsif (UNIVERSAL::isa($value, "Astro::FITS::Header")) { | 
| 1328 | 1 |  |  |  |  | 3 | @values = ($value); | 
| 1329 |  |  |  |  |  |  |  | 
| 1330 |  |  |  |  |  |  | } elsif (ref $value eq 'HASH') { | 
| 1331 |  |  |  |  |  |  | # Convert a hash to a Astro::FITS::Header | 
| 1332 |  |  |  |  |  |  | # If this is a tied hash already just get the object | 
| 1333 | 3 |  |  |  |  | 6 | my $tied = tied %$value; | 
| 1334 | 3 | 100 | 66 |  |  | 11 | if (defined $tied && UNIVERSAL::isa($tied, "Astro::FITS::Header")) { | 
| 1335 |  |  |  |  |  |  | # Just take the object | 
| 1336 | 1 |  |  |  |  | 3 | @values = ($tied); | 
| 1337 |  |  |  |  |  |  | } else { | 
| 1338 |  |  |  |  |  |  | # Convert it to a hash | 
| 1339 | 2 |  |  |  |  | 5 | @values = ( Astro::FITS::Header->new( Hash => $value ) ); | 
| 1340 |  |  |  |  |  |  | } | 
| 1341 |  |  |  |  |  |  |  | 
| 1342 |  |  |  |  |  |  | } elsif ((ref $value eq 'ARRAY') || (length $value > 70) || $value =~ m/\n/s ) { | 
| 1343 | 3 |  |  |  |  | 6 | my @val; | 
| 1344 |  |  |  |  |  |  | # @val gets intermediate breakdowns, @values gets line-by-line breakdowns. | 
| 1345 |  |  |  |  |  |  |  | 
| 1346 |  |  |  |  |  |  | # Change multiline strings into array refs | 
| 1347 | 3 | 100 |  |  |  | 18 | if (ref $value eq 'ARRAY') { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 1348 | 1 |  |  |  |  | 18 | @val = @$value; | 
| 1349 |  |  |  |  |  |  |  | 
| 1350 |  |  |  |  |  |  | } elsif (ref $value) { | 
| 1351 | 0 |  |  |  |  | 0 | croak "Can't put non-array ref values into a tied FITS header\n"; | 
| 1352 |  |  |  |  |  |  |  | 
| 1353 |  |  |  |  |  |  | } elsif ( $value =~ m/\n/s ) { | 
| 1354 | 2 |  |  |  |  | 7 | @val = split("\n",$value); | 
| 1355 | 2 |  |  |  |  | 5 | chomp @val; | 
| 1356 |  |  |  |  |  |  |  | 
| 1357 |  |  |  |  |  |  | } else { | 
| 1358 | 0 |  |  |  |  | 0 | @val = $value; | 
| 1359 |  |  |  |  |  |  | } | 
| 1360 |  |  |  |  |  |  |  | 
| 1361 |  |  |  |  |  |  | # Cut up really long items into multiline strings | 
| 1362 | 3 |  |  |  |  | 5 | my($val); | 
| 1363 | 3 |  |  |  |  | 8 | foreach $val(@val) { | 
| 1364 | 8 |  |  |  |  | 18 | while ((length $val) > 70) { | 
| 1365 | 0 |  |  |  |  | 0 | push(@values,substr($val,0,69)."\\"); | 
| 1366 | 0 |  |  |  |  | 0 | $val = substr($val,69); | 
| 1367 |  |  |  |  |  |  | } | 
| 1368 | 8 |  |  |  |  | 17 | push(@values,$val); | 
| 1369 |  |  |  |  |  |  | } | 
| 1370 |  |  |  |  |  |  | }                             ## End of complicated case | 
| 1371 |  |  |  |  |  |  | else { | 
| 1372 |  |  |  |  |  |  |  | 
| 1373 |  |  |  |  |  |  |  | 
| 1374 |  |  |  |  |  |  |  | 
| 1375 | 15 |  |  |  |  | 47 | @values = ($value); | 
| 1376 |  |  |  |  |  |  | } | 
| 1377 |  |  |  |  |  |  |  | 
| 1378 |  |  |  |  |  |  | # Upper case the relevant item name | 
| 1379 | 22 |  |  |  |  | 48 | $keyword = uc($keyword); | 
| 1380 |  |  |  |  |  |  |  | 
| 1381 | 22 | 100 |  |  |  | 60 | if ($keyword eq 'END') { | 
| 1382 |  |  |  |  |  |  | # Special case for END keyword | 
| 1383 |  |  |  |  |  |  | # (drops value on floor, makes sure there is one END at the end) | 
| 1384 | 1 |  |  |  |  | 4 | my @index = $self->index($keyword); | 
| 1385 | 1 | 50 | 33 |  |  | 6 | if ( @index != 1   ||   $index[0] != $#{$self->allitems}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 1386 | 1 |  |  |  |  | 2 | my $i; | 
| 1387 | 1 |  |  |  |  | 6 | while (defined($i = shift @index)) { | 
| 1388 | 0 |  |  |  |  | 0 | $self->remove($i); | 
| 1389 |  |  |  |  |  |  | } | 
| 1390 |  |  |  |  |  |  | } | 
| 1391 | 1 | 50 |  |  |  | 3 | unless( @index ) { | 
| 1392 | 1 |  |  |  |  | 12 | my $endcard = new Astro::FITS::Header::Item(Keyword=>'END', | 
| 1393 |  |  |  |  |  |  | Type=>'END', | 
| 1394 |  |  |  |  |  |  | Value=>1); | 
| 1395 | 1 |  |  |  |  | 7 | $self->insert( scalar ($self->allitems) , $endcard ); | 
| 1396 |  |  |  |  |  |  | } | 
| 1397 | 1 |  |  |  |  | 4 | return; | 
| 1398 |  |  |  |  |  |  |  | 
| 1399 |  |  |  |  |  |  | } | 
| 1400 |  |  |  |  |  |  |  | 
| 1401 | 21 | 100 |  |  |  | 55 | if ($keyword eq 'SIMPLE') { | 
| 1402 |  |  |  |  |  |  | # Special case for SIMPLE keyword | 
| 1403 |  |  |  |  |  |  | # (sets value correctly, makes sure there is one SIMPLE at the beginning) | 
| 1404 | 1 |  |  |  |  | 6 | my @index = $self->index($keyword); | 
| 1405 | 1 | 50 | 33 |  |  | 8 | if ( @index != 1  ||  $index[0] != 0) { | 
| 1406 | 1 |  |  |  |  | 54 | my $i; | 
| 1407 | 1 |  |  |  |  | 39 | while (defined ($i=shift @index)) { | 
| 1408 | 0 |  |  |  |  | 0 | $self->remove($i); | 
| 1409 |  |  |  |  |  |  | } | 
| 1410 |  |  |  |  |  |  | } | 
| 1411 | 1 | 50 |  |  |  | 8 | unless( @index ) { | 
| 1412 | 1 |  |  |  |  | 19 | my $simplecard = new Astro::FITS::Header::Item(Keyword=>'SIMPLE', | 
| 1413 |  |  |  |  |  |  | Value=>$values[0], | 
| 1414 |  |  |  |  |  |  | Type=>'LOGICAL'); | 
| 1415 | 1 |  |  |  |  | 9 | $self->insert(0, $simplecard); | 
| 1416 |  |  |  |  |  |  | } | 
| 1417 | 1 |  |  |  |  | 6 | return; | 
| 1418 |  |  |  |  |  |  | } | 
| 1419 |  |  |  |  |  |  |  | 
| 1420 |  |  |  |  |  |  |  | 
| 1421 |  |  |  |  |  |  | # Recognise _COMMENT | 
| 1422 | 20 |  |  |  |  | 31 | my $havevalue = 1; | 
| 1423 | 20 | 100 |  |  |  | 46 | if ($keyword =~ /_COMMENT$/) { | 
| 1424 | 3 |  |  |  |  | 10 | $keyword =~ s/_COMMENT$//; | 
| 1425 | 3 |  |  |  |  | 6 | $havevalue = 0; | 
| 1426 |  |  |  |  |  |  | } | 
| 1427 |  |  |  |  |  |  |  | 
| 1428 | 20 |  |  |  |  | 47 | my @items = $self->itembyname($keyword); | 
| 1429 |  |  |  |  |  |  |  | 
| 1430 |  |  |  |  |  |  | ## Remove extra items if necessary | 
| 1431 | 20 | 100 |  |  |  | 48 | if (scalar(@items) > scalar(@values)) { | 
| 1432 | 2 |  |  |  |  | 5 | my(@indices) = $self->index($keyword); | 
| 1433 | 2 |  |  |  |  | 4 | my($i); | 
| 1434 | 2 |  |  |  |  | 7 | for $i (1..(scalar(@items) - scalar(@values))) { | 
| 1435 | 3 |  |  |  |  | 8 | $self->remove( $indices[-$i] ); | 
| 1436 |  |  |  |  |  |  | } | 
| 1437 |  |  |  |  |  |  | } | 
| 1438 |  |  |  |  |  |  |  | 
| 1439 |  |  |  |  |  |  | ## Allocate new items if necessary | 
| 1440 | 20 |  |  |  |  | 56 | while (scalar(@items) < scalar(@values)) { | 
| 1441 |  |  |  |  |  |  |  | 
| 1442 | 16 |  |  |  |  | 58 | my $item = new Astro::FITS::Header::Item(Keyword=>$keyword,Value=>undef); | 
| 1443 |  |  |  |  |  |  | # (No need to set type here; Item does it for us) | 
| 1444 |  |  |  |  |  |  |  | 
| 1445 | 16 |  |  |  |  | 60 | $self->insert(-1,$item); | 
| 1446 | 16 |  |  |  |  | 40 | push(@items,$item); | 
| 1447 |  |  |  |  |  |  | } | 
| 1448 |  |  |  |  |  |  |  | 
| 1449 |  |  |  |  |  |  | ## Set values or comments | 
| 1450 | 20 |  |  |  |  | 41 | my($i); | 
| 1451 | 20 |  |  |  |  | 47 | for $i(0..$#values) { | 
| 1452 | 25 | 100 |  |  |  | 76 | if ($Astro::FITS::Header::COMMENT_FIELD{$keyword}) { | 
|  |  | 100 |  |  |  |  |  | 
| 1453 | 6 |  |  |  |  | 15 | $items[$i]->type('COMMENT'); | 
| 1454 | 6 |  |  |  |  | 12 | $items[$i]->comment($values[$i]); | 
| 1455 |  |  |  |  |  |  | } elsif (! $havevalue) { | 
| 1456 |  |  |  |  |  |  | # This is actually just changing the comment | 
| 1457 | 3 |  |  |  |  | 21 | $items[$i]->comment($values[$i]); | 
| 1458 |  |  |  |  |  |  | } else { | 
| 1459 | 16 | 100 | 100 |  |  | 97 | $items[$i]->type( (($#values > 0) || ref $value) ? 'STRING' : undef); | 
| 1460 |  |  |  |  |  |  |  | 
| 1461 | 16 |  |  |  |  | 81 | $items[$i]->value($values[$i]); | 
| 1462 | 16 | 100 |  |  |  | 94 | $items[$i]->type("STRING") if($#values > 0); | 
| 1463 |  |  |  |  |  |  | } | 
| 1464 |  |  |  |  |  |  | } | 
| 1465 |  |  |  |  |  |  | } | 
| 1466 |  |  |  |  |  |  |  | 
| 1467 |  |  |  |  |  |  |  | 
| 1468 |  |  |  |  |  |  | # reports whether a key is present in the hash | 
| 1469 |  |  |  |  |  |  | # SUBHEADERS only exist if there are subheaders | 
| 1470 |  |  |  |  |  |  | sub EXISTS { | 
| 1471 | 12 |  |  | 12 |  | 2825 | my ($self, $keyword) = @_; | 
| 1472 | 12 |  |  |  |  | 26 | $keyword = uc($keyword); | 
| 1473 |  |  |  |  |  |  |  | 
| 1474 | 12 | 100 |  |  |  | 33 | if ($keyword eq 'SUBHEADERS') { | 
| 1475 | 3 | 100 |  |  |  | 7 | return ( scalar(@{$self->subhdrs}) > 0 ? 1 : 0); | 
|  | 3 |  |  |  |  | 9 |  | 
| 1476 |  |  |  |  |  |  | } | 
| 1477 |  |  |  |  |  |  |  | 
| 1478 | 9 | 100 |  |  |  | 12 | if ( !exists( ${$self->{LOOKUP}}{$keyword} ) ) { | 
|  | 9 |  |  |  |  | 28 |  | 
| 1479 | 2 |  |  |  |  | 10 | return undef; | 
| 1480 |  |  |  |  |  |  | } | 
| 1481 |  |  |  |  |  |  |  | 
| 1482 |  |  |  |  |  |  | # if we are being asked for a keyword that is associated with a COMMENT or BLANK | 
| 1483 |  |  |  |  |  |  | # type we return FALSE for existence. An undef type means we have to assume a valid | 
| 1484 |  |  |  |  |  |  | # item with unknown type | 
| 1485 | 7 | 50 |  |  |  | 11 | if (  exists( ${$self->{LOOKUP}}{$keyword} ) ) { | 
|  | 7 |  |  |  |  | 17 |  | 
| 1486 | 7 |  |  |  |  | 11 | my $item = ${$self->{HEADER}}[${$self->{LOOKUP}}{$keyword}[0]]; | 
|  | 7 |  |  |  |  | 17 |  | 
|  | 7 |  |  |  |  | 11 |  | 
| 1487 | 7 |  |  |  |  | 19 | my $type = $item->type; | 
| 1488 | 7 | 100 | 66 |  |  | 40 | return undef if (defined $type && ($type eq 'COMMENT' || $type eq 'BLANK') ); | 
|  |  |  | 66 |  |  |  |  | 
| 1489 |  |  |  |  |  |  | } | 
| 1490 |  |  |  |  |  |  |  | 
| 1491 | 6 |  |  |  |  | 20 | return 1; | 
| 1492 |  |  |  |  |  |  |  | 
| 1493 |  |  |  |  |  |  | } | 
| 1494 |  |  |  |  |  |  |  | 
| 1495 |  |  |  |  |  |  | # deletes a key and value pair | 
| 1496 |  |  |  |  |  |  | sub DELETE { | 
| 1497 | 1 |  |  | 1 |  | 738 | my ($self, $keyword) = @_; | 
| 1498 | 1 |  |  |  |  | 4 | return $self->removebyname($keyword); | 
| 1499 |  |  |  |  |  |  | } | 
| 1500 |  |  |  |  |  |  |  | 
| 1501 |  |  |  |  |  |  | # empties the hash | 
| 1502 |  |  |  |  |  |  | sub CLEAR { | 
| 1503 | 3 |  |  | 3 |  | 1241 | my $self = shift; | 
| 1504 | 3 |  |  |  |  | 78 | $self->{HEADER} = [ ]; | 
| 1505 | 3 |  |  |  |  | 26 | $self->{LOOKUP} = { }; | 
| 1506 | 3 |  |  |  |  | 7 | $self->{LASTKEY} = undef; | 
| 1507 | 3 |  |  |  |  | 20 | $self->{SEENKEY} = undef; | 
| 1508 | 3 |  |  |  |  | 15 | $self->{SUBHDRS} = [ ]; | 
| 1509 |  |  |  |  |  |  | } | 
| 1510 |  |  |  |  |  |  |  | 
| 1511 |  |  |  |  |  |  | # implements keys() and each() | 
| 1512 |  |  |  |  |  |  | sub FIRSTKEY { | 
| 1513 | 9 |  |  | 9 |  | 1140 | my $self = shift; | 
| 1514 | 9 |  |  |  |  | 17 | $self->{LASTKEY} = 0; | 
| 1515 | 9 |  |  |  |  | 19 | $self->{SEENKEY} = {}; | 
| 1516 | 9 | 100 |  |  |  | 13 | return $self->_check_for_subhdr() unless @{$self->{HEADER}}; | 
|  | 9 |  |  |  |  | 30 |  | 
| 1517 | 8 |  |  |  |  | 14 | return ${$self->{HEADER}}[0]->keyword(); | 
|  | 8 |  |  |  |  | 28 |  | 
| 1518 |  |  |  |  |  |  | } | 
| 1519 |  |  |  |  |  |  |  | 
| 1520 |  |  |  |  |  |  | # implements keys() and each() | 
| 1521 |  |  |  |  |  |  | sub NEXTKEY { | 
| 1522 | 147 |  |  | 147 |  | 306 | my ($self, $keyword) = @_; | 
| 1523 |  |  |  |  |  |  |  | 
| 1524 |  |  |  |  |  |  | # abort if the number of keys we have served equals the number in the | 
| 1525 |  |  |  |  |  |  | # header array. One wrinkle is that if we have SUBHDRS we want to go | 
| 1526 |  |  |  |  |  |  | # round one more time | 
| 1527 |  |  |  |  |  |  |  | 
| 1528 | 147 | 100 |  |  |  | 210 | if ($self->{LASTKEY}+1 == scalar(@{$self->{HEADER}})) { | 
|  | 147 |  |  |  |  | 283 |  | 
| 1529 | 10 |  |  |  |  | 23 | return $self->_check_for_subhdr(); | 
| 1530 |  |  |  |  |  |  | } | 
| 1531 |  |  |  |  |  |  |  | 
| 1532 |  |  |  |  |  |  | # Skip later lines of multi-line cards since the tie interface | 
| 1533 |  |  |  |  |  |  | # will return all the lines for a single keyword request. | 
| 1534 | 137 |  |  |  |  | 186 | my($a); | 
| 1535 |  |  |  |  |  |  | do { | 
| 1536 | 139 |  |  |  |  | 169 | $self->{LASTKEY} += 1; | 
| 1537 | 139 |  |  |  |  | 214 | $a = $self->{HEADER}->[$self->{LASTKEY}]; | 
| 1538 |  |  |  |  |  |  | # Got to end of header if we do not have $a | 
| 1539 | 139 | 50 |  |  |  | 376 | return $self->_check_for_subhdr() unless defined $a; | 
| 1540 | 137 |  |  |  |  | 180 | } while ( $self->{SEENKEY}->{$a->keyword}); | 
| 1541 | 137 |  |  |  |  | 268 | $a = $a->keyword; | 
| 1542 |  |  |  |  |  |  |  | 
| 1543 | 137 |  |  |  |  | 232 | $self->{SEENKEY}->{$a} = 1; | 
| 1544 | 137 |  |  |  |  | 389 | return $a; | 
| 1545 |  |  |  |  |  |  | } | 
| 1546 |  |  |  |  |  |  |  | 
| 1547 |  |  |  |  |  |  | # called if we have run out of normal keys | 
| 1548 |  |  |  |  |  |  | #  args: $self Returns: undef or "SUBHEADER" | 
| 1549 |  |  |  |  |  |  | sub _check_for_subhdr { | 
| 1550 | 11 |  |  | 11 |  | 14 | my $self = shift; | 
| 1551 | 11 | 100 | 100 |  |  | 20 | if (scalar(@{ $self->subhdrs}) && !$self->{SEENKEY}->{SUBHEADERS}) { | 
|  | 11 |  |  |  |  | 22 |  | 
| 1552 | 2 |  |  |  |  | 5 | $self->{SEENKEY}->{SUBHEADERS} = 1; | 
| 1553 | 2 |  |  |  |  | 7 | return "SUBHEADERS"; | 
| 1554 |  |  |  |  |  |  | } | 
| 1555 | 9 |  |  |  |  | 37 | return undef; | 
| 1556 |  |  |  |  |  |  | } | 
| 1557 |  |  |  |  |  |  |  | 
| 1558 |  |  |  |  |  |  |  | 
| 1559 |  |  |  |  |  |  | # garbage collection | 
| 1560 |  |  |  |  |  |  | # sub DESTROY { } | 
| 1561 |  |  |  |  |  |  |  | 
| 1562 |  |  |  |  |  |  | # T I M E   A T   T H E   B A R  -------------------------------------------- | 
| 1563 |  |  |  |  |  |  |  | 
| 1564 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 1565 |  |  |  |  |  |  |  | 
| 1566 |  |  |  |  |  |  | C, C, | 
| 1567 |  |  |  |  |  |  | C, C. | 
| 1568 |  |  |  |  |  |  |  | 
| 1569 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 1570 |  |  |  |  |  |  |  | 
| 1571 |  |  |  |  |  |  | Copyright (C) 2007-2011 Science and Technology Facilties Council. | 
| 1572 |  |  |  |  |  |  | Copyright (C) 2001-2007 Particle Physics and Astronomy Research Council | 
| 1573 |  |  |  |  |  |  | and portions Copyright (C) 2002 Southwest Research Institute. | 
| 1574 |  |  |  |  |  |  | All Rights Reserved. | 
| 1575 |  |  |  |  |  |  |  | 
| 1576 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it under | 
| 1577 |  |  |  |  |  |  | the terms of the GNU General Public License as published by the Free Software | 
| 1578 |  |  |  |  |  |  | Foundation; either version 3 of the License, or (at your option) any later | 
| 1579 |  |  |  |  |  |  | version. | 
| 1580 |  |  |  |  |  |  |  | 
| 1581 |  |  |  |  |  |  | This program is distributed in the hope that it will be useful,but WITHOUT ANY | 
| 1582 |  |  |  |  |  |  | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | 
| 1583 |  |  |  |  |  |  | PARTICULAR PURPOSE. See the GNU General Public License for more details. | 
| 1584 |  |  |  |  |  |  |  | 
| 1585 |  |  |  |  |  |  | You should have received a copy of the GNU General Public License along with | 
| 1586 |  |  |  |  |  |  | this program; if not, write to the Free Software Foundation, Inc., 59 Temple | 
| 1587 |  |  |  |  |  |  | Place,Suite 330, Boston, MA  02111-1307, USA | 
| 1588 |  |  |  |  |  |  |  | 
| 1589 |  |  |  |  |  |  | =head1 AUTHORS | 
| 1590 |  |  |  |  |  |  |  | 
| 1591 |  |  |  |  |  |  | Alasdair Allan Eaa@astro.ex.ac.ukE, | 
| 1592 |  |  |  |  |  |  | Tim Jenness Et.jenness@jach.hawaii.eduE, | 
| 1593 |  |  |  |  |  |  | Craig DeForest Edeforest@boulder.swri.eduE, | 
| 1594 |  |  |  |  |  |  | Jim Lewis Ejrl@ast.cam.ac.ukE, | 
| 1595 |  |  |  |  |  |  | Brad Cavanagh Eb.cavanagh@jach.hawaii.eduE | 
| 1596 |  |  |  |  |  |  |  | 
| 1597 |  |  |  |  |  |  | =cut | 
| 1598 |  |  |  |  |  |  |  | 
| 1599 |  |  |  |  |  |  | package Astro::FITS::HeaderCollection; | 
| 1600 |  |  |  |  |  |  |  | 
| 1601 | 10 |  |  | 10 |  | 52178 | use 5.006; | 
|  | 10 |  |  |  |  | 59 |  | 
| 1602 | 10 |  |  | 10 |  | 59 | use warnings; | 
|  | 10 |  |  |  |  | 32 |  | 
|  | 10 |  |  |  |  | 687 |  | 
| 1603 | 10 |  |  | 10 |  | 80 | use strict; | 
|  | 10 |  |  |  |  | 24 |  | 
|  | 10 |  |  |  |  | 403 |  | 
| 1604 | 10 |  |  | 10 |  | 71 | use Carp; | 
|  | 10 |  |  |  |  | 62 |  | 
|  | 10 |  |  |  |  | 8907 |  | 
| 1605 |  |  |  |  |  |  |  | 
| 1606 |  |  |  |  |  |  | our $VERSION; | 
| 1607 |  |  |  |  |  |  | $VERSION = '3.09'; | 
| 1608 |  |  |  |  |  |  |  | 
| 1609 |  |  |  |  |  |  | # Class wrapper for subhdrs tie. Not (yet) a public interface | 
| 1610 |  |  |  |  |  |  | # we simply need a class that we can tie the subhdrs array to. | 
| 1611 |  |  |  |  |  |  |  | 
| 1612 |  |  |  |  |  |  | sub TIEARRAY { | 
| 1613 | 2 |  |  | 2 |  | 9 | my ($class, $container) = @_; | 
| 1614 |  |  |  |  |  |  | # create an object, but we want to avoid blessing the actual | 
| 1615 |  |  |  |  |  |  | # array into this class | 
| 1616 | 2 |  |  |  |  | 17 | return bless { SUBHDRS => $container }, $class; | 
| 1617 |  |  |  |  |  |  | } | 
| 1618 |  |  |  |  |  |  |  | 
| 1619 |  |  |  |  |  |  | # must return a new tie | 
| 1620 |  |  |  |  |  |  | sub FETCH { | 
| 1621 | 7 |  |  | 7 |  | 33 | my $self = shift; | 
| 1622 | 7 |  |  |  |  | 11 | my $index = shift; | 
| 1623 |  |  |  |  |  |  |  | 
| 1624 | 7 |  |  |  |  | 20 | my $arr = $self->{SUBHDRS}; | 
| 1625 | 7 | 50 | 33 |  |  | 34 | if ( $index >= 0 && $index <= $#$arr ) { | 
| 1626 | 7 |  |  |  |  | 21 | return $self->_hdr_to_tie( $arr->[$index] ); | 
| 1627 |  |  |  |  |  |  | } else { | 
| 1628 | 0 |  |  |  |  | 0 | return undef; | 
| 1629 |  |  |  |  |  |  | } | 
| 1630 |  |  |  |  |  |  | } | 
| 1631 |  |  |  |  |  |  |  | 
| 1632 |  |  |  |  |  |  | sub STORE { | 
| 1633 | 2 |  |  | 2 |  | 4 | my $self = shift; | 
| 1634 | 2 |  |  |  |  | 3 | my $index = shift; | 
| 1635 | 2 |  |  |  |  | 4 | my $value = shift; | 
| 1636 |  |  |  |  |  |  |  | 
| 1637 | 2 |  |  |  |  | 4 | my $hdr = $self->_tie_to_hdr( $value ); | 
| 1638 | 2 |  |  |  |  | 8 | $self->{SUBHDRS}->[$index] = $hdr; | 
| 1639 |  |  |  |  |  |  | } | 
| 1640 |  |  |  |  |  |  |  | 
| 1641 |  |  |  |  |  |  | sub FETCHSIZE { | 
| 1642 | 4 |  |  | 4 |  | 878 | my $self = shift; | 
| 1643 | 4 |  |  |  |  | 7 | return scalar( @{ $self->{SUBHDRS} }); | 
|  | 4 |  |  |  |  | 21 |  | 
| 1644 |  |  |  |  |  |  | } | 
| 1645 |  |  |  |  |  |  |  | 
| 1646 |  |  |  |  |  |  | sub STORESIZE { | 
| 1647 | 0 |  |  | 0 |  | 0 | croak "Tied STORESIZE for SUBHDRS not yet implemented\n"; | 
| 1648 |  |  |  |  |  |  | } | 
| 1649 |  |  |  |  |  |  |  | 
| 1650 |  |  |  | 0 |  |  | sub EXTEND { | 
| 1651 |  |  |  |  |  |  |  | 
| 1652 |  |  |  |  |  |  | } | 
| 1653 |  |  |  |  |  |  |  | 
| 1654 |  |  |  |  |  |  | sub EXISTS { | 
| 1655 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 1656 | 0 |  |  |  |  | 0 | my $index = shift; | 
| 1657 | 0 |  |  |  |  | 0 | my $arr = $self->{SUBHDRS}; | 
| 1658 |  |  |  |  |  |  |  | 
| 1659 | 0 | 0 | 0 |  |  | 0 | return 0 if $index > $#$arr || $index < 0; | 
| 1660 | 0 | 0 |  |  |  | 0 | return 1 if defined $self->{SUBHDRS}->[$index]; | 
| 1661 | 0 |  |  |  |  | 0 | return 0; | 
| 1662 |  |  |  |  |  |  | } | 
| 1663 |  |  |  |  |  |  |  | 
| 1664 |  |  |  |  |  |  | sub DELETE { | 
| 1665 | 0 |  |  | 0 |  | 0 | my $self = shift; | 
| 1666 | 0 |  |  |  |  | 0 | my $index = shift; | 
| 1667 | 0 |  |  |  |  | 0 | $self->{SUBHDRS}->[$index] = undef; | 
| 1668 |  |  |  |  |  |  | } | 
| 1669 |  |  |  |  |  |  |  | 
| 1670 |  |  |  |  |  |  | sub CLEAR { | 
| 1671 | 1 |  |  | 1 |  | 3 | my $self = shift; | 
| 1672 | 1 |  |  |  |  | 2 | @{ $self->{SUBHDRS} } = (); | 
|  | 1 |  |  |  |  | 4 |  | 
| 1673 |  |  |  |  |  |  | } | 
| 1674 |  |  |  |  |  |  |  | 
| 1675 |  |  |  |  |  |  | sub PUSH { | 
| 1676 | 1 |  |  | 1 |  | 598 | my $self = shift; | 
| 1677 | 1 |  |  |  |  | 3 | my @list = @_; | 
| 1678 |  |  |  |  |  |  |  | 
| 1679 |  |  |  |  |  |  | # convert | 
| 1680 | 1 |  |  |  |  | 2 | @list = map { $self->_tie_to_hdr($_) } @list; | 
|  | 1 |  |  |  |  | 3 |  | 
| 1681 | 1 |  |  |  |  | 6 | push(@{ $self->{SUBHDRS} }, @list); | 
|  | 1 |  |  |  |  | 4 |  | 
| 1682 |  |  |  |  |  |  | } | 
| 1683 |  |  |  |  |  |  |  | 
| 1684 |  |  |  |  |  |  | sub POP { | 
| 1685 | 1 |  |  | 1 |  | 333 | my $self = shift; | 
| 1686 | 1 |  |  |  |  | 2 | my $popped = pop( @{ $self->{SUBHDRS} } ); | 
|  | 1 |  |  |  |  | 2 |  | 
| 1687 | 1 |  |  |  |  | 3 | return $self->_hdr_to_tie($popped); | 
| 1688 |  |  |  |  |  |  | } | 
| 1689 |  |  |  |  |  |  |  | 
| 1690 |  |  |  |  |  |  | sub SHIFT { | 
| 1691 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 1692 | 1 |  |  |  |  | 2 | my $shifted = shift( @{ $self->{SUBHDRS} } ); | 
|  | 1 |  |  |  |  | 2 |  | 
| 1693 | 1 |  |  |  |  | 4 | return $self->_hdr_to_tie($shifted); | 
| 1694 |  |  |  |  |  |  | } | 
| 1695 |  |  |  |  |  |  |  | 
| 1696 |  |  |  |  |  |  | sub UNSHIFT { | 
| 1697 | 1 |  |  | 1 |  | 625 | my $self = shift; | 
| 1698 | 1 |  |  |  |  | 2 | my @list = @_; | 
| 1699 |  |  |  |  |  |  |  | 
| 1700 |  |  |  |  |  |  | # convert | 
| 1701 | 1 |  |  |  |  | 3 | @list = map { $self->_tie_to_hdr($_) } @list; | 
|  | 1 |  |  |  |  | 3 |  | 
| 1702 | 1 |  |  |  |  | 2 | unshift(@{ $self->{SUBHDRS} }, @list); | 
|  | 1 |  |  |  |  | 4 |  | 
| 1703 |  |  |  |  |  |  |  | 
| 1704 |  |  |  |  |  |  | } | 
| 1705 |  |  |  |  |  |  |  | 
| 1706 |  |  |  |  |  |  | # internal mappings | 
| 1707 |  |  |  |  |  |  |  | 
| 1708 |  |  |  |  |  |  | # Given an Astro::FITS::Header object, return the thing that | 
| 1709 |  |  |  |  |  |  | # should be returned to the user of the tie | 
| 1710 |  |  |  |  |  |  | sub _hdr_to_tie { | 
| 1711 | 9 |  |  | 9 |  | 14 | my $self = shift; | 
| 1712 | 9 |  |  |  |  | 14 | my $hdr = shift; | 
| 1713 |  |  |  |  |  |  |  | 
| 1714 | 9 | 50 |  |  |  | 21 | if (defined $hdr) { | 
| 1715 | 9 |  |  |  |  | 12 | my %header; | 
| 1716 | 9 |  |  |  |  | 36 | tie %header, ref($hdr), $hdr; | 
| 1717 | 9 |  |  |  |  | 83 | return \%header; | 
| 1718 |  |  |  |  |  |  | } | 
| 1719 | 0 |  |  |  |  | 0 | return undef; | 
| 1720 |  |  |  |  |  |  | } | 
| 1721 |  |  |  |  |  |  |  | 
| 1722 |  |  |  |  |  |  | # convert an input argument as either a Astro::FITS::Header object | 
| 1723 |  |  |  |  |  |  | # or a hash, to an internal representation (an A:F:H object) | 
| 1724 |  |  |  |  |  |  | sub _tie_to_hdr { | 
| 1725 | 4 |  |  | 4 |  | 7 | my $self = shift; | 
| 1726 | 4 |  |  |  |  | 5 | my $value = shift; | 
| 1727 |  |  |  |  |  |  |  | 
| 1728 | 4 | 50 |  |  |  | 16 | if (UNIVERSAL::isa($value, "Astro::FITS::Header")) { | 
|  |  | 50 |  |  |  |  |  | 
| 1729 | 0 |  |  |  |  | 0 | return $value; | 
| 1730 |  |  |  |  |  |  | } elsif (ref($value) eq 'HASH') { | 
| 1731 | 4 |  |  |  |  | 8 | my $tied = tied %$value; | 
| 1732 | 4 | 100 | 66 |  |  | 19 | if (defined $tied && UNIVERSAL::isa($tied, "Astro::FITS::Header")) { | 
| 1733 |  |  |  |  |  |  | # Just take the object | 
| 1734 | 3 |  |  |  |  | 10 | return $tied; | 
| 1735 |  |  |  |  |  |  | } else { | 
| 1736 |  |  |  |  |  |  | # Convert it to a hash | 
| 1737 |  |  |  |  |  |  | my @items = map { new Astro::FITS::Header::Item( Keyword => $_, | 
| 1738 | 1 |  |  |  |  | 4 | Value => $value->{$_} | 
| 1739 | 1 |  |  |  |  | 2 | ) } keys (%{$value}); | 
|  | 1 |  |  |  |  | 4 |  | 
| 1740 |  |  |  |  |  |  |  | 
| 1741 |  |  |  |  |  |  | # Create the Header object. | 
| 1742 | 1 |  |  |  |  | 3 | return new Astro::FITS::Header( Cards => \@items ); | 
| 1743 |  |  |  |  |  |  |  | 
| 1744 |  |  |  |  |  |  | } | 
| 1745 |  |  |  |  |  |  | } else { | 
| 1746 | 0 |  |  |  |  |  | croak "Do not know how to store '$value' in a SUBHEADER\n"; | 
| 1747 |  |  |  |  |  |  | } | 
| 1748 |  |  |  |  |  |  | } | 
| 1749 |  |  |  |  |  |  |  | 
| 1750 |  |  |  |  |  |  | # L A S T  O R D E R S ------------------------------------------------------ | 
| 1751 |  |  |  |  |  |  |  | 
| 1752 |  |  |  |  |  |  | 1; |