]> git.zerfleddert.de Git - micropolis/blame - src/tclx/tcllib/buildhelp.tcl
handle spaces in filenames
[micropolis] / src / tclx / tcllib / buildhelp.tcl
CommitLineData
6a5fa4e0
MG
1#
2# buildhelp.tcl --
3#
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
6# files.
7#
8#------------------------------------------------------------------------------
9# Copyright 1992 Karl Lehenbauer and Mark Diekhans.
10#
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
16# implied warranty.
17#------------------------------------------------------------------------------
18# $Id: buildhelp.tcl,v 2.1 1992/10/25 17:07:40 markd Exp $
19#------------------------------------------------------------------------------
20#
21# For nroff man pages, the areas of text to extract are delimited with:
22#
23# '@help: subjectdir/helpfile
24# '@endhelp
25#
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:
30#
31# nroff -man|col -xb {col -b on BSD derived systems}
32#
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:
35#
36# '@:Other text to include in the help page.
37#
38# A entry in the brief file, used by apropos my be included by:
39#
40# '@brief: Short, one line description
41#
42# These brief request must occur with in the bounds of a help section.
43#
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
46# with:
47#
48# '@header
49# '@endheader
50#
51# If multiple header blocks are encountered, they will all be preappended.
52#
53# For TCL script files, which are indentified because they end in ".tcl",
54# the text to be extracted is delimited by:
55#
56# #@help: subjectdir/helpfile
57# #@endhelp
58#
59# And brief lines are in the form:
60#
61# #@brief: Short, one line description
62#
63# The only processing done on text extracted from .tcl files it to replace
64# the # in column one with a space.
65#
66#
67#-----------------------------------------------------------------------------
68#
69# To run this program:
70#
71# tcl buildhelp.tcl [-m mergeTree] -b brief.brf helpDir file-1 file-2 ...
72#
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.
84#
85#-----------------------------------------------------------------------------
86
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
91#
92proc TruncFileName {pathName} {
93 global G_truncFileNames
94
95 if {!$G_truncFileNames} {
96 return $pathName}
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"
102}
103
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
107# permissions.
108
109proc EnsureDirs {filePath} {
110 set dirPath [file dirname $filePath]
111 if [file exists $dirPath] return
112 foreach dir [split $dirPath /] {
113 lappend dirList $dir
114 set partPath [join $dirList /]
115 if [file exists $partPath] continue
116
117 mkdir $partPath
118 chmod u=rwx,go=rx $partPath
119 }
120}
121
122
123#-----------------------------------------------------------------------------
124#
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.
128#
129
130proc ExtractNroffHeader {manPageFH} {
131 global nroffHeader
132 while {[gets $manPageFH manLine] >= 0} {
133 if {[string first "'@endheader" $manLine] == 0} {
134 break;
135 }
136 if {[string first "'@:" $manLine] == 0} {
137 set manLine [csubstr manLine 3 end]
138 }
139 append nroffHeader "$manLine\n"
140 }
141}
142
143#-----------------------------------------------------------------------------
144#
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.
148#
149
150proc ExtractNroffHelp {manPageFH manLine} {
151 global G_helpDir nroffHeader G_briefHelpFH G_colArgs
152
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"}
157 EnsureDirs $helpFile
158 set helpFH [open "| nroff -man | col $G_colArgs > $helpFile" w]
159 echo " creating help file $helpName"
160
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.
163
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
167 set foundBrief 0
168 while {[gets $manPageFH manLine] >= 0} {
169 if {[string first "'@endhelp" $manLine] == 0} {
170 break;
171 }
172 if {[string first "'@brief:" $manLine] == 0} {
173 if $foundBrief {
174 error {Duplicate "'@brief" entry"}
175 }
176 set foundBrief 1
177 puts $G_briefHelpFH "$helpName\t[csubstr $manLine 8 end]"
178 continue;
179 }
180 if {[string first "'@:" $manLine] == 0} {
181 set manLine [csubstr $manLine 3 end]
182 }
183 if {[string first "'@help" $manLine] == 0} {
184 error {"'@help" found within another help section"}
185 }
186 puts $helpFH $manLine
187 }
188 close $helpFH
189 chmod a-w,a+r $helpFile
190}
191
192#-----------------------------------------------------------------------------
193#
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.
197#
198
199proc 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"}
205 EnsureDirs $helpFile
206 set helpFH [open $helpFile w]
207 echo " creating help file $helpName"
208 set foundBrief 0
209 while {[gets $ScriptPageFH ScriptLine] >= 0} {
210 if {[string first "#@endhelp" $ScriptLine] == 0} {
211 break;
212 }
213 if {[string first "#@brief:" $ScriptLine] == 0} {
214 if $foundBrief {
215 error {Duplicate "#@brief" entry"}
216 }
217 set foundBrief 1
218 puts $G_briefHelpFH "$helpName\t[csubstr $ScriptLine 8 end]"
219 continue;
220 }
221 if {[string first "#@help" $ScriptLine] == 0} {
222 error {"#@help" found within another help section"}
223 }
224 if {[clength $ScriptLine] > 1} {
225 set ScriptLine " [csubstr $ScriptLine 1 end]"
226 } else {
227 set ScriptLine ""
228 }
229 puts $helpFH $ScriptLine
230 }
231 close $helpFH
232 chmod a-w,a+r $helpFile
233}
234
235#-----------------------------------------------------------------------------
236#
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.
240#
241
242proc ProcessNroffFile {pathName} {
243 global G_nroffScanCT G_scriptScanCT nroffHeader
244
245 set fileName [file tail $pathName]
246
247 set nroffHeader {}
248 set manPageFH [open $pathName r]
249 echo " scanning $pathName"
250 set matchInfo(fileName) [file tail $pathName]
251 scanfile $G_nroffScanCT $manPageFH
252 close $manPageFH
253}
254
255#-----------------------------------------------------------------------------
256#
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.
260#
261
262proc ProcessTclScript {pathName} {
263 global G_scriptScanCT nroffHeader
264
265 set scriptFH [open "$pathName" r]
266
267 echo " scanning $pathName"
268 set matchInfo(fileName) [file tail $pathName]
269 scanfile $G_scriptScanCT $scriptFH
270 close $scriptFH
271}
272
273#-----------------------------------------------------------------------------
274# Proc to copy the help merge tree, excluding the brief file and RCS files
275#
276
277proc CopyMergeTree {helpDirPath mergeTree} {
278 if {"[cindex $helpDirPath 0]" != "/"} {
279 set helpDirPath "[pwd]/$helpDirPath"
280 }
281 set oldDir [pwd]
282 cd $mergeTree
283
284 set curHelpDir "."
285
286 for_recursive_glob mergeFile {.} {
287 if [string match "*/RCS/*" $mergeFile] continue
288
289 set helpFile "$helpDirPath/$mergeFile"
290 if [file isdirectory $mergeFile] continue
291
292 if {[file exists $helpFile]} {
293 error "Help file already exists: $helpFile"}
294 EnsureDirs $helpFile
295 set inFH [open $mergeFile r]
296 set outFH [open $helpFile w]
297 copyfile $inFH $outFH
298 close $outFH
299 close $inFH
300 chmod a-w,a+r $helpFile
301 }
302 cd $oldDir
303}
304
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.
311
312proc GenerateHelp {helpDirPath briefFile mergeTree sourceFiles} {
313 global G_helpDir G_truncFileNames G_nroffScanCT
314 global G_scriptScanCT G_briefHelpFH G_colArgs
315
316 echo ""
317 echo "Begin building help tree"
318
319 # Determine version of col command to use (no -x on BSD)
320 if {[system {col -bx </dev/null >/dev/null 2>&1}] != 0} {
321 set G_colArgs {-b}
322 } else {
323 set G_colArgs {-bx}
324 }
325 set G_helpDir [glob $helpDirPath]
326
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"]
330 }
331
332 set status [catch {set tmpFH [open $G_helpDir/AVeryVeryBigFileName w]}]
333 if {$status != 0} {
334 set G_truncFileNames 1
335 } else {
336 close $tmpFH
337 unlink $G_helpDir/AVeryVeryBigFileName
338 set G_truncFileNames 0
339 }
340
341 set G_nroffScanCT [scancontext create]
342
343 scanmatch $G_nroffScanCT "^'@help:" {
344 ExtractNroffHelp $matchInfo(handle) $matchInfo(line)
345 continue
346 }
347
348 scanmatch $G_nroffScanCT "^'@header" {
349 ExtractNroffHeader $matchInfo(handle)
350 continue
351 }
352 scanmatch $G_nroffScanCT "^'@endhelp" {
353 error [concat {"'@endhelp" without corresponding "'@help:"} \
354 ", offset = $matchInfo(offset)"]
355 }
356 scanmatch $G_nroffScanCT "^'@brief" {
357 error [concat {"'@brief" without corresponding "'@help:"}
358 ", offset = $matchInfo(offset)"]
359 }
360
361 set G_scriptScanCT [scancontext create]
362 scanmatch $G_scriptScanCT "^#@help:" {
363 ExtractScriptHelp $matchInfo(handle) $matchInfo(line)
364 }
365
366 if ![lempty $mergeTree] {
367 echo " Merging tree: $mergeTree"
368 CopyMergeTree $helpDirPath $mergeTree
369 }
370
371
372 if {[file extension $briefFile] != ".brf"} {
373 puts stderr "Brief file \"$briefFile\" must have an extension \".brf\""
374 exit 1
375 }
376 if [file exists $G_helpDir/$briefFile] {
377 puts stderr "Brief file \"$G_helpDir/$briefFile\" already exists"
378 exit 1
379 }
380 set G_briefHelpFH [open "|sort > $G_helpDir/$briefFile" w]
381
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]
387 } else {
388 set status [catch {ProcessTclScript $manFile} msg]
389 }
390 if {$status != 0} {
391 echo "Error extracting help from: $manFile"
392 echo $msg
393 global errorInfo interactiveSession
394 if {!$interactiveSession} {
395 echo $errorInfo
396 exit 1
397 }
398 }
399 }
400
401 close $G_briefHelpFH
402 chmod a-w,a+r $G_helpDir/$briefFile
403 echo "*** completed extraction of all help files"
404}
405
406#-----------------------------------------------------------------------------
407# Print a usage message and exit the program
408proc Usage {} {
409 puts stderr {Wrong args: [-m mergetree] -b briefFile helpdir manfile1 [manfile2..]}
410 exit 1
411}
412
413#-----------------------------------------------------------------------------
414# Main program body, decides if help is interactive or batch.
415
416if {$interactiveSession} {
417 echo "To extract help, use the command:"
418 echo {GenerateHelp helpdir -m mergetree file-1 file-2 ...}
419} else {
420 set mergeTree {}
421 set briefFile {}
422 while {[string match "-*" [lindex $argv 0]]} {
423 set flag [lvarpop argv 0]
424 case $flag in {
425 "-m" {set mergeTree [lvarpop argv]}
426 "-b" {set briefFile [lvarpop argv]}
427 default Usage
428 }
429 }
430 if {[llength $argv] < 2} {
431 Usage
432 }
433 if [lempty $briefFile] {
434 puts stderr {must specify -b argument}
435 Usage
436 }
437 GenerateHelp [lindex $argv 0] $briefFile $mergeTree [lrange $argv 1 end]
438
439}
Impressum, Datenschutz