4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998 Damon Chaplin
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #############################################################################
23 # Script : gtkdoc-fixxref
24 # Description : This fixes cross-references in the HTML documentation.
25 #############################################################################
33 # name of documentation module
41 my %optctl = ('module' => \$MODULE,
42 'module-dir' => \$MODULE_DIR,
43 'html-dir' => \$HTML_DIR,
44 'extra-dir' => \@EXTRA_DIRS,
45 'version' => \$PRINT_VERSION,
46 'help' => \$PRINT_HELP);
47 GetOptions(\%optctl, "module=s", "module-dir=s", "html-dir:s", "extra-dir=s@",
57 gtkdoc-fixxref version @VERSION@ - fix cross references in html files
59 --module=MODULE_NAME Name of the doc module being parsed
60 --module-dir=MODULE_DIR The directory which contains the generated HTML
61 --html-dir=HTML_DIR The directory where gtk-doc generated documentation is
63 --extra-dir=EXTRA_DIR Directories to recursively scan for indices (index.sgml)
64 in addition to HTML_DIR
65 May be used more than once for multiple directories
66 --version Print the version of this program
67 --help Print this help
72 # This contains all the entities and their relative URLs.
74 # This hold the path entries we already scanned
79 if ($HTML_DIR =~ m%(.*?)/share/gtk-doc/html%) {
81 #print "Path prefix: $path_prefix\n";
84 if (!defined $MODULE_DIR) {
85 $MODULE_DIR="$HTML_DIR/$MODULE";
90 # We scan the directory containing GLib and any directories in GNOME2_PATH
91 # first, but these will be overriden by any later scans.
92 $dir = `pkg-config --variable=prefix glib-2.0`;
94 $dir = $dir . "/share/gtk-doc/html";
95 if (-d $dir && $dir ne $HTML_DIR) {
96 #print "Scanning GLib directory: $dir\n";
97 if ($dir !~ m%^\Q$path_prefix\E/%) {
98 &ScanIndices ($dir, 1);
100 &ScanIndices ($dir, 0);
102 push (@VisitedPaths, $dir);
105 if (defined ($ENV{"GNOME2_PATH"})) {
106 foreach $dir (split (/:/, $ENV{"GNOME2_PATH"})) {
107 $dir = $dir . "/share/gtk-doc/html";
108 if (-d $dir && $dir ne $HTML_DIR) {
109 #print "Scanning GNOME2_PATH directory: $dir\n";
110 if ($dir !~ m%^\Q$path_prefix\E/%) {
111 &ScanIndices ($dir, 1);
113 &ScanIndices ($dir, 0);
115 push (@VisitedPaths, $dir);
117 # ubuntu started to compress this as index.sgml.gz :/
118 # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
122 #print "Scanning HTML_DIR directory: $HTML_DIR\n";
123 &ScanIndices ($HTML_DIR, 0);
124 push (@VisitedPaths, $HTML_DIR);
125 #print "Scanning HTML_DIR directory: $MODULE_DIR\n";
126 &ScanIndices ($MODULE_DIR, 0);
127 push (@VisitedPaths, $MODULE_DIR);
129 # check all extra dirs, but skip already scanned dirs or subdirs of those
130 foreach my $dir (@EXTRA_DIRS) {
134 foreach $vdir (@VisitedPaths) {
135 if ($dir eq $vdir || $dir =~ m%^\Q$vdir\E/%) {
136 #print "Skipping EXTRA_DIR directory: $dir\n";
141 #print "Scanning EXTRA_DIR directory: $dir\n";
142 push (@VisitedPaths, $dir);
144 # If the --extra-dir option is not relative and is not sharing the same
145 # prefix as the target directory of the docs, we need to use absolute
146 # directories for the links
147 if ($dir !~m/^\.\./ && $dir !~ m%\Q$path_prefix\E/%) {
148 &ScanIndices ($dir, 1);
150 &ScanIndices ($dir, 0);
154 &FixCrossReferences ($MODULE_DIR);
157 my ($scan_dir, $use_absolute_links) = @_;
159 #print "Scanning source directory: $scan_dir absolute: $use_absolute_links\n";
161 # This array holds any subdirectories found.
164 opendir (HTMLDIR, $scan_dir) || return;
166 foreach $file (readdir (HTMLDIR)) {
167 if ($file eq '.' || $file eq '..') {
169 } elsif (-d "$scan_dir/$file") {
170 push (@subdirs, $file);
171 } elsif ($file eq "index.sgml") {
172 &ScanIndex ("$scan_dir/$file", $use_absolute_links);
174 # ubuntu started to compress this as index.sgml.gz :/
175 # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
179 # Now recursively scan the subdirectories.
181 foreach $dir (@subdirs) {
182 &ScanIndices ("$scan_dir/$dir", $use_absolute_links);
187 my ($file, $use_absolute_links) = @_;
188 #print "Scanning index file: $file absolute: $use_absolute_links\n";
190 # Determine the absolute directory, to be added to links in index.sgml
191 # if we need to use an absolute link.
192 # $file will be something like /opt/gnome/share/gtk-doc/html/gtk/index.sgml
193 # We want the part up to 'html' since the links in index.sgml include
196 if ($use_absolute_links) {
197 $file =~ /(.*\/)(.*?)\/index\.sgml/;
201 open (INDEXFILE, $file)
202 || die "Can't open $file: $!";
203 while (<INDEXFILE>) {
204 if (m/^<ANCHOR\s+id\s*=\s*"([^"]*)"\s+href\s*=\s*"([^"]*)"\s*>/) {
205 #print "Found id: $1 href: $2\n";
206 $Links{$1} = "$dir$2";
213 sub FixCrossReferences {
216 opendir (HTMLDIR, $scan_dir)
217 || die "Can't open HTML directory $scan_dir: $!";
219 foreach $file (readdir (HTMLDIR)) {
220 if ($file eq '.' || $file eq '..') {
222 } elsif ($file =~ m/.html?$/) {
223 &FixHTMLFile ("$scan_dir/$file");
232 #print "Fixing file: $file\n";
234 open (HTMLFILE, $file)
235 || die "Can't open $file: $!";
237 my $entire_file = <HTMLFILE>;
240 if ("@HIGHLIGHT@" ne "") {
241 $entire_file =~ s%<div class=\"(example-contents|informalexample)\"><pre class=\"programlisting\">(.*?)</pre></div>%&HighlightSource($1,$2);%gse;
242 # from the highlighter we get all the functions marked up
243 # now we could turn them into GTKDOCLINK items
244 $entire_file =~ s%(<span class=\"function\">)(.*?)(</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
245 # we could also try the first item in stuff marked up as 'normal'
246 $entire_file =~ s%(<span class=\"normal\">\s*)(.+?)((\s+.+?)?\s*</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
249 $entire_file =~ s%<GTKDOCLINK\s+HREF="([^"]*)"\s*>(.*?)</GTKDOCLINK\s*>% &MakeXRef($1,$2); %gse;
251 open (NEWFILE, ">$file.new")
252 || die "Can't open $file: $!";
253 print NEWFILE $entire_file;
257 || die "Can't delete $file: $!";
258 rename ("$file.new", $file)
259 || die "Can't rename $file.new: $!";
264 my ($id, $text) = @_;
266 my $href = $Links{$id};
269 # if it is a link to same module, remove path to make it work
271 if ($href =~ m%^\.\./$MODULE/(.*)$%) {
274 #print " Fixing link: $id, $href, $text\n";
275 return "<a href=\"$href\">$text</a>";
277 #print " no link for: $id, $text\n";
284 my ($pre,$symbol,$post) = @_;
286 my $id=CreateValidSGMLID($symbol);
288 #return "<span class=\"$type\"><GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK></span>";
289 return "$pre<GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK>$post";
293 sub HighlightSource {
294 my ($type, $source) = @_;
296 # chop of leading and trailing empty lines
297 $source =~ s/^\s*\n+//gs;
298 $source =~ s/[\s\n]+$//gs;
300 $source =~ m/^(\s*)/;
301 $source =~ s/^$1//gms;
302 # avoid double entity replacement
303 $source =~ s/</</g;
304 $source =~ s/>/>/g;
305 $source =~ s/&/&/g;
307 # write source to a temp file
308 my $temp_source_file="$MODULE_DIR/_temp_src.$$";
309 open (NEWFILE, ">$temp_source_file") || die "Can't open $temp_source_file: $!";
310 print NEWFILE $source;
314 my $highlighted_source=`@HIGHLIGHT@ @HIGHLIGHT_OPTIONS@$temp_source_file`;
315 if ("@HIGHLIGHT@" =~ m%/source-highlight%) {
316 $highlighted_source =~ s%^<\!-- .*? -->%%gs;
317 $highlighted_source =~ s%<pre><tt>(.*?)</tt></pre>%$1%gs;
319 elsif ("@HIGHLIGHT@" =~ m%/highlight%) {
320 # need to rewrite the stylesheet classes
321 $highlighted_source =~ s%<span class="com">%<span class="comment">%gs;
322 $highlighted_source =~ s%<span class="dir">%<span class="preproc">%gs;
323 $highlighted_source =~ s%<span class="kwd">%<span class="function">%gs;
324 $highlighted_source =~ s%<span class="kwa">%<span class="keyword">%gs;
325 $highlighted_source =~ s%<span class="line">%<span class="linenum">%gs;
326 $highlighted_source =~ s%<span class="num">%<span class="number">%gs;
327 $highlighted_source =~ s%<span class="str">%<span class="string">%gs;
328 $highlighted_source =~ s%<span class="sym">%<span class="symbol">%gs;
330 # $highlighted_source =~ s%</span>(.+)<span%</span><span class="normal">$1</span><span%gs;
332 # chop of leading and trailing empty lines
333 $highlighted_source =~ s/^[\s\n]+//gs;
334 $highlighted_source =~ s/[\s\n]+$//gs;
336 # turn common urls in comments into links
337 $highlighted_source =~ s%<span class="url">(.*?)</span>%<span class="url"><a href="$1">$1</a></span>%gs;
339 # we do own line-numbering
341 my $line_count = () = $highlighted_source =~ /\n/gs;
343 for($i=1;$i<($line_count+2);$i++) {
344 $source_lines.="$i\n";
348 unlink ($temp_source_file)
349 || die "Can't delete $temp_source_file: $!";
353 <table class="listing_frame" border="0" cellpadding="0" cellspacing="0">
356 <td class="listing_lines" align="right"><pre>$source_lines</pre></td>
357 <td class="listing_code"><pre class="programlisting">$highlighted_source</pre></td>
366 #############################################################################
367 # Function : CreateValidSGMLID
368 # Description : Creates a valid SGML 'id' from the given string.
369 # NOTE: SGML ids are case-insensitive, so we have a few special
370 # cases to avoid clashes of ids.
371 # Arguments : $id - the string to be converted into a valid SGML id.
372 #############################################################################
374 sub CreateValidSGMLID {
377 # Special case, '_' would end up as '' so we use 'gettext-macro' instead.
378 if ($id eq "_") { return "gettext-macro"; }
386 # Append ":CAPS" to all all-caps identifiers
387 if ($id !~ /[a-z]/ && $id !~ /-CAPS$/) { $id .= ":CAPS" };