Updated Spanish translation
[gtk-doc.git] / gtkdoc-fixxref.in
blob774970cb48e73adef067fb2efa5f8f69e769bfb0
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 push @INC, '@PACKAGE_DATA_DIR@';
32 require "gtkdoc-common.pl";
34 # Options
36 # name of documentation module
37 my $MODULE;
38 my $MODULE_DIR;
39 my $HTML_DIR = "";
40 my @EXTRA_DIRS;
41 my $PRINT_VERSION;
42 my $PRINT_HELP;
43 my $SRC_LANG;
45 my %optctl = ('module' => \$MODULE,
46               'module-dir' => \$MODULE_DIR,
47               'html-dir' => \$HTML_DIR,
48               'extra-dir' => \@EXTRA_DIRS,
49               'version' => \$PRINT_VERSION,
50               'help' => \$PRINT_HELP,
51               'src-lang' => \$SRC_LANG);
52 GetOptions(\%optctl, "module=s", "module-dir=s", "html-dir:s", "extra-dir=s@",
53         "src-lang=s", "version", "help");
55 if ($PRINT_VERSION) {
56     print "@VERSION@\n";
57     exit 0;
60 if ($PRINT_HELP) {
61         print <<EOF;
62 gtkdoc-fixxref version @VERSION@ - fix cross references in html files
64 --module=MODULE_NAME    Name of the doc module being parsed
65 --module-dir=MODULE_DIR The directory which contains the generated HTML
66 --html-dir=HTML_DIR     The directory where gtk-doc generated documentation is
67                         installed
68 --extra-dir=EXTRA_DIR   Directories to recursively scan for indices (index.sgml)
69                         in addition to HTML_DIR
70                         May be used more than once for multiple directories
71 --src-lang=SRC_LANG     Programing language used for syntax highlighting. The
72                         available languages depend on the source source
73                         highlighter you use.
74 --version               Print the version of this program
75 --help                  Print this help
76 EOF
77     exit 0;
80 if (!$SRC_LANG) {
81     $SRC_LANG="c"
84 # This contains all the entities and their relative URLs.
85 my %Links;
87 # failing link targets we don't warn about even once
88 my %NoLinks = (
89     'char'  => 1,
90     'double'  => 1,
91     'float'  => 1,
92     'int'  => 1,
93     'long'  => 1,
94     'main'  => 1,
95     'signed'  => 1,
96     'unsigned'  => 1,
97     'va-list' => 1,
98     'void'  => 1,
99     'GBoxed' => 1,
100     'GEnum' => 1,
101     'GFlags' => 1,
102     'GInterface' => 1
103     );
105 my $path_prefix="";
106 if ($HTML_DIR =~ m%(.*?)/share/gtk-doc/html%) {
107     $path_prefix=$1;
108     @TRACE@("Path prefix: $path_prefix");
111 if (!defined $MODULE_DIR) {
112   $MODULE_DIR="$HTML_DIR/$MODULE";
115 my $dir;
117 # We scan the directory containing GLib and any directories in GNOME2_PATH
118 # first, but these will be overriden by any later scans.
119 $dir = `pkg-config --variable=prefix glib-2.0`;
120 $dir =~ s/\s+$//;
121 $dir = $dir . "/share/gtk-doc/html";
122 if (-d $dir && $dir ne $HTML_DIR) {
123     @TRACE@("Scanning GLib directory: $dir");
125     # Some predefined link targets to get links into type hierarchies as these
126     # have no targets. These are always absolute for now.
127     $Links{'GBoxed'} = "$dir/gobject/gobject-Boxed-Types.html";
128     $Links{'GEnum'} = "$dir/gobject/gobject-Enumeration-and-Flag-Types.html";
129     $Links{'GFlags'} = "$dir/gobject/gobject-Enumeration-and-Flag-Types.html";
130     $Links{'GInterface'} = "$dir/gobject/GTypeModule.html";
132     if ($dir !~ m%^\Q$path_prefix\E/%) {
133         &ScanIndices ($dir, 1);
134     } else {
135         &ScanIndices ($dir, 0);
136     }
139 if (defined ($ENV{"GNOME2_PATH"})) {
140     foreach $dir (split (/:/, $ENV{"GNOME2_PATH"})) {
141         $dir = $dir . "/share/gtk-doc/html";
142         if (-d $dir && $dir ne $HTML_DIR) {
143             @TRACE@("Scanning GNOME2_PATH directory: $dir");
144             if ($dir !~ m%^\Q$path_prefix\E/%) {
145                 &ScanIndices ($dir, 1);
146             } else {
147                 &ScanIndices ($dir, 0);
148             }
149         }
150         # ubuntu started to compress this as index.sgml.gz :/
151         # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
152     }
155 @TRACE@("Scanning HTML_DIR directory: $HTML_DIR");
156 &ScanIndices ($HTML_DIR, 0);
157 @TRACE@("Scanning HTML_DIR directory: $MODULE_DIR");
158 &ScanIndices ($MODULE_DIR, 0);
160 # check all extra dirs, but skip already scanned dirs or subdirs of those
161 foreach my $dir (@EXTRA_DIRS) {
162     my $vdir;
163     @TRACE@("Scanning EXTRA_DIR directory: $dir");
165     # If the --extra-dir option is not relative and is not sharing the same
166     # prefix as the target directory of the docs, we need to use absolute
167     # directories for the links
168     if ($dir !~m/^\.\./ &&  $dir !~ m%\Q$path_prefix\E/%) {
169         &ScanIndices ($dir, 1);
170     } else {
171         &ScanIndices ($dir, 0);
172     }
175 if (defined($MODULE)) {
176     open (INPUT, "$MODULE-sections.txt")
177             || die "Can't open $MODULE-sections.txt: $!";
178     my $subsection = "";
179     while (<INPUT>) {
180         if (m/^#/) {
181             next;
183         } elsif (m/^<SECTION>/) {
184             $subsection = "";
185         } elsif (m/^<SUBSECTION\s*(.*)>/i) {
186             $subsection = $1;
187         } elsif (m/^<SUBSECTION>/) {
188             next;
189         } elsif (m/^<TITLE>(.*)<\/TITLE>/) {
190             next;
191         } elsif (m/^<FILE>(.*)<\/FILE>/) {
192             next;
193         } elsif (m/^<INCLUDE>(.*)<\/INCLUDE>/) {
194             next;
195         } elsif (m/^<\/SECTION>/) {
196             next;
197         } elsif (m/^(\S+)/) {
198             my $symbol=CreateValidSGMLID($1);
200             if ($subsection eq "Standard" || $subsection eq "Private") {
201                 $NoLinks{$symbol} = 1;
202             }
203         }
204     }
205     close (INPUT);
208 &FixCrossReferences ($MODULE_DIR);
210 sub ScanIndices {
211     my ($scan_dir, $use_absolute_links) = @_;
212     
213     @TRACE@("Scanning source directory: $scan_dir absolute: $use_absolute_links");
215     # This array holds any subdirectories found.
216     my (@subdirs) = ();
218     opendir (HTMLDIR, $scan_dir) || return;
219     my $file;
220     foreach $file (readdir (HTMLDIR)) {
221         if ($file eq '.' || $file eq '..') {
222             next;
223         } elsif (-d "$scan_dir/$file") {
224             push (@subdirs, $file);
225         } elsif ($file eq "index.sgml") {
226             &ScanIndex ("$scan_dir/$file", $use_absolute_links);
227         }
228         # ubuntu started to compress this as index.sgml.gz :/
229         # https://bugs.launchpad.net/ubuntu/+source/gtk-doc/+bug/77138
230     }
231     closedir (HTMLDIR);
233     # Now recursively scan the subdirectories.
234     my $dir;
235     foreach $dir (sort(@subdirs)) {
236         &ScanIndices ("$scan_dir/$dir", $use_absolute_links);
237     }
240 sub ScanIndex {
241     my ($file, $use_absolute_links) = @_;
243     # Determine the absolute directory, to be added to links in index.sgml
244     # if we need to use an absolute link.
245     # $file will be something like /opt/gnome/share/gtk-doc/html/gtk/index.sgml
246     # We want the part up to 'html' since the links in index.sgml include
247     # the rest.
248     my $dir = "../";
249     if ($use_absolute_links) {
250         # For uninstalled index.sgml files we'd need to map the path to where it
251         # will be installed to
252         if ($file !~ /\.\//) {
253           $file =~ /(.*\/)(.*?)\/index\.sgml/;
254           $dir = $1;
255         }
256     }
257     @TRACE@("Scanning index file=$file, absolute=$use_absolute_links, dir=$dir");
259     open (INDEXFILE, $file)
260         || die "Can't open $file: $!";
261     while (<INDEXFILE>) {
262         if (m/^<ANCHOR\s+id\s*=\s*"([^"]*)"\s+href\s*=\s*"([^"]*)"\s*>/) {
263             @TRACE@("Found id: $1 href: $2");
264             $Links{$1} = "$dir$2";
265         }
266     }
267     close (INDEXFILE);
271 sub FixCrossReferences {
272     my ($scan_dir) = @_;
274     opendir (HTMLDIR, $scan_dir)
275         || die "Can't open HTML directory $scan_dir: $!";
276     my $file;
277     foreach $file (readdir (HTMLDIR)) {
278         if ($file eq '.' || $file eq '..') {
279             next;
280         } elsif ($file =~ m/.html?$/) {
281             &FixHTMLFile ("$scan_dir/$file");
282         }
283     }
284     closedir (HTMLDIR);
288 sub FixHTMLFile {
289     my ($file) = @_;
290     @TRACE@("Fixing file: $file");
292     open (HTMLFILE, $file)
293         || die "Can't open $file: $!";
294     undef $/;
295     my $entire_file = <HTMLFILE>;
296     close (HTMLFILE);
298     if ("@HIGHLIGHT@" ne "") {
299         # FIXME: ideally we'd pass a clue about the example language to the highligher
300         # unfortunately the "language" attribute is not appearing in the html output
301         # we could patch the customization to have <code class="xxx"> inside of <pre>
302         if ("@HIGHLIGHT@" =~ m%/vim$%) {
303             $entire_file =~ s%<div class=\"(example-contents|informalexample)\"><pre class=\"programlisting\">(.*?)</pre></div>%&HighlightSourceVim($1,$2);%gse;
304         }
305         else {
306             $entire_file =~ s%<div class=\"(example-contents|informalexample)\"><pre class=\"programlisting\">(.*?)</pre></div>%&HighlightSource($1,$2);%gse;
307         }
308         # this just broke existing GTKDOCLINK tags
309         # &lt;GTKDOCLINK HREF=&quot;GST-PAD-SINK:CAPS&quot;&gt;GST_PAD_SINK&lt;/GTKDOCLINK&gt;
310         $entire_file =~ s%\&lt;GTKDOCLINK\s+HREF=\&quot;(.*?)\&quot;\&gt;(.*?)\&lt;/GTKDOCLINK\&gt;%\<GTKDOCLINK\ HREF=\"$1\"\>$2\</GTKDOCLINK\>%gs;
312         # from the highlighter we get all the functions marked up
313         # now we could turn them into GTKDOCLINK items
314         $entire_file =~ s%(<span class=\"function\">)(.*?)(</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
315         # we could also try the first item in stuff marked up as 'normal'
316         $entire_file =~ s%(<span class=\"normal\">\s*)(.+?)((\s+.+?)?\s*</span>)%&MakeGtkDocLink($1,$2,$3);%gse;
317     }
319     my @lines = split(/\n/, $entire_file);
320     for (my $i=0; $i<$#lines; $i++) {
321         $lines[$i] =~ s%<GTKDOCLINK\s+HREF="([^"]*)"\s*>(.*?)</GTKDOCLINK\s*>% &MakeXRef($file,$i+1,$1,$2); %ge;
322         #if ($lines[$i] =~ m/GTKDOCLINK/) {
323         #    print "make xref failed for line: ",$lines[$i], "\n";
324         #}
325     }
326     $entire_file = join("\n",@lines);
328     open (NEWFILE, ">$file.new")
329         || die "Can't open $file: $!";
330     print NEWFILE $entire_file;
331     close (NEWFILE);
333     unlink ($file)
334         || die "Can't delete $file: $!";
335     rename ("$file.new", $file)
336         || die "Can't rename $file.new: $!";
339 sub MakeXRef {
340     my ($file, $line, $id, $text) = @_;
342     my $href = $Links{$id};
344     # this is a workaround for some inconsistency we have with CreateValidSGMLID
345     if (!$href && $id =~ m/:/) {
346         my $tid = $id;
347         $tid =~ s/:/--/g;
348         $href = $Links{$tid};
349     }
350     # poor mans plural support
351     if (!$href && $id =~ m/s$/) {
352         my $tid = $id;
353         $tid =~ s/s$//g;
354         $href = $Links{$tid};
355     }
357     if ($href) {
358         # if it is a link to same module, remove path to make it work
359         # uninstalled
360         if (defined($MODULE) && $href =~ m%^\.\./$MODULE/(.*)$%) {
361             $href=$1;
362             @TRACE@("  Fixing link to uninstalled doc: $id, $href, $text");
363         } else {
364             @TRACE@("  Fixing link: $id, $href, $text");
365         }
366         return "<a href=\"$href\">$text</a>";
367     } else {
368         my $warn = 1;
369         @TRACE@("  no link for: $id, $text");
371         # don't warn multiple times and also skip blacklisted (ctypes)
372         $warn = 0 if exists $NoLinks{$id};
373         # if it's a function, don't warn if it does not contain a "_"
374         # (transformed to "-")
375         # - gnome coding style would use '_'
376         # - will avoid wrong warnings for ansi c functions
377         $warn = 0 if ($text =~ m/ class=\"function\"/ && $id !~ m/-/);
378         # if it's a 'return value', don't warn (implicitly created link)
379         $warn = 0 if ($text =~ m/ class=\"returnvalue\"/);
380         # if it's a 'type', don't warn if it starts with lowercase
381         # - gnome coding style would use CamelCase
382         $warn = 0 if ($text =~ m/ class=\"type\"/ && ($id =~ m/^[a-z]/));
383         # don't warn for self links
384         $warn = 0 if ($text eq $id);
386         if ($warn == 1) {
387           &LogWarning ($file, $line, "no link for: '$id' -> ($text).");
388           $NoLinks{$id} = 1;
389         }
390         return $text;
391     }
395 sub MakeGtkDocLink {
396     my ($pre,$symbol,$post) = @_;
398     my $id=CreateValidSGMLID($symbol);
400     # these are implicitely created links in highlighed sources
401     # we don't want warnings for those if the links cannot be resolved.
402     $NoLinks{$id} = 1;
404     #return "<span class=\"$type\"><GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK></span>";
405     return "$pre<GTKDOCLINK HREF=\"$id\">$symbol</GTKDOCLINK>$post";
409 sub HighlightSource {
410     my ($type, $source) = @_;
412     # chop of leading and trailing empty lines
413     $source =~ s/^\s*\n+//gs;
414     $source =~ s/[\s\n]+$//gs;
415     # cut common indent
416     $source =~ m/^(\s*)/;
417     $source =~ s/^$1//gms;
418     # avoid double entity replacement
419     $source =~ s/&lt;/</g;
420     $source =~ s/&gt;/>/g;
421     $source =~ s/&amp;/&/g;
423     # write source to a temp file
424     # FIXME: use .c for now to hint the language to the highlighter
425     my $temp_source_file="$MODULE_DIR/_temp_src.$$.c";
426     open (NEWFILE, ">$temp_source_file") || die "Can't open $temp_source_file: $!";
427     print NEWFILE $source;
428     close (NEWFILE);
430     @TRACE@(" running @HIGHLIGHT@ @HIGHLIGHT_OPTIONS@$temp_source_file ");
432     # format source
433     my $highlighted_source=`@HIGHLIGHT@ @HIGHLIGHT_OPTIONS@$temp_source_file`;
434     if ("@HIGHLIGHT@" =~ m%/source-highlight$%) {
435         $highlighted_source =~ s%^<\!-- .*? -->%%gs;
436         $highlighted_source =~ s%<pre><tt>(.*?)</tt></pre>%$1%gs;
437     }
438     elsif ("@HIGHLIGHT@" =~ m%/highlight$%) {
439         # need to rewrite the stylesheet classes
440         $highlighted_source =~ s%<span class="gtkdoc com">%<span class="comment">%gs;
441         $highlighted_source =~ s%<span class="gtkdoc dir">%<span class="preproc">%gs;
442         $highlighted_source =~ s%<span class="gtkdoc kwd">%<span class="function">%gs;
443         $highlighted_source =~ s%<span class="gtkdoc kwa">%<span class="keyword">%gs;
444         $highlighted_source =~ s%<span class="gtkdoc line">%<span class="linenum">%gs;
445         $highlighted_source =~ s%<span class="gtkdoc num">%<span class="number">%gs;
446         $highlighted_source =~ s%<span class="gtkdoc str">%<span class="string">%gs;
447         $highlighted_source =~ s%<span class="gtkdoc sym">%<span class="symbol">%gs;
448         # maybe also do
449         # $highlighted_source =~ s%</span>(.+)<span%</span><span class="normal">$1</span><span%gs;
450     }
451     # remove temp file
452     unlink ($temp_source_file)
453         || die "Can't delete $temp_source_file: $!";
455     return &HighlightSourcePostprocess($type, $highlighted_source);
458 sub HighlightSourceVim {
459     my ($type, $source) = @_;
461     # chop of leading and trailing empty lines
462     $source =~ s/^\s*\n+//gs;
463     $source =~ s/[\s\n]+$//gs;
464     # cut common indent
465     $source =~ m/^(\s*)/;
466     $source =~ s/^$1//gms;
467     # avoid double entity replacement
468     $source =~ s/&lt;/</g;
469     $source =~ s/&gt;/>/g;
470     $source =~ s/&amp;/&/g;
472     # write source to a temp file
473     my $temp_source_file="$MODULE_DIR/_temp_src.$$.h";
474     open (NEWFILE, ">$temp_source_file") || die "Can't open $temp_source_file: $!";
475     print NEWFILE $source;
476     close (NEWFILE);
478     # format source
479     system "echo 'let html_number_lines=0|let html_use_css=1|let html_use_xhtml=1|e $temp_source_file|syn on|set syntax=$SRC_LANG|run! syntax/2html.vim|w! $temp_source_file.html|qa!' | @HIGHLIGHT@ -n -e -u NONE -T xterm >/dev/null";
481     my $highlighted_source;
482     {
483         local $/;
484         open (NEWFILE, "<$temp_source_file.html");
485         $highlighted_source = <NEWFILE>;
486         close (NEWFILE);
487     }
488     $highlighted_source =~ s#.*<pre\b[^>]*>\n##s;
489     $highlighted_source =~ s#</pre>.*##s;
491     # need to rewrite the stylesheet classes
492     # FIXME: Vim has somewhat different syntax groups
493     $highlighted_source =~ s%<span class="Comment">%<span class="comment">%gs;
494     $highlighted_source =~ s%<span class="PreProc">%<span class="preproc">%gs;
495     $highlighted_source =~ s%<span class="Statement">%<span class="keyword">%gs;
496     $highlighted_source =~ s%<span class="Identifier">%<span class="function">%gs;
497     $highlighted_source =~ s%<span class="Constant">%<span class="number">%gs;
498     $highlighted_source =~ s%<span class="Special">%<span class="symbol">%gs;
499     $highlighted_source =~ s%<span class="Type">%<span class="type">%gs;
501     # remove temp files
502     unlink ($temp_source_file)
503         || die "Can't delete $temp_source_file: $!";
504     unlink ("$temp_source_file.html")
505         || die "Can't delete $temp_source_file.html: $!";
507     return &HighlightSourcePostprocess($type, $highlighted_source);
510 sub HighlightSourcePostprocess {
511     my ($type, $highlighted_source) = @_;
513     # chop of leading and trailing empty lines
514     $highlighted_source =~ s/^[\s\n]+//gs;
515     $highlighted_source =~ s/[\s\n]+$//gs;
517     # turn common urls in comments into links
518     $highlighted_source =~ s%<span class="url">(.*?)</span>%<span class="url"><a href="$1">$1</a></span>%gs;
520     # we do own line-numbering
521     my $source_lines="";
522     my $line_count = () = $highlighted_source =~ /\n/gs;
523     for (my $i=1; $i < ($line_count+2); $i++) {
524         $source_lines.="$i\n";
525     }
526     $source_lines =~ s/\n\Z//;
528     return <<END_OF_HTML
529 <div class="$type">
530   <table class="listing_frame" border="0" cellpadding="0" cellspacing="0">
531     <tbody>
532       <tr>
533         <td class="listing_lines" align="right"><pre>$source_lines</pre></td>
534         <td class="listing_code"><pre class="programlisting">$highlighted_source</pre></td>
535       </tr>
536     </tbody>
537   </table>
538 </div>
539 END_OF_HTML