home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Examples / AutoDoc / bin / autodoc
Encoding:
Text File  |  1995-11-02  |  22.5 KB  |  766 lines

  1. #!/usr/local/bin/perl5
  2.  
  3. ###############################################################################
  4. ###############################################################################
  5. ##
  6. ##    Written by Adam Swift (c) 1995 by Friday Software and Consulting
  7. ##                           All rights reserved.
  8. ##
  9. ##      This notice may not be removed from this source code.
  10. ##
  11. ##    This program is included in the MiscKit by permission from the author
  12. ##    and its use is governed by the MiscKit license, found in the file
  13. ##    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  14. ##    for a list of all applicable permissions and restrictions.
  15. ##
  16. ##    Because AutoDoc is licensed free of charge, there is no warranty 
  17. ##    for the program.  Copyright holder, Friday Software and Consulting, 
  18. ##    is providing this program "as is" and this program is distributed in 
  19. ##    the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
  20. ##    even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
  21. ##    PARTICULAR PURPOSE.
  22. ##
  23. ###############################################################################
  24. ###############################################################################
  25.  
  26. ##
  27. ## Set the required packages for normal execution 
  28. ##
  29. require 5.000;
  30.  
  31. ##
  32. ## Set this perl file's descriptive variables
  33. ##
  34. $file_name           = 'autodoc';
  35. $file_release       = '1.8.4';
  36.  
  37. $file_mlist    = '<autodoc@friday.com>';
  38. $file_copyright       = 'Friday Software and Consulting, 1995';
  39. $file_author       = 'Adam Swift <aswift@friday.com>';
  40. @file_contributors = 
  41.   ('Bill Bumgarner <bbum@friday.com>',
  42.    'Todd Anthony Nathan <todd@icebox.com>',
  43.    'Kim Shrier <kim@media.com>',
  44.    'Craig Kelley <ckelley@capaccess.org>');
  45.  
  46. $file_version       = '$Revision: 1.5 $'; #'
  47. $file_version       =~ s!(\$\w+: | \$)!!g; 
  48. $file_id           = '$Id: autodoc,v 1.5 1995/10/20 22:10:41 aswift Exp $'; #'
  49. $file_id           =~ s!(\$\w+: | \$)!!g;
  50.  
  51.  
  52. ###############################################################################
  53. #
  54. # Purpose:    This script extracts comments and other data from Objective-C 
  55. #         source and header files.  It processes this input to produce 
  56. #        Rich Text Formatted documentation, designed to look like the 
  57. #        NEXTSTEP developer documentation for Objective-C objects.
  58. #
  59. # HISTORY: START
  60. # $Log: autodoc,v $
  61. # Revision 1.5  1995/10/20  22:10:41  aswift
  62. # Completed checkin using DevMan Logs
  63. #
  64. # Revision 1.4  1995/10/20  16:45:28  aswift
  65. # Continuing to try DevMan Log history
  66. #
  67. # Release 1.8.4
  68. # - fixed "up to date documentation" testing 
  69. # - added missing small newlines between the methods and their documentation
  70. # - moved tab locations in the Defined Types stuff to improve doc apperance
  71. # - long method lines are now broken into multiple lines
  72. # - added new paragraph styles to the GenerateRTF module
  73. #
  74. # Release 1.8.3
  75. # - completely documented GenerateRTF.pm Autodoc module
  76. # - abstracted DumpDocs to remove rtf dependancies
  77. # - fixed case insensitive argument parsing to differentiate -D from -d (bbum)
  78. # - cleaned up usage of 'require' and 'use' to remove redundancy (bbum)
  79. # - added support for documenting what protocols an object conforms to.
  80. # - added support for documenting protocols. (Craig Kelley)
  81. # Release 1.8.2
  82. # - added version control to the support modules, and their version is now
  83. #    reported when the -version option is used
  84. # - removed some warning messages in file_expandpath
  85. # - fixed bug preventing doc creation with .[hm] files with no object def.
  86. # - fixed resource naming when files are specified with no project dir
  87. # - fixed boldifying values of typedef-type structures
  88. # - allowed multiple levels of indention to follow curly braces in typedef's
  89. #
  90. # Release 1.8.1 - MiscKit Release 1.6.1
  91. # - fixed documentation extraction failure detection
  92. # - added support for AD_PMLIBDIR to specify perl module lib directory
  93. # - added more log debugging to Autodoc .pm files
  94. # - moved LogDebug::Log.pm into Autodoc::LogDebug.pm
  95. # - moved FileSupport::Misc.pm into Autodoc::FileSupport.pm
  96. #
  97. # Release 1.8
  98. # - added -nosingles option to exclude unpaired '.h' and '.m' files from docs
  99. # - added support for functions, typedefs, defines, macros, and globals
  100. # - moved all autodoc doc creation into Autodoc::DumpDocs
  101. # - moved all autodoc source reading into Autodoc::ReadSource
  102. # - moved autodoc comment parsing into Autodoc::ParseComment
  103. # - moved source file scanning code into Autodoc::ScanFile module
  104. # - added timestamping capability for documentation
  105. # - can now set copyright string with environment var: AD_COPYRIGHT
  106. # - moved debug logging into LogDebug::Log
  107. # - moved filepath expansion into FileSupport::Misc
  108. #
  109. # Release 1.7 - contributions by b.bum
  110. # - added support for GetOpts::Long package; GetOpts::Long can deal w/single 
  111. #   character argnames as long as they aren't ambiguous.
  112. # - removed all warnings produced by perl -w
  113. # - modified scan_line to discard stars from the beginning of ADC lines
  114. # - added -help option;  shows help and exits.
  115. # - made a Source directory and moved code files into (as per the README)
  116. # - look for '## bbum';  i fixed a bunch of a stuff that produced
  117. #   warnings when the rtf documentation did not yet exist.
  118. # - fixed -force so that it actually works.
  119. # - added NULL to list of bold words
  120. # - any instance variable on a line w/the word "INTERNAL" will be skipped.
  121. # - fixed method parameter matching to allow whitespace between the : and arg.
  122. #   (Kim Shrier)
  123. # - fixed argument italicising in method docs to parse out whitespace between 
  124. #   the : and arg (Kim Shrier)
  125. #
  126. # Release 1.6
  127. # - added \ escaping for % and # characters to force display 
  128. #
  129. # Release 1.5.1
  130. # - fixed the "Category Description" bug.  Was putting out "Class Description"
  131. #   (Todd Nathan)
  132. #
  133. # Release 1.5 - MiscKit Release
  134. # - added option to force overwriting up-to-date documentation files
  135. # - added time check for source and doc files to prevent unnecessary work
  136. # - added support for copying .rtf and .rtfd files to the doc dir
  137. # - added support for specifying a copyright owner on the command line
  138. # - fixed ivar parsing so it doesn't skip the line with the starting brace
  139. #
  140. # Release 1.4
  141. # - added minimal category support.
  142. # - changed filename to autodoc (from AutoDoc)
  143. # - added support for relative path naming for documentation and project dirs.
  144. # - fixed bug which aborted doc creation if no newline was found on @end line
  145. # Release 1.3
  146. # - Added minimal support for lists of items via _{xxx desc} format
  147. # - Fixed matching problems at beginning and ends of text strings
  148. # - Added "id" to the list of bold words.
  149. # - Filtered out @public/@private/@protected modifiers in ivars.
  150. # - Fixed incorrect struct detection in ivars with curly braces in a following
  151. #   AutoDoc comment.
  152. #
  153. # Release 1.2
  154. # - Started tracking changes
  155. #
  156. # HISTORY: END
  157. ###############################################################################
  158. #
  159. # GOBAL VARIABLES THAT HOLD OBJECT INFORMATION:
  160. #
  161. #  @objects             The array of objects to generate docs for
  162. #
  163. # GLOBAL VARIABLES THAT HOLD EXECUTION MODE INFORMATION
  164. #
  165. #  $proj_dir        The object source project directory (input)
  166. #  $dest_dir        The object documentation destination directory (output)
  167. #  $cwd                 The current working directory autodoc was executed from
  168. #  $opt_silent        The console logging mode, 0 = not silent, 1 = silent
  169. #  $opt_tree            The documentation file organization, 0 = flat, 1 = tree
  170. #  $opt_force           True if doc creation should be forced when up-to-date
  171. #  $opt_rtf             True if rtf and rtfd files should be copied 
  172. #  $opt_nosingles       True if unpaired '.[hm]' files are excluded from docs 
  173. # GLOBAL VARIABLES THAT AFFECT DATA EXTRACTION
  174. #
  175. #  $obj_h               The path and file name of the object header file
  176. #  $obj_m               The path and file name of the object source file
  177. #
  178. # GLOBAL VARIABLES THAT AFFECT DOCUMENTATION DUMP
  179. #
  180. #  $obj_r               The path and file name of the object documentation file
  181. #
  182. # GLOBAL VARIABLES THAT SUPPORT SPECIAL BEHAVIORS
  183. #  $rtffiles
  184. #
  185. ##############################################################################
  186.  
  187. ##############################################################################
  188. #
  189. # PROGRAM INITIALIZATION AND ARGUMENT PROCESSING
  190. #
  191. #    Read in the command line arguments and configure the execution mode 
  192. #  variables appropriately.  Read in the files to operate on, and begin 
  193. #  processesing source files.
  194. #
  195. ##############################################################################
  196.  
  197. ##################
  198. # READ ARGUMENTS #
  199. ##################
  200. ## load GetOpt::Long, fix @INC, and check arguments.
  201. BEGIN {
  202.   use Getopt::Long;
  203.   $Getopt::Long::ignorecase = 0;
  204.  
  205.   $show_usage = "unrecognized or invalid argument"
  206.     unless &GetOptions('lib=s@',
  207.                        'project=s',
  208.                        'destination=s',
  209.                        'copyright=s',
  210.                        'version',
  211.                        'rtf',
  212.                        'force',
  213.                        'timestamp',
  214.                        'nosingles',
  215.                        'tree',
  216.                        'silent',
  217.                        'Debug:i',
  218.                        'help'
  219.                       );
  220.   
  221.   unshift (@INC, @opt_lib)
  222.     if @opt_lib;
  223.   unshift (@INC, $ENV{'AD_PMLIBDIR'})
  224.     if defined($ENV{'AD_PMLIBDIR'});
  225. }
  226.  
  227. #  $show_usage if GetOptions failed
  228. if ($show_usage) {
  229.   usage($show_usage);
  230. }
  231.  
  232. ##########################
  233. # Load Required Packages #
  234. ##########################
  235. use Cwd;
  236. use Autodoc::FileSupport;
  237. use Autodoc::LogDebug;
  238. use Autodoc::ScanFile;
  239. use Autodoc::ParseComments;
  240. use Autodoc::GenerateRTF;
  241. use Autodoc::ReadSource;
  242. use Autodoc::DumpDocs;
  243.  
  244. ######################
  245. # INITIALIZE GLOBALS #
  246. ######################
  247. $proj_dir    = "";        # no project directory
  248. $dest_dir    = "";        # no destination directory
  249. $cwd         = getcwd();
  250.  
  251. dblog (2, "Current working dir: $cwd\n");
  252.  
  253. ################################
  254. # Process Command Line Options #
  255. ################################
  256. # if -help, show usage and exit.
  257. if ($opt_help) {
  258.   $opt_help += 0; # shut up perl -w
  259.   &usage;
  260. }
  261.  
  262. # if -version appeared on the command line, show version and exit
  263. if ($opt_version) {
  264.   $opt_version += 0; # shut up perl -w
  265.   &show_version;
  266.   exit;
  267. }
  268.  
  269. # -silent causes autodoc to run silently
  270. if ($opt_silent) {
  271.   dblog (0, "Operating silently.");
  272.   $opt_silent = 1;
  273. }
  274.  
  275. # -rtf will copy rtf files
  276. if ($opt_rtf){
  277.   dblog (0, "Copying documentation files found in source.");
  278.   $opt_rtf = 1;
  279. }
  280.  
  281. # force document creation
  282. if ($opt_force) {
  283.     dblog (0, "Forcing documentation creation.");
  284.     $opt_force = 1;
  285. }
  286.  
  287. # build document tree
  288. if ($opt_tree) {
  289.   dblog (0, "Building documentation tree.");
  290.   $opt_tree = 1;
  291. }
  292.  
  293. # timestamp documentation
  294. if ($opt_timestamp) {
  295.   dblog (0, "Including timestamp in documentation.");
  296.   set_usetimestamp($opt_timestamp);
  297. }
  298.  
  299. # exclude unpaired source files from documentation
  300. if ($opt_nosingles) {
  301.   dblog (0, "Excluding unmatched source files from documentation");
  302.   $opt_nosingles += 0;
  303. }
  304.  
  305. # set copyright notice
  306. if ($opt_copyright) {
  307.   set_copyrightowner($opt_copyright);
  308.   dblog (0, "Setting copyright owner: ", copyrightowner());
  309. } else {
  310.   if (grep (m!AD_COPYRIGHT!, keys (%ENV))) {
  311.     set_copyrightowner($ENV{'AD_COPYRIGHT'});
  312.     dblog (0, "Setting copyright owner: ", copyrightowner());
  313.   }
  314. }
  315.  
  316. # set project directory
  317. if ($opt_project) {
  318.   $proj_dir = &file_expandpath ($opt_project);
  319.   
  320.   # if there isn't a trailing "/", append it
  321.   $proj_dir = "$proj_dir/" if (!($proj_dir =~ m!/$!));
  322.   dblog (0, "Project directory: $proj_dir");
  323. }
  324.  
  325. # destination directory specified
  326. if ($opt_destination) {
  327.   $dest_dir = &file_expandpath ($opt_destination);
  328.   
  329.   # if there isn't a trailing "/", append it
  330.   $dest_dir = "$dest_dir/" if (!($dest_dir =~ m/\/$/));
  331.   dblog (0, "Destination directory: $dest_dir");
  332. }
  333.  
  334. # set debugging level
  335. if ($opt_Debug) {
  336.   &set_dblog_debuglevel($opt_Debug);
  337.   dblog (0, "Debug level: $opt_Debug.");
  338. }
  339.  
  340. foreach (@ARGV) {
  341.   # strip of the .h or .m from the object source name
  342.   s/\.[hm]$//;
  343.   
  344.   $path = &file_expandpath ($_);
  345.   
  346.   # if it's root name isn't already in the list, then add it.
  347.   if (!(grep (/$path/, @objects))) {
  348.     push (@objects, $path);
  349.   } else {
  350.     dblog (1, "Source file specified twice: $path.");
  351.   }
  352. }
  353.  
  354. &check_inputfiles;
  355.  
  356.  
  357. ###############################################################################
  358. # MAIN PROGRAM OPERATION LOOP
  359. ###############################################################################
  360. MAINLOOP:                        # Main operating loop
  361.   foreach $currobject (@objects) {
  362.     
  363.     # prepare the object (h,m,rtf) file paths
  364.     &set_obj_filepaths ($currobject); 
  365.     
  366.     # check for a .mdoc file (used for documenting protocols)
  367.     if ((!(-e $obj_m))) {
  368.       $obj_mdoc = "${obj_m}doc";
  369.       if ((-e $obj_mdoc)) {
  370.         $obj_m = $obj_mdoc;
  371.       }
  372.     }
  373.     
  374.     $obj_m = ""
  375.       if ((!$opt_nosingles) && (!(-e $obj_m)));
  376.     
  377.     # check whether the doc file exists and is up to date
  378.     if ((-r $obj_h) && (($obj_m eq "") || (-r $obj_m))) {
  379.       
  380.       $docs_expired = 0;
  381.       $docs_expired = 1
  382.         if (file_findnewest($obj_h, $obj_m, $obj_r) ne $obj_r);
  383.       
  384.       unless ($opt_force || $docs_expired || !(-r $obj_r)) {
  385.         # Documentation file is up to date, skip this object
  386.         print "autodoc documentation up to date for $currobject.\n" 
  387.           if (!$opt_silent);
  388.         next MAINLOOP;
  389.       } 
  390.     } else {
  391.       warn ("Data extraction failed for $currobject, ",
  392.             "could not read source files.\n");
  393.       next MAINLOOP;
  394.     }
  395.     
  396.     # read object info and try to generate doc's
  397.     if (&read_objectinfo ($currobject, $obj_h, $obj_m)) {
  398.       
  399.       # Make any directories necessary for the docs...
  400.       if (($obj_r =~ m/\//) && (!&make_docdir ($obj_r))) {
  401.         warn ("Could not write to documentation directory for: ",
  402.               "$obj_r\n");
  403.         return 0;
  404.       } else {
  405.         if (dump_documentation ($currobject, $obj_r, $opt_silent)) {
  406.           &dblog (0, "Completed processing for object:\t",
  407.                   $currobject);
  408.         } else {
  409.           warn ("Documentation file dump failed for ",
  410.                 "$currobject.\n");
  411.         }
  412.       }
  413.     } else {
  414.       if ($obj_m ne "") {
  415.         warn ("Data extraction failed for $currobject, ",
  416.               "no documentation file generated.\n");
  417.       } else {
  418.         dblog (0, "Data extraction failed for $currobject, ",
  419.                "no documentation file generated.\n");
  420.       }
  421.     }
  422.   }
  423. # End MAINLOOP
  424.  
  425. COPYLOOP:                        # Copy loop for rtf files
  426.   foreach $rtffile (@rtffiles) {
  427.     
  428.     &set_rtf_filepaths ($rtffile);
  429.     
  430.     # Check if the source file is readable
  431.     if (!(-r $rtf_src)) {
  432.       warn ("Documentation copy failed for: $rtffile, ",
  433.             "Could not read file.\n");
  434.       next COPYLOOP;
  435.     }
  436.     
  437.     $docs_expired = 1
  438.       if (file_findnewest($rtf_src, $rtf_dest) eq $rtf_src);
  439.     
  440.     # Check if it is up to date
  441.     unless ($opt_force || $docs_expired || !(-r $rtf_dest)) {
  442.       print "autodoc documentation up to date for $rtffile.\n" 
  443.         if (!$opt_silent);
  444.       next COPYLOOP;
  445.     }
  446.     
  447.     # Make any directories necessary...
  448.     if ($rtf_dest =~ m/\//) {
  449.       if (!&make_docdir ($rtf_dest)) {
  450.         warn ("Could not write to documentation directory for: ",
  451.               "$rtf_dest\n");
  452.         next COPYLOOP;
  453.       }
  454.     }
  455.     print "autodoc copying $rtffile to $rtf_dest." 
  456.       if (!$opt_silent);
  457.     #    open (CP, "cd $cwd; cp -r $rtf_src $rtf_dest |");  Why?
  458.     system "cd $cwd; cp -r $rtf_src $rtf_dest";
  459.   }
  460. # End COPYLOOP
  461.  
  462.  
  463.  
  464. ###############################################################################
  465. # EXECUTION CONTROL AND GENERAL SUPPORT SUBROUTINES
  466. #
  467. #    Execution mode configuration from command line switches, and 
  468. #  preprocessing of input files and paths.  
  469. #
  470. ###############################################################################
  471.  
  472. #
  473. # Create all of the directories necessary for the documentation file specified
  474. #
  475. sub make_docdir
  476.   {
  477.     local ($docfile, $docdir, $partdir, @alldirs, $dir, $lastdir);
  478.     $docfile = $_[0];
  479.     
  480.     $docdir = $docfile;
  481.     $docdir =~ s/\/[^\/]+$//;
  482.     
  483.     if (-e $docdir) {
  484.       if (-d $docdir) {
  485.         if (-w $docdir) {
  486.           return 1;                # the directory exists, and is writable
  487.         } else {
  488.           warn ("Cannot write to directory: $docdir");
  489.         }
  490.         warn ("Directory would replace file: $docdir");
  491.       }
  492.       return 0;
  493.     } 
  494.     dblog (1, "Need to create documentation directory: $docdir");
  495.     
  496.     if ($docdir =~ m/^[^\/\.]/) {
  497.       $docdir = "./$docdir";
  498.     }
  499.     
  500.     @alldirs = split (/\//, $docdir);
  501.     
  502.   MKDIRS:
  503.     foreach $dir (@alldirs) {
  504.       if (!$lastdir) {
  505.         if (!$dir) {
  506.           $lastdir = "/";
  507.           next MKDIRS;
  508.         }
  509.         $lastdir = "$dir";
  510.         $partdir = "$dir";
  511.         next MKDIRS;
  512.       } 
  513.       
  514.       $partdir .= "/$dir";
  515.       if (!(-e $partdir)) {
  516.         if (-d $lastdir) {
  517.           if (-w $lastdir) {
  518.             print "autodoc creating $partdir ... " if (!$opt_silent);
  519.             if (mkdir ("$partdir", oct (755))) {
  520.               print "done\n" if (!$opt_silent);
  521.               dblog (2, "Made directory $partdir, with mode 755");
  522.             } else {
  523.               print "failed!\n" if (!$opt_silent);
  524.               warn ("Could not make directory: $partdir");
  525.               return 0;
  526.             } 
  527.           } else {
  528.             warn ("Cannot write to directory: $lastdir  ",
  529.                   "Can not create directory: $partdir");
  530.             return 0;
  531.           }
  532.         } else {
  533.           warn ("Directory would replace file: $lastdir  ",
  534.                 "Can not create directory: $partdir");
  535.           return 0;
  536.         }
  537.       }
  538.       $lastdir = "$partdir";
  539.     }
  540.  
  541.     return 1;
  542.   }
  543.  
  544.  
  545.  
  546. #
  547. # Check if we have valid object files or a project directory, create the 
  548. # list of object source files if none are specified.
  549. #
  550. sub check_inputfiles
  551.   {
  552.     dblog(2, "Checking input files");
  553.     
  554.     # check if the project directory is valid
  555.     if ($proj_dir ne "") {
  556.       if (!(-r $proj_dir)) {
  557.         die ("The project directory {$proj_dir} specified "
  558.              ."is not readable.\nDied");
  559.       }
  560.       if (!(-d $proj_dir)) {
  561.         die ("The project directory specified is not a directory.\nDied");
  562.       }
  563.     }
  564.     
  565.     if (scalar(@objects) == 0) {
  566.       if ($proj_dir ne "") {
  567.         &find_objectfiles;
  568.       }
  569.     }
  570.     
  571.     dblog (1, "Auto-documenting objects: (@objects)");
  572.     
  573.     if (($proj_dir ne "") && ($opt_rtf)) {
  574.       &find_rtffiles;
  575.     }
  576.     
  577.     dblog (1, "Copying documentation files: (@rtffiles)");
  578.     
  579.     if ((scalar(@objects) == 0) && ($proj_dir eq "")) {
  580.       &usage ("No source files or project directory specified.");
  581.     }
  582.  
  583. }
  584.  
  585.  
  586. #
  587. # Use find to recursively scan the project directory for object source files
  588. # then file @objects with all of the matched pairs of .h and .m files from 
  589. # the project directory
  590. #
  591. sub find_objectfiles
  592.   {
  593.     local (@projfiles, $pfile, $find_proj_dir);
  594.     
  595.     dblog (0, "Scanning project directory for object source files.");
  596.     
  597.     $find_proj_dir = $proj_dir;    # This is lame ... I'm just removing 
  598.     $find_proj_dir =~ s/\/$//;    # the trailing '/' from the file path
  599.     
  600.     open (FIND, "cd $cwd; find $find_proj_dir -name '*.[hm]' -print |");
  601.     while (<FIND>) {
  602.       chop;
  603.       s/$proj_dir//;
  604.       s/.[hm]$//;
  605.       push (@projfiles, $_);
  606.     }
  607.     @projfiles = sort @projfiles;
  608.     
  609.     while (@projfiles) {
  610.       $pfile = shift (@projfiles);
  611.       if (defined($pfile)) {
  612.         if (defined($projfiles[0]) && ($pfile eq $projfiles[0])) { 
  613.           # there must have been both a .h and a .m with the same root 
  614.           # since the only file names in @projfiles end in .h or .m
  615.           # the test to see if it is an object file is based on this.
  616.           push (@objects, $pfile);
  617.           shift (@projfiles);
  618.         } else {
  619.           # there is only one file with the .h or .m extension, if
  620.           # the option to disallow singles is not set, we add it 
  621.           push (@objects, $pfile)
  622.             if (!$opt_nosingles);
  623.         }
  624.       }
  625.     }
  626.   }
  627.  
  628.  
  629. #
  630. # Use find to recursively scan the project directory for 'rtf' and 'rtfd'
  631. # files.  Store the files to the array rtffiles
  632. #
  633. sub find_rtffiles
  634.   {
  635.     local ($pfile, $find_proj_dir);
  636.  
  637.     dblog (0, "Scanning project directory for rtf/rtfd files.");
  638.  
  639.     $find_proj_dir = $proj_dir;    # This is lame ... I'm just removing 
  640.     $find_proj_dir =~ s/\/$//;    # the trailing '/' from the file path
  641.     
  642.     open (FIND, "cd $cwd; find $find_proj_dir \\( -name '*.rtf' -o -name '*.rtfd' \\) -print |");
  643.     while (<FIND>) {
  644.       chop;
  645.       s/$proj_dir//;
  646.       push (@rtffiles, $_);
  647.     }
  648.     @rtffiles = sort @rtffiles;
  649.     
  650.   }
  651.  
  652.  
  653. #
  654. # generate the $obj_h, $obj_m and $obj_rtf file path variables.
  655. #
  656. sub set_obj_filepaths
  657.   {
  658.     local ($obj_root) = $_[0];
  659.     
  660.     $obj_h = "${proj_dir}${obj_root}.h";
  661.     $obj_m = "${proj_dir}${obj_root}.m";
  662.     
  663.     if ($opt_tree) {
  664.       $obj_r = $obj_root;        # if the obj_root is in a subdirectory
  665.       # remove any file extension on the 
  666.       # subdirectory name.
  667.       $obj_r =~ s/\.[^\.]+\//\//g;
  668.     } else {
  669.       if ($obj_root =~ m!/([^/]+)$!) {
  670.           $obj_r = $1;
  671.         } else {
  672.           $obj_r = $obj_root;
  673.         }
  674.     }
  675.     $obj_r = "$dest_dir$obj_r.rtf";
  676.     dblog(2, "Destination file set to: $obj_r");
  677. }
  678.  
  679. #
  680. # Generate the $rtf_src and $rtf_dest file path variables
  681. #
  682. sub set_rtf_filepaths
  683.   {
  684.     local ($rtf_root) = $_[0];
  685.     
  686.     # prepare the rtf source and dest file path
  687.     $rtf_src = "${proj_dir}${rtf_root}";
  688.     
  689.     if ($opt_tree) {
  690.       $rtf_dest = $rtf_root; 
  691.       
  692.       # If the rtf_root is in a subdirectory
  693.       # remove any file extension on the subdirectory name.
  694.       $rtf_dest =~ s/\.[^\.]+\//\//g;
  695.     } else {
  696.       if ($rtf_root =~ m!/([^/]+)$!) {
  697.         $rtf_dest =~ $1;
  698.       } else {
  699.         $rtf_dest = $rtf_root;
  700.       }
  701.     }
  702.     $rtf_dest = "$dest_dir$rtf_dest";
  703.   }
  704.  
  705. sub usage {
  706.   $error_fmt = shift;
  707.     
  708.   select(STDERR);
  709.     
  710.   printf "$file_name: $error_fmt\n", @_
  711.     if $error_fmt;
  712.  
  713.   print <<_ENDOFUSAGE_;
  714. Usage: $file_name [-force] [-rtf] [-tree] [-nosingles] [-timestamp] 
  715.            [-help] [-version] [-silent] [-Debug [#]]
  716.            [-copyright "Copyright String"] [-destination "dest path"]
  717.            [-project "project directory"] [ sourcefiles ...]
  718.  
  719.    -force            Force document creation for up to date files.
  720.    -rtf              Copy rtf and rtfd files fount in project tree.
  721.    -tree         Create a tree of documentation files.
  722.    -nosingles        Exclude unpaired ".h" and ".m" files from documentation
  723.    -timestamp         Insert a timestamp into the documentation
  724.    -help             Show this help and exit.       
  725.    -version         Show AutoDoc version/copyright and exit.
  726.    -silent         Operate silently;  do not generate log entries.
  727.    -Debug [#]        Set debugging level to #; 0 (default) is least, 5 is most.
  728.    -copyright "..."  Set copyrightowner in the copyright line to "...".
  729.    -destination ".." Create documentation files in directory "..".
  730.    -project "..."    Look for source files in the directory "...".
  731. _ENDOFUSAGE_
  732.    exit(1);
  733. }
  734.  
  735. #
  736. # Show version and copyright information
  737. #
  738. sub show_version
  739. {
  740.     local (@module_versions);
  741.  
  742.     @module_versions = (Autodoc::FileSupport::module_versionstamp(),
  743.                         Autodoc::LogDebug::module_versionstamp(),
  744.                         Autodoc::ScanFile::module_versionstamp(),
  745.                         Autodoc::ReadSource::module_versionstamp(),
  746.                         Autodoc::ParseComments::module_versionstamp(),
  747.                         Autodoc::DumpDocs::module_versionstamp(),
  748.                         Autodoc::GenerateRTF::module_versionstamp());
  749.     
  750.     print "This is $file_name Release $file_release (rev-$file_version)\n";
  751.     print "Module versions:\n\t", join ("\n\t", @module_versions), "\n";
  752.     print "Written by $file_author\n";
  753.     print "Copyright $file_copyright - All Rights Reserved\n";
  754.     print "Please send bugs and suggestions to:$file_mlist\n";
  755.     print "Contributions by:\n\t";
  756.     print join("\n\t", @file_contributors), "\n"
  757.       if scalar(@file_contributors);
  758.     exit(0);
  759. }
  760.