;+ ; NAME: ; www_help_make ; PURPOSE: ; Build a .HTML help system from source code headers ; CATEGORY: ; gen/idl ; CALLING SEQUENCE: PRO www_help_make, destination, header, section, style, $ swap_style = swap_style , $ email = email , $ cgi_bin = cgi_bin , $ crosslinks = crosslinks , $ mask = mask , $ calls = calls , $ includes = includes , $ externals = externals , $ copyright = copyright ; INPUTS: ; destination scalar; type: string ; destination directory for the html files ; header array; type: structure ; all the headers ; section array; type: string ; list of valid section headings ; style array[1]; type: structure ; defined in www_help ; used: style.html_name, style.html_type, style.title ; cgi_bin=cgi_bin scalar; string; default: none ; directory where web server looks for cgi files. ; This is the directory where www_help.cgi should reside. ; OPTIONAL INPUT PARAMETERS: ; mask=mask array; type: integer ; array with index numbers of 'header' to be processed ; swap_style=swap_style ; array[1]; type: structure ; if specified than a link is added to enable swapping ; to the help system for another group of source files. ; copyright=copyright ; scalar; type: text: dfault: none ; name of text file containing a copyright notice. ; The file name should be located in the destination directory, and ; should be given the name _copyright.txt. The will be ; used to set up a link to the copyright notice. ; email=email array; type: string ; list of email addresses. If any of these addresses is found it ; is converted to an html link ; crosslinks=crosslinks ; OUTPUTS: ; (bunch of html files) ; INCLUDE: @compile_opt.pro ; On error, return to caller @www_help_version.pro ; Defines version ; CALLS: ; strposn, www_help_check, www_help_get_calls, InitVar ; www_help_names, www_help_called_by, www_help_is_section, www_help_frames ; www_help_calls_file, www_help_mailto ; PROCEDURE: ; > The htm[0] is used as prefix for the name of all html files ; > All html files have extension htm[1] ; > All html files are created in the directory specified in htm[2] ; ; > The following html files are created: ; (name = htm[0]; htm = htm[1] ; ; name_frames.htm defines the frames for the help system ; name_alphabet.htm a list of all letters providing links to the ; first header with a name starting with that letter ; (case-insensitive) ; name_list.htm a list of all headers with names in alphabetical orders. ; Each name is a link to the corresponding header. ; name_a.htm, name_b.htm, name_c.htm, etc. ; contains the headers with name starting with the ; corresponding letters. ; ; > The current layout has three frames ; - one frame along the top containing name_alphabet.htm ; - one frame along the left containing name_list_htm. ; This frame is the target for links in the top frame. ; - one frame along the right containing the name_a.htm, etc. files ; This frame is the target for links in the left frame ; MODIFICATION HISTORY: ; JAN-2001, Paul Hick (UCSD/CASS) ; JAN-2002, Paul Hick (UCSD/CASS) ; Fixed bug in html file defining frames. The text frame would ; try to load the documentation for letter A even if the file ; does not exist. ; Now the file for the first letter that is present is loaded. ; MAR-2003, Paul Hick (UCSD/CASS) ; Added option to include copyright notice. ; SEP-2007, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Added code to write function/prodedure name, file name, and CALLS ; INCLUDE, SEE ALSO and EXTERNAL sections into a plain text file. File ; names are for.txt, pro.txt, etc. ; Added a link to cgi script www_help_dep to display all the module ; names and files a specific module depends on. ;- cgi = IsType(cgi_bin,/defined) IF cgi THEN BEGIN cgi_script = filepath(root=cgi_bin[0], 'www_help.cgi') dep_incl = n_elements(cgi_bin) GT 1 dep_script = filepath(root=cgi_bin[0], 'www_help_dep.cgi') ENDIF ; If 'mask' not set then process all headers InitVar, mask, lindgen(n_elements(header)) count = n_elements(mask) ; # headers to be processed ;======================================== ; Write file defining positions of frames name = style.html_name type = style.html_type first_letter = strlowcase( strmid(header[mask[0]].name,0,1) ) content = ['' , $ '',''+style.title+' Help','' , $ www_help_frames(name, name+'_'+first_letter, type) , $ '' , $ '<body bgcolor="#000000">' , $ '<p>This page uses frames.</p>' , $ '</body>' , $ '' , $ '' ] html_file = filepath(root=destination,name+'_frames'+type) message, /info, hide_env(html_file) openw , iu, /get_lun, /stream, html_file FOR i=0L,n_elements(content)-1 DO printf, iu, content[i] free_lun, iu ;======================================== ; Write file with the single character links A B C etc ; Set up a one-line list of letters A-Z with links to the first routine starting with each letter. ; This file (*_alphabet.htm) will fill in the top frame of the help window ; The links created have the form ; R content = ['','',''] content = [content, ''+style.master+ $ ''] IF n_elements(swap_style) NE 0 THEN $ content = [content, ''+swap_style.title+ $ ''] firstchar = strupcase( strmid(header[mask].link,0,1) ) isfirst = 0*header[mask].version FOR i=(byte('A'))[0],(byte('Z'))[0] DO BEGIN ; Loop over uppercase letters tmp = string(i) ; Uppercase single char iunit = (where(firstchar EQ tmp))[0] IF iunit NE -1 THEN BEGIN isfirst[iunit] = 1 tmp = ''+tmp+'' ENDIF content = [content, tmp] ENDFOR content = [content,'','',''] html_file = filepath(root=destination, name+'_alphabet'+type) message, /info, hide_env(html_file) openw , iu, /get_lun, /stream, html_file FOR i=0L,n_elements(content)-1 DO printf, iu, content[i] free_lun, iu ;======================================== ; Write the alphabetical list of routine names ; This file (*_list.htm) will fill the frame on the left ; First set up the links to the first routine for each letter (where isfirst = 1) content = replicate('', count) tmp = where(isfirst) content[tmp] += '' ; Now add the links for the routine names after inserting the proper target tmp = strposn(header[mask].flink,'>', /leadingback, front, back) content += front+' target="www_help_text"'+back content = '
  • '+content+'
  • ' ; Set up whole file content tt = systime() tt = strmid(tt,20)+'-'+strmid(tt,4,3)+'-'+strmid(tt,8,2) IF IsType(copyright,/defined) THEN BEGIN ;if (file_search( filepath(root=destination, copyright) ))[0] ne '' then begin notice_label = strmid(copyright, 0, strpos(copyright,'_')) IF notice_label EQ '' THEN notice_label = 'Copyright' tt = tt+' © '+notice_label+'' ;ENDIF ENDIF mailto = 'pphick@ucsd.edu' content = [ $ '' , $ '' , $ '' , $ style.title+' '+version , $ '' , $ '' , $ '' , $ '' , $ ''+style.title+' @'+tt , $ '
    ' , $ ''+version+' ('+www_help_mailto(mailto,/href,subject=version,title='Comments ?')+')', $ '
    ' , $ '' , $ '' , $ '' ] html_file = filepath(root=destination, name+'_list'+type) message, /info, hide_env(html_file) openw , iu, /get_lun, /stream, html_file FOR i=0L,n_elements(content)-1 DO printf, iu, content[i] free_lun, iu ; First make some corrections to the headers: make links for email addresses and ; names explicitly marked as linked in the source code by 'href='. www_help_check, header, mask, style, email, crosslinks ;======================================== ; Scan headers for 'CALLS', 'INCLUDE' and 'EXTERNAL' section ; If 'calls', 'includes' or 'externals' exist then they should be the result ; from a previous call with the same 'header', 'style' and 'section'. IF NOT ptr_valid(calls ) THEN www_help_get_calls, style, header, section, 'CALLS:' , calls=calls IF NOT ptr_valid(includes ) THEN www_help_get_calls, style, header, section, 'INCLUDE:' , call=includes IF NOT ptr_valid(externals) THEN www_help_get_calls, style, header, section, 'EXTERNAL:', call=externals IF ptr_valid(calls) THEN www_help_calls_file, style, header nocalls = 1-ptr_valid(calls ) noincludes = 1-ptr_valid(includes ) noexternals = 1-ptr_valid(externals) ;======================================== ; Open plain text file to receive the same information that ; goes into the *_a.html, *_b.html, etc. files. ; The file will contain the module name, the file name where ; the module is located, and the content of the 'CALLS', ; 'INCLUDE' and 'EXTERNAL' sections. The write statements ; are located in www_help_names. The file is closed right ; after the FOR loop starting below. db_file = filepath(root=destination, name+'.txt') IF dep_incl THEN $ db_hide = filepath(root='$DB',subdir=cgi_bin[1:*],name+'.txt') message, /info, hide_env(db_file) openw, ju, /get_lun, db_file ;======================================== ; Write the file containing the headers themselves. ; Each file stores routines starting with the same letter (case-insensitive) ; These files (*_a.htm, *_b.htm, etc.) fill the right frame new_file = 1 next_letter = '' FOR ithis=0L,count-1 DO BEGIN this = header[mask[ithis]] letter = strlowcase( strmid(this.link,0,1) ) ; Start a new html file for the next letter IF new_file THEN $ content = ['','' ] ; Write the location (full file name and library module name) origin = this.origin ; Check style.html_top for a replacement string at the start of the file name. ; If not specified than full file names are written to the html files. IF !version.os_family NE 'vms' AND $ style.html_top[0] NE '' AND style.html_top[1] NE '' THEN BEGIN tmp = filepath(root=style.html_top[1],'') ; Add trailing (back)slash if strpos(origin[0],tmp) eq 0 then $ origin[0] = filepath(root='$'+style.html_top[0], strmid(origin[0],strlen(tmp))) ENDIF IF origin[1] NE '' THEN origin[1] = '('+origin[1]+')' cgi_line = ''+strjoin(origin,' ')+'' IF cgi THEN BEGIN IF dep_incl THEN $ dep_line = ''+ $ '' + $ '' cgi_origin = origin[0] IF origin[1] NE '' then cgi_origin = cgi_origin+'+'+origin[1] cgi_line = ''+cgi_line+'' ENDIF content = [content, $ '', $ '', $ ''] IF dep_incl THEN BEGIN content = [content, $ ''] ENDIF content = [content, $ '', $ '', $ '
    ', $ ''+this.link+'', $ '', $ dep_line, $ '', $ cgi_line, $ '
    '] printf, ju, 'module: '+this.link printf, ju, 'file: '+strjoin(origin,' ') ; Write links to previous and next routine FOR i=ithis-1,ithis+1,2 DO BEGIN IF 0 LE i AND i LE count-1 THEN BEGIN tmp = strposn(header[mask[i]].flink,'>'+header[mask[i]].link+'<',front,back) content = [content, front+'>['+(['Previous','Next'])[(i-ithis+1)/2]+']<'+back] ENDIF ENDFOR content = [content, '
    ']
    
    	; If the _by_on flags are switched on here then the corresponding
    	; section CALLED BY or INCLUDED BY is not added.
    	; Note that the this.is_incl determination in www_help_get_header is
    	; flaky, so the next lines may cause problems (disappearing BY sections).
    
    	called_by_on	= nocalls     OR   this.is_incl
    	included_by_on	= noincludes  OR 1-this.is_incl
    	external_by_on	= noexternals OR   this.is_incl
    
    	sections	= ['CALLS:', 'SEE ALSO:', 'INCLUDE:', 'EXTERNAL:']
    	nsection	= n_elements(sections)
    	section_on	= intarr(nsection)
    
    
    	lines = *this.lines
    
    	; Check whether a sections CALLS: is present in the header.
    	; If not and this.calls is not a blank string (this can happen
    	; if the /automatic keyword is set) then we need to take
    	; special precautions to make sure it gets inserted by explicitly
    	; adding the line ' CALLS:' to the header.
    
    
    	IF this.calls NE '' THEN BEGIN			; Need to insert CALLS section
    
    		calls_section = (sections[where(sections EQ 'CALLS:')])[0]
    		iline = www_help_is_section(style, calls_section, lines)
    
    		IF iline EQ -1 THEN BEGIN			; No CALLS section in header
    			iline = (where(section EQ calls_section))[0]
    			IF iline NE -1 THEN BEGIN		; CALLS is a valid section
    				nsect = n_elements(section)	; Find a section that IS present
    				isect = iline
    				iline = -1
    				WHILE iline EQ -1 AND isect LT nsect-1 DO BEGIN
    					isect++
    					iline = www_help_is_section(style, section[isect], lines)
    				ENDWHILE
    			ENDIF
    
    			calls_section = ' '+calls_section
    
    			CASE iline OF 
    			-1  : lines = [lines,calls_section]
    			 0  : lines = [calls_section,lines]
    			ELSE: lines = [lines[0:iline-1],calls_section,lines[iline:*]]
    			ENDCASE
    
    			; Maybe not necessary, but better keep everything
    			; consistent. (www_help_names uses ithis to index
    			; header, so it probably IS necessary)
    
    			*header[mask[ithis]].lines = lines
    			 header[mask[ithis]].nline = n_elements(lines)
    			this = header[mask[ithis]]
    		ENDIF
    
    	ENDIF
    
    	FOR iline=0L,n_elements(lines)-1 DO BEGIN
    
    		line = lines[iline]
    
    		; If _on = 1, then CALLS, SEE ALSO or INCLUDE or EXTERNAL
    		; has started. Hyperlinks are created by checking 'header'
    		; and 'crosslinks' information. Process lines until _on
    		; flag is turned of (when the section ends)
    
    		FOR i=0,nsection-1 DO 		$
    			IF section_on[i] THEN	$
    				section_on[i] = www_help_names(iline, line, ithis, header, mask, $
    					section, sections[i], content, style, letter, linkout, crosslinks, ju=ju)
    
    		; As long as _by_on flag is off, check whether CALLED BY,
    		; INCLUDED BY or EXTERNAL BY section can be written. The
    		; _by_on flag is switched on after the section has been written.
    		; The section is created by inverting the 'calls',
    		; 'includes' or 'externals' information
    
    		IF NOT called_by_on   THEN called_by_on  =	$
    			www_help_called_by(line, ithis,header,mask,section,content,style ,letter,'CALLS:'   ,'CALLED BY:'  ,calls)
    		IF NOT included_by_on THEN included_by_on =	$
    			www_help_called_by(line, ithis,header,mask,section,content,style ,letter,'INCLUDE:' ,'INCLUDED BY:',includes)
    		IF NOT external_by_on THEN external_by_on =	$
    			www_help_called_by(line, ithis,header,mask,section,content,style ,letter,'EXTERNAL:','EXTERNAL BY:',externals)
    
    		IF total(section_on) EQ 0 THEN content = [content, line]
    
    		; Check for the start of CALLS, SEE ALSO, INCLUDE or
    		; EXTERNAL sections. Set _on flag if start is found.
    
    		FOR i=0,nsection-1 DO BEGIN
    			IF NOT section_on[i] THEN BEGIN
    				section_on[i] = www_help_is_section(style, sections[i], line) EQ 0
    
    				; If the _on flag for the CALLS section is switched on
    				; on the last line of the header, it needs to be written to disk
    				; before exiting the FOR loop
    
    				IF i EQ 0 THEN				$
    					IF section_on[i] THEN	$
    						IF iline EQ n_elements(lines)-1 THEN	$
    							section_on[i] = www_help_names(iline, noline, ithis, header, mask, $
    								section, sections[i], content, style, letter, linkout, crosslinks, ju=ju)
    			ENDIF
    		ENDFOR
    
    	ENDFOR
    
    	; If a BY section has not been written yet, add it now
    
    	IF NOT called_by_on   THEN called_by_on   =	$
    		www_help_called_by('', ithis, header,mask,section,content,style ,letter,'CALLS:'   ,'CALLED BY:'  ,calls    ,/force)
    	IF NOT included_by_on THEN included_by_on =	$
    		www_help_called_by('', ithis, header,mask,section,content,style ,letter,'INCLUDE:' ,'INCLUDED BY:',includes ,/force)
    	IF NOT external_by_on THEN external_by_on =	$
    		www_help_called_by('', ithis, header,mask,section,content,style ,letter,'EXTERNAL:','EXTERNAL BY:',externals,/force)
    
    	content = [content, '
    '] ; Check whether the end of the current letter has been reached ; If it is, write and close the file IF ithis+1 LT count THEN $ next_letter = strlowcase( strmid(header[mask[ithis+1]].link,0,1) ) new_file = ithis EQ count-1 OR next_letter NE letter CASE new_file OF 0: content = [content, '


    '] 1: BEGIN content = [content, '', ''] html_file = filepath(root=destination, name+'_'+letter+type) message, /info, hide_env(html_file) openw, iu, /get_lun, /stream, html_file FOR i=0L,n_elements(content)-1 DO printf, iu, content[i] free_lun, iu END ENDCASE ENDFOR free_lun, ju ;======================================== ; Destroy the heap variables 'calls', 'includes' and 'externals' unless they are specified as keywords IF NOT arg_present(calls ) THEN IF ptr_valid(calls ) THEN www_help_ptr, calls , /free IF NOT arg_present(includes ) THEN IF ptr_valid(includes ) THEN www_help_ptr, includes , /free IF NOT arg_present(externals) THEN IF ptr_valid(externals) THEN www_help_ptr, externals, /free RETURN & END