3 # The contents of this file are subject to the Netscape Public
4 # License Version 1.1 (the "License"); you may not use this file
5 # except in compliance with the License. You may obtain a copy of
6 # the License at http://www.mozilla.org/NPL/
8 # Software distributed under the License is distributed on an "AS
9 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10 # implied. See the License for the specific language governing
11 # rights and limitations under the License.
13 # The Original Code is Mozilla WebTools.
15 # The Initial Developer of the Original Code is Netscape
16 # Communications Corporation. Portions created by Netscape are
17 # Copyright (C) 1997-1999 Netscape Communications Corporation. All
20 # Alternatively, the contents of this file may be used under the
21 # terms of the GNU Public License (the "GPL"), in which case the
22 # provisions of the GPL are applicable instead of those above.
23 # If you wish to allow use of your version of this file only
24 # under the terms of the GPL and not to allow others to use your
25 # version of this file under the NPL, indicate your decision by
26 # deleting the provisions above and replace them with the notice
27 # and other provisions required by the GPL. If you do not delete
28 # the provisions above, a recipient may use your version of this
29 # file under either the NPL or the GPL.
32 # Robert Ginda <rginda@netscape.com>, Initial development.
33 # Pavel Hlavnicka <pavel@gingerall.cz>, seperate tocs, param linking.
34 # Petr Cimprich <petr@gingerall.cz>, nested frameset fix, encoded URLs.
35 # Petr Cimprich <petr@gingerall.cz>, Mozilla sidebar generated from TOC
42 my $outdir = shift || "apidocs";
83 my @TAGS = ("API", "ENTRY", "TYPE", "SUMMARY", "SYNTAX", "PARAM", "RETVAL",
84 "DESCRIPTION", "EXAMPLE", "NOTE", "SEEALSO", "DEPRECATED",
85 "EXTERNALREF", "GROUP", "C", "P", "BR", "B", "I", "S", "FOOT",
87 my @CDATA_TAGS = ($TAGS[$SUMMARY], $TAGS[$SYNTAX], $TAGS[$DESCRIPTION],
88 $TAGS[$EXAMPLE], $TAGS[$NOTE], $TAGS[$PARAM], $TAGS[$C],
89 $TAGS[$B], $TAGS[$I], $TAGS[$S], $TAGS[$FOOT], $TAGS[$HEAD]);
90 my @FORMATTING_TAGS = ($TAGS[$P], $TAGS[$C], $TAGS[$B], $TAGS[$I], $TAGS[$BR],
91 $TAGS[$BR], $TAGS[$S]);
92 my @FORMAT_CONTAINERS = ($TAGS[$SUMMARY], $TAGS[$PARAM], $TAGS[$RETVAL],
93 $TAGS[$DESCRIPTION], $TAGS[$NOTE], $TAGS[$C],
94 $TAGS[$B], $TAGS[$I], $TAGS[$FOOT], $TAGS[$HEAD]);
95 my @CODE_TAGS = ($TAGS[$SYNTAX], $TAGS[$EXAMPLE]);
97 my $URLVAR_ENTRY = "{e}";
99 my $footstr = "<center>This page was generated by " .
100 "<a href='http://www.mozilla.org/projects/apidoc' target='other_window'>" .
101 "<b>APIDOC</b></a>" .
102 "</center>\n</body></html>";
104 my $WARNING = "<!--\n" .
105 " -- HEADS UP! This page was *GENERATED* by APIDOC,\n".
106 " -- DO NOT EDIT THIS FILE BY HAND!\n" .
107 " -- See http://www.mozilla.org/projects/apidoc for information on APIDOC\n" .
108 " -- The original source file was " . $file . "\n" .
111 my $JS_COMPLETE = ("\n<script>\n" .
112 "function navToEntry(entry) {\n" .
113 " window.location.hash=entry;\n" .
115 "function navToGroup(group) {\n" .
116 " var f = parent.frames['toc-container'];\n" .
118 " window.open ('complete-toc.html#' + group, " .
119 "'toc_container');\n" .
121 " if (f.location.href.search('abc') != -1)\n" .
122 " f.location.href = 'complete-toc.html#' + group;\n" .
124 " f.location.hash = group;\n" .
129 my $JS_SPARSE = ("\n<script>\n" .
130 "function navToEntry(entry) {\n" .
131 " window.location.href='api-' + entry + '.html';\n" .
133 "function navToGroup(group) {\n" .
134 " var f = parent.frames['toc-container'];\n" .
136 " window.open ('sparse-toc.html#' + group, " .
137 "'toc_container');\n" .
139 " if (f.location.href.search('abc') != -1)\n" .
140 " f.location.href = 'sparse-toc.html#' + group;\n" .
142 " f.location.hash = group;\n" .
147 open (COMPLETE, ">" . $outdir . "/complete.html") ||
148 die ("Couldn't open $outdir/complete.html.\n");
149 open (COMPLETE_TOC, ">" . $outdir . "/complete-toc.html") ||
150 die ("Couldn't open $outdir/complete-toc.html.\n");
152 open (COMPLETE_TOC_ABC, ">" . $outdir . "/complete-toc-abc.html") ||
153 die ("Couldn't open $outdir/complete-toc-abc.html.\n");
154 open (COMPLETE_TOC_GRP, ">" . $outdir . "/complete-toc-grp.html") ||
155 die ("Couldn't open $outdir/complete-toc-grp.html.\n");
157 open (SPARSE_TOC, ">" . $outdir . "/sparse-toc.html") ||
158 die ("Couldn't open $outdir/sparse-toc.html.\n");
160 open (SPARSE_TOC_ABC, ">" . $outdir . "/sparse-toc-abc.html") ||
161 die ("Couldn't open $outdir/sparse-toc-abc.html.\n");
162 open (SPARSE_TOC_GRP, ">" . $outdir . "/sparse-toc-grp.html") ||
163 die ("Couldn't open $outdir/sparse-toc-grp.html.\n");
165 open (SIDEBAR_TOC, ">" . $outdir . "/sidebar-toc.html") ||
166 die ("Couldn't open $outdir/sidebar-toc.html.\n");
172 my $parser = new XML::Parser(ErrorContext => 2);
174 # pass 1, scan all <ENTRY> tags.
175 $parser->setHandlers(Start => \&p1_Start, End => \&p1_End);
176 $parser->parsefile($file);
178 # sanity check the tag stack from p1
179 if ($#tag_stack != -1) {
180 die ("OOPS: p1 left the tag stack in a bad state.\n");
183 # pass 2, populate the $entries hash.
184 $parser = new XML::Parser(Style => "Stream", ErrorContext => 2);
185 $parser->parsefile ($file);
187 # finally, write it all out.
193 for $k (sort (keys(%entries))) {
195 $html = &get_entry_html();
196 &add_entry_complete($html);
197 &add_entry_sparse($html);
198 &add_toc_complete(*COMPLETE_TOC);
199 &add_toc_complete(*COMPLETE_TOC_ABC);
200 &add_toc_sparse(*SPARSE_TOC);
201 &add_toc_sparse(*SPARSE_TOC_ABC);
202 #&debug_write_entry();
205 &end_abc(*SPARSE_TOC);
206 &end_abc(*SPARSE_TOC_ABC);
207 &end_abc(*COMPLETE_TOC);
208 &end_abc(*COMPLETE_TOC_ABC);
217 # pass 1, find all <ENTRY/>, <EXTERNALREF/>, and <GROUP/> tags
218 # (as well as groups implied by <TYPE/> and <DEPRECATED/> tags), so we
219 # can do things like auto link <C/> tags that refer to entrys,
220 # and validate <S/> tags in pass 2.
222 my $lasttagname = $tagname;
226 push (@tag_stack, $lasttagname);
230 $pending_attrs{$n} = shift;
233 my $value = $pending_attrs{"value"};
234 my $id = $pending_attrs{"id"};
236 if ($tagname eq $TAGS[$ENTRY]) {
238 $c = $entries{$id} = {$TAGS[$ENTRY] => $id};
240 &croak_attr ($expat, $tagname, "id");
242 } elsif ($tagname eq $TAGS[$TYPE]) {
244 &croak_attr ($expat, $tagname, "value");
246 $c->{$tagname} = $value;
247 push (@{$groups{$value}}, $c->{$TAGS[$ENTRY]});
248 push (@{$c->{$TAGS[$GROUP]}}, $value);
249 } elsif ($tagname eq $TAGS[$DEPRECATED]) {
251 push (@{$groups{"Deprecated"}}, $c->{$TAGS[$ENTRY]});
252 push (@{$c->{$TAGS[$GROUP]}}, "Deprecated");
253 } elsif ($tagname eq $TAGS[$GROUP]) {
254 if (($lasttagname ne $TAGS[$API]) &&
255 ($lasttagname ne $TAGS[$ENTRY])) {
256 $expat->xpcroak ("Tag $tagname can only be contained by ".
257 "an '" . $TAGS[$API] . "' or '" .
258 $TAGS[$ENTRY] . "' tag");
260 my $name = $pending_attrs{"name"};
262 &croak_attr ($expat, $tagname, "name");
264 if ($lasttagname ne $TAGS[$ENTRY]) {
266 &croak_attr ($expat, $tagname, "value");
269 $value = $c->{$TAGS[$ENTRY]};
271 if (!grep (/^$value$/, @{$groups{$name}})) {
272 # if it isn't already there, add it
273 push (@{$groups{$name}}, $value);
274 push (@{$entries{$value}->{$TAGS[$GROUP]}}, $name);
276 } elsif ($tagname eq $TAGS[$EXTERNALREF]) {
277 my $name = $pending_attrs{"name"};
278 my $value = $pending_attrs{"value"};
280 &croak_attr ($expat, $tagname, "name");
283 &croak_attr ($expat, $tagname, "value");
285 if ($lasttagname eq $TAGS[$API]) {
286 # if the externalref is a child of the API tag
287 if ($value =~ /$URLVAR_ENTRY/) {
288 # and it has a placeholder for the entry id,
289 # then attach it to every entry
290 $externals{$name} = $value;
292 # otherwise, just put it in the toc.
293 $toc_externals{$name} = $value;
295 } elsif ($lasttagname eq $TAGS[$ENTRY]) {
296 # if the externalref is a child of the ENTRY tag
297 # only attach it to this entry
298 $c->{$TAGS[$EXTERNALREF]}{$name} = $value;
300 $expat->xpcroak ("Tag $tagname can only be contained by ".
301 "an '" . $TAGS[$API] . "' or '" .
302 $TAGS[$ENTRY] . "' tag");
308 $tagname = pop (@tag_stack);
312 # phase 2 open tag handler
315 my $lasttagname = $tagname;
318 push (@tag_stack, $lasttagname);
319 push (@text_stack, $pending_text);
320 my $s = $#attr_stack + 1;
321 $attr_stack[$s]{"foo"} = "bar";
322 for (keys (%pending_attrs)) {
323 $attr_stack[$s]{$_} = $pending_attrs{$_};
329 if (!grep(/^$tagname$/, @TAGS)) {
330 $expat->xpcroak ("Unknown tag '$tagname'");
333 # print ("opening: ");
336 my $value = $pending_attrs{"value"};
337 my $id = $pending_attrs{"id"};
339 if ($tagname eq $TAGS[$API]) {
341 $expat->xpcroak ("Only one '$tagname' tag allowed");
344 &croak_attr ($expat, $tagname, "id");
349 if ($tagname eq $TAGS[$ENTRY]) {
351 &croak_attr ($expat, $tagname, "id");
354 } elsif ($tagname eq $TAGS[$SEE_ALSO]) {
356 &croak_attr ($expat, $tagname, "value");
357 } elsif (!$entries{$value}) {
358 $expat->xpcroak ("Undefined SEEALSO reference, '$value'");
360 if (!grep (/^$value$/, @{$c->{$TAGS[$SEE_ALSO]}})) {
361 push (@{$c->{$TAGS[$SEE_ALSO]}}, $value);
363 } elsif (grep(/^$tagname$/, @FORMATTING_TAGS)) {
364 if (!grep(/^$lasttagname$/, @FORMAT_CONTAINERS)) {
365 $expat->xpcroak ("Tag $lasttagname cannot contain formatting " .
368 } elsif (($tagname eq $TAGS[$PARAM]) || ($tagname eq $TAGS[$RETVAL])) {
369 if ($lasttagname ne $TAGS[$SYNTAX]) {
370 $expat->xpcroak ("Tag $tagname can only be contained by a '" .
371 $TAGS[$SYNTAX] . "' tag");
373 if (!$pending_attrs{"name"}) {
374 if ($tagname eq $TAGS[$RETVAL]) {
375 $pending_attrs{"name"} = "Return Value";
377 &croak_attr ($expat, $tagname, "name");
380 if (!$pending_attrs{"type"}) {
381 $pending_attrs{"type"} = " ";
382 # &croak_attr ($expat, $tagname, "type");
384 } elsif ((($tagname eq $TAGS[$HEAD]) || ($tagname eq $TAGS[$HEAD])) &&
385 ($lasttagname ne $TAGS[$API])) {
386 $expat->xpcroak ("Tag $tagname can only be contained by ".
387 "an '" . $TAGS[$API] . "' tag");
390 $expat->xpcroak ("Tag '$tagname' must be contained in an '" .
391 $TAGS[$API] . " tag");
396 # phase 2 close tag handler
399 $_ =~ /<\/([^\s>]*)/;
402 # print ("closing: ");
405 if (grep(/^$tagname$/, @CDATA_TAGS)) {
407 if ($pending_text eq "") {
408 print STDERR "WARNING: Empty container '$tagname' at line " .
409 $expat->current_line . " ignored.\n";
410 #$expat->xpcroak ("Empty container '$tagname'.");
414 if (grep(/^$tagname$/, @FORMATTING_TAGS)) {
416 if ($tagname eq $TAGS[$C]) {
418 if (($pending_text ne $c->{$TAGS[$ENTRY]}) &&
419 ($entries{$pending_text})) {
420 # if the contents are a valid entry
421 # add it to the SEEALSO, in case it's not already there
422 if (!grep (/^$pending_text$/, @{$c->{$TAGS[$SEE_ALSO]}})) {
423 push (@{$c->{$TAGS[$SEE_ALSO]}}, $pending_text);
426 $pending_text = &get_link($pending_text);
428 $pending_text = "<code>$pending_text</code>";
429 } elsif ($tagname eq $TAGS[$S]) {
432 if (($value = $entries{$pending_text}) ||
433 ($value = $toc_externals{$pending_text}) ||
434 ($value = $c->{$TAGS[$EXTERNALREF]}{$pending_text})) {
435 # it's a valid external reference
436 # put it in this entry's external references incase it isn't
438 $c->{$TAGS[$EXTERNALREF]}{$pending_text} = $value;
440 s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
442 "<a href='$_' target='other_window'>" .
444 } elsif ($value = $groups{$pending_text}) {
446 # put it in this entry's group references incase it isn't
448 if ((!$c->{$TAGS[$GROUP]}) ||
449 (!grep (/^$pending_text$/, @{$c->{$TAGS[$GROUP]}}))) {
450 push (@{$c->{$TAGS[$GROUP]}}, $pending_text);
452 $pending_text ="<a href='javascript:" .
453 "navToGroup(\"GROUP_$pending_text\")'>$pending_text</a>";
455 # it's just not valid
456 $expat->xpcroak ("Unknown reference in '" . $TAGS[$S] .
459 } elsif ($tagname eq $TAGS[$B]) {
461 $pending_text = "<b>$pending_text</b>";
462 } elsif ($tagname eq $TAGS[$I]) {
464 $pending_text = "<i>$pending_text</i>";
467 ("OOPS: Unhandled container formatting tag '$tagname'");
470 if ($tagname eq $TAGS[$P]) {
472 $pending_text = "<P>";
473 } elsif ($tagname eq $TAGS[$BR]) {
475 $pending_text = "<BR>";
478 ("OOPS: Unhandled non-container formatting tag '$tagname'");
481 # combine with previous pendingtext
482 $pending_text = pop(@text_stack) . $pending_text;
483 } elsif ($iscontainer) {
484 # not a formatting tag, store the accumulated pendingtext in the
485 # right place, after some whitespace trimming
486 my @lines = split ("\n", $pending_text);
487 my $iscode = grep (/^$tagname$/, @CODE_TAGS);
490 my $result_text = "";
492 for $i (0 ... $#lines) {
494 if ((($i != 0) && ($i != $#lines)) || ($line =~ /[\S\n]/)) {
496 $line = &add_leading_nbsp($line);
499 s/\.\s\s(.)/\.\ \ $1/g;
502 $line =~ /^[\s\n]*(.*)[\s\n]*/;
503 $result_text .= $1 . "\n";
511 if (($tagname eq $TAGS[$PARAM]) || ($tagname eq $TAGS[$RETVAL])) {
513 my $name = $pending_attrs{"name"};
514 my $type = $pending_attrs{"type"};
515 my $html = ("<td class='param-name'><code>$name</code></td>" .
516 "<td class='param-type'><code>$type</code></td>" .
517 "<td class='param-desc'>$result_text</td>\n");
518 push (@{$c->{$TAGS[$PARAM]}}, $html);
519 } elsif ($tagname eq $TAGS[$EXAMPLE]) {
520 $c->{$tagname . "_DESC"} = $pending_attrs{"desc"};
521 $c->{$tagname} = $result_text;
522 } elsif ($tagname eq $TAGS[$HEAD]) {
523 $user_head .= $result_text;
524 } elsif ($tagname eq $TAGS[$FOOT]) {
525 $user_foot .= $result_text;
527 $c->{$tagname} .= $result_text;
530 $pending_text = pop (@text_stack);
532 $pending_text = pop (@text_stack);
535 %pending_attrs = %{pop (@attr_stack)};
536 $tagname = pop (@tag_stack);
538 # print ("popped: ");
549 if (!grep(/^$tagname$/, @CDATA_TAGS)) {
550 $expat->xpcroak ("Tag '$tagname' cannot contain text");
561 my @types = split /\s*,\s*/, shift;
562 foreach my $type (@types) {
563 #_PH_ - fix to better parse C pointer types - a bit unsafe
564 $type =~ m|(&\s*)*([^ *]+)(\s*\*)*|;
565 my ($pre, $realtype, $post) = ($1, $2, $3);
566 if (exists $entries{$realtype}) {
567 if (!grep (/^$realtype$/, @{$c->{$TAGS[$SEE_ALSO]}})) {
568 push (@{$c->{$TAGS[$SEE_ALSO]}}, $realtype);
570 $realtype = &get_link($realtype) ;
571 $type = "$pre$realtype$post";
574 return join ", ", @types;
577 sub get_param_links {
579 if ($html =~ m|class='(param-type'><code>)(.*?)(</code>)|g) {
580 my $new_param = &get_type_links($2);
581 $html =~ s|class='(param-type'><code>)(.*?)(</code>)|$1$new_param$3|;
587 # get html for the current entry ($c)
589 $c->{$TAGS[$ENTRY]} =~ /\.?(.*)/;
591 $html = "<center><table class='api-entry' width='100%' cellspacing='0'" .
592 "border='1' cellpadding='10'>\n";
593 $html .= "<tr><td class='entry-heading'>\n";
595 $html .= "<table class='entry-heading-table' width='100%' cellpadding='5'" .
596 "cellspacing='0'><tr>\n";
597 $html .= "<td class='entry-title' valign='center'><font size='+5'>" .
598 $id . "</font></td>\n";
599 $html .= "<td class='entry-type' align='center' width='25%'>" .
600 $c->{$TAGS[$TYPE]} . "</td>\n";
601 if ($c->{$TAGS[$DEPRECATED]}) {
602 $html .= "<td class='entry-deprecated' align='center' width='25%'>" .
605 $html .= "</tr></table>\n";
607 $html .= "</td></tr>\n";
609 if ($c->{$TAGS[$SUMMARY]}) {
610 $html .= "<tr><td class='entry-summary'>\n";
611 $html .= "<h4 class='entry-subhead'>Summary</h4>\n";
612 $html .= $c->{$TAGS[$SUMMARY]};
613 $html .= "</td></tr>\n";
615 if ($c->{$TAGS[$SYNTAX]}) {
616 $html .= "<tr><td class='entry-syntax'>\n";
617 $html .= "<h4 class='entry-subhead'>Syntax</h4><pre>\n";
618 $html .= $c->{$TAGS[$SYNTAX]};
620 if ($c->{$TAGS[$PARAM]}) {
621 $html .= "<center><table class='param-list' border='1' " .
622 "cellpadding='3' cellspacing='1'>";
623 $html .= "<tr class='param-list-head'>";
624 $html .= "<th>Name</th><th>Type</th><th>Description</th></tr>\n";
625 my $param = shift (@{$c->{$TAGS[$PARAM]}});
630 $html .= "<tr class='param-row-even'>";
632 $html .= "<tr class='param-row-odd'>";
636 $param = &get_param_links($param);
638 $html .= $param . "</tr>\n";
639 $param = shift (@{$c->{$TAGS[$PARAM]}});
641 $html .= "</table></center>\n"
643 $html .= "</td></tr>\n";
645 if ($c->{$TAGS[$DESCRIPTION]}) {
646 $html .= "<tr><td class='entry-description'>\n";
647 $html .= "<h4 class='entry-subhead'>Description</h4>\n";
648 $html .= $c->{$TAGS[$DESCRIPTION]};
649 $html .= "</td></tr>\n";
651 if ($c->{$TAGS[$EXAMPLE]}) {
652 $html .= "<tr><td class='entry-example'>\n";
653 $html .= "<h4 class='entry-subhead'>Example</h4>\n";
654 if ($c->{$TAGS[$EXAMPLE] . "_DESC"}) {
655 $html .= $c->{$TAGS[$EXAMPLE] . "_DESC"} . "<br>";
657 $html .= "<pre>" . $c->{$TAGS[$EXAMPLE]};
658 $html .= "</pre></td></tr>\n";
660 if ($c->{$TAGS[$NOTE]}) {
661 $html .= "<tr><td class='entry-notes'>\n";
662 $html .= "<h4 class='entry-subhead'>Notes</h4>\n";
663 $html .= $c->{$TAGS[$NOTE]};
664 $html .= "</td></tr>\n";
667 my $sa = get_seealso();
669 $html .= "<tr><td class='entry-seealso'>\n";
670 $html .= "<h4 class='entry-subhead'>See Also</h4>\n";
672 $html .= "</td></tr>\n";
675 $html .= "</table></center><br>\n";
681 # get the see also section for the current entry ($c);
687 for (@{$c->{$TAGS[$GROUP]}}) {
688 push (@links, "<a href='javascript:navToGroup(\"GROUP_$_\")'>$_</a>");
692 $html .= "<tr class='seealso-groups'><td>Groups</td>\n";
693 $html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
698 # global externals (had a parent tag of <API/>)
699 for $k (keys(%externals)) {
701 s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
702 push (@links, "<a href='$_' target='other_window'>$k</a>");
705 # local externals (parented by <ENTRY/>
706 for $k (keys(%{$c->{$TAGS[$EXTERNALREF]}})) {
707 $_ = $c->{$TAGS[$EXTERNALREF]}{$k};
708 s/$URLVAR_ENTRY/$c->{$TAGS[$ENTRY]}/g;
709 push (@links, "<a href='$_' target='other_window'>$k</a>");
713 $html .= "<tr class='seealso-externals'><td>Documents</td>\n";
714 $html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
719 for $k (@{$c->{$TAGS[$SEE_ALSO]}}) {
720 push (@links, &get_link($k));
724 $html .= "<tr class='seealso-internals'><td>Entries</td>\n";
725 $html .= "<td>[ " . join (" | ", sort(@links)) . " ]</td></tr>\n";
729 $html = "<table class='seealso-table'>\n" . $html . "\n</table>\n";
736 sub add_entry_complete {
737 # add html for the current entry to the "complete" page
740 print COMPLETE "<a name='" . $c->{$TAGS[$ENTRY]} . "'></a>\n";
741 print COMPLETE $html;
745 sub add_entry_sparse {
746 # add html for the current entry to a new "sparse" page
748 my $outfile = $outdir . "/api-" . $c->{$TAGS[$ENTRY]} . ".html";
750 open (SPARSE, ">$outfile") ||
751 die ("Couldn't open $outfile.\n");
753 my $headstr = "<html><head><link rel=StyleSheet href='api-content.css' " .
754 "TYPE='text/css' MEDIA='screen'>" .
755 "<title>" . $c->{$TAGS[$ENTRY]} . "</title>" . $JS_SPARSE .
756 "</head><body bgcolor='white'>\n$WARNING" .
757 "<h1 class='title'>$apiid Reference</h1>\n" . $user_head;
759 print SPARSE $headstr;
762 print SPARSE $user_foot;
763 print SPARSE $footstr;
770 print G "</table></center></td></tr>\n";
773 sub write_toc_groups {
774 # Write the groups section of the toc to both the sparse and complete
776 my @groups = sort(keys (%groups));
779 my $head = "<tr class='toc-title'><th><br><h3>Grouped Listing</h3></th>" .
782 print COMPLETE_TOC $head;
783 print COMPLETE_TOC_GRP $head;
784 print SPARSE_TOC $head;
785 print SPARSE_TOC_GRP $head;
786 #print SIDEBAR_TOC $head;
789 $head = "<tr><td class='";
791 $head .= "toc-group-even";
793 $head .= "toc-group-odd";
795 $head .= "'><center><table border='0' cellspacing='0' cellpading='0' " .
797 $head .= "<tr><th><a name='GROUP_$g'>$g</a></th><td> </td></tr>\n";
798 print COMPLETE_TOC $head;
799 print COMPLETE_TOC_GRP $head;
800 print SPARSE_TOC $head;
801 print SPARSE_TOC_GRP $head;
802 print SIDEBAR_TOC $head;
804 for $e (sort(@{$groups{$g}})) {
806 &add_toc_complete(*COMPLETE_TOC);
807 &add_toc_complete(*COMPLETE_TOC_GRP);
808 &add_toc_sparse(*SPARSE_TOC);
809 &add_toc_sparse(*SPARSE_TOC_GRP);
810 &add_toc_sparse(*SIDEBAR_TOC, 1);
812 $head = "</table></center><br></td></tr>\n";
813 print COMPLETE_TOC $head;
814 print COMPLETE_TOC_GRP $head;
815 print SPARSE_TOC $head;
816 print SPARSE_TOC_GRP $head;
817 print SIDEBAR_TOC $head;
823 sub add_toc_complete {
825 # add the current entry ($c) to the complete toc
826 #print COMPLETE_TOC &add_toc(0);
833 # add the current entry ($c) to the sparse toc
834 #print SPARSE_TOC &add_toc(1);
835 print G &add_toc(1,$sidebar);
839 # add the current entry ($c) to the either the complete or sparse toc,
840 # based on the is_sparse parameter. Should only be called from
841 # add_toc_sparse or add_toc_complete.
842 my ($is_sparse, $sidebar) = @_;
844 my $classsuffix = $c->{$TAGS[$DEPRECATED]} ? "-deprecated" : "";
846 $html = "<tr><td class='toc-row$classsuffix'>";
848 $html .= &get_toc_link($c->{$TAGS[$ENTRY]}, $is_sparse,
849 "toc-entry$classsuffix", $sidebar)
853 $html .= "<td class='toc-ind-deprecated' width='10%' " .
854 "align='center' valign='center'>D</td>";
856 $html .= "<td> </td>";
865 # get a link for use in a content page. Works in both sparse and complete
866 # pages (because of the navToEntry call.)
868 my $entryE = _encode($entry); #_PC_
869 return ("<a href='javascript:navToEntry(\"$entryE\");'>$entry</a>");
873 # get a link for use in a toc page.
874 my ($entry, $is_sparse, $class, $sidebar) = @_;
876 my $entryE = _encode($entry); #_PC_
877 my $contentTarget = $sidebar ? '_content' : 'content-container';
880 return "<a class='$class' href='api-$entryE.html' " .
881 "target='$contentTarget'>$entry</a>\n";
883 return "<a href='complete.html#$entryE' class='$class' " .
884 "target='$contentTarget'>$entry</a>";
891 ('full-sparse' => [['alphabetical listing' => 'sparse-toc-abc.html'],
892 ['grouped listing' => 'sparse-toc-grp.html']],
893 'abc-sparse' => [['full listing' => 'sparse-toc.html'],
894 ['grouped listing' => 'sparse-toc-grp.html']],
895 'grp-sparse' => [['full listing' => 'sparse-toc.html'],
896 ['alphabetical listing' => 'sparse-toc-abc.html']],
897 'full-compl' => [['alphabetical listing' => 'complete-toc-abc.html'],
898 ['grouped listing' => 'complete-toc-grp.html']],
899 'abc-compl' => [['full listing' => 'complete-toc.html'],
900 ['grouped listing' => 'complete-toc-grp.html']],
901 'grp-compl' => [['full listing' => 'complete-toc.html'],
902 ['alphabetical listing' => 'complete-toc-abc.html']],
904 my $menu = $menu{$type};
907 foreach my $item (@$menu) {
908 $ret .= "<a href='" . $$item[1] . "'>" . $$item[0] . "</a><br>\n";
915 # initialize the complete content and toc files.
916 my $headstr = "<html><head><link rel=StyleSheet href='api-content.css' " .
917 "TYPE='text/css' MEDIA='screen'><title>$apiid</title></head>" .
918 $JS_COMPLETE . "<body bgcolor='white'>\n$WARNING" .
919 "<h1 class='title'>$apiid Reference</h1>\n" . $user_head;
921 print COMPLETE $headstr;
924 ("<html><head><link rel=StyleSheet href='api-toc.css' " .
925 "TYPE='text/css' MEDIA='screen'>" .
926 "<title>$apiid table of contents</title>" .
927 "</head>\n<body bgcolor='white'>\n$WARNING" .
928 "<h1 class='title'>$apiid Reference</h1><h4>Table of Contents</h4>\n");
930 ("<center><table class='toc-table' border='1' cellpadding='0' " .
931 "cellspacing='0' width='100%'>\n");
933 ("<tr class='toc-title'><th><br><h3>Alphabetical Listing</h3></th>" .
934 "</tr>\n<tr><td>\n" .
935 "<center><table class='toc-abc' border='0' cellspacing='0' " .
936 "cellpadding='0' width='100%'>\n");
938 my $sidebar1 = $tocstr1;
939 $sidebar1 =~ s/api\-toc\.css/sidebar.css/;
941 print COMPLETE_TOC $tocstr1;
942 print COMPLETE_TOC &get_menu("full-compl");
943 print COMPLETE_TOC $tocstr2;
944 print COMPLETE_TOC $abcstr;
946 print COMPLETE_TOC_ABC $tocstr1;
947 print COMPLETE_TOC_ABC &get_menu("abc-compl");
948 print COMPLETE_TOC_ABC $tocstr2;
949 print COMPLETE_TOC_ABC $abcstr;
951 print COMPLETE_TOC_GRP $tocstr1;
952 print COMPLETE_TOC_GRP &get_menu("grp-compl");
953 print COMPLETE_TOC_GRP $tocstr2;
955 print SPARSE_TOC $tocstr1;
956 print SPARSE_TOC &get_menu("full-sparse");
957 print SPARSE_TOC $tocstr2;
958 print SPARSE_TOC $abcstr;
960 print SPARSE_TOC_ABC $tocstr1;
961 print SPARSE_TOC_ABC &get_menu("abc-sparse");
962 print SPARSE_TOC_ABC $tocstr2;
963 print SPARSE_TOC_ABC $abcstr;
965 print SPARSE_TOC_GRP $tocstr1;
966 print SPARSE_TOC_GRP &get_menu("grp-sparse");
967 print SPARSE_TOC_GRP $tocstr2;
969 print SIDEBAR_TOC $sidebar1;
970 #print SIDEBAR_TOC &get_menu("grp-sparse");
971 print SIDEBAR_TOC $tocstr2;
979 print G "</table></center>\n";
980 print G &get_menu($menu) . "<p>\n" unless $sidebar;
981 print G $user_foot . "\n";
988 # finish up the complete content and toc files.
990 print COMPLETE $user_foot;
991 print COMPLETE $footstr;
994 &close_toc(*COMPLETE_TOC, "full-compl");
995 &close_toc(*COMPLETE_TOC_ABC, "abc-compl");
996 &close_toc(*COMPLETE_TOC_GRP, "grp-compl");
997 &close_toc(*SPARSE_TOC, "full-sparse");
998 &close_toc(*SPARSE_TOC_ABC, "abc-sparse");
999 &close_toc(*SPARSE_TOC_GRP, "grp-sparse");
1000 &close_toc(*SIDEBAR_TOC, "grp-sparse", 1);
1003 sub add_leading_nbsp {
1004 # replaces leading spaces with entities. Used for tags which
1010 if (!($str =~ /^(\s+)/)) {
1014 my $len = length($1);
1015 for $i (0 .. $len) {
1019 substr ($str, 0, $len) = $pfx;
1026 print ("tag: $tagname, attrs: " .
1027 join (", ", keys (%pending_attrs)) .
1028 ", stacks: " . $#text_stack . ", " . $#tag_stack . ", " .
1029 $#attr_stack . "\n");
1031 for (0 ... $#attr_stack) {
1032 print ("attribs at $_: " . join (", ", keys (%{$attr_stack[$_]})) .
1038 sub debug_write_entry {
1041 for $i (keys(%{$c})) {
1043 if (($i eq $TAGS[$SEE_ALSO]) || ($i eq ($TAGS[$PARAM]))) {
1044 $str = join (", ", @{$c->{$i}});
1049 print ("$i : $str\n");
1055 my ($expat, $tagname, $attr) = @_;
1057 $expat->xpcroak ("Tag $tagname needs an $attr attribute");
1060 #_PC_ - subroutine to encode URLs
1064 $entry =~ s/(\W)/sprintf("%%%x", ord($1))/eg;