4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998 Damon Chaplin
6 # 2007 David Necas (Yeti)
7 # 2007-2016 Stefan Sauer
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #############################################################################
25 # Script : gtkdoc-rebase
26 # Description : Rebases URI references in installed HTML documentation.
27 #############################################################################
31 use Getopt::Long qw(:config gnu_getopt);
34 push @INC, '@PACKAGE_DATA_DIR@';
35 require "gtkdoc-common.pl";
50 # These two point to the last seen URI of given type for a package:
51 # OnlineMap: package => on-line URI
52 # LocalMap: package => local URI
53 # This maps all seen URIs of a package to fix broken links in the process:
54 # RevMap: URI => package
55 my (%OnlineMap, %LocalMap, %RevMap);
56 # Remember what mangling we did.
60 Run() unless caller; # Run program unless loaded as a module
64 my %optctl = ('html-dir' => \$HTML_DIR,
65 'other-dir' => \@OTHER_DIRS,
66 'dest-dir' => \$DEST_DIR,
68 'relative' => \$RELATIVE,
69 'aggressive' => \$AGGRESSIVE,
70 'verbose' => \$VERBOSE,
71 'version' => \$PRINT_VERSION,
72 'help' => \$PRINT_HELP);
73 GetOptions(\%optctl, 'html-dir=s', 'other-dir=s@', 'dest-dir:s',
74 'online', 'relative', 'aggressive', 'verbose',
84 gtkdoc-rebase version @VERSION@ - rewrite the base url of html files
86 --html-dir=HTML_DIR The directory which contains the installed HTML
87 --other-dir=OTHER_DIR Directories to recursively scan for indices (index.sgml)
88 May be used more than once for multiple directories
89 --online Prefer cross-references to online documents
90 --relative Prefer relative cross-references
91 --aggressive Rebase links to all files that are under a directory
92 matching a package name.
93 --dest-dir=ROOT_DIR Staging area virtual root, this prefix will be removed
94 from HTML_DIR fore relative link calculation.
96 --version Print the version of this program
97 --help Print this help
103 die "No HTML directory (--html-dir) given.\n";
108 # We scan the directory containing GLib and any directories in GNOME2_PATH
109 # first, but these will be overriden by any later scans.
110 if (defined ($ENV{"GNOME2_PATH"})) {
111 foreach $dir (split(/:/, $ENV{"GNOME2_PATH"})) {
112 $dir = $dir . "/share/gtk-doc/html";
113 if ($dir && -d $dir) {
114 print "Prepending GNOME2_PATH directory: $dir\n" if $VERBOSE;
115 unshift @OTHER_DIRS, $dir;
120 $dir = `@PKG_CONFIG@ --variable=prefix glib-2.0`;
121 $dir =~ s/^\s*(\S*)\s*$/$1/;
122 $dir = $dir . "/share/gtk-doc/html";
123 print "Prepending GLib directory $dir\n" if $VERBOSE;
124 unshift @OTHER_DIRS, $dir;
126 # Check all other dirs, but skip already scanned dirs ord subdirs of those
128 $DEST_DIR =~ s#/?$#/#;
130 $HTML_DIR =~ s#/?$#/#;
132 foreach $dir (@OTHER_DIRS) {
133 &ScanDirectory($dir, $HTML_DIR);
137 &RelativizeLocalMap($HTML_DIR);
140 &RebaseReferences($HTML_DIR);
141 &PrintWhatWeHaveDone();
146 my ($dir, $self) = @_;
147 # This array holds any subdirectories found.
150 print "Scanning documentation directory $dir\n" if $VERBOSE;
152 if ("$dir/" eq $self) {
153 print "Excluding self\n" if $VERBOSE;
156 if (not opendir(HTMLDIR, $dir)) {
157 print "Cannot open $dir: $!\n";
164 foreach $file (readdir(HTMLDIR)) {
165 if ($file eq '.' or $file eq '..') {
168 elsif (-d "$dir/$file") {
169 push @subdirs, $file;
172 if ($file =~ m/\.devhelp2$/) {
173 print "Reading index from $file\n" if $VERBOSE;
174 my $o = &ReadDevhelp($dir, $file);
175 # Prefer this location over possibly stale index.sgml
181 if (!$onlinedir and ($file eq "index.sgml")) {
182 print "Reading index from index.sgml\n" if $VERBOSE;
183 $onlinedir = &ReadIndex($dir, $file);
186 elsif (($file eq "index.sgml.gz") && ! (-e "$dir/index.sgml")) {
187 # debian/ubuntu started to compress this as index.sgml.gz :/
189 Please fix https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138 . For now run:
193 elsif (($file =~ m/\.devhelp2.gz$/) && ! (-e "$dir/$1.devhelp2")) {
194 # debian/ubuntu started to compress this as *devhelp2.gz :/
196 Please fix https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/1466210 . For now run:
200 # we could consider supporting: use IO::Zlib;
204 &AddMap($dir, $onlinedir);
207 # Now recursively scan the subdirectories.
209 foreach my $subdir (@subdirs) {
210 &ScanDirectory("$dir/$subdir", $self);
216 my ($dir, $file) = @_;
219 open(INDEXFILE, "$dir/$file") || die "Can't open $dir/$file: $!";
220 while (<INDEXFILE>) {
221 # online must come before chapter/functions
222 last if m/<(chapters|functions)/;
223 if (m/ online="([^"]*)"/) {
225 # Remove trailing non-directory component.
226 $onlinedir =~ s#(.*/).*#$1#;
235 my ($dir, $file) = @_;
238 open(INDEXFILE, "$dir/$file") || die "Can't open $dir/$file: $!";
239 while (<INDEXFILE>) {
240 # ONLINE must come before any ANCHORs
242 if (m/^<ONLINE\s+href\s*=\s*"([^"]+)"\s*>/) {
244 # Remove trailing non-directory component.
245 $onlinedir =~ s#(.*/).*#$1#;
254 my ($dir, $onlinedir) = @_;
258 ($package = $dir) =~ s#.*/([^/]+)/#$1#;
259 if ($DEST_DIR and substr($dir, 0, length $DEST_DIR) eq $DEST_DIR) {
260 $dir = substr($dir, -1 + length $DEST_DIR);
263 print "On-line location of $package: $onlinedir\n" if $VERBOSE;
264 $OnlineMap{ $package } = $onlinedir;
265 $RevMap{ $onlinedir } = $package;
267 print "No On-line location for $package found\n" if $VERBOSE;
269 print "Local location of $package: $dir\n" if $VERBOSE;
270 $LocalMap{ $package } = $dir;
271 $RevMap{ $dir } = $package;
275 sub RelativizeLocalMap {
280 $self = realpath $self;
282 ($prefix = $self) =~ s#[^/]+/$##;
283 foreach my $package (keys %LocalMap) {
284 $dir = $LocalMap{ $package };
285 if (substr($dir, 0, length $prefix) eq $prefix) {
286 $dir = "../" . substr($dir, length $prefix);
287 $LocalMap{ $package } = $dir;
288 print "Relativizing local location of $package to $dir\n" if $VERBOSE;
294 sub RebaseReferences {
297 opendir(HTMLDIR, $dir) || die "Can't open HTML directory $dir: $!";
298 foreach my $file (readdir(HTMLDIR)) {
299 if ($file =~ m/\.html?$/) {
300 &RebaseFile("$dir$file");
309 print "Fixing file: $file\n" if $VERBOSE;
311 open(HTMLFILE, $file) || die "Can't open $file: $!";
314 my $text = <HTMLFILE>;
317 $text =~ s#(<a(?:\s+\w+=(?:"[^"]*"|'[^']*'))*\s+href=")([^"]*)(")#$1 . &RebaseLink($2) .$3#gse;
319 open(NEWFILE, ">$file.new") || die "Can't open $file: $!";
323 unlink($file) || die "Can't delete $file: $!";
324 rename("$file.new", $file) || die "Can't rename $file.new: $!";
330 my ($dir, $origdir, $file, $package);
332 if ($href =~ m#^(.*/)([^/]*)$#) {
333 $dir = $origdir = $1;
335 if ($RevMap{ $dir }) {
336 $package = $RevMap{ $dir };
338 elsif ($dir =~ m#^\.\./([^/]+)/#) {
341 elsif ($AGGRESSIVE) {
342 $dir =~ m#([^/]+)/$#;
347 if ($ONLINE && $OnlineMap{ $package }) {
348 $dir = $OnlineMap{ $package };
350 elsif ($LocalMap{ $package }) {
351 $dir = $LocalMap{ $package };
353 $href = $dir . $file;
355 @TRACE@("Can't determine package for '$href'");
357 if ($dir ne $origdir) {
358 if ($Mapped{ $origdir }) {
359 $Mapped{ $origdir }->[1]++;
362 $Mapped{ $origdir } = [ $dir, 1 ];
370 sub PrintWhatWeHaveDone {
371 my ($origdir, $info);
372 foreach $origdir (sort keys %Mapped) {
373 $info = $Mapped{$origdir};
374 print "$origdir -> ", $info->[0], " (", $info->[1], ")\n";