Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaAstro / FITSIO.jl / 166

26 Jul 2017 - 19:32 coverage: 72.418%. Remained the same
166

Pull #77

travis-ci

9181eb84f9c35729a3bad740fb7f9d93?size=18&default=identiconweb-flow
Minor change
Pull Request #77: [WIP] Add Documenter to build documentation

83 of 102 new or added lines in 5 files covered. (81.37%)

68 existing lines in 5 files now uncovered.

554 of 765 relevant lines covered (72.42%)

149.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.67
/src/header.jl
1
# FITSHeader methods
2

3
# -----------------------------------------------------------------------------
4
# Helper functions
5
#
6
# Used here and in other files. Functions that operate on FITSFile
7
# start with `fits_`.
8

9
function try_parse_hdrval(::Type{Bool}, s::String)
10
    if length(s) == 1
235×
11
        if s[1] == 'T'
168×
12
            return Nullable(true)
77×
13
        elseif s[1] == 'F'
91×
14
            return Nullable(false)
!
15
        end
16
    end
17
    return Nullable{Bool}()
252×
18
end
19

20
# Note that trailing whitespace is not significant in FITS header
21
# keywords, but *leading* whitespace is, so "'    '" parses as " " (a
22
# single space).  See CFITSIO manual section 4.5 for details.
23
#
24
# TODO: parse '' within the string as a single '.
25
function try_parse_hdrval(::Type{String}, s::String)
26
    if length(s) < 2 || s[1] != '\'' || s[end] != '\''
180×
27
        return Nullable{String}()
224×
28
    end
29

30
    i = endof(s) - 1
28×
31
    while i > 2
42×
32
        if s[i] != ' '
49×
33
            return Nullable(s[2:i])
28×
34
        end
35
        i -= 1
33×
36
    end
37
    return Nullable(s[2:i])
!
38
end
39

40
try_parse_hdrval(::Type{Float64}, s::String) = tryparse(Float64, s)
35×
41
try_parse_hdrval(::Type{Int}, s::String) = tryparse(Int, s)
160×
42

43
# Try to parse the header value as any type
44
function try_parse_hdrval(s::String)
45
    length(s) == 0 && return Nullable(nothing)
295×
46

47
    nb = try_parse_hdrval(Bool, s)
329×
48
    isnull(nb) || return nb
517×
49

50
    ns = try_parse_hdrval(String, s)
252×
51
    isnull(ns) || return ns
396×
52

53
    ni = try_parse_hdrval(Int, s)
224×
54
    isnull(ni) || return ni
352×
55

56
    nf = try_parse_hdrval(Float64, s)
49×
57
    isnull(nf) || return nf
77×
58

59
    return Nullable{Any}()
14×
60
end
61

62
# functions for displaying header values in show(io, header)
63
hdrval_repr(v::Bool) = v ? "T" : "F"
!
64
hdrval_repr(v::String) = @sprintf "'%s'" v
!
65
hdrval_repr(v::Union{AbstractFloat, Integer}) = string(v)
!
66

67
# returns one of: String, Bool, Int, Float64, nothing
68
# (never error)
69
function parse_header_val(s::String)
70
    nval = try_parse_hdrval(s)
295×
71
    return isnull(nval) ? s : get(nval)
531×
72
end
73

74
# Try to read the raw keys in order given; returns Nullable.
75
# (null if no key exists or if parsing an existing key is unsuccessful.)
76
function fits_try_read_keys{T}(f::FITSFile, ::Type{T}, keys)
77
    status = Cint[0]
20×
78
    value = Vector{UInt8}(71)
28×
79
    for key in keys
108×
80
        ccall((:ffgkey, libcfitsio), Cint,
136×
81
              (Ptr{Void},Ptr{UInt8},Ptr{UInt8},Ptr{UInt8},Ptr{Cint}),
82
              f.ptr, key, value, C_NULL, status)
83

84
        # If the key is found, return it. If there was some other error
85
        # besides key not found, throw an error.
