package Autodoc::ScanFile;

###############################################################################
###############################################################################
##
##    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.
##
###############################################################################
###############################################################################

require 5.000;

##########################
# load required packages #
##########################
use Exporter;
use Autodoc::LogDebug;

@ISA      = qw(Exporter);
@EXPORT   = qw(scan_line
			   scan_rescanline
			   scan_eoffound
			   scan_closefile
			   scan_openfile
			   scan_skipCStyleComments
			   scan_keepADCNewlines
			   scan_postprocess);

$module_version = '$Revision: 1.2 $';
$module_version =~ s!(\$\w+: | \$)!!g;
$module_id	    = '$Id: ScanFile.pm,v 1.2 1995/10/20 22:16:29 aswift Exp $';
$module_id      =~ s!(\$\w+: | \$)!!g;
$module_name	= $module_id;
$module_name	=~ s!^([^\,]+).*$!$1!;

############################################################################
# 
# Purpose: Module that encapsulates scanning text out of files, specifically
#          designed to scan entire autodoc style comments that span multiple
#          lines.
#
# HISTORY: START
# $Log: ScanFile.pm,v $
# Revision 1.2  1995/10/20  22:16:29  aswift
# Added DevMan style changes Log support
#
#
# HISTORY: END
############################################################################

#############################################################################
#
# NAME:       module_version
#
# ACTION:     returns the version number of this module
#
# RETURN:     the module version
#
#############################################################################
sub module_version
{
    return $module_version;
}

sub module_versionstamp
{
    return "$module_name (rev-$module_version)";
}

#############################################################################
#
# NAME:       scan_rescanline
#
# ACTION:     Sets a global variable so that scan_line will return the last
#             line it returned - if no argument is passed, the current value
#             will be returned
#
# GLOBALS:    $scan_repeatlast
#
# ARGUMENTS:  An argument may be passed to set $scan_skipCStyleComments
#
# RETURN:     1 if the next call to scan_line will return the previous line
#             scanned, 0 if the next call will 
#
#############################################################################
sub scan_rescanline
{
    $scan_repeatlast = 0 if (!defined($scan_repeatlast));
    $scan_repeatlast = $_[0] if (scalar(@_) > 0);
    return $scan_repeatlast;
}


#############################################################################
#
# NAME:       scan_eoffound
#
# ACTION:     Returns 1 if there is a file open and the end of file has
#             been encountered, 0 otherwise
#
# GLOBALS:    $scan_eoffound - YES if the end of file has been detected
#             $scan_fileopen - YES if there is a file open
#
# ARGUMENTS:  none
#
#############################################################################
sub scan_eoffound
{
    if (defined($scan_fileopen) && ($scan_fileopen == 1)) {
	$scan_eoffound = eof(SCANFILE);
	return $scan_eoffound;
    } else {
	return 0;
    }
}


#############################################################################
#
# NAME:       scan_closefile
#
# ACTION:     Closes the file currently open - if any.
#
# GLOBALS:    $scan_eoffound - YES if the end of file has been detected
#             $scan_fileopen - YES if there is a file open
#
# ARGUMENTS:  none
#
#############################################################################
sub scan_closefile
{
    if (defined ($scan_fileopen) && ($scan_fileopen == 1)) {
	close (SCANFILE);
    }
    $scan_fileopen = 0;
    $scan_eoffound = 0;
}


#############################################################################
#
# NAME:       scan_openfile
#
# ACTION:     Opens the file passed as the argument and sets the relevent 
#             globals appropriatly
#
# GLOBALS:    $scan_eoffound - YES if the end of file has been detected
#             $scan_fileopen - YES if there is a file open
#
# ARGUMENTS:  The path of the file to be opened
#
# RETURN:     Returns 0 if it fails, 1 if it succeeds
#
#############################################################################
sub scan_openfile
{
    local ($filename);

    $filename = $_[0];
    scan_closefile();

    if (!(open (SCANFILE, $filename))) {
	warn ("Unable to open file: $filename\n");
	return 0;
    } else {
	$scan_fileopen = 1;
	dblog (1, "Scanning from file:\t$filename");
	return 1;
    }
}


#############################################################################
#
# NAME:       scan_skipCStyleComments
#
# ACTION:     Sets a global variable so that scan_line will keep or discard 
#             c-style comments in its return - if no argument is passed, 
#             the current value will be returned
#
# GLOBALS:    $scan_skipCStyleComments
#
# ARGUMENTS:  An argument may be passed to set $scan_skipCStyleComments
#
# RETURN:     1 if it is skipping c-style comments, 0 otherwise
#
#############################################################################
sub scan_skipCStyleComments
{
    $scan_skipCStyleComments = 0 if (!defined($scan_skipCStyleComments));
    $scan_skipCStyleComments = $_[0] if (scalar(@_) > 0);
    return $scan_skipCStyleComments;
}


