Added British English translation by Jen Ockwell
[gtk-doc.git] / gtkdoc-fixxref.in
blob8e9e406212bcbfa0d2a11e00e871d9a08ff544e9
1 #!@PERL@ -w
2 # -*- cperl -*-
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 #############################################################################
23 # Script      : gtkdoc-fixxref
24 # Description : This fixes cross-references in the HTML documentation.
25 #############################################################################
27 use strict;
28 use bytes;
29 use Getopt::Long;
31 # Options
33 # name of documentation module
34 my $MODULE;
35 my $MODULE_DIR;
36 my $HTML_DIR = "";
37 my @EXTRA_DIRS;
38 my $PRINT_VERSION;
39 my $PRINT_HELP;
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@",
48         "version", "help");
50 if ($PRINT_VERSION) {
51     print "@VERSION@\n";
52     exit 0;
55 if ($PRINT_HELP) {
56         print <<EOF;
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
62                         installed
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
68 EOF
69     exit 0;
72 # This contains all the entities and their relative URLs.
73 my %Links;
74 # This hold the path entries we already scanned
75 my @VisitedPaths;
78 my $path_prefix="";
79 if ($HTML_DIR =~ m%(.*?)/share/gtk-doc/html%) {
80     $path_prefix=$1;
81     #print "Path prefix: $path_prefix\n";
84 if (!defined $MODULE_DIR) {
85   $MODULE_DIR="$HTML_DIR/$MODULE";
88 my $dir;
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`;
93 $dir =~ s/\s+$//;
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);
99     } else {
100         &ScanIndices ($dir, 0);
101     }
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);
112             } else {
113                 &ScanIndices ($dir, 0);
114             }
115             push (@VisitedPaths, $dir);
116         }
117         # ubuntu started to compress this as index.sgml.gz :/
118         # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
119     }
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) {
131     my $vdir;
132     my $skip = 0;
134     foreach $vdir (@VisitedPaths) {
135         if ($dir eq $vdir || $dir =~ m%^\Q$vdir\E/%) {
136             #print "Skipping EXTRA_DIR directory: $dir\n";
137             $skip=1;
138         }
139     }
140     next if $skip;
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);
149     } else {
150         &ScanIndices ($dir, 0);
151     }
154 &FixCrossReferences ($MODULE_DIR);
156 sub ScanIndices {
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.
162     my (@subdirs) = ();
164     opendir (HTMLDIR, $scan_dir) || return;
165     my $file;
166     foreach $file (readdir (HTMLDIR)) {
167         if ($file eq '.' || $file eq '..') {
168             next;
169         } elsif (-d "$scan_dir/$file") {
170             push (@subdirs, $file);
171         } elsif ($file eq "index.sgml") {
172             &ScanIndex ("$scan_dir/$file", $use_absolute_links);
173         }
174         # ubuntu started to compress this as index.sgml.gz :/
175         # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
176     }
177     closedir (HTMLDIR);
179     # Now recursively scan the subdirectories.
180     my $dir;
181     foreach $dir (@subdirs) {
182         &ScanIndices ("$scan_dir/$dir", $use_absolute_links);
183     }
186 sub ScanIndex {
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
194     # the rest.
195     my $dir = "../";
196     if ($use_absolute_links) {
197         $file =~ /(.*\/)(.*?)\/index\.sgml/;
198         $dir = $1;
199     }
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";
207         }
208     }
209     close (INDEXFILE);
213 sub FixCrossReferences {
214     my ($scan_dir) = @_;
216     opendir (HTMLDIR, $scan_dir)
217         || die "Can't open HTML directory $scan_dir: $!";
218     my $file;
219     foreach $file (readdir (HTMLDIR)) {
220         if ($file eq '.' || $file eq '..') {
221             next;
222         } elsif ($file =~ m/.html?$/) {
223             &FixHTMLFile ("$scan_dir/$file");
224         }
225     }
226     closedir (HTMLDIR);
230 sub FixHTMLFile {
231     my ($file) = @_;
232     #print "Fixing file: $file\n";
234     open (HTMLFILE, $file)
235         || die "Can't open $file: $!";
236     undef $/;
237     my $entire_file = <HTMLFILE>;
238     close (HTMLFILE);
239     
240     if ("@HIGHLIGHT@" ne "") {
241         if ("@HIGHLIGHT@" =~ m%/vim$%) {
242             $entire_file =~ s%<div class=\"(example-contents|informalexample)\"><pre class=\"programlisting\">(.*?)</pre></div>%&HighlightSourceVim($1,$2);%gse;
243         }
244         else {
245             $entire_file =~ s%<div class=\"(example-contents|informalexample)\"><pre class=\"programlisting\">(.*?)</pre></div>%&HighlightSource($1,$2);%gse;
246         }
247         # from the highlighter we get all the functions marked up
248         # now we could turn them into GTKDOCLINK items
249         $entire_file =~ s%(<span class=\"function\">)(.*?)(</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
250         # we could also try the first item in stuff marked up as 'normal'
251         $entire_file =~ s%(<span class=\"normal\">\s*)(.+?)((\s+.+?)?\s*</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
252     }
254     $entire_file =~ s%<GTKDOCLINK\s+HREF="([^"]*)"\s*>(.*?)</GTKDOCLINK\s*>% &MakeXRef($1,$2); %gse;
256     open (NEWFILE, ">$file.new")
257         || die "Can't open $file: $!";
258     print NEWFILE $entire_file;
259     close (NEWFILE);
261     unlink ($file)
262         || die "Can't delete $file: $!";
263     rename ("$file.new", $file)
264         || die "Can't rename $file.new: $!";
268 sub MakeXRef {
269     my ($id, $text) = @_;
271     my $href = $Links{$id};
273     if ($href) {
274         # if it is a link to same module, remove path to make it work
275         # uninstalled
276         if (defined($MODULE) && $href =~ m%^\.\./$MODULE/(.*)$%) {
277             $href=$1;
278         }
279         #print "  Fixing link: $id, $href, $text\n";
280         return "<a href=\"$href\">$text</a>";
281     } else {
282         #print "  no link for: $id, $text\n";
283         return $text;
284     }
288 sub MakeGtkDocLink {
289     my ($pre,$symbol,$post) = @_;
290     
291     my $id=CreateValidSGMLID($symbol);
292     
293     #return "<span class=\"$type\"><GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK></span>";
294     return "$pre<GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK>$post";
298 sub HighlightSource {
299     my ($type, $source) = @_;
301     # chop of leading and trailing empty lines
302     $source =~ s/^\s*\n+//gs;
303     $source =~ s/[\s\n]+$//gs;
304     # cut common indent
305     $source =~ m/^(\s*)/;
306     $source =~ s/^$1//gms;
307     # avoid double entity replacement
308     $source =~ s/&lt;/</g;
309     $source =~ s/&gt;/>/g;
310     $source =~ s/&amp;/&/g;
312     # write source to a temp file
313     # FIXME: use .c for now to hint the language to the highlighter
314     my $temp_source_file="$MODULE_DIR/_temp_src.$$.c";
315     open (NEWFILE, ">$temp_source_file") || die "Can't open $temp_source_file: $!";
316     print NEWFILE $source;
317     close (NEWFILE);
318     
319     #print" running @HIGHLIGHT@ @HIGHLIGHT_OPTIONS@$temp_source_file \n";
320     
321     # format source
322     my $highlighted_source=`@HIGHLIGHT@ @HIGHLIGHT_OPTIONS@$temp_source_file`;
323     if ("@HIGHLIGHT@" =~ m%/source-highlight$%) {
324         $highlighted_source =~ s%^<\!-- .*? -->%%gs;
325         $highlighted_source =~ s%<pre><tt>(.*?)</tt></pre>%$1%gs;
326     }
327     elsif ("@HIGHLIGHT@" =~ m%/highlight$%) {
328         # need to rewrite the stylesheet classes
329         $highlighted_source =~ s%<span class="gtkdoc com">%<span class="comment">%gs;
330         $highlighted_source =~ s%<span class="gtkdoc dir">%<span class="preproc">%gs;
331         $highlighted_source =~ s%<span class="gtkdoc kwd">%<span class="function">%gs;
332         $highlighted_source =~ s%<span class="gtkdoc kwa">%<span class="keyword">%gs;
333         $highlighted_source =~ s%<span class="gtkdoc line">%<span class="linenum">%gs;
334         $highlighted_source =~ s%<span class="gtkdoc num">%<span class="number">%gs;
335         $highlighted_source =~ s%<span class="gtkdoc str">%<span class="string">%gs;
336         $highlighted_source =~ s%<span class="gtkdoc sym">%<span class="symbol">%gs;
337         # maybe also do
338         # $highlighted_source =~ s%</span>(.+)<span%</span><span class="normal">$1</span><span%gs;
339     }
340     # remove temp file
341     unlink ($temp_source_file)
342         || die "Can't delete $temp_source_file: $!";
344     return &HighlightSourcePostprocess($type, $highlighted_source);
347 sub HighlightSourceVim {
348     my ($type, $source) = @_;
350     # chop of leading and trailing empty lines
351     $source =~ s/^[\s\n]+//gs;
352     $source =~ s/[\s\n]+$//gs;
353     # avoid double entity replacement
354     $source =~ s/&lt;/</g;
355     $source =~ s/&gt;/>/g;
356     $source =~ s/&amp;/&/g;
358     # write source to a temp file
359     my $temp_source_file="$MODULE_DIR/_temp_src.$$.h";
360     open (NEWFILE, ">$temp_source_file") || die "Can't open $temp_source_file: $!";
361     print NEWFILE $source;
362     close (NEWFILE);
364     # format source
365     system "echo 'let html_number_lines=0|let html_use_css=1|let use_xhtml=1|syn on|e $temp_source_file|run! syntax/2html.vim|wa!|qa!' | @HIGHLIGHT@ -n -e -u /dev/null -T xterm >/dev/null";
367     my $highlighted_source;
368     {
369         local $/;
370         open (NEWFILE, "<$temp_source_file.html");
371         $highlighted_source = <NEWFILE>;
372         close (NEWFILE);
373     }
374     $highlighted_source =~ s#.*<pre>\n##s;
375     $highlighted_source =~ s#</pre>.*##s;
377     # need to rewrite the stylesheet classes
378     # FIXME: Vim has somewhat different syntax groups
379     $highlighted_source =~ s%<span class="Comment">%<span class="comment">%gs;
380     $highlighted_source =~ s%<span class="PreProc">%<span class="preproc">%gs;
381     $highlighted_source =~ s%<span class="Statement">%<span class="keyword">%gs;
382     $highlighted_source =~ s%<span class="Identifier">%<span class="function">%gs;
383     $highlighted_source =~ s%<span class="Constant">%<span class="number">%gs;
384     $highlighted_source =~ s%<span class="Special">%<span class="symbol">%gs;
385     $highlighted_source =~ s%<span class="Type">%<span class="type">%gs;
387     # remove temp files
388     unlink ($temp_source_file)
389         || die "Can't delete $temp_source_file: $!";
390     unlink ("$temp_source_file.html")
391         || die "Can't delete $temp_source_file.html: $!";
393     return &HighlightSourcePostprocess($type, $highlighted_source);
396 sub HighlightSourcePostprocess {
397     my ($type, $highlighted_source) = @_;
399     # chop of leading and trailing empty lines
400     $highlighted_source =~ s/^[\s\n]+//gs;
401     $highlighted_source =~ s/[\s\n]+$//gs;
403     # turn common urls in comments into links
404     $highlighted_source =~ s%<span class="url">(.*?)</span>%<span class="url"><a href="$1">$1</a></span>%gs;
406     # we do own line-numbering
407     my $source_lines="";
408     my $line_count = () = $highlighted_source =~ /\n/gs;
409     for (my $i=1; $i < ($line_count+2); $i++) {
410         $source_lines.="$i\n";
411     }
412     $source_lines =~ s/\n\Z//;
414     return <<END_OF_HTML
415 <div class="$type">
416   <table class="listing_frame" border="0" cellpadding="0" cellspacing="0">
417     <tbody>
418       <tr>
419         <td class="listing_lines" align="right"><pre>$source_lines</pre></td>
420         <td class="listing_code"><pre class="programlisting">$highlighted_source</pre></td>
421       </tr>
422     </tbody>
423   </table>
424 </div>
425 END_OF_HTML
429 #############################################################################
430 # Function    : CreateValidSGMLID
431 # Description : Creates a valid SGML 'id' from the given string.
432 #               NOTE: SGML ids are case-insensitive, so we have a few special
433 #                     cases to avoid clashes of ids.
434 # Arguments   : $id - the string to be converted into a valid SGML id.
435 #############################################################################
437 sub CreateValidSGMLID {
438     my ($id) = $_[0];
440     # Special case, '_' would end up as '' so we use 'gettext-macro' instead.
441     if ($id eq "_") { return "gettext-macro"; }
443     $id =~ s/[_ ]/-/g;
444     $id =~ s/[,\.]//g;
445     $id =~ s/^-*//;
446     $id =~ s/::/-/g;
447     $id =~ s/:/--/g;
449     # Append ":CAPS" to all all-caps identifiers
450     if ($id !~ /[a-z]/ && $id !~ /-CAPS$/) { $id .= ":CAPS" };
452     return $id;