You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@apr.apache.org by fi...@apache.org on 2001/02/18 14:36:15 UTC
cvs commit: apr/build MakeEtags PrintPath cvstodsp5.pl dsp5tocvs.pl make_export.awk mkdep.sh mkdir.sh rules.mk.in scandoc.pl scandoc_template.pl
fielding 01/02/18 05:36:15
Added: build MakeEtags PrintPath cvstodsp5.pl dsp5tocvs.pl
make_export.awk mkdep.sh mkdir.sh rules.mk.in
scandoc.pl scandoc_template.pl
Log:
Moved from apr/helpers to apr/build (without changes).
scandoc has been renamed to scandoc.pl
default.pl has been renamed to scandoc_template.pl
Revision Changes Path
1.1 apr/build/MakeEtags
Index: MakeEtags
===================================================================
#!/bin/sh
# This file illustrates how to generate a useful TAGS file via etags
# for emacs. This should be invoked from the src directory i.e.:
# > helpers/MakeEtags
# and will create a TAGS file in the src directory.
# This script falls under the Apache License.
# See http://www.apache.org/docs/LICENSE
# Once you have created src/TAGS in emacs you'll need to setup
# tag-table-alist with an entry to assure it finds the single src/TAGS
# file from the many source directories. Something along these lines:
# (setq tag-table-alist
# '(("/home/me/work/apache-1.3/src/"
# . "/home/me/work/apache-1.3/src/")
# ))
# This requires a special version of etags, i.e. the
# one called "Exuberant ctags" available at:
# http://fly.hiwaay.net/~darren/ctags/
# Once that is setup you'll need to point to the
# executable here:
etags=~/local/bin/etags
# Exuberant etags is necessary since it can ignore some defined symbols
# that obscure the function signatures.
ignore=AP_DECLARE,AP_DECLARE_NONSTD,__declspec
# Create an etags file at the root of the source
# tree, then create symbol links to it from each
# directory in the source tree. By passing etags
# absolute pathnames we get a tag file that is
# NOT portable when we move the directory tree.
find . -name '*.[ch]' -print | $etags -I "$ignore" -L -
1.1 apr/build/PrintPath
Index: PrintPath
===================================================================
#!/bin/sh
# Look for program[s] somewhere in $PATH.
#
# Options:
# -s
# Do not print out full pathname. (silent)
# -pPATHNAME
# Look in PATHNAME instead of $PATH
#
# Usage:
# PrintPath [-s] [-pPATHNAME] program [program ...]
#
# Initially written by Jim Jagielski for the Apache configuration mechanism
# (with kudos to Kernighan/Pike)
#
# This script falls under the Apache License.
# See http://www.apache.org/docs/LICENSE
##
# Some "constants"
##
pathname=$PATH
echo="yes"
##
# Find out what OS we are running for later on
##
os=`(uname) 2>/dev/null`
##
# Parse command line
##
for args in $*
do
case $args in
-s ) echo="no" ;;
-p* ) pathname="`echo $args | sed 's/^..//'`" ;;
* ) programs="$programs $args" ;;
esac
done
##
# Now we make the adjustments required for OS/2 and everyone
# else :)
#
# First of all, all OS/2 programs have the '.exe' extension.
# Next, we adjust PATH (or what was given to us as PATH) to
# be whitespace seperated directories.
# Finally, we try to determine the best flag to use for
# test/[] to look for an executable file. OS/2 just has '-r'
# but with other OSs, we do some funny stuff to check to see
# if test/[] knows about -x, which is the prefered flag.
##
if [ "x$os" = "xOS/2" ]
then
ext=".exe"
pathname=`echo -E $pathname |
sed 's/^;/.;/
s/;;/;.;/g
s/;$/;./
s/;/ /g
s/\\\\/\\//g' `
test_exec_flag="-r"
else
ext="" # No default extensions
pathname=`echo $pathname |
sed 's/^:/.:/
s/::/:.:/g
s/:$/:./
s/:/ /g' `
# Here is how we test to see if test/[] can handle -x
testfile="pp.t.$$"
cat > $testfile <<ENDTEST
#!/bin/sh
if [ -x / ] || [ -x /bin ] || [ -x /bin/ls ]; then
exit 0
fi
exit 1
ENDTEST
if `/bin/sh $testfile 2>/dev/null`; then
test_exec_flag="-x"
else
test_exec_flag="-r"
fi
rm -f $testfile
fi
for program in $programs
do
for path in $pathname
do
if [ $test_exec_flag $path/${program}${ext} ] && \
[ ! -d $path/${program}${ext} ]; then
if [ "x$echo" = "xyes" ]; then
echo $path/${program}${ext}
fi
exit 0
fi
# Next try without extension (if one was used above)
if [ "x$ext" != "x" ]; then
if [ $test_exec_flag $path/${program} ] && \
[ ! -d $path/${program} ]; then
if [ "x$echo" = "xyes" ]; then
echo $path/${program}
fi
exit 0
fi
fi
done
done
exit 1
1.1 apr/build/cvstodsp5.pl
Index: cvstodsp5.pl
===================================================================
use IO::File;
use File::Find;
chdir '..';
find(\&tovc5, '.');
sub tovc5 {
if (m|.dsp$|) {
$oname = $_;
$tname = '.#' . $_;
$verchg = 0;
$srcfl = new IO::File $oname, "r" || die;
$dstfl = new IO::File $tname, "w" || die;
while ($src = <$srcfl>) {
if ($src =~ s|Format Version 6\.00|Format Version 5\.00|) {
$verchg = -1;
}
if ($src =~ s|^(# ADD CPP .*)/ZI (.*)|$1/Zi $2|) {
$verchg = -1;
}
if ($src =~ s|^(# ADD BASE CPP .*)/ZI (.*)|$1/Zi $2|) {
$verchg = -1;
}
if ($src !~ m|^# PROP AllowPerConfigDependencies|) {
print $dstfl $src; }
else {
$verchg = -1;
}
}
undef $srcfl;
undef $dstfl;
if ($verchg) {
unlink $oname || die;
rename $tname, $oname || die;
print "Converted VC6 project " . $oname . " to VC5 in " . $File::Find::dir . "\n";
}
else {
unlink $tname;
}
}
}
1.1 apr/build/dsp5tocvs.pl
Index: dsp5tocvs.pl
===================================================================
use IO::File;
use File::Find;
chdir '..';
find(\&tovc6, '.');
sub tovc6 {
if (m|.dsp$|) {
$oname = $_;
$tname = '.#' . $_;
$verchg = 0;
$srcfl = new IO::File $_, "r" || die;
$dstfl = new IO::File $tname, "w" || die;
while ($src = <$srcfl>) {
if ($src =~ s|Format Version 5\.00|Format Version 6\.00|) {
$verchg = -1;
}
if ($src =~ s|^(# ADD CPP .*)/Zi (.*)|$1/ZI $2|) {
$verchg = -1;
}
if ($src =~ s|^(# ADD BASE CPP .*)/Zi (.*)|$1/ZI $2|) {
$verchg = -1;
}
if ($src =~ s|^(!MESSAGE .*)\\\n|$1|) {
$cont = <$srcfl>;
$src = $src . $cont;
$verchg = -1;
}
print $dstfl $src;
if ($verchg && $src =~ m|^# Begin Project|) {
print $dstfl "# PROP AllowPerConfigDependencies 0\n";
}
}
undef $srcfl;
undef $dstfl;
if ($verchg) {
unlink $oname || die;
rename $tname, $oname || die;
print "Converted VC5 project " . $oname . " to VC6 in " . $File::Find::dir . "\n";
}
else {
unlink $tname;
}
}
}
1.1 apr/build/make_export.awk
Index: make_export.awk
===================================================================
# Based on Ryan Bloom's make_export.pl
/^#[ \t]*if(def)? (AP[RU]?_|!?defined).*/ {
if (old_filename != FILENAME) {
if (old_filename != "") printf("%s", line)
macro_no = 0
found = 0
count = 0
old_filename = FILENAME
line = ""
}
macro_stack[macro_no++] = macro
macro = substr($0, length($1)+2)
count++
line = line macro "\n"
next
}
/^#[ \t]*endif/ {
if (count > 0) {
count--
line = line "/" macro "\n"
macro = macro_stack[--macro_no]
}
if (count == 0) {
if (found != 0) {
printf("%s", line)
}
line = ""
}
next
}
/^[ \t]*(AP[RU]?_DECLARE[^(]*[(])?(const[ \t])?[a-z_]+[ \t\*]*[)]?[ \t]+[*]?([A-Za-z0-9_]+)\(/ {
if (count) {
found++
}
for (i = 0; i < count; i++) {
line = line "\t"
}
sub("^[ \t]*(AP[UR]?_DECLARE[^(]*[(])?(const[ \t])?[a-z_]+[ \t\*]*[)]?[ \t]+[*]?", "");
sub("[(].*", "");
line = line $0 "\n"
if (count == 0) {
printf("%s", line)
line = ""
}
next
}
END {
printf("%s", line)
}
1.1 apr/build/mkdep.sh
Index: mkdep.sh
===================================================================
#!/bin/sh
#
# 1) remove everything after the DO NOT REMOVE
# 2) generate the dependencies, adding them to the end of Makefile.new
# 3) move the Makefile.new back into place
#
# Note that we use && to ensure that Makefile is not changed if an error
# occurs during the process
#
sed -ne '1,/^# DO NOT REMOVE/p' Makefile > Makefile.new \
&& gcc -MM $* | sed -e "s/\.o:/\.lo:/" >> Makefile.new \
&& mv Makefile.new Makefile
1.1 apr/build/mkdir.sh
Index: mkdir.sh
===================================================================
#!/bin/sh
##
## mkdir.sh -- make directory hierarchy
##
## Based on `mkinstalldirs' from Noah Friedman <fr...@prep.ai.mit.edu>
## as of 1994-03-25, which was placed in the Public Domain.
## Cleaned up for Apache's Autoconf-style Interface (APACI)
## by Ralf S. Engelschall <rs...@apache.org>
##
#
# This script falls under the Apache License.
# See http://www.apache.org/docs/LICENSE
umask 022
errstatus=0
for file in ${1+"$@"} ; do
set fnord `echo ":$file" |\
sed -e 's/^:\//%/' -e 's/^://' -e 's/\// /g' -e 's/^%/\//'`
shift
pathcomp=
for d in ${1+"$@"}; do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" || errstatus=$?
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
1.1 apr/build/rules.mk.in
Index: rules.mk.in
===================================================================
# ====================================================================
# The Apache Software License, Version 1.1
#
# Copyright (c) 2000-2001 The Apache Software Foundation. All rights
# reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. The end-user documentation included with the redistribution,
# if any, must include the following acknowledgment:
# "This product includes software developed by the
# Apache Software Foundation (http://www.apache.org/)."
# Alternately, this acknowledgment may appear in the software itself,
# if and wherever such third-party acknowledgments normally appear.
#
# 4. The names "Apache" and "Apache Software Foundation" must
# not be used to endorse or promote products derived from this
# software without prior written permission. For written
# permission, please contact apache@apache.org.
#
# 5. Products derived from this software may not be called "Apache",
# nor may "Apache" appear in their name, without prior written
# permission of the Apache Software Foundation.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
# ====================================================================
#
# This software consists of voluntary contributions made by many
# individuals on behalf of the Apache Software Foundation. For more
# information on the Apache Software Foundation, please see
# <http://www.apache.org/>.
#
#
# rules.mk: standard rules for APR
#
@SET_MAKE@
#
# Configuration variables
#
top_builddir=@top_builddir@
CC=@CC@
AWK=@AWK@
LIBTOOL=@LIBTOOL@
CFLAGS=@CFLAGS@ @OPTIM@
CPPFLAGS=@CPPFLAGS@ $(INCLUDES)
LIBS=@LIBS@
LDFLAGS=@LDFLAGS@
RM=@RM@
SHELL=@SHELL@
MKEXPORT=@APR_MKEXPORT@
MKDEP=@APR_MKDEP@
SCANDOC=@APR_SCANDOC@
### make LTFLAGS somewhat variable?
LTFLAGS = --silent
#
# Basic macro setup
#
COMPILE = $(CC) $(CFLAGS) $(CPPFLAGS)
LT_COMPILE = $(LIBTOOL) --mode=compile $(LTFLAGS) $(COMPILE) -c $< && touch $@
LINK = $(LIBTOOL) --mode=link $(LTFLAGS) $(COMPILE) $(LDFLAGS) -o $@
#
# Standard build rules
#
all: all-recursive
depend: depend-recursive
clean: clean-recursive
distclean: distclean-recursive
extraclean: extraclean-recursive
install: all-recursive
all-recursive depend-recursive clean-recursive distclean-recursive \
extraclean-recursive:
@otarget=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; \
for i in $$list; do \
if test -d "$$i"; then \
target="$$otarget"; \
echo "Making $$target in $$i"; \
if test "$$i" = "."; then \
made_local=yes; \
target="local-$$target"; \
fi; \
(cd $$i && $(MAKE) $$target) || exit 1; \
fi; \
done; \
if test "$$otarget" = "all" && test -z "$(TARGETS)"; then \
made_local=n/a; \
fi; \
if test -z "$$made_local"; then \
$(MAKE) "local-$$otarget" || exit 1; \
fi
local-clean: x-local-clean
$(RM) -f *.o *.lo *.a *.la *.so $(CLEAN_TARGETS) $(PROGRAMS)
$(RM) -rf .libs
local-distclean: local-clean x-local-distclean
$(RM) -f Makefile $(DISTCLEAN_TARGETS)
local-extraclean: local-distclean
@if test -n "$(EXTRACLEAN_TARGETS)"; then \
echo $(RM) -f $(EXTRACLEAN_TARGETS) ; \
$(RM) -f $(EXTRACLEAN_TARGETS) ; \
fi
local-all: $(TARGETS)
local-depend:
@if test -n "`ls *.c 2> /dev/null`"; then \
echo $(MKDEP) $(CFLAGS) $(CPPFLAGS) *.c ; \
$(MKDEP) $(CFLAGS) $(CPPFLAGS) *.c ; \
fi
# to be filled in by the actual Makefile
x-local-clean x-local-distclean:
#
# Implicit rules for creating outputs from input files
#
.SUFFIXES:
.SUFFIXES: .c .lo .o
.c.o:
$(COMPILE) -c $<
.c.lo:
$(LT_COMPILE)
.PHONY: all depend clean distclean extraclean install \
all-recursive depend-recursive clean-recursive distclean-recursive \
extraclean-recursive
local-all local-depend local-clean local-distclean local-extraclean \
x-local-clean x-local-distclean
1.1 apr/build/scandoc.pl
Index: scandoc.pl
===================================================================
#!/usr/bin/perl
#
# ScanDoc - Version 0.12, A C/C++ Embedded Documentation Analyser
# ----------------------------------------------------------------
#
# Distributed under the "Artistic License". See the file
# "COPYING" that accompanies the ScanDoc distribution.
#
# See http://scandoc.sourceforge.net/ for more information and
# complete documentation.
#
# (c) 1997 - 2000 Talin and others.
require "ctime.pl";
require "getopts.pl";
# 1 = on (verbose); 0 = off
$debug = 0;
# Get the current date
$date = &ctime(time);
# Set the default tab size
$tabSize = 4;
$minorVersion = 12;
$majorVersion = 0;
$scandocURL = "http://scandoc.sourceforge.net/";
# Set up default templates
&Getopts( 'i:d:p:t:' );
if ($#ARGV < 0) {
die "Usage: -i <doc-template> -p <output-path> -t<tabsize> -d<sym>=<value> [ <input-files> ... ]\n";
}
# Read the template
if (!defined $opt_i) {
$opt_i = "default.pl";
}
&readTemplate( $opt_i );
# Set the destination path.
$destPath = "";
$destPath = $opt_p if (defined($opt_p));
# Set the tab size.
$tabSize = $opt_t if (defined($opt_t));
# Handle defines
if ($opt_d) {
foreach $def (split( /,/, $opt_d )) {
if ($def =~ /\s*(\w*)\=(.*)/) {
$${1} = $2;
}
else {
$${1} = 1;
}
}
}
# For each input filename, parse it
while ($srcfile = shift(@ARGV)) {
$linenumber = 0;
open( FILE, $srcfile ) || die "Can't open file $srcfile\n";
print STDERR "Reading \"$srcfile\"\n";
$docTag = 'description';
$docEmpty = 1;
$packageName = '.general';
$author = '';
$version = '';
$class = 0;
$_ = '';
while (&parseDeclaration( '' )) {}
}
# Collate subclasses and associate with class record.
foreach $className (keys %subclasses) {
my $class = &classRecord( $className );
if ($class) {
my @subs = ();
# print STDERR "$className ", join( ',', @{$subclasses{ $className }} ), "\n";
foreach $subName ($subclasses{ $className }) {
if (&classRecord( $subName )) {
push @subs, $subName;
}
$class->{ 'subs' } = @subs;
}
}
}
# Turn packages into objects. Special case for "default" package.
foreach $pkg (keys %packages)
{
# print STDERR $pkg, "\n";
bless $packages{ $pkg }, PackageRecord;
if ($pkg eq '.general') {
$packages{ $pkg }{ 'name' } = "General";
}
else {
$packages{ $pkg }{ 'name' } = $pkg;
}
# print STDERR $packages{ $pkg }->Classes(), "\n";
}
# Execute template file
# print STDERR $docTemplate; # For debugging
eval $docTemplate;
print STDERR $@;
exit;
# ======================= Subroutines ================================
# Read a line of input, and remove blank lines and preprocessor directives.
sub rdln {
my ($skip_next_line) = 0;
if (defined ($_)) {
my ($previous_line) = $_;
while ( (/^(\s*|\#.*)$/ || $skip_next_line ) && ($_ = <FILE>)) {
if ($previous_line =~ m/\\\s*/) { $skip_next_line = 1; }
else { $skip_next_line = 0; }
$previous_line = $_;
$linenumber++;
if ($debug) { print STDERR "(0:$srcfile) $linenumber.\n"; }
}
}
# Dispose of Apache specific macros
removeApacheMacros();
}
# Don't skip "#"
sub rdln2 {
if (defined ($_)) {
while (/^(\s*)$/ && ($_ = <FILE>)) {$linenumber++; if ($debug) { print STDERR "(0:$srcfile) $linenumber.\n"; } }
}
}
# Remove comments from current line
sub removeComment {
s|//.*||;
}
# parsing functions
sub matchKW { &rdln; return (s/^\s*($_[0])//, $1) if defined ($_); return (0, 0); }
#sub matchStruct { &rdln; return (s/^\s*(struct|class)//, $1) if defined ($_); return (0, 0); }
#sub matchPermission { &rdln; return (s/^\s*(public|private|protected)// && $1) if defined ($_); return (0,0); }
sub matchID { &rdln; return (s/^\s*([A-Za-z_]\w*)//, $1) if defined ($_); return (0,0); }
sub matchColon { &rdln; return (s/^\s*\://) if defined ($_); return 0; }
sub matchComma { &rdln; return (s/^\s*\,//) if defined ($_); return 0; }
sub matchSemi { &rdln; return (s/^\s*\;//) if defined ($_); return 0; }
sub matchRBracket { &rdln; return (s/^\s*\{//) if defined ($_); return 0; }
sub matchLBracket { &rdln; return (s/^\s*\}//) if defined ($_); return 0; }
sub matchRParen { &rdln; return (s/^\s*\(//) if defined ($_); return 0; }
sub matchLParen { &rdln; return (s/^\s*\)//) if defined ($_); return 0; }
sub matchRAngle { &rdln; return (s/^\s*\<//) if defined ($_); return 0; }
sub matchLAngle { &rdln; return (s/^\s*\>//) if defined ($_); return 0; }
sub matchDecl { &rdln; return (s/^(\s*[\s\w\*\[\]\~\&\n\:]+)//, $1) if defined ($_); return (0, 0); }
sub matchOper { &rdln; return (s/^\s*([\~\&\^\>\<\=\!\%\*\+\-\/\|\w]*)// && $1) if defined ($_); return 0; }
sub matchFuncOper { &rdln; return (s/^\s*(\(\))// && $1) if defined ($_); return 0; }
sub matchAny { &rdln; return (s/^\s*(\S+)//, $1) if defined ($_); return (0, 0); }
sub matchChar { &rdln; return (s/^(.)//, $1) if defined ($_); return (0, 0); }
sub matchChar2 { &rdln2; return (s/^(.)//, $1) if defined ($_); return (0, 0); }
sub matchString { &rdln; return (s/^\"(([^\\\"]|(\\.)))*\"//, $1) if defined ($_); return (0, 0); }
# Skip to next semicolon
sub skipToSemi {
while (!&matchSemi) {
&rdln;
s|//.*||; # Eat comments
if (&matchLBracket) {
&skipBody;
next;
}
last if !s/^\s*([^\s\{\;]+)//;
# print STDERR "$1 ";
}
}
# Skip function body
sub skipBody {
local( $nest );
$nest = 1;
for (;;) {
if (&matchRBracket) { $nest++; }
elsif (&matchLBracket) {
$nest--;
last if !$nest;
}
else {
last if ((($valid,) = &matchKW( "[^\{\}]")) && !$valid);
}
}
}
# Skip a string. (multiline)
sub skipString {
local( $char, $lastchar);
$lastchar = "\"";
for (;;) {
($valid, $char) = &matchChar2;
if (($char eq "\"") && ($lastchar ne "\\")) { last; }
if ($lastchar eq "\\") { $lastchar = " "; }
else { $lastchar = $char; }
}
}
# Skip everything in parenthesis.
sub skipParenBody {
local( $nest );
$nest = 1;
for (;;) {
if (&matchRParen) { $nest++; }
elsif (&matchLParen) {
$nest--;
last if !$nest;
}
else {
last if ((($valid,) = &matchKW( "[^\(\)]")) && !$valid);
}
}
}
# Parse (*name) syntax
sub parseParenPointer {
if (s/^(\s*\(\s*\*)//) {
$decl .= $1;
$nest = 1;
for (;;) {
# Preserve spaces, eliminate in-line comments
&removeComment;
while (s/^(\s+)//) { $decl .= $1; &rdln; }
if (&matchRParen) { $nest++; $decl .= "("; }
elsif (&matchLParen) {
$decl .= ")";
$nest--;
last if !$nest;
}
elsif ((($valid, $d) = &matchKW( "[^\(\)]*")) && $valid) { $decl .= $d; }
else { last; }
}
# Just in case there are array braces afterwards.
while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
}
}
# Parse template arguments
sub matchAngleArgs {
if (&matchRAngle) {
local ($args, $nest);
$args = "<";
$nest = 1;
for (;;) {
if (&matchRAngle) { $nest++; $args .= "<"; }
elsif (&matchLAngle) {
$nest--;
$args .= ">";
last if !$nest;
}
elsif ((($valid, $d) = &matchChar) && $valid) { $args .= $d; }
else { last; }
}
return $args;
}
else { return ''; }
}
# convert tabs to spaces
sub expandTabs {
local ($text) = @_;
local ($n);
while (($n = index($text,"\t")) >= 0) {
substr($text, $n, 1) = " " x ($tabSize-($n % $tabSize));
}
return $text;
}
# Process a line of text from a "special" comment
sub handleCommentLine {
local ($_) = @_;
if ($docEmpty) {
# Eliminate blank lines at the head of the doc.
return if (/^\s*$/);
}
# First, expand tabs.
$_ = &expandTabs( $_ );
# Remove gratuitous \s*\s (james)
s/(^|\n)\s*\*\s/$1/g;
# If it's one of the standard tags
if (s/^\s*\@(see|package|version|author|param|return|result|exception|keywords|deffunc|defvar|heading|todo)\s*//) {
my $tag = $1;
$tag = 'return' if ($tag eq 'result');
# for param and exception, split the param name and the text
# seperate them with tabs.
if ($tag eq "param" || $tag eq "exception") {
s/^\s*(\w+)\s*(.*)/\t$1\t$2/;
}
elsif ($tag eq "heading") {
# 'heading' is processed by the template, if at all.
$_ = "\@heading\t$_";
$tag = "description";
}
elsif ($tag eq 'todo') {
if ($todolist{ $srcfile } ne '') {
$todolist{ $srcfile } .= "\n";
}
}
# If it's @deffunc or @defvar
if ($tag =~ /def(.*)/) {
$type = $1;
# @deffunc and @defvar force a comment to be written out as if there was a
# declaration.
# Designed for use with macros and other constructs I can't parse.
if (/(\S+)\s+(.*)$/) {
$name = $1;
$decl = $2;
$dbname = &uniqueName( "$baseScope$name" );
my $entry = { 'type' => $type,
'name' => $name,
'longname'=> $name,
'fullname'=> "$name $decl",
'scopename'=>"$baseScope$name",
'uname' => $dbname,
'decl' => $decl,
'package' => $packageName };
bless $entry, MemberRecord;
if ($class) {
$entry->{ 'class' } = "$context";
$class->{ 'members' }{ $dbname } = $entry;
}
else {
$packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
}
$docTag = 'description';
&dumpComments( $entry );
return;
}
}
elsif ($tag eq 'package') {
s/^\s*//;
s/\s*$//;
$packageName = $_;
$docTag = 'description';
return;
}
elsif ($tag eq 'author') {
$author = $_;
$docTag = 'description';
return;
}
elsif ($tag eq 'version') {
$version = $_;
$docTag = 'description';
return;
}
$docTag = $tag;
}
elsif (/^\s*@\w+/) {
# any other line that begins with an @ should be inserted into the main
# description for later expansion.
$docTag = 'description';
}
# "To-do" lists are handled specially, and not associated with a class.
if ($docTag eq 'todo') {
$todolist{ $srcfile } .= $_;
return;
}
# Append to current doc tag, regardless of whether it's a new line
# or a continuation. Also mark this doc as non-empty.
$docTags{ $docTag } .= $_;
$docEmpty = 0;
# @see doesn't persist.
if ($docTag eq 'see') { $docTag = 'description'; }
# print STDERR ":$_";
}
# Clear doc tag information at end of class or file
sub clearComments {
$docTag = 'description';
$docEmpty = 1;
%docTags = ();
}
# Add doc tag information to current documented item
sub dumpComments {
local ($hashref) = @_;
if ($docEmpty == 0) {
if ($author ne '') { $hashref->{ 'author' } = $author; }
if ($version ne '') { $hashref->{ 'version' } = $version; }
$hashref->{ 'sourcefile' } = $srcfile;
# Store the tags for this documentation into the global doc symbol table
foreach $key (keys %docTags) {
my $data = $docTags{ $key };
$data =~ s/\s*$//;
$hashref->{ $key } = $data;
}
}
&clearComments();
}
# Generate a unique name from the given name.
sub uniqueName {
local ($name) = @_;
# Duplicate doc entries need to be distinguished, so give them a different label.
while ($docs{ $name }) {
if ($name =~ /-(\d+)$/) {
$name = $` . "-" . ($1 + 1);
}
else { $name .= "-2"; }
}
$docs{ $name } = 1;
return $name;
}
# Get the current class record.
sub classRecord {
local ($className) = @_;
local ($pkg) = $classToPackage{ $className };
if ($pkg) {
return $packages{ $pkg }{ 'classes' }{ $className };
}
return 0;
}
# Parse a declaration in the file
sub parseDeclaration {
local ($context) = @_;
local ($baseScope) = '';
local ($decl);
my ($token);
if ($context) { $baseScope = $context . "::"; }
&rdln;
if (!defined ($_)) { return 0; }
if (s|^\s*//\*\s+||) {
# Special C++ comment
&handleCommentLine( $' );
$_ = ''; &rdln;
}
elsif (s|^\s*//||) {
# Ordinary C++ comment
$_ = '';
&rdln;
}
elsif (s|^\s*\/\*\*\s+||) {
# Special C comments
s/\={3,}|\-{3,}|\*{3,}//; # Eliminate banner strips
$text = '';
$docTag = 'description';
# Special comment
while (!/\*\//) { &handleCommentLine( $_ ); $text .= $_; $_ = <FILE>; $linenumber++; if ($debug) { print STDERR "(1) $linenumber\n."; }}
s/\={3,}|\-{3,}|\*{3,}//; # Eliminate banner strips
/\*\//;
&handleCommentLine( $` );
$text.= $`; $_ = $';
}
elsif (s|^\s*\/\*||) {
# Ordinary C comment
$text = "";
while (!/\*\//) { $text .= $_; $_ = <FILE>; $linenumber++; if ($debug) { print STDERR "(2) $linenumber\n."; }}
/\*\//;
$text.= $`; $_ = $';
}
elsif ((($valid, $tag) = &matchKW( "template")) && $valid) {
# Template definition
$args = &matchAngleArgs;
&rdln;
##$tmplParams = $args; JAMES
$result = &parseDeclaration( $context );
##$tmplParams = ''; JAMES
return $result;
}
elsif ((($valid, $tag) = &matchKW("class|struct")) && $valid) {
# Class or structure definition
local ($className,$class);
if ((($valid, $className) = &matchID) && $valid) {
return 1 if (&matchSemi); # Only a struct tag
# A class instance
if ((($valid,)=&matchID) && $valid) {
&matchSemi;
return 1;
}
my $fullName = "$baseScope$className"; ##$tmplParams"; JAMES
# print STDERR "CLASS $fullName\n";
my @bases = ();
if (&matchColon) {
for (;;) {
my $p;
&matchKW( "virtual" );
$perm = "private";
if ((($valid, $p) = &matchKW( "public|private|protected" )) && $valid) { $perm = $p; }
&matchKW( "virtual" );
last if !( (($valid, $base) = &matchID) && $valid );
push @bases, $base;
push @{ $subclasses{ $base } }, $fullName;
# print STDERR " : $perm $base\n";
last if !&matchComma;
}
}
# print STDERR "\n";
# print STDERR "parsing class $fullName\n";
if ($docEmpty == 0) {
$class = { 'type' => $tag,
'name' => $fullName,
'longname'=> "$tag $className",
'fullname'=> "$tag $className",
'scopename'=> "$tag $fullName",
'uname' => $fullName,
'bases' => \@bases,
'package' => $packageName,
'members' => {} };
# print STDERR "$className: @bases\n";
bless $class, ClassRecord;
print STDERR " parsing class $fullName\n";
# $classToPackage{ $className } = $packageName;
$classToPackage{ $fullName } = $packageName;
# $classList{ $className } = $class;
$classList{ $fullName } = $class;
$packages{ $packageName }{ 'classes' }{ $fullName } = $class;
&dumpComments( $class );
}
if (&matchRBracket) {
local ($perm) = ("private");
while (!&matchLBracket) {
my $p;
if ((($valid, $p) = &matchKW( "public\:|private\:|protected\:" )) && $valid) {
$perm = $p;
}
else {
&parseDeclaration( $fullName )
|| die "Unmatched brace! line = $linenumber\n";
}
}
&matchSemi;
}
&clearComments;
}
}
elsif ( ((($valid,)=&matchKW( "enum")) && $valid) || ((($valid,)=&matchKW( "typedef" )) && $valid)) {
&skipToSemi;
}
elsif ((($valid,)=&matchKW( "friend\s*class" )) && $valid) {
&skipToSemi;
}
elsif ((($valid, $token) = &matchKW("extern\\s*\\\"C\\\"")) && $valid) {
&matchRBracket;
while (!&matchLBracket) {
&parseDeclaration( '' ) || die "Unmatched brace! line = $linenumber\n";
}
&matchSemi;
}
# elsif ($kw = &matchID) {
# $type = "$kw ";
#
# if ($kw =~/virtual|static|const|volatile/) {
# $type .= &typ;
# }
# }
elsif ((($valid, $decl) = &matchDecl) && $valid) {
my ($instanceClass) = "";
# print STDERR "DECLARATION=$decl, REST=$_, baseScope=$baseScope\n";
return 1 if ($decl =~ /^\s*$/);
if (!($class)) {
if ($decl =~ s/(\S*\s*)(\S+)\:\:(\S+)\s*$/$1$3/) {
$instanceClass = $2;
}
}
# Eliminate in-line comments
&removeComment;
# Check for multi-line declaration
while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
# Handle template args, but don't let operator overloading confuse us!
$tempArgs = '';
if (!($decl =~ /\boperator\b/) && ($tempArgs = &matchAngleArgs)) {
$tempArgs = $decl . $tempArgs;
$decl = '';
while ((($valid, $d) = &matchDecl) && $valid) { $decl .= $d; }
}
# Look for (*name) syntax
&parseParenPointer;
# Special handling for operator... syntax
$oper = "";
if ($decl =~ s/\boperator\b(.*)/operator/) {
$oper = $1;
$oper .= &matchOper;
# If, after all that there's no opers, then try a () operator
if (!($oper =~ /\S/)) { $oper .= &matchFuncOper; }
}
($type,$mod,$decl) = $decl =~ /([\s\w]*)([\s\*\&]+\s?)(\~?\w+(\[.*\])*)/;
$type = $tempArgs . $type;
$decl .= $oper;
if ($mod =~ /\s/) { $type .= $mod; $mod = ""; }
for (;;) {
# print STDERR "Looping: $type/$mod/$decl\n";
if (&matchRParen) {
$nest = 1;
$args = "";
for (;;) {
# print STDERR "Argloop $_\n";
# Process argument lists.
# Preserve spaces, eliminate in-line comments
# REM: Change this to save inline comments and automatically
# generate @param clauses
s|//.*||;
while (s/^(\s+)//) { $args .= " "; &rdln; }
if (&matchRParen) { $nest++; $args .= "("; }
elsif (&matchLParen) {
$nest--;
last if !$nest;
$args .= ")";
}
elsif ((($valid, $d) = &matchKW( "[\,\=\.\:\-]" )) && $valid) { $args .= $d; }
elsif ((($valid, $d) = &matchDecl) && $valid) { $args .= $d; }
elsif ((($valid, $d) = &matchAngleArgs) && $valid) { $args .= $d; }
elsif ((($valid, $d) = &matchString) && $valid) { $args .= "\"$d\""; }
else { last; }
}
# print STDERR "$type$mod$baseScope$decl($args);\n";
&matchKW( "const" );
# Search for any text within the name field
# if ($docTag && $decl =~ /\W*(~?\w*).*/)
if ($docEmpty == 0) {
$type =~ s/^\s+//;
$mod =~ s/\&/\&/g;
$args =~ s/\&/\&/g;
$args =~ s/\s+/ /g;
$dbname = &uniqueName( "$baseScope$decl" );
my $entry = { 'type' => 'func',
'name' => $decl,
'longname'=> "$decl()",
'fullname'=> "$type$mod$decl($args)",
'scopename'=>"$type$mod$baseScope$decl($args)",
'uname' => $dbname,
'decl' => "$type$mod$decl($args)",
'package' => $packageName };
bless $entry, MemberRecord;
if ($class) {
$entry->{ 'class' } = "$context";
$class->{ 'members' }{ $dbname } = $entry;
}
elsif ($instanceClass) {
$class = &classRecord ($instanceClass);
if (!($class)) {
print STDERR "WARNING: Skipping \"$instanceClass\:\:$decl\". Class \"$instanceClass\" not declared ($linenumber).\n";
} else {
$entry->{ 'class' } = "$instanceClass";
$class->{ 'members' }{ $dbname } = $entry;
$class = 0;
}
}
else {
$packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
}
&dumpComments( $entry );
}
else { &clearComments; }
s|//.*||;
# Constructor super-call syntax
if (&matchColon) {
# Skip over it.
for (;;) {
&rdln;
last if /^\s*(\{|\;)/;
last if !((($valid,)=&matchAny) && $valid);
}
}
last if &matchSemi;
if (&matchRBracket) { &skipBody; last; }
last if !&matchComma;
last if !((($valid, $decl) = &matchDecl) && $valid);
# Look for (*name) syntax
&parseParenPointer;
$decl =~ s/^\s*//;
$oper = "";
if ($decl =~ /\boperator\b/) {
$decl =~ s/\boperator\b(.*)/operator/;
$oper = $1 . &matchOper;
}
($mod,$d) = $decl =~ /^\s*([\*\&]*)\s*(\~?\w+(\[.*\])*)/;
$decl .= $oper;
$decl = $d if $d ne "";
}
else {
s|//.*||;
$final = 0;
if ((($valid,)=&matchKW( "\=" )) && $valid) {
for (;;) {
if (&matchRBracket) {
&skipBody;
$final = 1;
last;
}
if (&matchSemi) {
$final = 1;
last;
}
# var = new ... (...)
if ((($valid,)=&matchKW("new")) && $valid) {
&matchKW("[A-Za-z_0-9 ]*");
if (&matchRParen) {
&skipParenBody;
}
}
# var = (.....) ...
if (&matchRParen) {
&skipParenBody;
}
# var = ... * ...
&matchKW ("[\/\*\-\+]*");
# var = "..."
if ((($valid,) = &matchKW ("[\"]")) && $valid) {
&skipString;
}
#&matchString;
last if /^\s*,/;
#last if !((($valid,)=&matchAny) && $valid);
last if !((($valid,)=&matchKW("[A-Za-z_0-9 \-]*")) && $valid);
if (&matchSemi) {
$final = 1;
last;
}
}
}
s|//.*||;
# void ~*&foo[];
# void foo[];
# void far*foo[];
# print STDERR "Decl: $type$mod$baseScope$decl;\n";
# Search for any text within the name field
if ($docEmpty == 0 && ($decl =~ /\W*(~?\w*).*/))
{
$mod =~ s/\&/\&/g;
$name = $decl;
$dbname = &uniqueName( "$baseScope$1" );
my $entry = { 'type' => 'var',
'name' => $1,
'longname' => "$name",
'fullname' => "$type$mod$decl",
'scopename'=> "$baseScope$type$mod$decl",
'uname' => $dbname,
'decl' => "$type$mod$decl",
'package' => $packageName };
bless $entry, MemberRecord;
if ($class) {
$entry->{ 'class' } = "$context";
$class->{ 'members' }{ $dbname } = $entry;
}
else {
$packages{ $packageName }{ 'globals' }{ $dbname } = $entry;
}
&dumpComments( $entry );
}
else { &clearComments; }
last if $final;
last if &matchSemi;
last if !&matchComma;
last if !((($valid, $decl) = &matchDecl) && $valid);
# Look for (*name) syntax
&parseParenPointer;
$decl =~ s/^\s*//;
($mod,$d) = $decl =~ /^\s*([\*\&]*)(\~?\w+(\[.*\])*)/;
$decl = $d if $d ne "";
}
}
}
elsif ($context ne "" && /^\s*\}/) {
# print STDERR "Popping!\n";
return 1;
}
elsif (&matchRBracket) {
&skipBody;
}
elsif ((($valid, $token) = &matchAny) && $valid) {
# Comment in for debugging
# print STDERR "token: $token \n";
}
else { return 0; }
return 1;
}
# read a file into a string ( filename, default-value )
sub readFile {
local ( $filename, $result ) = @_;
if ($filename && open( FILE, $filename )) {
$result = "";
while (<FILE>) { $result .= $_; }
close( FILE );
}
return $result;
}
# Read the entire document template and translate into PERL code.
sub readTemplate {
local ( $filename ) = @_;
$docTemplate = '';
$indent = '';
$literal = 1; # We're in literal mode.
if (!-e $filename) {
if (-e "./templates/$filename") { $filename = "./templates/$filename"; }
elsif (-e "../templates/$filename") { $filename = "../templates/$filename"; }
else { die "Could not find template '$filename'.\n"; }
}
open( FILE, $filename ) || die "Error opening '$filename'.\n";
while (<FILE>) {
last if (/END/);
# if we found a code entry.
for (;;) {
&expandTabs( $_ );
if ($literal) {
# Check for beginning of code block.
if (s/^(.*)\<\<//) {
$line = $1;
if (substr( $line, 0, length( $indent ) ) eq $indent) {
substr( $line, 0, length( $indent ) ) = '';
}
if ($line ne '') {
$line =~ s/\"/\\\"/g;
$line =~ s/\$\((\w+)\.(\w+)\)/\" \. \$$1->$2() \. \"/g;
$docTemplate .= "${indent}print\"$line\";";
}
# else { $docTemplate .= "\n"; }
$literal = 0;
}
else {
if (substr( $_, 0, length( $indent ) ) eq $indent) {
substr( $_, 0, length( $indent ) ) = "";
}
chop;
s/\"/\\\"/g;
s/\$\((\w+)\.(\w+)\)/\" \. \$$1->$2() \. \"/g;
$_ = $indent . "print \"" . $_ . "\\n\";\n";
last;
}
}
else {
# Check for beginning of literal block.
if (s/^(\s*)\>\>//) {
$indent = $1;
$literal = 1;
}
elsif (s/^(\s*)(.*)\>\>//) {
$docTemplate .= "$indent$2";
$literal = 1;
}
else {
last;
}
}
}
$docTemplate .= $_;
}
close( FILE );
# print $docTemplate;
}
# Functions intended to be called from doc template file.
# Open a new output file
sub file {
my $mfile = $_[ 0 ];
open( STDOUT, ">$destPath$mfile" ) || die "Error writing to '$mfile'\n";
}
# return list of package objects
sub packages {
my ($p, @r);
@r = ();
foreach $p (sort keys %packages) {
push @r, $packages{ $p };
}
return @r;
}
# return list of source files which have to-do lists
sub todolistFiles {
my ($p, @r);
@r = ();
foreach $p (sort keys %todolist) {
push @r, $p;
}
return @r;
}
# return list of tab-delimited to-do-list texts.
sub todolistEntries {
local $_ = $todolist{ $_[0] };
s/^\s+//; # Remove whitespace from beginning
s/\s+$/\n/; # Remove whitespace from end
return split( /\n/, $_ );
}
# Convert package name to URL.
sub packageURL {
my $p = $_[0];
if ($p eq 'General') { $p = '.general'; }
if ($p eq '') { $p = '.general'; }
if (ref $packages{ $p }) {
return $packages{ $p }->url();
}
return 0;
}
# Get the see-also list for an object
sub seealsoList {
my $self = shift;
my ($see, $name, $url, $p, @r);
@r = ();
if (defined ($self->{ 'see' })) {
foreach $_ (split(/\n/,$self->{ 'see' })) {
if (/^\<a\s+href/) { # if already an HREF.
$name = $_;
$url = 0;
}
elsif (/([^\#]*)\#(.*)/) { # If a package name is present
$url = &packageURL( $1 ) . '#' . $2;
$name = $2;
}
else {
$name = $_;
$url = "#$_";
# This doesn't appear to do anything - so I commented it. (james)
# Look up the package in the index and use it to construct the html filename.
#if (/^([^\:]*)\:\:(.*)/) {
# $className = ($1 eq '') ? '' : $classToPackage{ $1 };
# $p = $packageToFile{ $className };
# if ($p ne '') {
# $url = &packageURL( $1 ) . '#' . $_;
# }
#}
}
$url =~ s/^\:*//; # Remove leading colons from name
$url =~ s/::/-/g; # Replace :: with dash
my $entry = { 'name' => $name,
'url' => $url };
bless $entry, DocReference;
push @r, $entry;
}
}
return @r;
}
sub removeApacheMacros {
# print "removing from $_";
s|AP_DECLARE\((.*?)\)|$1|;
}
# Class for parsed package
package PackageRecord;
sub classes {
my $self = shift;
my $classes = $self->{ 'classes' };
return map $classes->{ $_ }, (sort keys %$classes);
}
sub globals {
my $self = shift;
my $globals = $self->{ 'globals' };
return map $globals->{ $_ }, (sort keys %$globals);
}
sub globalvars {
my $self = shift;
my $globals = $self->{ 'globals' };
my ($p, @r);
@r = ();
foreach $p (sort keys %$globals) {
my $m = $globals->{ $p };
if ($m->{ 'type' } ne 'func') { push @r, $m; }
}
return @r;
}
sub globalfuncs {
my $self = shift;
my $globals = $self->{ 'globals' };
my ($p, @r);
@r = ();
foreach $p (sort keys %$globals) {
my $m = $globals->{ $p };
if ($m->{ 'type' } eq 'func') { push @r, $m; }
}
return @r;
}
sub name {
my $self = shift;
return $self->{ 'name' };
}
sub url {
my $self = shift;
return "default-pkg.html" if ($self->{ 'name' } eq '.general');
return $self->{ 'name' } . '.html';
}
sub anchor {
my $self = shift;
my $url = $self->{ 'name' };
return $url;
}
# Class for parsed class
package ClassRecord;
sub keywords { return ${$_[0]}{ 'keywords' }; }
sub author { return ${$_[0]}{ 'author' }; }
sub version { return ${$_[0]}{ 'version' }; }
sub name { return ${$_[0]}{ 'name' }; }
sub longname { return ${$_[0]}{ 'longname' }; }
sub fullname { return ${$_[0]}{ 'fullname' }; }
sub scopename { return ${$_[0]}{ 'scopename' }; }
sub sourcefile { return ${$_[0]}{ 'sourcefile' }; }
#sub description { return &::processDescription( ${$_[0]}{ 'description' } ); }
sub description { return ${$_[0]}{ 'description' }; }
sub seealso { &::seealsoList( $_[0] ); }
sub url {
my $self = shift;
return 0 unless $self->{ 'package' };
my $pname = ::packageURL( $self->{ 'package' } );
my $url = $self->{ 'uname' };
$url =~ s/::/-/g;
return "$pname#$url";
}
sub anchor {
my $self = shift;
my $url = $self->{ 'uname' };
$url =~ s/::/-/g;
return $url;
}
sub members {
my $self = shift;
my $members = $self->{ 'members' };
my ($p, @r);
@r = ();
foreach $p (sort keys %$members) {
push @r, $members->{ $p };
}
return @r;
}
sub membervars {
my $self = shift;
my $members = $self->{ 'members' };
my ($p, @r);
@r = ();
foreach $p (sort keys %$members) {
my $m = $members->{ $p };
if ($m->{ 'type' } ne 'func') { push @r, $m; }
}
return @r;
}
sub memberfuncs {
my $self = shift;
my $members = $self->{ 'members' };
my ($p, @r);
@r = ();
foreach $p (sort keys %$members) {
my $m = $members->{ $p };
if ($m->{ 'type' } eq 'func') { push @r, $m; }
}
return @r;
}
sub baseclasses {
my $self = shift;
my $bases = $self->{ 'bases' };
my ($p, $class, @r);
@r = ();
foreach $p (@$bases) {
unless ($class = $::classList{ $p }) {
# It's one we don't know about, so just make something up
$class = { 'name' => $p,
'longname'=> "class $p",
'fullname'=> "class $p",
'scopename'=>"class $p",
'uname' => $p,
'members' => {} };
if ($::classToPackage{ $p }) {
$class->{ 'package' } = $::classToPackage{ $p };
}
bless $class, ClassRecord;
}
push @r, $class;
}
return @r;
}
sub subclasses {
my $self = shift;
my $subs;
my ($p, $class, @r);
@r = ();
if (defined ($self->{ 'subs' })) {
$subs = $self->{ 'subs' };
foreach $p (sort @$subs) {
$class = $::classList{ $p };
push @r, $class;
}
}
return @r;
}
# Class for parsed class member or global
package MemberRecord;
sub type { return ${$_[0]}{ 'type' }; }
sub keywords { return ${$_[0]}{ 'keywords' }; }
sub author { return ${$_[0]}{ 'author' }; }
sub version { return ${$_[0]}{ 'version' }; }
sub name { return ${$_[0]}{ 'name' }; }
sub longname { return ${$_[0]}{ 'longname' }; }
sub fullname { return ${$_[0]}{ 'fullname' }; }
sub scopename { return ${$_[0]}{ 'scopename' }; }
sub returnValue { return ${$_[0]}{ 'return' }; }
sub sourcefile { return ${$_[0]}{ 'sourcefile' }; }
sub description { return ${$_[0]}{ 'description' }; }
sub seealso { &::seealsoList( $_[0] ); }
sub url {
my $self = shift;
return 0 unless $self->{ 'package' };
my $pname = ::packageURL( $self->{ 'package' } );
my $url = $self->{ 'uname' };
$url =~ s/::/-/g;
return "$pname#$url";
}
sub anchor {
my $self = shift;
my $url = $self->{ 'uname' };
$url =~ s/::/-/g;
$url;
}
sub params {
my $self = shift;
my $params = $self->{ 'param' };
my @r;
@r = ();
return 0 unless ($params);
my @paramList = split( /\t/, $params );
for ($i = 1; $i < $#paramList; $i += 2) {
my $entry = { 'name' => $paramList[ $i ],
'description' => $paramList[ $i + 1 ] };
bless $entry, ArgRecord;
push @r, $entry;
}
return @r;
}
sub exceptions {
my $self = shift;
my $params = $self->{ 'exception' };
my @r;
@r = ();
return 0 unless ($params);
my @paramList = split( /\t/, $params );
for ($i = 1; $i < $#paramList; $i += 2) {
my $entry = { 'name' => $paramList[ $i ],
'description' => $paramList[ $i + 1 ] };
bless $entry, ArgRecord;
push @r, $entry;
}
return @r;
}
package ArgRecord;
sub name { return ${$_[0]}{ 'name' }; }
sub description { return ${$_[0]}{ 'description' }; }
package DocReference;
sub name { return ${$_[0]}{ 'name' }; }
sub url { return ${$_[0]}{ 'url' }; }
1.1 apr/build/scandoc_template.pl
Index: scandoc_template.pl
===================================================================
<<
# Scandoc template file.
#
# This is an example set of templates that is designed to create several
# different kinds of index files. It generates a "master index" which intended
# for use with a frames browser; A "package index" which is the root page of
# the index, and then "package files" containing documentation for all of the
# classes within a single package.
######################################################################
## For quick and superficial customization,
## simply change these variables
$project_name = '[Apache Portable RunTime]';
#$company_logo = '<img src="../images/ScanDocBig.jpg">'; # change this to an image tag.
$copyright = '© 2000 [Apache Software Foundation]';
$image_directory = "../images/";
$bullet1_image = $image_directory . "ball1.gif";
$bullet2_image = $image_directory . "ball2.gif";
$bgcolor1 = "#FFFFFF";
$bgcolor2 = "#FFFFFF";
######################################################################
## Begin generating frame index file.
file "index.html";
>><html>
<head>
<meta http-equiv="Content-Type" content="text/html; iso-8859-1">
<title>$project_name</title>
</head>
<frameset cols="190,*">
<frame src="master.html" name="Master Index" noresize>
<frame src="packages.html" name="Documentation">
<noframes>
<body bgcolor="$bgcolor2" stylesrc="index.html">
<p>Some Documentation</p>
</body>
</noframes>
</frameset>
</html>
<<
######################################################################
## Begin generating master index file (left-hand frame).
file "master.html";
>><html>
<head>
<title>Master Index</title>
</head>
<body bgcolor="$bgcolor1" text=#0000ff link=#0020ff vlink=#0020ff>
<center><img src="${image_directory}ScanDocSmall.jpg" border="0" /></center>
<p>
<a href="packages.html" target="Documentation">Master Index</a>
</p>
<p>
<font size="2">
<nobr>
<<
## For each package, generate an index entry.
foreach $p (packages()) {
$_ = $p->url;
s/\s/_/g;
>><a href="$_" target="Documentation"><b>$(p.name)</b></a><br>
<dir>
<<
foreach $e ($p->classes()) {
$_ = $e->url;
s/\s/_/g;
>><li><a href="$_" target="Documentation">$(e.fullname)</a>
<<
}
foreach $e ($p->globals()) {
$_ = $e->url;
s/\s/_/g;
>><li><a href="$_" target="Documentation">$(e.fullname)</a>
<<
}
>></dir><<
}
>>
<a href="to-do.html" target="Documentation"><b>To-Do List</b></a><br>
</nobr>
</font>
</p>
</body>
</html>
<<
######################################################################
## Begin generating package index file
file "packages.html";
>><html>
<head>
<title>$project_name -- Packages</title>
</head>
<body bgcolor="$bgcolor2">
<center>$company_logo
<h1>Documentation for $project_name</h1>
</center>
<h2>Package List</h2>
<<
## For each package, generate an index entry.
foreach $p (packages()) {
$_ = $p->url;
s/\s/_/g;
>><a href = "$_">$(p.name)</a><br>
<<
}
>>
<p>
<hr size=4>
$copyright<br>
Generated by <a href="$scandocURL"><b>ScanDoc $majorVersion.$minorVersion</b></a><br>
Last Updated: $date<br>
</body>
</html>
<<
######################################################################
## Generate "To-do list"
file "to-do.html";
>><html>
<head>
<title>$project_name -- To-Do list</title>
</head>
<body bgcolor="$bgcolor2">
$company_logo
<h1>To-do list for $project_name</h1>
<<
if (&todolistFiles()) {
>><hr size=4><p>
<<
foreach $f (&todolistFiles()) {
my @m = &todolistEntries( $f );
if ($f =~ /([^\/]+)$/) { $f = $1; }
>><b>$f:</b><ul>
<<
foreach $text (@m) {
if ($text) {
print "<li>", &processDescription( $text ), "\n";
}
}
>></ul>
<<
}
}
>>
<hr size=4>
$copyright<br>
Generated by <a href="$scandocURL"><b>ScanDoc $majorVersion.$minorVersion</b></a><br>
Last Updated: $date<br>
</body>
</html>
<<
######################################################################
## Generate individual files for each package.
my $p;
foreach $p (packages()) {
$_ = $p->name;
s/\s/_/g;
file $_ . ".html";
>><html>
<head>
<title>$project_name -- $(p.name)</title>
</head>
<body bgcolor="$bgcolor2">
<center>
<font size=6><b>$project_name</b></font>
<hr size=4><p>
</center>
<h2>Package Name: $(p.name)</h2>
<b>
<<
## Generate class and member index at the top of the file.
foreach $c ($p->classes()) {
$_ = $c->url;
s/\s/_/g;
>><h3><img src="$bullet1_image" width=18 height=17 align=texttop>
<a href="$_">$(c.fullname)</h3></a>
<ul>
<<
foreach $m ($c->members()) {
$_ = $m->url;
s/\s/_/g;
>><li><a href="$_">$(m.longname)</a>
<<
}
>></ul>
<<
}
>>
</b>
<<
## Generate detailed class documentation
foreach $c ($p->classes()) {
## Output searchable keyword list
if ($c->keywords()) {
print "<!-- ", $c->keywords(), " -->\n";
}
>><hr size="4">
<a name="$(c.anchor)"></a>
<h1>$(c.fullname)</h1>
<table bgcolor="ffffff" border="0" cellspacing="4">
<tr>
<th align=center colspan=2>
</th>
</tr>
<<
# Output author tag
if ($c->author()) {
>><tr><th width=20% align=right>Author:</th><<
>><td>$(c.author)</td></tr><<
}
# Output package version
if ($c->version()) {
>><tr><th width=20% align=right>Version:</th><<
>><td>$(c.version)</td></tr><<
}
# Output Source file
if ($c->sourcefile()) {
>><tr><th width=20% align=right>Source:</th><<
>><td>$(c.sourcefile)</td></tr><<
}
# Output base class list
if ($c->baseclasses()) {
>><tr><th width=20% align=right>Base classes:</th>
<td><<
my @t = ();
foreach $b ($c->baseclasses()) {
my $name = $b->name();
if ($url = $b->url()) {
$_ = $url;
s/\s/_/g;
push @t, "<a href=\"$_\">$name</a>";
}
else { push @t, $name; }
}
print join( ', ', @t );
>></td></tr>
<<
}
# Output subclasses list
if ($c->subclasses()) {
>><tr><th width=20% align=right>Subclasses:</th>
<td><<
my @t = ();
foreach $s ($c->subclasses()) {
my $name = $s->name();
if ($url = $s->url()) {
$_ = $url;
s/\s/_/g;
push @t, "<a href=\"$_\">$name</a>";
}
else { push @t, $name; }
}
print join( ', ', @t );
>></td></tr><<
}
# Output main class description
>></tr>
</table>
<p>
<<
print &processDescription( $c->description() );
# Output "see also" information
if ($c->seealso()) {
>><p><dt><b>See Also</b><dd>
<<
my @r = ();
foreach $a ($c->seealso()) {
my $name = $a->name();
if ($url = $a->url()) {
$_ = $url;
s/\s/_/g;
push @r, "<a href=\"$_\">$name</a>";
}
else { push @r, $name; }
}
print join( ',', @r );
>><p>
<<
}
# Output class member index
if ($c->members()) {
print "<h2>Member Index</h2>\n";
print "<ul>";
foreach $m ($c->members()) {
$_ = $m->url;
s/\s/_/g;
>><li><a href="$_">$(m.fullname)</a>
<<
}
>></ul><<
}
# Output class member variable documentation
if ($c->membervars()) {
print "<h2>Class Variables</h2>\n";
print "<blockquote>\n";
foreach $m ($c->membervars()) { &variable( $m ); }
print "</blockquote>\n";
}
# Output class member function documentation
if ($c->memberfuncs()) {
print "<h2>Class Methods</h2>\n";
print "<blockquote>\n";
foreach $m ($c->memberfuncs()) { &function( $m ); }
print "</blockquote>\n";
}
}
# Output global variables
if ($p->globalvars()) {
>><h2>Global Variables</h2>
<blockquote>
<<
foreach $m ($p->globalvars()) { &variable( $m ); }
print "</blockquote>\n";
}
# Output global functions
if ($p->globalfuncs()) {
>><h2>Global Functions</h2>
<blockquote>
<<
foreach $m ($p->globalfuncs()) { &function( $m ); }
print "</blockquote>\n";
}
>>
<hr size=4>
$copyright<br>
Generated by <a href="$scandocURL"><b>ScanDoc $majorVersion.$minorVersion</b></a><br>
Last Updated: $date<br>
</body>
</html>
<<
} # end of foreach (packages) loop
######################################################################
## Subroutine to generate documentation for a member function or global function
sub function {
local ($f) = @_;
if ($f->keywords()) {
>><!-- $(f.keywords) -->
<<
}
>>
<a name="$(f.anchor)"></a>
<dl>
<dt>
<b><img src="$bullet2_image" width=19 height=17 align=texttop>$(f.fullname);</b>
<dd>
<<
print &processDescription( $f->description() );
>>
<p><dl>
<<
if ($f->params()) {
>>
<dt><b>Parameters</b><dd>
<table width="85%">
<<
foreach $a ($f->params()) {
>><tr valign=top><th align=right>
$(a.name)</th><td><<
print &processDescription( $a->description() );
>></td></tr>
<<
}
>></table>
<<
}
if ($f->returnValue()) {
>><dt><b>Return Value</b>
<dd><<
print &processDescription( $f->returnValue() );
>><p><<
}
if ($f->exceptions()) {
>><dt><b>Exceptions</b><dd>
<table width=85%><tr><td colspan=2><hr size=3></td></tr>
<<
foreach $a ($f->exceptions()) {
>><tr valign=top><th align=right>
$(a.name)</th><td><<
print &processDescription( $a->description() );
>></td></tr>
<<
}
>><tr><td colspan=2><hr size=3></td></tr></table>
<<
}
if ($f->seealso()) {
>><dt><b>See Also</b><dd>
<<
my @r = ();
foreach $a ($f->seealso()) {
my $name = $a->name();
if ($url = $a->url()) {
$_ = $url;
s/\s/_/g;
push @r, "<a href=\"$_\">$name</a>";
}
else { push @r, $name; }
}
print join( ',', @r );
>><p><<
}
>></dl></dl>
<<
}
######################################################################
## Subroutine to generate documentation for a member variable or global variable.
sub variable {
local ($v) = @_;
if ($v->keywords()) {
print "<!-- $(v.keywords) -->";
}
>>
<a name="$(v.name)"></a>
<dl><dt>
<b><img src="$bullet2_image" width=19 height=17 align=texttop>$(v.fullname);</b>
<dd>
<<print &processDescription( $v->description() );>>
<p><dl>
<<
if ($v->seealso()) {
>><dt><b>See Also</b><dd>
<<
$comma = 0;
foreach $a ($v->seealso()) {
$_ = $a->url;
s/\s/_/g;
if ($comma) { print ","; }
$comma = 1;
>><a href="$_">$(a.name)</a>
<<
}
>><p>
<<
}
>></dl></dl>
<<
}
######################################################################
sub processDescription {
local ($_) = @_;
# handle HTML markup issues.
s/</</g;
s/>/>/g;
s/^\s+//; # Remove whitespace from beginning
s/\s+$/\n/; # Remove whitespace from end
s/\n\n/<p>\n/g; # Replace multiple CR's with paragraph markers
s:\@heading(.*)\n:<p><h2>$1</h2>:; # Handle heading text
# Handle embedded image tags
s:\@caution:<p><img src=\"${image_directory}/caution.gif\" align=left>:;
s:\@warning:<p><img src=\"${image_directory}/warning.gif\" align=left>:;
s:\@bug:<p><img src=\"${image_directory}/bug.gif\">:;
s:\@tip:<p><img src=\"${image_directory}/tip.gif\">:;
return $_;
}