#!/u6/jma/TK8.0/bin/tclsh8.0
# -*- Mode : Tcl -*-

#
# This script generates automatically HTML Files giving the list of
# the function in a TCL file with all the interesting things about
# them.
# After reading Java documentation, I adapted it to my own needs.
# So here is a completed example:

# proc dummy {param1 {param2 "default value"} } {
#   #
#   # Function existing just for as
#   # an example purpose
#   # 
#   # @param param1 : First parameter with a long
#   # comment on several distinct
#   # line
#   # @param param2 : Comment for the 2nd parameter
#   # @global gl : Global variable to be returned
#   # @return This function return gl*gc
#   global gl gc
#
#   return gl*gc
# }
#

# @author Jean-Michel AUGUSTO jma@acri.fr
# @version 0.6
# @see #printUsage Usage of the tcldoc
#

set options(version) "0.6"

proc doOutput {msg} {
    #
    # Function called to put on stdout a message if the verbose mode
    # is on.
    #
    # @param msg : Message to display
    #
    # @global options : General Options of tcldoc
    #
    global options
    
    if { $options(verbose) == "on" } then {
	puts stdout $msg
    }
}

proc getsLine {fileID line} {
    #
    # Function called to get the next line in file identifier.
    # It calls the 'gets' TCL function but it also counts several
    # things like the total number of read lines and the number of
    # comment lines.
    #
    # @param fileID : File Identifier
    # @param line : Name of the variable where to put the read line
    #
    # @global stats : Array containing Statistics about the current
    # process
    #
    upvar 1 $line x
    global stats

    set regComment "^\[ \t\]*\#(.*)"
    
    set flag [gets $fileID x]
    if { $flag != -1} then {
	set stats(nbReadLine) [expr $stats(nbReadLine) + 1.0]
	if { [regexp -- $regComment $x] == 1} then {
	    #	    incr nbCommentLine
	    set stats(nbCommentLine) [expr $stats(nbCommentLine) + 1.0]
	}
    }
    return $flag
}

proc getComment {name} {
    #
    # Function called to get the comments for a given procedure
    #
    # @param name : Name of the Procedure/Function.
    #
    # @global listGlobal : An array containing a per-function list of used
    # global
    # @global infoProcParam : An array containing the comments associated
    # to the parameters of the function.
    # @global infoProcReturn : A String containing the comment
    # associated to the return value of the function
    # @global infoProcGlobal : An array containing the comments
    # associated to the globals used in the function
    # @global infoProcComment : The comment associated to the function
    # @global options : General Options of tcldoc
    #
    
    global listGlobal
    global infoProcParam
    global infoProcReturn 
    global infoProcGlobal
    global infoProcComment
    global options
    
    set regComment "^\#(.*)"
    set regParam "^@param\[ \t\]+(\[^: \t\]+)\[ \t\]*:(.*)"
    set regGlobal "^@global\[ \t\]+(\[^: \t\]+)\[ \t\]*:(.*)"
    set regReturn "^@return\[ \t\]+(.*)"
    set globalReg "^global\[ \t\]+(\[^;\]+)"

    set bodyProc [info body $name]
    
    set linesBody [split $bodyProc "\n"]
    set pos 0
    set nbLines [llength $linesBody]
    set currentType comment
    set currentParam ""
    set endC 0
    set listGlobal($name) ""

#
# We parse each line of the function body
#    
    foreach line $linesBody {	
	set line [string trim $line]
	if { [string length $line] == 0 } then {
	    continue
	}
	# Is it a global comment
	set flagC [regexp -nocase -- $regComment $line dummy comment] 	
	if { $flagC == 0 } then {
	    set endC 1
	    if { [regexp -- $globalReg $line dummy gl] == 1 } then {
		append listGlobal($name) " $gl"
	    }
	    continue
	}
	
	if { $endC == 1 } then {
	    continue
	}

	# It is a comment but we must determine which type of comment	
	set comment [string trim $comment]

	set flagParam [regexp -nocase -- \
			  $regParam $comment \
			  dummy paramName paramComment]
	set flagGlobal [regexp -nocase -- \
			   $regGlobal $comment \
			   dummy globalName globalComment]
	set flagReturn [regexp -nocase -- \
			   $regReturn $comment \
			   dummy returnComment]

	if { $flagParam == 1 } then {
	    # A @param
	    set currentType param
	    set currentParam $paramName
	    append infoProcParam($name,$currentParam) " $paramComment"
	} elseif { $flagGlobal == 1 } then {
	    # A @global
	    set currentType global
	    set currentParam $globalName
	    append infoProcGlobal($name,$currentParam) " $globalComment"
	} elseif { $flagReturn == 1 } then {
	    # A @return one
	    set currentType return
	    set currentParam ""
	    append infoProcReturn($name) " $returnComment"
	} else {
	    # We are not in a recognised line :
	    # we continue to affect to the same thing or
	    # we consider it s the general comment
	    # if it is first lines.
	    #
	    if { $currentType == "comment" } then {
		append infoProcComment($name)  " $comment"
	    } elseif { $currentType == "global" } then {
		append infoProcGlobal($name,$currentParam) " $comment"
	    } elseif { $currentType == "param" } then {
		append infoProcParam($name,$currentParam) " $comment"
	    } else {
		append infoProcReturn($name) " $comment"
	    }
	}
    }
    
    if { $options(sortGlobal) == "on" } then {
	set listGlobal($name) [lsort $listGlobal($name)]
    }
}

