os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/tools/tcltk-man2html.tcl
First public contribution.
2 # The next line is executed by /bin/sh, but not tcl \
3 exec tclsh8.4 "$0" ${1+"$@"}
5 package require Tcl 8.4
7 # Convert Ousterhout format man pages into highly crosslinked
10 # Along the way detect many unmatched font changes and other odd
13 # Note well, this program is a hack rather than a piece of software
14 # engineering. In that sense it's probably a good example of things
15 # that a scripting language, like Tcl, can do well. It is offered as
16 # an example of how someone might convert a specific set of man pages
17 # into hypertext, not as a general solution to the problem. If you
18 # try to use this, you'll be very much on your own.
20 # Copyright (c) 1995-1997 Roger E. Critchlow Jr
22 # The authors hereby grant permission to use, copy, modify, distribute,
23 # and license this software and its documentation for any purpose, provided
24 # that existing copyright notices are retained in all copies and that this
25 # notice is included verbatim in any distributions. No written agreement,
26 # license, or royalty fee is required for any of the authorized uses.
27 # Modifications to this software may be copyrighted by their authors
28 # and need not follow the licensing terms described here, provided that
29 # the new terms are clearly indicated on the first page of each file where
32 # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
33 # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
34 # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
35 # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
36 # POSSIBILITY OF SUCH DAMAGE.
38 # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
39 # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
40 # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
41 # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
42 # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
46 # May 15, 1995 - initial release
47 # May 16, 1995 - added a back to home link to toplevel table of
49 # May 18, 1995 - broke toplevel table of contents into separate
50 # pages for each section, and broke long table of contents
51 # into a one page for each man page.
52 # Mar 10, 1996 - updated for tcl7.5b3/tk4.1b3
53 # Apr 14, 1996 - incorporated command line parsing from Tom Tromey,
54 # <tromey@creche.cygnus.com> -- thanks Tom.
55 # - updated for tcl7.5/tk4.1 final release.
56 # - converted to same copyright as the man pages.
57 # Sep 14, 1996 - made various modifications for tcl7.6b1/tk4.2b1
58 # Oct 18, 1996 - added tcl7.6/tk4.2 to the list of distributions.
59 # Oct 22, 1996 - major hacking on indentation code and elsewhere.
61 # May 28, 1997 - added tcl8.0b1/tk8.0b1 to the list of distributions
62 # - cleaned source for tclsh8.0 execution
63 # - renamed output files for windoze installation
64 # - added spaces to tables
65 # Oct 24, 1997 - moved from 8.0b1 to 8.0 release
70 proc parse_command_line {} {
73 # These variables determine where the man pages come from and where
74 # the converted pages go to.
75 global tcltkdir tkdir tcldir webdir build_tcl build_tk
77 # Set defaults based on original code.
84 # Default search version is a glob pattern
85 set useversion {{,[8-9].[0-9]{,.[0-9]{,[0-9]}}}}
87 # Handle arguments a la GNU:
89 # --useversion=<version>
94 foreach option $argv {
95 switch -glob -- $option {
97 puts "tcltk-man-html $Version"
102 puts "usage: tcltk-man-html \[OPTION\] ...\n"
103 puts " --help print this help, then exit"
104 puts " --version print version number, then exit"
105 puts " --srcdir=DIR find tcl and tk source below DIR"
106 puts " --htmldir=DIR put generated HTML in DIR"
107 puts " --tcl build tcl help"
108 puts " --tk build tk help"
109 puts " --useversion version of tcl/tk to search for"
114 # length of "--srcdir=" is 9.
115 set tcltkdir [string range $option 9 end]
119 # length of "--htmldir=" is 10
120 set webdir [string range $option 10 end]
124 # length of "--useversion=" is 13
125 set useversion [string range $option 13 end]
137 puts stderr "tcltk-man-html: unrecognized option -- `$option'"
143 if {!$build_tcl && !$build_tk} {set build_tcl 1; set build_tk 1}
147 set tcldir [lindex [lsort [glob -nocomplain -tails -type d \
148 -directory $tcltkdir tcl$useversion]] end]
149 if {$tcldir == ""} then {
150 puts stderr "tcltk-man-html: couldn't find Tcl below $tcltkdir"
153 puts "using Tcl source directory $tcldir"
158 set tkdir [lindex [lsort [glob -nocomplain -tails -type d \
159 -directory $tcltkdir tk$useversion]] end]
160 if {$tkdir == ""} then {
161 puts stderr "tcltk-man-html: couldn't find Tk below $tcltkdir"
164 puts "using Tk source directory $tkdir"
167 # the title for the man pages overall
170 if {$build_tcl} {append overall_title "[capitalize $tcldir]"}
171 if {$build_tcl && $build_tk} {append overall_title "/"}
172 if {$build_tk} {append overall_title "[capitalize $tkdir]"}
173 append overall_title " Manual"
176 proc capitalize {string} {
177 return [string toupper $string 0]
183 set manual(report-level) 1
185 proc manerror {msg} {
189 if {[info exists manual(name)]} {
190 set name $manual(name)
192 if {[info exists manual(section)] && [string length $manual(section)]} {
193 puts stderr "$name: $manual(section): $msg"
195 puts stderr "$name: $msg"
199 proc manreport {level msg} {
201 if {$level < $manual(report-level)} {
215 return [string map [list \" {}] $arg]
218 proc parse-directive {line codename restname} {
219 upvar $codename code $restname rest
220 return [regexp {^(\.[.a-zA-Z0-9]*) *(.*)} $line all code rest]
223 proc process-text {text} {
226 set text [string map [list \
244 regsub -all {\\o'o\^'} $text {\ô} text; # o-circumflex in re_syntax.n
245 regsub -all {\\-\\\|\\-} $text -- text; # two hyphens
246 regsub -all -- {\\-\\\^\\-} $text -- text; # two hyphens
247 regsub -all {\\-} $text - text; # a hyphen
248 regsub -all "\\\\\n" $text "\\\\n" text; # backslashed newline
249 while {[string first "\\" $text] >= 0} {
251 if {[regsub {^([^\\]*)\\fC([^\\]*)\\fR(.*)$} $text \
252 {\1<TT>\2</TT>\3} text]} continue
254 if {[regsub {^([^\\]*)\\fB([^\\]*)\\fR(.*)$} $text \
255 {\1<B>\2</B>\3} text]} continue
257 if {[regsub {^([^\\]*)\\fB([^\\]*)\\fI(.*)$} $text \
258 {\1<B>\2</B>\\fI\3} text]} continue
260 if {[regsub {^([^\\]*)\\fI([^\\]*)\\fR(.*)$} $text \
261 {\1<I>\2</I>\3} text]} continue
263 if {[regsub {^([^\\]*)\\fI([^\\]*)\\fB(.*)$} $text \
264 {\1<I>\2</I>\\fB\3} text]} continue
266 if {[regsub {^([^\\]*)\\fB([^\\]*)\\fB(.*)$} $text \
268 || [regsub {^([^\\]*)\\fI([^\\]*)\\fI(.*)$} $text \
270 || [regsub {^([^\\]*)\\fR([^\\]*)\\fR(.*)$} $text \
271 {\1\\fR\2\3} ntext]} {
272 manerror "process-text: impotent font change: $text"
277 manerror "process-text: uncaught backslash: $text"
278 set text [string map [list "\\" "#92;"] $text]
283 ## pass 2 text input and matching
287 set manual(text-length) [llength $manual(text)]
288 set manual(text-pointer) 0
292 return [expr {$manual(text-pointer) < $manual(text-length)}]
297 set text [lindex $manual(text) $manual(text-pointer)]
298 incr manual(text-pointer)
301 manerror "read past end of text"
304 proc is-a-directive {line} {
305 return [string match .* $line]
307 proc split-directive {line opname restname} {
308 upvar $opname op $restname rest
309 set op [string range $line 0 2]
310 set rest [string trim [string range $line 3 end]]
312 proc next-op-is {op restname} {
316 set text [lindex $manual(text) $manual(text-pointer)]
317 if {[string equal -length 3 $text $op]} {
318 set rest [string range $text 4 end]
319 incr manual(text-pointer)
325 proc backup-text {n} {
327 if {$manual(text-pointer)-$n >= 0} {
328 incr manual(text-pointer) -$n
331 proc match-text args {
333 set nargs [llength $args]
334 if {$manual(text-pointer) + $nargs > $manual(text-length)} {
343 set arg [string trim $arg]
344 set targ [string trim [lindex $manual(text) $manual(text-pointer)]]
345 if {[string equal $arg $targ]} {
347 incr manual(text-pointer)
350 if {[regexp {^@(\w+)$} $arg all name]} {
354 incr manual(text-pointer)
357 if {[regexp -nocase {^(\.[A-Z][A-Z])@(\w+)$} $arg all op name]\
358 && [string equal $op [lindex $targ 0]]} {
360 set var [lrange $targ 1 end]
362 incr manual(text-pointer)
370 proc expand-next-text {n} {
372 return [join [lrange $manual(text) $manual(text-pointer) \
373 [expr {$manual(text-pointer)+$n-1}]] \n\n]
378 proc man-puts {text} {
380 lappend manual(output-$manual(wing-file)-$manual(name)) $text
384 ## build hypertext links to tables of contents
386 proc long-toc {text} {
388 set here M[incr manual(section-toc-n)]
389 set there L[incr manual(long-toc-n)]
390 lappend manual(section-toc) \
391 "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$text</A>"
392 return "<A NAME=\"$here\">$text</A>"
394 proc option-toc {name class switch} {
396 if {[string equal $manual(section) "WIDGET-SPECIFIC OPTIONS"]} {
397 # link the defined option into the long table of contents
398 set link [long-toc "$switch, $name, $class"]
399 regsub -- "$switch, $name, $class" $link "$switch" link
401 } elseif {[string equal $manual(name):$manual(section) \
402 "options:DESCRIPTION"]} {
403 # link the defined standard option to the long table of
404 # contents and make a target for the standard option references
405 # from other man pages.
406 set first [lindex $switch 0]
408 set there L[incr manual(long-toc-n)]
409 set manual(standard-option-$first) "<A HREF=\"$manual(name).htm#$here\">$switch, $name, $class</A>"
410 lappend manual(section-toc) "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$switch, $name, $class</A>"
411 return "<A NAME=\"$here\">$switch</A>"
413 error "option-toc in $manual(name) section $manual(section)"
416 proc std-option-toc {name} {
418 if {[info exists manual(standard-option-$name)]} {
419 lappend manual(section-toc) <DD>$manual(standard-option-$name)
420 return $manual(standard-option-$name)
422 set here M[incr manual(section-toc-n)]
423 set there L[incr manual(long-toc-n)]
425 lappend manual(section-toc) "<DD><A HREF=\"options.htm#$other\">$name</A>"
426 return "<A HREF=\"options.htm#$other\">$name</A>"
429 ## process the widget option section
430 ## in widget and options man pages
432 proc output-widget-options {rest} {
435 lappend manual(section-toc) <DL>
438 while {[next-op-is .OP rest]} {
439 switch -exact [llength $rest] {
440 3 { foreach {switch name class} $rest { break } }
442 set switch [lrange $rest 0 2]
443 set name [lindex $rest 3]
444 set class [lindex $rest 4]
447 fatal "bad .OP $rest"
450 if {![regexp {^(<.>)([-\w ]+)(</.>)$} $switch all oswitch switch cswitch]} {
451 if {![regexp {^(<.>)([-\w ]+) or ([-\w ]+)(</.>)$} $switch all oswitch switch1 switch2 cswitch]} {
452 error "not Switch: $switch"
454 set switch "$switch1$cswitch or $oswitch$switch2"
457 if {![regexp {^(<.>)([\w]*)(</.>)$} $name all oname name cname]} {
458 error "not Name: $name"
460 if {![regexp {^(<.>)([\w]*)(</.>)$} $class all oclass class cclass]} {
461 error "not Class: $class"
463 man-puts "$para<DT>Command-Line Name: $oswitch[option-toc $name $class $switch]$cswitch"
464 man-puts "<DT>Database Name: $oname$name$cname"
465 man-puts "<DT>Database Class: $oclass$class$cclass"
466 man-puts <DD>[next-text]
470 lappend manual(section-toc) </DL>
476 proc output-RS-list {} {
478 if {[next-op-is .IP rest]} {
479 output-IP-list .RS .IP $rest
480 if {[match-text .RE .sp .RS @rest .IP @rest2]} {
482 output-IP-list .RS .IP $rest2
484 if {[match-text .RE .sp .RS @rest .RE]} {
488 if {[next-op-is .RE rest]} {
493 while {[more-text]} {
495 if {[is-a-directive $line]} {
496 split-directive $line code rest
497 switch -exact $code {
502 manerror "unbalanced .RS at section end"
507 output-directive $line
518 ## process .IP lists which may be plain indents,
519 ## numeric lists, or definition lists
521 proc output-IP-list {context code rest} {
523 if {![string length $rest]} {
524 # blank label, plain indent, no contents entry
526 while {[more-text]} {
528 if {[is-a-directive $line]} {
529 split-directive $line code rest
530 if {[string equal $code ".IP"] && [string equal $rest {}]} {
534 if {[lsearch {.br .DS .RS} $code] >= 0} {
535 output-directive $line
546 # labelled list, make contents
548 [string compare $context ".SH"] &&
549 [string compare $context ".SS"]
554 lappend manual(section-toc) <DL>
558 while {[more-text]} {
560 if {[is-a-directive $line]} {
561 split-directive $line code rest
562 switch -exact $code {
565 output-IP-list .IP $code $rest
568 if {[string equal $manual(section) "ARGUMENTS"] || \
569 [regexp {^\[\d+\]$} $rest]} {
570 man-puts "$para<DT>$rest<DD>"
571 } elseif {[string equal {•} $rest]} {
572 man-puts "$para<DT><DD>$rest "
574 man-puts "$para<DT>[long-toc $rest]<DD>"
576 if {[string equal $manual(name):$manual(section) \
577 "selection:DESCRIPTION"]} {
578 if {[match-text .RE @rest .RS .RS]} {
579 man-puts <DT>[long-toc $rest]<DD>
587 output-directive $line
590 if {[match-text .RS]} {
591 output-directive $line
593 } elseif {[match-text .CS]} {
596 } elseif {[match-text .PP]} {
599 } elseif {[match-text .DS]} {
603 output-directive $line
607 if {[match-text @rest1 .br @rest2 .RS]} {
608 # yet another nroff kludge as above
609 man-puts "$para<DT>[long-toc $rest1]"
610 man-puts "<DT>[long-toc $rest2]<DD>"
612 } elseif {[match-text @rest .RE]} {
613 # gad, this is getting ridiculous
615 man-puts "</DL><P>$rest<DL>"
623 } elseif {$accept_RE} {
624 output-directive $line
647 man-puts "$para</DL>"
648 lappend manual(section-toc) </DL>
650 manerror "missing .RE in output-IP-list"
655 ## handle the NAME section lines
656 ## there's only one line in the NAME section,
657 ## consisting of a comma separated list of names,
658 ## followed by a hyphen and a short description.
660 proc output-name {line} {
662 # split name line into pieces
663 regexp {^([^-]+) - (.*)$} $line all head tail
664 # output line to manual page untouched
666 # output line to long table of contents
667 lappend manual(section-toc) <DL><DD>$line</DL>
668 # separate out the names for future reference
669 foreach name [split $head ,] {
670 set name [string trim $name]
671 if {[llength $name] > 1} {
672 manerror "name has a space: {$name}\nfrom: $line"
674 lappend manual(wing-toc) $name
675 lappend manual(name-$name) $manual(wing-file)/$manual(name)
679 ## build a cross-reference link if appropriate
681 proc cross-reference {ref} {
683 if {[string match Tcl_* $ref]} {
685 } elseif {[string match Tk_* $ref]} {
687 } elseif {[string equal $ref "Tcl"]} {
690 set lref [string tolower $ref]
693 ## nothing to reference
695 if {![info exists manual(name-$lref)]} {
696 foreach name {array file history info interp string trace
697 after clipboard grab image option pack place selection tk tkwait update winfo wm} {
698 if {[regexp "^$name \[a-z0-9]*\$" $lref] && \
699 [info exists manual(name-$name)] && \
700 [string compare $manual(tail) "$name.n"]} {
701 return "<A HREF=\"../$manual(name-$name).htm\">$ref</A>"
704 if {[lsearch {stdin stdout stderr end} $lref] >= 0} {
705 # no good place to send these
712 ## would be a self reference
714 foreach name $manual(name-$lref) {
715 if {[lsearch $name $manual(wing-file)/$manual(name)] >= 0} {
720 ## multiple choices for reference
722 if {[llength $manual(name-$lref)] > 1} {
723 set tcl_i [lsearch -glob $manual(name-$lref) *TclCmd*]
724 set tcl_ref [lindex $manual(name-$lref) $tcl_i]
725 set tk_i [lsearch -glob $manual(name-$lref) *TkCmd*]
726 set tk_ref [lindex $manual(name-$lref) $tk_i]
727 if {$tcl_i >= 0 && "$manual(wing-file)" == {TclCmd} \
728 || "$manual(wing-file)" == {TclLib}} {
729 return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
731 if {$tk_i >= 0 && "$manual(wing-file)" == {TkCmd} \
732 || "$manual(wing-file)" == {TkLib}} {
733 return "<A HREF=\"../$tk_ref.htm\">$ref</A>"
735 if {"$lref" == {exit} && "$manual(tail)" == {tclsh.1} && $tcl_i >= 0} {
736 return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
738 puts stderr "multiple cross reference to $ref in $manual(name-$lref) from $manual(wing-file)/$manual(tail)"
742 ## exceptions, sigh, to the rule
744 switch $manual(tail) {
746 if {$lref == {focus}} {
748 set clue [string first command $tail]
749 if {$clue < 0 || $clue > 5} {
753 if {[lsearch {bitmap image text} $lref] >= 0} {
759 if {[lsearch {image} $lref] >= 0} {
764 if {[lsearch {checkbutton radiobutton} $lref] >= 0} {
769 if {[lsearch {bitmap image set} $lref] >= 0} {
774 if {[lsearch {string} $lref] >= 0} {
779 if {[lsearch {text} $lref] >= 0} {
784 if {[lsearch {exec} $lref] >= 0} {
789 if {[lsearch {error continue break} $lref] >= 0} {
794 if {[lsearch {set} $lref] >= 0} {
800 ## return the cross reference
802 return "<A HREF=\"../$manual(name-$lref).htm\">$ref</A>"
805 ## reference generation errors
807 proc reference-error {msg text} {
809 puts stderr "$manual(tail): $msg: {$text}"
813 ## insert as many cross references into this text string as are appropriate
815 proc insert-cross-references {text} {
818 ## we identify cross references by:
820 ## <B>emboldening</B>
823 ## [a-zA-Z0-9]+ manual entry
824 ## and we avoid messing with already anchored text
827 ## find where each item lives
829 array set offset [list \
830 anchor [string first {<A } $text] \
831 end-anchor [string first {</A>} $text] \
832 quote [string first {``} $text] \
833 end-quote [string first {''} $text] \
834 bold [string first {<B>} $text] \
835 end-bold [string first {</B>} $text] \
836 tcl [string first {Tcl_} $text] \
837 tk [string first {Tk_} $text] \
838 Tcl1 [string first {Tcl manual entry} $text] \
839 Tcl2 [string first {Tcl overview manual entry} $text] \
844 foreach name [array names offset] {
845 if {$offset($name) >= 0} {
846 set invert($offset($name)) $name
847 lappend offsets $offset($name)
851 ## if nothing, then we're done.
853 if {![info exists offsets]} {
859 set offsets [lsort -integer $offsets]
861 ## see which we want to use
863 switch -exact $invert([lindex $offsets 0]) {
865 if {$offset(end-anchor) < 0} {
866 return [reference-error {Missing end anchor} $text]
868 set head [string range $text 0 $offset(end-anchor)]
869 set tail [string range $text [expr {$offset(end-anchor)+1}] end]
870 return $head[insert-cross-references $tail]
873 if {$offset(end-quote) < 0} {
874 return [reference-error "Missing end quote" $text]
876 if {$invert([lindex $offsets 1]) == "tk"} {
877 set offsets [lreplace $offsets 1 1]
879 if {$invert([lindex $offsets 1]) == "tcl"} {
880 set offsets [lreplace $offsets 1 1]
882 switch -exact $invert([lindex $offsets 1]) {
884 set head [string range $text 0 [expr {$offset(quote)-1}]]
885 set body [string range $text [expr {$offset(quote)+2}] \
886 [expr {$offset(end-quote)-1}]]
887 set tail [string range $text \
888 [expr {$offset(end-quote)+2}] end]
889 return "$head``[cross-reference $body]''[insert-cross-references $tail]"
893 set head [string range $text \
894 0 [expr {$offset(end-quote)+1}]]
895 set tail [string range $text \
896 [expr {$offset(end-quote)+2}] end]
897 return "$head[insert-cross-references $tail]"
900 return [reference-error "Uncaught quote case" $text]
903 if {$offset(end-bold) < 0} { return $text }
904 if {$invert([lindex $offsets 1]) == "tk"} {
905 set offsets [lreplace $offsets 1 1]
907 if {$invert([lindex $offsets 1]) == "tcl"} {
908 set offsets [lreplace $offsets 1 1]
910 switch -exact $invert([lindex $offsets 1]) {
912 set head [string range $text 0 [expr {$offset(bold)-1}]]
913 set body [string range $text [expr {$offset(bold)+3}] \
914 [expr {$offset(end-bold)-1}]]
915 set tail [string range $text \
916 [expr {$offset(end-bold)+4}] end]
917 return "$head<B>[cross-reference $body]</B>[insert-cross-references $tail]"
920 set head [string range $text \
921 0 [expr {$offset(end-bold)+3}]]
922 set tail [string range $text \
923 [expr {$offset(end-bold)+4}] end]
924 return "$head[insert-cross-references $tail]"
927 return [reference-error "Uncaught bold case" $text]
930 set head [string range $text 0 [expr {$offset(tk)-1}]]
931 set tail [string range $text $offset(tk) end]
932 if {![regexp {^(Tk_\w+)(.*)$} $tail all body tail]} {
933 return [reference-error "Tk regexp failed" $text]
935 return $head[cross-reference $body][insert-cross-references $tail]
938 set head [string range $text 0 [expr {$offset(tcl)-1}]]
939 set tail [string range $text $offset(tcl) end]
940 if {![regexp {^(Tcl_\w+)(.*)$} $tail all body tail]} {
941 return [reference-error {Tcl regexp failed} $text]
943 return $head[cross-reference $body][insert-cross-references $tail]
947 set off [lindex $offsets 0]
948 set head [string range $text 0 [expr {$off-1}]]
950 set tail [string range $text [expr {$off+3}] end]
951 return $head[cross-reference $body][insert-cross-references $tail]
956 return [reference-error "Out of place $invert([lindex $offsets 0])" $text]
961 ## process formatting directives
963 proc output-directive {line} {
965 # process format directive
966 split-directive $line code rest
967 switch -exact $code {
973 # drain any open lists
974 # announce the subject
975 set manual(section) $rest
976 # start our own stack of stuff
977 set manual($manual(name)-$manual(section)) {}
978 lappend manual(has-$manual(section)) $manual(name)
979 if {[string compare .SS $code]} {
980 man-puts "<H3>[long-toc $manual(section)]</H3>"
982 man-puts "<H4>[long-toc $manual(section)]</H4>"
984 # some sections can simply free wheel their way through the text
985 # some sections can be processed in their own loops
986 switch -exact $manual(section) {
988 if {[lsearch {CrtImgType.3 CrtItemType.3 CrtPhImgFmt.3} $manual(tail)] >= 0} {
989 # these manual pages have two NAME sections
990 if {[info exists manual($manual(tail)-NAME)]} {
993 set manual($manual(tail)-NAME) 1
998 if {[is-a-directive $line]} {
1000 output-name [join $names { }]
1003 lappend names [string trim $line]
1008 lappend manual(section-toc) <DL>
1010 if {[next-op-is .nf rest]
1011 || [next-op-is .br rest]
1012 || [next-op-is .fi rest]} {
1015 if {[next-op-is .SH rest]
1016 || [next-op-is .SS rest]
1017 || [next-op-is .BE rest]
1018 || [next-op-is .SO rest]} {
1022 if {[next-op-is .sp rest]} {
1026 set more [next-text]
1027 if {[is-a-directive $more]} {
1028 manerror "in SYNOPSIS found $more"
1032 foreach more [split $more \n] {
1034 if {[lsearch {TclLib TkLib} $manual(wing-file)] < 0} {
1035 lappend manual(section-toc) <DD>$more
1040 lappend manual(section-toc) </DL>
1044 while {[more-text]} {
1045 if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
1049 set more [next-text]
1050 if {[is-a-directive $more]} {
1056 foreach cr [split $more ,] {
1057 set cr [string trim $cr]
1058 if {![regexp {^<B>.*</B>$} $cr]} {
1061 if {[regexp {^<B>(.*)\([13n]\)</B>$} $cr all name]} {
1066 man-puts [join $nmore {, }]
1071 while {[more-text]} {
1072 if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
1076 set more [next-text]
1077 if {[is-a-directive $more]} {
1083 foreach key [split $more ,] {
1084 set key [string trim $key]
1085 lappend manual(keyword-$key) [list $manual(name) $manual(wing-file)/$manual(name).htm]
1086 set initial [string toupper [string index $key 0]]
1087 lappend keys "<A href=\"../Keywords/$initial.htm\#$key\">$key</A>"
1089 man-puts [join $keys {, }]
1094 if {[next-op-is .IP rest]} {
1095 output-IP-list $code .IP $rest
1098 if {[next-op-is .PP rest]} {
1104 if {[match-text @stuff .SE]} {
1105 output-directive {.SH STANDARD OPTIONS}
1107 foreach line [split $stuff \n] {
1108 foreach option [split $line \t] {
1109 lappend opts $option
1113 lappend manual(section-toc) <DL>
1114 foreach option [lsort $opts] {
1115 man-puts "<DT><B>[std-option-toc $option]</B>"
1118 lappend manual(section-toc) </DL>
1120 manerror "unexpected .SO format:\n[expand-next-text 2]"
1124 output-widget-options $rest
1128 output-IP-list .IP .IP $rest
1139 manerror "unexpected .RE"
1147 manerror "unexpected .DE"
1151 if {[next-op-is .ta rest]} {
1154 if {[match-text @stuff .DE]} {
1155 man-puts <PRE>$stuff</PRE>
1156 } elseif {[match-text .fi @ul1 @ul2 .nf @stuff .DE]} {
1157 man-puts "<PRE>[lindex $ul1 1][lindex $ul2 1]\n$stuff</PRE>"
1159 manerror "unexpected .DS format:\n[expand-next-text 2]"
1164 if {[next-op-is .ta rest]} {
1167 if {[match-text @stuff .CE]} {
1168 man-puts <PRE>$stuff</PRE>
1170 manerror "unexpected .CS format:\n[expand-next-text 2]"
1175 manerror "unexpected .CE"
1182 # these are tab stop settings for short tables
1183 switch -exact $manual(name):$manual(section) {
1185 {bind:EVENT TYPES} -
1186 {bind:BINDING SCRIPTS AND SUBSTITUTIONS} -
1188 {expr:MATH FUNCTIONS} -
1189 {history:DESCRIPTION} -
1190 {history:HISTORY REVISION} -
1191 {re_syntax:BRACKET EXPRESSIONS} -
1192 {switch:DESCRIPTION} -
1193 {upvar:DESCRIPTION} {
1197 manerror "ignoring $line"
1202 if {[match-text @more .fi]} {
1203 foreach more [split $more \n] {
1206 } elseif {[match-text .RS @more .RE .fi]} {
1208 foreach more [split $more \n] {
1212 } elseif {[match-text .RS @more .RS @more2 .RE .RE .fi]} {
1214 foreach more [split $more \n] {
1218 foreach more2 [split $more2 \n] {
1222 } elseif {[match-text .RS @more .RS @more2 .RE @more3 .RE .fi]} {
1224 foreach more [split $more \n] {
1228 foreach more2 [split $more2 \n] {
1232 foreach more3 [split $more3 \n] {
1236 } elseif {[match-text .sp .RS @more .RS @more2 .sp .RE .RE .fi]} {
1237 man-puts <P><DL><DD>
1238 foreach more [split $more \n] {
1242 foreach more2 [split $more2 \n] {
1245 man-puts </DL></DL><P>
1246 } elseif {[match-text .RS .sp @more .sp .RE .fi]} {
1247 man-puts <P><DL><DD>
1248 foreach more [split $more \n] {
1253 manerror "ignoring $line"
1257 manerror "ignoring $line"
1263 manerror "ignoring $line"
1266 manerror "unrecognized format directive: $line"
1271 ## merge copyright listings
1273 proc merge-copyrights {l1 l2} {
1274 foreach copyright [concat $l1 $l2] {
1275 if {[regexp {^Copyright +\(c\) +(\d+) +(by +)?(\w.*)$} $copyright all date by who]} {
1276 lappend dates($who) $date
1279 if {[regexp {^Copyright +\(c\) +(\d+)-(\d+) +(by +)?(\w.*)$} $copyright all from to by who]} {
1280 for {set date $from} {$date <= $to} {incr date} {
1281 lappend dates($who) $date
1285 if {[regexp {^Copyright +\(c\) +(\d+), *(\d+) +(by +)?(\w.*)$} $copyright all date1 date2 by who]} {
1286 lappend dates($who) $date1 $date2
1289 puts "oops: $copyright"
1291 foreach who [array names dates] {
1292 set list [lsort $dates($who)]
1293 if {[llength $list] == 1 || [lindex $list 0] == [lrange $list end end]} {
1294 lappend merge "Copyright (c) [lindex $list 0] $who"
1296 lappend merge "Copyright (c) [lindex $list 0]-[lrange $list end end] $who"
1299 return [lsort $merge]
1302 proc makedirhier {dir} {
1303 if {![file isdirectory $dir] && \
1304 [catch {file mkdir $dir} error]} {
1305 return -code error "cannot create directory $dir: $error"
1310 ## foreach of the man directories specified by args
1311 ## convert manpages into hypertext in the directory
1312 ## specified by html.
1314 proc make-man-pages {html args} {
1315 global env manual overall_title tcltkdesc
1317 set manual(short-toc-n) 1
1318 set manual(short-toc-fp) [open $html/contents.htm w]
1319 puts $manual(short-toc-fp) "<HTML><HEAD><TITLE>$overall_title</TITLE></HEAD>"
1320 puts $manual(short-toc-fp) "<BODY><HR><H3>$overall_title</H3><HR><DL>"
1321 set manual(merge-copyrights) {}
1323 if {$arg == ""} {continue}
1324 set manual(wing-glob) [lindex $arg 0]
1325 set manual(wing-name) [lindex $arg 1]
1326 set manual(wing-file) [lindex $arg 2]
1327 set manual(wing-description) [lindex $arg 3]
1328 set manual(wing-copyrights) {}
1329 makedirhier $html/$manual(wing-file)
1330 set manual(wing-toc-fp) [open $html/$manual(wing-file)/contents.htm w]
1332 puts stderr "scanning section $manual(wing-name)"
1333 # put the entry for this section into the short table of contents
1334 puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/contents.htm\">$manual(wing-name)</A><DD>$manual(wing-description)"
1335 # initialize the wing table of contents
1336 puts $manual(wing-toc-fp) "<HTML><HEAD><TITLE>$manual(wing-name) Manual</TITLE></HEAD>"
1337 puts $manual(wing-toc-fp) "<BODY><HR><H3>$manual(wing-name)</H3><HR>"
1338 # initialize the short table of contents for this section
1339 set manual(wing-toc) {}
1340 # initialize the man directory for this section
1341 makedirhier $html/$manual(wing-file)
1342 # initialize the long table of contents for this section
1343 set manual(long-toc-n) 1
1344 # get the manual pages for this section
1345 set manual(pages) [lsort [glob $manual(wing-glob)]]
1346 if {[lsearch -glob $manual(pages) */options.n] >= 0} {
1347 set n [lsearch $manual(pages) */options.n]
1348 set manual(pages) "[lindex $manual(pages) $n] [lreplace $manual(pages) $n $n]"
1350 # set manual(pages) [lrange $manual(pages) 0 5]
1351 foreach manual(page) $manual(pages) {
1353 puts stderr "scanning page $manual(page)"
1354 set manual(tail) [file tail $manual(page)]
1355 set manual(name) [file root $manual(tail)]
1356 set manual(section) {}
1357 if {[lsearch {case pack-old menubar} $manual(name)] >= 0} {
1359 manerror "discarding $manual(name)"
1362 set manual(infp) [open $manual(page)]
1364 set manual(partial-text) {}
1365 foreach p {.RS .DS .CS .SO} {
1368 set manual(stack) {}
1369 set manual(section) {}
1370 set manual(section-toc) {}
1371 set manual(section-toc-n) 1
1372 set manual(copyrights) {}
1373 lappend manual(all-pages) $manual(wing-file)/$manual(tail)
1374 manreport 100 $manual(name)
1375 while {[gets $manual(infp) line] >= 0} {
1377 if {[regexp {^[`'][/\\]} $line]} {
1378 if {[regexp {Copyright \(c\).*$} $line copyright]} {
1379 lappend manual(copyrights) $copyright
1384 if {"$line" == {'}} {
1388 if {[parse-directive $line code rest]} {
1389 switch -exact $code {
1390 .ad - .na - .so - .ne - .AS - .VE - .VS -
1396 if {"$manual(partial-text)" != {}} {
1397 lappend manual(text) [process-text $manual(partial-text)]
1398 set manual(partial-text) {}
1400 switch -exact $code {
1402 if {[llength $rest] == 0} {
1403 gets $manual(infp) rest
1405 lappend manual(text) "$code [unquote $rest]"
1408 lappend manual(text) "$code [unquote $rest]"
1412 lappend manual(text) "$code [unquote $rest]"
1414 .BS - .BE - .br - .fi - .sp -
1416 if {"$rest" != {}} {
1417 manerror "unexpected argument: $line"
1419 lappend manual(text) $code
1422 lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
1425 regexp {^(.*) +\d+$} $rest all rest
1426 lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
1429 while {[is-a-directive [set next [gets $manual(infp)]]]} {
1430 manerror "ignoring $next after .TP"
1432 if {"$next" != {'}} {
1433 lappend manual(text) ".IP [process-text $next]"
1437 lappend manual(text) [concat .OP [process-text \
1438 "\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]]
1442 lappend manual(text) {.PP}
1446 lappend manual(text) $code
1450 lappend manual(text) $code
1454 lappend manual(text) $code
1458 lappend manual(text) $code
1462 lappend manual(text) $code
1466 lappend manual(text) $code
1470 lappend manual(text) $code
1474 lappend manual(text) $code
1477 while {[gets $manual(infp) line] >= 0} {
1478 if {[string match "..*" $line]} {
1484 error "found .. outside of .de"
1487 manerror "unrecognized format directive: $line"
1491 if {$manual(partial-text) == ""} {
1492 set manual(partial-text) $line
1494 append manual(partial-text) \n$line
1498 if {$manual(partial-text) != ""} {
1499 lappend manual(text) [process-text $manual(partial-text)]
1503 if {$manual(.RS) != 0} {
1504 if {$manual(name) != "selection"} {
1505 puts "unbalanced .RS .RE"
1508 if {$manual(.DS) != 0} {
1509 puts "unbalanced .DS .DE"
1511 if {$manual(.CS) != 0} {
1512 puts "unbalanced .CS .CE"
1514 if {$manual(.SO) != 0} {
1515 puts "unbalanced .SO .SE"
1519 if {[next-op-is .HS rest]} {
1520 set manual($manual(name)-title) \
1521 "[lrange $rest 1 end] [lindex $rest 0] manual page"
1522 while {[more-text]} {
1523 set line [next-text]
1524 if {[is-a-directive $line]} {
1525 output-directive $line
1531 foreach copyright $manual(copyrights) {
1532 man-puts "<A HREF=\"../copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1534 man-puts "<A HREF=\"../copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr.</PRE>"
1535 set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)]
1536 } elseif {[next-op-is .TH rest]} {
1537 set manual($manual(name)-title) "[lrange $rest 4 end] - [lindex $rest 0] manual page"
1538 while {[more-text]} {
1539 set line [next-text]
1540 if {[is-a-directive $line]} {
1541 output-directive $line
1547 foreach copyright $manual(copyrights) {
1548 man-puts "<A HREF=\"../copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1550 man-puts "<A HREF=\"../copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr.</PRE>"
1551 set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)]
1553 manerror "no .HS or .TH record found"
1556 # make the long table of contents for this page
1558 set manual(toc-$manual(wing-file)-$manual(name)) [concat <DL> $manual(section-toc) </DL><HR>]
1562 # make the wing table of contents for the section
1565 foreach name $manual(wing-toc) {
1566 if {[string length $name] > $width} {
1567 set width [string length $name]
1570 set perline [expr {120 / $width}]
1571 set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}]
1574 foreach name [lsort $manual(wing-toc)] {
1575 set tail $manual(name-$name)
1576 if {[llength $tail] > 1} {
1577 manerror "$name is defined in more than one file: $tail"
1578 set tail [lindex $tail [expr {[llength $tail]-1}]]
1580 set tail [file tail $tail]
1581 append rows([expr {$n%$nrows}]) \
1582 "<td> <a href=\"$tail.htm\">$name</a>"
1585 puts $manual(wing-toc-fp) <table>
1586 foreach row [lsort -integer [array names rows]] {
1587 puts $manual(wing-toc-fp) <tr>$rows($row)</tr>
1589 puts $manual(wing-toc-fp) </table>
1592 # insert wing copyrights
1594 puts $manual(wing-toc-fp) "<HR><PRE>"
1595 foreach copyright $manual(wing-copyrights) {
1596 puts $manual(wing-toc-fp) "<A HREF=\"../copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1598 puts $manual(wing-toc-fp) "<A HREF=\"../copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr."
1599 puts $manual(wing-toc-fp) "</PRE></BODY></HTML>"
1600 close $manual(wing-toc-fp)
1601 set manual(merge-copyrights) [merge-copyrights $manual(merge-copyrights) $manual(wing-copyrights)]
1605 ## build the keyword index.
1607 proc strcasecmp {a b} { return [string compare -nocase $a $b] }
1608 set keys [lsort -command strcasecmp [array names manual keyword-*]]
1609 makedirhier $html/Keywords
1610 catch {eval file delete -- [glob $html/Keywords/*]}
1611 puts $manual(short-toc-fp) "<DT><A HREF=\"Keywords/contents.htm\">Keywords</A><DD>The keywords from the $tcltkdesc man pages."
1612 set keyfp [open $html/Keywords/contents.htm w]
1613 puts $keyfp "<HTML><HEAD><TITLE>$tcltkdesc Keywords</TITLE></HEAD>"
1614 puts $keyfp "<BODY><HR><H3>$tcltkdesc Keywords</H3><HR><H2>"
1615 foreach a {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
1616 puts $keyfp "<A HREF=\"$a.htm\">$a</A>"
1617 set afp [open $html/Keywords/$a.htm w]
1618 puts $afp "<HTML><HEAD><TITLE>$tcltkdesc Keywords - $a</TITLE></HEAD>"
1619 puts $afp "<BODY><HR><H3>$tcltkdesc Keywords - $a</H3><HR><H2>"
1620 foreach b {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z} {
1621 puts $afp "<A HREF=\"$b.htm\">$b</A>"
1623 puts $afp "</H2><HR><DL>"
1625 if {[string match -nocase "keyword-${a}*" $k]} {
1626 set k [string range $k 8 end]
1627 puts $afp "<DT><A NAME=\"$k\">$k</A><DD>"
1629 foreach man $manual(keyword-$k) {
1630 set name [lindex $man 0]
1631 set file [lindex $man 1]
1632 lappend refs "<A HREF=\"../$file\">$name</A>"
1634 puts $afp [join $refs {, }]
1637 puts $afp "</DL><HR><PRE>"
1638 # insert merged copyrights
1639 foreach copyright $manual(merge-copyrights) {
1640 puts $afp "<A HREF=\"copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1642 puts $afp "<A HREF=\"copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr."
1643 puts $afp "</PRE></BODY></HTML>"
1646 puts $keyfp "</H2><HR><PRE>"
1648 # insert merged copyrights
1649 foreach copyright $manual(merge-copyrights) {
1650 puts $keyfp "<A HREF=\"copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1652 puts $keyfp "<A HREF=\"copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr."
1653 puts $keyfp </PRE><HR></BODY></HTML>
1657 ## finish off short table of contents
1659 puts $manual(short-toc-fp) {<DT><A HREF="http://www.elf.org">Source</A><DD>More information about these man pages.}
1660 puts $manual(short-toc-fp) "</DL><HR><PRE>"
1661 # insert merged copyrights
1662 foreach copyright $manual(merge-copyrights) {
1663 puts $manual(short-toc-fp) "<A HREF=\"copyright.htm\">Copyright</A> © [lrange $copyright 2 end]"
1665 puts $manual(short-toc-fp) "<A HREF=\"copyright.htm\">Copyright</A> © 1995-1997 Roger E. Critchlow Jr."
1666 puts $manual(short-toc-fp) "</PRE></BODY></HTML>"
1667 close $manual(short-toc-fp)
1672 unset manual(section)
1673 foreach path $manual(all-pages) {
1674 set manual(wing-file) [file dirname $path]
1675 set manual(tail) [file tail $path]
1676 set manual(name) [file root $manual(tail)]
1677 set text $manual(output-$manual(wing-file)-$manual(name))
1679 foreach item $text {
1680 incr ntext [llength [split $item \n]]
1683 set toc $manual(toc-$manual(wing-file)-$manual(name))
1686 incr ntoc [llength [split $item \n]]
1689 puts stderr "rescanning page $manual(name) $ntoc/$ntext"
1690 set manual(outfp) [open $html/$manual(wing-file)/$manual(name).htm w]
1691 puts $manual(outfp) "<HTML><HEAD><TITLE>$manual($manual(name)-title)</TITLE></HEAD><BODY>"
1692 if {($ntext > 60) && ($ntoc > 32) || [lsearch {
1693 Hash LinkVar SetVar TraceVar ConfigWidg CrtImgType CrtItemType
1694 CrtPhImgFmt DoOneEvent GetBitmap GetColor GetCursor GetDash
1695 GetJustify GetPixels GetVisual ParseArgv QueueEvent
1696 } $manual(tail)] >= 0} {
1698 puts $manual(outfp) $item
1701 foreach item $text {
1702 puts $manual(outfp) [insert-cross-references $item]
1704 puts $manual(outfp) </BODY></HTML>
1705 close $manual(outfp)
1712 set tcltkdesc ""; set cmdesc ""; set appdir ""
1713 if {$build_tcl} {append tcltkdesc "Tcl"; append cmdesc "Tcl"; append appdir "$tcldir"}
1714 if {$build_tcl && $build_tk} {append tcltkdesc "/"; append cmdesc " and "; append appdir ","}
1715 if {$build_tk} {append tcltkdesc "Tk"; append cmdesc "Tk"; append appdir "$tkdir"}
1717 set usercmddesc "The interpreters which implement $cmdesc."
1718 set tclcmddesc {The commands which the <B>tclsh</B> interpreter implements.}
1719 set tkcmddesc {The additional commands which the <B>wish</B> interpreter implements.}
1720 set tcllibdesc {The C functions which a Tcl extended C program may use.}
1721 set tklibdesc {The additional C functions which a Tk extended C program may use.}
1725 make-man-pages $webdir \
1726 "$tcltkdir/{$appdir}/doc/*.1 \"$tcltkdesc Applications\" UserCmd {$usercmddesc}" \
1727 [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.n {Tcl Commands} TclCmd {$tclcmddesc}" : ""}] \
1728 [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.n {Tk Commands} TkCmd {$tkcmddesc}" : ""}] \
1729 [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.3 {Tcl Library} TclLib {$tcllibdesc}" : ""}] \
1730 [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.3 {Tk Library} TkLib {$tklibdesc}" : ""}]
1732 puts $error\n$errorInfo