FUNCTION FXPAR, HDR, NAME, ABORT, COUNT=MATCHES, COMMENT=COMMENTS, $
START=START, PRECHECK=PRECHECK, POSTCHECK=POSTCHECK, $
NOCONTINUE = NOCONTINUE, $
DATATYPE=DATATYPE
;+
; NAME:
; FXPAR()
; PURPOSE:
; Obtain the value of a parameter in a FITS header.
; EXPLANATION:
; The first 8 chacters of each element of HDR are searched for a match to
; NAME. If the keyword is one of those allowed to take multiple values
; ("HISTORY", "COMMENT", or " " (blank)), then the value is taken
; as the next 72 characters. Otherwise, it is assumed that the next
; character is "=", and the value (and optional comment) is then parsed
; from the last 71 characters. An error occurs if there is no parameter
; with the given name.
;
; If the value is too long for one line, it may be continued on to the
; the next input card, using the OGIP CONTINUE convention. For more info,
; http://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/ofwg_recomm/r13.html
;
; Complex numbers are recognized as two numbers separated by one or more
; space characters.
;
; If a numeric value has no decimal point (or E or D) it is returned as
; type LONG. If it contains more than 8 numerals, or contains the
; character 'D', then it is returned as type DOUBLE. Otherwise it is
; returned as type FLOAT. If an integer is too large to be stored as
; type LONG, then it is returned as DOUBLE.
;
; CALLING SEQUENCE:
; Result = FXPAR( HDR, NAME [, ABORT, COUNT=, COMMENT=, /NOCONTINUE ] )
;
; Result = FXPAR(HEADER,'DATE') ;Finds the value of DATE
; Result = FXPAR(HEADER,'NAXIS*') ;Returns array dimensions as
; ;vector
; REQUIRED INPUTS:
; HDR = FITS header string array (e.g. as returned by FXREAD). Each
; element should have a length of 80 characters
; NAME = String name of the parameter to return. If NAME is of the
; form 'keyword*' then an array is returned containing values
; of keywordN where N is an integer. The value of keywordN
; will be placed in RESULT(N-1). The data type of RESULT will
; be the type of the first valid match of keywordN
; found, unless DATATYPE is given.
; OPTIONAL INPUT:
; ABORT = String specifying that FXPAR should do a RETALL if a
; parameter is not found. ABORT should contain a string to be
; printed if the keyword parameter is not found. If not
; supplied, FXPAR will return with a negative !err if a keyword
; is not found.
; DATATYPE = A scalar value, indicating the type of vector
; data. All keywords will be cast to this type.
; Default: based on first keyword.
; Example: DATATYPE=0.0D (cast data to double precision)
; START = A best-guess starting position of the sought-after
; keyword in the header. If specified, then FXPAR
; first searches for scalar keywords in the header in
; the index range bounded by START-PRECHECK and
; START+POSTCHECK. This can speed up keyword searches
; in large headers. If the keyword is not found, then
; FXPAR searches the entire header.
;
; If not specified then the entire header is searched.
; Searches of the form 'keyword*' also search the
; entire header and ignore START.
;
; Upon return START is changed to be the position of
; the newly found keyword. Thus the best way to
; search for a series of keywords is to search for
; them in the order they appear in the header like
; this:
;
; START = 0L
; P1 = FXPAR('P1', START=START)
; P2 = FXPAR('P2', START=START)
; PRECHECK = If START is specified, then PRECHECK is the number
; of keywords preceding START to be searched.
; Default: 5
; POSTCHECK = If START is specified, then POSTCHECK is the number
; of keywords after START to be searched.
; Default: 20
; OUTPUT:
; The returned value of the function is the value(s) associated with the
; requested keyword in the header array.
;
; If the parameter is complex, double precision, floating point, long or
; string, then the result is of that type. Apostrophes are stripped from
; strings. If the parameter is logical, 1 is returned for T, and 0 is
; returned for F.
;
; If NAME was of form 'keyword*' then a vector of values are returned.
;
; OPTIONAL INPUT KEYWORDS:
; /NOCONTINUE = If set, then continuation lines will not be read, even
; if present in the header
; OPTIONAL OUTPUT KEYWORD:
; COUNT = Optional keyword to return a value equal to the number of
; parameters found by FXPAR.
; COMMENTS= Array of comments associated with the returned values.
;
; PROCEDURE CALLS:
; GETTOK(), VALID_NUM
; SIDE EFFECTS:
;
; The system variable !err is set to -1 if parameter not found, 0 for a
; scalar value returned. If a vector is returned it is set to the number
; of keyword matches found.
;
; If a keyword occurs more than once in a header, a warning is given,
; and the first occurence is used. However, if the keyword is "HISTORY",
; "COMMENT", or " " (blank), then multiple values are returned.
;
; NOTES:
; The functions SXPAR() and FXPAR() are nearly identical, although
; FXPAR() has slightly more sophisticated parsing. There is no
; particular reason for having two nearly identical procedures, but
; both are too widely used to drop either one.
;
; REVISION HISTORY:
; Version 1, William Thompson, GSFC, 12 April 1993.
; Adapted from SXPAR
; Version 2, William Thompson, GSFC, 14 October 1994
; Modified to use VALID_NUM instead of STRNUMBER. Inserted
; additional call to VALID_NUM to trap cases where character
; strings did not contain quotation marks.
; Version 3, William Thompson, GSFC, 22 December 1994
; Fixed bug with blank keywords, following suggestion by Wayne
; Landsman.
; Version 4, Mons Morrison, LMSAL, 9-Jan-98
; Made non-trailing ' for string tag just be a warning (not
; a fatal error). It was needed because "sxaddpar" had an
; error which did not write tags properly for long strings
; (over 68 characters)
; Version 5, Wayne Landsman GSFC, 29 May 1998
; Fixed potential problem with overflow of LONG values
; Version 6, Craig Markwardt, GSFC, 28 Jan 1998,
; Added CONTINUE parsing
; Version 7, Craig Markwardt, GSFC, 18 Nov 1999,
; Added START, PRE/POSTCHECK keywords for better
; performance
; Version 8, Craig Markwardt, GSFC, 08 Oct 2003,
; Added DATATYPE keyword to cast vector keywords type
; Version 9, Paul Hick, 22 Oct 2003, Corrected bug (NHEADER-1)
;-
;------------------------------------------------------------------------------
;
; Check the number of parameters.
;
IF N_PARAMS() LT 2 THEN BEGIN
PRINT,'Syntax: result = FXPAR( HDR, NAME [, ABORT ])'
RETURN, -1
ENDIF
;
; Determine the abort condition.
;
VALUE = 0
IF N_PARAMS() LE 2 THEN BEGIN
ABORT_RETURN = 0
ABORT = 'FITS Header'
END ELSE ABORT_RETURN = 1
IF ABORT_RETURN THEN ON_ERROR,1 ELSE ON_ERROR,2
;
; Check for valid header. Check header for proper attributes.
;
S = SIZE(HDR)
IF ( S[0] NE 1 ) OR ( S[2] NE 7 ) THEN $
MESSAGE,'FITS Header (first parameter) must be a string array'
;
; Convert the selected keyword NAME to uppercase.
;
NAM = STRTRIM( STRUPCASE(NAME) )
;
; Determine if NAME is of form 'keyword*'. If so, then strip off the '*', and
; set the VECTOR flag. One must consider the possibility that NAM is an empty
; string.
;
NAMELENGTH1 = (STRLEN(NAM) - 1) > 1
IF STRPOS( NAM, '*' ) EQ NAMELENGTH1 THEN BEGIN
NAM = STRMID( NAM, 0, NAMELENGTH1)
VECTOR = 1 ;Flag for vector output
NAME_LENGTH = STRLEN(NAM) ;Length of name
NUM_LENGTH = 8 - NAME_LENGTH ;Max length of number portion
IF NUM_LENGTH LE 0 THEN MESSAGE, $
'Keyword length must be 8 characters or less'
;
; Otherwise, extend NAME with blanks to eight characters.
;
ENDIF ELSE BEGIN
WHILE STRLEN(NAM) LT 8 DO NAM = NAM + ' '
VECTOR = 0
ENDELSE
;
; If of the form 'keyword*', then find all instances of 'keyword' followed by
; a number. Store the positions of the located keywords in NFOUND, and the
; value of the number field in NUMBER.
;
IF N_ELEMENTS(START) EQ 0 THEN START = -1L
START = LONG(START[0])
IF NOT VECTOR AND START GE 0 THEN BEGIN
IF N_ELEMENTS(PRECHECK) EQ 0 THEN PRECHECK = 5
IF N_ELEMENTS(POSTCHECK) EQ 0 THEN POSTCHECK = 20
NHEADER = N_ELEMENTS(HDR)
MN = (START - PRECHECK) > 0
MX = (START + POSTCHECK) < (NHEADER-1) ;Corrected bug
KEYWORD = STRMID(HDR[MN:MX], 0, 8)
ENDIF ELSE BEGIN
RESTART:
START = -1L
KEYWORD = STRMID( HDR, 0, 8)
ENDELSE
IF VECTOR THEN BEGIN
NFOUND = WHERE(STRPOS(KEYWORD,NAM) GE 0, MATCHES)
IF ( MATCHES GT 0 ) THEN BEGIN
NUMST= STRMID(HDR[NFOUND], NAME_LENGTH, NUM_LENGTH)
NUMBER = INTARR(MATCHES)-1
FOR I = 0, MATCHES-1 DO $
IF VALID_NUM( NUMST[I], NUM) THEN NUMBER[I] = NUM
IGOOD = WHERE(NUMBER GE 0, MATCHES)
IF MATCHES GT 0 THEN BEGIN
NFOUND = NFOUND[IGOOD]
NUMBER = NUMBER[IGOOD]
ENDIF
ENDIF
;
; Otherwise, find all the instances of the requested keyword. If more than
; one is found, and NAME is not one of the special cases, then print an error
; message.
;
ENDIF ELSE BEGIN
NFOUND = WHERE(KEYWORD EQ NAM, MATCHES)
IF MATCHES EQ 0 AND START GE 0 THEN GOTO, RESTART
IF START GE 0 THEN NFOUND = NFOUND + MN
IF (MATCHES GT 1) AND (NAM NE 'HISTORY ') AND $
(NAM NE 'COMMENT ') AND (NAM NE '') THEN $
MESSAGE,/INFORMATIONAL, 'WARNING- Keyword ' + $
NAM + 'located more than once in ' + ABORT
IF (MATCHES GT 0) THEN START = NFOUND[MATCHES-1]
ENDELSE
;
; Extract the parameter field from the specified header lines. If one of the
; special cases, then done.
;
IF MATCHES GT 0 THEN BEGIN
LINE = HDR[NFOUND]
SVALUE = STRTRIM( STRMID(LINE,9,71),2)
IF (NAM EQ 'HISTORY ') OR (NAM EQ 'COMMENT ') OR $
(NAM EQ ' ') THEN BEGIN
VALUE = STRTRIM( STRMID(LINE,8,72),2)
COMMENTS = STRARR(N_ELEMENTS(VALUE))
;
; Otherwise, test to see if the parameter contains a string, signalled by
; beginning with a single quote character (') (apostrophe).
;
END ELSE FOR I = 0,MATCHES-1 DO BEGIN
IF ( STRMID(SVALUE[I],0,1) EQ "'" ) THEN BEGIN
TEST = STRMID( SVALUE[I],1,STRLEN( SVALUE[I] )-1)
NEXT_CHAR = 0
OFF = 0
VALUE = ''
;
; Find the next apostrophe.
;
NEXT_APOST:
ENDAP = STRPOS(TEST, "'", NEXT_CHAR)
IF ENDAP LT 0 THEN MESSAGE, $
'WARNING: Value of '+NAME+' invalid in '+ABORT+ " (no trailing ')", /info
VALUE = VALUE + STRMID( TEST, NEXT_CHAR, ENDAP-NEXT_CHAR )
;
; Test to see if the next character is also an apostrophe. If so, then the
; string isn't completed yet. Apostrophes in the text string are signalled as
; two apostrophes in a row.
;
IF STRMID( TEST, ENDAP+1, 1) EQ "'" THEN BEGIN
VALUE = VALUE + "'"
NEXT_CHAR = ENDAP+2
GOTO, NEXT_APOST
ENDIF
;
; Extract the comment, if any.
;
SLASH = STRPOS(TEST, "/", ENDAP)
IF SLASH LT 0 THEN COMMENT = '' ELSE $
COMMENT = STRMID(TEST, SLASH+1, STRLEN(TEST)-SLASH-1)
;
; CM 19 Sep 1997
; This is a string that could be continued on the next line. Check this
; possibility with the following four criteria: *1) Ends with '&'
; (2) Next line is CONTINUE (3) LONGSTRN keyword is present (recursive call to
; FXPAR) 4. /NOCONTINE is not set
IF NOT KEYWORD_SET(NOCONTINUE) THEN BEGIN
OFF = OFF + 1
VAL = STRTRIM(VALUE,2)
IF (STRLEN(VAL) GT 0) AND $
(STRMID(VAL, STRLEN(VAL)-1, 1) EQ '&') AND $
(STRMID(HDR[NFOUND[I]+OFF],0,8) EQ 'CONTINUE') THEN BEGIN
IF (SIZE(FXPAR(HDR, 'LONGSTRN',/NOCONTINUE)))[1] EQ 7 THEN BEGIN
VALUE = STRMID(VAL, 0, STRLEN(VAL)-1)
TEST = HDR[NFOUND[I]+OFF]
TEST = STRMID(TEST, 8, STRLEN(TEST)-8)
TEST = STRTRIM(TEST, 2)
IF STRMID(TEST, 0, 1) NE "'" THEN MESSAGE, $
'ERROR: Invalidly CONTINUEd string in '+ABORT
NEXT_CHAR = 1
GOTO, NEXT_APOST
ENDIF
ENDIF
ENDIF
;
; If not a string, then separate the parameter field from the comment field.
;
ENDIF ELSE BEGIN
TEST = SVALUE[I]
SLASH = STRPOS(TEST, "/")
IF SLASH GT 0 THEN BEGIN
COMMENT = STRMID(TEST, SLASH+1, STRLEN(TEST)-SLASH-1)
TEST = STRMID(TEST, 0, SLASH)
END ELSE COMMENT = ''
;
; Find the first word in TEST. Is it a logical value ('T' or 'F')?
;
TEST2 = TEST
VALUE = GETTOK(TEST2,' ')
TEST2 = STRTRIM(TEST2,2)
IF ( VALUE EQ 'T' ) THEN BEGIN
VALUE = 1
END ELSE IF ( VALUE EQ 'F' ) THEN BEGIN
VALUE = 0
END ELSE BEGIN
;
; Test to see if a complex number. It's a complex number if the value and the
; next word, if any, both are valid numbers.
;
IF STRLEN(TEST2) EQ 0 THEN GOTO, NOT_COMPLEX
VALUE2 = GETTOK(TEST2,' ')
IF VALID_NUM(VALUE,VAL1) AND VALID_NUM(VALUE2,VAL2) $
THEN BEGIN
VALUE = COMPLEX(VAL1,VAL2)
GOTO, GOT_VALUE
ENDIF
;
; Not a complex number. Decide if it is a floating point, double precision,
; or integer number. If an error occurs, then a string value is returned.
; If the integer is not within the range of a valid long value, then it will
; be converted to a double.
;
NOT_COMPLEX:
ON_IOERROR, GOT_VALUE
VALUE = TEST
IF NOT VALID_NUM(VALUE) THEN GOTO, GOT_VALUE
IF (STRPOS(VALUE,'.') GE 0) OR (STRPOS(VALUE,'E') $
GE 0) OR (STRPOS(VALUE,'D') GE 0) THEN BEGIN
IF ( STRPOS(VALUE,'D') GT 0 ) OR $
( STRLEN(VALUE) GE 8 ) THEN BEGIN
VALUE = DOUBLE(VALUE)
END ELSE VALUE = FLOAT(VALUE)
ENDIF ELSE BEGIN
LMAX = 2.0D^31 - 1.0D
LMIN = -2.0D31
VALUE = DOUBLE(VALUE)
if (VALUE GE LMIN) and (VALUE LE LMAX) THEN $
VALUE = LONG(VALUE)
ENDELSE
;
GOT_VALUE:
ON_IOERROR, NULL
ENDELSE
ENDELSE ; if string
;
; Add to vector if required.
;
IF VECTOR THEN BEGIN
MAXNUM = MAX(NUMBER)
IF ( I EQ 0 ) THEN BEGIN
IF N_ELEMENTS(DATATYPE) EQ 0 THEN BEGIN
;; Data type determined from keyword
SZ_VALUE = SIZE(VALUE)
ENDIF ELSE BEGIN
;; Data type requested by user
SZ_VALUE = SIZE(DATATYPE[0])
ENDELSE
RESULT = MAKE_ARRAY( MAXNUM, TYPE=SZ_VALUE[1])
COMMENTS = STRARR(MAXNUM)
ENDIF
RESULT[ NUMBER[I]-1 ] = VALUE
COMMENTS[ NUMBER[I]-1 ] = COMMENT
ENDIF ELSE BEGIN
COMMENTS = COMMENT
ENDELSE
ENDFOR
;
; Set the value of !ERR for the number of matches for vectors, or simply 0
; otherwise.
;
IF VECTOR THEN BEGIN
!ERR = MATCHES
RETURN, RESULT
ENDIF ELSE !ERR = 0
;
; Error point for keyword not found.
;
ENDIF ELSE BEGIN
IF ABORT_RETURN THEN MESSAGE,'Keyword '+NAM+' not found in '+ABORT
!ERR = -1
ENDELSE
;
RETURN, VALUE
END
Return to the shapelets web page or the code help menu.
| Last modified on 2nd Mar 2009 by Richard Massey. |