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

通讯编程

开发平台:

Visual C++

  1. # man2html2.tcl --
  2. #
  3. # This file defines procedures that are used during the second pass of the
  4. # man page to html conversion process. It is sourced by man2html.tcl.
  5. #
  6. # Copyright (c) 1996 by Sun Microsystems, Inc.
  7. #
  8. # SCCS: @(#) man2html2.tcl 1.2 96/03/21 10:48:30
  9. #
  10. # Global variables used by these scripts:
  11. #
  12. # NAME_file - array indexed by NAME and containing file names used
  13. # for hyperlinks.
  14. #
  15. # textState - state variable defining action of 'text' proc.
  16. #
  17. # nestStk - stack oriented list containing currently active
  18. # HTML tags (UL, OL, DL). Local to 'nest' proc.
  19. #
  20. # inDT - set by 'TPmacro', cleared by 'newline'. Used to insert
  21. # the <DT> tag while in a dictionary list <DL>.
  22. #
  23. # curFont - Name of special font that is currently in
  24. # use.  Null means the default paragraph font
  25. # is being used.
  26. #
  27. # file - Where to output the generated HTML.
  28. #
  29. # fontStart - Array to map font names to starting sequences.
  30. #
  31. # fontEnd - Array to map font names to ending sequences.
  32. #
  33. # noFillCount - Non-zero means don't fill the next $noFillCount
  34. # lines: force a line break at each newline.  Zero
  35. # means filling is enabled, so don't output line
  36. # breaks for each newline.
  37. #
  38. # footer - info inserted at bottom of each page. Normally read
  39. # from the xref.tcl file
  40. # initGlobals --
  41. #
  42. # This procedure is invoked to set the initial values of all of the
  43. # global variables, before processing a man page.
  44. #
  45. # Arguments:
  46. # None.
  47. proc initGlobals {} {
  48.     global file noFillCount textState
  49.     global fontStart fontEnd curFont inPRE charCnt
  50.     nest init
  51.     set inPRE 0
  52.     set textState 0
  53.     set curFont ""
  54.     set fontStart(Code) "<B>"
  55.     set fontStart(Emphasis) "<I>"
  56.     set fontEnd(Code) "</B>"
  57.     set fontEnd(Emphasis) "</I>"
  58.     set noFillCount 0
  59.     set charCnt 0
  60.     setTabs 0.5i
  61. }
  62. # beginFont --
  63. #
  64. # Arranges for future text to use a special font, rather than
  65. # the default paragraph font.
  66. #
  67. # Arguments:
  68. # font - Name of new font to use.
  69. proc beginFont font {
  70.     global curFont file fontStart
  71.     if {$curFont == $font} {
  72. return
  73.     }
  74.     endFont
  75.     puts -nonewline $file $fontStart($font)
  76.     set curFont $font
  77. }
  78. # endFont --
  79. #
  80. # Reverts to the default font for the paragraph type.
  81. #
  82. # Arguments:
  83. # None.
  84. proc endFont {} {
  85.     global curFont file fontEnd
  86.     if {$curFont != ""} {
  87.     puts -nonewline $file $fontEnd($curFont)
  88.     set curFont ""
  89.     }
  90. }
  91. # text --
  92. #
  93. # This procedure adds text to the current paragraph.  If this is
  94. # the first text in the paragraph then header information for the
  95. # paragraph is output before the text.
  96. #
  97. # Arguments:
  98. # string - Text to output in the paragraph.
  99. proc text string {
  100.     global file textState inDT charCnt
  101.     set pos [string first "t" $string]
  102.     if {$pos >= 0} {
  103.      text [string range $string 0 [expr $pos-1]]
  104.      tab
  105.      text [string range $string [expr $pos+1] end]
  106. return    
  107.     }
  108.     incr charCnt [string length $string]
  109.     regsub -all {&} $string {&amp;}  string
  110.     regsub -all {<} $string {&lt;}  string
  111.     regsub -all {>} $string {&gt;}  string
  112.     regsub -all {"} $string {&quot;}  string
  113.     switch $textState {
  114. REF { 
  115.     if {$inDT == {}} {
  116. set string [insertRef $string]
  117.     }
  118. }
  119. SEE { 
  120.     global NAME_file
  121.     foreach i [split $string] {
  122. if ![regexp -nocase {^[a-z_]+} [string trim $i] i ] {
  123. #      puts "Warning: $i in SEE ALSO not found"
  124.     continue
  125. }
  126. if ![catch {set ref $NAME_file($i)} ] {
  127.     regsub $i $string "<A HREF="$ref.html">$i</A>" string
  128. }
  129.     }
  130. }
  131.     }
  132.     puts -nonewline $file "$string"
  133. }
  134. # insertRef --
  135. #
  136. #
  137. # Arguments:
  138. # string - Text to output in the paragraph.
  139. proc insertRef string {
  140.     global NAME_file self
  141.     set path {}
  142.     if ![catch {set ref $NAME_file([string trim $string])} ] {
  143. if {"$ref.html" != $self} {
  144.     set string "<A HREF="${path}$ref.html">$string</A>"
  145. #     puts "insertRef: $self $ref.html ---$string--"
  146. }
  147.     }
  148.     return $string
  149. }
  150. # macro --
  151. #
  152. # This procedure is invoked to process macro invocations that start
  153. # with "." (instead of ').
  154. #
  155. # Arguments:
  156. # name - The name of the macro (without the ".").
  157. # args - Any additional arguments to the macro.
  158. proc macro {name args} {
  159.     switch $name {
  160. AP {
  161.     if {[llength $args] != 3} {
  162. puts stderr "Bad .AP macro: .$name [join $args " "]"
  163.     }
  164.     setTabs {1.25i 2.5i 3.75i}
  165.     TPmacro {}
  166.     font B
  167.     text "[lindex $args 0]  "
  168.     font I
  169.     text "[lindex $args 1]"
  170.     font R
  171.     text " ([lindex $args 2])"
  172.     newline
  173. }
  174. AS {} ;# next page and previous page
  175. br {
  176.     lineBreak
  177. }
  178. BS {}
  179. BE {}
  180. CE {
  181.     global file noFillCount inPRE
  182.     puts $file </PRE></BLOCKQUOTE>
  183.     set inPRE 0
  184. }
  185. CS { ;# code section
  186.     global file noFillCount inPRE
  187.     puts -nonewline $file <BLOCKQUOTE><PRE>
  188.     set inPRE 1
  189. }
  190. DE {
  191.     global file noFillCount inPRE
  192.     puts $file </PRE></BLOCKQUOTE>
  193.     set inPRE 0
  194.     set noFillCount 0
  195. }
  196. DS {
  197.     global file noFillCount inPRE
  198.     puts -nonewline $file <BLOCKQUOTE><PRE>
  199.     set noFillCount 10000000
  200.     set inPRE 1
  201. }
  202. fi {
  203.     global noFillCount
  204.     set noFillCount 0
  205. }
  206. IP {
  207.     IPmacro $args
  208. }
  209. LP {
  210.     nest decr
  211.     nest incr
  212.     newPara
  213. }
  214. ne {
  215. }
  216. nf {
  217.     global noFillCount
  218.     set noFillCount 1000000
  219. }
  220. OP {
  221.     global inDT file inPRE 
  222.     if {[llength $args] != 3} {
  223. puts stderr "Bad .OP macro: .$name [join $args " "]"
  224.     }
  225.     nest para DL DT
  226.     set inPRE 1
  227.     puts -nonewline $file <PRE>
  228.     setTabs 4c
  229.     text "Command-Line Name:"
  230.     tab
  231.     font B
  232.     set x [lindex $args 0]
  233.     regsub -all {\-} $x - x
  234.     text $x
  235.     newline
  236.     font R
  237.     text "Database Name:"
  238.     tab
  239.     font B
  240.     text [lindex $args 1]
  241.     newline
  242.     font R
  243.     text "Database Class:"
  244.     tab
  245.     font B
  246.     text [lindex $args 2]
  247.     font R
  248.     puts -nonewline $file </PRE>
  249.     set inDT "n<DD>" ;# next newline writes inDT 
  250.     set inPRE 0
  251.     newline
  252. }
  253. PP {
  254.     nest decr
  255.     nest incr
  256.     newPara
  257. }
  258. RE {
  259.     nest decr    
  260. }
  261. RS {
  262.     nest incr
  263. }
  264. SE {
  265.     global noFillCount textState inPRE file
  266.     font R
  267.     puts -nonewline $file </PRE>
  268.     set inPRE 0
  269.     set noFillCount 0
  270.     nest reset
  271.     newPara
  272.     text "See the "
  273.     font B
  274.     set temp $textState
  275.     set textState REF
  276.     text options
  277.     set textState $temp
  278.     font R
  279.     text " manual entry for detailed descriptions of the above options."
  280. }
  281. SH {
  282.     SHmacro $args
  283. }
  284. SO {
  285.     global noFillCount inPRE file
  286.     SHmacro "STANDARD OPTIONS"
  287.     setTabs {4c 8c 12c}
  288.     set noFillCount 1000000
  289.     puts -nonewline $file <PRE>
  290.     set inPRE 1
  291.     font B
  292. }
  293. so {
  294.     if {$args != "man.macros"} {
  295. puts stderr "Unknown macro: .$name [join $args " "]"
  296.     }
  297. }
  298. sp { ;# needs work
  299.     if {$args == ""} {
  300. set count 1
  301.     } else {
  302. set count [lindex $args 0]
  303.     }
  304.     while {$count > 0} {
  305. lineBreak
  306. incr count -1
  307.     }
  308. }
  309. ta {
  310.     setTabs $args
  311. }
  312. TH {
  313.     THmacro $args
  314. }
  315. TP {
  316.     TPmacro $args
  317. }
  318. UL { ;# underline
  319.     global file
  320.     puts -nonewline $file "<B><U>"
  321.     text [lindex $args 0]
  322.     puts -nonewline $file "</U></B>"
  323.     if {[llength $args] == 2} {
  324. text [lindex $args 1]
  325.     }
  326. }
  327. VE {
  328. #     global file
  329. #     puts -nonewline $file "</FONT>"
  330. }
  331. VS {
  332. #     global file
  333. #     if {[llength $args] > 0} {
  334. # puts -nonewline $file "<BR>"
  335. #     }
  336. #     puts -nonewline $file "<FONT COLOR="GREEN">"
  337. }
  338. default {
  339.     puts stderr "Unknown macro: .$name [join $args " "]"
  340. }
  341.     }
  342. # global nestStk; puts "$name [format "%-20s" $args] $nestStk"
  343. # flush stdout; flush stderr
  344. }
  345. # font --
  346. #
  347. # This procedure is invoked to handle font changes in the text
  348. # being output.
  349. #
  350. # Arguments:
  351. # type - Type of font: R, I, B, or S.
  352. proc font type {
  353.     global textState
  354.     switch $type {
  355. P -
  356. R {
  357.     endFont
  358.     if {$textState == "REF"} {
  359. set textState INSERT
  360.     }
  361. }
  362. B {
  363.     beginFont Code
  364.     if {$textState == "INSERT"} {
  365. set textState REF
  366.     }
  367. }
  368. I {
  369.     beginFont Emphasis
  370. }
  371. S {
  372. }
  373. default {
  374.     puts stderr "Unknown font: $type"
  375. }
  376.     }
  377. }
  378. # formattedText --
  379. #
  380. # Insert a text string that may also have fB-style font changes
  381. # and a few other backslash sequences in it.
  382. #
  383. # Arguments:
  384. # text - Text to insert.
  385. proc formattedText text {
  386. # puts "formattedText: $text"
  387.     while {$text != ""} {
  388. set index [string first \ $text]
  389. if {$index < 0} {
  390.     text $text
  391.     return
  392. }
  393. text [string range $text 0 [expr $index-1]]
  394. set c [string index $text [expr $index+1]]
  395. switch -- $c {
  396.     f {
  397. font [string index $text [expr $index+2]]
  398. set text [string range $text [expr $index+3] end]
  399.     }
  400.     e {
  401. text \
  402. set text [string range $text [expr $index+2] end]
  403.     }
  404.     - {
  405. dash
  406. set text [string range $text [expr $index+2] end]
  407.     }
  408.     | {
  409. set text [string range $text [expr $index+2] end]
  410.     }
  411.     default {
  412. puts stderr "Unknown sequence: \$c"
  413. set text [string range $text [expr $index+2] end]
  414.     }
  415. }
  416.     }
  417. }
  418. # dash --
  419. #
  420. # This procedure is invoked to handle dash characters ("-" in
  421. # troff).  It outputs a special dash character.
  422. #
  423. # Arguments:
  424. # None.
  425. proc dash {} {
  426.     global textState charCnt
  427.     if {$textState == "NAME"} {
  428.      set textState 0
  429.     }
  430.     incr charCnt
  431.     text "-"
  432. }
  433. # tab --
  434. #
  435. # This procedure is invoked to handle tabs in the troff input.
  436. # Right now it does nothing.
  437. #
  438. # Arguments:
  439. # None.
  440. proc tab {} {
  441.     global inPRE charCnt tabString
  442. # ? charCnt
  443.     if {$inPRE == 1} {
  444. set pos [expr $charCnt % [string length $tabString] ]
  445. set spaces [string first "1" [string range $tabString $pos end] ]
  446. text [format "%*s" [incr spaces] " "]
  447.     } else {
  448. # puts "tab: found tab outside of <PRE> block"
  449.     }
  450. }
  451. # setTabs --
  452. #
  453. # This procedure handles the ".ta" macro, which sets tab stops.
  454. #
  455. # Arguments:
  456. # tabList - List of tab stops, each consisting of a number
  457. # followed by "i" (inch) or "c" (cm).
  458. proc setTabs {tabList} {
  459.     global file breakPending tabString
  460. # puts "setTabs: --$tabList--"
  461.     set last 0
  462.     set tabString {}
  463.     set charsPerInch 14.
  464.     set numTabs [llength $tabList]
  465.     foreach arg $tabList {
  466. if {[scan $arg "%f%s" distance units] != 2} {
  467.     puts stderr "bad distance "$arg""
  468.     return 0
  469.      }
  470. switch -- $units {
  471.     c {
  472. set distance [expr $distance * $charsPerInch / 2.54 ]
  473.     }
  474.     i {
  475. set distance [expr $distance * $charsPerInch]
  476.     }
  477.     default {
  478. puts stderr "bad units in distance "$arg""
  479. continue
  480.     }
  481.      }
  482. # ? distance
  483.      lappend tabString [format "%*s1" [expr round($distance-$last-1)] " "]
  484.      set last $distance
  485.     }
  486.     set tabString [join $tabString {}]
  487. # puts "setTabs: --$tabString--"
  488. }
  489. # lineBreak --
  490. #
  491. # Generates a line break in the HTML output.
  492. #
  493. # Arguments:
  494. # None.
  495. proc lineBreak {} {
  496.     global file inPRE
  497.     puts $file "<BR>"
  498. }
  499. # newline --
  500. #
  501. # This procedure is invoked to handle newlines in the troff input.
  502. # It outputs either a space character or a newline character, depending
  503. # on fill mode.
  504. #
  505. # Arguments:
  506. # None.
  507. proc newline {} {
  508.     global noFillCount file inDT inPRE charCnt
  509.     if {$inDT != {} } {
  510.      puts $file "n$inDT"
  511.      set inDT {}
  512.     } elseif {$noFillCount == 0 || $inPRE == 1} {
  513. puts $file {}
  514.     } else {
  515. lineBreak
  516. incr noFillCount -1
  517.     }
  518.     set charCnt 0
  519. }
  520. # char --
  521. #
  522. # This procedure is called to handle a special character.
  523. #
  524. # Arguments:
  525. # name - Special character named in troff x or (xx construct.
  526. proc char name {
  527.     global file charCnt
  528.     incr charCnt
  529. # puts "char: $name"
  530.     switch -exact $name {
  531. \0 { ;#  
  532.     puts -nonewline $file " "
  533. }
  534. \\ { ;#  
  535.     puts -nonewline $file "\"
  536. }
  537. \(+- {  ;#  +/-
  538.     puts -nonewline $file "&#177;"
  539. }
  540. \% {} ;#  %
  541. \| { ;#  |
  542. }
  543. default {
  544.     puts stderr "Unknown character: $name"
  545. }
  546.     }
  547. }
  548. # macro2 --
  549. #
  550. # This procedure handles macros that are invoked with a leading "'"
  551. # character instead of space.  Right now it just generates an
  552. # error diagnostic.
  553. #
  554. # Arguments:
  555. # name - The name of the macro (without the ".").
  556. # args - Any additional arguments to the macro.
  557. proc macro2 {name args} {
  558.     puts stderr "Unknown macro: '$name [join $args " "]"
  559. }
  560. # SHmacro --
  561. #
  562. # Subsection head; handles the .SH macro.
  563. #
  564. # Arguments:
  565. # name - Section name.
  566. proc SHmacro argList {
  567.     global file noFillCount textState charCnt
  568.     set args [join $argList " "]
  569.     if {[llength $argList] < 1} {
  570. puts stderr "Bad .SH macro: .$name $args"
  571.     }
  572.     set noFillCount 0
  573.     nest reset
  574.     puts -nonewline $file "<H3>"
  575.     text $args
  576.     puts $file "</H3>"
  577. # ? args textState
  578.     # control what the text proc does with text
  579.     
  580.     switch $args {
  581. NAME {set textState NAME}
  582. DESCRIPTION {set textState INSERT}
  583. INTRODUCTION {set textState INSERT}
  584. "WIDGET-SPECIFIC OPTIONS" {set textState INSERT}
  585. "SEE ALSO" {set textState SEE}
  586. KEYWORDS {set textState 0}
  587.     }
  588.     set charCnt 0
  589. }
  590. # IPmacro --
  591. #
  592. # This procedure is invoked to handle ".IP" macros, which may take any
  593. # of the following forms:
  594. #
  595. # .IP [1] Translate to a "1Step" paragraph.
  596. # .IP [x] (x > 1) Translate to a "Step" paragraph.
  597. # .IP Translate to a "Bullet" paragraph.
  598. # .IP text count Translate to a FirstBody paragraph with special
  599. # indent and tab stop based on "count", and tab after
  600. # "text".
  601. #
  602. # Arguments:
  603. # argList - List of arguments to the .IP macro.
  604. #
  605. # HTML limitations: 'count' in '.IP text count' is ignored.
  606. proc IPmacro argList {
  607.     global file
  608.     setTabs 0.5i
  609.     set length [llength $argList]
  610.     if {$length == 0} {
  611.      nest para UL LI
  612. return
  613.     }
  614.     if {$length == 1} {
  615.      nest para OL LI
  616.     return
  617. }
  618.     if {$length > 1} {
  619.      nest para DL DT
  620.     formattedText [lindex $argList 0]
  621.     puts $file "n<DD>"
  622.     return
  623.     }
  624.     puts stderr "Bad .IP macro: .IP [join $argList " "]"
  625. }
  626. # TPmacro --
  627. #
  628. # This procedure is invoked to handle ".TP" macros, which may take any
  629. # of the following forms:
  630. #
  631. # .TP x Translate to an indented paragraph with the
  632. #  specified indent (in 100 twip units).
  633. # .TP Translate to an indented paragraph with
  634. #  default indent.
  635. #
  636. # Arguments:
  637. # argList - List of arguments to the .IP macro.
  638. #
  639. # HTML limitations: 'x' in '.TP x' is ignored.
  640. proc TPmacro {argList} {
  641.     global inDT
  642.     nest para DL DT
  643.     set inDT "n<DD>" ;# next newline writes inDT 
  644.     setTabs 0.5i
  645. }
  646. # THmacro --
  647. #
  648. # This procedure handles the .TH macro.  It generates the non-scrolling
  649. # header section for a given man page, and enters information into the
  650. # table of contents.  The .TH macro has the following form:
  651. #
  652. # .TH name section date footer header
  653. #
  654. # Arguments:
  655. # argList - List of arguments to the .TH macro.
  656. proc THmacro {argList} {
  657.     global file
  658.     if {[llength $argList] != 5} {
  659. set args [join $argList " "]
  660. puts stderr "Bad .TH macro: .$name $args"
  661.     }
  662.     set name  [lindex $argList 0] ;# Tcl_UpVar
  663.     set page  [lindex $argList 1] ;# 3
  664.     set vers  [lindex $argList 2] ;# 7.4
  665.     set lib   [lindex $argList 3] ;# Tcl
  666.     set pname [lindex $argList 4] ;# {Tcl Library Procedures}
  667.     puts -nonewline $file "<HTML><HEAD><TITLE>"
  668.     text "$lib - $name ($page)"
  669.     puts $file "</TITLE></HEAD><BODY>n"
  670.     
  671.     puts -nonewline $file "<H1><CENTER>"
  672.     text $pname
  673.     puts $file "</CENTER></H1>n"
  674. }
  675. # newPara --
  676. #
  677. # This procedure sets the left and hanging indents for a line.
  678. # Indents are specified in units of inches or centimeters, and are
  679. # relative to the current nesting level and left margin.
  680. #
  681. # Arguments:
  682. # None
  683. proc newPara {} {
  684.     global file nestStk
  685.     if {[lindex $nestStk end] != "NEW" } {
  686. nest decr    
  687.     }
  688.     puts -nonewline $file "<P>"
  689. }
  690. # nest --
  691. #
  692. # This procedure takes care of inserting the tags associated with the
  693. # IP, TP, RS, RE, LP and PP macros. Only 'nest para' takes arguments.
  694. #
  695. # Arguments:
  696. # op - operation: para, incr, decr, reset, init
  697. # listStart - begin list tag: OL, UL, DL.
  698. # listItem - item tag:       LI, LI, DT.
  699. proc nest {op {listStart "NEW"} {listItem {} } } {
  700.     global file nestStk inDT charCnt
  701. # puts "nest: $op $listStart $listItem"
  702.     switch $op {
  703. para {
  704.     set top [lindex $nestStk end]
  705.     if {$top == "NEW" } {
  706. set nestStk [lreplace $nestStk end end $listStart]
  707. puts $file "<$listStart>"
  708.     } elseif {$top != $listStart} {
  709. puts stderr "nest para: bad stack"
  710. exit 1
  711.     }
  712.     puts $file "n<$listItem>"
  713.     set charCnt 0
  714. }
  715. incr {
  716.    lappend nestStk NEW
  717. }
  718. decr {
  719.     if {[llength $nestStk] == 0} {
  720. puts stderr "nest error: nest length is zero"
  721. set nestStk NEW
  722.     }
  723.     set tag [lindex $nestStk end]
  724.     if {$tag != "NEW"} {
  725. puts $file "</$tag>"
  726.     }
  727.     set nestStk [lreplace $nestStk end end]
  728. }
  729. reset {
  730.     while {[llength $nestStk] > 0} {
  731. nest decr
  732.     }
  733.     set nestStk NEW
  734. }
  735. init {
  736.     set nestStk NEW
  737.     set inDT {}
  738. }
  739.     }
  740.     set charCnt 0
  741. }
  742. # do --
  743. #
  744. # This is the toplevel procedure that translates a man page
  745. # to Frame.  It runs the man2tcl program to turn the man page
  746. # into a script, then it evals that script.
  747. #
  748. # Arguments:
  749. # fileName - Name of the file to translate.
  750. proc do fileName {
  751.     global file self html_dir package footer
  752.     set self "[file tail $fileName].html"
  753.     set file [open "$html_dir/$package/$self" w]
  754.     puts "  Pass 2 -- $fileName"
  755.     flush stdout
  756.     initGlobals
  757.     if [catch {eval [exec man2tcl [glob $fileName]]} msg] {
  758. global errorInfo
  759. puts stderr $msg
  760. puts "in"
  761. puts stderr $errorInfo
  762. exit 1
  763.     }
  764.     nest reset
  765.     puts $file $footer
  766.     puts $file "</BODY></HTML>"
  767.     close $file
  768. }