#!/usr/local/bin/perl # # Build documentation from a definition file, a template, and possibly # a bunch of individual description files. # # -d identifies the definition file (see api.list for documentation). # # -l specifies a layout type: # # 0 means full, with each entry in a separate document starting with an # H3 heading and the main document containing a linked subtable of # contents for each type of entry (routines, constants, et cetera); # 1 is the same as 0, except everything is in a single monolithic file; # 2 means simpler, with no tables of subcontents and each entry jumping # right to the definition without the preamble. # # Layout 2 results in reduced file size (though it's still huge), but # is slightly susceptible to potentially confusing display values if # an entry has no definition in the data file. Layout 1 guarantees # a little more text in such a case, but at a significant cost in file size. # Layout 0 is the best for reference work, but scanning through # definitions is more difficult since they're in separate files. # # -n indicates that there should be NO hyperlinks in the output. (Useful # if destined for inclusion in a on-electronic format.) # # -o specifies the name of the master output file, or "-" for stdout. # Note that "-" is not permitted in combination with "-l 0" because this # name is used in anchors with that layout. # # -t specifies the template file for the main dictionary page. # # -v enables verbose mode. # # -D enable debug messages (if any are implemented). # # Edit history: # # 2001-05-04 Ken Coar # Added -n option (no hyperlinks). # 2000-09-16 Ken Coar # Reworked to use the APIdict.pm module, to which a lot of the # file reading/writing functionality has been moved. # 2000-07-23 Ken Coar # Fix up the handling of '\\' in the formatter. Also added # messages when description files are missing or not specified. # 2000-07-12 Ken Coar # Add some more verbosity, and fix item emission for layout styles > 0. # 1999-12-08 Ken Coar # Downcase the HTML tags and do some line merging. # 1999-03-31 Ken Coar # Get rid of the ARGV processing and use command-line options # instead. Add a third level of layout; 0 now means 'full,' # with each definition in its own file. # 1998-06-23 Chuck Murcko # Bug fix for ARGV[1] processing of arguments with value 0. # 1998-05-26 Ken Coar # Change missing-args message to a 'usage' display, change references # to s, clean up some style issues, and document what Ben's # changes meant and how to use them. # 1998-05-25 Ben Laurie # Add capability for alternate, simpler, layout of output. ARGV[1] is # either 0 for full cross-linked output or 1 for simple. # 1998-05-03 Ken Coar # Cleaned up a little bit, from horrible to bad, before checking in to # CVS. # 1998-04-?? Ken Coar # Prototyped.. # use APIdict; # # Make sure that anything we utter to stderr shows up instanter.. # $tfh = select(STDERR); $| = 1; select($tfh); $command_line = join(" ", $0, @ARGV); use Getopt::Std; @errors = (); $ofh = \*STDOUT; getopts("Dd:l:no:t:v", \%arg); $Verbose = defined($arg{'v'}); $Debug = defined($arg{'D'}); if (! defined($arg{'d'})) { push(@errors, "definition file (-d option) is required"); } else { $Dfile = $arg{'d'}; } if ((! defined($arg{'l'})) || ($arg{'l'} < 0) || ($arg{'l'} > 2)) { push(@errors, "layout type (-l option) must be a value 0-2"); } else { $Layout = $arg{'l'}; &verbose("Using layout style $Layout"); } $nolinks = $arg{'n'}; &verbose("Hyperlinking is " . ($nolinks ? "OFF" : "ON")); if ((! defined($arg{'o'})) && ($Layout < 1)) { push(@errors, "output filename (-o option) is required with -l 0"); } elsif (($arg{'o'} eq '-') && ($Layout < 1)) { push(@errors, "output filename (-o options) may not be '-' with -l 0"); } elsif (defined($arg{'o'}) && ($arg{'o'} ne '-')) { open $ofh, ">$arg{'o'}" || die "can't open output file"; } if (! defined($arg{'t'})) { push(@errors, "output template file (-t option) is required"); } else { $InFile = $arg{'t'}; } if ($#errors > -1) { foreach (@errors) { print STDERR "$0: $_\n"; } &usage(); exit(1); } $dict = new APIdict($Dfile); $dict->hyperlinks(! $nolinks); $OutFile = "$InFile.bak"; %URL = (); %HREF = (); @Prologue = (); @Epilogue = (); @code_bracket = ("", ""); @no_bracket = ("", ""); # # # Just in case the input template was the output from a previous run, # save it in case *this* run doesn't work as expected. # # Now copy the input file to a backup, extracting the prologue and # epilogue sections as we go. # &verbose("Copying input template ($InFile) to backup ($OutFile)"); open INFILE, "<$InFile" || die ("Can't open input file $InFile"); open OUTFILE, ">$OutFile" || die ("Can't open output file $OutFile"); $state = 1; while ($line = ) { print OUTFILE $line; if ($state == 1) { push (@Prologue, $line); } elsif ($state == 2) { push (@Epilogue, $line); } if ($line =~ m::) { $state = 0; } elsif ($line =~ m::) { push (@Epilogue, $line); $state = 2; } } close INFILE; close OUTFILE; foreach $item ($dict->entity_list()) { $URL{$item} = &makeURL($item, %URL); $HREF{$item} = &makeHREF($item, %URL); } # # Done reading in the input.. time to make the doughnuts. # &verbose("Dumping prologue."); foreach $line (@Prologue) { $line =~ s"(\$Generated by:).*\$"$1 $command_line \$"; print $ofh $line; } $x_routines = $dict->insert_link('Routine Descriptions', "", "", '#Routines'); $x_structures = $dict->insert_link('Data Structure Descriptions', "", "", '#Structures'); $x_cells = $dict->insert_link('Data Cell Descriptions', "", "", '#Cells'); $x_consts = $dict->insert_link('Constant Descriptions', "", "", '#Constants'); print $ofh <Table of Contents
  • $x_routines
  • $x_structures
  • $x_cells
  • $x_consts