86
        if status[1] == 0
56×
87
            return try_parse_hdrval(T, unsafe_string(pointer(value)))
!
88
        elseif status[1] != 202
56×
89
            error(fits_get_errstatus(status[1]))
only 166.1 and 166.4 - 16×
90
        end
91
    end
92
    return Nullable{T}()
28×
93
end
94

95
# Build a string with extension keywords, if present.
96
# This is a helper function for show(::HDU).
97
const EXTNAME_KEYS = ["EXTNAME", "HDUNAME"]
98
const EXTVER_KEYS = ["EXTVER", "HDUVER"]
99
fits_try_read_extname(f::FITSFile) =
10×
100
    fits_try_read_keys(f, String, EXTNAME_KEYS)
101
fits_try_read_extver(f::FITSFile) = fits_try_read_keys(f, Int, EXTVER_KEYS)
10×
102

103
function fits_get_ext_info_string(f::FITSFile)
104
    extname = fits_try_read_extname(f)
!
105
    extver = fits_try_read_extver(f)
!
106
    if !isnull(extname) && !isnull(extver)
!
107
        return " (name=$(repr(get(extname))), ver=$(get(extver)))"
!
108
    elseif !isnull(extname)
!
109
        return " (name=$(repr(get(extname))))"
!
110
    end
111
    return ""
!
112
end
113

114

115
# Return indices of reserved keys in a header.
116
# This is more complex than you would think because some reserved keys
117
# are only reserved when other keys are present. Also, in general a key
118
# may appear more than once in a header.
119
const RESERVED_KEYS = ["SIMPLE","EXTEND","XTENSION","BITPIX","PCOUNT","GCOUNT",
120
                       "THEAP","EXTNAME","BSCALE","BZERO","BLANK",
121
                       "ZQUANTIZ","ZDITHER0","ZIMAGE","ZCMPTYPE","ZSIMPLE",
122
                       "ZTENSION","ZPCOUNT","ZGCOUNT","ZBITPIX","ZEXTEND",
123
                       "CHECKSUM","DATASUM"]
124
function reserved_key_indices(hdr::FITSHeader)
125
    nhdr = length(hdr)
15×
126
    indices = Int[]
21×
127
    for i=1:nhdr
199×
128
        if in(hdr.keys[i], RESERVED_KEYS)
140×
129
            push!(indices, i)
67×
130
        end
131
    end
132

133
    # Note that this removes anything matching NAXIS\d regardless of # of axes.
134
    if in("NAXIS", hdr.keys)
21×
135
        for i=1:nhdr
77×
136
            if ismatch(r"^NAXIS\d*$", hdr.keys[i])
56×
137
                push!(indices, i)
43×
138
            end
139
        end
140
    end
141

142
    if in("ZNAXIS", hdr.keys)
21×
143
        for i=1:nhdr
!
144
            if (ismatch(r"^ZNAXIS\d*$", hdr.keys[i]) ||
!
145
                ismatch(r"^ZTILE\d*$", hdr.keys[i]) ||
!
146
                ismatch(r"^ZNAME\d*$", hdr.keys[i]) ||
!
147
                ismatch(r"^ZVAL\d*$", hdr.keys[i]))
!
148
                push!(indices, i)
!
149
            end
150
        end
151
    end
152

153
    if in("TFIELDS", hdr.keys)
21×
154
        for i=1:nhdr
!
155
            for re in [r"^TFORM\d*$", r"^TTYPE\d*$", r"^TDIM\d*$",
!
156
                       r"^TUNIT\d*$", r"^TSCAL\d*$", r"^TZERO\d*$",
!
157
                       r"^TNULL\d*$", r"^TDISP\d*$", r"^TDMIN\d*$",
!
158
                       r"^TDMAX\d*$", r"^TDESC\d*$", r"^TROTA\d*$",
!
159
                       r"^TRPIX\d*$", r"^TRVAL\d*$", r"^TDELT\d*$",
!
160
                       r"^TCUNI\d*$", r"^TFIELDS$"]
