1#
2# cpmanpages.tcl --
3#
4# Tool used during build to copy manual pages to master directories.  This
5# program knows the internals of the build, so its very specific to this
6# task.
7#
8# It is run in the following manner:
9#
10#     cpmanpages ?flags? separator cmd func unix sourceDir targetDir
11#
12# flags are:
13#   o -rmcat - remove any existing "cat" files associated with man pages.
14#
15# arguments are:
16#   o separator - Either "." or "", the separator in the manual page directory
17#     name (/usr/man/man1 vs /usr/man/man.1).
18#   o cmd - Section to put the Tcl command manual pages in. (*.n pages).
19#   o func - Section to put the Tcl C function manual pages in. (*.3 pages).
20#   o unix - Section to put the Tcl Unix command manual pages in.
21#     Maybe empty. (*.1 pages).
22#   o sourceDir - directory containing manual pages to install.
23#   o targetDir - manual directory to install pages in.  This is the directory
24#     containing the section directories, e.g. /usr/local/man.
25#
26# If any of these strings are quoted with "@" (e.g. @.@), then the two "@"
27# are removed.  This is to work around problems with systems were quoted empty
28# strings don't make it past make and shell expansion, resulting in a missing
29# argument.
30#------------------------------------------------------------------------------
31# Copyright 1992-1999 Karl Lehenbauer and Mark Diekhans.
32#
33# Permission to use, copy, modify, and distribute this software and its
34# documentation for any purpose and without fee is hereby granted, provided
35# that the above copyright notice appear in all copies.  Karl Lehenbauer and
36# Mark Diekhans make no representations about the suitability of this
37# software for any purpose.  It is provided "as is" without express or
38# implied warranty.
39#------------------------------------------------------------------------------
40# $Id: cpmanpages.tcl,v 8.4 1999/03/31 06:37:59 markd Exp $
41#------------------------------------------------------------------------------
42#
43
44#------------------------------------------------------------------------------
45# Unquote --
46#
47# Remove "@" if they quote a string.
48#------------------------------------------------------------------------------
49
50proc Unquote str {
51    regsub -- {^@(.*)@$} $str {\1} str
52    return $str
53}
54
55#------------------------------------------------------------------------------
56# CopyManFile --
57#
58# Called to open a copy a man file.  Recursively called to include .so files.
59#------------------------------------------------------------------------------
60
61proc CopyManFile {sourceFile targetFH} {
62
63    set sourceFH [open $sourceFile r]
64
65    while {[gets $sourceFH line] >= 0} {
66        if [string match {.V[SE]*} $line] continue
67        if [string match {.so *} $line] {
68            set soFile [string trim [crange $line 3 end]]
69            CopyManFile "[file dirname $sourceFile]/$soFile" $targetFH
70            continue
71        }
72        puts $targetFH $line
73    }
74
75    close $sourceFH
76}
77
78#------------------------------------------------------------------------------
79# CopyManPage --
80#
81# Copy the specified manual page and change the ownership.  The manual page
82# is edited to remove change bars (.VS and .VE macros). Files included with .so
83# are merged in.
84#------------------------------------------------------------------------------
85
86proc CopyManPage {sourceFile targetFile} {
87    global gzip
88    if ![file exists [file dirname $targetFile]] {
89        mkdir -path [file dirname $targetFile]
90    }
91    catch {file delete $targetFile $targetFile.gz}
92
93    set targetFH [open $targetFile w]
94    CopyManFile $sourceFile $targetFH
95    close $targetFH
96    if $gzip {
97        exec gzip -9f $targetFile
98    }
99}
100
101#------------------------------------------------------------------------------
102# GetManNames --
103#
104#   Search a manual page (nroff source) for the name line.  Parse the name
105# line into all of the functions or commands that it references.  This isn't
106# comprehensive, but it works for all of the Tcl, TclX and Tk man pages.
107#
108# Parameters:
109#   o manFile (I) - The path to the  manual page file.
110# Returns:
111#   A list contain the functions or commands or {} if the name line can't be
112# found or parsed.
113#------------------------------------------------------------------------------
114
115proc GetManNames manFile {
116
117   set manFH [open $manFile]
118
119   #
120   # Search for name line.  Once found, grab the next line that is not a
121   # nroff macro.  If we end up with a blank line, we didn't find it.
122   #
123   while {[gets $manFH line] >= 0} {
124       if [regexp {^.SH NAME.*$} $line] {
125           break
126       }
127   }
128   while {[gets $manFH line] >= 0} {
129       if {![string match ".*" $line]} break
130   }
131   close $manFH
132
133   set line [string trim $line]
134   if {$line == ""} return
135
136   #
137   # Lets try and parse the name list out of the line
138   #
139   if {![regexp {^(.*)(\\-)} $line {} namePart]} {
140       if {![regexp {^(.*)(-)} $line {} namePart]} return
141   }
142
143   #
144   # This magic converts the name line into a list
145   #
146
147   if {[catch {join [split $namePart ,] " "} namePart] != 0} return
148
149   return $namePart
150
151}
152
153#------------------------------------------------------------------------------
154# InstallShortMan --
155#   Install a manual page on a system that does not have long file names.
156#
157# Parameters:
158#   o sourceFile - Manual page source file path.
159#   o targetDir - Directory to install the file in.
160#   o extension - Extension to use for the installed file.
161# Returns:
162#   A list of the man files created, relative to targetDir.
163#------------------------------------------------------------------------------
164
165proc InstallShortMan {sourceFile targetDir extension} {
166
167    set manFileName "[file tail [file root $sourceFile]].$extension"
168
169    CopyManPage $sourceFile "$targetDir/$manFileName"
170
171    return $manFileName
172}
173
174#------------------------------------------------------------------------------
175# InstallLongMan --
176#   Install a manual page on a system that has long file names.
177#
178# Parameters:
179#   o sourceFile - Manual page source file path.
180#   o targetDir - Directory to install the file in.
181#   o extension - Extension to use for the installed file.
182# Returns:
183#   A list of the man files created, relative to targetDir.  They are all links
184# to the same entry.
185#------------------------------------------------------------------------------
186
187proc InstallLongMan {sourceFile targetDir extension} {
188    global gzip
189    set manNames [GetManNames $sourceFile]
190    if [lempty $manNames] {
191        set baseName [file tail [file root $sourceFile]]
192        puts stderr "Warning: can't parse NAME line for man page: $sourceFile."
193        puts stderr "         Manual page only available as: $baseName"
194        set manNames [list [file tail [file root $sourceFile]]]
195    }
196
197    # Copy file to the first name in the list.
198
199    set firstFilePath $targetDir/[lvarpop manNames].$extension
200    set created [list [file tail $firstFilePath]]
201
202    CopyManPage $sourceFile $firstFilePath
203
204    # Link it to the rest of the names in the list.
205
206    foreach manName $manNames {
207        set targetFile  $targetDir/$manName.$extension
208        file delete $targetFile $targetFile.gz
209        if $gzip {
210            set cmd "link $firstFilePath.gz $targetFile.gz"
211        } else {
212            set cmd "link $firstFilePath $targetFile"
213        }
214        if {[catch {
215                eval $cmd
216            } msg] != 0} {
217            puts stderr "error from: $cmd"
218            puts stderr "    $msg"
219        } else {
220            lappend created [file tail $targetFile]
221        }
222    }
223    return $created
224}
225
226#------------------------------------------------------------------------------
227# InstallManPage --
228#   Install a manual page on a system.
229#
230# Parameters:
231#   o sourceFile - Manual page source file path.
232#   o manDir - Directory to build the directoy containing the manual files in.
233#   o section - Section to install the manual page in.
234# Globals
235#   o longNames - If long file names are supported.
236#   o manSeparator - Character used to seperate man directory name from the
237#     section name.
238#   o rmcat - true if cat files are to be removed.
239#------------------------------------------------------------------------------
240
241proc InstallManPage {sourceFile manDir section} {
242    global longNames manSeparator rmcat
243
244    set targetDir "$manDir/man${manSeparator}${section}"
245
246    if $longNames {
247        set files [InstallLongMan $sourceFile $targetDir $section]
248    } else {
249        set files [InstallShortMan $sourceFile $targetDir $section]
250    }
251
252    if $rmcat {
253        foreach file $files {
254            catch {
255                file delete [list $manDir/cat${manSeparator}${section}/$file]
256            }
257        }
258    }
259}
260
261#------------------------------------------------------------------------------
262# main prorgam
263
264umask 022
265
266# Parse command line args
267
268set rmcat 0
269set gzip 0
270while {[string match -* $argv]} {
271    set opt [lvarpop argv]
272    switch -- $opt {
273        -rmcat {set rmcat 1}
274        -gzip {set gzip 1}
275        default {
276            puts stderr "unknown flag: $opt"
277        }
278    }
279}
280if {[llength $argv] != 6} {
281    puts stderr "wrong # args: cpmanpages ?flags? separator cmd func unix sourceDir targetDir"
282    exit 1
283}
284
285
286set manSeparator    [Unquote [lindex $argv 0]]
287set sectionXRef(.n) [Unquote [lindex $argv 1]]
288set sectionXRef(.3) [Unquote [lindex $argv 2]]
289set sectionXRef(.1) [Unquote [lindex $argv 3]]
290set sourceDir       [Unquote [lindex $argv 4]]
291set targetDir       [Unquote [lindex $argv 5]]
292
293# Remove undefined sections from the array.
294
295foreach sec [array names sectionXRef] {
296   if [lempty sectionXRef($sec)] {
297       unset sectionXRef($sec)
298   }
299}
300
301puts stdout "Copying manual pages from $sourceDir to $targetDir"
302
303# Determine if long file names are available.
304
305if ![file exists $targetDir] {
306    mkdir -path $targetDir
307}
308set testName "$targetDir/TclX-long-test-file-name"
309
310if [catch {open $testName w} fh] {
311    puts stdout ""
312    puts stdout "*** NOTE: long file names do not appear to be available on"
313    puts stdout "*** this system. Attempt to create a long named file in"
314    puts stdout "*** $targetDir returned the error: $errorCode"
315    puts stdout ""
316    set longNames 0
317} else {
318    close $fh
319    file delete $testName
320    set longNames 1
321}
322
323set sourceFiles [glob -- $sourceDir/*.n $sourceDir/*.1 $sourceDir/*.3]
324
325set ignoreFiles {}
326
327# Actually install the files.
328
329foreach sourceFile $sourceFiles {
330    if {[lsearch $ignoreFiles [file tail $sourceFile]] >= 0} continue
331
332    set ext [file extension $sourceFile]
333    if ![info exists sectionXRef($ext)] {
334        puts stderr "WARNING: Don't know how to handle section for $sourceFile,"
335        continue
336    }
337    InstallManPage $sourceFile $targetDir $sectionXRef($ext)
338}
339
340
341
342