Update LOCAL_PATCHES after libsanitizer merge.
[official-gcc.git] / gcc / ada / gnathtml.pl
blob548fde1ef0ce5c13c84c531c85c6629995d632f2
1 #! /usr/bin/env perl
3 #-----------------------------------------------------------------------------
4 #- --
5 #- GNAT COMPILER COMPONENTS --
6 #- --
7 #- G N A T H T M L --
8 #- --
9 #- Copyright (C) 1998-2009, Free Software Foundation, Inc. --
10 #- --
11 #- GNAT is free software; you can redistribute it and/or modify it under --
12 #- terms of the GNU General Public License as published by the Free Soft- --
13 #- ware Foundation; either version 3, or (at your option) any later ver- --
14 #- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 #- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 #- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 #- for more details. You should have received a copy of the GNU General --
18 #- Public License distributed with GNAT; see file COPYING3. If not see --
19 #- <http://www.gnu.org/licenses/>. --
20 #- --
21 #- GNAT was originally developed by the GNAT team at New York University. --
22 #- Extensive contributions were provided by Ada Core Technologies Inc. --
23 #- --
24 #-----------------------------------------------------------------------------
26 ## This script converts an Ada file (and its dependency files) to Html.
27 ## Keywords, comments and strings are color-hilighted. If the cross-referencing
28 ## information provided by Gnat (when not using the -gnatx switch) is found,
29 ## the html files will also have some cross-referencing features, i.e. if you
30 ## click on a type, its declaration will be displayed.
32 ## To find more about the switches provided by this script, please use the
33 ## following command :
34 ## perl gnathtml.pl -h
35 ## You may also change the first line of this script to indicates where Perl is
36 ## installed on your machine, so that you can just type
37 ## gnathtml.pl -h
39 ## Unless you supply another directory with the -odir switch, the html files
40 ## will be saved saved in a html subdirectory
42 use Cwd 'abs_path';
43 use File::Basename;
45 ### Print help if necessary
46 sub print_usage
48 print "Usage is:\n";
49 print " $0 [switches] main_file[.adb] main_file2[.adb] ...\n";
50 print " -83 : Use Ada83 keywords only (default is Ada95)\n";
51 print " -cc color : Choose the color for comments\n";
52 print " -d : Convert also the files which main_file depends on\n";
53 print " -D : same as -d, also looks for files in the standard library\n";
54 print " -f : Include cross-references for local entities too\n";
55 print " -absolute : Display absolute filenames in the headers\n";
56 print " -h : Print this help page\n";
57 print " -lnb : Display line numbers every nb lines\n";
58 print " -Idir : Specify library/object files search path\n";
59 print " -odir : Name of the directory where the html files will be\n";
60 print " saved. Default is 'html/'\n";
61 print " -pfile : Use file as a project file (.adp file)\n";
62 print " -sc color : Choose the color for symbol definitions\n";
63 print " -Tfile : Read the name of the files from file rather than the\n";
64 print " command line\n";
65 print " -ext ext : Choose the generated file names extension (default\n";
66 print " is htm)\n";
67 print "This program attempts to generate an html file from an Ada file\n";
68 exit;
71 ### Parse the command line
72 local ($ada83_mode) = 0;
73 local ($prjfile) = "";
74 local (@list_files) = ();
75 local ($line_numbers) = 0;
76 local ($dependencies) = 0;
77 local ($standard_library) = 0;
78 local ($output_dir) = "html";
79 local ($xref_variable) = 0;
80 local (@search_dir) = ('.');
81 local ($tab_size) = 8;
82 local ($comment_color) = "green";
83 local ($symbol_color) = "red";
84 local ($absolute) = 0;
85 local ($fileext) = "htm";
87 while ($_ = shift @ARGV)
89 /^-83$/ && do { $ada83_mode = 1; };
90 /^-d$/ && do { $dependencies = 1; };
91 /^-D$/ && do { $dependencies = 1;
92 $standard_library = 1; };
93 /^-f$/ && do { $xref_variable = 1; };
94 /^-absolute$/ && do {$absolute = 1; };
95 /^-h$/ && do { &print_usage; };
96 /^[^-]/ && do { $_ .= ".adb" if (! /\.ad[bs]$/);
97 push (@list_files, $_); };
99 if (/^-o\s*(.*)$/)
101 $output_dir = ($1 eq "") ? shift @ARGV : $1;
102 chop $output_dir if ($output_dir =~ /\/$/);
103 &print_usage if ($output_dir =~ /^-/ || $output_dir eq "");
106 if (/^-T\s*(.*)$/)
108 my ($source_file) = ($1 eq "") ? shift @ARGV : $1;
109 local (*SOURCE);
110 open (SOURCE, "$source_file") || die "file not found: $source_file";
111 while (<SOURCE>) {
112 @files = split;
113 foreach (@files) {
114 $_ .= ".adb" if (! /\.ad[bs]$/);
115 push (@list_files, $_);
120 if (/^-cc\s*(.*)$/)
122 $comment_color = ($1 eq "") ? shift @ARGV : $1;
123 &print_usage if ($comment_color =~ /^-/ || $comment_color eq "");
126 if (/^-sc\s*(.*)$/)
128 $symbol_color = ($1 eq "") ? shift @ARGV : $1;
129 &print_usage if ($symbol_color =~ /^-/ || $symbol_color eq "");
132 if (/^-I\s*(.*)$/)
134 push (@search_dir, ($1 eq "") ? scalar (shift @ARGV) : $1);
137 if (/^-p\s*(.*)$/)
139 $prjfile = ($1 eq "") ? shift @ARGV : $1;
140 &print_usage if ($prjfile =~ /^-/ || $prjfile eq "");
143 if (/^-l\s*(.*)$/)
145 $line_numbers = ($1 eq "") ? shift @ARGV : $1;
146 &print_usage if ($line_numbers =~ /^-/ || $line_numbers eq "");
149 if (/^-ext\s*(.*)$/)
151 $fileext = ($1 eq "") ? shift @ARGV : $1;
152 &print_usage if ($fileext =~ /^-/ || $fileext eq "");
156 &print_usage if ($#list_files == -1);
157 local (@original_list) = @list_files;
159 ## This regexp should match all the files from the standard library (and only them)
160 ## Note that at this stage the '.' in the file names has been replaced with __
161 $standard_file_regexp="^([agis]-|ada__|gnat__|system__|interface__).*\$";
163 local (@src_dir) = ();
164 local (@obj_dir) = ();
166 if ($standard_library) {
167 open (PIPE, "gnatls -v | ");
168 local ($mode) = "";
169 while (defined ($_ = <PIPE>)) {
170 chop;
171 s/^\s+//;
172 $_ = './' if (/<Current_Directory>/);
173 next if (/^$/);
175 if (/Source Search Path:/) {
176 $mode = 's';
178 elsif (/Object Search Path:/) {
179 $mode = 'o';
181 elsif ($mode eq 's') {
182 push (@src_dir, $_);
184 elsif ($mode eq 'o') {
185 push (@obj_dir, $_);
188 close (PIPE);
190 else
192 push (@src_dir, "./");
193 push (@obj_dir, "./");
196 foreach (@list_files) {
197 local ($dir) = $_;
198 $dir =~ s/\/([^\/]+)$//;
199 push (@src_dir, $dir. '/');
200 push (@obj_dir, $dir. '/');
203 ### Defines and compiles the Ada key words :
204 local (@Ada_keywords) = ('abort', 'abs', 'accept', 'access', 'all', 'and',
205 'array', 'at', 'begin', 'body', 'case', 'constant',
206 'declare', 'delay', 'delta', 'digits', 'do', 'else',
207 'elsif', 'end', 'entry', 'exception', 'exit', 'for',
208 'function', 'generic', 'goto', 'if', 'in', 'is',
209 'limited', 'loop', 'mod', 'new', 'not', 'null', 'of',
210 'or', 'others', 'out', 'package', 'pragma', 'private',
211 'procedure', 'raise', 'range', 'record', 'rem',
212 'renames', 'return', 'reverse', 'select', 'separate',
213 'subtype', 'task', 'terminate', 'then', 'type',
214 'until', 'use', 'when', 'while', 'with', 'xor');
215 local (@Ada95_keywords) = ('abstract', 'aliased', 'protected', 'requeue',
216 'tagged');
218 local (%keywords) = ();
219 grep (++ $keywords{$_}, @Ada_keywords);
220 grep (++ $keywords{$_}, @Ada95_keywords) unless ($ada83_mode);
222 ### Symbols declarations for the current file
223 ### format is (line_column => 1, ...)
224 local (%symbols);
226 ### Symbols usage for the current file
227 ### format is ($adafile#$line_$column => $htmlfile#$linedecl_$columndecl, ...)
228 local (%symbols_used);
230 ### the global index of all symbols
231 ### format is ($name => [[file, line, column], [file, line, column], ...])
232 local (%global_index);
234 #########
235 ## This function create the header of every html file.
236 ## These header is returned as a string
237 ## Params: - Name of the Ada file associated with this html file
238 #########
239 sub create_header
241 local ($adafile) = shift;
242 local ($string) = "<HEAD><TITLE>$adafile</TITLE></HEAD>
243 <BODY>\n";
245 if ($adafile ne "")
247 $string .= "<HR><DIV ALIGN=\"center\"><H1> File : $adafile "
248 . "</H1></DIV><HR>\n<PRE>";
250 return $string;
253 #########
254 ## Protect a string (or character) from the Html parser
255 ## Params: - the string to protect
256 ## Out: - the protected string
257 #########
258 sub protect_string
260 local ($string) = shift;
261 $string =~ s/&/&amp;/g;
262 $string =~ s/</&lt;/g;
263 $string =~ s/>/&gt;/g;
264 return $string;
267 #########
268 ## This function creates the footer of the html file
269 ## The footer is returned as a string
270 ## Params : - Name of the Ada file associated with this html file
271 #########
272 sub create_footer
274 local ($adafile) = shift;
275 local ($string) = "";
276 $string = "</PRE>" if ($adafile ne "");
277 return $string . "</BODY></HTML>\n";
280 #########
281 ## This function creates the string to use for comment output
282 ## Params : - the comment itself
283 #########
284 sub output_comment
286 local ($comment) = &protect_string (shift);
287 return "<FONT COLOR=$comment_color><EM>--$comment</EM></FONT>";
290 ########
291 ## This function creates the string to use for symbols output
292 ## Params : - the symbol to output
293 ## - the current line
294 ## - the current column
295 ########
296 sub output_symbol
298 local ($symbol) = &protect_string (shift);
299 local ($lineno) = shift;
300 local ($column) = shift;
301 return "<FONT COLOR=$symbol_color><A NAME=\"$lineno\_$column\">$symbol</A></FONT>";
304 ########
305 ## This function creates the string to use for keyword output
306 ## Params : - the keyword to output
307 ########
308 sub output_keyword
310 local ($keyw) = shift;
311 return "<b>$keyw</b>";
314 ########
315 ## This function outputs a line number
316 ## Params : - the line number to generate
317 ########
318 sub output_line_number
320 local ($no) = shift;
321 if ($no != -1)
323 return "<EM><FONT SIZE=-1>" . sprintf ("%4d ", $no) . "</FONT></EM>";
325 else
327 return "<FONT SIZE=-1> </FONT>";
331 ########
332 ## Converts a character into the corresponding Ada type
333 ## This is based on the ali format (see lib-xref.adb) in the GNAT sources
334 ## Note: 'f' or 'K' should be returned in case a link from the body to the
335 ## spec needs to be generated.
336 ## Params : - the character to convert
337 ########
338 sub to_type
340 local ($char) = shift;
341 $char =~ tr/a-z/A-Z/;
343 return 'array' if ($char eq 'A');
344 return 'boolean' if ($char eq 'B');
345 return 'class' if ($char eq 'C');
346 return 'decimal' if ($char eq 'D');
347 return 'enumeration' if ($char eq 'E');
348 return 'floating point' if ($char eq 'F');
349 return 'signed integer' if ($char eq 'I');
350 # return 'generic package' if ($char eq 'K');
351 return 'block' if ($char eq 'L');
352 return 'modular integer' if ($char eq 'M');
353 return 'enumeration literal' if ($char eq 'N');
354 return 'ordinary fixed point' if ($char eq 'O');
355 return 'access' if ($char eq 'P');
356 return 'label' if ($char eq 'Q');
357 return 'record' if ($char eq 'R');
358 return 'string' if ($char eq 'S');
359 return 'task' if ($char eq 'T');
360 return 'f' if ($char eq 'U');
361 return 'f' if ($char eq 'V');
362 return 'exception' if ($char eq 'X');
363 return 'entry' if ($char eq 'Y');
364 return "$char";
367 ########
368 ## Changes a file name to be http compatible
369 ########
370 sub http_string
372 local ($str) = shift;
373 $str =~ s/\//__/g;
374 $str =~ s/\\/__/g;
375 $str =~ s/:/__/g;
376 $str =~ s/\./__/g;
377 return $str;
380 ########
381 ## Creates the complete file-name, with directory
382 ## use the variables read in the .prj file
383 ## Params : - file name
384 ## RETURNS : the relative path_name to the file
385 ########
386 sub get_real_file_name
388 local ($filename) = shift;
389 local ($path) = $filename;
391 foreach (@src_dir)
393 if ( -r "$_$filename")
395 $path = "$_$filename";
396 last;
400 $path =~ s/^\.\///;
401 return $path if (substr ($path, 0, 1) ne '/');
403 ## We want to return relative paths only, so that the name of the HTML files
404 ## can easily be generated
405 local ($pwd) = `pwd`;
406 chop ($pwd);
407 local (@pwd) = split (/\//, $pwd);
408 local (@path) = split (/\//, $path);
410 while (@pwd)
412 if ($pwd [0] ne $path [0])
414 return '../' x ($#pwd + 1) . join ("/", @path);
416 shift @pwd;
417 shift @path;
419 return join ('/', @path);
422 ########
423 ## Reads and parses .adp files
424 ## Params : - adp file name
425 ########
426 sub parse_prj_file
428 local ($filename) = shift;
429 local (@src) = ();
430 local (@obj) = ();
432 print "Parsing project file : $filename\n";
434 open (PRJ, $filename) || do { print " ... sorry, file not found\n";
435 return;
437 while (<PRJ>)
439 chop;
440 s/\/$//;
441 push (@src, $1 . "/") if (/^src_dir=(.*)/);
442 push (@obj, $1 . "/") if (/^obj_dir=(.*)/);
444 unshift (@src_dir, @src);
445 unshift (@obj_dir, @obj);
446 close (PRJ);
449 ########
450 ## Finds a file in the search path
451 ## Params : - the name of the file
452 ## RETURNS : - the directory/file_name
453 ########
454 sub find_file
456 local ($filename) = shift;
458 foreach (@search_dir) {
459 if (-f "$_/$filename") {
460 return "$_/$filename";
463 return $filename;
466 ########
467 ## Inserts a new reference in the list of references
468 ## Params: - Ref as it appears in the .ali file ($line$type$column)
469 ## - Current file for the reference
470 ## - Current offset to be added from the line (handling of
471 ## pragma Source_Reference)
472 ## - Current entity reference
473 ## Modifies: - %symbols_used
474 ########
475 sub create_new_reference
477 local ($ref) = shift;
478 local ($lastfile) = shift;
479 local ($offset) = shift;
480 local ($currentref) = shift;
481 local ($refline, $type, $refcol);
483 ## Do not generate references to the standard library files if we
484 ## do not generate the corresponding html files
485 return if (! $standard_library && $lastfile =~ /$standard_file_regexp/);
487 ($refline, $type, $extern, $refcol) = /(\d+)(.)(<[^>]+>)?(\d+)/;
488 $refline += $offset;
490 ## If we have a body, then we only generate the cross-reference from
491 ## the spec to the body if we have a subprogram (or a package)
494 if ($type eq "b")
495 # && ($symbols {$currentref} eq 'f' || $symbols {$currentref} eq 'K'))
497 local ($cref_file, $cref) = ($currentref =~ /([^\#]+).$fileext\#(.+)/);
499 $symbols_used {"$cref_file#$cref"} = "$lastfile.$fileext#$refline\_$refcol";
500 $symbols_used {"$lastfile#$refline\_$refcol"} = $currentref;
501 $symbols {"$lastfile.$fileext#$refline\_$refcol"} = "body";
504 ## Do not generate cross-references for "e" and "t", since these point to the
505 ## semicolon that terminates the block -- irrelevant for gnathtml
506 ## "p" is also removed, since it is used for primitive subprograms
507 ## "d" is also removed, since it is used for discriminants
508 ## "i" is removed since it is used for implicit references
509 ## "z" is used for generic formals
510 ## "k" is for references to parent package
511 ## "=", "<", ">", "^" is for subprogram parameters
513 elsif ($type !~ /[eztpid=<>^k]/)
515 $symbols_used {"$lastfile#$refline\_$refcol"} = $currentref;
519 ########
520 ## Parses the ali file associated with the current Ada file
521 ## Params : - the complete ali file name
522 ########
523 sub parse_ali
525 local ($filename) = shift;
526 local ($currentfile);
527 local ($currentref);
528 local ($lastfile);
530 # A file | line type column reference
531 local ($reference) = "(?:(?:\\d+\\|)?\\d+.\\d+|\\w+)";
533 # The following variable is used to represent the possible xref information
534 # output by GNAT when -gnatdM is used. It includes renaming references, and
535 # references to the parent type, as well as references to the generic parent
537 local ($typeref) = "(?:=$reference|<$reference>|\\{$reference\\}|\\($reference\\)|\\[$reference\\])?";
539 # The beginning of an entity declaration line in the ALI file
540 local ($decl_line) = "^(\\d+)(.)(\\d+)[ *]([\\w\\d.-]+|\"..?\")$typeref\\s+(\\S.*)?\$";
542 # Contains entries of the form [ filename source_reference_offset]
543 # Offset needs to be added to the lines read in the cross-references, and are
544 # used when the source comes from a gnatchop-ed file. See lib-write.ads, lines
545 # with ^D in the ALI file.
546 local (@reffiles) = ();
548 open (ALI, &find_file ($filename)) || do {
549 print "no ", &find_file ($filename), " file...\n";
550 return;
552 local (@ali) = <ALI>;
553 close (ALI);
555 undef %symbols;
556 undef %symbols_used;
558 foreach (@ali)
560 ## The format of D lines is
561 ## D source-name time-stamp checksum [subunit-name] line:file-name
563 if (/^D\s+([\w\d.-]+)\s+\S+ \S+(\s+\D[^: ]+)?( (\d+):(.*))?/)
565 # The offset will be added to each cross-reference line. If it is
566 # greater than 1, this means that we have a pragma Source_Reference,
567 # and this must not be counted in the xref information.
568 my ($file, $offset) = ($1, (defined $4) ? 2 - $4 : 0);
570 if ($dependencies)
572 push (@list_files, $1) unless (grep (/$file/, @list_files));
574 push (@reffiles, [&http_string (&get_real_file_name ($file)), $offset]);
577 elsif (/^X\s+(\d+)/)
579 $currentfile = $lastfile = $1 - 1;
582 elsif (defined $currentfile && /$decl_line/)
584 my ($line) = $1 + $reffiles[$currentfile][1];
585 next if (! $standard_library
586 && $reffiles[$currentfile][0] =~ /$standard_file_regexp/);
587 if ($xref_variable || $2 eq &uppercases ($2))
589 $currentref = $reffiles[$currentfile][0] . ".$fileext#$line\_$3";
590 $symbols {$currentref} = &to_type ($2);
591 $lastfile = $currentfile;
593 local ($endofline) = $5;
595 foreach (split (" ", $endofline))
597 (s/^(\d+)\|//) && do { $lastfile = $1 - 1; };
598 &create_new_reference
599 ($_, $reffiles[$lastfile][0],
600 $reffiles[$lastfile][1], $currentref);
603 else
605 $currentref = "";
608 elsif (/^\.\s(.*)/ && $reffiles[$currentfile][0] ne "" && $currentref ne "")
610 next if (! $standard_library
611 && $reffiles[$currentfile][0] =~ /$standard_file_regexp/);
612 foreach (split (" ", $1))
614 (s/^(\d+)\|//) && do { $lastfile = $1 - 1; };
615 &create_new_reference
616 ($_, $reffiles[$lastfile][0], $reffiles[$lastfile][1],
617 $currentref);
623 #########
624 ## Return the name of the ALI file to use for a given source
625 ## Params: - Name of the source file
626 ## return: Name and location of the ALI file
627 #########
629 sub ali_file_name {
630 local ($source) = shift;
631 local ($alifilename, $unitname);
632 local ($in_separate) = 0;
634 $source =~ s/\.ad[sb]$//;
635 $alifilename = $source;
636 $unitname = $alifilename;
637 $unitname =~ s/-/./g;
639 ## There are two reasons why we might not find the ALI file: either the
640 ## user did not generate them at all, or we are working on a separate unit.
641 ## Thus, we search in the parent's ALI file.
643 while ($alifilename ne "") {
645 ## Search in the object path
646 foreach (@obj_dir) {
648 ## Check if the ALI file does apply to the source file
649 ## We check the ^D lines, which have the following format:
650 ## D source-name time-stamp checksum [subunit-name] line:file-name
652 if (-r "$_$alifilename.ali") {
653 if ($in_separate) {
654 open (FILE, "$_$alifilename.ali");
656 if (grep (/^D \S+\s+\S+\s+\S+ $unitname/, <FILE>)) {
657 close FILE;
658 return "$_$alifilename.ali";
660 } else {
661 ## If the ALI file doesn't apply to the source file, we can
662 ## return now, since there won't be a parent ALI file above
663 ## anyway
664 close FILE;
665 return "$source.ali";
667 } else {
668 return "$_$alifilename.ali";
673 ## Get the parent's ALI file name
675 if (! ($alifilename =~ s/-[^-]+$//)) {
676 $alifilename = "";
678 $in_separate = 1;
681 return "$source.ali";
684 #########
685 ## Convert a path to an absolute path
686 #########
688 sub to_absolute
690 local ($path) = shift;
691 local ($name, $suffix, $separator);
692 ($name,$path,$suffix) = fileparse ($path, ());
693 $path = &abs_path ($path);
694 $separator = substr ($path, 0, 1);
695 return $path . $separator . $name;
698 #########
699 ## This function outputs the html version of the file FILE
700 ## The output is send to FILE.htm.
701 ## Params : - Name of the file to convert (ends with .ads or .adb)
702 #########
703 sub output_file
705 local ($filename_param) = shift;
706 local ($lineno) = 1;
707 local ($column);
708 local ($found);
710 local ($alifilename) = &ali_file_name ($filename_param);
712 $filename = &get_real_file_name ($filename_param);
713 $found = &find_file ($filename);
715 ## Read the whole file
716 open (FILE, $found) || do {
717 print $found, " not found ... skipping.\n";
718 return 0;
720 local (@file) = <FILE>;
721 close (FILE);
723 ## Parse the .ali file to find the cross-references
724 print "converting ", $filename, "\n";
725 &parse_ali ($alifilename);
727 ## Create and initialize the html file
728 open (OUTPUT, ">$output_dir/" . &http_string ($filename) . ".$fileext")
729 || die "Couldn't write $output_dir/" . &http_string ($filename)
730 . ".$fileext\n";
732 if ($absolute) {
733 print OUTPUT &create_header (&to_absolute ($found)), "\n";
734 } else {
735 print OUTPUT &create_header ($filename_param), "\n";
738 ## Print the file
739 $filename = &http_string ($filename);
740 foreach (@file)
742 local ($index);
743 local ($line) = $_;
744 local ($comment);
746 $column = 1;
747 chop ($line);
749 ## Print either the line number or a space if required
750 if ($line_numbers)
752 if ($lineno % $line_numbers == 0)
754 print OUTPUT &output_line_number ($lineno);
756 else
758 print OUTPUT &output_line_number (-1);
762 ## First, isolate any comment on the line
763 undef $comment;
764 $index = index ($line, '--');
765 if ($index != -1) {
766 $comment = substr ($line, $index + 2);
767 if ($index > 1)
769 $line = substr ($line, 0, $index);
771 else
773 undef $line;
777 ## Then print the line
778 if (defined $line)
780 $index = 0;
781 while ($index < length ($line))
783 local ($substring) = substr ($line, $index);
785 if ($substring =~ /^\t/)
787 print OUTPUT ' ' x ($tab_size - (($column - 1) % $tab_size));
788 $column += $tab_size - (($column - 1) % $tab_size);
789 $index ++;
791 elsif ($substring =~ /^(\w+)/
792 || $substring =~ /^("[^\"]*")/
793 || $substring =~ /^(\W)/)
795 local ($word) = $1;
796 $index += length ($word);
798 local ($lowercase) = $word;
799 $lowercase =~ tr/A-Z/a-z/;
801 if ($keywords{$lowercase})
803 print OUTPUT &output_keyword ($word);
805 elsif ($symbols {"$filename.$fileext#$lineno\_$column"})
807 ## A symbol can both have a link and be a reference for
808 ## another link, as is the case for bodies and
809 ## declarations
811 if ($symbols_used{"$filename#$lineno\_$column"})
813 print OUTPUT "<A HREF=\"",
814 $symbols_used{"$filename#$lineno\_$column"},
815 "\">", &protect_string ($word), "</A>";
816 print OUTPUT &output_symbol ('', $lineno, $column);
818 else
820 print OUTPUT &output_symbol ($word, $lineno, $column);
823 ## insert only functions into the global index
825 if ($symbols {"$filename.$fileext#$lineno\_$column"} eq 'f')
827 push (@{$global_index {$word}},
828 [$filename_param, $filename, $lineno, $column]);
831 elsif ($symbols_used{"$filename#$lineno\_$column"})
833 print OUTPUT "<A HREF=\"",
834 $symbols_used{"$filename#$lineno\_$column"},
835 "\">", &protect_string ($word), "</A>";
837 else
839 print OUTPUT &protect_string ($word);
841 $column += length ($word);
843 else
845 $index ++;
846 $column ++;
847 print OUTPUT &protect_string (substr ($substring, 0, 1));
852 ## Then output the comment
853 print OUTPUT &output_comment ($comment) if (defined $comment);
854 print OUTPUT "\n";
856 $lineno ++;
859 print OUTPUT &create_footer ($filename);
860 close (OUTPUT);
861 return 1;
864 #########
865 ## This function generates the global index
866 #########
867 sub create_index_file
869 open (INDEX, ">$output_dir/index.$fileext") || die "couldn't write $output_dir/index.$fileext";
871 print INDEX <<"EOF";
872 <HTML>
873 <HEAD><TITLE>Source Browser</TITLE></HEAD>
874 <FRAMESET COLS='250,*'>
875 <NOFRAME>
879 local (@files) = &create_file_index;
880 print INDEX join ("\n", @files), "\n";
882 print INDEX "<HR>\n";
883 local (@functions) = &create_function_index;
884 print INDEX join ("\n", @functions), "\n";
886 print INDEX <<"EOF";
887 </NOFRAME>
888 <FRAMESET ROWS='50%,50%'>
889 <FRAME NAME=files SRC=files.$fileext>
890 <FRAME NAME=funcs SRC=funcs.$fileext>
891 </FRAMESET>
892 <FRAME NAME=main SRC=main.$fileext>
893 </FRAMESET>
894 </HTML>
897 close (INDEX);
899 open (MAIN, ">$output_dir/main.$fileext") || die "couldn't write $output_dir/main.$fileext";
900 print MAIN &create_header (""),
901 "<P ALIGN=right>",
902 "<A HREF=main.$fileext TARGET=_top>[No frame version is here]</A>",
903 "<P>",
904 join ("\n", @files), "\n<HR>",
905 join ("\n", @functions), "\n";
907 if ($dependencies) {
908 print MAIN "<HR>\n";
909 print MAIN "You should start your browsing with one of these files:\n";
910 print MAIN "<UL>\n";
911 foreach (@original_list) {
912 print MAIN "<LI><A HREF=", &http_string (&get_real_file_name ($_)),
913 ".$fileext>$_</A>\n";
916 print MAIN &create_footer ("");
917 close (MAIN);
920 #######
921 ## Convert to upper cases (did not exist in Perl 4)
922 #######
924 sub uppercases {
925 local ($tmp) = shift;
926 $tmp =~ tr/a-z/A-Z/;
927 return $tmp;
930 #######
931 ## This function generates the file_index
932 ## RETURN : - table with the html lines to be printed
933 #######
934 sub create_file_index
936 local (@output) = ("<H2 ALIGN=CENTER>Files</H2>");
939 open (FILES, ">$output_dir/files.$fileext") || die "couldn't write $output_dir/files.$fileext";
940 print FILES &create_header (""), join ("\n", @output), "\n";
943 if ($#list_files > 20)
945 local ($last_letter) = '';
946 foreach (sort {&uppercases ($a) cmp &uppercases ($b)} @list_files)
948 next if ($_ eq "");
949 if (&uppercases (substr ($_, 0, 1)) ne $last_letter)
951 if ($last_letter ne '')
953 print INDEX_FILE "</UL></BODY></HTML>\n";
954 close (INDEX_FILE);
956 $last_letter = &uppercases (substr ($_, 0, 1));
957 open (INDEX_FILE, ">$output_dir/files/$last_letter.$fileext")
958 || die "couldn't write $output_dir/files/$last_letter.$fileext";
959 print INDEX_FILE <<"EOF";
960 <HTML><HEAD><TITLE>$last_letter</TITLE></HEAD>
961 <BODY>
962 <H2>Files - $last_letter</H2>
963 <A HREF=../files.$fileext TARGET=_self>[index]</A>
964 <UL COMPACT TYPE=DISC>
967 local ($str) = "<A HREF=files/$last_letter.$fileext>[$last_letter]</A>";
968 push (@output, $str);
969 print FILES "$str\n";
971 print INDEX_FILE "<LI><A HREF=../",
972 &http_string (&get_real_file_name ($_)),
973 ".$fileext TARGET=main>$_</A>\n"; ## Problem with TARGET when in no_frame mode!
976 print INDEX_FILE "</UL></BODY></HTML>\n";
977 close INDEX_FILE;
979 else
981 push (@output, "<UL COMPACT TYPE=DISC>");
982 print FILES "<UL COMPACT TYPE=DISC>";
983 foreach (sort {&uppercases ($a) cmp &uppercases ($b)} @list_files)
985 next if ($_ eq "");
986 local ($ref) = &http_string (&get_real_file_name ($_));
987 push (@output, "<LI><A HREF=$ref.$fileext>$_</A>");
988 print FILES "<LI><A HREF=$ref.$fileext TARGET=main>$_</A>\n";
992 print FILES &create_footer ("");
993 close (FILES);
995 push (@output, "</UL>");
996 return @output;
999 #######
1000 ## This function generates the function_index
1001 ## RETURN : - table with the html lines to be printed
1002 #######
1003 sub create_function_index
1005 local (@output) = ("<H2 ALIGN=CENTER>Functions/Procedures</H2>");
1006 local ($initial) = "";
1008 open (FUNCS, ">$output_dir/funcs.$fileext") || die "couldn't write $output_dir/funcs.$fileext";
1009 print FUNCS &create_header (""), join ("\n", @output), "\n";
1011 ## If there are more than 20 entries, we just want to create some
1012 ## submenus
1013 if (scalar (keys %global_index) > 20)
1015 local ($last_letter) = '';
1016 foreach (sort {&uppercases ($a) cmp &uppercases ($b)} keys %global_index)
1018 if (&uppercases (substr ($_, 0, 1)) ne $last_letter)
1020 if ($last_letter ne '')
1022 print INDEX_FILE "</UL></BODY></HTML>\n";
1023 close (INDEX_FILE);
1026 $last_letter = &uppercases (substr ($_, 0, 1));
1027 $initial = $last_letter;
1028 if ($initial eq '"')
1030 $initial = "operators";
1032 if ($initial ne '.')
1034 open (INDEX_FILE, ">$output_dir/funcs/$initial.$fileext")
1035 || die "couldn't write $output_dir/funcs/$initial.$fileext";
1036 print INDEX_FILE <<"EOF";
1037 <HTML><HEAD><TITLE>$initial</TITLE></HEAD>
1038 <BODY>
1039 <H2>Functions - $initial</H2>
1040 <A HREF=../funcs.$fileext TARGET=_self>[index]</A>
1041 <UL COMPACT TYPE=DISC>
1044 local ($str) = "<A HREF=funcs/$initial.$fileext>[$initial]</A>";
1045 push (@output, $str);
1046 print FUNCS "$str\n";
1049 local ($ref);
1050 local ($is_overloaded) = ($#{$global_index {$_}} > 0 ? 1 : 0);
1051 foreach $ref (@{$global_index {$_}})
1053 ($file, $full_file, $lineno, $column) = @{$ref};
1054 local ($symbol) = ($is_overloaded ? "$_ - $file:$lineno" : $_);
1055 print INDEX_FILE "<LI><A HREF=../$full_file.$fileext#$lineno\_$column TARGET=main>$symbol</A>";
1059 print INDEX_FILE "</UL></BODY></HTML>\n";
1060 close INDEX_FILE;
1062 else
1064 push (@output, "<UL COMPACT TYPE=DISC>");
1065 print FUNCS "<UL COMPACT TYPE=DISC>";
1066 foreach (sort {&uppercases ($a) cmp &uppercases ($b)} keys %global_index)
1068 local ($ref);
1069 local ($is_overloaded) = ($#{$global_index {$_}} > 0 ? 1 : 0);
1070 foreach $ref (@{$global_index {$_}})
1072 ($file, $full_file, $lineno, $column) = @{$ref};
1073 local ($symbol) = ($is_overloaded ? "$_ - $file:$lineno" : $_);
1074 push (@output, "<LI><A HREF=$full_file.$fileext#$lineno\_$column>$symbol</A>");
1075 print FUNCS "<LI><A HREF=$full_file.$fileext#$lineno\_$column TARGET=main>$symbol</A>";
1080 print FUNCS &create_footer ("");
1081 close (FUNCS);
1083 push (@output, "</UL>");
1084 return (@output);
1087 ######
1088 ## Main function
1089 ######
1091 local ($index_file) = 0;
1093 mkdir ($output_dir, 0755) if (! -d $output_dir);
1094 mkdir ($output_dir."/files", 0755) if (! -d $output_dir."/files");
1095 mkdir ($output_dir."/funcs", 0755) if (! -d $output_dir."/funcs");
1097 &parse_prj_file ($prjfile) if ($prjfile);
1099 while ($index_file <= $#list_files)
1101 local ($file) = $list_files [$index_file];
1103 if (&output_file ($file) == 0)
1105 $list_files [$index_file] = "";
1107 $index_file ++;
1109 &create_index_file;
1111 $indexfile = "$output_dir/index.$fileext";
1112 $indexfile =~ s!//!/!g;
1113 print "You can now download the $indexfile file to see the ",
1114 "created pages\n";