!
161
                if ismatch(re, hdr.keys[i])
!
162
                    push!(indices, i)
!
163
                end
164
            end
165
        end
166
    end
167

168
    return indices
21×
169
end
170

171

172
# Write header to CHDU.
173
# If `clean` is true, skip writing reserved header keywords.
174
function fits_write_header(f::FITSFile, hdr::FITSHeader, clean::Bool=true)
175
    indices = clean ? reserved_key_indices(hdr) : Int[]
15×
176
    for i=1:length(hdr)
199×
177
        if clean && in(i, indices)
260×
178
            continue
42×
179
        end
180
        if hdr.keys[i] == "COMMENT"
98×
181
            fits_write_comment(f, hdr.comments[i])
18×
182
        elseif hdr.keys[i] == "HISTORY"
84×
183
            fits_write_history(f, hdr.comments[i])
18×
184
        elseif hdr.comments[i] == ""
70×
185
            fits_update_key(f, hdr.keys[i], hdr.values[i])
!
186
        else
187
            fits_update_key(f, hdr.keys[i], hdr.values[i], hdr.comments[i])
136×
188
        end
189
    end
190
end
191

192

193
# -----------------------------------------------------------------------------
194
# Public API
195

196

197
"""
198
    read_key(hdu, key)
199

200
Read the specified key and return a tuple of `(value, comment)`.
201

202
The key, can be either the index of the header record (Integer)
203
or the header keyword (ASCIIString).
204

205
### Example ###
206

207
```julia
208

209
```
210
"""
211
function read_key(hdu::HDU, key::Integer)
212
    fits_assert_open(hdu.fitsfile)
5×
213
    fits_movabs_hdu(hdu.fitsfile, hdu.ext)
7×
214
    keyout, value, comment = fits_read_keyn(hdu.fitsfile, key)
27×
215
    keyout, parse_header_val(value), comment
7×
216
end
217

218
function read_key(hdu::HDU, key::String)
219
    fits_assert_open(hdu.fitsfile)
5×
220
    fits_movabs_hdu(hdu.fitsfile, hdu.ext)
7×
221
    value, comment = fits_read_keyword(hdu.fitsfile, key)
21×
222
    parse_header_val(value), comment
7×
223
end
224

225
"""
226
    read_header(hdu)
227

228
Read the entire header from the given HDU and return a `FITSHeader` object.
229
The value of each header record is parsed as `Int`, `Float64`, `ASCIIString`,
230
`Bool` or `nothing` according to the FITS standard.
231

232
If the value cannot be parsed according to the FITS standard, the value is
233
stored as the raw unparsed `ASCIIString`.
234

235
### Example ###
236

237
```julia
238

239
```
240
"""
241
function read_header(hdu::HDU)
242
    fits_assert_open(hdu.fitsfile)
25×
243
    fits_movabs_hdu(hdu.fitsfile, hdu.ext)
35×
244

245
    # Below, we use a direct call to ffgkyn so that we can keep reusing the
246
    # same buffers.
247
    key = Vector{UInt8}(81)
35×
248
    value = Vector{UInt8}(81)
35×
249
    comment = Vector{UInt8}(81)
35×
250
    status = Cint[0]
35×
251

252
    nkeys, morekeys = fits_get_hdrspace(hdu.fitsfile)
105×
253

254
    # Initialize output arrays
255
    keys = Vector{String}(nkeys)
35×
256
    values = Vector{Any}(nkeys)
35×
257
    comments = Vector{String}(nkeys)
35×
258
    for i=1:nkeys
521×
259
        ccall((:ffgkyn,libcfitsio), Cint,
1,083×
260
              (Ptr{Void},Cint,Ptr{UInt8},Ptr{UInt8},Ptr{UInt8},Ptr{Cint}),
261
              hdu.fitsfile.ptr, i, key, value, comment, status)
262
        keys[i] = unsafe_string(pointer(key))
