;+
;NAME: ptr_extract
;Function: ptrs = ptr_extract(p,EXCEPT=EXCEPT)
;Purpose:
;   Recursively searches the input (of any type) and returns an array of all
;   pointers found.
;   This is useful for freeing pointers contained within some complicated
;   structure heirachy or pointer list.
;   if no pointers are found then a scaler null pointer is returned.
;   This routine ignores object pointers!
;Keywords:
;   EXCEPTPTRS = an array of pointers that should not be included in the output.
;Created by Davin Larson. May 2002.
;-
function ptr_extract,p,exceptptrs=exceptptrs
dt = size(/type,p)
n  = n_elements(p)
nul = ptr_new()
ret = nul
if n_elements(exceptptrs) eq 0 then exceptptrs=ptr_new()

if dt eq 10 then begin     ; Pointers
   for i=0,n-1 do begin
      if total(exceptptrs eq p[i]) gt 0 then continue              ; already encountered
      ret = [ret,p[i]]
      exceptptrs = [exceptptrs,p[i]]
      if ptr_valid(p[i]) then $
          ret = [ret,ptr_extract(*p[i],exceptptrs=exceptptrs)]
   endfor
endif

if dt eq 8 then begin    ; Structures
   tags = tag_names(p)
   ntag = n_elements(tags)
   for i=0,ntag-1 do begin
      r = ptr_extract(p.(i),exceptptrs=exceptptrs)
      if keyword_set(r) then ret=[ret,r]
   endfor
end

w = where(ret ne nul,nw)

return,nw gt 0 ? ret[w] : nul
end