#!/ldcg/bin/perl =pod This is TclDOC. TclDOC is a perl script written by LIGO LDAS to create HTML web pages from Tcl/Tk code. This script will take PROPERLY formatted Tcl/Tk and generate documentation in HTML format. It assumes that every procedure has a comment header with 5 possible sections, followed by a procedure block: ## *********************************************** ## ## Name: tclProc ## ## Description: ## Just another Tcl Procedure! ## ## Parameters: ## this a thing of type 1 ## that a thing of type 2 ## other any other thing ## ## Usage: ## set foo [ tclProc stuff ] ## ## Comments: ## Not much practical use for anything! ## ## "stuff" may have 4 possible values: ## 1. foo ## 2. bar ## 3. baz ## 4. bim ## ;#ol proc tclProc { {stuff "nonsense"} } { set me "up"; puts "me down!"; return $nonsense; } ## *********************************************** Note the ;#ol at the bottom of the list. It is a special flag to denote the end of an ordered list in a comment block -- the list will be indented nicely in the HTML output! Lines in the "Parameter" block will be made into unordered lists. Tags currently supported: * ;#ol Used to declare the end of an ordered list in a comment block, as above. * ;#barecode Used at the beginning of a code block which is NOT contained in a procedure, since the "proc" identifier is normally used to identify Tcl code. * ;#end Declares the end of a ;#barecode block when no subsequent procs will be declared, and thus no "}" will be found in column 0. Note that it is absolutely necessary for the final right curly in a code block to be in column zero. =cut use Carp; use File::Basename; use POSIX qw(strftime); BEGIN{ # define some colors: $red = "#FF0000"; $orange = "#CC6600"; $green = "#339900"; $blue = "#3300FF"; $violet = "#BB00BB"; # regex patterns. here there be dragons! $global_rsc_vars = ' (\$)?::[A-Z0-9_]+'; $ns_var_rx = ' ([\$\{]+)?(::)?[a-z]+(\})?::[a-zA-Z\*]+'; $procnames = ' (operator|emergency|(\$\{)?[a-z]+(\})?::[a-zA-Z2]+|[a-z]+[A-Z2]+[a-zA-Z0-9]+)'; $numbers = ' [-]?\d+(\.\d+)?([eE]([+-])?\d+)?'; $varnames = '\$(\{)?([a-zA-Z0-9\_\-]+)(\})?((\()?(\$)?[a-zA-Z0-9\-\_]+(\))?)?'; $escapes = '\\\$|\\\t|\\\r|\\\n|\\\"|\\\{|\\\}|\\\[|\\\]'; $sect = "
§   §   §
\n"; $reds = "[^a-zA-Z0-9-_\.\>](global|upvar|uplevel|unset|array |set |variable|incr |gets |puts |flush| append|vwait|expr )"; $blues = "[^a-zA-Z0-9-_\.\>](case|default |elseif|else |if |then|return |switch|while|foreach|break|continue|catch |source |eval |exec |system|socket |interp )"; $greens = "[^a-zA-Z0-9-_\.\>](polygon|fill|outline|format|image|wm |linsert|lindex|lsort|llength|lappend|lreplace|lrange|concat |list )"; $violets = "[^a-zA-Z0-9-_\.\>](scale |destroy |open |close |read )"; $oranges = "[^a-zA-Z0-9-_\.\>](winfo|clock|clicks|fileevent|fconfigure|info |string |regexp |pack |place |grid |file )"; $bolds = "[^a-zA-Z0-9-_\.\>](upvar|global|uplevel|namespace|fileevent|fconfigure|source |eval |exec |system|socket |interp |expr )"; } # END OF BEGIN BLOCK $outdir="."; while ($infile = shift @ARGV){ if ( $infile =~ /^-o(.*)$/ ) { $outdir = $1; next; } $i = 0; # open it or complain mightily: open (infid, $infile) or croak "can't find file: $infile\n"; ($base, $dir, $ext) = fileparse($infile); $date = strftime "%m/%d/%Y", localtime; $title = "The $base Script"; $base =~ s/\.//g; $outfile = "$outdir/$base.html"; open (outfid, "> $outfile") or croak "can't open file: $outfile\n"; # print the HEAD block, etc. print outfid "\n\n\n$title\n\n\n\n\n\"LDAS\n
\n\"TclDOC\n
\n

\n$title\n

\n

Modification Date: $date