proc parseFile {file} {
    #
    # Function called to parse a Tcl/Tk file and then to creat the right
    # structure for enabling the program to output description of the
    # functions and parameters.
    #
    # @param file: File to parse
    #
    # @global options: Array for prg options
    # @global listProc: List of all recognised functions of the file
    # @global infoProc: array containing functions information
    # @global infoProcParam: array containing parameters information
    # @global infoProcComment: array containing all the sarting comments
    # @global infoProcGlobal: array containing all the global
    # parameters
    # @global infoProcReturn: array containing all the return
    # comments.
    # @global infoProcDefault : Array containing the Default values
    # for the optional parameters
    # @global infoProcErr : Array containing the name of the erroneous
    # functions.
    # @global commentFile : Comments Associated to the whole file.
    # @global commentFileNb : Number of Comments associated to the whole file.
    # @global stats : Array containing Statistics about the current
    # process
    #

    global options
    global listProc
    global infoProc
    global infoProcParam
    global infoProcComment
    global infoProcGlobal
    global infoProcReturn
    global infoProcDefault
    global infoProcErr
    global commentFile
    global commentFileNb
    global stats

    set listProc {}

    set fd [open $file "r"]

    if { $fd == "" } then {
	puts stderr "File $file not readable"
	exit 1
    }


    set commentReg "^\#(.*)"

    set commentFileNb 0    

    # First we take all the initial comments lines as a file comment
    # except if they match the removeReg regular expression
    set flag [getsLine $fd lineRead]
    lappend stats(listFile) $file
    while {$flag != -1 } {
	if { [string length $lineRead] == 0 } then {
	    set flag [getsLine $fd lineRead]
	    continue
	}
	set flagC [regexp -- $commentReg $lineRead dummy comment]
	
	if {$flagC != 1} then {
	    break
	}
	set res [regexp -- $options(removeReg) $lineRead]
	if { $res == 0 } then {
	    set commentFile($commentFileNb) [string trim $comment]
	    incr commentFileNb
	}
	set flag [getsLine $fd lineRead]
    }

    #
    # The general comment is finished : now we search for the procs
    #
    while { $flag != -1 } {
	set res [regexp -nocase -- $options(procReg) $lineRead dummy name]

	if { $res == 1 } then {
	    # Start of a new proc
	    set cmd $lineRead
	    while { $flag != -1 && [info complete $cmd] == 0 } {
		set flag [getsLine $fd lineRead]
		append cmd "\n$lineRead"
	    }
	    # Evaluation of the function
	    set flagEval [catch { eval $cmd } ]
	    if { $flagEval == 0 } then {
		# We update all the internal variables.
		lappend listProc $name
		set param [info args $name]
		set infoProc($name) $param
		foreach p $infoProc($name) {
		    if { [info default $name $p def] == 1 } then {
			set infoProcDefault($name,$p) $def
		    }
		}
		
		#
		# Now we check for the comments.
		#
		getComment $name
		if { $options(removeFunction) == "on" } then {
		    # we remove the function
		    rename $name ""
		}
	    } else {
		puts stderr "ERROR : $name can be evaluated correctly"
		set stats(nbErrFunction) [expr $stats(nbErrFunction) + 1.0]
		lappend infoProcErr($file) $name
	    }
	}

	set flag [getsLine $fd lineRead]
    }
    
    foreach proce $listProc {
	lappend stats(generalFctList) [list $file $proce]
    }

    close $fd
    
    if { $options(sortProc) == "on"} then {
	set listProc [lsort $listProc]
    }
}

proc outputFctDefault {fileID file} {
    #
    # Function called to make an HTML dump of the found structure. The
    # parameters, comments and global parameters are delivered.
    # The output is put on one file
    #
    # @param fileID: File Identifier
    # @param file : File Name
    # 
    # @global options: Array for prg options
    # @global listProc: List of all recognised functions of the file
    # @global listGlobal: An array containing a per-function list of used
    # global variables
    # @global infoProc: array containing functions information
    # @global infoProcParam: array containing parameters information
    # @global infoProcComment: array containing all the sarting comments
    # @global infoProcGlobal: array containing all the global
    # parameters
    # @global infoProcReturn: array containing all the return
    # comments.
    # @global infoProcDefault : Array containing the Default values
    # for the optional parameters
    # @global commentFile : Comments Associated to the whole file
    # @global commentFileNb : Number of Lines for the file
    # @global stats : Array containing Statistics about the current
    # process
    # @global missingCommentFct : List of non commented functions
    # @global missingCommentParam : List of non commented parameters
    # @global missingCommentGlobal : List of non commented globals
    # @global missingCommentReturn : List of non commented return
    #
    #
    
    global options
    global listProc
    global listGlobal
    global infoProc
    global infoProcReturn
    global infoProcParam
    global infoProcComment
    global infoProcGlobal
    global infoProcDefault
    global commentFile
    global commentFileNb
    global stats
    global missingCommentFct
    global missingCommentGlobal
    global missingCommentParam
    global missingCommentReturn

    foreach proce $listProc {
	puts $fileID "<H2><A NAME=\"$proce\">Function $proce</A></H2>"
	puts $fileID "<P>"
	
	# Display of the general comments
	if { [info exists infoProcComment($proce)] == 1 } then {
	    puts $fileID "Associated Comment<P>"
	    puts $fileID "$infoProcComment($proce)"
	    set stats(nbCommentedFct) [expr $stats(nbCommentedFct) + 1.0]
	} else {
	    if { $options(showEmptyComment) == "on" } then {
		puts $fileID "[subst $options(noCommentFormat)]<P>"
	    }
	    lappend missingCommentFct [list $file $proce]
	} 
	
	if { [info exists infoProc($proce)] == 1} then {
	    set listParam $infoProc($proce)
	} else {
	    set listParam ""
	}

	# Display of the parameters
	if { [llength $listParam] != 0 && $options(detailParam) == "on" } then {
	    puts $fileID "<H3>Parameters</H3>"
	    puts $fileID "<DL>"

	    foreach param $listParam {
		set stats(nbParam) [expr $stats(nbParam) + 1.0]
		if { [info exists infoProcDefault($proce,$param)] == 1 } then {
		    set def $infoProcDefault($proce,$param)
		    puts $fileID "<DT>$options(parameterBulletHTML)$param (<B>Optional parameter with default value: \"$def\"</B>)"
		    if { [info exists infoProcParam($proce,$param)] == 0 || \
			    $infoProcParam($proce,$param) == "" } then {
			if { $options(showEmptyComment) == "on"} then {
			    puts $fileID "<DD>[subst $options(noCommentFormat)]"
			}
			lappend missingCommentParam [list $file $proce $param]
		    } else {
			set stats(nbCommentedParam) [expr $stats(nbCommentedParam) +1.0]
			puts $fileID "<DD>$infoProcParam($proce,$param)"
		    }
		} else {
		    puts $fileID "<DT>$options(parameterBulletHTML)$param"
		    if { [info exists infoProcParam($proce,$param)] == 0 || \
			    $infoProcParam($proce,$param) == "" } then {
			if { $options(showEmptyComment) == "on"} then {
			    puts $fileID "<DD>[subst $options(noCommentFormat)]"
			}
			lappend missingCommentParam [list $file $proce $param]
		    } else {
			puts $fileID "<DD>$infoProcParam($proce,$param)"
			set stats(nbCommentedParam) [expr $stats(nbCommentedParam) +1.0]
		    }
		}
	    }
	    
	    puts $fileID "</DL>"
	    puts $fileID "\n"
	}
	
# display of the globals
	if { [info exists listGlobal($proce)] == 1 && \
		[llength $listGlobal($proce)] != 0 && \
		$options(detailGlobal) == "on" } then {
	    puts $fileID "<H3>Global parameters</H3>"
	    puts $fileID "\n<DL>"
	    foreach item $listGlobal($proce) {
		set stats(nbGlobal) [expr $stats(nbGlobal) + 1.0]
		puts $fileID "<DT>$options(parameterBulletHTML)$item"
		if { [info exists infoProcGlobal($proce,$item)] == 0 || \
			$infoProcGlobal($proce,$item) == "" } then {
		    if { $options(showEmptyComment) == "on" } then {
			puts $fileID "<DD>[subst $options(noCommentFormat)]"
		    }
		    lappend missingCommentGlobal [list $file $proce $item]
		} else {
		    set stats(nbCommentedGlobal) [expr $stats(nbCommentedGlobal) + 1.0]
		    puts $fileID "<DD>$infoProcGlobal($proce,$item)"
		}
		puts $fileID "</DL>"
	    }
	}

# Display the return information if any	
	if { [info exists infoProcReturn($proce)] == 1 } then {
	    puts $fileID "\n<H3>Return Value</H3>\n\n$infoProcReturn($proce)\n"
	} else {
	    lappend missingCommentReturn [list $file $proce]
	}
	
	if { $proce != [lindex $listProc end] } then {
	    puts $fileID "\n$options(procSeparatorHTML)\n"
	}
    }
}

