Initial add of APIDOC api documentation script. a=leaf

This commit is contained in:
rginda%netscape.com 2000-03-01 01:14:20 +00:00
Родитель 08212e4ea0
Коммит 4406893998
9 изменённых файлов: 1463 добавлений и 0 удалений

27
webtools/apidoc/README Normal file
Просмотреть файл

@ -0,0 +1,27 @@
FILES:
===* parse_devedge_doc.pl
Requires:
nothing.
Description:
Parses the nasty devedge document (jsref.htm) into somewhat nicer xml.
Syntax:
perl parse_devedge_doc.pl < jsref.htm > jsref.xml
===* parse_apidoc.pl
Requires:
XML::Parser (http://search.cpan.org/search?dist=XML-Parser)
Description:
Parses apidoc xml files, producing html output for viewing in normal browsers.
Output will be placed in the specified directory, or ./apidocs if none is
specified. Output pages with content will refer to api-content.css, table
of content pages will refer to api-toc.css.
Syntax:
perl parse_apidoc.pl jsref.xml [<output-directory>]

Просмотреть файл

@ -0,0 +1,55 @@
body {
background: #F9F1D1;
}
.api-entry {
background: white;
}
.entry-heading {
background: lightgrey;
}
.entry-title {
font-weight: bold;
}
.entry-type {
background: black;
color: white;
font-weight: bold;
}
.entry-deprecated {
font-weight: bold;
background: red;
color: white;
}
.entry-summary {
}
.entry-syntax {
background: #EEEEEE;
}
.param-list-head {
background: lightgrey;
}
.param-row-even {
background: white;
}
.entry-description {
}
.entry-example {
}
.entry-notes {
}
.entry-seealso {
background: #EEEEEE;
}

Просмотреть файл

@ -0,0 +1,30 @@
body {
background: #F9F1D1;
}
a {
/* text-decoration: none;*/
}
.toc-title {
background: lightgrey;
}
.toc-abc,
.toc-group-even {
background: white;
}
.toc-group-odd {
background: #EEEEEE;
}
.toc-entry-deprecated {
font-weight: bold;
}
.toc-ind-deprecated {
font-weight: bold;
background: red;
color: white;
}

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<frameset name='doc-frameset' cols='25%,*'>
<frame name='toc-container' src='apidocs/complete-toc.html'>
<frame name='content-container' src='apidocs/complete.html'>
</frameset>
</html>

Просмотреть файл

Просмотреть файл

@ -0,0 +1,877 @@
#!/usr/bin/perl
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is Mozilla WebTools.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Contributor(s):
# Robert Ginda <rginda@netscape.com>, Initial development.
#
use strict;
use XML::Parser;
my $file = shift;
my $outdir = shift || "apidocs";
my $c;
my $tagname;
my $pending_param;
my $pending_text;
my %pending_attrs;
my %groups;
my %externals;
my %toc_externals;
my $user_foot;
my $user_head;
my @tag_stack;
my @text_stack;
my @attr_stack;
my $inited = 0;
my %entries;
my $apiid;
my $API = 0;
my $ENTRY = 1;
my $TYPE = 2;
my $SUMMARY = 3;
my $SYNTAX = 4;
my $PARAM = 5;
my $RETVAL = 6;
my $DESCRIPTION = 7;
my $EXAMPLE = 8;
my $NOTE = 9;
my $SEE_ALSO = 10;
my $DEPRECATED = 11;
my $EXTERNALREF = 12;
my $GROUP = 13;
my $C = 14;
my $P = 15;
my $BR = 16;
my $B = 17;
my $I = 18;
my $S = 19;
my $FOOT = 20;
my $HEAD = 21;
my $COMPLETED = 22;
my @TAGS = ("API", "ENTRY", "TYPE", "SUMMARY", "SYNTAX", "PARAM", "RETVAL",
"DESCRIPTION", "EXAMPLE", "NOTE", "SEEALSO", "DEPRECATED",
"EXTERNALREF", "GROUP", "C", "P", "BR", "B", "I", "S", "FOOT",
"HEAD");
my @CDATA_TAGS = ($TAGS[$SUMMARY], $TAGS[$SYNTAX], $TAGS[$DESCRIPTION],
$TAGS[$EXAMPLE], $TAGS[$NOTE], $TAGS[$PARAM], $TAGS[$C],
$TAGS[$B], $TAGS[$I], $TAGS[$S], $TAGS[$FOOT], $TAGS[$HEAD]);
my @FORMATTING_TAGS = ($TAGS[$P], $TAGS[$C], $TAGS[$B], $TAGS[$I], $TAGS[$BR],
$TAGS[$BR], $TAGS[$S]);
my @FORMAT_CONTAINERS = ($TAGS[$SUMMARY], $TAGS[$PARAM], $TAGS[$RETVAL],
$TAGS[$DESCRIPTION], $TAGS[$NOTE], $TAGS[$C],
$TAGS[$B], $TAGS[$I], $TAGS[$FOOT], $TAGS[$HEAD]);
my @CODE_TAGS = ($TAGS[$SYNTAX], $TAGS[$EXAMPLE]);
my $URLVAR_ENTRY = "{e}";
my $footstr = "<center>This page was generated by " .
"<a href='www.mozilla.org/projects/apidoc'><b>APIDOC</b></a>" .
"</center>\n</body></html>";
my $JS_COMPLETE = ("\n<script>\n" .
"function navToEntry(entry) {\n" .
" window.document.location.hash=entry;\n" .
"}\n" .
"function navToGroup(group) {\n" .
" var f = top.frames['toc-container'];\n" .
" if (!f)\n".
" window.open ('complete-toc.html#' + group, " .
"'toc_container');\n" .
" else {\n" .
" f.document.location.href = 'complete-toc.html';\n" .
" f.document.location.hash = group;\n" .
" }\n" .
"}\n" .
"</script>\n");
my $JS_SPARSE = ("\n<script>\n" .
"function navToEntry(entry) {\n" .
" window.document.location.href='api-' + entry + '.html';\n" .
"}\n" .
"function navToGroup(group) {\n" .
" var f = top.frames['toc-container'];\n" .
" if (!f)\n".
" window.open ('sparse-toc.html#' + group, " .
"'toc_container');\n" .
" else {\n" .
" f.document.location.href = 'sparse-toc.html';\n" .
" f.document.location.hash = group;\n" .
" }\n" .
"}\n" .
"</script>\n");
open (COMPLETE, ">" . $outdir . "/complete.html") ||
die ("Couldn't open $outdir/complete.html.\n");
open (COMPLETE_TOC, ">" . $outdir . "/complete-toc.html") ||
die ("Couldn't open $outdir/complete-toc.html.\n");
open (SPARSE_TOC, ">" . $outdir . "/sparse-toc.html") ||
die ("Couldn't open $outdir/sparse-toc.html.\n");
&main();
sub main {
my $parser = new XML::Parser(ErrorContext => 2);
# pass 1, scan all <ENTRY> tags.
$parser->setHandlers(Start => \&p1_Start, End => \&p1_End);
$parser->parsefile($file);
# sanity check the tag stack from p1
if ($#tag_stack != -1) {
die ("OOPS: p1 left the tag stack in a bad state.\n");
}
# pass 2, populate the $entries hash.
$parser = new XML::Parser(Style => "Stream", ErrorContext => 2);
$parser->parsefile ($file);
# finally, write it all out.
&init_files();
my $k;
my $html;
for $k (sort (keys(%entries))) {
$c = $entries{$k};
$html = &get_entry_html();
&add_entry_complete($html);
&add_entry_sparse($html);
&add_toc_complete();
&add_toc_sparse();
#&debug_write_entry();
}
&write_toc_groups();
&close_files();
}
sub p1_Start {
# pass 1, find all <ENTRY/>, <EXTERNALREF/>, and <GROUP/> tags
# (as well as groups implied by <TYPE/> and <DEPRECATED/> tags), so we
# can do things like auto link <C/> tags that refer to entrys,
# and validate <S/> tags in pass 2.
my $expat = shift;
my $lasttagname = $tagname;
my $n;
my %pending_attrs;
push (@tag_stack, $lasttagname);
$tagname = shift;
while ($n = shift) {
$pending_attrs{$n} = shift;
}
my $value = $pending_attrs{"value"};
my $id = $pending_attrs{"id"};
if ($tagname eq $TAGS[$ENTRY]) {
if ($id) {
$c = $entries{$id} = {$TAGS[$ENTRY] => $id};
} else {
&croak_attr ($expat, $tagname, "id");
}
} elsif ($tagname eq $TAGS[$TYPE]) {
if (!$value) {
&croak_attr ($expat, $tagname, "value");
}
$c->{$tagname} = $value;
push (@{$groups{$value}}, $c->{$TAGS[$ENTRY]});
push (@{$c->{$TAGS[$GROUP]}}, $value);
} elsif ($tagname eq $TAGS[$DEPRECATED]) {
$c->{$tagname} = 1;
push (@{$groups{"Deprecated"}}, $c->{$TAGS[$ENTRY]});
push (@{$c->{$TAGS[$GROUP]}}, "Deprecated");
} elsif ($tagname eq $TAGS[$GROUP]) {
if (($lasttagname ne $TAGS[$API]) &&
($lasttagname ne $TAGS[$ENTRY])) {
$expat->xpcroak ("Tag $tagname can only be contained by ".
"an '" . $TAGS[$API] . "' or '" .
$TAGS[$ENTRY] . "' tag");
}
my $name = $pending_attrs{"name"};
if (!$name) {
&croak_attr ($expat, $tagname, "name");
}
if ($lasttagname ne $TAGS[$ENTRY]) {
if (!$value) {
&croak_attr ($expat, $tagname, "value");
}
} else {
$value = $c->{$TAGS[$ENTRY]};
}
if (!grep (/^$value$/, @{$groups{$name}})) {
# if it isn't already there, add it
push (@{$groups{$name}}, $value);
push (@{$entries{$value}->{$TAGS[$GROUP]}}, $name);
}
} elsif ($tagname eq $TAGS[$EXTERNALREF]) {
my $name = $pending_attrs{"name"};
my $value = $pending_attrs{"value"};
if (!$name) {
&croak_attr ($expat, $tagname, "name");
}
if (!$value) {
&croak_attr ($expat, $tagname, "value");
}
if ($lasttagname eq $TAGS[$API]) {
# if the externalref is a child of the API tag
if ($value =~ /$URLVAR_ENTRY/) {
# and it has a placeholder for the entry id,
# then attach it to every entry
$externals{$name} = $value;
} else {
# otherwise, just put it in the toc.
$toc_externals{$name} = $value;
}
} elsif ($lasttagname eq $TAGS[$ENTRY]) {
# if the externalref is a child of the ENTRY tag
# only attach it to this entry
$c->{$TAGS[$EXTERNALREF]}{$name} = $value;
} else {
$expat->xpcroak ("Tag $tagname can only be contained by ".
"an '" . $TAGS[$API] . "' or '" .
$TAGS[$ENTRY] . "' tag");
}
}
}
sub p1_End {
$tagname = pop (@tag_stack);
}
sub StartTag {
my ($expat) = @_;
$_ =~ /<([^\s>]*)/;
my $lasttagname = $tagname;
$tagname = $1;
push (@tag_stack, $lasttagname);
push (@text_stack, $pending_text);
my $s = $#attr_stack + 1;
$attr_stack[$s]{"foo"} = "bar";
for (keys (%pending_attrs)) {
$attr_stack[$s]{$_} = $pending_attrs{$_};
}
$pending_text = "";
%pending_attrs = %_;
if (!grep(/^$tagname$/, @TAGS)) {
$expat->xpcroak ("Unknown tag '$tagname'");
}
# print ("opening: ");
# &debug_dump_c();
my $value = $pending_attrs{"value"};
my $id = $pending_attrs{"id"};
if ($tagname eq $TAGS[$API]) {
if ($inited) {
$expat->xpcroak ("Only one '$tagname' tag allowed");
}
if (!$id) {
&croak_attr ($expat, $tagname, "id");
}
$apiid = $id;
$inited = 1;
} elsif ($inited) {
if ($tagname eq $TAGS[$ENTRY]) {
if (!$id) {
&croak_attr ($expat, $tagname, "id");
}
$c = $entries{$id};
} elsif ($tagname eq $TAGS[$SEE_ALSO]) {
if (!$value) {
&croak_attr ($expat, $tagname, "value");
} elsif (!$entries{$value}) {
$expat->xpcroak ("Undefined SEEALSO reference, '$value'");
}
if (!grep (/^$value$/, @{$c->{$TAGS[$SEE_ALSO]}})) {
push (@{$c->{$TAGS[$SEE_ALSO]}}, $value);
}
} elsif (grep(/^$tagname$/, @FORMATTING_TAGS)) {
if (!grep(/^$lasttagname$/, @FORMAT_CONTAINERS)) {
$expat->xpcroak ("Tag $lasttagname cannot contain formatting " .
"tags");
}
} elsif (($tagname eq $TAGS[$PARAM]) || ($tagname eq $TAGS[$RETVAL])) {
if ($lasttagname ne $TAGS[$SYNTAX]) {
$expat->xpcroak ("Tag $tagname can only be contained by a '" .
$TAGS[$SYNTAX] . "' tag");
}
if (!$pending_attrs{"name"}) {
if ($tagname eq $TAGS[$RETVAL]) {
$pending_attrs{"name"} = "Return Value";
} else {
&croak_attr ($expat, $tagname, "name");
}
}
if (!$pending_attrs{"type"}) {
$pending_attrs{"type"} = "&nbsp;";
# &croak_attr ($expat, $tagname, "type");
}
} elsif ((($tagname eq $TAGS[$HEAD]) || ($tagname eq $TAGS[$HEAD])) &&
($lasttagname ne $TAGS[$API])) {
$expat->xpcroak ("Tag $tagname can only be contained by ".
"an '" . $TAGS[$API] . "' tag");
}
} else {
$expat->xpcroak ("Tag '$tagname' must be contained in an '" .
$TAGS[$API] . " tag");
}
}
sub EndTag {
my ($expat) = @_;
my $iscontainer = 0;
$_ =~ /<\/([^\s>]*)/;
$tagname = $1;
# print ("closing: ");
# &debug_dump_c();
if (grep(/^$tagname$/, @CDATA_TAGS)) {
$iscontainer = 1;
if ($pending_text eq "") {
$expat->xpcroak ("Empty container '$tagname'.");
}
}
if (grep(/^$tagname$/, @FORMATTING_TAGS)) {
if ($iscontainer) {
if ($tagname eq $TAGS[$C]) {
# code tag
if (($pending_text ne $c->{$TAGS[$ENTRY]}) &&
($entries{$pending_text})) {
# if the contents are a valid entry
# add it to the SEEALSO, in case it's not already there
if (!grep (/^$pending_text$/, @{$c->{$TAGS[$SEE_ALSO]}})) {
push (@{$c->{$TAGS[$SEE_ALSO]}}, $pending_text);
}
# and make it a link
$pending_text = &get_link($pending_text);
}
$pending_text = "<code>$pending_text</code>";
} elsif ($tagname eq $TAGS[$S]) {
# seealso reference
my $value;
if (($value = $entries{$pending_text}) ||
($value = $toc_externals{$pending_text}) ||
($value = $c->{$TAGS[$EXTERNALREF]}{$pending_text})) {
# it's a valid external reference
# put it in this entry's external references incase it isn't
# already there.
$c->{$TAGS[$EXTERNALREF]}{$pending_text} = $value;
$_ = $value;
s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
$pending_text =
"<a href='$_' target='other_window'>" .
"$pending_text</a>";
} elsif ($value = $groups{$pending_text}) {
# it's a valid group
# put it in this entry's group references incase it isn't
# already there.
if ((!$c->{$TAGS[$GROUP]}) ||
(!grep (/^$pending_text$/, @{$c->{$TAGS[$GROUP]}}))) {
push (@{$c->{$TAGS[$GROUP]}}, $pending_text);
}
$pending_text ="<a href='javascript:" .
"navToGroup(\"GROUP_$pending_text\")'>$pending_text</a>";
} else {
# it's just not valid
$expat->xpcroak ("Unknown reference in '" . $TAGS[$S] .
"' tag");
}
} elsif ($tagname eq $TAGS[$B]) {
# bold
$pending_text = "<b>$pending_text</b>";
} elsif ($tagname eq $TAGS[$I]) {
# italic
$pending_text = "<i>$pending_text</i>";
} else {
expat->xpcroak
("OOPS: Unhandled container formatting tag '$tagname'");
}
} else {
if ($tagname eq $TAGS[$P]) {
# paragraph
$pending_text = "<P>";
} elsif ($tagname eq $TAGS[$BR]) {
# br
$pending_text = "<BR>";
} else {
expat->xpcroak
("OOPS: Unhandled non-container formatting tag '$tagname'");
}
}
# combine with previous pendingtext
$pending_text = pop(@text_stack) . $pending_text;
} elsif ($iscontainer) {
# not a formatting tag, store the accumulated pendingtext in the
# right place, after some whitespace trimming
my @lines = split ("\n", $pending_text);
my $iscode = grep (/^$tagname$/, @CODE_TAGS);
my $i;
my $line;
my $result_text = "";
for $i (0 ... $#lines) {
$line = $lines[$i];
if ((($i != 0) && ($i != $#lines)) || ($line =~ /[\S\N]/)) {
if ($iscode) {
$line = &add_leading_nbsp($line);
} else {
$_ = $line;
s/\.\s\s(.)/\.\&nbsp;\&nbsp;$1/g;
$line = $_;
}
$line =~ /^[\s\n]*(.*)[\s\n]*/;
$result_text .= $1 . "\n";
}
}
$_ = $result_text;
# s/\n/<br>/g;
$result_text = $_;
if (($tagname eq $TAGS[$PARAM]) || ($tagname eq $TAGS[$RETVAL])) {
# parameter block
my $name = $pending_attrs{"name"};
my $type = $pending_attrs{"type"};
my $html = ("<td class='param-name'><code>$name</code></td>" .
"<td class='param-type'><code>$type</code></td>" .
"<td class='param-desc'>$result_text</td>\n");
push (@{$c->{$TAGS[$PARAM]}}, $html);
} elsif ($tagname eq $TAGS[$EXAMPLE]) {
$c->{$tagname . "_DESC"} = $pending_attrs{"desc"};
$c->{$tagname} = $result_text;
} elsif ($tagname eq $TAGS[$HEAD]) {
$user_head .= $result_text;
} elsif ($tagname eq $TAGS[$FOOT]) {
$user_foot .= $result_text;
} else {
$c->{$tagname} = $result_text;
}
$pending_text = pop (@text_stack);
} else {
$pending_text = pop (@text_stack);
}
%pending_attrs = %{pop (@attr_stack)};
$tagname = pop (@tag_stack);
# print ("popped: ");
# &debug_dump_c();
}
sub Text {
my ($expat) = @_;
if (/^[\s\n]+$/) {
return;
}
if (!grep(/^$tagname$/, @CDATA_TAGS)) {
$expat->xpcroak ("Tag '$tagname' cannot contain text");
}
$pending_text .= $_;
}
sub EndDocument {
}
sub get_entry_html {
my $html = "";
$c->{$TAGS[$ENTRY]} =~ /\.?(.*)/;
my $id = $1;
$html = "<center><table class='api-entry' width='100%' cellspacing='0'" .
"border='1' cellpadding='10'>\n";
$html .= "<tr><td class='entry-heading'>\n";
$html .= "<table class='entry-heading-table' width='100%' cellpadding='5'" .
"cellspacing='0'><tr>\n";
$html .= "<td class='entry-title' valign='center'><font size='+5'>" .
$id . "</font></td>\n";
$html .= "<td class='entry-type' align='center' width='25%'>" .
$c->{$TAGS[$TYPE]} . "</td>\n";
if ($c->{$TAGS[$DEPRECATED]}) {
$html .= "<td class='entry-deprecated' align='center' width='25%'>" .
"Deprecated</td>\n";
}
$html .= "</tr></table>\n";
$html .= "</td></tr>\n";
if ($c->{$TAGS[$SUMMARY]}) {
$html .= "<tr><td class='entry-summary'>\n";
$html .= "<h4 class='entry-subhead'>Summary</h4>\n";
$html .= $c->{$TAGS[$SUMMARY]};
$html .= "</td></tr>\n";
}
if ($c->{$TAGS[$SYNTAX]}) {
$html .= "<tr><td class='entry-syntax'>\n";
$html .= "<h4 class='entry-subhead'>Syntax</h4><pre>\n";
$html .= $c->{$TAGS[$SYNTAX]};
$html .= "</pre>\n";
if ($c->{$TAGS[$PARAM]}) {
$html .= "<center><table class='param-list' border='1' " .
"cellpadding='3' cellspacing='1'>";
$html .= "<tr class='param-list-head'>";
$html .= "<th>Name</th><th>Type</th><th>Description</th></tr>\n";
my $param = shift (@{$c->{$TAGS[$PARAM]}});
my $even = 1;
while ($param) {
$_ = $param;
if ($even == 1) {
$html .= "<tr class='param-row-even'>";
} else {
$html .= "<tr class='param-row-odd'>";
}
$param = $_;
$even *= -1;
$html .= $param . "</tr>\n";
$param = shift (@{$c->{$TAGS[$PARAM]}});
}
$html .= "</table></center>\n"
}
$html .= "</td></tr>\n";
}
if ($c->{$TAGS[$DESCRIPTION]}) {
$html .= "<tr><td class='entry-description'>\n";
$html .= "<h4 class='entry-subhead'>Description</h4>\n";
$html .= $c->{$TAGS[$DESCRIPTION]};
$html .= "</td></tr>\n";
}
if ($c->{$TAGS[$EXAMPLE]}) {
$html .= "<tr><td class='entry-example'>\n";
$html .= "<h4 class='entry-subhead'>Example</h4>\n";
if ($c->{$TAGS[$EXAMPLE] . "_DESC"}) {
$html .= $c->{$TAGS[$EXAMPLE] . "_DESC"} . "<br>";
}
$html .= "<pre>" . $c->{$TAGS[$EXAMPLE]};
$html .= "</pre></td></tr>\n";
}
if ($c->{$TAGS[$NOTE]}) {
$html .= "<tr><td class='entry-notes'>\n";
$html .= "<h4 class='entry-subhead'>Notes</h4>\n";
$html .= $c->{$TAGS[$NOTE]};
$html .= "</td></tr>\n";
}
my $sa = get_seealso();
if ($sa) {
$html .= "<tr><td class='entry-seealso'>\n";
$html .= "<h4 class='entry-subhead'>See Also</h4>\n";
$html .= $sa;
$html .= "</td></tr>\n";
}
$html .= "</table></center><br>\n";
return $html;
}
sub get_seealso {
my @links;
my $k;
my $i;
my $html = "";
for (@{$c->{$TAGS[$GROUP]}}) {
push (@links, "<a href='javascript:navToGroup(\"GROUP_$_\")'>$_</a>");
}
if ($#links != -1) {
$html .= "<tr class='seealso-groups'><td>Groups</td>\n";
$html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
}
@links = ();
# global externals (had a parent tag of <API/>)
for $k (keys(%externals)) {
$_ = $externals{$k};
s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
push (@links, "<a href='$_' target='other_window'>$k</a>");
}
# local externals (parented by <ENTRY/>
for $k (keys(%{$c->{$TAGS[$EXTERNALREF]}})) {
$_ = $c->{$TAGS[$EXTERNALREF]}{$k};
s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
push (@links, "<a href='$_' target='other_window'>$k</a>");
}
if ($#links != -1) {
$html .= "<tr class='seealso-externals'><td>Documents</td>\n";
$html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
}
@links = ();
for $k (@{$c->{$TAGS[$SEE_ALSO]}}) {
push (@links, &get_link($k));
}
if ($#links != -1) {
$html .= "<tr class='seealso-internals'><td>Entries</td>\n";
$html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
}
if ($html) {
$html = "<table class='seealso-table'>\n" . $html . "\n</table>\n";
}
return $html;
}
sub add_entry_complete {
my ($html) = @_;
print COMPLETE "<a name='" . $c->{$TAGS[$ENTRY]} . "'></a>\n";
print COMPLETE $html;
}
sub add_entry_sparse {
my ($html) = @_;
my $outfile = $outdir . "/api-" . $c->{$TAGS[$ENTRY]} . ".html";
open (SPARSE, ">$outfile") ||
die ("Couldn't open $outfile.\n");
my $headstr = "<html><head><link rel=StyleSheet href='api-content.css' " .
"TYPE='text/css' MEDIA='screen'>" .
"<title>" . $c->{$TAGS[$ENTRY]} . "</title>" . $JS_SPARSE .
"</head><body bgcolor='white'>\n" .
"<h1 class='title'>$apiid Reference</h1>\n" . $user_head;
print SPARSE $headstr;
print SPARSE $html;
print SPARSE $user_foot;
print SPARSE $footstr;
close SPARSE;
}
sub write_toc_groups {
my @groups = sort(keys (%groups));
my $g;
my $even = 1;
my $head = "</table></center></td></tr>\n" .
"<tr class='toc-title'><th><br><h3>Grouped Listing</h3></th>" .
"</tr>\n";
print COMPLETE_TOC $head;
print SPARSE_TOC $head;
for $g (@groups) {
$head = "<tr><td class='";
if ($even == 1) {
$head .= "toc-group-even";
} else {
$head .= "toc-group-odd";
}
$head .= "'><center><table border='0' cellspacing='0' cellpading='0' " .
"width='100%'>\n";
$head .= "<tr><th><a name='GROUP_$g'>$g</a></th><td>&nbsp;</td></tr>\n";
print COMPLETE_TOC $head;
print SPARSE_TOC $head;
my $e;
for $e (sort(@{$groups{$g}})) {
$c = $entries{$e};
&add_toc_complete();
&add_toc_sparse();
}
$head = "</table></center><br></td></tr>\n";
print COMPLETE_TOC $head;
print SPARSE_TOC $head;
$even *= -1;
}
}
sub add_toc_complete {
print COMPLETE_TOC &add_toc(0);
}
sub add_toc_sparse {
print SPARSE_TOC &add_toc(1);
}
sub add_toc {
my ($is_sparse) = @_;
my $html;
my $classsuffix = $c->{$TAGS[$DEPRECATED]} ? "-deprecated" : "";
$html = "<tr><td class='toc-row$classsuffix'>";
$html .= &get_toc_link($c->{$TAGS[$ENTRY]}, $is_sparse,
"toc-entry$classsuffix")
. "</td>";
if ($classsuffix) {
$html .= "<td class='toc-ind-deprecated' width='10%' " .
"align='center' valign='center'>D</td>";
} else {
$html .= "<td>&nbsp;</td>";
}
$html .= "</tr>\n";
return $html;
}
sub get_link {
my ($entry) = @_;
return ("<a href='javascript:navToEntry(\"$entry\");'>$entry</a>");
}
sub get_toc_link {
my ($entry, $is_sparse, $class) = @_;
if ($is_sparse) {
return "<a class='$class' href='api-$entry.html' " .
"target='content-container'>$entry</a>\n";
} else {
return "<a href='complete.html#$entry' class='$class' " .
"target='content-container'>$entry</a>";
}
}
sub init_files {
my $headstr = "<html><head><link rel=StyleSheet href='api-content.css' " .
"TYPE='text/css' MEDIA='screen'><title>$apiid</title></head>" .
$JS_COMPLETE . "<body bgcolor='white'>\n" .
"<h1 class='title'>$apiid Reference</h1>\n" . $user_head;
print COMPLETE $headstr;
my $tocstr =
("<html><head><link rel=StyleSheet href='api-toc.css' " .
"TYPE='text/css' MEDIA='screen'>" .
"<title>$apiid table of contents</title>" .
"</head>\n<body bgcolor='white'>\n" .
"<h1 class='title'>$apiid Reference</h1><h4>Table of Contents</h4>\n" .
"<center><table class='toc-table' border='1' cellpadding='0' " .
"cellspacing='0' width='100%'>\n" .
"<tr class='toc-title'><th><br><h3>Alphabetical Listing</h3></th>" .
"</tr>\n<tr><td>\n" .
"<center><table class='toc-abc' border='0' cellspacing='0' " .
"cellpadding='0' width='100%'>\n");
print COMPLETE_TOC $tocstr;
print SPARSE_TOC $tocstr;
}
sub close_files {
print COMPLETE $user_foot;
print COMPLETE $footstr;
close COMPLETE;
print COMPLETE_TOC "</table></center>" . $user_foot;
print COMPLETE_TOC $footstr;
close COMPLETE_TOC;
print SPARSE_TOC "</table></center>" . $user_foot;
print SPARSE_TOC $footstr;
close SPARSE_TOC;
}
sub add_leading_nbsp {
my ($str) = @_;
my $i;
my $pfx = "";
if (!($str =~ /^(\s+)/)) {
return $str;
}
my $len = length($1);
for $i (0 .. $len) {
$pfx .= "&nbsp;";
}
substr ($str, 0, $len) = $pfx;
return $str;
}
sub debug_dump_c {
print ("tag: $tagname, attrs: " .
join (", ", keys (%pending_attrs)) .
", stacks: " . $#text_stack . ", " . $#tag_stack . ", " .
$#attr_stack . "\n");
for (0 ... $#attr_stack) {
print ("attribs at $_: " . join (", ", keys (%{$attr_stack[$_]})) .
"\n");
}
}
sub debug_write_entry {
my $i;
for $i (keys(%{$c})) {
my $str = "";
if (($i eq $TAGS[$SEE_ALSO]) || ($i eq ($TAGS[$PARAM]))) {
$str = join (", ", @{$c->{$i}});
} else {
$str = $c->{$i};
}
print ("$i : $str\n");
}
print ("===\n");
}
sub croak_attr {
my ($expat, $tagname, $attr) = @_;
$expat->xpcroak ("Tag $tagname needs an $attr attribute");
}

Просмотреть файл

@ -0,0 +1,393 @@
#!/usr/bin/perl
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is JavaScript Core Tests.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
my $API = 0;
my $ENTRY = 1;
my $TYPE = 2;
my $SUMMARY = 3;
my $SYNTAX = 4;
my $PARAM = 5;
my $RETVAL = 6;
my $DESCRIPTION = 7;
my $EXAMPLE = 8;
my $NOTE = 9;
my $SEE_ALSO = 10;
my $DEPRECATED = 11;
my $EXTERNALREF = 12;
my $GROUP = 13;
my $C = 14;
my $P = 15;
my $B = 16;
my $I = 17;
my $COMPLETED = 18;
my @TAGS = ("API", "ENTRY", "TYPE", "SUMMARY", "SYNTAX", "PARAM", "RETVAL",
"DESCRIPTION", "EXAMPLE", "NOTE", "SEEALSO", "DEPRECATED",
"EXTERNALREF", "GROUP", "C", "P", "B", "I");
my $NAMESPACE = ""; # "APIDOC";
my $TAB = " ";
my $indent_pfx = "";
&parse_old_doc ();
sub parse_old_doc {
my $done = 0;
&output ("<?xml version='1.0' encoding='ISO-8859-1' standalone='yes'?>");
&output ("<!DOCTYPE api>");
&open_container ($TAGS[$API], "id", "JavaScript-1.5");
&tag ($TAGS[$EXTERNALREF], "name", "LXR ID Search", "value",
"http://lxr.mozilla.org/seamonkey/ident?i={e}");
my $line = <>;
while (!$done) {
if ($line =~ /\<H1\>\<A NAME\=\"(.*)\"\>\<\/A\>/i) {
# beginning of a new API entry
$line = &parse_entry ($1);
} else {
$line = "";
}
if ($line eq "") {
$line = <> or $done = 1;
}
}
&close_container ($TAGS[$API]);
}
sub parse_entry {
my $deprecated = 0;
my ($name) = @_;
my $line, $partialline = "";
my $mode = $ENTRY, $submode = 0;
&open_container ($TAGS[$mode], "id", $name);
while ($mode != $COMPLETED) {
if ($partialline) {
$line = $partialline;
$partialline = "";
} else {
$line = <>;
}
if ($line =~ /\<H1\>\<A NAME\=\"(.*)\"\>\<\/A\>/i) {
# oops, somehow we're at the next entry
# stop what we're doing and
# return this line to the caller
&close_container ($TAGS[$mode]);
$partialline = $line;
$mode = $COMPLETED;
} elsif ($mode == $ENTRY) {
if ($line =~ /\<\/A\>\<\/H1\>/i) {
$mode = $TYPE;
}
} elsif ($mode == $TYPE) {
if ($line =~ /\<A NAME=\"\d+\"\>/i) {
# useless line
} elsif ($line =~ /([^\.]+).\s+(.*)/) {
&tag ($TAGS[$mode], "value", $1);
if ($2) {
$mode = $SUMMARY;
&open_container ($TAGS[$mode]);
$partialline = $2;
}
if ($line =~ /deprecated/i) {
$deprecated = 1;
}
}
} elsif ($mode == $SUMMARY) {
if ($line =~ /deprecated/i) {
$deprecated = 1;
}
if ($line =~ /(.*)?(\<\/A\>\<\/P\>)$/) {
&output (&fixup($1));
# if line ended with </A></P>, we're at the end of the summary
&close_container ($TAGS[$mode]);
$mode = $SYNTAX;
} else {
&output ($line);
}
} elsif (($mode == $SYNTAX) || ($mode == $DESCRIPTION) ||
($mode == $EXAMPLE) || ($mode == $NOTE)) {
if ($submode == 0) {
if ($line =~ /\<\/A\>\<\/H4\>/) {
if ($mode == $EXAMPLE) {
$line = <>;
$line = <>; # eat two useless lines
$line = <>; # next is the description
&open_container ($TAGS[$mode], "desc",
&fixup_all($line));
# are you having fun yet?
} else {
&open_container ($TAGS[$mode]);
}
$submode = 1;
}
} elsif ($submode == 1) {
if ($line =~ /<H4><A NAME="Head3;"><\/A>/) {
#start of a new section
&close_container ($TAGS[$mode]);
$submode = 0;
$line = <>;
$mode = $COMPLETED;
if ($line =~ /\<A NAME\=\"\d+\">/) {
$line = <>;
if ($line =~ /(description|example|note|see also)/i) {
if (lc($1) eq "description") {
$mode = $DESCRIPTION;
} elsif (lc($1) eq "example") {
$mode = $EXAMPLE;
} elsif (lc($1) eq "note") {
$mode = $NOTE;
} else {
$mode = $SEE_ALSO;
}
}
}
} elsif ($line =~ /<BLOCKQUOTE><B>NOTE:/) {
# note embedded in description section
&close_container ($TAGS[$mode]);
$mode = $NOTE;
&open_container ($TAGS[$mode]);
} elsif (($mode == $NOTE) && ($line =~ /<\/BLOCKQUOTE>/)) {
# note over
$partialline = '<H4><A NAME="Head3;"></A>';
# dirty little hack to get it to execute the
# 'figure out next mode' logic above.
} elsif (($mode == $SYNTAX) || ($mode == $EXAMPLE)) {
if (($mode == $SYNTAX) &&
($line =~ /(.*)<TABLE BORDER="0">/)) {
# syntax parameter table start
$line = $1;
$submode = 2;
}
$_ = $line;
s/<br>/\n/ig;
s/<[^>]*>//g;
s/^\s*//g;
s/\s*$//g;
s/&nbsp;/ /g;
if (/[\S\N]/) {
print ("$_\n");
}
} elsif ($line =~ /(.*)<TABLE BORDER="0">/) {
&output (&fixup($1));
&output ("<![CDATA[");
&output ('<TABLE BORDER="0">');
$submode = 2;
} elsif ($line =~ /<ul><P><LI>/) {
&output ("<![CDATA[");
&output (&fixup_cdata($line));
$submode = 2;
} else {
# if all else f[l]ails, just print it.
&output (&fixup($line));
}
} elsif (($mode == $SYNTAX) && ($submode == 2)) {
# inside parameter list table
my $col = 0;
my $name, $type, $desc = "";
$line = <>;
while (!($line =~ /<\/TABLE>/)) {
if ((($col == 0) || ($col == 1)) &&
($line =~ /(.*)<\/A><\/P>/)) {
$1 =~ /<CODE>(.*)<\/CODE>/;
if ($col == 0) {
$name = $1;
$col = 1;
} else {
$type = $1;
$col = 2;
}
} elsif (($col == 2) &&
(!($line =~
/<TR><TD VALIGN=baseline ALIGN=left>/))) {
$desc .= &fixup_more ($line);
} elsif ($col == 2) {
&open_container ($TAGS[$PARAM], "name", $name,
"type", $type);
&output ($desc);
&close_container ($TAGS[$PARAM]);
$name = "";
$type = "";
$desc = "";
$col = 0;
}
$line = <>;
}
&open_container ($TAGS[$PARAM], "name", $name,
"type", $type);
&output ($desc);
&close_container ($TAGS[$PARAM]);
$submode = 1;
} elsif ($submode == 2) {
if (($line =~ /<\/TABLE>/) || ($line =~ /<\/ul>/)) {
&output (&fixup_cdata ($line));
&output ("]]>");
$submode = 1;
} else {
&output (&fixup_cdata ($line));
}
}
} elsif ($mode == $SEE_ALSO) {
if ($line =~ /(.*)<\/P>/) {
my $list = &fixup ($1);
my @refs = split(/,\s*/, $list);
for (@refs) {
if ($_) {
&tag ($TAGS[$mode], "value", $_);
}
}
$mode = $COMPLETED;
}
} else {
die ("Unknown mode '$mode' encountered.\n");
}
}
if ($mode != $COMPLETED) {
die ("Bad state");
}
if ($deprecated) {
&tag ($TAGS[$DEPRECATED]);
}
&close_container ($TAGS[$ENTRY]);
return $partialline;
}
sub output {
my ($line) = @_;
s/^\s+//;
s/\s+$//;
if (!($line =~ /^\n*$/)) {
$_ = $line;
s/\n*$//;
s/^\s*\n*//;
if (/[\S\N]/) {
print $indent_pfx . $_ . "\n";
}
}
}
sub fixup_all {
# wipe out ALL markup
($_) = @_;
s/<[^>]*>//g;
s/\n//g;
return $_;
}
sub fixup_more {
# all fixups, plus paragraph->br
($_) = @_;
$_ = &fixup($_);
s/<P\/>/<BR\/>/g;
return $_;
}
sub fixup {
# clean up all markup, and change HTML tags to XML tags
($_) = @_;
s/<CODE>/<C>/g;
s/<\/CODE>/<\/C>/g;
s/<BR>//ig;
s/<\/P>|<P>/<P\/>/g;
s/(<P\/>)+/<P\/>/g;
return &fixup_cdata($_);
}
sub fixup_cdata {
# clean up markup for use in <![CDATA[ tags
($_) = @_;
s/<TD VALIGN=(.*) ALIGN=([^>]*)>/<TD VALIGN='$1' ALIGN='$2'\>/g;
s/<TR><TD VALIGN='baseline' ALIGN='left'><P>/<\/TD><\/TR><TR> <TD VALIGN='baseline' ALIGN='left'><P>/g;
s/<\/B><\/A><TD VALIGN='baseline' ALIGN='left'>/<\/B><\/TD><TD VALIGN='baseline' ALIGN='left'>/ig;
s/<\/P><TD VALIGN='baseline' ALIGN='left'>/<\/TD><TD VALIGN='baseline' ALIGN='left'>/g;
s/<\/TABLE>/<\/TD><\/TR><\/TABLE >/g;
s/<PRE>|<\/PRE>//g;
s/<BR>/<BR\/>/ig;
s/\<A[^\>]+\>//g;
s/\<\/A\>//g;
return $_;
}
sub open_container {
my ($tag_name) = @_;
&open_tag (1, @_);
$indent_pfx .= $TAB;
}
sub tag {
&open_tag (0, @_);
}
sub open_tag {
my $iscontainer = shift(@_);
my $tagname = shift(@_);
my @attrs = @_;
my $attrname;
my $tag = "";
$tag .= "<";
if ($NAMESPACE) {
$tag .= "$NAMESPACE:";
}
$tag .= $tagname;
while ($attrname = shift(@attrs)) {
$tag .= " $attrname='" . shift (@attrs) . "'";
}
if (!$iscontainer) {
$tag .= "/";
}
$tag .= ">";
&output ($tag);
}
sub close_container {
my ($tag_name) = @_;
substr($indent_pfx, 0, length($TAB)) = "";
my $tag = "</";
if ($NAMESPACE) {
$tag .= "$NAMESPACE:";
}
&output ($tag . "$tag_name>");
}

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<frameset name='doc-frameset' cols='30%,*'>
<frame name='toc-container' src='apidocs/sparse-toc.html'>
<frame name='content-container' src='about:blank'>
</frameset>
</html>

Просмотреть файл

@ -0,0 +1,67 @@
<?xml version='1.0' encoding='ISO-8859-1' standalone='yes'?>
<!DOCTYPE api>
<API id='basic test 1'>
<HEAD>
This is the heading.
</HEAD>
<FOOT>
Don't look here!
</FOOT>
<EXTERNALREF name="LXR ID Lookup" value="http://lxr.mozilla.org/mozilla/ident?i={e}"/>
<ENTRY id="foo">
<TYPE value="Function"/>
<SUMMARY>
<C>foo</C> is cool.
</SUMMARY>
<DESCRIPTION>
<C>foo</C> is the function you want to use. Other functions
like <C>bar</C> and <C>baz</C> aren't half as good as foo.
The <S>JSBot page</S> is badly out of date. The <S>Function</S>
group has other functions in this api.
</DESCRIPTION>
<SYNTAX>
void foo(int x, float y)
<PARAM name="x" type="int">
Does what x does.
</PARAM>
<PARAM name="y" type="float">
Does what y does, better than x.
</PARAM>
</SYNTAX>
<EXAMPLE desc="Do it like this or you will suffer!">
foo (1, 2) /* calls foo */
foo (3, 4) /* calls foo with better arguments*/
</EXAMPLE>
<EXTERNALREF name="JSBot page" value="http://www.ndcico.com/jsbot"/>
<SEEALSO value="bar"/>
</ENTRY>
<ENTRY id="bar">
<DEPRECATED/>
<TYPE value="Function"/>
<SUMMARY>
<C>bar</C> is lame.
</SUMMARY>
<DESCRIPTION>
<C>bar</C> is less than half as good as <C>foo</C>.
</DESCRIPTION>
<SYNTAX>
void bar(int x, float y)
<PARAM name="x" type="int">
Does what x does.
</PARAM>
<PARAM name="y" type="float">
Does what y does, better than x.
</PARAM>
</SYNTAX>
<EXAMPLE desc="Do it like this or you will suffer!">
bar (1, 2) /* calls bar */
bar (3, 4) /* calls bar with worser arguments*/
</EXAMPLE>
<GROUP name="Useless Functions"/>
</ENTRY>
<GROUP name="Useless Functions" value="bar"/>
<GROUP name="Cool Functions" value="foo"/>
</API>