4 # Program to extract help files from TCL manual pages or TCL script files.
5 # The help directories are built as a hierarchical tree of subjects and help
8 #------------------------------------------------------------------------------
9 # Copyright 1992 Karl Lehenbauer and Mark Diekhans.
11 # Permission to use, copy, modify, and distribute this software and its
12 # documentation for any purpose and without fee is hereby granted, provided
13 # that the above copyright notice appear in all copies. Karl Lehenbauer and
14 # Mark Diekhans make no representations about the suitability of this
15 # software for any purpose. It is provided "as is" without express or
17 #------------------------------------------------------------------------------
18 # $Id: buildhelp.tcl,v 2.1 1992/10/25 17:07:40 markd Exp $
19 #------------------------------------------------------------------------------
21 # For nroff man pages, the areas of text to extract are delimited with:
23 # '@help: subjectdir/helpfile
26 # start in column one. The text between these markers is extracted and stored
27 # in help/subjectdir/help. The file must not exists, this is done to enforced
28 # cleaning out the directories before help file generation is started, thus
29 # removing any stale files. The extracted text is run through:
31 # nroff -man|col -xb {col -b on BSD derived systems}
33 # If there is other text to include in the helpfile, but not in the manual
34 # page, the text, along with nroff formatting commands, may be included using:
36 # '@:Other text to include in the help page.
38 # A entry in the brief file, used by apropos my be included by:
40 # '@brief: Short, one line description
42 # These brief request must occur with in the bounds of a help section.
44 # If some header text, such as nroff macros, need to be preappended to the
45 # text streem before it is run through nroff, then that text can be bracketed
51 # If multiple header blocks are encountered, they will all be preappended.
53 # For TCL script files, which are indentified because they end in ".tcl",
54 # the text to be extracted is delimited by:
56 # #@help: subjectdir/helpfile
59 # And brief lines are in the form:
61 # #@brief: Short, one line description
63 # The only processing done on text extracted from .tcl files it to replace
64 # the # in column one with a space.
67 #-----------------------------------------------------------------------------
69 # To run this program:
71 # tcl buildhelp.tcl [-m mergeTree] -b brief.brf helpDir file-1 file-2 ...
73 # o -m mergeTree is a tree of help code, plus a brief file to merge with the
74 # help files that are to be extracted. This will become part of the new
75 # help tree. Used to merge in the documentation from UCB Tcl.
76 # o -b specified the name of the brief file to create form the @brief entries.
77 # It must have an extension of ".brf".
78 # o helpDir is the help tree root directory. helpDir should exists, but any
79 # subdirectories that don't exists will be created. helpDir should be
80 # cleaned up before the start of manual page generation, as this program
81 # will not overwrite existing files.
82 # o file-n are the nroff manual pages (.man) or .tcl or .tlib files to extract
83 # the help files from.
85 #-----------------------------------------------------------------------------
87 #-----------------------------------------------------------------------------
88 # Truncate a file name of a help file if the system does not support long
89 # file names. If the name starts with `Tcl_', then this prefix is removed.
90 # If the name is then over 14 characters, it is truncated to 14 charactes
92 proc TruncFileName
{pathName
} {
93 global G_truncFileNames
95 if {!$G_truncFileNames} {
97 set fileName
[file tail
$pathName]
98 if {"[crange $fileName 0 3]" == "Tcl_"} {
99 set fileName
[crange
$fileName 4 end
]}
100 set fileName
[crange
$fileName 0 13]
101 return "[file dirname $pathName]/$fileName"
104 #-----------------------------------------------------------------------------
105 # Proc to ensure that all directories for the specified file path exists,
106 # and if they don't create them. Don't use -path so we can set the
109 proc EnsureDirs
{filePath
} {
110 set dirPath
[file dirname
$filePath]
111 if [file exists
$dirPath] return
112 foreach dir
[split $dirPath /] {
114 set partPath
[join $dirList /]
115 if [file exists
$partPath] continue
118 chmod u
=rwx
,go
=rx
$partPath
123 #-----------------------------------------------------------------------------
125 # Proc to extract nroff text to use as a header to all pass to nroff when
126 # processing a help file.
127 # manPageFH - The file handle of the manual page.
130 proc ExtractNroffHeader
{manPageFH
} {
132 while {[gets $manPageFH manLine
] >= 0} {
133 if {[string first
"'@endheader" $manLine] == 0} {
136 if {[string first
"'@:" $manLine] == 0} {
137 set manLine
[csubstr manLine
3 end
]
139 append nroffHeader
"$manLine\n"
143 #-----------------------------------------------------------------------------
145 # Proc to extract a nroff help file when it is located in the text.
146 # manPageFH - The file handle of the manual page.
147 # manLine - The '@help: line starting the data to extract.
150 proc ExtractNroffHelp
{manPageFH manLine
} {
151 global G_helpDir nroffHeader G_briefHelpFH G_colArgs
153 set helpName
[string trim
[csubstr
$manLine 7 end
]]
154 set helpFile
[TruncFileName
"$G_helpDir/$helpName"]
155 if {[file exists
$helpFile]} {
156 error "Help file already exists: $helpFile"}
158 set helpFH
[open "| nroff -man | col $G_colArgs > $helpFile" w
]
159 echo
" creating help file $helpName"
161 # Nroff commands from .TH macro to get the formatting right. The `\n'
162 # are newline separators to output, the `\\n' become `\n' in the text.
164 puts $helpFH ".ad b\n.PD\n.nrIN \\n()Mu\n.nr)R 0\n.nr)I \\n()Mu"
165 puts $helpFH ".nr)R 0\n.\}E\n.DT\n.na\n.nh"
166 puts $helpFH $nroffHeader
168 while {[gets $manPageFH manLine
] >= 0} {
169 if {[string first
"'@endhelp" $manLine] == 0} {
172 if {[string first
"'@brief:" $manLine] == 0} {
174 error {Duplicate
"'@brief" entry"}
177 puts $G_briefHelpFH "$helpName\t[csubstr
$manLine 8 end
]"
180 if {[string first "'
@:" $manLine] == 0} {
181 set manLine [csubstr $manLine 3 end]
183 if {[string first "'
@help
" $manLine] == 0} {
184 error {"'
@help
" found within another help section"}
186 puts $helpFH $manLine
189 chmod a-w
,a
+r
$helpFile
192 #-----------------------------------------------------------------------------
194 # Proc to extract a tcl script help file when it is located in the text.
195 # ScriptPageFH - The file handle of the .tcl file.
196 # ScriptLine - The #@help: line starting the data to extract.
199 proc ExtractScriptHelp
{ScriptPageFH ScriptLine
} {
200 global G_helpDir G_briefHelpFH
201 set helpName
[string trim
[csubstr
$ScriptLine 7 end
]]
202 set helpFile
"$G_helpDir/$helpName"
203 if {[file exists
$helpFile]} {
204 error "Help file already exists: $helpFile"}
206 set helpFH
[open $helpFile w
]
207 echo
" creating help file $helpName"
209 while {[gets $ScriptPageFH ScriptLine
] >= 0} {
210 if {[string first
"#@endhelp" $ScriptLine] == 0} {
213 if {[string first
"#@brief:" $ScriptLine] == 0} {
215 error {Duplicate
"#@brief" entry"}
218 puts $G_briefHelpFH "$helpName\t[csubstr
$ScriptLine 8 end
]"
221 if {[string first "#@help" $ScriptLine] == 0} {
222 error {"#@help" found within another help section
"}
224 if {[clength $ScriptLine] > 1} {
225 set ScriptLine " [csubstr
$ScriptLine 1 end
]"
229 puts $helpFH $ScriptLine
232 chmod a-w,a+r $helpFile
235 #-----------------------------------------------------------------------------
237 # Proc to scan a nroff manual file looking for the start of a help text
238 # sections and extracting those sections.
239 # pathName - Full path name of file to extract documentation from.
242 proc ProcessNroffFile {pathName} {
243 global G_nroffScanCT G_scriptScanCT nroffHeader
245 set fileName [file tail $pathName]
248 set manPageFH [open $pathName r]
249 echo " scanning
$pathName"
250 set matchInfo(fileName) [file tail $pathName]
251 scanfile $G_nroffScanCT $manPageFH
255 #-----------------------------------------------------------------------------
257 # Proc to scan a Tcl script file looking for the start of a
258 # help text sections and extracting those sections.
259 # pathName - Full path name of file to extract documentation from.
262 proc ProcessTclScript {pathName} {
263 global G_scriptScanCT nroffHeader
265 set scriptFH [open "$pathName" r]
267 echo " scanning
$pathName"
268 set matchInfo(fileName) [file tail $pathName]
269 scanfile $G_scriptScanCT $scriptFH
273 #-----------------------------------------------------------------------------
274 # Proc to copy the help merge tree, excluding the brief file and RCS files
277 proc CopyMergeTree {helpDirPath mergeTree} {
278 if {"[cindex
$helpDirPath 0]" != "/"} {
279 set helpDirPath "[pwd]/$helpDirPath"
286 for_recursive_glob mergeFile {.} {
287 if [string match "*/RCS
/*" $mergeFile] continue
289 set helpFile "$helpDirPath/$mergeFile"
290 if [file isdirectory $mergeFile] continue
292 if {[file exists $helpFile]} {
293 error "Help
file already exists
: $helpFile"}
295 set inFH [open $mergeFile r]
296 set outFH [open $helpFile w]
297 copyfile $inFH $outFH
300 chmod a-w,a+r $helpFile
305 #-----------------------------------------------------------------------------
306 # GenerateHelp: main procedure. Generates help from specified files.
307 # helpDirPath - Directory were the help files go.
308 # mergeTree - Help file tree to merge with the extracted help files.
309 # briefFile - The name of the brief file to create.
310 # sourceFiles - List of files to extract help files from.
312 proc GenerateHelp {helpDirPath briefFile mergeTree sourceFiles} {
313 global G_helpDir G_truncFileNames G_nroffScanCT
314 global G_scriptScanCT G_briefHelpFH G_colArgs
317 echo "Begin building help tree
"
319 # Determine version of col command to use (no -x on BSD)
320 if {[system {col -bx </dev/null >/dev/null 2>&1}] != 0} {
325 set G_helpDir [glob $helpDirPath]
327 if {![file isdirectory $G_helpDir]} {
328 error [concat "$G_helpDir is not a directory or does not exist.
"
329 "This should be the help root directory
"]
332 set status [catch {set tmpFH [open $G_helpDir/AVeryVeryBigFileName w]}]
334 set G_truncFileNames 1
337 unlink $G_helpDir/AVeryVeryBigFileName
338 set G_truncFileNames 0
341 set G_nroffScanCT [scancontext create]
343 scanmatch $G_nroffScanCT "^'
@help
:" {
344 ExtractNroffHelp $matchInfo(handle) $matchInfo(line)
348 scanmatch $G_nroffScanCT "^'
@header
" {
349 ExtractNroffHeader $matchInfo(handle)
352 scanmatch $G_nroffScanCT "^'
@endhelp
" {
353 error [concat {"'
@endhelp
" without corresponding "'
@help
:"} \
354 ", offset
= $matchInfo(offset
)"]
356 scanmatch $G_nroffScanCT "^'
@brief
" {
357 error [concat {"'
@brief
" without corresponding "'
@help
:"}
358 ", offset
= $matchInfo(offset
)"]
361 set G_scriptScanCT [scancontext create]
362 scanmatch $G_scriptScanCT "^
#@help:" {
363 ExtractScriptHelp
$matchInfo(handle
) $matchInfo(line
)
366 if ![lempty
$mergeTree] {
367 echo
" Merging tree: $mergeTree"
368 CopyMergeTree
$helpDirPath $mergeTree
372 if {[file extension
$briefFile] != ".brf"} {
373 puts stderr
"Brief file \"$briefFile\" must have an extension \".brf\""
376 if [file exists
$G_helpDir/$briefFile] {
377 puts stderr
"Brief file \"$G_helpDir/$briefFile\" already exists"
380 set G_briefHelpFH
[open "|sort > $G_helpDir/$briefFile" w
]
382 foreach manFile
$sourceFiles {
383 set manFile
[glob $manFile]
384 set ext
[file extension
$manFile]
385 if {"$ext" == ".man"} {
386 set status
[catch {ProcessNroffFile
$manFile} msg
]
388 set status
[catch {ProcessTclScript
$manFile} msg
]
391 echo
"Error extracting help from: $manFile"
393 global errorInfo interactiveSession
394 if {!$interactiveSession} {
402 chmod a-w
,a
+r
$G_helpDir/$briefFile
403 echo
"*** completed extraction of all help files"
406 #-----------------------------------------------------------------------------
407 # Print a usage message and exit the program
409 puts stderr
{Wrong args
: [-m mergetree
] -b briefFile helpdir manfile1
[manfile2..
]}
413 #-----------------------------------------------------------------------------
414 # Main program body, decides if help is interactive or batch.
416 if {$interactiveSession} {
417 echo
"To extract help, use the command:"
418 echo
{GenerateHelp helpdir
-m mergetree file-1 file-2 ...
}
422 while {[string match
"-*" [lindex $argv 0]]} {
423 set flag
[lvarpop argv
0]
425 "-m" {set mergeTree
[lvarpop argv
]}
426 "-b" {set briefFile
[lvarpop argv
]}
430 if {[llength $argv] < 2} {
433 if [lempty
$briefFile] {
434 puts stderr
{must specify
-b argument
}
437 GenerateHelp
[lindex $argv 0] $briefFile $mergeTree [lrange $argv 1 end
]