proc outputFctTable {fileID file} {
    #
    # Function called to make an HTML dump of the found structure. The
    # parameters, comments and global parameters are delivered.
    # The output is put on one file
    #
    # @param fileID : File Identifier
    # @param file: Filename corresponding to the actual structure
    # 
    # @global options: Array for prg options
    # @global listProc: List of all recognised functions of the file
    # @global listGlobal: An array containing a per-function list of used
    # global variables
    # @global infoProc: array containing functions information
    # @global infoProcParam: array containing parameters information
    # @global infoProcComment: array containing all the sarting comments
    # @global infoProcGlobal: array containing all the global
    # parameters
    # @global infoProcReturn: array containing all the return
    # comments.
    # @global infoProcDefault : Array containing the Default values
    # for the optional parameters
    # @global commentFile : Comments Associated to the whole file
    # @global commentFileNb : Number of Lines for the file
    # @global options: Array of the current options of the prog
    # @global stats : Array containing Statistics about the current
    # process
      # @global missingCommentFct : List of non commented functions
    # @global missingCommentParam : List of non commented parameters
    # @global missingCommentGlobal : List of non commented globals
    # @global missingCommentReturn : List of non commented return
#

    global options
    global listProc
    global listGlobal
    global infoProc
    global infoProcReturn
    global infoProcParam
    global infoProcComment
    global infoProcGlobal
    global infoProcDefault
    global commentFile
    global commentFileNb
    global stats
    global missingCommentFct
    global missingCommentParam
    global missingCommentReturn
    global missingCommentGlobal

    puts $fileID "<TABLE $options(tableParam)>"

    foreach proce $listProc {
	puts $fileID "<TR $options(TRFunction)>"
	puts $fileID "<TD COLSPAN=3 $options(TDFunction)><H2><A NAME=\"$proce\">Function $proce</A></H2></TD>"
	puts $fileID "</TR>"

	# Function Comment
	if { [info exists infoProcComment($proce)] == 1 } then {
	    puts $fileID "<TR $options(TRFunctionComment)>"
	    puts $fileID "<TD COLSPAN=3 $options(TDFunctionComment)>$infoProcComment($proce)</TD>"
	    puts $fileID "</TR>"
	    set stats(nbCommentedFct) [expr $stats(nbCommentedFct) + 1.0]
	    
	} else {
	    if { $options(showEmptyComment) == "on" } then {
		puts $fileID "<TR $options(TRFunctionComment)>"
		puts $fileID "<TD COLSPAN=3 $options(TDFunctionComment)>[subst $options(noCommentFormat)]</TD>"
		puts $fileID "</TR>"
	    }	
	    lappend missingCommentFct [list $file $proce]
	} 
	
	if { [info exists infoProc($proce)] == 1} then {
	    set listParam $infoProc($proce)
	} else {
	    set listParam ""
	}

# Display of parameters	
	if { [llength $listParam] != 0 && \
		$options(detailParam) == "on" } then {
	    puts $fileID "<TR $options(TRParam)>"
	    puts $fileID "<TD COLSPAN=3 $options(TDParam)><H3>Parameters</H3></TD>"
	    puts $fileID "</TR>"
	    
	    foreach param $listParam {
		set stats(nbParam) [expr $stats(nbParam) + 1.0]
		if { [info exists infoProcDefault($proce,$param)] == 1 } then {
		    set def $infoProcDefault($proce,$param)
		    puts $fileID "<TR $options(TRParamLine)>"
		    puts $fileID "<TD $options(TDParamName)>${param}(<B>Optional parameter</B>)</TD>"
		    
		    if { [info exists infoProcParam($proce,$param)] == 0 || \
			    $infoProcParam($proce,$param) == "" } then {
			if { $options(showEmptyComment) == "on"} then {
			    puts $fileID "<TD $options(TDParamComment)>[subst $options(noCommentFormat)]</TD>"
			} else {
			    puts $fileID "<TD $options(TDParamComment)></TD>"
			}
			puts $fileID "<TD $options(TDParamComment)>\"$def\"</TD>"	
			lappend missingCommentParam [list $file $proce $param]
		    } else {
			set stats(nbCommentedParam) [expr $stats(nbCommentedParam) + 1.0]
			puts $fileID "<TD $options(TDParamComment)>$infoProcParam($proce,$param)</TD>" 		
			puts $fileID "<TD $options(TDParamValue)>\"$def\"</TD>"
		    }
		    puts $fileID "</TR>"
		} else {
		    puts $fileID "<TR $options(TRParamLine)>"
		    puts $fileID "<TD $options(TDParamName)>$param</TD>"

		    if { [info exists infoProcParam($proce,$param)] == 0 || \
			    $infoProcParam($proce,$param) == "" } then {
			if { $options(showEmptyComment) == "on"} then {
			    puts $fileID "<TD $options(TDParamComment) COLSPAN=2>[subst $options(noCommentFormat)]</TD>" 		
			} else {   
			    puts $fileID "<TD $options(TDParamComment) COLSPAN=2></TD>"	
			    lappend missingCommentParam [list $file $proce $param]
			}

		    } else {
			set stats(nbCommentedParam) [expr $stats(nbCommentedParam) + 1.0]
			puts $fileID "<TD $options(TDParamComment) COLSPAN=2>$infoProcParam($proce,$param)</TD>" 		
		    }
		    
		    puts $fileID "</TR>"
		} 
	    }
	}
# Display of globals
	if { [info exists listGlobal($proce)] == 1 && \
		[llength $listGlobal($proce)] != 0 && \
		$options(detailGlobal) == "on" } then {
	    puts $fileID "<TR $options(TRGlobal)>"
	    puts $fileID "<TD $options(TDGlobal) COLSPAN=3><H3>Global Parameters</H3></TD>"
	    puts $fileID "</TR>"

	    foreach item $listGlobal($proce) {
		set stats(nbGlobal) [expr $stats(nbGlobal) + 1.0]
		puts $fileID "<TR $options(TRGlobalLine)>"
		puts $fileID "<TD $options(TDGlobalName)>$item</TD>"
		if { [info exists infoProcGlobal($proce,$item)] == 0 || \
			$infoProcGlobal($proce,$item) == "" } then {
		    if { $options(showEmptyComment) == "on" } then {
			puts $fileID "<TD $options(TDGlobalComment) COLSPAN=2><I>[subst $options(noCommentFormat)]</TD>"
		    } else {
			puts $fileID "<TD $options(TDGlobalComment) COLSPAN=2></TD>"
		    }
		    lappend missingCommentGlobal [list $file $proce $item]
		} else {
		    set stats(nbCommentedGlobal) [expr $stats(nbCommentedGlobal) + 1.0 ]
		    puts $fileID "<TD $options(TDGlobalComment) COLSPAN=2>$infoProcGlobal($proce,$item)</TD>"
		}
		puts $fileID "</TR>"
	    }
	}
# Display Return comments if any	
	if { [info exists infoProcReturn($proce)] == 1 } then {
	    puts $fileID "<TR $options(TRReturn)>"
	    puts $fileID "<TD $options(TDReturn) COLSPAN=3><H3>Return Value</H3></TD>"
	    puts $fileID "</TR>"
	    puts $fileID "<TR $options(TRReturnComment)>"
	    puts $fileID "<TD $options(TDReturnComment) COLSPAN=3>$infoProcReturn($proce)</TD>"
	    puts $fileID "</TR>"
	} else {
	    lappend missingCommentReturn [list $file $proce]
	}	
    }
    puts $fileID "</TABLE>\n"
}

