# tRNAscanSE/Utils.pm # This module contains utility functions used in tRNAscan-SE. # # -------------------------------------------------------------- # This module is part of the tRNAscan-SE program. # Copyright (C) 2017 Patricia Chan and Todd Lowe # -------------------------------------------------------------- # package tRNAscanSE::Utils; use strict; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(check_output_file open_for_read open_for_write open_for_append tempname print_filename rev_comp_seq max min seg_overlap error_exit_status trim pad pad_num); our %comp_map = ( # Complement map 'A' => 'T', 'T' => 'A', 'U' => 'A', 'G' => 'C', 'C' => 'G', 'Y' => 'R', 'R' => 'Y', 'S' => 'W', 'W' => 'S', 'M' => 'K', 'K' => 'M', 'B' => 'V', 'V' => 'B', 'H' => 'D', 'D' => 'H', 'N' => 'N', 'X' => 'X', '?' => '?', '-' => '-'); sub check_output_file { my ($fname, $prompt_for_overwrite) = @_; my ($ans, $ansline); if ((-e $fname) && ($prompt_for_overwrite)) { print STDERR "\nWARNING: $fname exists already.\n\n", " (O)verwrite file, (A)ppend to file, or (Q)uit program? "; $ansline = ; $ans = substr($ansline, 0, 1); while ($ans !~ /[AOQaoq]/) { print STDERR "\nReply (O)verwrite (A)ppend, or (Q)uit [O/A/Q]: "; $ansline = ; $ans = substr($ansline, 0, 1); } if (uc($ans) eq 'Q') { die "\ntRNAscan-SE aborted.\n\n"; } elsif (uc($ans) eq 'A') { print STDERR "\n Appending to $fname...\n"; open(FHAND,">>$fname") || die "Unable to open $fname for appending. ", "Aborting program.\n"; close(FHAND); return; # successful exit status } else { # $ans eq 'O'verwrote print STDERR "\n Overwriting $fname...\n"; } } open(FHAND, ">$fname") || die "Unable to open $fname for writing. Aborting program.\n"; close(FHAND); } sub open_for_read { my ($FHAND, $fname) = @_; open($$FHAND, "$fname") || die "Unable to open $fname for reading. Aborting program.\n"; } sub open_for_write { my ($FHAND, $fname) = @_; open($$FHAND, ">$fname") || die "Unable to open $fname for writing. Aborting program.\n"; } sub open_for_append { my ($FHAND, $fname) = @_; open ($$FHAND, ">>$fname") || die "FATAL: Unable to open output file ", &print_filename($fname), "\n\n"; } # Function: tempname # by SE, modification by TMJL # Returns a unique temporary filename. # # Normally puts temp files to /tmp. This directory can # be overridden by an environment variable TMPDIR. # sub tempname { my ($temp_dir, $exten) = @_; my ($name); $name = "$temp_dir/tscan$$"."$exten"; return $name; } sub print_filename { my ($fname) = @_; if ($fname eq "-") { $fname = "Standard output"; } return $fname; } sub rev_comp_seq { my ($seq) = @_; my ($seqlen) = length($seq); my ($i, $j, $rcseq); $rcseq = 'X' x $seqlen; # pre-extending string for efficiency for ($i = ($seqlen - 1), $j = 0; $i > -1; $i--, $j++) { substr($rcseq, $j, 1) = $comp_map{(substr($seq, $i, 1))}; } return $rcseq; } sub complement_seq { my ($seq) = @_; my $comp_seq = ""; for (my $i = 0; $i < length($seq); $i++) { $comp_seq .= $comp_map{(substr($seq, $i, 1))}; } return $comp_seq; } sub min { my ($a, $b) = @_; if ($a < $b) { return ($a); } else { return ($b); } } sub max { my ($a, $b) = @_; if ($a > $b) { return ($a); } else { return ($b); } } sub seg_overlap { my ($seg1_a, $seg1_b, $seg2_a, $seg2_b, $range) = @_; if ($range == 0) { if ((($seg1_a >= $seg2_a) && ($seg1_a <= $seg2_b)) || (($seg1_b >= $seg2_a) && ($seg1_b <= $seg2_b)) || (($seg2_a >= $seg1_a) && ($seg2_a <= $seg1_b)) || (($seg2_b >= $seg1_a) && ($seg2_b <= $seg1_b))) { return 1; } else { return 0; } } else { if ((($seg1_a >= ($seg2_a - $range)) && ($seg1_a <= ($seg2_a + $range))) || (($seg1_b >= ($seg2_b - $range)) && ($seg1_b <= ($seg2_b + $range))) || (($seg2_a >= ($seg1_a - $range)) && ($seg2_a <= ($seg1_a + $range))) || (($seg2_b >= ($seg1_b - $range)) && ($seg2_b <= ($seg1_b + $range)))) { return 1; } else { return 0; } } } sub error_exit_status { my ($prog_name, $seq_name) = @_; if ($? != 0) { print STDERR "$prog_name could not complete successfully for $seq_name.\n", "Possible memory allocation problem or missing file. (Exit code=",$?,").\n\n"; return 1; } else { return 0; } } sub trim { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } sub pad { my ($string, $len) = @_; my $remain = $len - length($string); my $value = ""; if ($remain > 0) { $value = ' ' x $remain; } $value .= $string; return $value; } sub pad_num { my ($num, $len) = @_; my $string = sprintf("%d", $num); my $remain = $len - length($string); my $value = ""; if ($remain > 0) { $value = '0' x $remain; } $value .= $string; return $value; } 1;