 #
#
# Warning: I removed the dependence on $[, but I have not tested it.
# [It has been tested somewhat, now. 10 Dec 93]
#
# 17 May 95: Changed local declaration from $loners to $loner. 
# Added return value of 1 at end of package. -ajm
#
# 7 Jan 95: Changed $unflowed match inside foreach $loner loop by moving
#           comma to end of character class so perl5 wouldn't complain.
# 
#

# We want strings to start at 1 so they read like columns in FORTRAN.
# $[ = 1; # This should not be done in a library!
# I might be able to get away with it using "package", but I'm 
# a little new for that.

# Package-local variables.
{
    package Fortran_Manipulate;

    # What should the first 6 columns of a continuation line look like?
    # (For OUTPUT)
    $cont_line_start = "     +";

    # This is how we tell if we're looking at a continuation line.
    # Note that /$cont_line_regex/o means compile only once because
    # the variable $cont_line_regex won't be changing.
    $cont_line_regex = '^     \S';

    # This is what a comment line looks like.
    $comment_line_regex = '^[cC\*]';

    # Fortran character set. Strictly speaking, these are the only
    # characters in the world. We don't want to be this pedantic, I think.
    # (I'm not even going to check that it's quoted properly.)
    # $FORTRAN_charset="[a-zA-Z0-9 =~-*/(),.$':]";
}


# unify: join first line & continuation lines together, cutting out 
# columns 1-6 of the continuation lines

sub unify {

    # Assume that @_ begins with an initial line, has all of that
    # line's continuation lines, and ends with the next literal
    # line in the file.

    # ASSUMPTION: all of the lines have already been chopped.

    # YUKS: Leaves in indentation spacing on continuation line.

    local (*Fortran_Manipulate'unflowed_lines) = @_;

    package Fortran_Manipulate;
    
    local ($line, $newly_gotten, $i);

    # Get the first line and pad it to column 72 with blanks. 
    # The other option is to pad the *previous* line when we read 
    # a continuation line. This one is probably faster.

    # Get at most 72 columns of the line. This means we ignore garbage
    # after column 72, including newlines. (Yay!)

    $line = substr (shift (@unflowed_lines),$[,72);
    $line .= ' ' x ( 72 - length($line)); # Duplicated below.


    while ( substr ($unflowed_lines[$[], $[, 6) =~ /$cont_line_regex/o )
    {
	# Get the line starting at column 7.
        # Stop at column 72, in case the line is longer. (12/15/93 ajm)
	$newly_gotten = substr(shift(@unflowed_lines),$[+6, 66);

	# Pad to column 72 with blanks. (72 = 6 start + 66 significant, 
        # so we really only want to pad 66 blanks here. 12/15/93 ajm)

	$newly_gotten .= ' ' x ( 66 - length($newly_gotten)); # As above.

	$line .= $newly_gotten;
    }

    $line .= "\n";

    return ($line);

}

# 
# We need to get no more than 66 characters for a flowed line because
# if the line is not first line in a series of continuation lines, it
# will have "     +" prepended to it, so it will grow by 6 characters.
#
# Actually, we want 72 on the first line so as not to break up strings
# and stuff that comes right at the end.
#
# For some reason, this routine respects embedded newlines in the
# line it gets. This means that if your line already has newlines, 
# it will break there in addition to anywhere else it should. 
#
# This routine adds a newline to the end of stuff it returns.
#
{
    package Fortran_Manipulate;

# Given an index, change it to the length of the string from the first
# character to that location in an array. (Inclusive on both ends.)

sub loc_to_size {
    local ($location) = @_;
    return ( $location - $[ + 1);
}

sub size_to_loc {
    local ($size) = @_;
    return ( $size - 1 + $[ );
}
    
sub get_at_most_n {

    # We take a line as an argument. We return the position 
    # at which we chopped it and the string we grabbed.

    local ($chars,$line) = @_;
    local ($return_loc);
    local ($flowed) = "";

    $return_loc = index ($line,"\n");

    if ( $return_loc == ($[ - 1) || &loc_to_size($return_loc) > $chars)
    {
	$flowed .= substr ($line, $[, $chars) . "\n";

	# Set $return_loc so we chop off only that much
	# of the string before wrapping again.
        
        # We need a size -> location change here. 
	$return_loc = &size_to_loc($chars) ;
    }
    else
    {
	# $return_loc is the position of the newline. This position is
	# calculated starting at $[, so we need to normalize it to 
	# be a length. We to this by calling &loc_to_size().

	$flowed .= substr ($line, $[, &loc_to_size($return_loc));
    }
    
    return ($return_loc, $flowed);
}

} # End package Fortran_Manipulate;

# flow: breaks a single long line into lines of length <= 72 chars,
# placing strings in @nobreak_list on lines by themselves
#
# 'flow' respects embedded newlines in your line, so it will break
# there in addition to at the ends of lines. It should add in the 
# continuation line prefix by itself after the newline.

sub flow {

    # Given an unflowed line, return a bunch of lines with
    # newlines at the end of each one.

    # IN: 1 long line, NOT ending with a newline.
    # OUT: a string of lines & newlines, each 72 chars or less in length

    local($Fortran_Manipulate'unflowed,@Fortran_Manipulate'no_break) = @_;

    package Fortran_Manipulate;

    # Issue a warning if we have more than 19 continuation lines.
    local ($linecount) = 0;

    local ($loner);

    # Place each expression we don't want to break on its own line.
    # Include trailing comma and spaces to look good.
    foreach $loner (@no_break)
    {
	$unflowed =~ s/($loner[\) ,]*)/\n$1\n/g;
    }

    # Change "\n\n" to a single "\n". No sense in blank continuation lines.
    # The string "\n\n" will occur when there are 2 consecutive 
    # tokens in @no_break.
    $unflowed =~ s/\n\n/\n/g;

    local ($flowed, $tmp_flow);
    local ($return_loc);

    ($return_loc, $flowed) = &get_at_most_n (72,$unflowed);

    # Hack off the previously used line up to the current location.
    substr ($unflowed, $[, &loc_to_size($return_loc)) = "";

    while ( length ($unflowed) > 0 )
    {
	($return_loc, $tmp_flow) = &get_at_most_n(66,$unflowed);
	$flowed .= $tmp_flow;

	# Hack off the previously used line up to current loc.
	substr ($unflowed, $[, &loc_to_size($return_loc)) = "";

	# If the line only has whitespace left on it, we don't want
	# to process it anymore.
	if ( $unflowed =~ m/^\s*$/ )
	{
	    $unflowed = "";
	}
	
	$linecount++;
    }

    # Change all of the newlines to "[newline][Continuation Line]"
    $flowed =~ s/\n{2,}/\n/g;
    $flowed =~ s/\n/\n$cont_line_start/g;

    # Remove the last continuation.
    # print STDERR "flowed: $flowed\n";
    # print STDERR  "cont_line_regex: $cont_line_regex\n";
    $flowed =~ s/\n$cont_line_regex$/\n/m;

    if ($linecount > 19)
    {
	print STDERR "Warning: there may be more than 19 continuation lines.\n";
	print STDERR "Going to output:\n";
	print STDERR "$flowed";
    }

    return ($flowed);

}

1;