#############################################################################
#
# NAME:       scan_keepADCNewlines
#
# ACTION:     Sets a global variable so that scan_line will keep or discard
#             newlines from autodoc comments - if no argument is passed, 
#             the current value will be returned
#
# GLOBALS:    $scan_keepADCNewlines
#
# ARGUMENTS:  An argument may be passed to set $scan_keepADCNewlines
#
# RETURN:     1 if it is keeping newlines, 0 otherwise
#
#############################################################################
sub scan_keepADCNewlines
{
    $scan_keepADCNewlines = 1 if (!defined($scan_keepADCNewlines));
    $scan_keepADCNewlines = $_[0] if (scalar(@_) > 0);
    return $scan_keepADCNewlines;
}


#############################################################################
#
# NAME:       scan_line
#
# ACTION:     Read and return a line from the passed file handle.  
#             Ignore blank lines.  Always scan up to the AutoDoc comment 
#             end if we encounter an AutoDoc comment start on a line.  
#             If the $scan_keepADCnewlines is true, encode the newlines into 
#             the string, since they affect paragraph formatting
#             in the documentation.
#
#             If $scan_repeatlast is TRUE return the last line scanned in.  
#             $scan_ok records whether the eof has been enountered
#
# GLOBALS     $scan_repeatlast - YES if the previous line should be returned
#             $scan_lastline - the last line that was scanned by scan line
#             $scan_fileopen - 1 if a scan file is open (SCANFILE is valid)
#
# ARGUMENTS:  none
#
# RETURN:     A string containing the last line scanned from the file
#
#############################################################################
sub scan_line
{
    local ($in, $inputline, $findADCend, $findCSCend, $rescan);

    use Autodoc::LogDebug;

    # return the last line scanned if $scan_lastline is 1
    if (scan_rescanline()) {
	scan_rescanline(0);
	if (defined($scan_lastline)) {
	    dblog (4, "Repeating last scan_line: [$scan_lastline]");
	    return $scan_lastline;	# return last line scanned
	} else {
	    dblog (4, "Repeating last scan_line: --no last scan_line--");
	    return "";
	}
    }
    $in          = "";
    $inputline   = "";
    $findADCend  = 0;
    $rescan      = 0;

  SCANLINE:			
    while (1) {

	if ($rescan == 0) {
	    # scan in the next line for processing
	    if ((!defined ($scan_fileopen)) || ($scan_fileopen == 0)) {
		dblog (1, "No scan file open, scan_line failed.\n");
		return "";		# return FALSE
	    }
	    if (scan_eoffound()) {
		dblog (1, "EOF reached, scan_line couldn\'t read line.");
		return "";		# return FALSE
	    }
	    $in = <SCANFILE>;
	    chop ($in) if ($in =~ m!\n$!);
	} else {
	    # process whatever is in $in again
	    $rescan = 0;
	}

	if (scan_skipCStyleComments()) {
	    if ($findCSCend) {
		if ($in =~ m!\*+/!) {
		    $findCSCend = 0;
		    $in = $';	# continue processing with the remaining text
		} else {
		    next SCANLINE; # scan a new line and look for the CSC end
		}
	    }

	    # ignore anything after a '//' found on a line
	    $in = $` if ($in =~ m!//!);

	    if (($in =~ m!/\*!) && !($in =~ m!/\*+\"!)) {
		# check for a single line comment
		if ($in =~ m!/\*+[^\"].*\*+/!) {
		    $in = "$`$'";
		    $rescan = 1;
		    next SCANLINE; # make sure there aren't more comments
		} else {
		    $inputline .= $`;
		    $findCSCend = 1;
		    next SCANLINE;
		}
	    }
	}

	# scan the whole AutoDoc style comment into the $inputline
	if ($findADCend) {

	    # kill any '*'s that appear on the beginning of the line 
	    $in = $' if ($in =~ m!^\s*\*+!);

	    if (scan_keepADCNewlines() && !($in =~ m/\S+/)) {
		$inputline .= "\\n"; # blank lines make newlines in docs
	    } else {
		$inputline .= " ";
	    }
	    if (!($in =~ m!\*+/!)) {

		$inputline .= $in;
		next SCANLINE;	# Keep looking...
	    } else {		# Found the ADC end
		$findADCend = 0;
	    }
	} else {
	    # read to end of autodoc comment if we are inside one
	    if (($in =~ m!/\*+\"!) && !($in =~ m!\*+/!)) {
		$inputline .= $in;
		$findADCend = 1;
		next SCANLINE;
	    }
	}

	$inputline .= $in;
	if ($inputline =~ m/\S+/) {
	    last SCANLINE;	# found data on a line, so return it
	}		     
    }
    
    $scan_lastline = &scan_postprocess($inputline);

    dblog (4, "scanned[$scan_lastline]");
    return $scan_lastline;		# return new $scan_lastline
}


#############################################################################
#
# NAME:       scan_postprocess
#
# ACTION:     Removes whitespace from the beginning and end of the string, 
#             and compresses all whitespace runs into a single space
#
# ARGUMENTS:  The string to be processed
#
# RETURN:     Returns the processed version of the line
#
#############################################################################
sub scan_postprocess
{
    local ($line);

    $line = $_[0];

    $line =~ s!\s*$!!;		# remove whitespace from the end of the line
    $line =~ s!^\s*!!;	        # and the beginning of the line
    $line =~ s/\s+/ /g;		# turn all whitespace into a single space

    return $line
}

1;
    
