;+ ; NAME: ; DXBREAK ; ; AUTHOR: ; Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770 ; craigm@lheamail.gsfc.nasa.gov ; ; PURPOSE: ; Sets an IDL breakpoint ; ; CALLING SEQUENCE: ; DXBREAK, LINE ; current procedure (OR)" ; DXBREAK, 'PROCNAME', LINE ; named procedure (OR)" ; DXBREAK, 'path/procname.pro', LINE ; procedure path (OR)" ; DXBREAK, PROCNAME, LINE ; without quotes" ; ; DESCRIPTION: ; ; DXBREAK is a convenience routine for setting IDL breakpoints. ; ; The benefits over the built-in IDL procedure BREAKPOINT are: ; * fewer characters to type; ; * full pathname not required, just a procedure name; and ; * for breakpoints within the current procedure, the file name ; is not needed. ; ; To clear breakpoints, use either DXCLEAR or BREAKPOINT, /CLEAR. ; ; INPUTS: ; ; LINE - the line number where the breakpoint is to be set. This ; value is required. ; ; PROCNAME - the procedure name in which the breakpoint is to be ; set. Note that IDL requires that a procedure be ; compiled on disk -- console-compiled or .RUN files ; cannot have breakpoints set. ; ; The name is one of: ; * the procedure or function name; ; * the full path to the procedure or function; OR ; * an unquoted procedure or function name. ; ; DXBREAK will search your path to find the correct ; procedure. The first file found will be used. ; ; ; KEYWORDS: ; ; ONCE - if set, then the breakpoint will only occur once. The same ; as the ONCE keyword to BREAKPOINT. ; ; IS_FUNCTION - if set, and there is an ambiguity between whether ; PROCNAME is a procedure or a function, then DXBREAK ; will assume that it is a function. ; ; EXAMPLE: ; ; dxbreak, 'myfunc', 50 ; ; Set breakpoint in MYFUNC at line 50. ; ; SEE ALSO: ; ; BREAKPOINT, DXCLEAR ; ; MODIFICATION HISTORY: ; Written, 15 Apr 2000 ; Addition of NOCATCH keyword for internal testing, 21 Sep 2000, CM ; Made mostly compatible with IDL v4, 21 Sep 2000, CM ; Added AFTER keyword, 13 Dec 2000, CM ; Removed AFTER, use _EXTRA instead, 08 Apr 2001, CM ; ; $Id: dxbreak.pro,v 1.4 2001/04/08 16:59:55 craigm Exp $ ; ;- ; Copyright (C) 2000-2001, Craig Markwardt ; This software is provided as is without any warranty whatsoever. ; Permission to use, copy, modify, and distribute modified or ; unmodified copies is granted, provided this copyright and disclaimer ; are included unchanged. ;- pro dxbreak, arg0, arg1, is_function=is_func0, once=once, nocatch=nocatch, $ _EXTRA=extra forward_function routine_info, routine_names if NOT keyword_set(nocatch) then begin catch, catcherr if catcherr NE 0 then begin CATCH_HANDLER: catch, /cancel print, 'ERROR: could not set breakpoint; is it compiled yet?' return endif endif if n_params() EQ 0 then begin USAGE_MESSAGE: print, 'USAGE:' print, " dxbreak, LINE ; current procedure (OR)" print, " dxbreak, 'PROCNAME', LINE ; named procedure (OR)" print, " dxbreak, 'path/procname.pro', LINE ; procedure path (OR)" print, " dxbreak, PROCNAME, LINE ; without quotes" return endif line = -1 proc = '' file = '' resolved = 0 ;; Parse parameters... either LINE alone or PROC+LINE if n_params() EQ 1 then begin ;; Line number only specified if n_elements(arg0) EQ 0 then goto, USAGE_MESSAGE arg = arg0 ;; Type checking only LINE_CHECK: sz = size(arg) tp = sz(sz(0)+1) if tp EQ 0 OR (tp GE 6 AND tp LE 11) then goto, USAGE_MESSAGE line = floor(arg(0)) endif else begin ;; File and line number specified if n_elements(arg1) EQ 0 then goto, USAGE_MESSAGE sz = size(arg0) tp = sz(sz(0)+1) if tp EQ 7 then begin ;; String file name specified file = arg0(0) proc = strupcase(arg0(0)) if strpos(strlowcase(file), '.pro') GE 0 then resolved = 1 $ else file = strlowcase(file) + '.pro' arg = arg1 goto, LINE_CHECK endif else begin ;; Variable name is procedure or function name level = routine_names(/level) proc = routine_names(arg0, arg_name=level-1) if n_elements(proc) LT 1 then goto, USAGE_MESSAGE file = proc(0) proc = proc(0) if proc EQ '' then goto, USAGE_MESSAGE arg = arg1 goto, LINE_CHECK endelse endelse if line LT 0 then begin print, 'ERROR: line number was not specified' return endif ;; Make sure the procedure is compiled if file NE '' AND NOT resolved then begin is_func = 0 pass = 0 RETRY_FIND: pass = pass + 1 ;; Compare to known proc/funcs funcs = routine_names(/functions) procs = routine_names() whf = where(proc EQ funcs, ctf) whp = where(proc EQ procs, ctp) if ctp GT 0 AND ctf GT 0 then begin ;; Both procs and funcs are listed; decide in favor of procs ;; unless is_funct0 is set if keyword_set(is_funct0) then is_func = 1 endif else begin ;; It's a function if ctf GT 0 then is_func = 1 endelse if ctf EQ 0 AND ctp EQ 0 then begin ;; If it is found in neither, then try compiling, and then ;; go through the process again if pass EQ 1 then begin p1 = 0 & p2 = 0 catch, catcherr ;; Errors will fall through!! if p2 EQ 0 then begin ;; Try as a function p2 = 1 resolve_routine, proc, /is_function endif if p1 EQ 0 then begin ;; Try as a procedure p1 = 1 resolve_routine, proc endif ;; Revert to original error handler catcherr = 0 catch, catcherr if catcherr NE 0 then goto, CATCH_HANDLER goto, RETRY_FIND endif print, 'ERROR: '+proc+' is not a valid procedure' return endif ;; Get source code path name if double(!version.release) GE 5 then begin ;; IDL v5. We can get the filename directly path = routine_info(proc, /source, functions=is_func) file = path.path endif else begin ;; IDL v4. We guess that it's the lowercase procname with .pro file = strlowcase(proc)+'.pro' endelse resolved = 1 endif ;; The file is not known yet, so this must be the current procedure if file EQ '' then begin @dxcommon.pro dxlreset tb = dxptrace(dbtraceback) n = n_elements(tb) file = (tb(0).path)(0) fline = (tb(0).line)(0) if fline EQ 0 OR file EQ '' OR file EQ filepath(/terminal) $ OR file EQ '/dev/tty' then begin print, 'ERROR: '+tb(0).name+' is not on disk' return endif proc = (tb(0).name)(0) resolved = 1 endif ;; Scan each path element until the file is found; the '' path is ;; for the case where we know the path of the file already. paths = expand_path(!path, /array, count=pathcount) if pathcount EQ 0 then paths = [''] else paths = ['', paths] pathcount = pathcount + 1 ;; Check for existence by opening them. get_lun, unit for i = 0L, pathcount-1 do begin if paths(i) EQ '' then path = file $ else path = filepath(root=paths(i), file) openr, unit, path, error=openerr if openerr EQ 0 then goto, READ_SUCCESS endfor free_lun, unit print, 'ERROR: the procedure '+proc+' was not found in your path' return READ_SUCCESS: free_lun, unit breakpoint, path, line, /set, once=keyword_set(once), _EXTRA=extra print, 'Breakpoint set at: '+strupcase(proc)+' '+strtrim(line,2)+$ ' ('+path+')' end