proc outputHTML {file} {
    #
    # Function called to make an HTML dump of the found structure. The
    # parameters, comments and global parameters are delivered.
    # The output is put on one file
    #
    # @param file: Filename corresponding to the actual structure
    # 
    # @global options: Array for prg options
    # @global listProc: List of all recognised functions of the file
    # @global listGlobal: An array containing a per-function list of used
    # global variables
    # @global infoProc: array containing functions information
    # @global infoProcParam: array containing parameters information
    # @global infoProcComment: array containing all the sarting comments
    # @global infoProcGlobal: array containing all the global
    # parameters
    # @global infoProcReturn: array containing all the return
    # comments.
    # @global infoProcErr : Array containing the name of the erroneous
    # functions.
    # @global infoProcDefault : Array containing the Default values
    # for the optional parameters
    # @global commentFile : Comments Associated to the whole file
    # @global commentFileNb : Number of Comments
    #
    
    global options
    global listProc
    global listGlobal
    global infoProc
    global infoProcReturn
    global infoProcParam
    global infoProcComment
    global infoProcGlobal
    global infoProcDefault
    global infoProcErr
    global commentFile
    global commentFileNb

    set newFile [file tail $file]
    set outputFile [file join $options(directory) "$newFile.html"]

    set regAuthor "^@author\[ \t\]+(.*)"
    set regVersion "^@version\[ \t\]+(.*)"
    set regSee "^@see\[ \t\]+(.*)"

    if { $options(forceWrite) == "off" } then {
	if { [file exists $outputFile] == 1 } then {
	    puts stderr "$outputFile already exists."
	    return 1
	}
    }

    set fileID [open $outputFile "w"]

    if { $fileID == "" } then {
	puts stderr "\t=> Impossible to open the output file"
	return 1
    }

    puts $fileID "<HTML>"
    puts $fileID "<HEAD>"
    puts $fileID "\n<TITLE>"
    puts $fileID "[file tail $file] Description"
    puts $fileID "</TITLE>"
    puts $fileID "\n<!-- Automatically genererated by tcldoc version $options(version) -->"
    puts $fileID "</HEAD>"

    puts $fileID $options(bodyHTML)
    puts $fileID $options(startFileHTML)
    puts $fileID "<P $options(fileTitleParagraph)>"
    puts $fileID "<FONT $options(fileTitleFont)>"
    puts $fileID "[file tail $file] Description"
    puts $fileID "</FONT>"
    puts $fileID "</P>"
    
    if {[info exists commentFile] == 1 } then {
	if { $commentFileNb != 0 } then {
	    puts $fileID "<PRE>"
	    for {set nb 0} {$nb < $commentFileNb} {incr nb} {
		set flagA [regexp -- $regAuthor $commentFile($nb) dummy author]
		set flagV [regexp -- $regVersion $commentFile($nb) dummy version]
		set flagS [regexp -- $regSee $commentFile($nb) dummy link]
		if { $flagA == 1 } then {
		    puts $fileID "<B>Author :</B> $author"
		} elseif { $flagV == 1} then {
		    puts $fileID "<B>Version :</B> $version"
		} elseif { $flagS == 1} then {
		    if { [llength $link] == 1 } then {
			puts $fileID "<B>See Also :</B> <A HREF=\"$link\">$link</A>"
		    } else {
			set l [lindex $link 0]
			set toSee [lrange $link 1 end]
			puts $fileID "<B>See Also :</B> <A HREF=\"$l\">$toSee</A>"
		    }
		} else {
		    puts $fileID "$commentFile($nb)"
		}
	    }
	    puts $fileID "</PRE><P>"
	}
    }
    
    if { [info exists infoProcErr($file)] == 1} then {
	puts $fileID "<FONT COLOR=\"$options(errorColor)\">List of Errorneous Functions</FONT>"
	puts $fileID "<DL>"
	
	foreach proce $infoProcErr($file) {
	    puts $fileID "<DT>$options(functionBulletHTML)$proce"
	}
	puts $fileID "</DL>"
	puts $fileID "\n"
    }

    if { [llength $listProc] > 0 } then {
	if { $options(indexFunction) == "on" } then {
	    puts $fileID "List of Functions"
	    puts $fileID "<DL>"
	    
	    foreach proce $listProc {
		puts $fileID "<DT>$options(functionBulletHTML)<A HREF=\"\#$proce\">$proce</A>"
	    }
	    puts $fileID "</DL>"
	    puts $fileID "\n"
	}
	
	switch $options(htmlType) {
	    "table" {
		outputFctTable $fileID $file
	    }
	    "normal" -
	    default {
		outputFctDefault $fileID $file
	    }
	}
    }

    
    puts $fileID "\n"
    puts $fileID $options(endFileHTML)
    puts $fileID "</BODY>"
    puts $fileID "</HTML>"

    close $fileID

    return 0
}