EOHT print $ofh <Routine Descriptions
EOHT &verbose("Analysing routines: \\c"); @keys = $dict->routine_list(); push(@keys, $dict->macro_list()); &list_items(@keys); &verbose(($#keys + 1) . " found."); &verbose("Dumping routines."); &dump_list('R', @keys); print $ofh <Data Structure Definitions
EOHT &verbose("Analysing structures: \\c"); @keys = $dict->structure_list(); &list_items(@keys); &verbose(($#keys + 1) . " found."); &verbose("Dumping structures."); &dump_list('S', @keys); print $ofh <Global Data Cells
EOHT &verbose("Analysing data cells: \\c"); @keys = $dict->cell_list(); &list_items(@keys); &verbose(($#keys + 1) . " found."); &verbose("Dumping data cells."); &dump_list('D', @keys); $etext = <Constant Definitions

Many of the compile-time choices are determined by the settings of various constants created with #define statements. Things like the maximum size of fixed-length buffers, the server version string, and operating system-specific code fragment compilation are controlled by constants.

Some of the Apache Web server's constants (such as SERVER_VERSION) can be overridden with compile-time definitions on the compiler command line. Others, like MAX_STRING_LEN, are provided as conveniences, and shouldn't be modified except under special circumstances. Still others, such as OR_LIMIT, have specific values that must not be altered.


EOHT $etext = $dict->add_links($etext, "", %HREF); print $ofh $etext; &verbose("Analysing constants: \\c"); @keys = $dict->constant_list(); &list_items(@keys); &verbose(($#keys + 1) . " found."); &verbose("Dumping constants."); &dump_list('C', @keys); &verbose("Dumping epilogue."); print $ofh @Epilogue; exit(0); # # Dump a hash in alphabetical order. # sub dump_list { local($prefix, @keys) = @_; my($i) = 0; @keys = sort {uc($a) cmp uc($b)} (@keys); foreach $key (@keys) { local (*dfh); local ($previous, $next) = ("", ""); $previous = $keys[$i - 1] if ($i > 0); $next = $keys[$i + 1] if ($i < $#keys); if ($Layout == 0) { open(dfh, ">$URL{$key}"); &dump_item(\*dfh, $prefix, $key, $list{$key}, $previous, $next); close(dfh); } else { &dump_item($ofh, $prefix, $key, $list{$key}, $previous, $next); } $i++; } } sub list_items { local(@items) = @_; if ($Layout == 0) { print $ofh < EOHT foreach (sort {uc($a) cmp uc($b)} (@items)) { my ($uri) = $HREF{"$_"}; print $ofh "
  • " . $dict->insert_link($_, @code_bracket, $uri) . "
  • \n"; } print $ofh < EOHT } print $ofh < EOHT return 0; } # # Turn an entry into a URL according to the layout. # sub makeURL { local ($key, %URL) = @_; my ($prefix, $postfix) = ("", ""); if ($Layout == 0) { $prefix = "apidoc_"; $postfix = ".html"; } return "$prefix$key$postfix"; } # # Turn an entry into a anchor reference according to the layout. # sub makeHREF { local ($key, %URL) = @_; my ($prefix, $postfix) = ("", ""); if ($Layout == 0) { $prefix = "apidoc_"; $postfix = ".html"; } else { $prefix = "#"; } return "$prefix$key$postfix"; } sub dump_item { my($ofh, $prefix, $key, $record, $previous, $next) = @_; my($rtype) = $dict->category($key); my($iname) = $key; my($idef) = $dict->definition($key); my($isamp) = $dict->example($key); my($iref) = $dict->see_also($key); my($idesc) = $dict->description($key); my($uri) = $URL{$iname}; my($href) = $HREF{$iname}; my($edited); print $ofh < Apache 1.3 API: $iname

    Apache 1.3 API Documentation

    EOHT my($p) = $dict->category_name($rtype); if ($Layout == 0) { print $ofh <$p $iname EOHT } else { print <$p $iname EOHT } $edited = $dict->add_links($idef, $iname, %HREF); if (! $edited) { $edited = "No prototype or definition available."; &verbose("$0: no definition for $iname"); } if ($Layout < 2) { print $ofh < Definition:

    $edited
         
    EOHT } else { if ($edited =~ /$iname/) { $edited =~ s/$iname/$iname<\/b>/; } else { $edited="$iname: $edited"; } print $ofh "
    $edited
    \n"; } $edited = $dict->add_links($isamp, $iname, @code_bracket, %HREF); if ((! $edited) && ($Layout < 2)) { $edited = "No examples available."; &verbose("$0: no examples for $iname"); } if (($Layout < 2) || $edited) { print $ofh < Usage example:

    $edited
         
    EOHT } $idesc = $dict->description($key); if ($idesc) { $idesc = $dict->add_links($idesc, $key, @code_bracket, %HREF); print $ofh <description_file($key))) { &verbose("$0: no details listed for $iname"); print $ofh < No documentation available.

    EOHT } elsif (! -r $idname) { &verbose("$0: detail file does not exist: $idname for $iname"); print $ofh < Documentation file not accessible.

    EOHT } else { print STDERR "Shouldn't get here!\n"; } $edited = $iref; $edited =~ s/[\s,]//g; if ($edited) { local ($ref) = $iref; local ($ref_list) = "
    "; local ($sees) = ""; $ref =~ s/\s+//g; print $ofh <
    See also:
    EOHT # # Expand any aliased 'see-also' entries. # $sees = join(",\n ", $dict->expanded_seealso($key)); $edited = $dict->add_links($sees, $key, @code_bracket, %HREF); $edited =~ s:(">)([^<]+)($2$3:g; # print STDERR "$0: undefined cross-reference: " # . "$iname references undefined entity $_.\n"; print $ofh <$edited EOHT } print $ofh < EOHT if ($Layout == 0) { if ($previous) { $previous = $dict->insert_link($previous, @code_bracket, $HREF{$previous}); } else { $previous = "(none)"; } if ($next) { $next = $dict->insert_link($next, @code_bracket, $HREF{$next}); } else { $next = "(none)"; } print $ofh < Previous: $previous Next: $next

    EOHT print $ofh &link('Table of Contents', $arg{'o'}) . "\n"; print $ofh "(" . &link('Routines', "$arg{'o'}#Routines") . ",\n"; print $ofh &link('Structures', "$arg{'o'}#Structures") . ",\n"; print $ofh &link('Data Cells', "$arg{'o'}#Cells") . ",\n"; print $ofh &link('Constants', "$arg{'o'}#Constants") . ")\n"; print $ofh < EOHT } } sub usage { print STDERR "Usage:\n $0 -l [0|1|2] -t template-file -d api-data " . "-o dict-file\n"; exit 1; } sub verbose { my(@lines) = @_; my($suffix); if ($Verbose) { foreach (@lines) { if (m:\\c$:) { $suffix = ""; s:\\c$::; } else { $suffix = "\n"; } print STDERR $_, $suffix; } } return 1; } sub debug { my(@lines) = @_; my($suffix); if ($Debug) { foreach (@lines) { if (m:\\c$:) { $suffix = ""; s:\\c$::; } else { $suffix = "\n"; } print STDERR $_, $suffix; } } return 1; } sub link { my($anchor, $href, $sayso) = @_; my($result); if (! $href) { $href = $HREF{$anchor}; } if ($nolinks) { $result = "$anchor"; &verbose("No link for '$anchor'"); } else { $result = "$anchor"; &verbose("Hyperlinking '$anchor'") if ($sayso); } return $result; }