;+
;FUNCTION:
;  res =  strfilter(stringarray,searchstring)
;PURPOSE:
;  Returns the subset of stringarray that matchs searchstring
;  '*' will match all (non-null) strings
;  ''  will match only the null string
;  Output can be modified with keywords
;  NOTE: this routine is very similar to the STRMATCH routine introduced in IDL 5.3
;     it has some enhancements that make it useful.
;     (i.e.: filterstring can also be an array)
;INPUT:
;  stringarray:  An array of strings to be filtered
;  searchstring: A string that may contain wildcard characters ("*")
;           (If searchstring is an array then results are OR'd together)
;RETURN VALUE:
;  Either:
;     Array of matching strings.
;  or:
;     Array of string indices.
;  or:
;     Byte array with same dimension as input string.
;  Depends upon keyword setting (See below)
;
;KEYWORDS:
;  FOLD_CASE: if set then CASE is ignored.   (only IDL 5.3 and later)
;  STRING: if set then the matching strings are returned.  (default)
;  INDEX:  if set then the indices are returned.
;  BYTES:  if set then a byte array is returned with same dimension as input string array (similar to STRMATCH).
;  NEGATE: pass only strings that do NOT match.
;  COUNT:  A named variable that will contain the number of matched strings.
;  NO_MATCH:  A named variable that will contain either a subset of searchstring that
;             failed to match stringarray, an array of indices to that subset, or a 
;             byte array whose dimensions match the number of elements in searchstring.
;             The data type returned will match that of the return value.
;             (only IDL 5.3 and later)
;Limitations:
;  This function still needs modification to accept the '?' character
;  July 2000;  modified to use the IDL strmatch function so that '?' is accepted for versions > 5.4
;EXAMPLE:
;  Print,strfilter(findfile('*'),'*.pro',/negate) ; print all files that do NOT end in .pro
;AUTHOR:
;  Davin Larson,  Space Sciences Lab, Berkeley; Feb, 1999
;VERSION:  01/10/08
;-
function strfilter,str,matchs,count=count,  $
     wildcard=wildcard,fold_case=fold_case,  $
     delimiter=delimiter, no_match=no_match, $
     index=index,string=retstr,byte=bt,negate=negate


if !version.release ge '5.3' then begin
   matcharray = keyword_set(matchs) ? matchs : ''
   if keyword_set(delimiter) and size(/dimen,matcharray) eq 0 then $
        matcharray = strsplit(matcharray,delimiter,/extract)
   if keyword_set(wildcard) then dprint,'Wildcard "'+wildcard+'" ignored'
   
   ;initialize vars for return values and substrings with no matches
   ret = 0b
   missed = replicate(1b, n_elements(matcharray))
   
   ;loop over substrings to find matches within the array
   for k=0,n_elements(matcharray)-1 do begin
     new = strmatch(str,matcharray[k],fold_case=fold_case)
     ret = new or ret
     if total(new) gt 0 then missed[k] = 0b
   endfor

   ;pass back info on which searches found no matches,
   ;the type of data passed back should match that of the return value
   midx = where(missed, nm)
   no_match = nm gt 0  ?  matcharray[midx] : ''  
   if keyword_set(string) then no_match = no_match
   if keyword_set(index) then no_match = midx
   if keyword_set(bt) then no_match = missed

   
endif else begin   ; Old version follows:

ns = strlen(str)
ret = ns eq -1   ; set to 0

if not keyword_set(wildcard) then wildcard='*'

for k=0,n_elements(matchs)-1 do begin
match = matchs[k]

;mss=str_sep(match,wildcard)
mss=strsplit(match,wildcard,/extract)
nmss= keyword_set(match) ? n_elements(mss) : 0

;quick test to improve speed,  required to find a null string
if match eq wildcard then begin
    ret[*] = 1
    goto,skip   ; pass all strings
endif

;quick test to improve speed, but not required
if nmss eq 1 then begin        ;no wildcards to match do the simple thing
    ret = (str eq match) or ret
    goto,skip
endif


lms = strlen(mss)

for i=0,n_elements(str)-1 do begin    ; Unfortunately strmid and strpos don't allow pos to be vectors
  temp = str[i]                     ; so an extra loop is required here
  p = 0
  for j=0,nmss-1 do begin
    p2 = (j lt nmss-1) ? strpos(temp,mss[j],p) : rstrpos(temp,mss[j])
    if j eq 0 then r = (p2 eq 0) else r = (p2 ge p)
    p = p2 + lms[j]
    if r eq 0 then goto,break
  endfor
  r = p eq ns[i]
  break:
  ret[i]= ret[i] or r
endfor
skip:

endfor
endelse    ; end of old version


if keyword_set(negate) then ret = (ret eq 0)
ind = where(ret,count)
nstr = count eq 0 ?  '' : str[ind]
if keyword_set(retstr) then return, nstr
if keyword_set(index)  then return, ind
if keyword_set(bt)     then return, ret
;message,/info,'Please use KEYWORD, default will change to STRING'
return,nstr   ; this default may change!
end