proc writeSummaryTable {fileID} {
    #
    # Function called to generate a Summary in a Table format
    #
    # @param fileID : file Identifier
    #
    # @global stats : Array containing Statistics about the current
    # process
    # @global options: Array for prg options
    #
    global stats
    global options 


    puts $fileID "<TABLE $options(tableParam)>"

    set nbFile [llength $stats(listFile)]
    set nbFct [llength $stats(generalFctList)]
    set percComment [expr $stats(nbCommentLine)/$stats(nbReadLine)*100.0]

    puts $fileID "<TR $options(TRSummary)>"
    puts $fileID "<TD $options(TDSummary) COLSPAN=2><H1>Summary</H1></TD>"
    puts $fileID "</TR>"

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>File Handled</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%4.0f</TD>" \
		     $nbFile]
    puts $fileID "</TR>"

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>Found Functions</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%4.0f</TD>" \
		     $nbFct]
    puts $fileID "</TR>"

    if { $stats(nbErrFunction) != 0.0 } then {
	puts $fileID "<TR $options(TRSummaryLine)>"
	puts $fileID "<TD $options(TDSummaryText)><FONT COLOR=\"$options(errorColor)\">Erroneous Functions</FONT></TD>"
	puts $fileID [format "<TD $options(TDSummaryValue)><FONT COLOR=\"$options(errorColor)\">%4.0f</FONT></TD>" \
			 $stats(nbErrFunction)]
	puts $fileID "</TR>"
    }

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>Lines Read</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%4.0f</TD>" \
		     $stats(nbReadLine) ]
    puts $fileID "</TR>"

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>Comment Lines</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%4.0f</TD>" \
		     $stats(nbCommentLine) ]
    puts $fileID "</TR>"

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>Comment Percentage</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%04.2f%%</TD>" \
		     $percComment]
    puts $fileID "</TR>"

    puts $fileID "<TR $options(TRSummaryLine)>"
    puts $fileID "<TD $options(TDSummaryText)>Commented Functions</TD>"
    puts $fileID [format "<TD $options(TDSummaryValue)>%04.2f%% (%4.0f/%4.0f)" \
		     [expr $stats(nbCommentedFct)/$nbFct*100.0] \
		     $stats(nbCommentedFct) $nbFct ]
    if { $options(showEmptyComment) == "on" && \
	    $nbFct != $stats(nbCommentedFct) && \
	    $nbFct != 0} then {
	puts $fileID [format "<A HREF=\"\#uncommentFct\">Uncommented Fct</A>"]
    }
    puts $fileID "</TD>"
    puts $fileID "</TR>"
    
    if { $options(detailParam) == "on" } then {
	puts $fileID "<TR $options(TRSummaryLine)>"
	puts $fileID "<TD $options(TDSummaryText)>Commented Parameters</TD>"
	puts $fileID [format "<TD $options(TDSummaryValue)>%04.2f%% (%4.0f/%4.0f)" \
			 [expr $stats(nbCommentedParam)/$stats(nbParam)*100.0] \
			 $stats(nbCommentedParam) $stats(nbParam) ]
	if { $options(showEmptyComment) == "on" && \
		$stats(nbParam) != $stats(nbCommentedParam) && \
		$stats(nbParam) != 0} then {
	    puts $fileID [format "<A HREF=\"\#uncommentParam\">Uncommented Parameters</A>"]
	}
	puts $fileID "</TD>"
	puts $fileID "</TR>"
    }
    if { $options(detailGlobal) == "on" } then {
	puts $fileID "<TR $options(TRSummaryLine)>"
	puts $fileID "<TD $options(TDSummaryText)>Commented Globals</TD>"
	puts $fileID [format "<TD $options(TDSummaryValue)>%04.2f%% (%4.0f/%4.0f)" \
			 [expr $stats(nbCommentedGlobal)/$stats(nbGlobal)*100.0] \
			 $stats(nbCommentedGlobal) $stats(nbGlobal) ]
	if { $options(showEmptyComment) == "on" && \
		$stats(nbGlobal) != $stats(nbCommentedGlobal) && \
		$stats(nbGlobal) != 0} then {
	    puts $fileID [format "<A HREF=\"\#uncommentGlobal\">Uncommented Global</A>"]
	}
	puts $fileID "</TD>"
	puts $fileID "</TR>"
    }

    puts $fileID "</TABLE>"
}