513×
263
        values[i] = parse_header_val(unsafe_string(pointer(value)))
513×
264
        comments[i] = unsafe_string(pointer(comment))
741×
265
    end
266
    fits_assert_ok(status[1])
35×
267
    FITSHeader(keys, values, comments)
35×
268
end
269

270
"""
271
    read_header(hdu, String)
272

273
Read the entire header from the given HDU as a single string.
274

275
### Example ###
276

277
```julia
278

279
```
280
"""
281
function read_header(hdu::HDU, ::Type{String})
282
    # Return the header as a raw string.
283

284
    fits_assert_open(hdu.fitsfile)
10×
285
    fits_movabs_hdu(hdu.fitsfile, hdu.ext)
14×
286

287
    fits_hdr2str(hdu.fitsfile)
14×
288
end
289

290
length(hdr::FITSHeader) = length(hdr.keys)
40×
291
haskey(hdr::FITSHeader, key::String) = in(key, hdr.keys)
5×
NEW
292
keys(hdr::FITSHeader) = hdr.keys
!
NEW
293
values(hdr::FITSHeader) = hdr.values
!
294
getindex(hdr::FITSHeader, key::String) = hdr.values[hdr.map[key]]
20×
NEW
295
getindex(hdr::FITSHeader, i::Integer) = hdr.values[i]
!
296

297
function setindex!(hdr::FITSHeader, value::Any, key::String)
298
    if in(key, hdr.keys)
10×
299
        hdr.values[hdr.map[key]] = value
18×
300
    else
UNCOV
301
        push!(hdr.keys, key)
!
UNCOV
302
        push!(hdr.values, value)
!
UNCOV
303
        push!(hdr.comments, "")
!
UNCOV
304
        hdr.map[key] = length(hdr.keys)
!
305
    end
306
end
307

308
function setindex!(hdr::FITSHeader, value::Any, i::Integer)
309
    hdr.values[i] = value
5×
310
end
311

312
# Comments
UNCOV
313
get_comment(hdr::FITSHeader, key::String) = hdr.comments[hdr.map[key]]
!
314
get_comment(hdr::FITSHeader, i::Integer) = hdr.comments[i]
10×
315
function set_comment!(hdr::FITSHeader, key::String, comment::String)
316
    hdr.comments[hdr.map[key]] = comment
5×
317
end
318
function set_comment!(hdr::FITSHeader, i::Integer, comment::String)
NEW
319
    hdr.comments[i] = comment
!
320
end
321

322
# Display the header
323
function show(io::IO, hdr::FITSHeader)
NEW
324
    for i=1:length(hdr)
!
NEW
325
        cl = length(hdr.comments[i])
!
NEW
326
        if hdr.keys[i] == "COMMENT" || hdr.keys[i] == "HISTORY"
!
NEW
327
            if cl > 71
!
NEW
328
                @printf io "%s %s\n" hdr.keys[i] hdr.comments[i][1:71]
!
329
            else
UNCOV
330
                @printf io "%s %s\n" hdr.keys[i] hdr.comments[i]
!
331
            end
332
        else
UNCOV
333
            @printf io "%-8s" hdr.keys[i]
!
334
            if hdr.values[i] === nothing
!
UNCOV
335
                print(io, "                      ")
!
UNCOV
336
                rc = 50  # remaining characters on line
!
337
            else
UNCOV
338
                val = hdrval_repr(hdr.values[i])
!
339
                @printf io "= %20s" val
!
340
                rc = length(val) <= 20 ? 50 : 70 - length(val)
!
341
            end
342

343
            if cl > 0
!
UNCOV
344
                if cl > rc - 3
!
345
                    @printf io " / %s" hdr.comments[i][1:rc-3]
!
346
                else
UNCOV
347
                    @printf io " / %s" hdr.comments[i]
!
348
                end
349
            end
350
            print(io, "\n")
!
351
        end
352
    end
353
end
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2023 Coveralls, Inc