App-PTP

 view release on metacpan or  search on metacpan

lib/App/PTP/Files.pm  view on Meta::CPAN

our @EXPORT_OK = qw(write_side_output read_side_input write_handle);

# The reference to this variable is used in the input list to specify that the
# standard input should be read.
our $stdin_marker = '<STDIN>';

# The reference to this variable is used in the input list to specify that all
# the inputs have been merged.
our $merged_marker = '<merged input>';

my $global_output_fh;

# $stdout is where the default (non-debug) output of the program should go. It
# will always be STDOUT, except during the tests.
sub init_global_output {
  my ($options, $stdout) = @_;
  if ($options->{output}) {
    if ($options->{debug_mode}) {
      print "All output is going to: $options->{output}\n";
    }
    my $mode = $options->{append} ? '>>' : '>';
    open($global_output_fh, "${mode}:encoding($options->{output_encoding})", $options->{output})
        or die "Cannot open output file '$options->{output}': $!.\n";
  } elsif (not $options->{in_place}) {
    print "All output is going to STDOUT.\n" if $options->{debug_mode};
    $global_output_fh = $stdout;
  }
  # We're setting the correct binmode for STDOUT here, because it can be used
  # when in_place is true, but also if the --tee command is used.
  binmode($stdout, ":encoding($options->{output_encoding})");
}

sub close_global_output {
  my ($options) = @_;
  if ($options->{output}) {
    close $global_output_fh
        or die "Cannot close output file '$options->{output}': $!.\n";
  }
}

# read_handle(handle)
# Reads the content of the given handle and returns an array ref containing two
# elements. The first one is an array-ref with all the lines of the file and the
# second one is a variable indicating if the last line of the file had a final
# separator.
# This method uses the value of the `$input_separator` global option.
sub read_handle {
  my ($handle, $options) = @_;
  local $/ = undef;  # enable slurp mode;
  my $content = <$handle>;
  if (not defined $content) {
    if ($@) {
      chomp($@);
      die "FATAL: Cannot read input: $@\n";
    }
    # Theoretically this should not happen. But, on 5.22 this seems to happens
    # if the input file is empty.
    $content = '';
  }
  my @content;
  if ($options->{preserve_eol}) {
    @content = $content =~ /\G ( .*? (?n: $options->{input_separator} ))/xgcms;
  } else {
    @content = $content =~ /\G (.*?) (?n: $options->{input_separator} )/xgcms;
  }
  my $missing_final_separator = 0;
  if ((pos($content) // 0) < length($content)) {
    $missing_final_separator = 1;
    print "The last line has no separator.\n" if $options->{debug_mode};
    push @content, substr($content, pos($content) // 0);
  }
  return (\@content, $missing_final_separator);
}

# read_file(path)
# Opens the given file, applies the correct read option, and calls read_handle.
sub read_file {
  my ($path, $options) = @_;
  print "Reading file: ${path}\n" if $options->{debug_mode};
  open(my $fh, "<:encoding($options->{input_encoding})", $path)
      or die "Cannot open file '$path': $!.\n";
  my @data = read_handle($fh, $options);
  close($fh) or die "Cannot close the file '$path': $!.\n";
  return @data;
}

# read_stdin()
# Applies the correct read option to STDIN and calls read_handle(STDIN).
sub read_stdin {
  my ($options, $stdin) = @_;
  print "Reading STDIN\n" if $options->{debug_mode};
  binmode($stdin, ":encoding($options->{input_encoding})");
  return read_handle($stdin, $options);
}

# read_input($input, $options, \*STDIN)
# Checks whether the input is the $stdin_marker or a file name and calls the
# matching method to read it, the third argument is the file-handle to read
# when $input is the $stdin_marker (usually STDIN except in tests).
sub read_input {
  my ($input, $options, $stdin) = @_;
  if (ref($input)) {
    if ($input == \$stdin_marker) {
      return read_stdin($options, $stdin);
    } else {
      die 'Should not happen ('.Dumper($input).")\n";
    }
  }
  return read_file($input, $options);
}

# write_content($handle, \@content, $missing_final_separator, \%options)
sub write_handle {
  my ($handle, $content, $missing_final_separator, $options) = @_;
  return unless @$content;
  local $, = $options->{output_separator};
  local $\ = $options->{output_separator}
      if $options->{fix_final_separator} || !$missing_final_separator;
  print $handle @$content;
}



( run in 0.493 second using v1.01-cache-2.11-cpan-ceb78f64989 )