proc writeSummaryDefault {fileID} {
    #
    # Function called to generate a Summary in the default/normal format
    #
    # @param fileID : file Identifier
    #
    # @global stats : Array containing Statistics about the current
    # process
    # @global options: Array for prg options
    #

    global stats
    global options

    puts $fileID "<H1>Summary</H1>"
    set nbFile [llength $stats(listFile)]
    set nbFct [llength $stats(generalFctList)]
    puts $fileID "$nbFile files has been handled.<BR>"
    puts $fileID [format "%4.0f functions has been found.<BR>" \
		     $nbFct]
    puts $fileID [format "%4.0f functions are erroneous.<BR>" \
		     $stats(nbErrFunction)]
    puts $fileID [format "%4.0f lines of TCL code has been read.<BR>" \
		     $stats(nbReadLine) ]
    puts $fileID [format "%4.0f lines are comments.<BR>" \
		     $stats(nbCommentLine) ]
    set percComment [expr $stats(nbCommentLine)/$stats(nbReadLine)*100.0]
    puts $fileID [format "This gives you a comment percentage of %04.2f%%.<BR>" \
		     $percComment]
    puts $fileID [format "%04.2f%% of the functions have a comment (%4.0f/%4.f)." \
		     [expr $stats(nbCommentedFct)/$nbFct*100.0] \
		     $stats(nbCommentedFct) $nbFct ]
    if { $options(showEmptyComment) == "on" && \
	    $nbFct != $stats(nbCommentedFct) && \
	    $nbFct != 0} then {
	puts $fileID [format "<A HREF=\"\#uncommentFct\">Uncommented Fct</A>"]
    }
    puts $fileID "<BR>"
    
    if { $options(detailParam) == "on" } then {
	puts $fileID [format "%04.2f%% of the parameters have a comment (%4.0f/%4.f)." \
			 [expr $stats(nbCommentedParam)/$stats(nbParam)*100.0] \
			 $stats(nbCommentedParam) $stats(nbParam) ]
	if { $options(showEmptyComment) == "on" && \
		$stats(nbParam) != $stats(nbCommentedParam) && \
		$stats(nbParam) != 0} then {
	    puts $fileID [format "<A HREF=\"\#uncommentParam\">Uncommented Parameters</A>"]
	}
	puts $fileID "<BR>"
    }

    if { $options(detailGlobal) == "on" } then {
	puts $fileID [format "%04.2f%% of the global have a comment (%4.0f/%4.f)." \
			 [expr $stats(nbCommentedGlobal)/$stats(nbGlobal)*100.0] \
			 $stats(nbCommentedGlobal) $stats(nbGlobal) ]
	if { $options(showEmptyComment) == "on" && \
		$stats(nbGlobal) != $stats(nbCommentedGlobal) && \
		$stats(nbGlobal) != 0} then {
	    puts $fileID [format "<A HREF=\"\#uncommentGlobal\">Uncommented Globals</A>"]
	}
	puts $fileID "<BR>"
    }
}

proc writeIndex {listFile} {
    #
    # Function called to set the header of an
    # HTML file
    #
    # @param listFile : List of file to handle
    #
    # @global options: Array of the current options of the prog
    # @global stats : Array containing Statistics about the current
    # process
    # @global generalFctList : List of all the Functions.
    # @global missingCommentFct : List of non commented functions
    # @global missingCommentParam : List of non commented parameters
    # @global missingCommentGlobal : List of non commented globals
    # @global missingCommentReturn : List of non commented return
    #
    global options
    global generalFctList
    global stats
    global missingCommentFct
    global missingCommentReturn
    global missingCommentGlobal
    global missingCommentParam

    set outputFile [file join $options(directory) "index.html"]

    if { [file exists $outputFile] == 1 } then {
	if { $options(forceWrite) == "off" } then {
	    puts stderr "IndexFile $outputFile already exists."
	    puts stderr "\t-> It is not generated."
	    return 1
	}
    }

    set fileID [open $outputFile "w"]

    if { $fileID == "" } then {
	puts stderr "\t=> Impossible to open the output file"
	return 1
    }

    puts $fileID "<HTML>"
    puts $fileID "<HEAD>"
    puts $fileID "\n<TITLE>"
    puts $fileID $options(indexTitle)
    puts $fileID "</TITLE>"
    puts $fileID "\n<!-- Automatically genererated by tcldoc version $options(version) -->"
    puts $fileID "</HEAD>"

    puts $fileID $options(bodyHTML)
    puts $fileID "$options(startIndexHTML)"
    puts $fileID "<P $options(fileTitleParagraph)>"
    puts $fileID "<FONT $options(fileTitleFont)>"
    puts $fileID "$options(indexTitle)"
    puts $fileID "</FONT>"
    puts $fileID "</P>"

    if { $options(summary) == "on" } then {
	switch $options(htmlType) {
	    "table" {
		writeSummaryTable $fileID
	    }
	    default {
		writeSummaryDefault $fileID		
	    }
	}
    }

    puts $fileID "<H1>File Index</H1>"
    puts $fileID "<DL>"
    
    if { $options(sortFile) == "on" } then {
	set listFile [lsort $stats(listFile)]
    } else {
	set listFile $stats(listFile)
    }
    
    foreach file $listFile {
	puts $fileID "<DT>$options(parameterBulletHTML)<A REL=\"chapter\" HREF=\"[file tail $file].html\">[file tail $file]</A>"
    }
    puts $fileID "</DL>"
    puts $fileID "\n"
    
    puts $fileID "<P>"
    
    if { $options(generalFunctionList) == "on"} then {
	puts $fileID "<H1>Function Index</H1>"
	puts $fileID "<DL>"
	if { $options(sortProc) =="on"} then {
	    set listFct [lsort $stats(generalFctList)]
	} else {
	    set listFct $stats(generalFctList)
	}
	foreach item $stats(generalFctList) {
	    set file [lindex $item 0]
	    set proce [lindex $item 1]
	    puts $fileID "<DT>$options(parameterBulletHTML)<A HREF=\"$file.html\#$proce\">$proce</A>"
	}
	puts $fileID "</DL>"
	puts $fileID "\n"
	
	puts $fileID "<P>"
	
    }

    if  { $options(showEmptyComment) == "on" } then {

	if {[info exists missingCommentFct] == 1} then {
	    puts $fileID "<H1><A NAME=\"uncommentFct\">Not Commented Functions</A></H1>"
	    puts $fileID "<DL>"
	    
	    foreach item $missingCommentFct {
		set f [lindex $item 0]
		set p [lindex $item 1]
		puts $fileID "<DT>$options(parameterBulletHTML) <A HREF=\"[file tail $f].html\#$p\">$p</A> in [file tail $f]"
	    }
	    puts $fileID "</DL>"
	    puts $fileID "\n"
	}

	if {[info exists missingCommentGlobal] == 1} then {
	    puts $fileID "<H1><A NAME=\"uncommentGlobal\">Not Commented Globals</A></H1>"
	    puts $fileID "<DL>"
	    
	    foreach item $missingCommentGlobal {
		set f [lindex $item 0]
		set p [lindex $item 1]
		set g [lindex $item 2]
		puts $fileID "<DT>$options(parameterBulletHTML)<A HREF=\"[file tail $f].html\#$p\">$g</A> in function $p ([file tail $f])"
	    }
	    puts $fileID "</DL>"
	    puts $fileID "\n"
	}

	if {[info exists missingCommentParam] == 1} then {
	    puts $fileID "<H1><A NAME=\"uncommentParam\">Not Commented Parameters</A></H1>"
	    puts $fileID "<DL>"
	    
	    foreach item $missingCommentParam {
		set f [lindex $item 0]
		set p [lindex $item 1]
		set pr [lindex $item 2]
		puts $fileID "<DT>$options(parameterBulletHTML)<A HREF=\"[file tail $f].html\#$p\">$pr</A> in function $p ([file tail $f])</A>"
	    }
	    puts $fileID "</DL>"
	    puts $fileID "\n"
	}
    }

    puts $fileID "\n"
    puts $fileID "$options(endIndexHTML)"
    puts $fileID "</BODY>"
    puts $fileID "</HTML>"

    close $fileID

    return 0
}

