]> git.donarmstrong.com Git - biopieces.git/blob - code_perl/Maasha/Common.pm
fixes and stuff
[biopieces.git] / code_perl / Maasha / Common.pm
1 package Maasha::Common;
2
3
4 # Copyright (C) 2006-2007 Martin A. Hansen.
5
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20 # http://www.gnu.org/copyleft/gpl.html
21
22
23 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DESCRIPTION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
24
25
26 # This module contains commonly used routines
27
28
29 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
30
31
32 use strict;
33 use Carp;
34 use Data::Dumper;
35 use Storable;
36 use IO::File;
37 use Time::HiRes qw( gettimeofday );
38 use Maasha::Config;
39
40 use Exporter;
41
42 use vars qw( @ISA @EXPORT @EXPORT_OK );
43
44 @ISA = qw( Exporter ) ;
45
46 use Inline ( C => <<'END_C', DIRECTORY => $ENV{ "BP_TMP" } );
47
48 int index_m( char *str, char *substr, size_t str_len, size_t substr_len, size_t offset, size_t max_mismatch )
49 {
50     /* Martin A. Hansen & Selene Fernandez, August 2008 */
51
52     /* Locates a substring within a string starting from offset and allowing for max_mismatch mismatches. */
53     /* The begin position of the substring is returned if found otherwise -1 is returned. */
54
55     int i = 0;
56     int j = 0;
57
58     size_t max_match = substr_len - max_mismatch;
59
60     i = offset;
61
62     while ( i < str_len - ( max_match + max_mismatch ) + 1 )
63     {
64         j = 0;
65         
66         while ( j < substr_len - ( max_match + max_mismatch ) + 1 )
67         {
68             if ( match_m( str, substr, str_len, substr_len, i, j, max_match, max_mismatch ) != 0 ) {
69                 return i;
70             }
71
72             j++;
73         }
74     
75         i++;
76     }
77
78     return -1;
79 }
80
81
82 int match_m( char *str, char *substr, size_t str_len, size_t substr_len, size_t str_offset, size_t substr_offset, size_t max_match, size_t max_mismatch )
83 {
84     /* Martin A. Hansen & Selene Fernandez, August 2008 */
85
86     /* Compares a string and substring starting at speficied string and substring offset */
87     /* positions allowing for a specified number of mismatches. Returns 1 if there is a */
88     /* match otherwise returns 0. */
89
90     size_t match    = 0;
91     size_t mismatch = 0;
92
93     while ( str_offset <= str_len && substr_offset <= substr_len )
94     {
95         if ( str[ str_offset ] == substr[ substr_offset ] )
96         {
97             match++;
98
99             if ( match >= max_match ) {
100                 return 1;
101             };
102         }
103         else
104         {
105             mismatch++;
106
107             if ( mismatch > max_mismatch ) {
108                 return 0;
109             }
110         }
111     
112         str_offset++;
113         substr_offset++;
114     }
115
116     return 0;
117 }
118
119
120 END_C
121
122
123
124 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
125
126
127 sub error
128 {
129     # Martin A. Hansen, February 2008.
130
131     # Print error message and exit with stack trace.
132
133     my ( $msg,        # Error message.
134          $no_stack,   # disable stack trace - OPTIONAL
135        ) = @_;
136
137     # Returns nothing.
138
139     my ( $script, $error, @lines, $line, $routine, $file, $line_no, @table, $routine_max, $file_max, $line_max );
140
141     chomp $msg;
142
143     $script = get_scriptname();
144
145     $error  = Carp::longmess();
146
147     @lines  = split "\n", $error;
148
149     $line   = shift @lines;
150
151     push @table, [ "Routine", "File", "Line" ];
152     push @table, [ "-------", "----", "----" ];
153
154     $routine_max = length "Routine";
155     $file_max    = length "File";
156     $line_max    = length "Line";
157
158     if ( $line =~ /^ at (.+) line (\d+)$/ )
159     {
160         $file    = $1;
161         $line_no = $2;
162
163         $file_max = length $file    if length $file    > $file_max;
164         $line_max = length $line_no if length $line_no > $line_max;
165
166         push @table, [ "", $file, $line_no ];
167     }
168     else
169     {
170         die qq(ERROR: Unrecognized error line "$line"\n);
171     }
172
173     foreach $line ( @lines )
174     {
175         if ( $line =~ /^\s*(.+) called at (.+) line (\d+)\s*$/ )
176         {
177             $routine = $1;
178             $file    = $2;
179             $line_no = $3;
180             
181             $routine =~ s/\(.+\)$/ .../;
182
183             $routine_max = length $routine if length $routine > $routine_max;
184             $file_max    = length $file    if length $file    > $file_max;
185             $line_max    = length $line_no if length $line_no > $line_max;
186
187             push @table, [ $routine, $file, $line_no ];
188         }
189         else
190         {
191             die qq(ERROR: Unrecognized error line "$line"\n);
192         }
193     }
194
195     $msg =~ s/\.$//;
196
197     print STDERR qq(\nERROR!\n\nProgram \'$script\' failed: $msg.\n\n);
198
199     die( "MAASHA_ERROR" ) if $no_stack;
200
201     $routine_max += 3;
202     $file_max    += 3;
203     $line_max    += 3;
204
205     foreach $line ( @table ) {
206         printf( STDERR "%-${routine_max}s%-${file_max}s%s\n", @{ $line } );
207     }
208
209     print STDERR "\n";
210
211     die( "MAASHA_ERROR" );
212 }
213
214
215 sub read_open
216 {
217     # Martin A. Hansen, January 2004.
218
219     # Read opens a file and returns a filehandle.
220
221     my ( $path,   # full path to file
222        ) = @_;
223
224     # returns filehandle
225
226     my ( $fh, $type );
227
228     $type = `file $path` if -f $path;
229
230     if ( $type =~ /gzip compressed/ ) {
231         $fh = new IO::File "zcat $path|" or Maasha::Common::error( qq(Could not read-open file "$path": $!) );
232     } else {
233         $fh = new IO::File $path, "r" or Maasha::Common::error( qq(Could not read-open file "$path": $!) );
234     }
235
236     return $fh;
237 }
238
239
240 sub write_open
241 {
242     # Martin A. Hansen, January 2004.
243
244     # write opens a file and returns a filehandle
245
246     my ( $path,   # full path to file
247          $gzip,   # flag if data is to be gzipped - OPRIONAL
248        ) = @_;
249
250     # returns filehandle
251
252     my ( $fh );
253
254     if ( $gzip ) {
255         $fh = new IO::File "|gzip -f>$path" or Maasha::Common::error( qq(Could not write-open file "$path": $!) );
256     } else {
257         $fh = new IO::File $path, "w" or Maasha::Common::error( qq(Could not write-open file "$path": $!) );
258     }
259
260     return $fh;
261 }
262
263
264 sub append_open
265 {
266     # Martin A. Hansen, February 2006.
267
268     # append opens file and returns a filehandle
269
270     my ( $path,     # path to file
271        ) = @_;
272
273     # returns filehandle
274
275     my ( $fh );
276
277     $fh = new IO::File $path, "a" or Maasha::Common::error( qq(Could not append-open file "$path": $!) );
278
279     return $fh;
280 }
281
282
283 sub pipe_open
284 {
285     # Martin A. Hansen, January 2007.
286
287     # opens a pipe and returns a filehandle
288
289     my ( $fh );
290     
291     $fh = new IO::File "-" or Maasha::Common::error( qq(Could not open pipe: $!) );
292
293     return $fh;
294 }
295
296
297 sub read_args
298 {
299     # Martin A. Hansen, December 2006
300
301     # reads arguments from @ARGV which is strictly formatted.
302     # three kind of argments are accepted:
303     # 1) file names           [filename]
304     # 2) options with value   [--option=value]
305     # 3) option without value [--option]
306
307     my ( $args,      # list of arguments
308          $ok_args,   # list of accepted arguments - OPTIONAL
309        ) = @_;
310
311     # returns a hashref
312
313     my ( %ok_hash, $arg, @dirs, @files, %hash );
314
315     foreach $arg ( @{ $args } )
316     {
317         if ( $arg =~ /^--([^=]+)=(.+)$/ ) {
318             $hash{ $1 } = $2;
319         } elsif ( $arg =~ /^--(.+)$/ ) {
320             $hash{ $1 } = 1;
321         } elsif ( -d $arg ) {
322             push @dirs, $arg;
323         } elsif ( -f $arg ) {
324             push @files, $arg;
325         } else {
326             Maasha::Common::error( qq(Bad syntax in argument->"$arg") );
327         }
328     }
329
330     $hash{ "DIRS" }  = \@dirs;
331     $hash{ "FILES" } = \@files;
332
333     if ( $ok_args )
334     {
335         map { $ok_hash{ $_ } = 1 } @{ $ok_args };
336
337         $ok_hash{ "DIRS" }  = 1;
338         $ok_hash{ "FILES" } = 1;
339
340         map { Maasha::Common::error( qq(Unknown argument->"$_") ) if not exists $ok_hash{ $_ } } keys %hash;
341     }
342
343     return wantarray ? %hash : \%hash;
344 }
345
346
347 sub get_time
348 {
349     # Martin A. Hansen, July 2008.
350
351     # Get current time as a number.
352
353     # Returns a number.
354
355     return time;
356 }
357
358
359 sub get_time_hires
360 {
361     # Martin A. Hansen, May 2008.
362
363     # Get current time in high resolution.
364
365     # Returns a float.
366
367     return gettimeofday();
368 }
369
370
371 sub get_processid
372 {
373     # Martin A. Hansen, July 2008.
374
375     # Get process id for current process.
376
377     # Returns a number.
378
379     return $$;
380 }
381
382
383 sub get_sessionid
384 {
385     # Martin A. Hansen, April 2008.
386
387     # Create a session id based on time and pid.
388
389     # Returns a number
390
391     return get_time . get_processid;
392 }
393
394
395 sub get_user
396 {
397     # Martin A. Hansen, July 2008.
398
399     # Return the user name of the current user.
400
401     # Returns a string.
402
403     return $ENV{ 'USER' };
404 }
405
406
407 sub get_tmpdir
408 {
409     # Martin A. Hansen, April 2008.
410
411     # Create a temporary directory based on
412     # $ENV{ 'BP_TMP' } and sessionid.
413
414     # this thing is a really bad solution and needs to be removed.
415
416     # Returns a path.
417
418     my ( $user, $sid, $pid, $path );
419
420     Maasha::Common::error( qq(no BP_TMP set in %ENV) ) if not -d $ENV{ 'BP_TMP' };
421
422     $user = Maasha::Common::get_user();
423     $sid  = Maasha::Common::get_sessionid();
424     $pid  = Maasha::Common::get_processid();
425
426     $path = "$ENV{ 'BP_TMP' }/" . join( "_", $user, $sid, $pid, "bp_tmp" );
427     
428     Maasha::Filesys::dir_create( $path );
429
430     return $path;
431 }
432
433
434 sub get_scriptname
435 {
436     # Martin A. Hansen, February 2007
437
438     # returns the script name
439
440     return ( split "/", $0 )[ -1 ];
441 }
442
443
444 sub get_basename
445 {
446     # Martin A. Hansen, February 2007
447
448     # Given a full path to a file returns the basename,
449     # which is the part of the name before the last '.'.
450
451     my ( $path,   # full path to filename
452        ) = @_;
453
454     my ( $basename );
455
456     $basename = ( split "/", $path )[ -1 ];
457
458     $basename =~ s/(.+)\.?.*/$1/;
459
460     return $basename
461 }
462
463
464 sub get_fields
465 {
466     # Martin A. Hansen, July 2008.
467
468     # Given a filehandle to a file gets the
469     # next line which is split into a list of
470     # fields that is returned.
471
472     my ( $fh,          # filehandle
473          $delimiter,   # field seperator - OPTIONAL
474        ) = @_;
475
476     # Returns a list.
477
478     my ( $line, @fields );
479
480     $line = <$fh>;
481
482     return if not defined $line;
483
484     chomp $line;
485
486     $delimiter ||= "\t";
487
488     @fields = split "$delimiter", $line;
489
490     return wantarray ? @fields : \@fields;
491 }
492
493
494 sub run
495 {
496     # Martin A. Hansen, April 2007.
497
498     # Run an execute with optional arguments.
499
500     my ( $exe,      # executable to run
501          $args,     # argument string
502          $nice,     # nice flag
503        ) = @_;
504
505     # Returns nothing.
506
507     my ( $command_line, $result );
508
509     $command_line  = Maasha::Config::get_exe( $exe );
510     $command_line .= " " . $args if $args;
511     $command_line  = "nice -n19 " . $command_line if $nice;
512
513     system( $command_line ) == 0 or Maasha::Common::error( qq(Could not execute "$command_line": $?) );
514 }
515
516
517 sub run_and_return
518 {
519     # Martin A. Hansen, April 2008.
520
521     # Run an execute with optional arguments returning the output
522     # as a list.
523
524     my ( $exe,      # executable to run
525          $args,     # argument string
526          $nice,     # nice flag
527        ) = @_;
528
529     # Returns a list.
530
531     my ( $command_line, @result );
532
533     $command_line  = Maasha::Config::get_exe( $exe );
534     $command_line .= " " . $args if $args;
535     $command_line  = "nice -n19 " . $command_line if $nice;
536
537     @result = `$command_line`; 
538
539     chomp @result;
540
541     return wantarray ? @result : \@result;
542 }
543
544
545 sub time_stamp
546 {
547     # Martin A. Hansen, February 2006.
548
549     # returns timestamp for use in log file.
550     # format: YYYY-MM-DD HH:MM:SS
551
552     # returns string
553
554     my ( $year, $mon, $day, $time );
555
556     ( undef, undef, undef, $day, $mon, $year, undef, undef ) = gmtime( time );
557
558     $mon  += 1;       # first month is 0, so we correct accordingly
559     $year += 1900;
560
561     $day  = sprintf "%02d", $day;
562     $mon  = sprintf "%02d", $mon;
563
564     $time = localtime;
565
566     $time =~ s/.*(\d{2}:\d{2}:\d{2}).*/$1/;
567
568     return "$year-$mon-$day $time";
569 }
570
571
572 sub time_stamp_diff
573 {
574     # Martin A. Hansen, June 2009.
575
576     # Return the difference between two time stamps in
577     # the time stamp format.
578
579     my ( $t0,   # time stamp 0
580          $t1,   # time stamp 1
581        ) = @_;
582
583     # Returns a time stamp string.
584
585     my ( $year0, $mon0, $day0, $hour0, $min0, $sec0,
586          $year1, $mon1, $day1, $hour1, $min1, $sec1,
587          $year,  $mon,  $day,  $hour,  $min,  $sec );
588
589     $t0 =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/;
590     $year0 = $1;
591     $mon0  = $2;
592     $day0  = $3;
593     $hour0 = $4;
594     $min0  = $5;
595     $sec0  = $6;
596
597     $sec0 += $day0 * 24 * 60 * 60;
598     $sec0 += $hour0 * 60 * 60;;
599     $sec0 += $min0  * 60;
600
601     $t1 =~ /(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)/;
602     $year1 = $1;
603     $mon1  = $2;
604     $day1  = $3;
605     $hour1 = $4;
606     $min1  = $5;
607     $sec1  = $6;
608
609     $sec1 += $day1 * 24 * 60 * 60;
610     $sec1 += $hour1 * 60 * 60;;
611     $sec1 += $min1  * 60;
612
613     $year = $year1 - $year0;
614     $mon  = $mon1  - $mon0;
615     $day  = $day1  - $day0; 
616
617     $sec  = $sec1 - $sec0;
618
619     $hour = int( $sec / ( 60 * 60 ) );
620     $sec -= $hour * 60 * 60;
621
622     $min  = int( $sec / 60 );
623     $sec -= $min * 60;
624
625     return join( ":", sprintf( "%02d", $hour ), sprintf( "%02d", $min ), sprintf( "%02d", $sec ) );
626 }
627
628
629 sub process_running
630 {
631     # Martin A. Hansen, July 2008.
632
633     # Given a process ID check if it is running
634     # on the system. Return 1 if the process is
635     # running else 0.
636
637     my ( $pid,   # process ID to check.
638        ) = @_;
639
640     # Returns boolean
641
642     my ( @ps_table );
643     
644     @ps_table = run_and_return( "ps", " a" );
645
646     if ( grep /^\s*$pid\s+/, @ps_table ) {
647         return 1;
648     } else {
649         return 0;
650     }
651 }
652
653
654 sub wrap_line
655 {
656     # Martin A. Hansen, May 2005
657
658     # Takes a given line and wraps it to a given width,
659     # without breaking any words.
660     
661     my ( $line,   # line to wrap
662          $width,  # wrap width
663        ) = @_;
664
665     # Returns a list of lines.
666
667     my ( @lines, $substr, $wrap_pos, $pos, $new_line );
668
669     $pos = 0;
670
671     while ( $pos < length $line )
672     {
673         $substr = substr $line, $pos, $width;
674
675         if ( length $substr == $width )
676         {
677             $substr   = reverse $substr;
678             $wrap_pos = index $substr, " ";
679
680             $new_line = substr $line, $pos, $width - $wrap_pos;
681             $new_line =~ s/ $//;
682         
683             $pos += $width - $wrap_pos;
684         }
685         else
686         {
687             $new_line = $substr;
688
689             $pos += $width;
690         }
691
692         push @lines, $new_line;
693     }
694
695     return wantarray ? @lines : \@lines;
696 }
697
698
699 # >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
700
701 1;