home *** CD-ROM | disk | FTP | other *** search
- #!/usr/local/bin/perl5
-
- ###############################################################################
- ###############################################################################
- ##
- ## Written by Adam Swift (c) 1995 by Friday Software and Consulting
- ## All rights reserved.
- ##
- ## This notice may not be removed from this source code.
- ##
- ## This program is included in the MiscKit by permission from the author
- ## and its use is governed by the MiscKit license, found in the file
- ## "LICENSE.rtf" in the MiscKit distribution. Please refer to that file
- ## for a list of all applicable permissions and restrictions.
- ##
- ## Because AutoDoc is licensed free of charge, there is no warranty
- ## for the program. Copyright holder, Friday Software and Consulting,
- ## is providing this program "as is" and this program is distributed in
- ## the hope that it will be useful, but WITHOUT ANY WARRANTY; without
- ## even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- ## PARTICULAR PURPOSE.
- ##
- ###############################################################################
- ###############################################################################
-
- ##
- ## Set the required packages for normal execution
- ##
- require 5.000;
-
- ##
- ## Set this perl file's descriptive variables
- ##
- $file_name = 'autodoc';
- $file_release = '1.8.4';
-
- $file_mlist = '<autodoc@friday.com>';
- $file_copyright = 'Friday Software and Consulting, 1995';
- $file_author = 'Adam Swift <aswift@friday.com>';
- @file_contributors =
- ('Bill Bumgarner <bbum@friday.com>',
- 'Todd Anthony Nathan <todd@icebox.com>',
- 'Kim Shrier <kim@media.com>',
- 'Craig Kelley <ckelley@capaccess.org>');
-
- $file_version = '$Revision: 1.5 $'; #'
- $file_version =~ s!(\$\w+: | \$)!!g;
- $file_id = '$Id: autodoc,v 1.5 1995/10/20 22:10:41 aswift Exp $'; #'
- $file_id =~ s!(\$\w+: | \$)!!g;
-
-
- ###############################################################################
- #
- # Purpose: This script extracts comments and other data from Objective-C
- # source and header files. It processes this input to produce
- # Rich Text Formatted documentation, designed to look like the
- # NEXTSTEP developer documentation for Objective-C objects.
- #
- # HISTORY: START
- # $Log: autodoc,v $
- # Revision 1.5 1995/10/20 22:10:41 aswift
- # Completed checkin using DevMan Logs
- #
- # Revision 1.4 1995/10/20 16:45:28 aswift
- # Continuing to try DevMan Log history
- #
- # Release 1.8.4
- # - fixed "up to date documentation" testing
- # - added missing small newlines between the methods and their documentation
- # - moved tab locations in the Defined Types stuff to improve doc apperance
- # - long method lines are now broken into multiple lines
- # - added new paragraph styles to the GenerateRTF module
- #
- # Release 1.8.3
- # - completely documented GenerateRTF.pm Autodoc module
- # - abstracted DumpDocs to remove rtf dependancies
- # - fixed case insensitive argument parsing to differentiate -D from -d (bbum)
- # - cleaned up usage of 'require' and 'use' to remove redundancy (bbum)
- # - added support for documenting what protocols an object conforms to.
- # - added support for documenting protocols. (Craig Kelley)
- #
- # Release 1.8.2
- # - added version control to the support modules, and their version is now
- # reported when the -version option is used
- # - removed some warning messages in file_expandpath
- # - fixed bug preventing doc creation with .[hm] files with no object def.
- # - fixed resource naming when files are specified with no project dir
- # - fixed boldifying values of typedef-type structures
- # - allowed multiple levels of indention to follow curly braces in typedef's
- #
- # Release 1.8.1 - MiscKit Release 1.6.1
- # - fixed documentation extraction failure detection
- # - added support for AD_PMLIBDIR to specify perl module lib directory
- # - added more log debugging to Autodoc .pm files
- # - moved LogDebug::Log.pm into Autodoc::LogDebug.pm
- # - moved FileSupport::Misc.pm into Autodoc::FileSupport.pm
- #
- # Release 1.8
- # - added -nosingles option to exclude unpaired '.h' and '.m' files from docs
- # - added support for functions, typedefs, defines, macros, and globals
- # - moved all autodoc doc creation into Autodoc::DumpDocs
- # - moved all autodoc source reading into Autodoc::ReadSource
- # - moved autodoc comment parsing into Autodoc::ParseComment
- # - moved source file scanning code into Autodoc::ScanFile module
- # - added timestamping capability for documentation
- # - can now set copyright string with environment var: AD_COPYRIGHT
- # - moved debug logging into LogDebug::Log
- # - moved filepath expansion into FileSupport::Misc
- #
- # Release 1.7 - contributions by b.bum
- # - added support for GetOpts::Long package; GetOpts::Long can deal w/single
- # character argnames as long as they aren't ambiguous.
- # - removed all warnings produced by perl -w
- # - modified scan_line to discard stars from the beginning of ADC lines
- # - added -help option; shows help and exits.
- # - made a Source directory and moved code files into (as per the README)
- # - look for '## bbum'; i fixed a bunch of a stuff that produced
- # warnings when the rtf documentation did not yet exist.
- # - fixed -force so that it actually works.
- # - added NULL to list of bold words
- # - any instance variable on a line w/the word "INTERNAL" will be skipped.
- # - fixed method parameter matching to allow whitespace between the : and arg.
- # (Kim Shrier)
- # - fixed argument italicising in method docs to parse out whitespace between
- # the : and arg (Kim Shrier)
- #
- # Release 1.6
- # - added \ escaping for % and # characters to force display
- #
- # Release 1.5.1
- # - fixed the "Category Description" bug. Was putting out "Class Description"
- # (Todd Nathan)
- #
- # Release 1.5 - MiscKit Release
- # - added option to force overwriting up-to-date documentation files
- # - added time check for source and doc files to prevent unnecessary work
- # - added support for copying .rtf and .rtfd files to the doc dir
- # - added support for specifying a copyright owner on the command line
- # - fixed ivar parsing so it doesn't skip the line with the starting brace
- #
- # Release 1.4
- # - added minimal category support.
- # - changed filename to autodoc (from AutoDoc)
- # - added support for relative path naming for documentation and project dirs.
- # - fixed bug which aborted doc creation if no newline was found on @end line
- #
- # Release 1.3
- # - Added minimal support for lists of items via _{xxx desc} format
- # - Fixed matching problems at beginning and ends of text strings
- # - Added "id" to the list of bold words.
- # - Filtered out @public/@private/@protected modifiers in ivars.
- # - Fixed incorrect struct detection in ivars with curly braces in a following
- # AutoDoc comment.
- #
- # Release 1.2
- # - Started tracking changes
- #
- # HISTORY: END
- ###############################################################################
- #
- # GOBAL VARIABLES THAT HOLD OBJECT INFORMATION:
- #
- # @objects The array of objects to generate docs for
- #
- # GLOBAL VARIABLES THAT HOLD EXECUTION MODE INFORMATION
- #
- # $proj_dir The object source project directory (input)
- # $dest_dir The object documentation destination directory (output)
- # $cwd The current working directory autodoc was executed from
- # $opt_silent The console logging mode, 0 = not silent, 1 = silent
- # $opt_tree The documentation file organization, 0 = flat, 1 = tree
- # $opt_force True if doc creation should be forced when up-to-date
- # $opt_rtf True if rtf and rtfd files should be copied
- # $opt_nosingles True if unpaired '.[hm]' files are excluded from docs
- #
- # GLOBAL VARIABLES THAT AFFECT DATA EXTRACTION
- #
- # $obj_h The path and file name of the object header file
- # $obj_m The path and file name of the object source file
- #
- # GLOBAL VARIABLES THAT AFFECT DOCUMENTATION DUMP
- #
- # $obj_r The path and file name of the object documentation file
- #
- # GLOBAL VARIABLES THAT SUPPORT SPECIAL BEHAVIORS
- # $rtffiles
- #
- ##############################################################################
-
- ##############################################################################
- #
- # PROGRAM INITIALIZATION AND ARGUMENT PROCESSING
- #
- # Read in the command line arguments and configure the execution mode
- # variables appropriately. Read in the files to operate on, and begin
- # processesing source files.
- #
- ##############################################################################
-
- ##################
- # READ ARGUMENTS #
- ##################
- ## load GetOpt::Long, fix @INC, and check arguments.
- BEGIN {
- use Getopt::Long;
- $Getopt::Long::ignorecase = 0;
-
- $show_usage = "unrecognized or invalid argument"
- unless &GetOptions('lib=s@',
- 'project=s',
- 'destination=s',
- 'copyright=s',
- 'version',
- 'rtf',
- 'force',
- 'timestamp',
- 'nosingles',
- 'tree',
- 'silent',
- 'Debug:i',
- 'help'
- );
-
- unshift (@INC, @opt_lib)
- if @opt_lib;
- unshift (@INC, $ENV{'AD_PMLIBDIR'})
- if defined($ENV{'AD_PMLIBDIR'});
- }
-
- # $show_usage if GetOptions failed
- if ($show_usage) {
- usage($show_usage);
- }
-
- ##########################
- # Load Required Packages #
- ##########################
- use Cwd;
- use Autodoc::FileSupport;
- use Autodoc::LogDebug;
- use Autodoc::ScanFile;
- use Autodoc::ParseComments;
- use Autodoc::GenerateRTF;
- use Autodoc::ReadSource;
- use Autodoc::DumpDocs;
-
- ######################
- # INITIALIZE GLOBALS #
- ######################
- $proj_dir = ""; # no project directory
- $dest_dir = ""; # no destination directory
- $cwd = getcwd();
-
- dblog (2, "Current working dir: $cwd\n");
-
- ################################
- # Process Command Line Options #
- ################################
- # if -help, show usage and exit.
- if ($opt_help) {
- $opt_help += 0; # shut up perl -w
- &usage;
- }
-
- # if -version appeared on the command line, show version and exit
- if ($opt_version) {
- $opt_version += 0; # shut up perl -w
- &show_version;
- exit;
- }
-
- # -silent causes autodoc to run silently
- if ($opt_silent) {
- dblog (0, "Operating silently.");
- $opt_silent = 1;
- }
-
- # -rtf will copy rtf files
- if ($opt_rtf){
- dblog (0, "Copying documentation files found in source.");
- $opt_rtf = 1;
- }
-
- # force document creation
- if ($opt_force) {
- dblog (0, "Forcing documentation creation.");
- $opt_force = 1;
- }
-
- # build document tree
- if ($opt_tree) {
- dblog (0, "Building documentation tree.");
- $opt_tree = 1;
- }
-
- # timestamp documentation
- if ($opt_timestamp) {
- dblog (0, "Including timestamp in documentation.");
- set_usetimestamp($opt_timestamp);
- }
-
- # exclude unpaired source files from documentation
- if ($opt_nosingles) {
- dblog (0, "Excluding unmatched source files from documentation");
- $opt_nosingles += 0;
- }
-
- # set copyright notice
- if ($opt_copyright) {
- set_copyrightowner($opt_copyright);
- dblog (0, "Setting copyright owner: ", copyrightowner());
- } else {
- if (grep (m!AD_COPYRIGHT!, keys (%ENV))) {
- set_copyrightowner($ENV{'AD_COPYRIGHT'});
- dblog (0, "Setting copyright owner: ", copyrightowner());
- }
- }
-
- # set project directory
- if ($opt_project) {
- $proj_dir = &file_expandpath ($opt_project);
-
- # if there isn't a trailing "/", append it
- $proj_dir = "$proj_dir/" if (!($proj_dir =~ m!/$!));
- dblog (0, "Project directory: $proj_dir");
- }
-
- # destination directory specified
- if ($opt_destination) {
- $dest_dir = &file_expandpath ($opt_destination);
-
- # if there isn't a trailing "/", append it
- $dest_dir = "$dest_dir/" if (!($dest_dir =~ m/\/$/));
- dblog (0, "Destination directory: $dest_dir");
- }
-
- # set debugging level
- if ($opt_Debug) {
- &set_dblog_debuglevel($opt_Debug);
- dblog (0, "Debug level: $opt_Debug.");
- }
-
- foreach (@ARGV) {
- # strip of the .h or .m from the object source name
- s/\.[hm]$//;
-
- $path = &file_expandpath ($_);
-
- # if it's root name isn't already in the list, then add it.
- if (!(grep (/$path/, @objects))) {
- push (@objects, $path);
- } else {
- dblog (1, "Source file specified twice: $path.");
- }
- }
-
- &check_inputfiles;
-
-
- ###############################################################################
- #
- # MAIN PROGRAM OPERATION LOOP
- #
- ###############################################################################
- MAINLOOP: # Main operating loop
- foreach $currobject (@objects) {
-
- # prepare the object (h,m,rtf) file paths
- &set_obj_filepaths ($currobject);
-
- # check for a .mdoc file (used for documenting protocols)
- if ((!(-e $obj_m))) {
- $obj_mdoc = "${obj_m}doc";
- if ((-e $obj_mdoc)) {
- $obj_m = $obj_mdoc;
- }
- }
-
- $obj_m = ""
- if ((!$opt_nosingles) && (!(-e $obj_m)));
-
- # check whether the doc file exists and is up to date
- if ((-r $obj_h) && (($obj_m eq "") || (-r $obj_m))) {
-
- $docs_expired = 0;
- $docs_expired = 1
- if (file_findnewest($obj_h, $obj_m, $obj_r) ne $obj_r);
-
- unless ($opt_force || $docs_expired || !(-r $obj_r)) {
- # Documentation file is up to date, skip this object
- print "autodoc documentation up to date for $currobject.\n"
- if (!$opt_silent);
- next MAINLOOP;
- }
- } else {
- warn ("Data extraction failed for $currobject, ",
- "could not read source files.\n");
- next MAINLOOP;
- }
-
- # read object info and try to generate doc's
- if (&read_objectinfo ($currobject, $obj_h, $obj_m)) {
-
- # Make any directories necessary for the docs...
- if (($obj_r =~ m/\//) && (!&make_docdir ($obj_r))) {
- warn ("Could not write to documentation directory for: ",
- "$obj_r\n");
- return 0;
- } else {
- if (dump_documentation ($currobject, $obj_r, $opt_silent)) {
- &dblog (0, "Completed processing for object:\t",
- $currobject);
- } else {
- warn ("Documentation file dump failed for ",
- "$currobject.\n");
- }
- }
- } else {
- if ($obj_m ne "") {
- warn ("Data extraction failed for $currobject, ",
- "no documentation file generated.\n");
- } else {
- dblog (0, "Data extraction failed for $currobject, ",
- "no documentation file generated.\n");
- }
- }
- }
- # End MAINLOOP
-
- COPYLOOP: # Copy loop for rtf files
- foreach $rtffile (@rtffiles) {
-
- &set_rtf_filepaths ($rtffile);
-
- # Check if the source file is readable
- if (!(-r $rtf_src)) {
- warn ("Documentation copy failed for: $rtffile, ",
- "Could not read file.\n");
- next COPYLOOP;
- }
-
- $docs_expired = 1
- if (file_findnewest($rtf_src, $rtf_dest) eq $rtf_src);
-
- # Check if it is up to date
- unless ($opt_force || $docs_expired || !(-r $rtf_dest)) {
- print "autodoc documentation up to date for $rtffile.\n"
- if (!$opt_silent);
- next COPYLOOP;
- }
-
- # Make any directories necessary...
- if ($rtf_dest =~ m/\//) {
- if (!&make_docdir ($rtf_dest)) {
- warn ("Could not write to documentation directory for: ",
- "$rtf_dest\n");
- next COPYLOOP;
- }
- }
- print "autodoc copying $rtffile to $rtf_dest."
- if (!$opt_silent);
- # open (CP, "cd $cwd; cp -r $rtf_src $rtf_dest |"); Why?
- system "cd $cwd; cp -r $rtf_src $rtf_dest";
- }
- # End COPYLOOP
-
-
-
- ###############################################################################
- #
- # EXECUTION CONTROL AND GENERAL SUPPORT SUBROUTINES
- #
- # Execution mode configuration from command line switches, and
- # preprocessing of input files and paths.
- #
- ###############################################################################
-
- #
- # Create all of the directories necessary for the documentation file specified
- #
- sub make_docdir
- {
- local ($docfile, $docdir, $partdir, @alldirs, $dir, $lastdir);
- $docfile = $_[0];
-
- $docdir = $docfile;
- $docdir =~ s/\/[^\/]+$//;
-
- if (-e $docdir) {
- if (-d $docdir) {
- if (-w $docdir) {
- return 1; # the directory exists, and is writable
- } else {
- warn ("Cannot write to directory: $docdir");
- }
- warn ("Directory would replace file: $docdir");
- }
- return 0;
- }
- dblog (1, "Need to create documentation directory: $docdir");
-
- if ($docdir =~ m/^[^\/\.]/) {
- $docdir = "./$docdir";
- }
-
- @alldirs = split (/\//, $docdir);
-
- MKDIRS:
- foreach $dir (@alldirs) {
- if (!$lastdir) {
- if (!$dir) {
- $lastdir = "/";
- next MKDIRS;
- }
- $lastdir = "$dir";
- $partdir = "$dir";
- next MKDIRS;
- }
-
- $partdir .= "/$dir";
- if (!(-e $partdir)) {
- if (-d $lastdir) {
- if (-w $lastdir) {
- print "autodoc creating $partdir ... " if (!$opt_silent);
- if (mkdir ("$partdir", oct (755))) {
- print "done\n" if (!$opt_silent);
- dblog (2, "Made directory $partdir, with mode 755");
- } else {
- print "failed!\n" if (!$opt_silent);
- warn ("Could not make directory: $partdir");
- return 0;
- }
- } else {
- warn ("Cannot write to directory: $lastdir ",
- "Can not create directory: $partdir");
- return 0;
- }
- } else {
- warn ("Directory would replace file: $lastdir ",
- "Can not create directory: $partdir");
- return 0;
- }
- }
- $lastdir = "$partdir";
- }
-
- return 1;
- }
-
-
-
- #
- # Check if we have valid object files or a project directory, create the
- # list of object source files if none are specified.
- #
- sub check_inputfiles
- {
- dblog(2, "Checking input files");
-
- # check if the project directory is valid
- if ($proj_dir ne "") {
- if (!(-r $proj_dir)) {
- die ("The project directory {$proj_dir} specified "
- ."is not readable.\nDied");
- }
- if (!(-d $proj_dir)) {
- die ("The project directory specified is not a directory.\nDied");
- }
- }
-
- if (scalar(@objects) == 0) {
- if ($proj_dir ne "") {
- &find_objectfiles;
- }
- }
-
- dblog (1, "Auto-documenting objects: (@objects)");
-
- if (($proj_dir ne "") && ($opt_rtf)) {
- &find_rtffiles;
- }
-
- dblog (1, "Copying documentation files: (@rtffiles)");
-
- if ((scalar(@objects) == 0) && ($proj_dir eq "")) {
- &usage ("No source files or project directory specified.");
- }
-
- }
-
-
- #
- # Use find to recursively scan the project directory for object source files
- # then file @objects with all of the matched pairs of .h and .m files from
- # the project directory
- #
- sub find_objectfiles
- {
- local (@projfiles, $pfile, $find_proj_dir);
-
- dblog (0, "Scanning project directory for object source files.");
-
- $find_proj_dir = $proj_dir; # This is lame ... I'm just removing
- $find_proj_dir =~ s/\/$//; # the trailing '/' from the file path
-
- open (FIND, "cd $cwd; find $find_proj_dir -name '*.[hm]' -print |");
- while (<FIND>) {
- chop;
- s/$proj_dir//;
- s/.[hm]$//;
- push (@projfiles, $_);
- }
- @projfiles = sort @projfiles;
-
- while (@projfiles) {
- $pfile = shift (@projfiles);
- if (defined($pfile)) {
- if (defined($projfiles[0]) && ($pfile eq $projfiles[0])) {
- # there must have been both a .h and a .m with the same root
- # since the only file names in @projfiles end in .h or .m
- # the test to see if it is an object file is based on this.
- push (@objects, $pfile);
- shift (@projfiles);
- } else {
- # there is only one file with the .h or .m extension, if
- # the option to disallow singles is not set, we add it
- push (@objects, $pfile)
- if (!$opt_nosingles);
- }
- }
- }
- }
-
-
- #
- # Use find to recursively scan the project directory for 'rtf' and 'rtfd'
- # files. Store the files to the array rtffiles
- #
- sub find_rtffiles
- {
- local ($pfile, $find_proj_dir);
-
- dblog (0, "Scanning project directory for rtf/rtfd files.");
-
- $find_proj_dir = $proj_dir; # This is lame ... I'm just removing
- $find_proj_dir =~ s/\/$//; # the trailing '/' from the file path
-
- open (FIND, "cd $cwd; find $find_proj_dir \\( -name '*.rtf' -o -name '*.rtfd' \\) -print |");
- while (<FIND>) {
- chop;
- s/$proj_dir//;
- push (@rtffiles, $_);
- }
- @rtffiles = sort @rtffiles;
-
- }
-
-
- #
- # generate the $obj_h, $obj_m and $obj_rtf file path variables.
- #
- sub set_obj_filepaths
- {
- local ($obj_root) = $_[0];
-
- $obj_h = "${proj_dir}${obj_root}.h";
- $obj_m = "${proj_dir}${obj_root}.m";
-
- if ($opt_tree) {
- $obj_r = $obj_root; # if the obj_root is in a subdirectory
- # remove any file extension on the
- # subdirectory name.
- $obj_r =~ s/\.[^\.]+\//\//g;
- } else {
- if ($obj_root =~ m!/([^/]+)$!) {
- $obj_r = $1;
- } else {
- $obj_r = $obj_root;
- }
- }
- $obj_r = "$dest_dir$obj_r.rtf";
- dblog(2, "Destination file set to: $obj_r");
- }
-
- #
- # Generate the $rtf_src and $rtf_dest file path variables
- #
- sub set_rtf_filepaths
- {
- local ($rtf_root) = $_[0];
-
- # prepare the rtf source and dest file path
- $rtf_src = "${proj_dir}${rtf_root}";
-
- if ($opt_tree) {
- $rtf_dest = $rtf_root;
-
- # If the rtf_root is in a subdirectory
- # remove any file extension on the subdirectory name.
- $rtf_dest =~ s/\.[^\.]+\//\//g;
- } else {
- if ($rtf_root =~ m!/([^/]+)$!) {
- $rtf_dest =~ $1;
- } else {
- $rtf_dest = $rtf_root;
- }
- }
- $rtf_dest = "$dest_dir$rtf_dest";
- }
-
- sub usage {
- $error_fmt = shift;
-
- select(STDERR);
-
- printf "$file_name: $error_fmt\n", @_
- if $error_fmt;
-
- print <<_ENDOFUSAGE_;
- Usage: $file_name [-force] [-rtf] [-tree] [-nosingles] [-timestamp]
- [-help] [-version] [-silent] [-Debug [#]]
- [-copyright "Copyright String"] [-destination "dest path"]
- [-project "project directory"] [ sourcefiles ...]
-
- -force Force document creation for up to date files.
- -rtf Copy rtf and rtfd files fount in project tree.
- -tree Create a tree of documentation files.
- -nosingles Exclude unpaired ".h" and ".m" files from documentation
- -timestamp Insert a timestamp into the documentation
- -help Show this help and exit.
- -version Show AutoDoc version/copyright and exit.
- -silent Operate silently; do not generate log entries.
- -Debug [#] Set debugging level to #; 0 (default) is least, 5 is most.
- -copyright "..." Set copyrightowner in the copyright line to "...".
- -destination ".." Create documentation files in directory "..".
- -project "..." Look for source files in the directory "...".
- _ENDOFUSAGE_
- exit(1);
- }
-
- #
- # Show version and copyright information
- #
- sub show_version
- {
- local (@module_versions);
-
- @module_versions = (Autodoc::FileSupport::module_versionstamp(),
- Autodoc::LogDebug::module_versionstamp(),
- Autodoc::ScanFile::module_versionstamp(),
- Autodoc::ReadSource::module_versionstamp(),
- Autodoc::ParseComments::module_versionstamp(),
- Autodoc::DumpDocs::module_versionstamp(),
- Autodoc::GenerateRTF::module_versionstamp());
-
- print "This is $file_name Release $file_release (rev-$file_version)\n";
- print "Module versions:\n\t", join ("\n\t", @module_versions), "\n";
- print "Written by $file_author\n";
- print "Copyright $file_copyright - All Rights Reserved\n";
- print "Please send bugs and suggestions to:$file_mlist\n";
- print "Contributions by:\n\t";
- print join("\n\t", @file_contributors), "\n"
- if scalar(@file_contributors);
- exit(0);
- }
-