tcltk-man2html.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:47k
源码类别:

通讯编程

开发平台:

Visual C++

  1. #!/bin/sh
  2. # The next line is executed by /bin/sh, but not tcl 
  3. exec tclsh8.4 "$0" ${1+"$@"}
  4. package require Tcl 8.4
  5. # Convert Ousterhout format man pages into highly crosslinked
  6. # hypertext.
  7. #
  8. # Along the way detect many unmatched font changes and other odd
  9. # things.
  10. #
  11. # Note well, this program is a hack rather than a piece of software
  12. # engineering.  In that sense it's probably a good example of things
  13. # that a scripting language, like Tcl, can do well.  It is offered as
  14. # an example of how someone might convert a specific set of man pages
  15. # into hypertext, not as a general solution to the problem.  If you
  16. # try to use this, you'll be very much on your own.
  17. #
  18. # Copyright (c) 1995-1997 Roger E. Critchlow Jr
  19. #
  20. # The authors hereby grant permission to use, copy, modify, distribute,
  21. # and license this software and its documentation for any purpose, provided
  22. # that existing copyright notices are retained in all copies and that this
  23. # notice is included verbatim in any distributions. No written agreement,
  24. # license, or royalty fee is required for any of the authorized uses.
  25. # Modifications to this software may be copyrighted by their authors
  26. # and need not follow the licensing terms described here, provided that
  27. # the new terms are clearly indicated on the first page of each file where
  28. # they apply.
  29. # IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
  30. # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  31. # ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
  32. # DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
  33. # POSSIBILITY OF SUCH DAMAGE.
  34. # THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
  35. # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  36. # FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
  37. # IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
  38. # NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
  39. # MODIFICATIONS.
  40. #
  41. # Revisions:
  42. #  May 15, 1995 - initial release
  43. #  May 16, 1995 - added a back to home link to toplevel table of
  44. # contents.
  45. #  May 18, 1995 - broke toplevel table of contents into separate
  46. # pages for each section, and broke long table of contents
  47. # into a one page for each man page.
  48. #  Mar 10, 1996 - updated for tcl7.5b3/tk4.1b3
  49. #  Apr 14, 1996 - incorporated command line parsing from Tom Tromey,
  50. #   <tromey@creche.cygnus.com> -- thanks Tom.
  51. # - updated for tcl7.5/tk4.1 final release.
  52. # - converted to same copyright as the man pages.
  53. #  Sep 14, 1996 - made various modifications for tcl7.6b1/tk4.2b1
  54. #  Oct 18, 1996 - added tcl7.6/tk4.2 to the list of distributions.
  55. #  Oct 22, 1996 - major hacking on indentation code and elsewhere.
  56. #  Mar  4, 1997 - 
  57. #  May 28, 1997 - added tcl8.0b1/tk8.0b1 to the list of distributions
  58. # - cleaned source for tclsh8.0 execution
  59. # - renamed output files for windoze installation
  60. # - added spaces to tables
  61. #  Oct 24, 1997 - moved from 8.0b1 to 8.0 release
  62. #
  63. set Version "0.32"
  64. proc parse_command_line {} {
  65.     global argv Version
  66.     # These variables determine where the man pages come from and where
  67.     # the converted pages go to.
  68.     global tcltkdir tkdir tcldir webdir build_tcl build_tk
  69.     # Set defaults based on original code.
  70.     set tcltkdir ../..
  71.     set tkdir {}
  72.     set tcldir {}
  73.     set webdir ../html
  74.     set build_tcl 0
  75.     set build_tk 0
  76.     # Default search version is a glob pattern
  77.     set useversion {{,[8-9].[0-9]{,.[0-9]{,[0-9]}}}}
  78.     # Handle arguments a la GNU:
  79.     #   --version
  80.     #   --useversion=<version>
  81.     #   --help
  82.     #   --srcdir=/path
  83.     #   --htmldir=/path
  84.     foreach option $argv {
  85. switch -glob -- $option {
  86.     --version {
  87. puts "tcltk-man-html $Version"
  88. exit 0
  89.     }
  90.     --help {
  91. puts "usage: tcltk-man-html [OPTION] ...n"
  92. puts "  --help              print this help, then exit"
  93. puts "  --version           print version number, then exit"
  94. puts "  --srcdir=DIR        find tcl and tk source below DIR"
  95. puts "  --htmldir=DIR       put generated HTML in DIR"
  96. puts "  --tcl               build tcl help"
  97. puts "  --tk                build tk help"
  98. puts "  --useversion        version of tcl/tk to search for"
  99. exit 0
  100.     }
  101.     --srcdir=* {
  102. # length of "--srcdir=" is 9.
  103. set tcltkdir [string range $option 9 end]
  104.     }
  105.     --htmldir=* {
  106. # length of "--htmldir=" is 10
  107. set webdir [string range $option 10 end]
  108.     }
  109.     --useversion=* {
  110. # length of "--useversion=" is 13
  111. set useversion [string range $option 13 end]
  112.     }
  113.     --tcl {
  114. set build_tcl 1
  115.     }
  116.     --tk {
  117. set build_tk 1
  118.     }
  119.     default {
  120. puts stderr "tcltk-man-html: unrecognized option -- `$option'"
  121. exit 1
  122.     }
  123. }
  124.     }
  125.     if {!$build_tcl && !$build_tk} {set build_tcl 1; set build_tk 1}
  126.     if {$build_tcl} {
  127. # Find Tcl.
  128. set tcldir [lindex [lsort [glob -nocomplain -tails -type d 
  129.        -directory $tcltkdir tcl$useversion]] end]
  130. if {$tcldir == ""} then {
  131.     puts stderr "tcltk-man-html: couldn't find Tcl below $tcltkdir"
  132.     exit 1
  133. }
  134. puts "using Tcl source directory $tcldir"
  135.     }
  136.     if {$build_tk} {
  137. # Find Tk.
  138. set tkdir [lindex [lsort [glob -nocomplain -tails -type d 
  139.       -directory $tcltkdir tk$useversion]] end]
  140. if {$tkdir == ""} then {
  141.     puts stderr "tcltk-man-html: couldn't find Tk below $tcltkdir"
  142.     exit 1
  143. }
  144. puts "using Tk source directory $tkdir"
  145.     }
  146.     # the title for the man pages overall
  147.     global overall_title
  148.     set overall_title ""
  149.     if {$build_tcl} {append overall_title "[capitalize $tcldir]"}
  150.     if {$build_tcl && $build_tk} {append overall_title "/"}
  151.     if {$build_tk} {append overall_title "[capitalize $tkdir]"}
  152.     append overall_title " Manual"
  153. }
  154. proc capitalize {string} {
  155.     return [string toupper $string 0]
  156. }
  157. ##
  158. ##
  159. ##
  160. set manual(report-level) 1
  161. proc manerror {msg} {
  162.     global manual
  163.     set name {}
  164.     set subj {}
  165.     if {[info exists manual(name)]} {
  166. set name $manual(name)
  167.     }
  168.     if {[info exists manual(section)] && [string length $manual(section)]} {
  169. puts stderr "$name: $manual(section):  $msg"
  170.     } else {
  171. puts stderr "$name: $msg"
  172.     }
  173. }
  174. proc manreport {level msg} {
  175.     global manual
  176.     if {$level < $manual(report-level)} {
  177. manerror $msg
  178.     }
  179. }
  180. proc fatal {msg} {
  181.     global manual
  182.     manerror $msg
  183.     exit 1
  184. }
  185. ##
  186. ## parsing
  187. ##
  188. proc unquote arg {
  189.     return [string map [list " {}] $arg]
  190. }
  191. proc parse-directive {line codename restname} {
  192.     upvar $codename code $restname rest
  193.     return [regexp {^(.[.a-zA-Z0-9]*) *(.*)} $line all code rest]
  194. }
  195. proc process-text {text} {
  196.     global manual
  197.     # preprocess text
  198.     set text [string map [list 
  199.     {&} "t" 
  200.     {&} {&amp;} 
  201.     {\} {&#92;} 
  202.     {e} {&#92;} 
  203.     { } {&nbsp;} 
  204.     {|} {&nbsp;} 
  205.     {} { } 
  206.     {%} {} 
  207.     "\n" "n" 
  208.     " {&quot;} 
  209.     {<} {&lt;} 
  210.     {>} {&gt;} 
  211.     {(+-} {&#177;} 
  212.     {fP} {fR} 
  213.     {.} . 
  214.     {(bu} {&#8226;} 
  215.     ] $text]
  216.     regsub -all {\o'o^'} $text {&ocirc;} text; # o-circumflex in re_syntax.n
  217.     regsub -all {\-\|\-} $text -- text; # two hyphens
  218.     regsub -all -- {\-\^\-} $text -- text; # two hyphens
  219.     regsub -all {\-} $text - text; # a hyphen
  220.     regsub -all "\\n" $text "\&#92;n" text; # backslashed newline
  221.     while {[string first "\" $text] >= 0} {
  222. # C R
  223. if {[regsub {^([^\]*)\fC([^\]*)\fR(.*)$} $text 
  224. {1<TT>2</TT>3} text]} continue
  225. # B R
  226. if {[regsub {^([^\]*)\fB([^\]*)\fR(.*)$} $text 
  227. {1<B>2</B>3} text]} continue
  228. # B I
  229. if {[regsub {^([^\]*)\fB([^\]*)\fI(.*)$} $text 
  230. {1<B>2</B>\fI3} text]} continue
  231. # I R
  232. if {[regsub {^([^\]*)\fI([^\]*)\fR(.*)$} $text 
  233. {1<I>2</I>3} text]} continue
  234. # I B
  235. if {[regsub {^([^\]*)\fI([^\]*)\fB(.*)$} $text 
  236. {1<I>2</I>\fB3} text]} continue
  237. # B B, I I, R R
  238. if {[regsub {^([^\]*)\fB([^\]*)\fB(.*)$} $text 
  239. {1\fB23} ntext]
  240.     || [regsub {^([^\]*)\fI([^\]*)\fI(.*)$} $text 
  241.     {1\fI23} ntext]
  242.     || [regsub {^([^\]*)\fR([^\]*)\fR(.*)$} $text 
  243.     {1\fR23} ntext]} {
  244.     manerror "process-text: impotent font change: $text"
  245.     set text $ntext
  246.     continue
  247. }
  248. # unrecognized
  249. manerror "process-text: uncaught backslash: $text"
  250. set text [string map [list "\" "#92;"] $text]
  251.     }
  252.     return $text
  253. }
  254. ##
  255. ## pass 2 text input and matching
  256. ##
  257. proc open-text {} {
  258.     global manual
  259.     set manual(text-length) [llength $manual(text)]
  260.     set manual(text-pointer) 0
  261. }
  262. proc more-text {} {
  263.     global manual
  264.     return [expr {$manual(text-pointer) < $manual(text-length)}]
  265. }
  266. proc next-text {} {
  267.     global manual
  268.     if {[more-text]} {
  269. set text [lindex $manual(text) $manual(text-pointer)]
  270. incr manual(text-pointer)
  271. return $text
  272.     }
  273.     manerror "read past end of text"
  274.     error "fatal"
  275. }
  276. proc is-a-directive {line} {
  277.     return [string match .* $line]
  278. }
  279. proc split-directive {line opname restname} {
  280.     upvar $opname op $restname rest
  281.     set op [string range $line 0 2]
  282.     set rest [string trim [string range $line 3 end]]
  283. }
  284. proc next-op-is {op restname} {
  285.     global manual
  286.     upvar $restname rest
  287.     if {[more-text]} {
  288. set text [lindex $manual(text) $manual(text-pointer)]
  289. if {[string equal -length 3 $text $op]} {
  290.     set rest [string range $text 4 end]
  291.     incr manual(text-pointer)
  292.     return 1
  293. }
  294.     }
  295.     return 0
  296. }
  297. proc backup-text {n} {
  298.     global manual
  299.     if {$manual(text-pointer)-$n >= 0} {
  300. incr manual(text-pointer) -$n
  301.     }
  302. }
  303. proc match-text args {
  304.     global manual
  305.     set nargs [llength $args]
  306.     if {$manual(text-pointer) + $nargs > $manual(text-length)} {
  307. return 0
  308.     }
  309.     set nback 0
  310.     foreach arg $args {
  311. if {![more-text]} {
  312.     backup-text $nback
  313.     return 0
  314. }
  315. set arg [string trim $arg]
  316. set targ [string trim [lindex $manual(text) $manual(text-pointer)]]
  317. if {[string equal $arg $targ]} {
  318.     incr nback
  319.     incr manual(text-pointer)
  320.     continue
  321. }
  322. if {[regexp {^@(w+)$} $arg all name]} {
  323.     upvar $name var
  324.     set var $targ
  325.     incr nback
  326.     incr manual(text-pointer)
  327.     continue
  328. }
  329. if {[regexp -nocase {^(.[A-Z][A-Z])@(w+)$} $arg all op name]
  330. && [string equal $op [lindex $targ 0]]} {
  331.     upvar $name var
  332.     set var [lrange $targ 1 end]
  333.     incr nback
  334.     incr manual(text-pointer)
  335.     continue
  336. }
  337. backup-text $nback
  338. return 0
  339.     }
  340.     return 1
  341. }
  342. proc expand-next-text {n} {
  343.     global manual
  344.     return [join [lrange $manual(text) $manual(text-pointer) 
  345.     [expr {$manual(text-pointer)+$n-1}]] nn]
  346. }
  347. ##
  348. ## pass 2 output
  349. ##
  350. proc man-puts {text} {
  351.     global manual
  352.     lappend manual(output-$manual(wing-file)-$manual(name)) $text
  353. }
  354. ##
  355. ## build hypertext links to tables of contents
  356. ##
  357. proc long-toc {text} {
  358.     global manual
  359.     set here M[incr manual(section-toc-n)]
  360.     set there L[incr manual(long-toc-n)]
  361.     lappend manual(section-toc) 
  362.     "<DD><A HREF="$manual(name).htm#$here" NAME="$there">$text</A>"
  363.     return "<A NAME="$here">$text</A>"
  364. }
  365. proc option-toc {name class switch} {
  366.     global manual
  367.     if {[string equal $manual(section) "WIDGET-SPECIFIC OPTIONS"]} {
  368. # link the defined option into the long table of contents
  369. set link [long-toc "$switch, $name, $class"]
  370. regsub -- "$switch, $name, $class" $link "$switch" link
  371. return $link
  372.     } elseif {[string equal $manual(name):$manual(section) 
  373.     "options:DESCRIPTION"]} {
  374. # link the defined standard option to the long table of
  375. # contents and make a target for the standard option references
  376. # from other man pages.
  377. set first [lindex $switch 0]
  378. set here M$first
  379. set there L[incr manual(long-toc-n)]
  380. set manual(standard-option-$first) "<A HREF="$manual(name).htm#$here">$switch, $name, $class</A>"
  381. lappend manual(section-toc) "<DD><A HREF="$manual(name).htm#$here" NAME="$there">$switch, $name, $class</A>"
  382. return "<A NAME="$here">$switch</A>"
  383.     } else {
  384. error "option-toc in $manual(name) section $manual(section)"
  385.     }
  386. }
  387. proc std-option-toc {name} {
  388.     global manual
  389.     if {[info exists manual(standard-option-$name)]} {
  390. lappend manual(section-toc) <DD>$manual(standard-option-$name)
  391. return $manual(standard-option-$name)
  392.     }
  393.     set here M[incr manual(section-toc-n)]
  394.     set there L[incr manual(long-toc-n)]
  395.     set other M$name
  396.     lappend manual(section-toc) "<DD><A HREF="options.htm#$other">$name</A>"
  397.     return "<A HREF="options.htm#$other">$name</A>"
  398. }
  399. ##
  400. ## process the widget option section
  401. ## in widget and options man pages
  402. ##
  403. proc output-widget-options {rest} {
  404.     global manual
  405.     man-puts <DL>
  406.     lappend manual(section-toc) <DL>
  407.     backup-text 1
  408.     set para {}
  409.     while {[next-op-is .OP rest]} {
  410. switch -exact [llength $rest] {
  411.     3 { foreach {switch name class} $rest { break } }
  412.     5 {
  413. set switch [lrange $rest 0 2]
  414. set name [lindex $rest 3]
  415. set class [lindex $rest 4]
  416.     }
  417.     default {
  418. fatal "bad .OP $rest"
  419.     }
  420. }
  421. if {![regexp {^(<.>)([-w ]+)(</.>)$} $switch all oswitch switch cswitch]} {
  422.     if {![regexp {^(<.>)([-w ]+) or ([-w ]+)(</.>)$} $switch all oswitch switch1 switch2 cswitch]} {
  423. error "not Switch: $switch"
  424.     } else {
  425. set switch "$switch1$cswitch or $oswitch$switch2"
  426.     }
  427. }
  428. if {![regexp {^(<.>)([w]*)(</.>)$} $name all oname name cname]} {
  429.     error "not Name: $name"
  430. }
  431. if {![regexp {^(<.>)([w]*)(</.>)$} $class all oclass class cclass]} {
  432.     error "not Class: $class"
  433. }
  434. man-puts "$para<DT>Command-Line Name: $oswitch[option-toc $name $class $switch]$cswitch"
  435. man-puts "<DT>Database Name: $oname$name$cname"
  436. man-puts "<DT>Database Class: $oclass$class$cclass"
  437. man-puts <DD>[next-text]
  438. set para <P>
  439.     }
  440.     man-puts </DL>
  441.     lappend manual(section-toc) </DL>
  442. }
  443. ##
  444. ## process .RS lists
  445. ##
  446. proc output-RS-list {} {
  447.     global manual
  448.     if {[next-op-is .IP rest]} {
  449. output-IP-list .RS .IP $rest
  450. if {[match-text .RE .sp .RS @rest .IP @rest2]} {
  451.     man-puts <P>$rest
  452.     output-IP-list .RS .IP $rest2
  453. }
  454. if {[match-text .RE .sp .RS @rest .RE]} {
  455.     man-puts <P>$rest
  456.     return
  457. }
  458. if {[next-op-is .RE rest]} {
  459.     return
  460. }
  461.     }
  462.     man-puts <DL><DD>
  463.     while {[more-text]} {
  464. set line [next-text]
  465. if {[is-a-directive $line]} {
  466.     split-directive $line code rest
  467.     switch -exact $code {
  468. .RE {
  469.     break
  470. }
  471. .SH - .SS {
  472.     manerror "unbalanced .RS at section end"
  473.     backup-text 1
  474.     break
  475. }
  476. default {
  477.     output-directive $line
  478. }
  479.     }
  480. } else {
  481.     man-puts $line
  482. }
  483.     }
  484.     man-puts </DL>
  485. }
  486. ##
  487. ## process .IP lists which may be plain indents,
  488. ## numeric lists, or definition lists
  489. ##
  490. proc output-IP-list {context code rest} {
  491.     global manual
  492.     if {![string length $rest]} {
  493. # blank label, plain indent, no contents entry
  494. man-puts <DL><DD>
  495. while {[more-text]} {
  496.     set line [next-text]
  497.     if {[is-a-directive $line]} {
  498. split-directive $line code rest
  499. if {[string equal $code ".IP"] && [string equal $rest {}]} {
  500.     man-puts "<P>"
  501.     continue
  502. }
  503. if {[lsearch {.br .DS .RS} $code] >= 0} {
  504.     output-directive $line
  505. } else {
  506.     backup-text 1
  507.     break
  508. }
  509.     } else {
  510. man-puts $line
  511.     }
  512. }
  513. man-puts </DL>
  514.     } else {
  515. # labelled list, make contents
  516. if {
  517.     [string compare $context ".SH"] &&
  518.     [string compare $context ".SS"]
  519. } then {
  520.     man-puts <P>
  521. }
  522. man-puts <DL>
  523. lappend manual(section-toc) <DL>
  524. backup-text 1
  525. set accept_RE 0
  526. set para {}
  527. while {[more-text]} {
  528.     set line [next-text]
  529.     if {[is-a-directive $line]} {
  530. split-directive $line code rest
  531. switch -exact $code {
  532.     .IP {
  533. if {$accept_RE} {
  534.     output-IP-list .IP $code $rest
  535.     continue
  536. }
  537. if {[string equal $manual(section) "ARGUMENTS"] || 
  538. [regexp {^[d+]$} $rest]} {
  539.     man-puts "$para<DT>$rest<DD>"
  540. } elseif {[string equal {&#8226;} $rest]} {
  541.    man-puts "$para<DT><DD>$rest&nbsp;"
  542. } else {
  543.     man-puts "$para<DT>[long-toc $rest]<DD>"
  544. }
  545. if {[string equal $manual(name):$manual(section) 
  546. "selection:DESCRIPTION"]} {
  547.     if {[match-text .RE @rest .RS .RS]} {
  548. man-puts <DT>[long-toc $rest]<DD>
  549.     }
  550. }
  551.     }
  552.     .sp -
  553.     .br -
  554.     .DS -
  555.     .CS {
  556. output-directive $line
  557.     }
  558.     .RS {
  559. if {[match-text .RS]} {
  560.     output-directive $line
  561.     incr accept_RE 1
  562. } elseif {[match-text .CS]} {
  563.     output-directive .CS
  564.     incr accept_RE 1
  565. } elseif {[match-text .PP]} {
  566.     output-directive .PP
  567.     incr accept_RE 1
  568. } elseif {[match-text .DS]} {
  569.     output-directive .DS
  570.     incr accept_RE 1
  571. } else {
  572.     output-directive $line
  573. }
  574.     }
  575.     .PP {
  576. if {[match-text @rest1 .br @rest2 .RS]} {
  577.     # yet another nroff kludge as above
  578.     man-puts "$para<DT>[long-toc $rest1]"
  579.     man-puts "<DT>[long-toc $rest2]<DD>"
  580.     incr accept_RE 1
  581. } elseif {[match-text @rest .RE]} {
  582.     # gad, this is getting ridiculous
  583.     if {!$accept_RE} {
  584. man-puts "</DL><P>$rest<DL>"
  585. backup-text 1
  586. set para {}
  587. break
  588.     } else {
  589. man-puts "<P>$rest"
  590. incr accept_RE -1
  591.     }
  592. } elseif {$accept_RE} {
  593.     output-directive $line
  594. } else {
  595.     backup-text 1
  596.     break
  597. }
  598.     }
  599.     .RE {
  600. if {!$accept_RE} {
  601.     backup-text 1
  602.     break
  603. }
  604. incr accept_RE -1
  605.     }
  606.     default {
  607. backup-text 1
  608. break
  609.     }
  610. }
  611.     } else {
  612. man-puts $line
  613.     }
  614.     set para <P>
  615. }
  616. man-puts "$para</DL>"
  617. lappend manual(section-toc) </DL>
  618. if {$accept_RE} {
  619.     manerror "missing .RE in output-IP-list"
  620. }
  621.     }
  622. }
  623. ##
  624. ## handle the NAME section lines
  625. ## there's only one line in the NAME section,
  626. ## consisting of a comma separated list of names,
  627. ## followed by a hyphen and a short description.
  628. ##
  629. proc output-name {line} {
  630.     global manual
  631.     # split name line into pieces
  632.     regexp {^([^-]+) - (.*)$} $line all head tail
  633.     # output line to manual page untouched
  634.     man-puts $line
  635.     # output line to long table of contents
  636.     lappend manual(section-toc) <DL><DD>$line</DL>
  637.     # separate out the names for future reference
  638.     foreach name [split $head ,] {
  639. set name [string trim $name]
  640. if {[llength $name] > 1} {
  641.     manerror "name has a space: {$name}nfrom: $line"
  642. }
  643. lappend manual(wing-toc) $name
  644. lappend manual(name-$name) $manual(wing-file)/$manual(name)
  645.     }
  646. }
  647. ##
  648. ## build a cross-reference link if appropriate
  649. ##
  650. proc cross-reference {ref} {
  651.     global manual
  652.     if {[string match Tcl_* $ref]} {
  653. set lref $ref
  654.     } elseif {[string match Tk_* $ref]} {
  655. set lref $ref
  656.     } elseif {[string equal $ref "Tcl"]} {
  657. set lref $ref
  658.     } else {
  659. set lref [string tolower $ref]
  660.     }
  661.     ##
  662.     ## nothing to reference
  663.     ##
  664.     if {![info exists manual(name-$lref)]} {
  665. foreach name {array file history info interp string trace
  666. after clipboard grab image option pack place selection tk tkwait update winfo wm} {
  667.     if {[regexp "^$name [a-z0-9]*$" $lref] && 
  668.     [info exists manual(name-$name)] && 
  669.     [string compare $manual(tail) "$name.n"]} {
  670. return "<A HREF="../$manual(name-$name).htm">$ref</A>"
  671.     }
  672. }
  673. if {[lsearch {stdin stdout stderr end} $lref] >= 0} {
  674.     # no good place to send these
  675.     # tcl tokens?
  676.     # also end
  677. }
  678. return $ref
  679.     }
  680.     ##
  681.     ## would be a self reference
  682.     ##
  683.     foreach name $manual(name-$lref) {
  684. if {[lsearch $name $manual(wing-file)/$manual(name)] >= 0} {
  685.     return $ref
  686. }
  687.     }
  688.     ##
  689.     ## multiple choices for reference
  690.     ##
  691.     if {[llength $manual(name-$lref)] > 1} {
  692. set tcl_i [lsearch -glob $manual(name-$lref) *TclCmd*]
  693. set tcl_ref [lindex $manual(name-$lref) $tcl_i]
  694. set tk_i [lsearch -glob $manual(name-$lref) *TkCmd*]
  695. set tk_ref [lindex $manual(name-$lref) $tk_i]
  696. if {$tcl_i >= 0 && "$manual(wing-file)" == {TclCmd} 
  697. ||  "$manual(wing-file)" == {TclLib}} {
  698.     return "<A HREF="../$tcl_ref.htm">$ref</A>"
  699. }
  700. if {$tk_i >= 0 && "$manual(wing-file)" == {TkCmd} 
  701. || "$manual(wing-file)" == {TkLib}} {
  702.     return "<A HREF="../$tk_ref.htm">$ref</A>"
  703. }
  704. if {"$lref" == {exit} && "$manual(tail)" == {tclsh.1} && $tcl_i >= 0} {
  705.     return "<A HREF="../$tcl_ref.htm">$ref</A>"
  706. }
  707. puts stderr "multiple cross reference to $ref in $manual(name-$lref) from $manual(wing-file)/$manual(tail)"
  708. return $ref
  709.     }
  710.     ##
  711.     ## exceptions, sigh, to the rule
  712.     ##
  713.     switch $manual(tail) {
  714. canvas.n {
  715.     if {$lref == {focus}} {
  716. upvar tail tail
  717. set clue [string first command $tail]
  718. if {$clue < 0 ||  $clue > 5} {
  719.     return $ref
  720. }
  721.     }
  722.     if {[lsearch {bitmap image text} $lref] >= 0} {
  723. return $ref
  724.     }
  725. }
  726. checkbutton.n -
  727. radiobutton.n {
  728.     if {[lsearch {image} $lref] >= 0} {
  729. return $ref
  730.     }
  731. }
  732. menu.n {
  733.     if {[lsearch {checkbutton radiobutton} $lref] >= 0} {
  734. return $ref
  735.     }
  736. }
  737. options.n {
  738.     if {[lsearch {bitmap image set} $lref] >= 0} {
  739. return $ref
  740.     }
  741. }
  742. regexp.n {
  743.     if {[lsearch {string} $lref] >= 0} {
  744. return $ref
  745.     }
  746. }
  747. source.n {
  748.     if {[lsearch {text} $lref] >= 0} {
  749. return $ref
  750.     }
  751. }
  752. history.n {
  753.     if {[lsearch {exec} $lref] >= 0} {
  754. return $ref
  755.     }
  756. }
  757. return.n {
  758.     if {[lsearch {error continue break} $lref] >= 0} {
  759. return $ref
  760.     }
  761. }
  762. scrollbar.n {
  763.     if {[lsearch {set} $lref] >= 0} {
  764. return $ref
  765.     }
  766. }
  767.     }
  768.     ##
  769.     ## return the cross reference
  770.     ##
  771.     return "<A HREF="../$manual(name-$lref).htm">$ref</A>"
  772. }
  773. ##
  774. ## reference generation errors
  775. ##
  776. proc reference-error {msg text} {
  777.     global manual
  778.     puts stderr "$manual(tail): $msg: {$text}"
  779.     return $text
  780. }
  781. ##
  782. ## insert as many cross references into this text string as are appropriate
  783. ##
  784. proc insert-cross-references {text} {
  785.     global manual
  786.     ##
  787.     ## we identify cross references by:
  788.     ##     ``quotation''
  789.     ##    <B>emboldening</B>
  790.     ##    Tcl_ prefix
  791.     ##    Tk_ prefix
  792.     ##   [a-zA-Z0-9]+ manual entry
  793.     ## and we avoid messing with already anchored text
  794.     ##
  795.     ##
  796.     ## find where each item lives
  797.     ##
  798.     array set offset [list 
  799.     anchor [string first {<A } $text] 
  800.     end-anchor [string first {</A>} $text] 
  801.     quote [string first {``} $text] 
  802.     end-quote [string first {''} $text] 
  803.     bold [string first {<B>} $text] 
  804.     end-bold [string first {</B>} $text] 
  805.     tcl [string first {Tcl_} $text] 
  806.     tk [string first {Tk_} $text] 
  807.     Tcl1 [string first {Tcl manual entry} $text] 
  808.     Tcl2 [string first {Tcl overview manual entry} $text] 
  809.     ]
  810.     ##
  811.     ## accumulate a list
  812.     ##
  813.     foreach name [array names offset] {
  814. if {$offset($name) >= 0} {
  815.     set invert($offset($name)) $name
  816.     lappend offsets $offset($name)
  817. }
  818.     }
  819.     ##
  820.     ## if nothing, then we're done.
  821.     ##
  822.     if {![info exists offsets]} {
  823. return $text
  824.     }
  825.     ##
  826.     ## sort the offsets
  827.     ##
  828.     set offsets [lsort -integer $offsets]
  829.     ##
  830.     ## see which we want to use
  831.     ##
  832.     switch -exact $invert([lindex $offsets 0]) {
  833. anchor {
  834.     if {$offset(end-anchor) < 0} {
  835. return [reference-error {Missing end anchor} $text]
  836.     }
  837.     set head [string range $text 0 $offset(end-anchor)]
  838.     set tail [string range $text [expr {$offset(end-anchor)+1}] end]
  839.     return $head[insert-cross-references $tail]
  840. }
  841. quote {
  842.     if {$offset(end-quote) < 0} {
  843. return [reference-error "Missing end quote" $text]
  844.     }
  845.     if {$invert([lindex $offsets 1]) == "tk"} {
  846. set offsets [lreplace $offsets 1 1]
  847.     }
  848.     if {$invert([lindex $offsets 1]) == "tcl"} {
  849. set offsets [lreplace $offsets 1 1]
  850.     }
  851.     switch -exact $invert([lindex $offsets 1]) {
  852. end-quote {
  853.     set head [string range $text 0 [expr {$offset(quote)-1}]]
  854.     set body [string range $text [expr {$offset(quote)+2}] 
  855.     [expr {$offset(end-quote)-1}]]
  856.     set tail [string range $text 
  857.     [expr {$offset(end-quote)+2}] end]
  858.     return "$head``[cross-reference $body]''[insert-cross-references $tail]"
  859. }
  860. bold -
  861. anchor {
  862.     set head [string range $text 
  863.     0 [expr {$offset(end-quote)+1}]]
  864.     set tail [string range $text 
  865.     [expr {$offset(end-quote)+2}] end]
  866.     return "$head[insert-cross-references $tail]"
  867. }
  868.     }
  869.     return [reference-error "Uncaught quote case" $text]
  870. }
  871. bold {
  872.     if {$offset(end-bold) < 0} { return $text }
  873.     if {$invert([lindex $offsets 1]) == "tk"} {
  874. set offsets [lreplace $offsets 1 1]
  875.     }
  876.     if {$invert([lindex $offsets 1]) == "tcl"} {
  877. set offsets [lreplace $offsets 1 1]
  878.     }
  879.     switch -exact $invert([lindex $offsets 1]) {
  880. end-bold {
  881.     set head [string range $text 0 [expr {$offset(bold)-1}]]
  882.     set body [string range $text [expr {$offset(bold)+3}] 
  883.     [expr {$offset(end-bold)-1}]]
  884.     set tail [string range $text 
  885.     [expr {$offset(end-bold)+4}] end]
  886.     return "$head<B>[cross-reference $body]</B>[insert-cross-references $tail]"
  887. }
  888. anchor {
  889.     set head [string range $text 
  890.     0 [expr {$offset(end-bold)+3}]]
  891.     set tail [string range $text 
  892.     [expr {$offset(end-bold)+4}] end]
  893.     return "$head[insert-cross-references $tail]"
  894. }
  895.     }
  896.     return [reference-error "Uncaught bold case" $text]
  897. }
  898. tk {
  899.     set head [string range $text 0 [expr {$offset(tk)-1}]]
  900.     set tail [string range $text $offset(tk) end]
  901.     if {![regexp {^(Tk_w+)(.*)$} $tail all body tail]} {
  902. return [reference-error "Tk regexp failed" $text]
  903.     }
  904.     return $head[cross-reference $body][insert-cross-references $tail]
  905. }
  906. tcl {
  907.     set head [string range $text 0 [expr {$offset(tcl)-1}]]
  908.     set tail [string range $text $offset(tcl) end]
  909.     if {![regexp {^(Tcl_w+)(.*)$} $tail all body tail]} {
  910. return [reference-error {Tcl regexp failed} $text]
  911.     }
  912.     return $head[cross-reference $body][insert-cross-references $tail]
  913. }
  914. Tcl1 -
  915. Tcl2 {
  916.     set off [lindex $offsets 0]
  917.     set head [string range $text 0 [expr {$off-1}]]
  918.     set body Tcl
  919.     set tail [string range $text [expr {$off+3}] end]
  920.     return $head[cross-reference $body][insert-cross-references $tail]
  921. }
  922. end-anchor -
  923. end-bold -
  924. end-quote {
  925.     return [reference-error "Out of place $invert([lindex $offsets 0])" $text]
  926. }
  927.     }
  928. }
  929. ##
  930. ## process formatting directives
  931. ##
  932. proc output-directive {line} {
  933.     global manual
  934.     # process format directive
  935.     split-directive $line code rest
  936.     switch -exact $code {
  937. .BS -
  938. .BE {
  939.     # man-puts <HR>
  940. }
  941. .SH - .SS {
  942.     # drain any open lists
  943.     # announce the subject
  944.     set manual(section) $rest
  945.     # start our own stack of stuff
  946.     set manual($manual(name)-$manual(section)) {}
  947.     lappend manual(has-$manual(section)) $manual(name)
  948.     if {[string compare .SS $code]} {
  949. man-puts "<H3>[long-toc $manual(section)]</H3>"
  950.     } else {
  951. man-puts "<H4>[long-toc $manual(section)]</H4>"
  952.     }
  953.     # some sections can simply free wheel their way through the text
  954.     # some sections can be processed in their own loops
  955.     switch -exact $manual(section) {
  956. NAME {
  957.     if {[lsearch {CrtImgType.3 CrtItemType.3 CrtPhImgFmt.3} $manual(tail)] >= 0} {
  958. # these manual pages have two NAME sections
  959. if {[info exists manual($manual(tail)-NAME)]} {
  960.     return
  961. }
  962. set manual($manual(tail)-NAME) 1
  963.     }
  964.     set names {}
  965.     while {1} {
  966. set line [next-text]
  967. if {[is-a-directive $line]} {
  968.     backup-text 1
  969.     output-name [join $names { }]
  970.     return
  971. } else {
  972.     lappend names [string trim $line]
  973. }
  974.     }
  975. }
  976. SYNOPSIS {
  977.     lappend manual(section-toc) <DL>
  978.     while {1} {
  979. if {[next-op-is .nf rest]
  980.  || [next-op-is .br rest]
  981.  || [next-op-is .fi rest]} {
  982.     continue
  983. }
  984. if {[next-op-is .SH rest]
  985.          || [next-op-is .SS rest]
  986.          || [next-op-is .BE rest]
  987.  || [next-op-is .SO rest]} {
  988.     backup-text 1
  989.     break
  990. }
  991. if {[next-op-is .sp rest]} {
  992.     #man-puts <P>
  993.     continue
  994. }
  995. set more [next-text]
  996. if {[is-a-directive $more]} {
  997.     manerror "in SYNOPSIS found $more"
  998.     backup-text 1
  999.     break
  1000. } else {
  1001.     foreach more [split $more n] {
  1002. man-puts $more<BR>
  1003. if {[lsearch {TclLib TkLib} $manual(wing-file)] < 0} {
  1004.     lappend manual(section-toc) <DD>$more
  1005. }
  1006.     }
  1007. }
  1008.     }
  1009.     lappend manual(section-toc) </DL>
  1010.     return
  1011. }
  1012. {SEE ALSO} {
  1013.     while {[more-text]} {
  1014. if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
  1015.     backup-text 1
  1016.     return
  1017. }
  1018. set more [next-text]
  1019. if {[is-a-directive $more]} {
  1020.     manerror "$more"
  1021.     backup-text 1
  1022.     return
  1023. }
  1024. set nmore {}
  1025. foreach cr [split $more ,] {
  1026.     set cr [string trim $cr]
  1027.     if {![regexp {^<B>.*</B>$} $cr]} {
  1028. set cr <B>$cr</B>
  1029.     }
  1030.     if {[regexp {^<B>(.*)([13n])</B>$} $cr all name]} {
  1031. set cr <B>$name</B>
  1032.     }
  1033.     lappend nmore $cr
  1034. }
  1035. man-puts [join $nmore {, }]
  1036.     }
  1037.     return
  1038. }
  1039. KEYWORDS {
  1040.     while {[more-text]} {
  1041. if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
  1042.     backup-text 1
  1043.     return
  1044. }
  1045. set more [next-text]
  1046. if {[is-a-directive $more]} {
  1047.     manerror "$more"
  1048.     backup-text 1
  1049.     return
  1050. }
  1051. set keys {}
  1052. foreach key [split $more ,] {
  1053.     set key [string trim $key]
  1054.     lappend manual(keyword-$key) [list $manual(name) $manual(wing-file)/$manual(name).htm]
  1055.     set initial [string toupper [string index $key 0]]
  1056.     lappend keys "<A href="../Keywords/$initial.htm#$key">$key</A>"
  1057. }
  1058. man-puts [join $keys {, }]
  1059.     }
  1060.     return
  1061. }
  1062.     }
  1063.     if {[next-op-is .IP rest]} {
  1064. output-IP-list $code .IP $rest
  1065. return
  1066.     }
  1067.     if {[next-op-is .PP rest]} {
  1068. return
  1069.     }
  1070.     return
  1071. }
  1072. .SO {
  1073.     if {[match-text @stuff .SE]} {
  1074. output-directive {.SH STANDARD OPTIONS}
  1075. set opts {}
  1076. foreach line [split $stuff n] {
  1077.     foreach option [split $line t] {
  1078. lappend opts $option
  1079.     }
  1080. }
  1081. man-puts <DL>
  1082. lappend manual(section-toc) <DL>
  1083. foreach option [lsort $opts] {
  1084.     man-puts "<DT><B>[std-option-toc $option]</B>"
  1085. }
  1086. man-puts </DL>
  1087. lappend manual(section-toc) </DL>
  1088.     } else {
  1089. manerror "unexpected .SO format:n[expand-next-text 2]"
  1090.     }
  1091. }
  1092. .OP {
  1093.     output-widget-options $rest
  1094.     return
  1095. }
  1096. .IP {
  1097.     output-IP-list .IP .IP $rest
  1098.     return
  1099. }
  1100. .PP {
  1101.     man-puts <P>
  1102. }
  1103. .RS {
  1104.     output-RS-list
  1105.     return
  1106. }
  1107. .RE {
  1108.     manerror "unexpected .RE"
  1109.     return
  1110. }
  1111. .br {
  1112.     man-puts <BR>
  1113.     return
  1114. }
  1115. .DE {
  1116.     manerror "unexpected .DE"
  1117.     return
  1118. }
  1119. .DS {
  1120.     if {[next-op-is .ta rest]} {
  1121.     }
  1122.     if {[match-text @stuff .DE]} {
  1123. man-puts <PRE>$stuff</PRE>
  1124.     } elseif {[match-text .fi @ul1 @ul2 .nf @stuff .DE]} {
  1125. man-puts "<PRE>[lindex $ul1 1][lindex $ul2 1]n$stuff</PRE>"
  1126.     } else {
  1127. manerror "unexpected .DS format:n[expand-next-text 2]"
  1128.     }
  1129.     return
  1130. }
  1131. .CS {
  1132.     if {[next-op-is .ta rest]} {
  1133.     }
  1134.     if {[match-text @stuff .CE]} {
  1135. man-puts <PRE>$stuff</PRE>
  1136.     } else {
  1137. manerror "unexpected .CS format:n[expand-next-text 2]"
  1138.     }
  1139.     return
  1140. }
  1141. .CE {
  1142.     manerror "unexpected .CE"
  1143.     return
  1144. }
  1145. .sp {
  1146.     man-puts <P>
  1147. }
  1148. .ta {
  1149.     # these are tab stop settings for short tables
  1150.     switch -exact $manual(name):$manual(section) {
  1151. {bind:MODIFIERS} -
  1152. {bind:EVENT TYPES} -
  1153. {bind:BINDING SCRIPTS AND SUBSTITUTIONS} -
  1154. {expr:OPERANDS} -
  1155. {expr:MATH FUNCTIONS} -
  1156. {history:DESCRIPTION} -
  1157. {history:HISTORY REVISION} -
  1158. {re_syntax:BRACKET EXPRESSIONS} -
  1159. {switch:DESCRIPTION} -
  1160. {upvar:DESCRIPTION} {
  1161.     return; # fix.me
  1162. }
  1163. default {
  1164.     manerror "ignoring $line"
  1165. }
  1166.     }
  1167. }
  1168. .nf {
  1169.     if {[match-text @more .fi]} {
  1170. foreach more [split $more n] {
  1171.     man-puts $more<BR>
  1172. }
  1173.     } elseif {[match-text .RS @more .RE .fi]} {
  1174. man-puts <DL><DD>
  1175. foreach more [split $more n] {
  1176.     man-puts $more<BR>
  1177. }
  1178. man-puts </DL>
  1179.     } elseif {[match-text .RS @more .RS @more2 .RE .RE .fi]} {
  1180. man-puts <DL><DD>
  1181. foreach more [split $more n] {
  1182.     man-puts $more<BR>
  1183. }
  1184. man-puts <DL><DD>
  1185. foreach more2 [split $more2 n] {
  1186.     man-puts $more2<BR>
  1187. }
  1188. man-puts </DL></DL>
  1189.     } elseif {[match-text .RS @more .RS @more2 .RE @more3 .RE .fi]} {
  1190. man-puts <DL><DD>
  1191. foreach more [split $more n] {
  1192.     man-puts $more<BR>
  1193. }
  1194. man-puts <DL><DD>
  1195. foreach more2 [split $more2 n] {
  1196.     man-puts $more2<BR>
  1197. }
  1198. man-puts </DL><DD>
  1199. foreach more3 [split $more3 n] {
  1200.     man-puts $more3<BR>
  1201. }
  1202. man-puts </DL>
  1203.     } elseif {[match-text .sp .RS @more .RS @more2 .sp .RE .RE .fi]} {
  1204. man-puts <P><DL><DD>
  1205. foreach more [split $more n] {
  1206.     man-puts $more<BR>
  1207. }
  1208. man-puts <DL><DD>
  1209. foreach more2 [split $more2 n] {
  1210.     man-puts $more2<BR>
  1211. }
  1212. man-puts </DL></DL><P>
  1213.     } elseif {[match-text .RS .sp @more .sp .RE .fi]} {
  1214. man-puts <P><DL><DD>
  1215. foreach more [split $more n] {
  1216.     man-puts $more<BR>
  1217. }
  1218. man-puts </DL><P>
  1219.     } else {
  1220. manerror "ignoring $line"
  1221.     }
  1222. }
  1223. .fi {
  1224.     manerror "ignoring $line"
  1225. }
  1226. .na -
  1227. .ad -
  1228. .UL -
  1229. .ne {
  1230.     manerror "ignoring $line"
  1231. }
  1232. default {
  1233.     manerror "unrecognized format directive: $line"
  1234. }
  1235.     }
  1236. }
  1237. ##
  1238. ## merge copyright listings
  1239. ## 
  1240. proc merge-copyrights {l1 l2} {
  1241.     foreach copyright [concat $l1 $l2] {
  1242. if {[regexp {^Copyright +(c) +(d+) +(by +)?(w.*)$} $copyright all date by who]} {
  1243.     lappend dates($who) $date
  1244.     continue
  1245. }
  1246. if {[regexp {^Copyright +(c) +(d+)-(d+) +(by +)?(w.*)$} $copyright all from to by who]} {
  1247.     for {set date $from} {$date <= $to} {incr date} {
  1248. lappend dates($who) $date
  1249.     }
  1250.     continue
  1251. }
  1252. if {[regexp {^Copyright +(c) +(d+), *(d+) +(by +)?(w.*)$} $copyright all date1 date2 by who]} {
  1253.     lappend dates($who) $date1 $date2
  1254.     continue
  1255. }
  1256. puts "oops: $copyright"
  1257.     }
  1258.     foreach who [array names dates] {
  1259. set list [lsort $dates($who)]
  1260. if {[llength $list] == 1 || [lindex $list 0] == [lrange $list end end]} {
  1261.     lappend merge "Copyright (c) [lindex $list 0] $who"
  1262. } else {
  1263.     lappend merge "Copyright (c) [lindex $list 0]-[lrange $list end end] $who"
  1264. }
  1265.     }
  1266.     return [lsort $merge]
  1267. }
  1268. proc makedirhier {dir} {
  1269.     if {![file isdirectory $dir] && 
  1270.     [catch {file mkdir $dir} error]} {
  1271. return -code error "cannot create directory $dir: $error"
  1272.     }
  1273. }
  1274. ##
  1275. ## foreach of the man directories specified by args
  1276. ## convert manpages into hypertext in the directory
  1277. ## specified by html.
  1278. ##
  1279. proc make-man-pages {html args} {
  1280.     global env manual overall_title tcltkdesc
  1281.     makedirhier $html
  1282.     set manual(short-toc-n) 1
  1283.     set manual(short-toc-fp) [open $html/contents.htm w]
  1284.     puts $manual(short-toc-fp) "<HTML><HEAD><TITLE>$overall_title</TITLE></HEAD>"
  1285.     puts $manual(short-toc-fp) "<BODY><HR><H3>$overall_title</H3><HR><DL>"
  1286.     set manual(merge-copyrights) {}
  1287.     foreach arg $args {
  1288. if {$arg == ""} {continue}
  1289. set manual(wing-glob) [lindex $arg 0]
  1290. set manual(wing-name) [lindex $arg 1]
  1291. set manual(wing-file) [lindex $arg 2]
  1292. set manual(wing-description) [lindex $arg 3]
  1293. set manual(wing-copyrights) {}
  1294. makedirhier $html/$manual(wing-file)
  1295. set manual(wing-toc-fp) [open $html/$manual(wing-file)/contents.htm w]
  1296. # whistle
  1297. puts stderr "scanning section $manual(wing-name)"
  1298. # put the entry for this section into the short table of contents
  1299. puts $manual(short-toc-fp) "<DT><A HREF="$manual(wing-file)/contents.htm">$manual(wing-name)</A><DD>$manual(wing-description)"
  1300. # initialize the wing table of contents
  1301. puts $manual(wing-toc-fp) "<HTML><HEAD><TITLE>$manual(wing-name) Manual</TITLE></HEAD>"
  1302. puts $manual(wing-toc-fp) "<BODY><HR><H3>$manual(wing-name)</H3><HR>"
  1303. # initialize the short table of contents for this section
  1304. set manual(wing-toc) {}
  1305. # initialize the man directory for this section
  1306. makedirhier $html/$manual(wing-file)
  1307. # initialize the long table of contents for this section
  1308. set manual(long-toc-n) 1
  1309. # get the manual pages for this section
  1310. set manual(pages) [lsort [glob $manual(wing-glob)]]
  1311. if {[lsearch -glob $manual(pages) */options.n] >= 0} {
  1312.     set n [lsearch $manual(pages) */options.n]
  1313.     set manual(pages) "[lindex $manual(pages) $n] [lreplace $manual(pages) $n $n]"
  1314. }
  1315. # set manual(pages) [lrange $manual(pages) 0 5]
  1316. foreach manual(page) $manual(pages) {
  1317.     # whistle
  1318.     puts stderr "scanning page $manual(page)"
  1319.     set manual(tail) [file tail $manual(page)]
  1320.     set manual(name) [file root $manual(tail)]
  1321.     set manual(section) {}
  1322.     if {[lsearch {case pack-old menubar} $manual(name)] >= 0} {
  1323. # obsolete
  1324. manerror "discarding $manual(name)"
  1325. continue
  1326.     }
  1327.     set manual(infp) [open $manual(page)]
  1328.     set manual(text) {}
  1329.     set manual(partial-text) {}
  1330.     foreach p {.RS .DS .CS .SO} {
  1331. set manual($p) 0
  1332.     }
  1333.     set manual(stack) {}
  1334.     set manual(section) {}
  1335.     set manual(section-toc) {}
  1336.     set manual(section-toc-n) 1
  1337.     set manual(copyrights) {}
  1338.     lappend manual(all-pages) $manual(wing-file)/$manual(tail)
  1339.     manreport 100 $manual(name)
  1340.     while {[gets $manual(infp) line] >= 0} {
  1341. manreport 100 $line
  1342. if {[regexp {^[`'][/\]} $line]} {
  1343.     if {[regexp {Copyright (c).*$} $line copyright]} {
  1344. lappend manual(copyrights) $copyright
  1345.     }
  1346.     # comment
  1347.     continue
  1348. }
  1349. if {"$line" == {'}} {
  1350.     # comment
  1351.     continue
  1352. }
  1353. if {[parse-directive $line code rest]} {
  1354.     switch -exact $code {
  1355. .ad - .na - .so - .ne - .AS - .VE - .VS -
  1356. . {
  1357.     # ignore
  1358.     continue
  1359. }
  1360.     }
  1361.     if {"$manual(partial-text)" != {}} {
  1362. lappend manual(text) [process-text $manual(partial-text)]
  1363. set manual(partial-text) {}
  1364.     }
  1365.     switch -exact $code {
  1366. .SH - .SS {
  1367.     if {[llength $rest] == 0} {
  1368. gets $manual(infp) rest
  1369.     }
  1370.     lappend manual(text) "$code [unquote $rest]"
  1371. }
  1372. .TH {
  1373.     lappend manual(text) "$code [unquote $rest]"
  1374. }
  1375. .HS - .UL -
  1376. .ta {
  1377.     lappend manual(text) "$code [unquote $rest]"
  1378. }
  1379. .BS - .BE - .br - .fi - .sp -
  1380. .nf {
  1381.     if {"$rest" != {}} {
  1382. manerror "unexpected argument: $line"
  1383.     }
  1384.     lappend manual(text) $code
  1385. }
  1386. .AP {
  1387.     lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \fB[lindex $rest 1]\fR ([lindex $rest 2])"]]
  1388. }
  1389. .IP {
  1390.     regexp {^(.*) +d+$} $rest all rest
  1391.     lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
  1392. }
  1393. .TP {
  1394.     while {[is-a-directive [set next [gets $manual(infp)]]]} {
  1395.      manerror "ignoring $next after .TP"
  1396.     }
  1397.     if {"$next" != {'}} {
  1398. lappend manual(text) ".IP [process-text $next]"
  1399.     }
  1400. }
  1401. .OP {
  1402.     lappend manual(text) [concat .OP [process-text 
  1403.     "\fB[lindex $rest 0]\fR \fB[lindex $rest 1]\fR \fB[lindex $rest 2]\fR"]]
  1404. }
  1405. .PP -
  1406. .LP {
  1407.     lappend manual(text) {.PP}
  1408. }
  1409. .RS {
  1410.     incr manual(.RS)
  1411.     lappend manual(text) $code
  1412. }
  1413. .RE {
  1414.     incr manual(.RS) -1
  1415.     lappend manual(text) $code
  1416. }
  1417. .SO {
  1418.     incr manual(.SO)
  1419.     lappend manual(text) $code
  1420. }
  1421. .SE {
  1422.     incr manual(.SO) -1
  1423.     lappend manual(text) $code
  1424. }
  1425. .DS {
  1426.     incr manual(.DS)
  1427.     lappend manual(text) $code
  1428. }
  1429. .DE {
  1430.     incr manual(.DS) -1
  1431.     lappend manual(text) $code
  1432. }
  1433. .CS {
  1434.     incr manual(.CS)
  1435.     lappend manual(text) $code
  1436. }
  1437. .CE {
  1438.     incr manual(.CS) -1
  1439.     lappend manual(text) $code
  1440. }
  1441. .de {
  1442.     while {[gets $manual(infp) line] >= 0} {
  1443. if {[string match "..*" $line]} {
  1444.     break
  1445. }
  1446.     }
  1447. }
  1448. .. {
  1449.     error "found .. outside of .de"
  1450. }
  1451. default {
  1452.     manerror "unrecognized format directive: $line"
  1453. }
  1454.     }
  1455. } else {
  1456.     if {$manual(partial-text) == ""} {
  1457. set manual(partial-text) $line
  1458.     } else {
  1459. append manual(partial-text) n$line
  1460.     }
  1461. }
  1462.     }
  1463.     if {$manual(partial-text) != ""} {
  1464. lappend manual(text) [process-text $manual(partial-text)]
  1465.     }
  1466.     close $manual(infp)
  1467.     # fixups
  1468.     if {$manual(.RS) != 0} {
  1469. if {$manual(name) != "selection"} {
  1470.     puts "unbalanced .RS .RE"
  1471. }
  1472.     }
  1473.     if {$manual(.DS) != 0} {
  1474. puts "unbalanced .DS .DE"
  1475.     }
  1476.     if {$manual(.CS) != 0} {
  1477. puts "unbalanced .CS .CE"
  1478.     }
  1479.     if {$manual(.SO) != 0} {
  1480. puts "unbalanced .SO .SE"
  1481.     }
  1482.     # output conversion
  1483.     open-text
  1484.     if {[next-op-is .HS rest]} {
  1485. set manual($manual(name)-title) 
  1486. "[lrange $rest 1 end] [lindex $rest 0] manual page"
  1487. while {[more-text]} {
  1488.     set line [next-text]
  1489.     if {[is-a-directive $line]} {
  1490. output-directive $line
  1491.     } else {
  1492. man-puts $line
  1493.     }
  1494. }
  1495. man-puts <HR><PRE>
  1496. foreach copyright $manual(copyrights) {
  1497.     man-puts "<A HREF="../copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1498. }
  1499. man-puts "<A HREF="../copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr.</PRE>"
  1500. set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)]
  1501.     } elseif {[next-op-is .TH rest]} {
  1502. set manual($manual(name)-title) "[lrange $rest 4 end] - [lindex $rest 0] manual page"
  1503. while {[more-text]} {
  1504.     set line [next-text]
  1505.     if {[is-a-directive $line]} {
  1506. output-directive $line
  1507.     } else {
  1508. man-puts $line
  1509.     }
  1510. }
  1511. man-puts <HR><PRE>
  1512. foreach copyright $manual(copyrights) {
  1513.     man-puts "<A HREF="../copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1514. }
  1515. man-puts "<A HREF="../copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr.</PRE>"
  1516. set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)]
  1517.     } else {
  1518. manerror "no .HS or .TH record found"
  1519.     }
  1520.     #
  1521.     # make the long table of contents for this page
  1522.     #
  1523.     set manual(toc-$manual(wing-file)-$manual(name)) [concat <DL> $manual(section-toc) </DL><HR>]
  1524. }
  1525. #
  1526. # make the wing table of contents for the section
  1527. #
  1528. set width 0
  1529. foreach name $manual(wing-toc) {
  1530.     if {[string length $name] > $width} {
  1531. set width [string length $name]
  1532.     }
  1533. }
  1534. set perline [expr {120 / $width}]
  1535. set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}]
  1536. set n 0
  1537.         catch {unset rows}
  1538. foreach name [lsort $manual(wing-toc)] {
  1539.     set tail $manual(name-$name)
  1540.     if {[llength $tail] > 1} {
  1541. manerror "$name is defined in more than one file: $tail"
  1542. set tail [lindex $tail [expr {[llength $tail]-1}]]
  1543.     }
  1544.     set tail [file tail $tail]
  1545.     append rows([expr {$n%$nrows}]) 
  1546.     "<td> <a href="$tail.htm">$name</a>"
  1547.     incr n
  1548. }
  1549. puts $manual(wing-toc-fp) <table>
  1550.         foreach row [lsort -integer [array names rows]] {
  1551.     puts $manual(wing-toc-fp) <tr>$rows($row)</tr>
  1552. }
  1553. puts $manual(wing-toc-fp) </table>
  1554. #
  1555. # insert wing copyrights
  1556. #
  1557. puts $manual(wing-toc-fp) "<HR><PRE>"
  1558. foreach copyright $manual(wing-copyrights) {
  1559.     puts $manual(wing-toc-fp) "<A HREF="../copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1560. }
  1561. puts $manual(wing-toc-fp) "<A HREF="../copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr."
  1562. puts $manual(wing-toc-fp) "</PRE></BODY></HTML>"
  1563. close $manual(wing-toc-fp)
  1564. set manual(merge-copyrights) [merge-copyrights $manual(merge-copyrights) $manual(wing-copyrights)]
  1565.     }
  1566.     ##
  1567.     ## build the keyword index.
  1568.     ##
  1569.     proc strcasecmp {a b} { return [string compare -nocase $a $b] }
  1570.     set keys [lsort -command strcasecmp [array names manual keyword-*]]
  1571.     makedirhier $html/Keywords
  1572.     catch {eval file delete -- [glob $html/Keywords/*]}
  1573.     puts $manual(short-toc-fp) "<DT><A HREF="Keywords/contents.htm">Keywords</A><DD>The keywords from the $tcltkdesc man pages."
  1574.     set keyfp [open $html/Keywords/contents.htm w]
  1575.     puts $keyfp "<HTML><HEAD><TITLE>$tcltkdesc Keywords</TITLE></HEAD>"
  1576.     puts $keyfp "<BODY><HR><H3>$tcltkdesc Keywords</H3><HR><H2>"
  1577.     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} {
  1578. puts $keyfp "<A HREF="$a.htm">$a</A>"
  1579. set afp [open $html/Keywords/$a.htm w]
  1580. puts $afp "<HTML><HEAD><TITLE>$tcltkdesc Keywords - $a</TITLE></HEAD>"
  1581. puts $afp "<BODY><HR><H3>$tcltkdesc Keywords - $a</H3><HR><H2>"
  1582. 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} {
  1583.     puts $afp "<A HREF="$b.htm">$b</A>"
  1584. }
  1585. puts $afp "</H2><HR><DL>"
  1586. foreach k $keys {
  1587.     if {[string match -nocase "keyword-${a}*" $k]} {
  1588. set k [string range $k 8 end]
  1589. puts $afp "<DT><A NAME="$k">$k</A><DD>"
  1590. set refs {}
  1591. foreach man $manual(keyword-$k) {
  1592.     set name [lindex $man 0]
  1593.     set file [lindex $man 1]
  1594.     lappend refs "<A HREF="../$file">$name</A>"
  1595. }
  1596. puts $afp [join $refs {, }]
  1597.     }
  1598. }
  1599. puts $afp "</DL><HR><PRE>"
  1600. # insert merged copyrights
  1601. foreach copyright $manual(merge-copyrights) {
  1602.     puts $afp "<A HREF="copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1603. }
  1604. puts $afp "<A HREF="copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr."
  1605. puts $afp "</PRE></BODY></HTML>"
  1606. close $afp
  1607.     }
  1608.     puts $keyfp "</H2><HR><PRE>"
  1609.     # insert merged copyrights
  1610.     foreach copyright $manual(merge-copyrights) {
  1611. puts $keyfp "<A HREF="copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1612.     }
  1613.     puts $keyfp "<A HREF="copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr."
  1614.     puts $keyfp </PRE><HR></BODY></HTML>
  1615.     close $keyfp
  1616.     ##
  1617.     ## finish off short table of contents
  1618.     ##
  1619.     puts $manual(short-toc-fp) {<DT><A HREF="http://www.elf.org">Source</A><DD>More information about these man pages.}
  1620.     puts $manual(short-toc-fp) "</DL><HR><PRE>"
  1621.     # insert merged copyrights
  1622.     foreach copyright $manual(merge-copyrights) {
  1623. puts $manual(short-toc-fp) "<A HREF="copyright.htm">Copyright</A> &#169; [lrange $copyright 2 end]"
  1624.     }
  1625.     puts $manual(short-toc-fp) "<A HREF="copyright.htm">Copyright</A> &#169; 1995-1997 Roger E. Critchlow Jr."
  1626.     puts $manual(short-toc-fp) "</PRE></BODY></HTML>"
  1627.     close $manual(short-toc-fp)
  1628.     ##
  1629.     ## output man pages
  1630.     ##
  1631.     unset manual(section)
  1632.     foreach path $manual(all-pages) {
  1633. set manual(wing-file) [file dirname $path]
  1634. set manual(tail) [file tail $path]
  1635. set manual(name) [file root $manual(tail)]
  1636. set text $manual(output-$manual(wing-file)-$manual(name))
  1637. set ntext 0
  1638. foreach item $text {
  1639.     incr ntext [llength [split $item n]]
  1640.     incr ntext
  1641. }
  1642. set toc $manual(toc-$manual(wing-file)-$manual(name))
  1643. set ntoc 0
  1644. foreach item $toc {
  1645.     incr ntoc [llength [split $item n]]
  1646.     incr ntoc
  1647. }
  1648. puts stderr "rescanning page $manual(name) $ntoc/$ntext"
  1649. set manual(outfp) [open $html/$manual(wing-file)/$manual(name).htm w]
  1650. puts $manual(outfp) "<HTML><HEAD><TITLE>$manual($manual(name)-title)</TITLE></HEAD><BODY>"
  1651. if {($ntext > 60) && ($ntoc > 32) || [lsearch {
  1652.     Hash LinkVar SetVar TraceVar ConfigWidg CrtImgType CrtItemType
  1653.     CrtPhImgFmt DoOneEvent GetBitmap GetColor GetCursor GetDash
  1654.     GetJustify GetPixels GetVisual ParseArgv QueueEvent
  1655. } $manual(tail)] >= 0} {
  1656.     foreach item $toc {
  1657. puts $manual(outfp) $item
  1658.     }
  1659. }
  1660. foreach item $text {
  1661.     puts $manual(outfp) [insert-cross-references $item]
  1662. }
  1663. puts $manual(outfp) </BODY></HTML>
  1664. close $manual(outfp)
  1665.     }
  1666.     return {}
  1667. }
  1668. parse_command_line
  1669. set tcltkdesc ""; set cmdesc ""; set appdir ""
  1670. if {$build_tcl} {append tcltkdesc "Tcl"; append cmdesc "Tcl"; append appdir "$tcldir"}
  1671. if {$build_tcl && $build_tk} {append tcltkdesc "/"; append cmdesc " and "; append appdir ","}
  1672. if {$build_tk} {append tcltkdesc "Tk"; append cmdesc "Tk"; append appdir "$tkdir"}
  1673. set usercmddesc "The interpreters which implement $cmdesc."
  1674. set tclcmddesc {The commands which the <B>tclsh</B> interpreter implements.}
  1675. set tkcmddesc {The additional commands which the <B>wish</B> interpreter implements.}
  1676. set tcllibdesc {The C functions which a Tcl extended C program may use.}
  1677. set tklibdesc {The additional C functions which a Tk extended C program may use.}
  1678. if {1} {
  1679.     if {[catch {
  1680. make-man-pages $webdir 
  1681.     "$tcltkdir/{$appdir}/doc/*.1 "$tcltkdesc Applications" UserCmd {$usercmddesc}" 
  1682.     [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.n {Tcl Commands} TclCmd {$tclcmddesc}" : ""}] 
  1683.     [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.n {Tk Commands} TkCmd {$tkcmddesc}" : ""}] 
  1684.     [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.3 {Tcl Library} TclLib {$tcllibdesc}" : ""}] 
  1685.     [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.3 {Tk Library} TkLib {$tklibdesc}" : ""}]
  1686.     } error]} {
  1687. puts $errorn$errorInfo
  1688.     }
  1689. }