proc resetFile {} {
    #
    # Function called to reset all the information about a file.
    #
    # @global listProc: List of all recognised functions of the file
    # @global listGlobal: An array containing a per-function list of used
    # global variables
    # @global infoProc: array containing functions information
    # @global infoProcParam: array containing parameters information
    # @global infoProcComment: array containing all the sarting comments
    # @global infoProcGlobal: array containing all the global
    # parameters
    # @global infoProcReturn: array containing all the return
    # comments.
    # @global infoProcDefault : Array containing the Default values
    # for the optional parameters
    # @global commentFile : Comments Associated to the whole file
    # @global commentFileNb : Number of Lines for the file
    #
    global listProc
    global listGlobal
    global infoProc
    global infoProcComment
    global infoProcGlobal
    global infoProcParam
    global infoProcDefault
    global commentFile
    global commentFileNb

    catch {
	unset listProc
	unset infoProc
	unset infoProcComment
	unset infoProcGlobal
	unset infoProcParam
	unset infoProcDefault
	unset listGlobal
	unset commentFile
	unset commentFileNb
    }
}

proc resetOptions {} {
    #
    # Function to reset the options of the program.
    #   
    # @global options: Array of the current options of the prog
    #

    global options

    set options(verbose) off
    
    set options(forceWrite) off

    set options(listFile) ""
    
    set options(sortProc) "off"
    set options(sortGlobal) "off"
    set options(sortFile) "off"
    
    set options(showEmptyComment) "off"
    
    set options(detailGlobal) "on"
    set options(detailParam) "on"

    set options(htmlIndex) "on"
    set options(summary) "on"
    set options(generalFunctionList) "on"

    set options(indexFunction) "on"
    
    set options(indexTitle) "TCL Documentation"

    set options(configFile) "~/.tcldocrc"

    set options(htmlType) normal
    set options(bodyHTML) "<BODY>"

    set options(procSeparatorHTML) "\n<P><HR>\n"
    set options(parameterBulletHTML) ""
    set options(functionBulletHTML) ""

    set options(tableParam)  ""

    set options(TRFunction) ""
    set options(TDFunction) "ALIGN=CENTER"
    set options(TRFunctionComment) ""
    set options(TDFunctionComment) "ALIGN=LEFT"

    set options(TRParam) ""
    set options(TDParam) "ALIGN=CENTER"

    set options(TRParamLine) ""
    set options(TDParamName) "ALIGN=LEFT"
    set options(TDParamComment) "ALIGN=LEFT"
    set options(TDParamValue) "ALIGN=LEFT"

    set options(TRGlobal) ""
    set options(TDGlobal) "ALIGN=CENTER"
    set options(TRGlobalLine) ""
    set options(TDGlobalName) "ALIGN=LEFT"
    set options(TDGlobalComment) "ALIGN=LEFT"

    set options(TRReturn) ""
    set options(TDReturn) "ALIGN=CENTER"

    set options(TRReturnComment) ""
    set options(TDReturnComment) "ALIGN=LEFT"

    set options(TRSummary) ""
    set options(TDSummary) "ALIGN=CENTER"

    set options(TRSummaryLine) ""
    set options(TDSummaryText) "ALIGN=LEFT"
    set options(TDSummaryValue) "ALIGN=CENTER"

    set options(errorColor) red

    set options(fileTitleParagraph) "ALIGN=CENTER"
    set options(fileTitleFont) "SIZE=\"+3\" COLOR=\"blue\""
    
    set options(startIndexHTML) ""
    set options(endIndexHTML) ""
    set options(startFileHTML) ""
    set options(endFileHTML) ""

    set options(directory) "."
    set options(removeReg) "^\#!.*|^\# -\*-.*"
    set options(procReg) "^proc\[ \t\]*(\[^ \t\]*)\[ \t\]*\{.*"
    set options(noCommentFormat) "No Comment"
    return 0
}

