; docformat = 'rst rst' ;+ ;- ;+ ; :Description: ; Parses a text file or a string array into a hash. The text is interpreted ; as lines containing key=value pairs, and can contain comments. Values can ; can be converted to integers or reals, if possible. ; Values are returned as a (possibly empty) hash, where all keys are strings. ; ; The complement to this function is `pp_writepars`. ; ; :Params: ; input : in, required ; If `input_is_strings` is not set, this is a string with the name of a text ; file to read and parse. Otherwise, it is a string array, interpreted in the ; same way a file would be (each element corresponding to one file line). ; ; :Keywords: ; numbers : in, optional, default=1 ; Sets the type of conversion for values which are numbers, if any. If set to ; zero, no conversion is made (all values are returned as strings). If set to ; 1, values which are integers are returned as long64s, and values which are reals ; are returned as doubles. ; key_case : in, optional, default=0 ; If set to 1, keys are converted to all uppercase. If set to 2, keys are converted ; to all lowcase. ; nan : in, optional, default=1 ; Passed on to pp_isnumber. If set, NaNs (in several spellings) are accepted ; when testing if a value is a real number. ; infinity : in, optional, default=1 ; Passed on to pp_isnumber. If set, infinities (in several spellings) are accepted ; when testing if a value is a real number. ; input_is_strings : in, optional, default=0 ; If set, `input` is treated as a string array, where each element is a line ; to parse. Otherwise, `input` is treated as the name of a text file to read ; and parse. ; comment_marker : in, optional, default='#' ; The character to use to mark comments in the text to process. Anything in ; a line following this marker is ingored (even if it is escaped or inside ; quotes). If something different from deafult is given, it must be a valid ; regular expression (that is, especial regex characters must be escaped). ; value_separator : in, optional, default='=' ; The character to use to separate keys from values. If anyhting other than ; default is used, it should be kept in mind that this is the separator given ; to strsplit. Thus it follows strsplit's rules. ; comment_lines : out, optional ; Provides a string array with all lines that were not put into the hash (comment ; lines, or lines that were not recognized as containing a valid key=value). ; ; :Examples: ; ; Make up some content to read, in the form of a string array:: ; ; example_string=['#some comments','a=1 #some other comments',' b = -9',"c = 'some string' #some more comments",'d=98.765d-6 #in some units'] ; foreach el,example_string do print,el ; ;#some comments ; ;a=1 #some other comments ; ; b = -9 ; ;c = 'some string' #some more comments ; ;d=98.765d-6 #in some units ; ; Now parse it and chek the results:: ; ; pars=pp_readpars(example_string,/input_is_string) ; print,pars ; ;c: 'some string' ; ;a: 1 ; ;b: -9 ; ;d: 9.8765000e-05 ; foreach el,pars do help,el ; ;EL STRING = ''some string'' ; ;EL LONG64 = 1 ; ;EL LONG64 = -9 ; ;EL DOUBLE = 9.8765000e-05 ; ; :Uses: pp_isnumber ; ; :Todo: ; Support values as arrays. For now, the value array would be returned as ; a string, which could be parsed afterwards. ; Support returning comments from the same lines as values. For now, comments ; following values are discarded (comments in standalone lines, and lines not ; recognized are valid key=value, can be retrieved with ``comment_lines``). ; ; :Author: Paulo Penteado (pp.penteado@gmail.com), Feb/2011 ;- function pp_readpars,input,numbers=numbers,key_case=kcase,nan=nan,infinity=infinity,$ input_is_strings=inpstr,comment_marker=comment,value_separator=value_separator,$ comment_lines=comment_lines compile_opt idl2, logical_predicate ;Defaults numbers=n_elements(numbers) eq 1 ? numbers : 1B kcase=n_elements(kcase) eq 1 ? kcase : 0B inpstr=n_elements(inpstr) eq 1 ? inpstr : 0B comment_marker=n_elements(comment_marker) eq 1 ? comment_marker : '#' value_separator=n_elements(value_separator) eq 1 ? value_separator : '=' ;Read the file into strings if (inpstr) then lines=input else begin nlines=file_lines(input) lines=strarr(nlines) openr,unit,input,/get_lun readf,unit,lines free_lun,unit endelse ;Parse the lines ret=hash() comment_lines=list() lines=strtrim(lines,2) ;Locate the comments (everything following a '#', even if the '#' is quoted or escaped) slines=strsplit(lines,comment_marker,/regex,/extract,/preserve_null) foreach line,slines,i do begin if line[0] then begin ;Skip lines that are entirely comments, or are empty tmp=strsplit(line[0],value_separator,/extract,count=count) if (count ge 2) then begin ;Skip line if it does not have more than two parts separated by '=' key=strtrim(tmp[0],2) case kcase of ;Change key case if selected 1: key=strupcase(key) 2: key=strlowcase(key) else: endcase value=strtrim(strjoin(tmp[1:-1],'='),2) ;Reassemble value if it was separated in pieces by '=' case numbers of ;If value is to be converted to number (if possible) 1 : value=pp_isnumber(value,/integer) ? long64(value) : pp_isnumber(value,infinity=infinity,nan=nan) ? double(value) : value 2 : value=pp_isnumber(value,infinity=infinity,nan=nan) ? double(value) : value else : endcase endif else comment_lines.add,lines[i] ret[key]=value endif else comment_lines.add,lines[i] endforeach comment_lines=comment_lines.toarray() return,ret end