\n"; while(){ $block = "proc"; #initially assume we are in a code block /^##/ && ( $block = "comment" ); #double hashes define a comment s/^##(\s)(\*+)?//; #strip those nasty double hashes s//\>/g; #finish defanging /^( +)?$/ && next; #toss blank lines s/( +)$//g; #strip trailing whitespace #handle the "hash-bang" line, etc. /^#!.+|^# \\$|^exec .+sh \"\$0\" \$\{1\+\"\$\@\"\}$/ && {$stuff=$stuff."
$_
\n" and next}; if ( $block eq "comment" ){ #handle the name line specially /(Name:[\s]+)(.+)/ && {$stuff=$stuff."
\n" and $toc[$i++]=$2}; #find tcl source code file references to link to. #smarter patterns can be used here!! #s/ LDASgwrap/ LDASgwrap<\/a>/g; s/ (([a-zA-Z_]+)\.tcl)/ $1<\/a>/g; #s/ (([a-zA-Z]+)\.rsc)/ $1<\/a>/g; #find things that look like proc names (mixed case words). s/$procnames/$&<\/i>/g; #s/$ns_var_rx/$&<\/i>/g; #find ordered lists s/^( +)?1\.// && {$stuff=$stuff."
    \n
  1. $_\n" and next}; #find ordered list items >1 s/^( +)?\d+\.// && {$stuff=$stuff."
  2. $_\n" and next}; #find ;#ol tags indicating the end of ordered lists /^( +)?;#ol( +)?/ && {$stuff=$stuff."
\n" and next}; #set a flag fo the usage section /Parameters:$/ && {$params=1}; /Usage:$/ && {$usage=1}; /Usage:$/ && {$params=0}; /Comments:$/ && {$comment=1}; /Comments:$/ && {$usage=0}; #handle a comment section heading /(Name|Description)\:.*/ && {$stuff=$stuff."
\n$&\n
\n" and next}; /Parameters:$/ && {$stuff=$stuff."
\n$&\n
    \n" and next}; /Usage:$/ && {$stuff=$stuff."
\n$&\n
\n
" and next};
        /Comments:$/ && {$stuff=$stuff."
\n$&\n
\n" and next}; #handle a unordered list casually /^( +)?\*/ && {$_="
\n".$_}; #make the ul entry for a param item $params && {$_="
  • $_"}; $stuff=$stuff."$_"; #special line breaking conditionals /[\.\!\?\)\:]( +)?$/ && {$stuff=$stuff."
    \n"}; next; } if ( $block eq "proc" ){ #handle the special ;#barecode tag /^( +)?;#barecode( +)?/ && {$stuff=$stuff."
    \n" and next};
            #preformat tag the proc
            if (/^proc/o){ 
            s/$procnames/$&<\/b>/g;
            #s/$ns_var_rx/$&<\/b>/g;
            $stuff=$stuff."
    \n$_";
            next;
            }
            #find the final curly of a proc and close preformatting
            /^\}( +)?$/o 
            && {$stuff=$stuff."$_\n
    \n$sect" and next}; #handle an ;#end tag /^;#end( +)?$/o && {$stuff=$stuff."\n
    \n$sect" and next}; #deal with a line consisting solely of a comment /^( +)?\;\#/o && {$stuff=$stuff."$_" and next}; #line continuation backslashes s/(\\)\s*$/\\<\/font>\n/g; #block delineating braces s/^(\s*)(\})/$1$2<\/font>/g; s/(\{)\s*$/$1<\/font>\n/g; #special handling of quoted strings s/(\\)?\".+\"/$&<\/font>/g; #don't do syntax highlighting in embedded comments! $comment=""; /(.+)(;.+)/o && {$_=$1 and $comment="$2\n"}; #various syntax highlighting rules s/ -[a-zA-Z]+/$&<\/font>/g; s/$procnames/$&<\/b>/g; #s/$ns_var_rx/$&<\/b>/g; s/$bolds/$&<\/b>/g; s/$global_rsc_vars/$&<\/font><\/b>/g; s/$oranges/$&<\/font>/g; s/$numbers/$&<\/font>/g; s/$varnames/$&<\/font>/g; s/$reds/$&<\/font>/g; s/$blues/$&<\/font>/g; s/$greens/$&<\/font>/g; s/$violets/$&<\/font>/g; s/^\s*(frame|menu|label|(check)?button|toplevel|canvas|entry|text) /$&<\/font>/g; s/$escapes/$&<\/font>/g; $stuff=$stuff."$_"."$comment" and next; } } close infid; # initialize the iterator for the toc printing. $i = 1; # set up the table: print outfid "\n\n

    Table of Procedures

    \n\n
    \n"; # dump the toc entries into two columns: foreach (sort @toc) { print outfid "\"red $_
    \n"; if ($i++ == int($#toc/2)+1) {print outfid "
    \n"}; } # lock up the table. print outfid "
    \n

    \n\n\n"; # print all the stuff from the main loop: print outfid $stuff; # print the footer: print outfid "\n

    \n

    \n\"up\nBack to Top\n\"up\n

    \n
    \n\n"; close outfid; $stuff = ""; @toc = (); } #end of while