proc parseOptions {} {
    #
    # Function called to parse the arguments coming from the command line
    # and to transfer them in options for the program.
    #
    # @global options: Array of the current options of the prog
    # @global argv : The Arguments passed to the Script
    # @global argv0 : Name of the script
    #
    
    global options
    global argv
    global argv0

    if { [llength $argv] == 0 } then {
	return 1
    }

    set ind [lsearch $argv "-help"]
    if { $ind != -1 } then {
	return 1
    }

    set ind [lsearch $argv "-directory"]
    if { $ind != -1 } then {
	set index [expr $ind + 1]
	set value [lrange $argv $index $index]
	set argv [lreplace $argv $ind $index]

	set options(directory) $value
    }

    set ind [lsearch $argv "-configFile"]
    if { $ind != -1 } then {
	set index [expr $ind + 1]
	set value [lrange $argv $index $index]
	set argv [lreplace $argv $ind $index]

	set options(configFile) $value
    }

    set ind [lsearch $argv "-htmlType"]
    if { $ind != -1 } then {
	set index [expr $ind + 1]
	set value [lrange $argv $index $index]
	set argv [lreplace $argv $ind $index]

	set value [string trim $value]

	set options(htmlType) $value
    }

    set ind [lsearch $argv "-indexTitle"]
    if { $ind != -1 } then {
	set index [expr $ind + 1]
	set value [lrange $argv $index $index]
	set argv [lreplace $argv $ind $index]

	set options(indexTitle) ""
	foreach w $value {
	    set options(indexTitle) "$options(indexTitle) $w"
	}
    }

    set ind [lsearch $argv "-verbose"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(verbose) "on"
    }

    set ind [lsearch $argv "-forceWrite"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(forceWrite) "on"
    }

    set ind [lsearch $argv "-sortFile"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(sortFile) "on"
    }

    set ind [lsearch $argv "-sortProc"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(sortProc) "on"
    }

    set ind [lsearch $argv "-sortGlobal"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(sortGlobal) "on"
    }

    set ind [lsearch $argv "-noDetailGlobal"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(detailGlobal) "off"
    }

    set ind [lsearch $argv "-noDetailParam"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(detailParam) "off"
    }

    set ind [lsearch $argv "-noHtmlIndex"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(htmlIndex) "off"
    }
    set ind [lsearch $argv "-noSummary"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(summary) "off"
    }
    set ind [lsearch $argv "-noGeneralFunctionList"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(generalFunctionList) "off"
    }

    set ind [lsearch $argv "-noIndexFunction"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(indexFunction) "off"
    }
    set ind [lsearch $argv "-noRemoveFct"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(removeFunction) "off"
    }

    set ind [lsearch $argv "-showEmpty"]
    if { $ind != -1 } then {
	set argv [lreplace $argv $ind $ind]
	set options(showEmptyComment) "on"
    }


    set options(listFile) $argv

    return 0
}

proc printUsage {} {
    #
    # Function called to print the usage of the script
    #
    # @global argv0 : Name of the script
    # @global options: Array of the current options of the prog
    #
    global argv0
    global options

    puts stdout "$argv0 :Automatic Documentation Generator"
    puts stdout "Version $options(version)"
    puts stdout "For comments and bugs : jma@acri.fr"
    puts stdout "Usage : $argv0 \[options\] TCL-files\n"
    puts stdout "Options:"
    puts stdout "\t-help"
    puts stdout "\t-configFile file"
    puts stdout "\t-directory directoryName"
    puts stdout "\t-indexTitle title"
    puts stdout "\t-htmlType table|normal"
    puts stdout "\t-verbose"
    puts stdout "\t-forceWrite"
    puts stdout "\t-sortFile"
    puts stdout "\t-sortProc"
    puts stdout "\t-sortGlobal"
    puts stdout "\t-showEmpty"
    puts stdout "\t-noDetailGlobal"
    puts stdout "\t-noDetailParam"
    puts stdout "\t-noHtmlIndex"
    puts stdout "\t-noSummary"
    puts stdout "\t-noRemoveFct"
    puts stdout "\t-noGeneralFunctionList"
    puts stdout "\t-noIndexFunction"
}

#
# Parsing the commandline options
#
if { [resetOptions] != 0 } then {
    exit 1
}


if { $options(configFile) != "" } then {
    if { [file readable $options(configFile)] == 1 } then {
	doOutput "Config File ($options(configFile)) Reading..."
	
	set flag [catch {
	    source $options(configFile)
	} ]
	if { $flag == 0 } then {
	    doOutput "Configuration OK."
	} else {
	    puts stderr "ERROR during reading of the configuration file."
	}
    }
}

set flagParse [parseOptions]
if { $flagParse == 1 } then {
    printUsage
    exit 0
} elseif { $flagParse <0 } then {
    exit 2
}

if { $options(listFile) == "" } then {
    puts stderr " No file to handle"
    exit 3
}

switch $options(htmlType) {
    "table" {
    }
    "normal" {
    }
    default {
	puts stderr "Unknow HTML output type ($options(htmlType))"
	puts stderr "default one ('normal') is taken"
    }
}

#
# Now the parsing of the files
#
if { $options(sortFile) == "on" } then {
    set listFile [lsort $options(listFile)]
} else {
    set listFile $options(listFile)
}

#
# Init of File
#

set nbErr 0
set stats(nbReadLine) 0.0
set stats(nbCommentLine) 0.0
set stats(generalFctList) {}
set stats(listFile) {}
set stats(nbCommentedFct) 0.0
set stats(nbParam) 0.0
set stats(nbCommentedParam) 0.0
set stats(nbGlobal) 0.0
set stats(nbCommentedGlobal) 0.0
set stats(nbErrFunction) 0.0

foreach file $listFile {
    if { [file readable $file] == 1 } then {
	doOutput "[file tail $file] handling ..."

	resetFile 
	parseFile $file

	#
	# now giving the result
	#
	incr nbErr [outputHTML $file]
    } else {
	incr nbErr
	puts stderr "$file not readable."
    }
}

set toReturn 0
if { $nbErr == 0 } then {
    if { $options(htmlIndex) == "on" } then {
	doOutput "\nIndex generation... "
	set toReturn [writeIndex $listFile]
    }
} else {
    puts stderr "$nbErr Errors : the index file is not written."
    set toReturn 1
}

exit $toReturn

#
# End of the program
#

