;+ ; NAME: ; www_help_info_sub ; PURPOSE: ; Collect info from call to IDL procedure resolve_routine ; CATEGORY: ; www_help ; CALLING SEQUENCE: PRO www_help_info_sub, name, path, file_name, n, list, flag=flag, skip=skip ; INPUTS: ; name scalar; type: string ; name of procedure of function ; path scalar; type: string ; fully-qualified name of file containing 'name' ; OUTPUTS: ; n scalar; type: integer ; # entries in 'list' ; list array[n]; type: string ; list of names of procedures and functions called by ; 'name' ; OPTIONAL OUTPUTS: ; flag=flag scalar; type: string ; status message; null string is all is well ; skip=skip scalar; type: string ; name of file with list of procedures to be skipped ; (mostly because they are so buggy IDL crashes when ; trying to compile them). ; INCLUDE: @compile_opt.pro ; On error, return to caller ; SEE ALSO: ; www_help_get_info ; PROCEDURE: ; > This procedure should not call any other function in order not ; to mess up the results from the resolve_routine call. ; MODIFICATION HISTORY: ; FEB-2002, Paul Hick (UCSD/CASS) ; JUN-2004, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added strcompress to catch sillyness like tabs and multiple spaces ; in the procedure/function declaration. ;- flag = '' n = 0 list = '' name = strupcase(name) file_name = strupcase(file_name) ; Procedure can't compile itself while running so return IF file_name EQ 'WWW_HELP_INFO_SUB' THEN RETURN flag = 'error reading file' ; Start reading the file. Establish error handling: if something ; goes wrong return n=0. on_ioerror, CLEANUP openr, /get_lun, iu, path record = '' readf, iu, record record = strupcase(strcompress(strtrim(record,2))) ; The first non-comment line should start with 'pro' or 'function' ; We also allow the first line to be an include file (statement starts with @). WHILE strcompress(record,/rem) EQ '' OR $ strpos(record,';') EQ 0 OR $ strpos(record,'@') EQ 0 DO BEGIN readf, iu, record record = strupcase(strcompress(strtrim(record,2))) ENDWHILE IF strpos(record,'PRO' ) NE 0 AND $ strpos(record,'FUNCTION') NE 0 THEN BEGIN on_ioerror, NULL free_lun, iu message, /info, 'not a procedure or function: '+file_name flag = 'no PRO or FUNCTION statement' ENDIF ELSE BEGIN ; The file name MUST also be a function or procedure???? ; Why do I need this? flag = 'file name does not match procedure/function name' ;pos = strpos(name,'::') ;if pos ne -1 then $ ; if strpos(file_name,'__') eq pos then $ ; file_name = strmid(file_name,0,pos)+'::'+strmid(file_name,pos+2) pro_id = 'PRO ' +file_name fnc_id = 'FUNCTION '+file_name record = strtrim(record,2) REPEAT BEGIN pos = strpos(record, ';') IF pos NE 0 THEN BEGIN ; Skip comments IF pos NE -1 THEN record = strtrim(strmid(record,0,pos)) pos = strpos(record,pro_id) EQ 0 OR strpos(record,fnc_id) EQ 0 IF pos THEN BEGIN CASE 0 OF ; Extract trailing end of record strpos(record,pro_id): record = strmid(record, strlen(pro_id)) strpos(record,fnc_id): record = strmid(record, strlen(fnc_id)) ENDCASE ; The trailing end (after pro_id/fnc_id) must be empty, or ; start with a space or comma pos = strmid(record,0,1) pos = record EQ '' OR pos EQ ' ' OR pos EQ ',' ENDIF ENDIF IF NOT pos THEN BEGIN readf, iu, record record = strtrim(strcompress(strupcase(record)),2) ENDIF ENDREP UNTIL pos on_ioerror, NULL free_lun, iu ;is_fnc = strpos(record,fnc_id) eq 0 ; Check for the skip file $www_help/www_help.skip ; This contains procedures that will stop resolve_routine dead in its tracks. ; This happens primarily if the compiled file does not have an end statements. IF skip NE '' THEN BEGIN flag = 'procedure on exception list' openr, /get_lun, iu, skip skip = '' WHILE NOT eof(iu) DO BEGIN readf, iu, record skip = [skip, record] ENDWHILE free_lun, iu IF (where(file_name EQ skip))[0] NE -1 THEN RETURN ENDIF flag = 'compilation error' message, /info, path ; pro_before should contain only $MAIN$, and WWW_HELP_INFO_SUB ; fnc_before should be the null scalar pro_before = routine_info() fnc_before = routine_info(/func) resolve_routine, file_name, /either pro_after = routine_info() fnc_after = routine_info(/func) IF pro_after[0] EQ '' THEN npro_after = 0 ELSE npro_after = n_elements(pro_after) IF fnc_after[0] EQ '' THEN nfnc_after = 0 ELSE nfnc_after = n_elements(fnc_after) list = '' ; Pick up all non-trivial entries in pro_after and fnc_after that are not present in fnc_before ; and fnc_before. Also throw the procedure name itself; this would be thrown out anyway as a ; self-reference. (This could also be done with function where_common but that would where_common ; on the fnc_before list. We don't want that.) FOR i=0,npro_after-1 DO $ IF pro_after[i] NE '' AND pro_after[i] NE name AND (where(pro_after[i] EQ pro_before))[0] EQ -1 THEN list = [list,pro_after[i]] FOR i=0,nfnc_after-1 DO $ IF fnc_after[i] NE '' AND fnc_after[i] NE name AND (where(fnc_after[i] EQ fnc_before))[0] EQ -1 THEN list = [list,fnc_after[i]] n = n_elements(list)-1 IF n NE 0 THEN BEGIN list = [list[1:*]] list = strjoin(list[sort(list)],', ') ENDIF flag = 'ok' ENDELSE RETURN CLEANUP: IF n_elements(iu) NE 0 THEN free_lun, iu n = 0 list = '' RETURN & END