]> git.sur5r.net Git - cc65/blob - src/ca65html/ca65html
Use a broader character set for labels, so we can save a few bytes (these
[cc65] / src / ca65html / ca65html
1 #!/usr/bin/perl
2 ###############################################################################
3 #                                                                             #
4 #                                   main.c                                    #
5 #                                                                             #
6 #                      Convert a ca65 source into HTML                        #
7 #                                                                             #
8 #                                                                             #
9 #                                                                             #
10 #  (C) 2000      Ullrich von Bassewitz                                        #
11 #                Wacholderweg 14                                              #
12 #                D-70597 Stuttgart                                            #
13 #  EMail:        uz@musoftware.de                                             #
14 #                                                                             #
15 #                                                                             #
16 #  This software is provided 'as-is', without any expressed or implied        #
17 #  warranty.  In no event will the authors be held liable for any damages     #
18 #  arising from the use of this software.                                     #
19 #                                                                             #
20 #  Permission is granted to anyone to use this software for any purpose,      #
21 #  including commercial applications, and to alter it and redistribute it     #
22 #  freely, subject to the following restrictions:                             #
23 #                                                                             #
24 #  1. The origin of this software must not be misrepresented; you must not    #
25 #     claim that you wrote the original software. If you use this software    #
26 #     in a product, an acknowledgment in the product documentation would be   #
27 #     appreciated but is not required.                                        #
28 #  2. Altered source versions must be plainly marked as such, and must not    #
29 #     be misrepresented as being the original software.                       #
30 #  3. This notice may not be removed or altered from any source               #
31 #     distribution.                                                           #
32 #                                                                             #
33 ###############################################################################
34
35
36
37 use strict 'vars';
38 use warnings;
39
40 # Modules
41 use Getopt::Long;
42
43
44
45 #-----------------------------------------------------------------------------#
46 #                                  Variables                                  #
47 # ----------------------------------------------------------------------------#
48
49
50
51 # Global variables
52 my %Files       = ();           # List of all files.
53 my $FileCount   = 0;            # Number of input files
54 my %Exports     = ();           # List of exported symbols.
55 my %Imports     = ();           # List of imported symbols.
56 my %Labels      = ();           # List of all labels
57 my $LabelNum    = 0;            # Counter to generate unique labels
58
59 # Command line options
60 my $BGColor     = "#FFFFFF";    # Background color
61 my $Debug       = 0;            # No debugging
62 my $Help        = 0;            # Help flag
63 my $HTMLDir     = "";           # Directory in which to create the files
64 my $IndexCols   = 6;            # Columns in the file listing
65 my $IndexTitle  = "Index";      # Title of index page
66 my $IndexName   = "index.html"; # Name of index page
67 my $IndexPage   = 0;            # Create an index page
68 my $LinkStyle   = 0;            # Default link style
69 my $ReplaceExt  = 0;            # Replace extension instead of appending
70 my $TextColor   = "#000000";    # Text color
71 my $Verbose     = 0;            # Be quiet
72
73 # Table used to convert the label number into names
74 my @NameTab     = ("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K",
75                    "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
76                    "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6",
77                    "7", "8", "9");
78
79
80
81 #-----------------------------------------------------------------------------#
82 #                              Helper functions                               #
83 # ----------------------------------------------------------------------------#
84
85
86
87 # Terminate with an error
88 sub Abort {
89     print STDERR "ca65html: @_\n";
90     exit 1;
91 }
92
93 # Print a message if verbose is true
94 sub Gabble {
95     if ($Verbose) {
96         print "ca65html: @_\n";
97     }
98 }
99
100 # Generate a label and return it
101 sub GenLabel {
102
103     my $I;
104     my $L = "";;
105     my $Num = $LabelNum++;
106
107     # Generate the label
108     for ($I = 0; $I < 4; $I++) {
109         $L = $NameTab[$Num % 36] . $L;
110         $Num /= 36;
111     }
112     return $L;
113 }
114
115 # Make an output file name from an input file name
116 sub GetOutName {
117
118     # Input name is parameter
119     my $InName = $_[0];
120
121     # Create the output file name from the input file name
122     if ($ReplaceExt && $InName =~ /^(.+)\.([^\.\/]*)$/) {
123         return "$1.html";
124     } else {
125         return "$InName.html";
126     }
127 }
128
129 # Remove illegal characters from a string
130 sub Cleanup {
131     my $S = shift (@_);
132     $S =~ s/&/&amp;/g;
133     $S =~ s/</&lt;/g;
134     $S =~ s/>/&gt;/g;
135     $S =~ s/\"/&quot;/g;
136     return $S;
137 }
138
139 # Strip a path from a filename and return just the name
140 sub StripPath {
141
142     # Filename is argument
143     my $FileName = $_[0];
144
145     # Remove a path name if we have one
146     $FileName =~ /^(.*?)([^\/]*)$/;
147     return $2;
148 }
149
150
151
152 #-----------------------------------------------------------------------------#
153 #                         Document header and footer                          #
154 # ----------------------------------------------------------------------------#
155
156
157
158 # Print the document header
159 sub DocHeader {
160     my $OUT = shift (@_);
161     my $Asm = shift (@_);
162     print $OUT <<"EOF";
163 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html-40/loose.dtd">
164 <html>
165 <head>
166 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
167 <meta name="GENERATOR" content="ca65html">
168 <title>$Asm</title>
169 </head>
170 <body bgcolor="$BGColor" text="$TextColor" link="#0000d0" vlink="#000060" alink="#00d0d0">
171 <p><br><p>
172 <center><h1>$Asm</h1></center>
173 <hr><p><br><p>
174 <pre>
175 EOF
176 }
177
178 # Print the document footer
179 sub DocFooter {
180     my $OUT  = shift (@_);
181     my $Name = shift (@_);
182
183     # Get the current date and time
184     my $Today = localtime;
185
186     print $OUT <<"EOF";
187 </pre>
188 <p><br><p>
189 <hr size=1 noshade>
190 <address>
191 <a href="http://validator.w3.org/check/referer"><img border=0 src="http://validator.w3.org/images/vh40" alt="Valid HTML 4.0!" height=31 width=88 align=right></a>
192 $Name; generated on $Today by ca65html<br>
193 <a href=\"mailto:uz\@cc65.org\">uz\@cc65.org</a>
194 </address>
195 </body>
196 </html>
197 EOF
198 }
199
200
201
202 #-----------------------------------------------------------------------------#
203 #                            File list management                             #
204 # ----------------------------------------------------------------------------#
205
206
207
208 sub AddFile {
209
210     # Argument is file to add
211     my $FileName = $_[0];
212
213     # Get just the name (remove a path if there is one)
214     my $Name = StripPath ($FileName);
215
216     # Check if we have the file already
217     if (exists ($Files{$Name})) {
218         Gabble ("File \"$FileName\" already known");
219         return;
220     }
221
222     # Check with the full pathname. If we don't find it, search in the current
223     # directory
224     if (-f $FileName && -r $FileName) {
225         $Files{$Name} = $FileName;
226         $FileCount++;
227     } elsif (-f $Name && -r $Name) {
228         $Files{$Name} = $Name;
229         $FileCount++;
230     } else {
231         Abort ("$FileName not found or not readable");
232     }
233 }
234
235
236
237 #-----------------------------------------------------------------------------#
238 #                       Referencing and defining labels                       #
239 # ----------------------------------------------------------------------------#
240
241
242
243 # Get a label reference
244 sub RefLabel {
245
246     # Arguments are: Filename, identifier, item that should be tagged
247     my $FileName = $_[0];
248     my $Id       = $_[1];
249     my $Item     = $_[2];
250
251     # Search for the identifier in the list of labels
252     if (exists ($Labels{$FileName}{$Id})) {
253         # It is a label (in this file)
254         return sprintf ("<a href=\"#%s\">%s</a>", $Labels{$FileName}{$Id}, $Item);
255     } elsif (exists ($Imports{$FileName}{$Id})) {
256         # It is an import. If LinkStyle is 1, or if the file exporting the
257         # identifier is not visible, we link to the .import statement in the
258         # current file. Otherwise we link directly to the referenced symbol
259         # in the file that exports it.
260         if ($LinkStyle == 1 or not exists ($Exports{$Id})) {
261             return sprintf ("<a href=\"#%s\">%s</a>", $Imports{$FileName}{$Id}, $Item);
262         } else {
263             # Get the filename from the export
264             my $Label;
265             ($FileName, $Label) = split (/#/, $Exports{$Id});
266             if (not defined ($Labels{$FileName}{$Id})) {
267                 # This may currently happen because we don't see .include
268                 # statements, so we may have an export but no definition.
269                 # Link to the .export statement instead
270                 $Label = $Exports{$Id};
271             } else {
272                 # Link to the definition in the file
273                 $Label = sprintf ("%s#%s", $FileName, $Labels{$FileName}{$Id});
274             }
275             return sprintf ("<a href=\"%s\">%s</a>", $Label, $Item);
276         }
277     } else {
278         # The symbol is unknown, return as is
279         return $Item;
280     }
281 }
282
283
284
285 #-----------------------------------------------------------------------------#
286 #                                   Pass 1                                    #
287 # ----------------------------------------------------------------------------#
288
289
290
291 # Process1: Read one file for the first time.
292 sub Process1 {
293
294     # Variables
295     my $Line;
296     my $Id;
297
298     # Filename is parameter
299     my $InName = shift(@_);
300
301     # Create the output file name from the input file name
302     my $OutName = GetOutName ($InName);
303
304     # Current cheap local label prefix is empty
305     my $CheapPrefix = "";
306
307     # Open a the input file
308     my $FileName = $Files{$InName};     # Includes path if needed
309     open (INPUT, "<$FileName") or Abort ("Cannot open $FileName: $!");
310
311     # Keep the user happy
312     Gabble ("$FileName => $OutName");
313
314     # Read and process all lines from the file
315     while ($Line = <INPUT>) {
316
317         # Remove the newline
318         chop ($Line);
319
320         # Check for a label
321         if ($Line =~ /^\s*(\@?)([_a-zA-Z][_\w]*)\s*(:|=)/) {
322
323             # Is this a local label?
324             if ($1 eq "\@") {
325                 # Use the prefix
326                 $Id = "$CheapPrefix$1$2";
327             } else {
328                 # Use as is
329                 $Id = $2;
330                 # Remember the id as new cheap local prefix
331                 $CheapPrefix = $Id;
332             }
333
334             # Remember the label
335             $Labels{$OutName}{$Id} = GenLabel();
336
337         # Check for an import statement
338         } elsif ($Line =~ /^\s*(\.import|\.importzp)\s+(.*?)(\s*)(;.*$|$)/) {
339
340             # Split into a list of identifiers
341             my @Ids = split (/\s*,\s*/, $2);
342             for $Id (@Ids) {
343                 $Imports{$OutName}{$Id} = GenLabel();
344             }
345
346         # Check for an export statement
347         } elsif ($Line =~ /^\s*(\.export|\.exportzp)\s+(.*?)(\s*)(;.*$|$)/) {
348
349             # Split into a list of identifiers
350             my @Ids = split (/\s*,\s*/, $2);
351             for $Id (@Ids) {
352                 $Exports{$Id} = sprintf ("%s#%s", $OutName, GenLabel());
353             }
354
355         # Check for a .proc statement
356         } elsif ($Line =~ /^\s*\.proc\s+([_a-zA-Z][_\w]*)?.*$/) {
357
358             # Do we have an id?
359             $Id = $1;
360             if ($Id ne "") {
361                 $Labels{$OutName}{$Id} = GenLabel();
362             }
363
364         }
365     }
366
367     # Close the input file
368     close (INPUT);
369 }
370
371
372
373 # Pass1: Read all files for the first time.
374 sub Pass1 () {
375
376     # Keep the user happy
377     Gabble ("Pass 1");
378
379     # Walk over the files
380     for my $InName (keys (%Files)) {
381         # Process one file
382         Process1 ($InName);
383     }
384 }
385
386
387
388 #-----------------------------------------------------------------------------#
389 #                                   Pass 2                                    #
390 # ----------------------------------------------------------------------------#
391
392
393
394 # Process2: Read one file the second time.
395 sub Process2 {
396
397     # Variables
398     my $Base;
399     my $Ext;
400     my $Line;
401     my $OutLine;
402     my $Id;
403     my $Label;
404     my $Operand;
405     my $Comment;
406
407     # Input file is parameter
408     my $InName = shift(@_);
409
410     # Create the output file name from the input file name
411     my $OutName = GetOutName ($InName);
412
413     # Current cheap local label prefix is empty
414     my $CheapPrefix = "";
415
416     # Open a the input file
417     my $FileName = $Files{$InName};     # Includes path if needed
418     open (INPUT, "<$FileName") or Abort ("Cannot open $FileName: $!");
419
420     # Open the output file and print the HTML header
421     open (OUTPUT, ">$HTMLDir$OutName") or Abort ("Cannot open $OutName: $!");
422     DocHeader (OUTPUT, $InName);
423
424     # Keep the user happy
425     Gabble ("$FileName => $OutName");
426
427     # The instructions that will have hyperlinks if a label is used
428     my $Ins = "adc|add|and|bcc|bcs|beq|bit|bmi|bne|bpl|bcv|bra|bvs|".
429               "cmp|cpx|cpy|dec|eor|inc|jmp|jsr|lda|ldx|ldy|ora|rol|".
430               "sbc|sta|stx|sty|sub|";
431
432     # Read the input file, replacing references by hyperlinks and mark
433     # labels as link targets.
434     while ($Line = <INPUT>) {
435
436         # Remove the newline
437         chop ($Line);
438
439         # Clear the output line
440         $OutLine = "";
441
442         # Check for a label. If we have one, process it and remove it
443         # from the line
444         if ($Line =~ /^\s*?(\@?)([_a-zA-Z][_\w]*)(\s*)(:|=)(.*)$/) {
445
446             # Is this a local label?
447             if ("$1" eq "\@") {
448                 # Use the prefix
449                 $Id = "$CheapPrefix$1$2";
450             } else {
451                 # Use as is
452                 $Id = $2;
453                 # Remember the id as new cheap local prefix
454                 $CheapPrefix = $Id;
455             }
456
457             # Get the label for the id
458             $Label = $Labels{$OutName}{$Id};
459
460             # Print the label with a tag
461             $OutLine .= sprintf ("<a name=\"%s\">%s%s</a>%s%s", $Label, $1, $2, $3, $4);
462
463             # Use the remainder for line
464             $Line = $5;
465         }
466
467         # Print any leading whitespace and remove it, so we don't have to
468         # care about whitespace below.
469         if ($Line =~ /^(\s+)(.*)$/) {
470             $OutLine .= "$1";
471             $Line = $2;
472         }
473
474         # Handle the import statements
475         if ($Line =~ /^(\.import|\.importzp)(\s+)(.*)$/) {
476
477             # Print any fixed stuff from the line and remove it
478             $OutLine .= "$1$2";
479             $Line = $3;
480
481             # Print all identifiers if there are any
482             while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) {
483
484                 # Identifier is $1, remainder is $2
485                 $Id = $1;
486                 $Line = $2;
487
488                 # Variable to assemble HTML representation
489                 my $Item = $Id;
490
491                 # If we have an export for this import, add a link to this
492                 # export definition
493                 if (exists ($Exports{$Id})) {
494                     $Label = $Exports{$Id};
495                     $Item = sprintf ("<a href=\"%s\">%s</a>", $Label, $Item);
496                 }
497
498                 # Make this import a link target
499                 if (exists ($Imports{$OutName}{$Id})) {
500                     $Label = $Imports{$OutName}{$1};
501                     $Item = sprintf ("<a name=\"%s\">%s</a>", $Label, $Item);
502                 }
503
504                 # Add the HTML stuff to the output line
505                 $OutLine .= $Item;
506
507                 # Check if another identifier follows
508                 if ($Line =~ /^(\s*),(\s*)(.*)$/) {
509                     $OutLine .= "$1,$2";
510                     $Line = $3;
511                 } else {
512                     last;
513                 }
514             }
515
516             # Add an remainder if there is one
517             $OutLine .= Cleanup ($Line);
518
519         # Handle export statements
520         } elsif ($Line =~ /^(\.export|\.exportzp)(\s+)(.*)$/) {
521
522             # Print the command the and white space
523             $OutLine .= "$1$2";
524             $Line = $3;
525
526             # Print all identifiers if there are any
527             while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) {
528
529                 # Identifier is $1, remainder is $2
530                 $Id = $1;
531                 $Line = $2;
532
533                 # Variable to assemble HTML representation
534                 my $Item = $Id;
535
536                 # If we have a definition for this export in this file, add
537                 # a link to the definition.
538                 if (exists ($Labels{$OutName}{$1})) {
539                     $Label = $Labels{$OutName}{$1};
540                     $Item = sprintf ("<a href=\"#%s\">%s</a>", $Label, $Item);
541                 }
542
543                 # If we have this identifier in the list of exports, add a
544                 # jump target for the export.
545                 if (exists ($Exports{$Id})) {
546                     $Label = $Exports{$Id};
547                     # Be sure to use only the label part
548                     $Label =~ s/^(.*#)(.*)$/$2/;
549                     $Item = sprintf ("<a name=\"%s\">%s</a>", $Label, $Item);
550                 }
551
552                 # Add the HTML stuff to the output line
553                 $OutLine .= $Item;
554
555                 # Check if another identifier follows
556                 if ($Line =~ /^(\s*),(\s*)(.*)$/) {
557                     $OutLine .= "$1,$2";
558                     $Line = $3;
559                 } else {
560                     last;
561                 }
562             }
563
564             # Add an remainder if there is one
565             $OutLine .= Cleanup ($Line);
566
567         # Check for .addr and .word
568         } elsif ($Line =~ /^(\.addr|\.word)(\s+)(.*)$/) {
569
570             # Print the command the and white space
571             $OutLine .= "$1$2";
572             $Line = $3;
573
574             # Print all identifiers if there are any
575             while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) {
576                 if (exists ($Labels{$OutName}{$1})) {
577                     $Label = $Labels{$OutName}{$1};
578                     $OutLine .= sprintf ("<a href=\"#%s\">%s</a>", $Label, $1);
579                 } else {
580                     $OutLine .= "$1";
581                 }
582                 $Line = $2;
583                 if ($Line =~ /^(\s*),(\s*)(.*)$/) {
584                     $OutLine .= "$1,$2";
585                     $Line = $3;
586                 } else {
587                     last;
588                 }
589             }
590
591             # Add an remainder if there is one
592             $OutLine .= Cleanup ($Line);
593
594         # Handle .proc
595         } elsif ($Line =~ /^(\.proc\s+)([_a-zA-Z][_\w]*)?(.*)$/) {
596
597             # Do we have an identifier?
598             if ($2 ne "") {
599                 # Get the label for the id
600                 $Label = $Labels{$OutName}{$2};
601
602                 # Print the label with a tag
603                 $OutLine .= sprintf ("%s<a name=\"%s\">%s</a>", $1, $Label, $2);
604
605                 # Use the remainder for line
606                 $Line = $3;
607             }
608
609             # Cleanup the remainder and add it
610             $OutLine .= Cleanup ($Line);
611
612         # Handle .include
613         } elsif ($Line =~ /^(\.include)(\s+)\"((?:[^\"]+?|\\\")+)\"(\s*)(;.*$|$)/) {
614
615             # Add the fixed stuff to the output line
616             $OutLine .= "$1$2\"";
617
618             # Get the filename into a named variable
619             my $FileName = $3;
620
621             # Remember the remainder
622             $Line = "\"$4$5";
623
624             # Get the name without a path
625             my $Name = StripPath ($FileName);
626
627             # We don't need FileName any longer as is, so clean it up
628             $FileName = Cleanup ($FileName);
629
630             # If the include file is among the list of our files, add a link,
631             # otherwise just add the name as is.
632             if (exists ($Files{$Name})) {
633                 $OutLine .= sprintf ("<a href=\"%s\">%s</a>", GetOutName ($Name), $FileName);
634             } else {
635                 $OutLine .= $FileName;
636             }
637
638             # Add the remainder
639             $OutLine .= Cleanup ($Line);
640
641         # Check for any legal instruction
642         } elsif ($Line =~ /^($Ins)(\s+)(.*?)(\s*)(;.*$|$)/) {
643
644             # Print the instruction and white space
645             $OutLine .= "$1$2";
646
647             # Remember the remaining parts
648             $Operand = $3;
649             $Comment = Cleanup ("$4$5");
650
651             # Check for the first identifier in the operand and replace it
652             # by a hyperlink
653             if ($Operand =~ /^([^_a-zA-Z]*?)(\@?)([_a-zA-Z][_\w]*)(.*)$/) {
654
655                 # Is this a local label?
656                 if ("$2" eq "\@") {
657                     # Use the prefix
658                     $Id = "$CheapPrefix$2$3";
659                 } else {
660                     # Use as is
661                     $Id = $3;
662                 }
663
664                 # Get the reference to this label if we find it
665                 $Operand = Cleanup($1) . RefLabel($OutName, $Id, $2 . $3) . Cleanup($4);
666             }
667
668             # Reassemble and print the line
669             $OutLine .= "$Operand$Comment";
670
671         } else {
672
673             # Nothing known - print the line
674             $OutLine .= Cleanup ($Line);
675
676         }
677
678         # Print the result
679         print OUTPUT "$OutLine\n";
680     }
681
682     # Print the HTML footer
683     DocFooter (OUTPUT, $OutName);
684
685     # Close the files
686     close (INPUT);
687     close (OUTPUT);
688 }
689
690
691
692 # Pass2: Read all files the second time.
693 sub Pass2 () {
694
695     # Keep the user happy
696     Gabble ("Pass 2");
697
698     # Walk over the files
699     for my $InName (keys (%Files)) {
700         # Process one file
701         Process2 ($InName);
702     }
703 }
704
705
706
707 #-----------------------------------------------------------------------------#
708 #                            Create an index page                             #
709 # ----------------------------------------------------------------------------#
710
711
712
713 # Print a list of all files
714 sub FileIndex {
715
716     # File is argument
717     my $INDEX = $_[0];
718
719     # Print the file list in a table
720     print $INDEX "<h2>Files</h2><p>\n";
721     print $INDEX "<table border=\"0\" width=\"100%\">\n";
722     my $Count = 0;
723     for my $File (sort (keys (%Files))) {
724
725         #
726         if (($Count % $IndexCols) == 0) {
727             print $INDEX "<tr>\n";
728         }
729         printf $INDEX "<td><a href=\"%s\">%s</a></td>\n", GetOutName ($File), $File;
730         if (($Count % $IndexCols) == $IndexCols-1) {
731             print $INDEX "</tr>\n";
732         }
733         $Count++;
734     }
735     if (($Count % $IndexCols) != 0) {
736         print $INDEX "</tr>\n";
737     }
738     print $INDEX "</table><p><br><p>\n";
739 }
740
741
742
743 # Print a list of all exports
744 sub ExportIndex {
745
746     # File is argument
747     my $INDEX = $_[0];
748
749     # Print the file list in a table
750     print $INDEX "<h2>Exports</h2><p>\n";
751     print $INDEX "<table border=\"0\" width=\"100%\">\n";
752     my $Count = 0;
753     for my $Export (sort (keys (%Exports))) {
754
755         # Get the export
756         my $File;
757         my $Label;
758         ($File, $Label) = split (/#/, $Exports{$Export});
759
760         # The label is the label of the export statement. If we can find the
761         # actual label, use this instead.
762         if (exists ($Labels{$File}{$Export})) {
763             $Label = $Labels{$File}{$Export};
764         }
765
766         #
767         if (($Count % $IndexCols) == 0) {
768             print $INDEX "<tr>\n";
769         }
770         printf $INDEX "<td><a href=\"%s#%s\">%s</a></td>\n", $File, $Label, $Export;
771         if (($Count % $IndexCols) == $IndexCols-1) {
772             print $INDEX "</tr>\n";
773         }
774         $Count++;
775     }
776     if (($Count % $IndexCols) != 0) {
777         print $INDEX "</tr>\n";
778     }
779     print $INDEX "</table><p><br><p>\n";
780 }
781
782
783
784 sub CreateIndex {
785
786     # Open the index page file
787     open (INDEX, ">$HTMLDir$IndexName") or Abort ("Cannot open $IndexName: $!");
788
789     # Print the header
790     print INDEX <<"EOF";
791 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html-40/loose.dtd">
792 <html>
793 <head>
794 <meta http-equiv="Content-Type" content=\"text/html; charset=iso-8859-1">
795 <meta name="GENERATOR" content="ca65html">
796 <title>$IndexTitle</title>
797 </head>
798 <body bgcolor="$BGColor" text="$TextColor" link="#0000d0" vlink="#000060" alink="#00d0d0">
799 <p><br><p>
800 <center><h1>$IndexTitle</h1></center>
801 <hr><p><br><p>
802 EOF
803
804     # Print the file list in a table
805     FileIndex (INDEX);
806     ExportIndex (INDEX);
807
808     # Print the document footer
809     DocFooter (INDEX, $IndexName);
810
811     # Close the index file
812     close (INDEX);
813 }
814
815
816
817 #-----------------------------------------------------------------------------#
818 #                           Print usage information                           #
819 # ----------------------------------------------------------------------------#
820
821
822
823 sub Usage {
824     print "Usage: ca65html [options] file ...\n";
825     print "Options:\n";
826     print "  --bgcolor color     Use background color c instead of $BGColor\n";
827     print "  --help              This text\n";
828     print "  --htmldir dir       Specify directory for HTML files\n";
829     print "  --indexcols n       Use n columns on index page (default $IndexCols)\n";
830     print "  --indexname file    Use file for the index file instead of $IndexName\n";
831     print "  --indexpage         Create an index page\n";
832     print "  --indextitle title  Use title as the index title instead of $IndexTitle\n";
833     print "  --linkstyle style   Use the given link style\n";
834     print "  --replaceext        Replace source extension instead of appending .html\n";
835     print "  --textcolor color   Use text color c instead of $TextColor\n";
836     print "  --verbose           Be more verbose\n";
837 }
838
839
840
841 #-----------------------------------------------------------------------------#
842 #                                    Main                                     #
843 # ----------------------------------------------------------------------------#
844
845
846
847 # Get program options
848 GetOptions ("bgcolor=s"         => \$BGColor,
849             "debug!"            => \$Debug,
850             "help"              => \$Help,
851             "htmldir=s"         => \$HTMLDir,
852             "indexcols=i"       => \$IndexCols,
853             "indexname=s"       => \$IndexName,
854             "indexpage"         => \$IndexPage,
855             "indextitle=s"      => \$IndexTitle,
856             "linkstyle=i"       => \$LinkStyle,
857             "replaceext"        => \$ReplaceExt,
858             "textcolor=s"       => \$TextColor,
859             "verbose!"          => \$Verbose,
860             "<>"                => \&AddFile);
861
862 # Check some arguments
863 if ($IndexCols <= 0 || $IndexCols >= 20) {
864     Abort ("Invalid value for --indexcols option");
865 }
866 if ($HTMLDir ne "" && $HTMLDir =~ /[^\/]$/) {
867     # Add a trailing path separator
868     $HTMLDir .= "/";
869 }
870
871
872
873 # Print help if requested
874 if ($Help) {
875     Usage ();
876 }
877
878 # Check if we have input files given
879 if ($FileCount == 0) {
880     Abort ("No input files");
881 }
882
883 # Convert the documents
884 Pass1 ();
885 Pass2 ();
886
887 # Generate an index page if requested
888 if ($IndexPage) {
889     CreateIndex ();
890 }
891
892 # Done
893 exit 0;
894