Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/tools/tcltk-man2html.tcl @ 25

Last change on this file since 25 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 49.4 KB
Line 
1#!/bin/sh
2# The next line is executed by /bin/sh, but not tcl \
3exec tclsh8.4 "$0" ${1+"$@"}
4
5package require Tcl 8.5
6
7# Convert Ousterhout format man pages into highly crosslinked hypertext.
8#
9# Along the way detect many unmatched font changes and other odd 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
20set Version "0.40"
21
22set ::CSSFILE "docs.css"
23
24proc parse_command_line {} {
25    global argv Version
26
27    # These variables determine where the man pages come from and where
28    # the converted pages go to.
29    global tcltkdir tkdir tcldir webdir build_tcl build_tk
30
31    # Set defaults based on original code.
32    set tcltkdir ../..
33    set tkdir {}
34    set tcldir {}
35    set webdir ../html
36    set build_tcl 0
37    set build_tk 0
38    # Default search version is a glob pattern
39    set useversion {{,[8-9].[0-9]{,[.ab][0-9]{,[0-9]}}}}
40
41    # Handle arguments a la GNU:
42    #   --version
43    #   --useversion=<version>
44    #   --help
45    #   --srcdir=/path
46    #   --htmldir=/path
47
48    foreach option $argv {
49        switch -glob -- $option {
50            --version {
51                puts "tcltk-man-html $Version"
52                exit 0
53            }
54
55            --help {
56                puts "usage: tcltk-man-html \[OPTION\] ...\n"
57                puts "  --help              print this help, then exit"
58                puts "  --version           print version number, then exit"
59                puts "  --srcdir=DIR        find tcl and tk source below DIR"
60                puts "  --htmldir=DIR       put generated HTML in DIR"
61                puts "  --tcl               build tcl help"
62                puts "  --tk                build tk help"
63                puts "  --useversion        version of tcl/tk to search for"
64                exit 0
65            }
66
67            --srcdir=* {
68                # length of "--srcdir=" is 9.
69                set tcltkdir [string range $option 9 end]
70            }
71
72            --htmldir=* {
73                # length of "--htmldir=" is 10
74                set webdir [string range $option 10 end]
75            }
76
77            --useversion=* {
78                # length of "--useversion=" is 13
79                set useversion [string range $option 13 end]
80            }
81
82            --tcl {
83                set build_tcl 1
84            }
85
86            --tk {
87                set build_tk 1
88            }
89
90            default {
91                puts stderr "tcltk-man-html: unrecognized option -- `$option'"
92                exit 1
93            }
94        }
95    }
96
97    if {!$build_tcl && !$build_tk} {
98        set build_tcl 1;
99        set build_tk 1
100    }
101
102    if {$build_tcl} {
103        # Find Tcl.
104        set tcldir [lindex [lsort [glob -nocomplain -tails -type d \
105                -directory $tcltkdir tcl$useversion]] end]
106        if {$tcldir eq ""} {
107            puts stderr "tcltk-man-html: couldn't find Tcl below $tcltkdir"
108            exit 1
109        }
110        puts "using Tcl source directory $tcldir"
111    }
112
113    if {$build_tk} {
114        # Find Tk.
115        set tkdir [lindex [lsort [glob -nocomplain -tails -type d \
116                                      -directory $tcltkdir tk$useversion]] end]
117        if {$tkdir eq ""} {
118            puts stderr "tcltk-man-html: couldn't find Tk below $tcltkdir"
119            exit 1
120        }
121        puts "using Tk source directory $tkdir"
122    }
123
124    # the title for the man pages overall
125    global overall_title
126    set overall_title ""
127    if {$build_tcl} {
128        append overall_title "[capitalize $tcldir]"
129    }
130    if {$build_tcl && $build_tk} {
131        append overall_title "/"
132    }
133    if {$build_tk} {
134        append overall_title "[capitalize $tkdir]"
135    }
136    append overall_title " Documentation"
137}
138
139proc capitalize {string} {
140    return [string toupper $string 0]
141}
142
143##
144##
145##
146set manual(report-level) 1
147
148proc manerror {msg} {
149    global manual
150    set name {}
151    set subj {}
152    set procname [lindex [info level -1] 0]
153    if {[info exists manual(name)]} {
154        set name $manual(name)
155    }
156    if {[info exists manual(section)] && [string length $manual(section)]} {
157        puts stderr "$name: $manual(section): $procname: $msg"
158    } else {
159        puts stderr "$name: $procname: $msg"
160    }
161}
162
163proc manreport {level msg} {
164    global manual
165    if {$level < $manual(report-level)} {
166        uplevel 1 [list manerror $msg]
167    }
168}
169
170proc fatal {msg} {
171    global manual
172    uplevel 1 [list manerror $msg]
173    exit 1
174}
175
176##
177## templating
178##
179proc indexfile {} {
180    if {[info exists ::TARGET] && $::TARGET eq "devsite"} {
181        return "index.tml"
182    } else {
183        return "contents.htm"
184    }
185}
186proc copyright {copyright {level {}}} {
187    # We don't actually generate a separate copyright page anymore
188    #set page "${level}copyright.htm"
189    #return "<A HREF=\"$page\">Copyright</A> &#169; [htmlize-text [lrange $copyright 2 end]]"
190    # obfuscate any email addresses that may appear in name
191    set who [string map {@ (at)} [lrange $copyright 2 end]]
192    return "Copyright &copy; [htmlize-text $who]"
193}
194proc copyout {copyrights {level {}}} {
195    set out "<div class=\"copy\">"
196    foreach c $copyrights {
197        append out "[copyright $c $level]\n"
198    }
199    append out "</div>"
200    return $out
201}
202proc CSS {{level ""}} {
203    return "<link rel=\"stylesheet\" href=\"${level}$::CSSFILE\" type=\"text/css\" media=\"all\">\n"
204}
205proc DOCTYPE {} {
206    return "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">"
207}
208proc htmlhead {title header args} {
209    set level ""
210    if {[lindex $args end] eq "../[indexfile]"} {
211        # XXX hack - assume same level for CSS file
212        set level "../"
213    }
214    set out "[DOCTYPE]\n<HTML>\n<HEAD><TITLE>$title</TITLE>\n[CSS $level]</HEAD>\n"
215    foreach {uptitle url} $args {
216        set header "<a href=\"$url\">$uptitle</a> <small>&gt;</small> $header"
217    }
218    append out "<BODY><H2>$header</H2>"
219    global manual
220    if {[info exists manual(subheader)]} {
221        set subs {}
222        foreach {name subdir} $manual(subheader) {
223            if {$name eq $title} {
224                lappend subs $name
225            } else {
226                lappend subs "<A HREF=\"${level}$subdir/[indexfile]\">$name</A>"
227            }
228        }
229        append out "\n<H3>[join $subs { | }]</H3>"
230    }
231    return $out
232}
233proc gencss {} {
234    set hBd "1px dotted #11577b"
235    return "
236body, div, p, th, td, li, dd, ul, ol, dl, dt, blockquote {
237    font-family: Verdana, sans-serif;
238}
239
240pre, code { font-family: 'Courier New', Courier, monospace; }
241
242pre {
243    background-color:  #f6fcec;
244    border-top:        1px solid #6A6A6A;
245    border-bottom:     1px solid #6A6A6A;
246    padding:           1em;
247    overflow:          auto;
248}
249
250body {
251    background-color:  #FFFFFF;
252    font-size:         12px;
253    line-height:       1.25;
254    letter-spacing:    .2px;
255    padding-left:      .5em;
256}
257
258h1, h2, h3, h4 {
259    font-family:       Georgia, serif;
260    padding-left:      1em;
261    margin-top:        1em;
262}
263
264h1 {
265    font-size:         18px;
266    color:             #11577b;
267    border-bottom:     $hBd;
268    margin-top:        0px;
269}
270
271h2 {
272    font-size:         14px;
273    color:             #11577b;
274    background-color:  #c5dce8;
275    padding-left:      1em;
276    border:            1px solid #6A6A6A;
277}
278
279h3, h4 {
280    color:             #1674A4;
281    background-color:  #e8f2f6;
282    border-bottom:     $hBd;
283    border-top:        $hBd;
284}
285
286h3 { font-size: 12px; }
287h4 { font-size: 11px; }
288
289.keylist dt, .arguments dt {
290  width: 20em;
291  float: left;
292  padding: 2px;
293  border-top: 1px solid #999;
294}
295
296.keylist dt { font-weight: bold; }
297
298.keylist dd, .arguments dd {
299  margin-left: 20em;
300  padding: 2px;
301  border-top: 1px solid #999;
302}
303
304.copy {
305    background-color:  #f6fcfc;
306    white-space:       pre;
307    font-size:         80%;
308    border-top:        1px solid #6A6A6A;
309    margin-top:        2em;
310}
311"
312}
313
314##
315## parsing
316##
317proc unquote arg {
318    return [string map [list \" {}] $arg]
319}
320
321proc parse-directive {line codename restname} {
322    upvar 1 $codename code $restname rest
323    return [regexp {^(\.[.a-zA-Z0-9]*) *(.*)} $line all code rest]
324}
325
326proc htmlize-text {text {charmap {}}} {
327    # contains some extras for use in nroff->html processing
328    # build on the list passed in, if any
329    lappend charmap \
330        {&}     {&amp;} \
331        {\\}    "&#92;" \
332        {\e}    "&#92;" \
333        {\ }    {&nbsp;} \
334        {\|}    {&nbsp;} \
335        {\0}    { } \
336        \"      {&quot;} \
337        {<}     {&lt;} \
338        {>}     {&gt;} \
339        \u201c "&#8220;" \
340        \u201d "&#8221;"
341
342    return [string map $charmap $text]
343}
344
345proc process-text {text} {
346    global manual
347    # preprocess text
348    set charmap [list \
349                     {\&}       "\t" \
350                     {\%}       {} \
351                     "\\\n"     "\n" \
352                     {\(+-}     "&#177;" \
353                     {\(co}     "&copy;" \
354                     {\(em}     "&#8212;" \
355                     {\(fm}     "&#8242;" \
356                     {\(mu}     "&#215;" \
357                     {\(->}     "<font size=\"+1\">&#8594;</font>" \
358                     {\fP}      {\fR} \
359                     {\.}       . \
360                     {\(bu}     "&#8226;" \
361                    ]
362    lappend charmap {\o'o^'} {&ocirc;} ; # o-circumflex in re_syntax.n
363    lappend charmap {\-\|\-} --        ; # two hyphens
364    lappend charmap {\-} -             ; # a hyphen
365
366    set text [htmlize-text $text $charmap]
367    # General quoted entity
368    regsub -all {\\N'(\d+)'} $text "\\&#\\1;" text
369    while {[string first "\\" $text] >= 0} {
370        # C R
371        if {[regsub {^([^\\]*)\\fC([^\\]*)\\fR(.*)$} $text \
372                {\1<TT>\2</TT>\3} text]} continue
373        # B R
374        if {[regsub {^([^\\]*)\\fB([^\\]*)\\fR(.*)$} $text \
375                {\1<B>\2</B>\3} text]} continue
376        # B I
377        if {[regsub {^([^\\]*)\\fB([^\\]*)\\fI(.*)$} $text \
378                {\1<B>\2</B>\\fI\3} text]} continue
379        # I R
380        if {[regsub {^([^\\]*)\\fI([^\\]*)\\fR(.*)$} $text \
381                {\1<I>\2</I>\3} text]} continue
382        # I B
383        if {[regsub {^([^\\]*)\\fI([^\\]*)\\fB(.*)$} $text \
384                {\1<I>\2</I>\\fB\3} text]} continue
385        # B B, I I, R R
386        if {
387            [regsub {^([^\\]*)\\fB([^\\]*)\\fB(.*)$} $text \
388                {\1\\fB\2\3} ntext]
389            || [regsub {^([^\\]*)\\fI([^\\]*)\\fI(.*)$} $text \
390                    {\1\\fI\2\3} ntext]
391            || [regsub {^([^\\]*)\\fR([^\\]*)\\fR(.*)$} $text \
392                    {\1\\fR\2\3} ntext]
393        } then {
394            manerror "impotent font change: $text"
395            set text $ntext
396            continue
397        }
398        # unrecognized
399        manerror "uncaught backslash: $text"
400        set text [string map [list "\\" "&#92;"] $text]
401    }
402    return $text
403}
404##
405## pass 2 text input and matching
406##
407proc open-text {} {
408    global manual
409    set manual(text-length) [llength $manual(text)]
410    set manual(text-pointer) 0
411}
412proc more-text {} {
413    global manual
414    return [expr {$manual(text-pointer) < $manual(text-length)}]
415}
416proc next-text {} {
417    global manual
418    if {[more-text]} {
419        set text [lindex $manual(text) $manual(text-pointer)]
420        incr manual(text-pointer)
421        return $text
422    }
423    manerror "read past end of text"
424    error "fatal"
425}
426proc is-a-directive {line} {
427    return [string match .* $line]
428}
429proc split-directive {line opname restname} {
430    upvar 1 $opname op $restname rest
431    set op [string range $line 0 2]
432    set rest [string trim [string range $line 3 end]]
433}
434proc next-op-is {op restname} {
435    global manual
436    upvar 1 $restname rest
437    if {[more-text]} {
438        set text [lindex $manual(text) $manual(text-pointer)]
439        if {[string equal -length 3 $text $op]} {
440            set rest [string range $text 4 end]
441            incr manual(text-pointer)
442            return 1
443        }
444    }
445    return 0
446}
447proc backup-text {n} {
448    global manual
449    if {$manual(text-pointer)-$n >= 0} {
450        incr manual(text-pointer) -$n
451    }
452}
453proc match-text args {
454    global manual
455    set nargs [llength $args]
456    if {$manual(text-pointer) + $nargs > $manual(text-length)} {
457        return 0
458    }
459    set nback 0
460    foreach arg $args {
461        if {![more-text]} {
462            backup-text $nback
463            return 0
464        }
465        set arg [string trim $arg]
466        set targ [string trim [lindex $manual(text) $manual(text-pointer)]]
467        if {$arg eq $targ} {
468            incr nback
469            incr manual(text-pointer)
470            continue
471        }
472        if {[regexp {^@(\w+)$} $arg all name]} {
473            upvar 1 $name var
474            set var $targ
475            incr nback
476            incr manual(text-pointer)
477            continue
478        }
479        if {[regexp -nocase {^(\.[A-Z][A-Z])@(\w+)$} $arg all op name]\
480                && [string equal $op [lindex $targ 0]]} {
481            upvar 1 $name var
482            set var [lrange $targ 1 end]
483            incr nback
484            incr manual(text-pointer)
485            continue
486        }
487        backup-text $nback
488        return 0
489    }
490    return 1
491}
492proc expand-next-text {n} {
493    global manual
494    return [join [lrange $manual(text) $manual(text-pointer) \
495            [expr {$manual(text-pointer)+$n-1}]] \n\n]
496}
497##
498## pass 2 output
499##
500proc man-puts {text} {
501    global manual
502    lappend manual(output-$manual(wing-file)-$manual(name)) $text
503}
504
505##
506## build hypertext links to tables of contents
507##
508proc long-toc {text} {
509    global manual
510    set here M[incr manual(section-toc-n)]
511    set there L[incr manual(long-toc-n)]
512    lappend manual(section-toc) \
513            "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$text</A>"
514    return "<A NAME=\"$here\">$text</A>"
515}
516proc option-toc {name class switch} {
517    global manual
518    if {[string match "*OPTIONS" $manual(section)]} {
519        if {$manual(name) ne "ttk_widget"} {
520            # link the defined option into the long table of contents
521            set link [long-toc "$switch, $name, $class"]
522            regsub -- "$switch, $name, $class" $link "$switch" link
523            return $link
524        }
525    } elseif {"$manual(name):$manual(section)" ne "options:DESCRIPTION"} {
526        error "option-toc in $manual(name) section $manual(section)"
527    }
528
529    # link the defined standard option to the long table of contents and make
530    # a target for the standard option references from other man pages.
531
532    set first [lindex $switch 0]
533    set here M$first
534    set there L[incr manual(long-toc-n)]
535    set manual(standard-option-$manual(name)-$first) \
536        "<A HREF=\"$manual(name).htm#$here\">$switch, $name, $class</A>"
537    lappend manual(section-toc) \
538        "<DD><A HREF=\"$manual(name).htm#$here\" NAME=\"$there\">$switch, $name, $class</A>"
539    return "<A NAME=\"$here\">$switch</A>"
540}
541proc std-option-toc {name page} {
542    global manual
543    if {[info exists manual(standard-option-$page-$name)]} {
544        lappend manual(section-toc) <DD>$manual(standard-option-$page-$name)
545        return $manual(standard-option-$page-$name)
546    }
547    manerror "missing reference to \"$name\" in $page.n"
548    set here M[incr manual(section-toc-n)]
549    set there L[incr manual(long-toc-n)]
550    set other M$name
551    lappend manual(section-toc) "<DD><A HREF=\"$page.htm#$other\">$name</A>"
552    return "<A HREF=\"$page.htm#$other\">$name</A>"
553}
554##
555## process the widget option section
556## in widget and options man pages
557##
558proc output-widget-options {rest} {
559    global manual
560    man-puts <DL>
561    lappend manual(section-toc) <DL>
562    backup-text 1
563    set para {}
564    while {[next-op-is .OP rest]} {
565        switch -exact -- [llength $rest] {
566            3 {
567                lassign $rest switch name class
568            }
569            5 {
570                set switch [lrange $rest 0 2]
571                set name [lindex $rest 3]
572                set class [lindex $rest 4]
573            }
574            default {
575                fatal "bad .OP $rest"
576            }
577        }
578        if {![regexp {^(<.>)([-\w ]+)(</.>)$} $switch \
579                all oswitch switch cswitch]} {
580            if {![regexp {^(<.>)([-\w ]+) or ([-\w ]+)(</.>)$} $switch \
581                    all oswitch switch1 switch2 cswitch]} {
582                error "not Switch: $switch"
583            }
584            set switch "$switch1$cswitch or $oswitch$switch2"
585        }
586        if {![regexp {^(<.>)([\w]*)(</.>)$} $name all oname name cname]} {
587            error "not Name: $name"
588        }
589        if {![regexp {^(<.>)([\w]*)(</.>)$} $class all oclass class cclass]} {
590            error "not Class: $class"
591        }
592        man-puts "$para<DT>Command-Line Name: $oswitch[option-toc $name $class $switch]$cswitch"
593        man-puts "<DT>Database Name: $oname$name$cname"
594        man-puts "<DT>Database Class: $oclass$class$cclass"
595        man-puts <DD>[next-text]
596        set para <P>
597
598        if {[next-op-is .RS rest]} {
599            while {[more-text]} {
600                set line [next-text]
601                if {[is-a-directive $line]} {
602                    split-directive $line code rest
603                    switch -exact -- $code {
604                        .RE {
605                            break
606                        }
607                        .SH - .SS {
608                            manerror "unbalanced .RS at section end"
609                            backup-text 1
610                            break
611                        }
612                        default {
613                            output-directive $line
614                        }
615                    }
616                } else {
617                    man-puts $line
618                }
619            }
620        }
621    }
622    man-puts </DL>
623    lappend manual(section-toc) </DL>
624}
625
626##
627## process .RS lists
628##
629proc output-RS-list {} {
630    global manual
631    if {[next-op-is .IP rest]} {
632        output-IP-list .RS .IP $rest
633        if {[match-text .RE .sp .RS @rest .IP @rest2]} {
634            man-puts <P>$rest
635            output-IP-list .RS .IP $rest2
636        }
637        if {[match-text .RE .sp .RS @rest .RE]} {
638            man-puts <P>$rest
639            return
640        }
641        if {[next-op-is .RE rest]} {
642            return
643        }
644    }
645    man-puts <DL><DD>
646    while {[more-text]} {
647        set line [next-text]
648        if {[is-a-directive $line]} {
649            split-directive $line code rest
650            switch -exact -- $code {
651                .RE {
652                    break
653                }
654                .SH - .SS {
655                    manerror "unbalanced .RS at section end"
656                    backup-text 1
657                    break
658                }
659                default {
660                    output-directive $line
661                }
662            }
663        } else {
664            man-puts $line
665        }
666    }
667    man-puts </DL>
668}
669
670##
671## process .IP lists which may be plain indents,
672## numeric lists, or definition lists
673##
674proc output-IP-list {context code rest} {
675    global manual
676    if {![string length $rest]} {
677        # blank label, plain indent, no contents entry
678        man-puts <DL><DD>
679        while {[more-text]} {
680            set line [next-text]
681            if {[is-a-directive $line]} {
682                split-directive $line code rest
683                if {$code eq ".IP" && $rest eq {}} {
684                    man-puts "<P>"
685                    continue
686                }
687                if {$code in {.br .DS .RS}} {
688                    output-directive $line
689                } else {
690                    backup-text 1
691                    break
692                }
693            } else {
694                man-puts $line
695            }
696        }
697        man-puts </DL>
698    } else {
699        # labelled list, make contents
700        if {$context ne ".SH" && $context ne ".SS"} {
701            man-puts <P>
702        }
703        set dl "<DL class=\"[string tolower $manual(section)]\">"
704        man-puts $dl
705        lappend manual(section-toc) $dl
706        backup-text 1
707        set accept_RE 0
708        set para {}
709        while {[more-text]} {
710            set line [next-text]
711            if {[is-a-directive $line]} {
712                split-directive $line code rest
713                switch -exact -- $code {
714                    .IP {
715                        if {$accept_RE} {
716                            output-IP-list .IP $code $rest
717                            continue
718                        }
719                        if {$manual(section) eq "ARGUMENTS" || \
720                                [regexp {^\[\d+\]$} $rest]} {
721                            man-puts "$para<DT>$rest<DD>"
722                        } elseif {"&#8226;" eq $rest} {
723                            man-puts "$para<DT><DD>$rest&nbsp;"
724                        } else {
725                            man-puts "$para<DT>[long-toc $rest]<DD>"
726                        }
727                        if {"$manual(name):$manual(section)" eq \
728                                "selection:DESCRIPTION"} {
729                            if {[match-text .RE @rest .RS .RS]} {
730                                man-puts <DT>[long-toc $rest]<DD>
731                            }
732                        }
733                    }
734                    .sp - .br - .DS - .CS {
735                        output-directive $line
736                    }
737                    .RS {
738                        if {[match-text .RS]} {
739                            output-directive $line
740                            incr accept_RE 1
741                        } elseif {[match-text .CS]} {
742                            output-directive .CS
743                            incr accept_RE 1
744                        } elseif {[match-text .PP]} {
745                            output-directive .PP
746                            incr accept_RE 1
747                        } elseif {[match-text .DS]} {
748                            output-directive .DS
749                            incr accept_RE 1
750                        } else {
751                            output-directive $line
752                        }
753                    }
754                    .PP {
755                        if {[match-text @rest1 .br @rest2 .RS]} {
756                            # yet another nroff kludge as above
757                            man-puts "$para<DT>[long-toc $rest1]"
758                            man-puts "<DT>[long-toc $rest2]<DD>"
759                            incr accept_RE 1
760                        } elseif {[match-text @rest .RE]} {
761                            # gad, this is getting ridiculous
762                            if {!$accept_RE} {
763                                man-puts "</DL><P>$rest<DL>"
764                                backup-text 1
765                                set para {}
766                                break
767                            } else {
768                                man-puts "<P>$rest"
769                                incr accept_RE -1
770                            }
771                        } elseif {$accept_RE} {
772                            output-directive $line
773                        } else {
774                            backup-text 1
775                            break
776                        }
777                    }
778                    .RE {
779                        if {!$accept_RE} {
780                            backup-text 1
781                            break
782                        }
783                        incr accept_RE -1
784                    }
785                    default {
786                        backup-text 1
787                        break
788                    }
789                }
790            } else {
791                man-puts $line
792            }
793            set para <P>
794        }
795        man-puts "$para</DL>"
796        lappend manual(section-toc) </DL>
797        if {$accept_RE} {
798            manerror "missing .RE in output-IP-list"
799        }
800    }
801}
802##
803## handle the NAME section lines
804## there's only one line in the NAME section,
805## consisting of a comma separated list of names,
806## followed by a hyphen and a short description.
807##
808proc output-name {line} {
809    global manual
810    # split name line into pieces
811    regexp {^([^-]+) - (.*)$} $line all head tail
812    # output line to manual page untouched
813    man-puts $line
814    # output line to long table of contents
815    lappend manual(section-toc) <DL><DD>$line</DD></DL>
816    # separate out the names for future reference
817    foreach name [split $head ,] {
818        set name [string trim $name]
819        if {[llength $name] > 1} {
820            manerror "name has a space: {$name}\nfrom: $line"
821        }
822        lappend manual(wing-toc) $name
823        lappend manual(name-$name) $manual(wing-file)/$manual(name)
824    }
825}
826##
827## build a cross-reference link if appropriate
828##
829proc cross-reference {ref} {
830    global manual
831    if {[string match "Tcl_*" $ref]} {
832        set lref $ref
833    } elseif {[string match "Tk_*" $ref]} {
834        set lref $ref
835    } elseif {$ref eq "Tcl"} {
836        set lref $ref
837    } else {
838        set lref [string tolower $ref]
839    }
840    ##
841    ## nothing to reference
842    ##
843    if {![info exists manual(name-$lref)]} {
844        foreach name {
845            array file history info interp string trace after clipboard grab
846            image option pack place selection tk tkwait update winfo wm
847        } {
848            if {[regexp "^$name \[a-z0-9]*\$" $lref] && \
849                    [info exists manual(name-$name)] && \
850                    $manual(tail) ne "$name.n"} {
851                return "<A HREF=\"../$manual(name-$name).htm\">$ref</A>"
852            }
853        }
854        if {$lref in {stdin stdout stderr end}} {
855            # no good place to send these
856            # tcl tokens?
857            # also end
858        }
859        return $ref
860    }
861    ##
862    ## would be a self reference
863    ##
864    foreach name $manual(name-$lref) {
865        if {"$manual(wing-file)/$manual(name)" in $name} {
866            return $ref
867        }
868    }
869    ##
870    ## multiple choices for reference
871    ##
872    if {[llength $manual(name-$lref)] > 1} {
873        set tcl_i [lsearch -glob $manual(name-$lref) *TclCmd*]
874        set tcl_ref [lindex $manual(name-$lref) $tcl_i]
875        set tk_i [lsearch -glob $manual(name-$lref) *TkCmd*]
876        set tk_ref [lindex $manual(name-$lref) $tk_i]
877        if {$tcl_i >= 0 && $manual(wing-file) eq "TclCmd"
878                || $manual(wing-file) eq "TclLib"} {
879            return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
880        }
881        if {$tk_i >= 0 && $manual(wing-file) eq "TkCmd"
882                || $manual(wing-file) eq "TkLib"} {
883            return "<A HREF=\"../$tk_ref.htm\">$ref</A>"
884        }
885        if {$lref eq "exit" && $manual(tail) eq "tclsh.1" && $tcl_i >= 0} {
886            return "<A HREF=\"../$tcl_ref.htm\">$ref</A>"
887        }
888        puts stderr "multiple cross reference to $ref in $manual(name-$lref) from $manual(wing-file)/$manual(tail)"
889        return $ref
890    }
891    ##
892    ## exceptions, sigh, to the rule
893    ##
894    switch -exact -- $manual(tail) {
895        canvas.n {
896            if {$lref eq "focus"} {
897                upvar 1 tail tail
898                set clue [string first command $tail]
899                if {$clue < 0 ||  $clue > 5} {
900                    return $ref
901                }
902            }
903            if {$lref in {bitmap image text}} {
904                return $ref
905            }
906        }
907        checkbutton.n - radiobutton.n {
908            if {$lref in {image}} {
909                return $ref
910            }
911        }
912        menu.n {
913            if {$lref in {checkbutton radiobutton}} {
914                return $ref
915            }
916        }
917        options.n {
918            if {$lref in {bitmap image set}} {
919                return $ref
920            }
921        }
922        regexp.n {
923            if {$lref in {string}} {
924                return $ref
925            }
926        }
927        source.n {
928            if {$lref in {text}} {
929                return $ref
930            }
931        }
932        history.n {
933            if {$lref in {exec}} {
934                return $ref
935            }
936        }
937        return.n {
938            if {$lref in {error continue break}} {
939                return $ref
940            }
941        }
942        scrollbar.n {
943            if {$lref in {set}} {
944                return $ref
945            }
946        }
947    }
948    ##
949    ## return the cross reference
950    ##
951    return "<A HREF=\"../$manual(name-$lref).htm\">$ref</A>"
952}
953##
954## reference generation errors
955##
956proc reference-error {msg text} {
957    global manual
958    puts stderr "$manual(tail): $msg: {$text}"
959    return $text
960}
961##
962## insert as many cross references into this text string as are appropriate
963##
964proc insert-cross-references {text} {
965    global manual
966    ##
967    ## we identify cross references by:
968    ##     ``quotation''
969    ##    <B>emboldening</B>
970    ##    Tcl_ prefix
971    ##    Tk_ prefix
972    ##    [a-zA-Z0-9]+ manual entry
973    ## and we avoid messing with already anchored text
974    ##
975    ##
976    ## find where each item lives
977    ##
978    array set offset [list \
979            anchor [string first {<A } $text] \
980            end-anchor [string first {</A>} $text] \
981            quote [string first {``} $text] \
982            end-quote [string first {''} $text] \
983            bold [string first {<B>} $text] \
984            end-bold [string first {</B>} $text] \
985            tcl [string first {Tcl_} $text] \
986            tk [string first {Tk_} $text] \
987            Tcl1 [string first {Tcl manual entry} $text] \
988            Tcl2 [string first {Tcl overview manual entry} $text] \
989            ]
990    ##
991    ## accumulate a list
992    ##
993    foreach name [array names offset] {
994        if {$offset($name) >= 0} {
995            set invert($offset($name)) $name
996            lappend offsets $offset($name)
997        }
998    }
999    ##
1000    ## if nothing, then we're done.
1001    ##
1002    if {![info exists offsets]} {
1003        return $text
1004    }
1005    ##
1006    ## sort the offsets
1007    ##
1008    set offsets [lsort -integer $offsets]
1009    ##
1010    ## see which we want to use
1011    ##
1012    switch -exact -- $invert([lindex $offsets 0]) {
1013        anchor {
1014            if {$offset(end-anchor) < 0} {
1015                return [reference-error {Missing end anchor} $text]
1016            }
1017            set head [string range $text 0 $offset(end-anchor)]
1018            set tail [string range $text [expr {$offset(end-anchor)+1}] end]
1019            return $head[insert-cross-references $tail]
1020        }
1021        quote {
1022            if {$offset(end-quote) < 0} {
1023                return [reference-error "Missing end quote" $text]
1024            }
1025            if {$invert([lindex $offsets 1]) eq "tk"} {
1026                set offsets [lreplace $offsets 1 1]
1027            }
1028            if {$invert([lindex $offsets 1]) eq "tcl"} {
1029                set offsets [lreplace $offsets 1 1]
1030            }
1031            switch -exact -- $invert([lindex $offsets 1]) {
1032                end-quote {
1033                    set head [string range $text 0 [expr {$offset(quote)-1}]]
1034                    set body [string range $text [expr {$offset(quote)+2}] \
1035                            [expr {$offset(end-quote)-1}]]
1036                    set tail [string range $text \
1037                            [expr {$offset(end-quote)+2}] end]
1038                    return "$head``[cross-reference $body]''[insert-cross-references $tail]"
1039                }
1040                bold -
1041                anchor {
1042                    set head [string range $text \
1043                            0 [expr {$offset(end-quote)+1}]]
1044                    set tail [string range $text \
1045                            [expr {$offset(end-quote)+2}] end]
1046                    return "$head[insert-cross-references $tail]"
1047                }
1048            }
1049            return [reference-error "Uncaught quote case" $text]
1050        }
1051        bold {
1052            if {$offset(end-bold) < 0} {
1053                return $text
1054            }
1055            if {$invert([lindex $offsets 1]) eq "tk"} {
1056                set offsets [lreplace $offsets 1 1]
1057            }
1058            if {$invert([lindex $offsets 1]) eq "tcl"} {
1059                set offsets [lreplace $offsets 1 1]
1060            }
1061            switch -exact -- $invert([lindex $offsets 1]) {
1062                end-bold {
1063                    set head [string range $text 0 [expr {$offset(bold)-1}]]
1064                    set body [string range $text [expr {$offset(bold)+3}] \
1065                            [expr {$offset(end-bold)-1}]]
1066                    set tail [string range $text \
1067                            [expr {$offset(end-bold)+4}] end]
1068                    return "$head<B>[cross-reference $body]</B>[insert-cross-references $tail]"
1069                }
1070                anchor {
1071                    set head [string range $text \
1072                            0 [expr {$offset(end-bold)+3}]]
1073                    set tail [string range $text \
1074                            [expr {$offset(end-bold)+4}] end]
1075                    return "$head[insert-cross-references $tail]"
1076                }
1077            }
1078            return [reference-error "Uncaught bold case" $text]
1079        }
1080        tk {
1081            set head [string range $text 0 [expr {$offset(tk)-1}]]
1082            set tail [string range $text $offset(tk) end]
1083            if {![regexp {^(Tk_\w+)(.*)$} $tail all body tail]} {
1084                return [reference-error "Tk regexp failed" $text]
1085            }
1086            return $head[cross-reference $body][insert-cross-references $tail]
1087        }
1088        tcl {
1089            set head [string range $text 0 [expr {$offset(tcl)-1}]]
1090            set tail [string range $text $offset(tcl) end]
1091            if {![regexp {^(Tcl_\w+)(.*)$} $tail all body tail]} {
1092                return [reference-error {Tcl regexp failed} $text]
1093            }
1094            return $head[cross-reference $body][insert-cross-references $tail]
1095        }
1096        Tcl1 -
1097        Tcl2 {
1098            set off [lindex $offsets 0]
1099            set head [string range $text 0 [expr {$off-1}]]
1100            set body Tcl
1101            set tail [string range $text [expr {$off+3}] end]
1102            return $head[cross-reference $body][insert-cross-references $tail]
1103        }
1104        end-anchor -
1105        end-bold -
1106        end-quote {
1107            return [reference-error "Out of place $invert([lindex $offsets 0])" $text]
1108        }
1109    }
1110}
1111##
1112## process formatting directives
1113##
1114proc output-directive {line} {
1115    global manual
1116    # process format directive
1117    split-directive $line code rest
1118    switch -exact -- $code {
1119        .BS - .BE {
1120            # man-puts <HR>
1121        }
1122        .SH - .SS {
1123            # drain any open lists
1124            # announce the subject
1125            set manual(section) $rest
1126            # start our own stack of stuff
1127            set manual($manual(name)-$manual(section)) {}
1128            lappend manual(has-$manual(section)) $manual(name)
1129            if {$code ne ".SS"} {
1130                man-puts "<H3>[long-toc $manual(section)]</H3>"
1131            } else {
1132                man-puts "<H4>[long-toc $manual(section)]</H4>"
1133            }
1134            # some sections can simply free wheel their way through the text
1135            # some sections can be processed in their own loops
1136            switch -exact -- $manual(section) {
1137                NAME {
1138                    if {$manual(tail) in {CrtImgType.3 CrtItemType.3 CrtPhImgFmt.3}} {
1139                        # these manual pages have two NAME sections
1140                        if {[info exists manual($manual(tail)-NAME)]} {
1141                            return
1142                        }
1143                        set manual($manual(tail)-NAME) 1
1144                    }
1145                    set names {}
1146                    while {1} {
1147                        set line [next-text]
1148                        if {[is-a-directive $line]} {
1149                            backup-text 1
1150                            output-name [join $names { }]
1151                            return
1152                        } else {
1153                            lappend names [string trim $line]
1154                        }
1155                    }
1156                }
1157                SYNOPSIS {
1158                    lappend manual(section-toc) <DL>
1159                    while {1} {
1160                        if {
1161                            [next-op-is .nf rest]
1162                            || [next-op-is .br rest]
1163                            || [next-op-is .fi rest]
1164                        } then {
1165                            continue
1166                        }
1167                        if {
1168                            [next-op-is .SH rest]
1169                            || [next-op-is .SS rest]
1170                            || [next-op-is .BE rest]
1171                            || [next-op-is .SO rest]
1172                        } then {
1173                            backup-text 1
1174                            break
1175                        }
1176                        if {[next-op-is .sp rest]} {
1177                            #man-puts <P>
1178                            continue
1179                        }
1180                        set more [next-text]
1181                        if {[is-a-directive $more]} {
1182                            manerror "in SYNOPSIS found $more"
1183                            backup-text 1
1184                            break
1185                        }
1186                        foreach more [split $more \n] {
1187                            man-puts $more<BR>
1188                            if {$manual(wing-file) in {TclLib TkLib}} {
1189                                lappend manual(section-toc) <DD>$more
1190                            }
1191                        }
1192                    }
1193                    lappend manual(section-toc) </DL>
1194                    return
1195                }
1196                {SEE ALSO} {
1197                    while {[more-text]} {
1198                        if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
1199                            backup-text 1
1200                            return
1201                        }
1202                        set more [next-text]
1203                        if {[is-a-directive $more]} {
1204                            manerror "$more"
1205                            backup-text 1
1206                            return
1207                        }
1208                        set nmore {}
1209                        foreach cr [split $more ,] {
1210                            set cr [string trim $cr]
1211                            if {![regexp {^<B>.*</B>$} $cr]} {
1212                                set cr <B>$cr</B>
1213                            }
1214                            if {[regexp {^<B>(.*)\([13n]\)</B>$} $cr all name]} {
1215                                set cr <B>$name</B>
1216                            }
1217                            lappend nmore $cr
1218                        }
1219                        man-puts [join $nmore {, }]
1220                    }
1221                    return
1222                }
1223                KEYWORDS {
1224                    while {[more-text]} {
1225                        if {[next-op-is .SH rest] || [next-op-is .SS rest]} {
1226                            backup-text 1
1227                            return
1228                        }
1229                        set more [next-text]
1230                        if {[is-a-directive $more]} {
1231                            manerror "$more"
1232                            backup-text 1
1233                            return
1234                        }
1235                        set keys {}
1236                        foreach key [split $more ,] {
1237                            set key [string trim $key]
1238                            lappend manual(keyword-$key) [list $manual(name) $manual(wing-file)/$manual(name).htm]
1239                            set initial [string toupper [string index $key 0]]
1240                            lappend keys "<A href=\"../Keywords/$initial.htm\#$key\">$key</A>"
1241                        }
1242                        man-puts [join $keys {, }]
1243                    }
1244                    return
1245                }
1246            }
1247            if {[next-op-is .IP rest]} {
1248                output-IP-list $code .IP $rest
1249                return
1250            }
1251            if {[next-op-is .PP rest]} {
1252                return
1253            }
1254            return
1255        }
1256        .SO {
1257            set targetPage $rest
1258            if {[match-text @stuff .SE]} {
1259                output-directive {.SH STANDARD OPTIONS}
1260                set opts [split $stuff \n\t]
1261                man-puts <DL>
1262                lappend manual(section-toc) <DL>
1263                foreach option [lsort -dictionary $opts] {
1264                    man-puts "<DT><B>[std-option-toc $option $targetPage]</B>"
1265                }
1266                man-puts </DL>
1267                lappend manual(section-toc) </DL>
1268            } else {
1269                manerror "unexpected .SO format:\n[expand-next-text 2]"
1270            }
1271        }
1272        .OP {
1273            output-widget-options $rest
1274            return
1275        }
1276        .IP {
1277            output-IP-list .IP .IP $rest
1278            return
1279        }
1280        .PP {
1281            man-puts <P>
1282        }
1283        .RS {
1284            output-RS-list
1285            return
1286        }
1287        .RE {
1288            manerror "unexpected .RE"
1289            return
1290        }
1291        .br {
1292            man-puts <BR>
1293            return
1294        }
1295        .DE {
1296            manerror "unexpected .DE"
1297            return
1298        }
1299        .DS {
1300            if {[next-op-is .ta rest]} {
1301                # skip the leading .ta directive if it is there
1302            }
1303            if {[match-text @stuff .DE]} {
1304                set td "<td><p style=\"font-size:12px;padding-left:.5em;padding-right:.5em;\">"
1305                set bodyText [string map [list \n <tr>$td \t $td] \n$stuff]
1306                man-puts "<dl><dd><table border=\"0\">$bodyText</table></dl>"
1307                #man-puts <PRE>$stuff</PRE>
1308            } elseif {[match-text .fi @ul1 @ul2 .nf @stuff .DE]} {
1309                man-puts "<PRE>[lindex $ul1 1][lindex $ul2 1]\n$stuff</PRE>"
1310            } else {
1311                manerror "unexpected .DS format:\n[expand-next-text 2]"
1312            }
1313            return
1314        }
1315        .CS {
1316            if {[next-op-is .ta rest]} {
1317                # ???
1318            }
1319            if {[match-text @stuff .CE]} {
1320                man-puts <PRE>$stuff</PRE>
1321            } else {
1322                manerror "unexpected .CS format:\n[expand-next-text 2]"
1323            }
1324            return
1325        }
1326        .CE {
1327            manerror "unexpected .CE"
1328            return
1329        }
1330        .sp {
1331            man-puts <P>
1332        }
1333        .ta {
1334            # these are tab stop settings for short tables
1335            switch -exact -- $manual(name):$manual(section) {
1336                {bind:MODIFIERS} -
1337                {bind:EVENT TYPES} -
1338                {bind:BINDING SCRIPTS AND SUBSTITUTIONS} -
1339                {expr:OPERANDS} -
1340                {expr:MATH FUNCTIONS} -
1341                {history:DESCRIPTION} -
1342                {history:HISTORY REVISION} -
1343                {switch:DESCRIPTION} -
1344                {upvar:DESCRIPTION} {
1345                    return;                     # fix.me
1346                }
1347                default {
1348                    manerror "ignoring $line"
1349                }
1350            }
1351        }
1352        .nf {
1353            if {[match-text @more .fi]} {
1354                foreach more [split $more \n] {
1355                    man-puts $more<BR>
1356                }
1357            } elseif {[match-text .RS @more .RE .fi]} {
1358                man-puts <DL><DD>
1359                foreach more [split $more \n] {
1360                    man-puts $more<BR>
1361                }
1362                man-puts </DL>
1363            } elseif {[match-text .RS @more .RS @more2 .RE .RE .fi]} {
1364                man-puts <DL><DD>
1365                foreach more [split $more \n] {
1366                    man-puts $more<BR>
1367                }
1368                man-puts <DL><DD>
1369                foreach more2 [split $more2 \n] {
1370                    man-puts $more2<BR>
1371                }
1372                man-puts </DL></DL>
1373            } elseif {[match-text .RS @more .RS @more2 .RE @more3 .RE .fi]} {
1374                man-puts <DL><DD>
1375                foreach more [split $more \n] {
1376                    man-puts $more<BR>
1377                }
1378                man-puts <DL><DD>
1379                foreach more2 [split $more2 \n] {
1380                    man-puts $more2<BR>
1381                }
1382                man-puts </DL><DD>
1383                foreach more3 [split $more3 \n] {
1384                    man-puts $more3<BR>
1385                }
1386                man-puts </DL>
1387            } elseif {[match-text .sp .RS @more .RS @more2 .sp .RE .RE .fi]} {
1388                man-puts <P><DL><DD>
1389                foreach more [split $more \n] {
1390                    man-puts $more<BR>
1391                }
1392                man-puts <DL><DD>
1393                foreach more2 [split $more2 \n] {
1394                    man-puts $more2<BR>
1395                }
1396                man-puts </DL></DL><P>
1397            } elseif {[match-text .RS .sp @more .sp .RE .fi]} {
1398                man-puts <P><DL><DD>
1399                foreach more [split $more \n] {
1400                    man-puts $more<BR>
1401                }
1402                man-puts </DL><P>
1403            } else {
1404                manerror "ignoring $line"
1405            }
1406        }
1407        .fi {
1408            manerror "ignoring $line"
1409        }
1410        .na -
1411        .ad -
1412        .UL -
1413        .ne {
1414            manerror "ignoring $line"
1415        }
1416        default {
1417            manerror "unrecognized format directive: $line"
1418        }
1419    }
1420}
1421##
1422## merge copyright listings
1423##
1424proc merge-copyrights {l1 l2} {
1425    set merge {}
1426    set re1 {^Copyright +(?:\(c\)|\\\(co|&copy;) +(\w.*?)(?:all rights reserved)?(?:\. )*$}
1427    set re2 {^(\d+) +(?:by +)?(\w.*)$}         ;# date who
1428    set re3 {^(\d+)-(\d+) +(?:by +)?(\w.*)$}   ;# from to who
1429    set re4 {^(\d+), *(\d+) +(?:by +)?(\w.*)$} ;# date1 date2 who
1430    foreach copyright [concat $l1 $l2] {
1431        if {[regexp -nocase -- $re1 $copyright -> info]} {
1432            set info [string trimright $info ". "] ; # remove extra period
1433            if {[regexp -- $re2 $info -> date who]} {
1434                lappend dates($who) $date
1435                continue
1436            } elseif {[regexp -- $re3 $info -> from to who]} {
1437                for {set date $from} {$date <= $to} {incr date} {
1438                    lappend dates($who) $date
1439                }
1440                continue
1441            } elseif {[regexp -- $re3 $info -> date1 date2 who]} {
1442                lappend dates($who) $date1 $date2
1443                continue
1444            }
1445        }
1446        puts "oops: $copyright"
1447    }
1448    foreach who [array names dates] {
1449        set list [lsort -dictionary $dates($who)]
1450        if {[llength $list] == 1 || [lindex $list 0] eq [lrange $list end end]} {
1451            lappend merge "Copyright &copy; [lindex $list 0] $who"
1452        } else {
1453            lappend merge "Copyright &copy; [lindex $list 0]-[lrange $list end end] $who"
1454        }
1455    }
1456    return [lsort -dictionary $merge]
1457}
1458
1459proc makedirhier {dir} {
1460    if {![file isdirectory $dir] && \
1461            [catch {file mkdir $dir} error]} {
1462        return -code error "cannot create directory $dir: $error"
1463    }
1464}
1465
1466proc addbuffer {args} {
1467    global manual
1468    if {$manual(partial-text) ne ""} {
1469        append manual(partial-text) \n
1470    }
1471    append manual(partial-text) [join $args ""]
1472}
1473proc flushbuffer {} {
1474    global manual
1475    if {$manual(partial-text) ne ""} {
1476        lappend manual(text) [process-text $manual(partial-text)]
1477        set manual(partial-text) ""
1478    }
1479}
1480
1481##
1482## foreach of the man directories specified by args
1483## convert manpages into hypertext in the directory
1484## specified by html.
1485##
1486proc make-man-pages {html args} {
1487    global manual overall_title tcltkdesc
1488    makedirhier $html
1489    set cssfd [open $html/$::CSSFILE w]
1490    puts $cssfd [gencss]
1491    close $cssfd
1492    set manual(short-toc-n) 1
1493    set manual(short-toc-fp) [open $html/[indexfile] w]
1494    puts $manual(short-toc-fp) [htmlhead $overall_title $overall_title]
1495    puts $manual(short-toc-fp) "<DL class=\"keylist\">"
1496    set manual(merge-copyrights) {}
1497    foreach arg $args {
1498        # preprocess to set up subheader for the rest of the files
1499        if {![llength $arg]} {
1500            continue
1501        }
1502        set name [lindex $arg 1]
1503        set file [lindex $arg 2]
1504        lappend manual(subheader) $name $file
1505    }
1506    foreach arg $args {
1507        if {![llength $arg]} {
1508            continue
1509        }
1510        set manual(wing-glob) [lindex $arg 0]
1511        set manual(wing-name) [lindex $arg 1]
1512        set manual(wing-file) [lindex $arg 2]
1513        set manual(wing-description) [lindex $arg 3]
1514        set manual(wing-copyrights) {}
1515        makedirhier $html/$manual(wing-file)
1516        set manual(wing-toc-fp) [open $html/$manual(wing-file)/[indexfile] w]
1517        # whistle
1518        puts stderr "scanning section $manual(wing-name)"
1519        # put the entry for this section into the short table of contents
1520        puts $manual(short-toc-fp) "<DT><A HREF=\"$manual(wing-file)/[indexfile]\">$manual(wing-name)</A></DT><DD>$manual(wing-description)</DD>"
1521        # initialize the wing table of contents
1522        puts $manual(wing-toc-fp) [htmlhead $manual(wing-name) \
1523                $manual(wing-name) $overall_title "../[indexfile]"]
1524        # initialize the short table of contents for this section
1525        set manual(wing-toc) {}
1526        # initialize the man directory for this section
1527        makedirhier $html/$manual(wing-file)
1528        # initialize the long table of contents for this section
1529        set manual(long-toc-n) 1
1530        # get the manual pages for this section
1531        set manual(pages) [lsort -dictionary [glob $manual(wing-glob)]]
1532        set n [lsearch -glob $manual(pages) */ttk_widget.n]
1533        if {$n >= 0} {
1534            set manual(pages) "[lindex $manual(pages) $n] [lreplace $manual(pages) $n $n]"
1535        }
1536        set n [lsearch -glob $manual(pages) */options.n]
1537        if {$n >= 0} {
1538            set manual(pages) "[lindex $manual(pages) $n] [lreplace $manual(pages) $n $n]"
1539        }
1540        # set manual(pages) [lrange $manual(pages) 0 5]
1541        set LQ \u201c
1542        set RQ \u201d
1543        foreach manual_page $manual(pages) {
1544            set manual(page) $manual_page
1545            # whistle
1546            puts stderr "scanning page $manual(page)"
1547            set manual(tail) [file tail $manual(page)]
1548            set manual(name) [file root $manual(tail)]
1549            set manual(section) {}
1550            if {$manual(name) in {case pack-old menubar}} {
1551                # obsolete
1552                manerror "discarding $manual(name)"
1553                continue
1554            }
1555            set manual(infp) [open $manual(page)]
1556            set manual(text) {}
1557            set manual(partial-text) {}
1558            foreach p {.RS .DS .CS .SO} {
1559                set manual($p) 0
1560            }
1561            set manual(stack) {}
1562            set manual(section) {}
1563            set manual(section-toc) {}
1564            set manual(section-toc-n) 1
1565            set manual(copyrights) {}
1566            lappend manual(copyrights) "Copyright &copy; 1995-1997 Roger E. Critchlow Jr."
1567            lappend manual(all-pages) $manual(wing-file)/$manual(tail)
1568            manreport 100 $manual(name)
1569            while {[gets $manual(infp) line] >= 0} {
1570                manreport 100 $line
1571                if {[regexp {^[`'][/\\]} $line]} {
1572                    if {[regexp {Copyright (?:\(c\)|\\\(co).*$} $line copyright]} {
1573                        lappend manual(copyrights) $copyright
1574                    }
1575                    # comment
1576                    continue
1577                }
1578                if {"$line" eq {'}} {
1579                    # comment
1580                    continue
1581                }
1582                if {![parse-directive $line code rest]} {
1583                    addbuffer $line
1584                    continue
1585                }
1586                switch -exact -- $code {
1587                    .ad - .na - .so - .ne - .AS - .VE - .VS - . {
1588                        # ignore
1589                        continue
1590                    }
1591                }
1592                switch -exact -- $code {
1593                    .SH - .SS {
1594                        flushbuffer
1595                        if {[llength $rest] == 0} {
1596                            gets $manual(infp) rest
1597                        }
1598                        lappend manual(text) "$code [unquote $rest]"
1599                    }
1600                    .TH {
1601                        flushbuffer
1602                        lappend manual(text) "$code [unquote $rest]"
1603                    }
1604                    .QW {
1605                        set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
1606                        addbuffer $LQ [unquote [lindex $rest 0]] $RQ \
1607                            [unquote [lindex $rest 1]]
1608                    }
1609                    .PQ {
1610                        set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
1611                        addbuffer ( $LQ [unquote [lindex $rest 0]] $RQ \
1612                            [unquote [lindex $rest 1]] ) \
1613                            [unquote [lindex $rest 2]]
1614                    }
1615                    .QR {
1616                        set rest [regexp -all -inline {\"(?:[^""]+)\"|\S+} $rest]
1617                        addbuffer $LQ [unquote [lindex $rest 0]] - \
1618                            [unquote [lindex $rest 1]] $RQ \
1619                            [unquote [lindex $rest 2]]
1620                    }
1621                    .MT {
1622                        addbuffer $LQ$RQ
1623                    }
1624                    .HS - .UL - .ta {
1625                        flushbuffer
1626                        lappend manual(text) "$code [unquote $rest]"
1627                    }
1628                    .BS - .BE - .br - .fi - .sp - .nf {
1629                        flushbuffer
1630                        if {"$rest" ne {}} {
1631                            manerror "unexpected argument: $line"
1632                        }
1633                        lappend manual(text) $code
1634                    }
1635                    .AP {
1636                        flushbuffer
1637                        lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
1638                    }
1639                    .IP {
1640                        flushbuffer
1641                        regexp {^(.*) +\d+$} $rest all rest
1642                        lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
1643                    }
1644                    .TP {
1645                        flushbuffer
1646                        while {[is-a-directive [set next [gets $manual(infp)]]]} {
1647                            manerror "ignoring $next after .TP"
1648                        }
1649                        if {"$next" ne {'}} {
1650                            lappend manual(text) ".IP [process-text $next]"
1651                        }
1652                    }
1653                    .OP {
1654                        flushbuffer
1655                        lappend manual(text) [concat .OP [process-text \
1656                                "\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]]
1657                    }
1658                    .PP - .LP {
1659                        flushbuffer
1660                        lappend manual(text) {.PP}
1661                    }
1662                    .RS {
1663                        flushbuffer
1664                        incr manual(.RS)
1665                        lappend manual(text) $code
1666                    }
1667                    .RE {
1668                        flushbuffer
1669                        incr manual(.RS) -1
1670                        lappend manual(text) $code
1671                    }
1672                    .SO {
1673                        flushbuffer
1674                        incr manual(.SO)
1675                        if {[llength $rest] == 0} {
1676                            lappend manual(text) "$code options"
1677                        } else {
1678                            lappend manual(text) "$code [unquote $rest]"
1679                        }
1680                    }
1681                    .SE {
1682                        flushbuffer
1683                        incr manual(.SO) -1
1684                        lappend manual(text) $code
1685                    }
1686                    .DS {
1687                        flushbuffer
1688                        incr manual(.DS)
1689                        lappend manual(text) $code
1690                    }
1691                    .DE {
1692                        flushbuffer
1693                        incr manual(.DS) -1
1694                        lappend manual(text) $code
1695                    }
1696                    .CS {
1697                        flushbuffer
1698                        incr manual(.CS)
1699                        lappend manual(text) $code
1700                    }
1701                    .CE {
1702                        flushbuffer
1703                        incr manual(.CS) -1
1704                        lappend manual(text) $code
1705                    }
1706                    .de {
1707                        while {[gets $manual(infp) line] >= 0} {
1708                            if {[string match "..*" $line]} {
1709                                break
1710                            }
1711                        }
1712                    }
1713                    .. {
1714                        error "found .. outside of .de"
1715                    }
1716                    default {
1717                        flushbuffer
1718                        manerror "unrecognized format directive: $line"
1719                    }
1720                }
1721            }
1722            flushbuffer
1723            close $manual(infp)
1724            # fixups
1725            if {$manual(.RS) != 0} {
1726                puts "unbalanced .RS .RE"
1727            }
1728            if {$manual(.DS) != 0} {
1729                puts "unbalanced .DS .DE"
1730            }
1731            if {$manual(.CS) != 0} {
1732                puts "unbalanced .CS .CE"
1733            }
1734            if {$manual(.SO) != 0} {
1735                puts "unbalanced .SO .SE"
1736            }
1737            # output conversion
1738            open-text
1739            set haserror 0
1740            if {[next-op-is .HS rest]} {
1741                set manual($manual(name)-title) \
1742                        "[lrange $rest 1 end] [lindex $rest 0] manual page"
1743            } elseif {[next-op-is .TH rest]} {
1744                set manual($manual(name)-title) "[lindex $rest 0] manual page - [lrange $rest 4 end]"
1745            } else {
1746                set haserror 1
1747                manerror "no .HS or .TH record found"
1748            }
1749            if {!$haserror} {
1750                while {[more-text]} {
1751                    set line [next-text]
1752                    if {[is-a-directive $line]} {
1753                        output-directive $line
1754                    } else {
1755                        man-puts $line
1756                    }
1757                }
1758                man-puts [copyout $manual(copyrights) "../"]
1759                set manual(wing-copyrights) [merge-copyrights $manual(wing-copyrights) $manual(copyrights)]
1760            }
1761            #
1762            # make the long table of contents for this page
1763            #
1764            set manual(toc-$manual(wing-file)-$manual(name)) [concat <DL> $manual(section-toc) </DL>]
1765        }
1766
1767        #
1768        # make the wing table of contents for the section
1769        #
1770        set width 0
1771        foreach name $manual(wing-toc) {
1772            if {[string length $name] > $width} {
1773                set width [string length $name]
1774            }
1775        }
1776        set perline [expr {120 / $width}]
1777        set nrows [expr {([llength $manual(wing-toc)]+$perline)/$perline}]
1778        set n 0
1779        catch {unset rows}
1780        foreach name [lsort -dictionary $manual(wing-toc)] {
1781            set tail $manual(name-$name)
1782            if {[llength $tail] > 1} {
1783                manerror "$name is defined in more than one file: $tail"
1784                set tail [lindex $tail [expr {[llength $tail]-1}]]
1785            }
1786            set tail [file tail $tail]
1787            append rows([expr {$n%$nrows}]) \
1788                    "<td> <a href=\"$tail.htm\">$name</a>"
1789            incr n
1790        }
1791        puts $manual(wing-toc-fp) <table>
1792        foreach row [lsort -integer [array names rows]] {
1793            puts $manual(wing-toc-fp) <tr>$rows($row)</tr>
1794        }
1795        puts $manual(wing-toc-fp) </table>
1796
1797        #
1798        # insert wing copyrights
1799        #
1800        puts $manual(wing-toc-fp) [copyout $manual(wing-copyrights) "../"]
1801        puts $manual(wing-toc-fp) "</BODY></HTML>"
1802        close $manual(wing-toc-fp)
1803        set manual(merge-copyrights) [merge-copyrights $manual(merge-copyrights) $manual(wing-copyrights)]
1804    }
1805
1806    ##
1807    ## build the keyword index.
1808    ##
1809    file delete -force -- $html/Keywords
1810    makedirhier $html/Keywords
1811    set keyfp [open $html/Keywords/[indexfile] w]
1812    puts $keyfp [htmlhead "$tcltkdesc Keywords" "$tcltkdesc Keywords" \
1813                     $overall_title "../[indexfile]"]
1814    set letters {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}
1815    # Create header first
1816    set keyheader {}
1817    foreach a $letters {
1818        set keys [array names manual "keyword-\[[string totitle $a$a]\]*"]
1819        if {[llength $keys]} {
1820            lappend keyheader "<A HREF=\"$a.htm\">$a</A>"
1821        } else {
1822            # No keywords for this letter
1823            lappend keyheader $a
1824        }
1825    }
1826    set keyheader "<H3>[join $keyheader " |\n"]</H3>"
1827    puts $keyfp $keyheader
1828    foreach a $letters {
1829        set keys [array names manual "keyword-\[[string totitle $a$a]\]*"]
1830        if {![llength $keys]} {
1831            continue
1832        }
1833        # Per-keyword page
1834        set afp [open $html/Keywords/$a.htm w]
1835        puts $afp [htmlhead "$tcltkdesc Keywords - $a" \
1836                       "$tcltkdesc Keywords - $a" \
1837                       $overall_title "../[indexfile]"]
1838        puts $afp $keyheader
1839        puts $afp "<DL class=\"keylist\">"
1840        foreach k [lsort -dictionary $keys] {
1841            set k [string range $k 8 end]
1842            puts $afp "<DT><A NAME=\"$k\">$k</A></DT>"
1843            puts $afp "<DD>"
1844            set refs {}
1845            foreach man $manual(keyword-$k) {
1846                set name [lindex $man 0]
1847                set file [lindex $man 1]
1848                lappend refs "<A HREF=\"../$file\">$name</A>"
1849            }
1850            puts $afp "[join $refs {, }]</DD>"
1851        }
1852        puts $afp "</DL>"
1853        # insert merged copyrights
1854        puts $afp [copyout $manual(merge-copyrights)]
1855        puts $afp "</BODY></HTML>"
1856        close $afp
1857    }
1858    # insert merged copyrights
1859    puts $keyfp [copyout $manual(merge-copyrights)]
1860    puts $keyfp "</BODY></HTML>"
1861    close $keyfp
1862
1863    ##
1864    ## finish off short table of contents
1865    ##
1866    puts $manual(short-toc-fp) "<DT><A HREF=\"Keywords/[indexfile]\">Keywords</A><DD>The keywords from the $tcltkdesc man pages."
1867    puts $manual(short-toc-fp) "</DL>"
1868    # insert merged copyrights
1869    puts $manual(short-toc-fp) [copyout $manual(merge-copyrights)]
1870    puts $manual(short-toc-fp) "</BODY></HTML>"
1871    close $manual(short-toc-fp)
1872
1873    ##
1874    ## output man pages
1875    ##
1876    unset manual(section)
1877    foreach path $manual(all-pages) {
1878        set manual(wing-file) [file dirname $path]
1879        set manual(tail) [file tail $path]
1880        set manual(name) [file root $manual(tail)]
1881        set text $manual(output-$manual(wing-file)-$manual(name))
1882        set ntext 0
1883        foreach item $text {
1884            incr ntext [llength [split $item \n]]
1885            incr ntext
1886        }
1887        set toc $manual(toc-$manual(wing-file)-$manual(name))
1888        set ntoc 0
1889        foreach item $toc {
1890            incr ntoc [llength [split $item \n]]
1891            incr ntoc
1892        }
1893        puts stderr "rescanning page $manual(name) $ntoc/$ntext"
1894        set outfd [open $html/$manual(wing-file)/$manual(name).htm w]
1895        puts $outfd [htmlhead "$manual($manual(name)-title)" \
1896                $manual(name) $manual(wing-file) "[indexfile]" \
1897                $overall_title "../[indexfile]"]
1898        if {
1899            (($ntext > 60) && ($ntoc > 32)) || $manual(tail) in {
1900                Hash LinkVar SetVar TraceVar ConfigWidg CrtImgType CrtItemType
1901                CrtPhImgFmt DoOneEvent GetBitmap GetColor GetCursor GetDash
1902                GetJustify GetPixels GetVisual ParseArgv QueueEvent
1903            }
1904        } then {
1905            foreach item $toc {
1906                puts $outfd $item
1907            }
1908        }
1909        foreach item $text {
1910            puts $outfd [insert-cross-references $item]
1911        }
1912        puts $outfd "</BODY></HTML>"
1913        close $outfd
1914    }
1915    return {}
1916}
1917
1918parse_command_line
1919
1920set tcltkdesc ""; set cmdesc ""; set appdir ""
1921if {$build_tcl} {
1922    append tcltkdesc "Tcl"
1923    append cmdesc "Tcl"
1924    append appdir "$tcldir"
1925}
1926if {$build_tcl && $build_tk} {
1927    append tcltkdesc "/"
1928    append cmdesc " and "
1929    append appdir ","
1930}
1931if {$build_tk} {
1932    append tcltkdesc "Tk"
1933    append cmdesc "Tk"
1934    append appdir "$tkdir"
1935}
1936
1937set usercmddesc "The interpreters which implement $cmdesc."
1938set tclcmddesc {The commands which the <B>tclsh</B> interpreter implements.}
1939set tkcmddesc {The additional commands which the <B>wish</B> interpreter implements.}
1940set tcllibdesc {The C functions which a Tcl extended C program may use.}
1941set tklibdesc {The additional C functions which a Tk extended C program may use.}
1942
1943if {1} {
1944    if {[catch {
1945        make-man-pages $webdir \
1946            "$tcltkdir/{$appdir}/doc/*.1 \"$tcltkdesc Applications\" UserCmd {$usercmddesc}" \
1947            [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.n {Tcl Commands} TclCmd {$tclcmddesc}" : ""}] \
1948            [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.n {Tk Commands} TkCmd {$tkcmddesc}" : ""}] \
1949            [expr {$build_tcl ? "$tcltkdir/$tcldir/doc/*.3 {Tcl Library} TclLib {$tcllibdesc}" : ""}] \
1950            [expr {$build_tk ? "$tcltkdir/$tkdir/doc/*.3 {Tk Library} TkLib {$tklibdesc}" : ""}]
1951    } error]} {
1952        puts $error\n$errorInfo
1953    }
1954}
Note: See TracBrowser for help on using the repository browser.