1package TIGR::Foundation; 2{ 3 4=head1 NAME 5 6TIGR::Foundation - TIGR Foundation object 7 8=head1 SYNOPSIS 9 10 use TIGR::Foundation; 11 my $obj_instance = new TIGR::Foundation; 12 13=head1 DESCRIPTION 14 15This module defines a structure for Perl programs to utilize 16logging, version reporting, and dependency checking in a simple way. 17 18=cut 19 20 BEGIN { 21 require 5.006_00; # error if using Perl < v5.6.0 22 } 23 24 use strict; 25 use Cwd; 26 use Cwd 'chdir'; 27 use Cwd 'abs_path'; 28 use File::Basename; 29 use Getopt::Long; 30 use IO::Handle; 31 use POSIX qw(strftime); 32 use Sys::Hostname; 33 use English; 34 35 require Exporter; 36 37 our @ISA; 38 our @EXPORT; 39 @ISA = ('Exporter'); 40 @EXPORT = qw( 41 isReadableFile 42 isWritableFile 43 isExecutableFile 44 isCreatableFile 45 isReadableDir 46 isWritableDir 47 isCreatableDir 48 isCreatablePath 49 50 getISODate 51 getSybaseDate 52 getMySQLDate 53 getFilelabelDate 54 getLogfileDate 55 ); 56 57 ## internal variables and identifiers 58 our $REVISION = (qw$Revision: 1.1.1.1 $)[-1]; 59 our $VERSION = '1.1'; 60 our $VERSION_STRING = "$VERSION (Build $REVISION)"; 61 our @DEPEND = (); # there are no dependencies 62 63 64 ## prototypes 65 66 # Functional Class : general 67 sub new(); 68 sub getProgramInfo($); 69 sub runCommand($); 70 71 # Functional Class : depend 72 sub printDependInfo(); 73 sub printDependInfoAndExit(); 74 sub addDependInfo(@); 75 76 # Functional Class : version 77 sub getVersionInfo(); 78 sub printVersionInfo(); 79 sub printVersionInfoAndExit(); 80 sub setVersionInfo($); 81 82 # Functional Class : help 83 sub printHelpInfo(); 84 sub printHelpInfoAndExit(); 85 sub setHelpInfo($); 86 87 # Functional Class : usage 88 sub printUsageInfo(); 89 sub printUsageInfoAndExit(); 90 sub setUsageInfo($); 91 92 # Functional Class : files 93 sub isReadableFile($); 94 sub isExecutableFile($); 95 sub isWritableFile($); 96 sub isCreatableFile($); 97 sub isReadableDir($); 98 sub isWritableDir($); 99 sub isCreatableDir($); 100 sub isCreatablePath($); 101 102 # Functional Class : date 103 sub getISODate(;@); 104 sub getSybaseDate(;@); 105 sub getMySQLDate(;@); 106 sub getFilelabelDate(;@); 107 sub getLogfileDate(;@); 108 109 # Functional Class : logging 110 sub setDebugLevel($;$); 111 sub getDebugLevel(); 112 sub setLogFile($;$); 113 sub getLogFile(); 114 sub getErrorFile(); 115 sub printDependInfo(); 116 sub invalidateLogFILES(); 117 sub cleanLogFILES(); 118 sub closeLogERROR(); 119 sub closeLogMSG(); 120 sub openLogERROR(); 121 sub openLogMSG(); 122 sub logAppend($;$); 123 sub debugPush(); 124 sub debugPop(); 125 sub logLocal($$); 126 sub logError($;$); 127 sub bail($;$); 128 129 # Functional Class : modified methods 130 sub TIGR_GetOptions(@); 131 132 ## Implementation 133 134 135# Functional Class : general 136 137=over 138 139=item $obj_instance = new TIGR::Foundation; 140 141This function creates a new instance of the TIGR::Foundation 142object. A reference pointing to the object is returned on success. Otherwise, 143this method returns undefined. 144 145=cut 146 147 148 sub new() { 149 150 my $self = {}; 151 my $pkg = shift; 152 my $user_name = getpwuid($<); 153 my $host_name = hostname(); 154 155 # create the object 156 bless $self, $pkg; 157 158 ## Instance variables and identifiers, by functional class 159 160 # Functional Class : general 161 my $pname = basename($0, ()); # extract the script name 162 163 if((defined ($pname)) && ($pname =~ /^(.*)$/)) { 164 $pname = $1; 165 $self->{program_name} = $pname ; 166 } 167 168 if ($self->{program_name} =~ /^-$/) { # check if '-' is the input 169 $self->{program_name} = "STDIN"; 170 } 171 172 my $pcommand = join (' ', @ARGV); 173 174 if((defined ($pcommand)) && ($pcommand =~ /^(.*)$/)) { 175 $pcommand = $1; 176 $self->{invocation} = $pcommand ; 177 } 178 179 # The following four variables are to contain information specified by 180 # the 'host' program; there are methods of setting and retrieving each 181 182 # Functional Class : depend 183 @{$self->{depend_info}} = (); 184 185 # Functional Class : version 186 $self->{version_info} = undef; 187 188 # Functional Class : help 189 $self->{help_info} = undef; 190 191 # Functional Class : usage 192 $self->{usage_info} = undef; 193 194 # Functional Class : logging 195 $self->{debug_level} = undef; # default debug is not defined 196 @{$self->{debug_store}} = (); # the backup debug level stack 197 @{$self->{debug_queue}} = (); # queue used by MSG routine 198 @{$self->{error_queue}} = (); # queue used by ERROR routine 199 $self->{max_debug_queue_size} = 100; # maximum size for queue before 200 # log entries are expired 201 @{$self->{log_files}} = # these log files are consulted 202 ("$self->{program_name}.log", # on file write error and are 203 "/tmp/$self->{program_name}.$$.log"); # modified by setLogFile 204 $self->{msg_file_open_flag} = 0; # flag to check logLocal file 205 $self->{error_file_open_flag} = 0; # flag to check logError file 206 $self->{msg_file_used} = 0; # flag to indicate if log file 207 $self->{error_file_used} = 0; # has been written to 208 $self->{msg_append_flag} = 0; # by default logs are truncated 209 $self->{error_append_flag} = 0; # by default logs are truncated 210 $self->{log_append_setting} = 0; # (truncate == 0) 211 $self->{static_log_file} = undef; # user defined log file 212 $self->{start_time} = undef; # program start time 213 $self->{finish_time} = undef; # program stop time 214 215 # Log program invocation 216 $self->logLocal("START: " . "Username:$user_name, ". 217 "Hostname: $host_name ". $self->getProgramInfo('name') . 218 " " . $self->getProgramInfo('invocation'), 0); 219 $self->{start_time} = time; 220 221 return $self; 222 } 223 224 225 226=item $value = $obj_instance->getProgramInfo($field_type); 227 228This function returns field values for specified field types describing 229attributes of the program. The C<$field_type> parameter must be a listed 230attribute: C<name>, C<invocation>, C<env_path>, C<abs_path>. 231The C<name> field specifies the bare name of the executable. The 232C<invocation> field specifies the command line arguments passed to the 233executable. The C<env_path> value returns the environment path to the 234working directory. The C<abs_path> value specifies the absolute path to the 235working directory. If C<env_path> is found to be inconsistent, then that 236value will return the C<abs_path> value. If an invalid C<$field_type> is 237passed, the function returns undefined. 238 239=cut 240 241 242 sub getProgramInfo($) { 243 my $self = shift; 244 my $field_type = shift; 245 my $return_value = undef; 246 if (defined $field_type) { 247 $field_type =~ /^name$/ && do { 248 $return_value = $self->{program_name}; 249 }; 250 $field_type =~ /^invocation$/ && do { 251 $return_value = $self->{invocation}; 252 }; 253 $field_type =~ /^env_path$/ && do { 254 my $return_value = ""; 255 if ( 256 (defined $ENV{'PWD'}) && 257 (abs_path($ENV{'PWD'}) eq abs_path(".")) && 258 ($ENV{'PWD'} =~ /^(.*)$/) 259 ) { 260 $ENV{'PWD'} = $1; 261 $return_value = $ENV{'PWD'}; 262 } 263 else { 264 my $tmp_val = abs_path("."); 265 266 if((defined ($tmp_val)) && ($tmp_val =~ /^(.*)$/)) { 267 $tmp_val = $1; 268 $return_value = $tmp_val; 269 } 270 } 271 return $return_value; 272 }; 273 274 $field_type =~ /^abs_path$/ && do { 275 my $tmp_val = abs_path("."); 276 277 if((defined ($tmp_val)) && ($tmp_val =~ /^(.*)$/)) { 278 $tmp_val = $1; 279 $return_value = $tmp_val; 280 } 281 }; 282 } 283 return $return_value; 284 } 285 286=item $exit_code = $obj_instance->runCommand($command_str); 287 288This function passes the argument C<$command_str> to /bin/sh 289for processing. The return value is the exit code of the 290C<$command_str>. If the exit code is not defined, then either the signal or 291core dump value of the execution is returned, whichever is applicable. Perl 292variables C<$?> and C<$!> are set accordingly. If C<$command_str> is not 293defined, this function returns undefined. Log messages are recorded at log 294level 4 to indicate the type of exit status and the corresponding code. 295Invalid commands return -1. 296 297=cut 298 299 300 sub runCommand($) { 301 my $self = shift; 302 my $command_str = shift; 303 my $exit_code = undef; 304 my $signal_num = undef; 305 my $dumped_core = undef; 306 my $invalid_command = undef; 307 my $return_value = undef; 308 my @info_arr = getpwuid($<); 309 my $len = @info_arr; 310 my $home_dir = $info_arr[7]; 311 my $current_dir = $self->getProgramInfo("abs_path"); 312 313 if((defined ($ENV{PATH})) && ($ENV{PATH} =~ /^(.*)$/)) {#taint checking 314 $ENV{PATH} = $1; 315 my $path_var = $ENV{PATH}; 316 my @paths = split /:/, $path_var; 317 my $pathval = undef; 318 my $i = 0; 319 my $paths_len = @paths; 320 321 for ($i = 0; $i < $paths_len ; $i++) { 322 #substituting ~ with the home pathname. 323 $pathval = $paths[$i]; 324 $pathval =~ s/^~$/$home_dir/g; 325 my $home_root = $home_dir."\/"; 326 $pathval =~ s/^~\//$home_root/g; 327 328 #substituting . with the current pathname. 329 $pathval =~ s/^\.$/$current_dir/g; 330 my $current_root = $current_dir."\/"; 331 $pathval =~ s/^\.\//$current_root/g; 332 $paths[$i] = $pathval; 333 } 334 335 $ENV{PATH} = join(":", @paths); 336 } 337 338 if((defined ($command_str)) && ($command_str =~ /^(.*)$/)) {#taint 339 #checking 340 $command_str = $1; 341 system($command_str); 342 $exit_code = $? >> 8; 343 $signal_num = $? & 127; 344 $dumped_core = $? & 128; 345 346 if ($? == -1) { 347 $invalid_command = -1; 348 } 349 350 if ( 351 (!defined $invalid_command) && 352 ($exit_code == 0) && 353 ($signal_num == 0) && 354 ($dumped_core != 0) 355 ) { 356 357 $self->logLocal("Command '" . $command_str . "' core dumped", 4); 358 $return_value = $dumped_core; 359 } 360 elsif ( 361 (!defined $invalid_command) && 362 ($exit_code == 0) && 363 ($signal_num != 0) 364 ) { 365 366 $self->logLocal("Command '" . $command_str . 367 "' exited on signal " . $signal_num, 4); 368 $return_value = $signal_num; 369 } 370 elsif ((!defined $invalid_command)) { 371 372 $self->logLocal("Command '" . $command_str . 373 "' exited with exit code " . $exit_code, 4); 374 $return_value = $exit_code; 375 } 376 else { 377 378 $self->logLocal("Command '" . $command_str . 379 "' exited with invalid code " . $?, 4); 380 $return_value = $?; 381 } 382 } 383 return $return_value; 384 } 385 386 387# Functional Class : depend 388 389=item $obj_instance->printDependInfo(); 390 391The C<printDependInfo()> function prints the dependency list created by 392C<addDependInfo()>. One item is printed per line. 393 394=cut 395 396 397 sub printDependInfo() { 398 my $self = shift; 399 foreach my $dependent (@{$self->{depend_info}}) { 400 print STDERR $dependent, "\n"; 401 } 402 } 403 404 405=item $obj_instance->printDependInfoAndExit(); 406 407The C<printDependInfoAndExit()> function prints the dependency list created by 408C<addDependInfo()>. One item is printed per line. The function exits with 409exit code 0. 410 411=cut 412 413 414 sub printDependInfoAndExit() { 415 my $self = shift; 416 $self->printDependInfo(); 417 exit 0; 418 } 419 420 421=item $obj_instance->addDependInfo(@depend_list); 422 423The C<addDependInfo()> function adds C<@depend_list> information 424to the dependency list. If C<@depend_list> is empty, the internal 425dependency list is emptied. Contents of C<@depend_list> are not checked 426for validity (eg. they can be composed entirely of white space or 427multiple files per record). The first undefined record in C<@depend_list> 428halts reading in of dependency information. 429 430=cut 431 432 433 sub addDependInfo(@) { 434 my $self = shift; 435 my $num_elts = 0; 436 while (my $data_elt = shift @_) { 437 push (@{$self->{depend_info}}, $data_elt); 438 $num_elts++; 439 } 440 if ($num_elts == 0) { 441 @{$self->{depend_info}} = (); 442 } 443 } 444 445 446# Functional Class : version 447 448=item $version_string = $obj_instance->getVersionInfo(); 449 450The C<getVersionInfo()> function returns the version information set by the 451C<setVersionInfo()> function. 452 453=cut 454 455 456 sub getVersionInfo() { 457 my $self = shift; 458 return $self->{version_info}; 459 } 460 461 462=item $obj_instance->printVersionInfo(); 463 464The C<printVersionInfo()> function prints the version information set by the 465C<setVersionInfo()> function. If there is no defined version information, 466a message is returned notifying the user. 467 468=cut 469 470 471 sub printVersionInfo() { 472 my $self = shift; 473 if (defined $self->getVersionInfo()) { 474 print STDERR $self->getProgramInfo('name'), 475 " ", $self->getVersionInfo(), "\n"; 476 } 477 else { 478 print STDERR $self->getProgramInfo('name'), 479 " has no defined version information\n"; 480 } 481 } 482 483 484=item $obj_instance->printVersionInfoAndExit(); 485 486The C<printVersionInfoAndExit()> function prints version info set by the 487C<setVersionInfo()> function. If there is no defined version information, 488a message is printed notifying the user. This function calls exit with 489exit code 0. 490 491=cut 492 493 494 sub printVersionInfoAndExit() { 495 my $self = shift; 496 $self->printVersionInfo(); 497 exit 0; 498 } 499 500 501=item $obj_instance->setVersionInfo($version_string); 502 503The C<setVersionInfo()> function sets the version information to be reported 504by C<getVersionInfo()>. If C<$version_string> is empty, invalid, or 505undefined, the stored version information will be undefined. 506 507=cut 508 509 510 sub setVersionInfo($) { 511 my $self = shift; 512 my $v_info = shift; 513 if ( 514 (defined $v_info) && 515 ($v_info =~ /\S/) && 516 ((ref $v_info) eq "") 517 ) { 518 $self->{version_info} = $v_info; 519 } 520 else { 521 $self->{version_info} = undef; 522 } 523 } 524 525 526# Functional Class : help 527 528=item $obj_instance->printHelpInfo(); 529 530The C<printHelpInfo()> function prints the help information passed by the 531C<setHelpInfo()> function. 532 533=cut 534 535 536 sub printHelpInfo() { 537 my $self = shift; 538 if (defined $self->{help_info}) { 539 print STDERR $self->{help_info}; 540 } 541 else { 542 print STDERR "No help information defined.\n"; 543 } 544 } 545 546 547=item $obj_instance->printHelpInfoAndExit(); 548 549The C<printHelpInfoAndExit()> function prints the help info passed by the 550C<setHelpInfo()> function. This function exits with exit code 0. 551 552=cut 553 554 555 sub printHelpInfoAndExit() { 556 my $self = shift; 557 $self->printHelpInfo(); 558 exit 0; 559 } 560 561 562=item $obj_instance->setHelpInfo($help_string); 563 564The C<setHelpInfo()> function sets the help information via C<$help_string>. 565If C<$help_string> is undefined, invalid, or empty, the help information 566is undefined. 567 568=cut 569 570 571 sub setHelpInfo($) { 572 my $self = shift; 573 my $help_string = shift; 574 if ( 575 (defined $help_string) && 576 ($help_string =~ /\S/) && 577 ((ref $help_string) eq "") 578 ) { 579 chomp($help_string);#removing a new line if it is there. 580 $self->{help_info} = $help_string."\n";#adding a new line to help. 581 } 582 else { 583 $self->{help_info} = undef; 584 } 585 } 586 587 588# Functional Class : usage 589 590=item $obj_instance->printUsageInfo(); 591 592The C<printUsageInfo()> function prints the usage information reported by the 593C<setUsageInfo()> function. If no usage information is defined, but help 594information is defined, help information will be printed. 595 596=cut 597 598 599 sub printUsageInfo() { 600 601 my $self = shift; 602 if (defined $self->{usage_info}) { 603 print STDERR $self->{usage_info}; 604 } 605 elsif (defined $self->{help_info}) { 606 print STDERR $self->{help_info}; 607 } 608 else { 609 print STDERR "No usage information defined.\n"; 610 } 611 } 612 613 614=item $obj_instance->printUsageInfoAndExit(); 615 616The C<printUsageInfoAndExit()> function prints the usage information the 617reported by the C<setUsageInfo()> function and exits with status 1. 618 619=cut 620 621 622 sub printUsageInfoAndExit() { 623 my $self = shift; 624 $self->printUsageInfo(); 625 $self->bail("Incorrect command line"); 626 } 627 628 629=item $obj_instance->setUsageInfo($usage_string); 630 631The C<setUsageInfo()> function sets the usage information via C<$usage_string>. 632If C<$usage_string> is undefined, invalid, or empty, the usage information 633is undefined. 634 635=cut 636 637 638 sub setUsageInfo($) { 639 my $self = shift; 640 my $usage_string = shift; 641 if ( 642 (defined $usage_string) && 643 ($usage_string =~ /\S/) && 644 ((ref $usage_string) eq "") 645 ) { 646 chomp($usage_string); #removing a new line if it is there. 647 $self->{usage_info} = $usage_string."\n";#adding a new line to usage 648 } 649 else { 650 $self->{usage_info} = undef; 651 } 652 } 653 654 655# Functional Class : files 656 657=item $valid = isReadableFile($file_name); 658 659This function accepts a single scalar parameter containing a file name. 660If the file corresponding to the file name is a readable plain file or symbolic 661link, this function returns 1. Otherwise, the function returns 0. If the file 662name passed is undefined, this function returns 0 as well. 663 664=cut 665 666 667 sub isReadableFile($) { 668 my $file = shift; 669 if (scalar(@_) != 0) { #incase the method was invoked as an instance 670 #method 671 $file = shift; 672 } 673 674 if (defined ($file) && # was a file name passed? 675 ((-f $file) || (-l $file)) && # is the file a file or sym. link? 676 (-r $file) # is the file readable? 677 ) { 678 return 1; 679 } 680 else { 681 return 0; 682 } 683 } 684 685 686=item $valid = isExecutableFile($file_name); 687 688This function accepts a single scalar parameter containing a file name. 689If the file corresponding to the file name is an executable plain file 690or symbolic link, this function returns 1. Otherwise, the function returns 0. 691If the file name passed is undefined, this function returns 0 as well. 692 693=cut 694 695 696 sub isExecutableFile($) { 697 my $file = shift; 698 if (scalar(@_) != 0) { # incase the method was invoked as a instance 699 # method 700 $file = shift; 701 } 702 703 if (defined ($file) && # was a file name passed? 704 ((-f $file) || (-l $file)) && # is the file a file or sym. link? 705 (-x $file) # is the file executable? 706 ) { 707 return 1; 708 } 709 else { 710 return 0; 711 } 712 } 713 714 715=item $valid = isWritableFile($file_name); 716 717This function accepts a single scalar parameter containing a file name. 718If the file corresponding to the file name is a writable plain file 719or symbolic link, this function returns 1. Otherwise, the function returns 0. 720If the file name passed is undefined, this function returns 0 as well. 721 722=cut 723 724 725 sub isWritableFile($) { 726 my $file = shift; 727 if (scalar(@_) != 0) { # incase the method was invoked as a instance 728 # method 729 $file = shift; 730 } 731 732 if (defined ($file) && # was a file name passed? 733 ((-f $file) || (-l $file)) && # is the file a file or sym. link? 734 (-w $file) # is the file writable? 735 ) { 736 return 1; 737 } 738 else { 739 return 0; 740 } 741 } 742 743 744=item $valid = isCreatableFile($file_name); 745 746This function accepts a single scalar parameter containing a file name. If 747the file corresponding to the file name is creatable this function returns 1. 748The function checks if the location of the file is writable by the effective 749user id (EUID). If the file location does not exist or the location is not 750writable, the function returns 0. If the file name passed is undefined, 751this function returns 0 as well. Note that files with suffix F</> are not 752supported under UNIX platforms, and will return 0. 753 754=cut 755 756 757 sub isCreatableFile($) { 758 my $file = shift; 759 if (scalar(@_) != 0) { # incase the method was invoked as an instance 760 # method 761 $file = shift; 762 } 763 764 my $return_code = 0; 765 766 if ( 767 (defined ($file)) && 768 (! -e $file) && 769 ($file !~ /\/$/) 770 ) { 771 my $dirname = dirname($file); 772 # check the writability of the directory 773 $return_code = isWritableDir($dirname); 774 } 775 else { 776 # the file exists, it's not creatable 777 $return_code = 0; 778 } 779 return $return_code; 780 } 781 782 783=item $valid = isReadableDir($directory_name); 784 785This function accepts a single scalar parameter containing a directory name. 786If the name corresponding to the directory is a readable, searchable directory 787entry, this function returns 1. Otherwise, the function returns 0. If the 788name passed is undefined, this function returns 0 as well. 789 790=cut 791 792 793 sub isReadableDir($) { 794 my $file = shift; 795 if (scalar(@_) != 0) { # incase the method was invoked as an instance 796 # method 797 $file = shift; 798 } 799 800 if (defined ($file) && # was a name passed? 801 (-d $file) && # is the name a directory? 802 (-r $file) && # is the directory readable? 803 (-x $file) # is the directory searchable? 804 ) { 805 return 1; 806 } 807 else { 808 return 0; 809 } 810 } 811 812 813=item $valid = isWritableDir($directory_name); 814 815This function accepts a single scalar parameter containing a directory name. 816If the name corresponding to the directory is a writable, searchable directory 817entry, this function returns 1. Otherwise, the function returns 0. If the 818name passed is undefined, this function returns 0 as well. 819 820=cut 821 822 823 sub isWritableDir($) { 824 my $file = shift; 825 if (scalar(@_) != 0) { # incase the method was invoked as an instance 826 # method 827 $file = shift; 828 } 829 830 if (defined ($file) && # was a name passed? 831 (-d $file) && # is the name a directory? 832 (-w $file) && # is the directory writable? 833 (-x $file) # is the directory searchable? 834 ) { 835 return 1; 836 } 837 else { 838 return 0; 839 } 840 } 841 842 843=item $valid = isCreatableDir($directory_name); 844 845This function accepts a single scalar parameter containing a directory name. 846If the name corresponding to the directory is creatable this function returns 8471. The function checks if the immediate parent of the directory is writable by 848the effective user id (EUID). If the parent directory does not exist or the 849tree is not writable, the function returns 0. If the directory name passed is 850undefined, this function returns 0 as well. 851 852=cut 853 854 855 sub isCreatableDir($) { 856 my $dir = shift; 857 if (scalar(@_) != 0) { # incase the method was invoked as an instance 858 # method 859 $dir = shift; 860 } 861 my $return_code = 0; 862 863 if (defined ($dir)) { 864 $dir =~ s/\/$//g; 865 $return_code = isCreatableFile($dir); 866 } 867 return $return_code; 868 } 869 870 871=item $valid = isCreatablePath($path_name); 872 873This function accepts a single scalar parameter containing a path name. If 874the C<$path_name> is creatable this function returns 1. The function checks 875if the directory hierarchy of the path is creatable or writable by the 876effective user id (EUID). This function calls itself recursively until 877an existing directory node is found. If that node is writable, ie. the path 878can be created in it, then this function returns 1. Otherwise, the function 879returns 0. This function also returns zero if the C<$path_name> supplied 880is disconnected from a reachable directory tree on the file system. 881If the path already exists, this function returns 0. The C<$path_name> may 882imply either a path to a file or a directory. Path names may be relative or 883absolute paths. Any unresolvable relative paths will return 0 as well. This 884includes paths with F<..> back references to nonexistent directories. 885This function is recursive whereas C<isCreatableFile()> and 886C<isCreatableDir()> are not. 887 888=cut 889 890 891 sub isCreatablePath($) { 892 my $pathname = shift; 893 if (scalar(@_) != 0) { # incase the method was invoked as an instance 894 # method 895 $pathname = shift; 896 } 897 my $return_code = 0; 898 899 if (defined $pathname) { 900 # strip trailing '/' 901 $pathname =~ s/(.+)\/$/$1/g; 902 my $filename = basename($pathname); 903 my $dirname = dirname($pathname); 904 if ( 905 (! -e $pathname) && 906 ($dirname ne $pathname) && 907 ($filename ne "..") 908 ) { 909 if (-e $dirname) { 910 $return_code = isWritableDir($dirname); 911 } 912 else { 913 $return_code = isCreatablePath($dirname); 914 } 915 } 916 else { 917 $return_code = 0; 918 } 919 } 920 return $return_code; 921 } 922 923 924# Functional Class : date 925 926=item $date_string = getISODate($tm); 927 928This function returns the ISO 8601 datetime as a string given a time 929structure as returned by the C<time> function. If no arguments 930are supplied, this function returns the current time. If incorrect 931arguments are supplied, this function returns undefined. 932 933=cut 934 935 936 sub getISODate(;@) { 937 #checking if the function is invoked as an instance method. 938 if((defined(ref $_[0])) && ((ref $_[0]) eq "TIGR::Foundation")){ 939 shift; 940 } 941 my @time_val = @_; 942 my $time_str = undef; 943 if (scalar(@time_val) == 0) { 944 @time_val = localtime; 945 } 946 eval { 947 $time_str = strftime "%Y-%m-%d %H:%M:%S", @time_val; 948 }; 949 return $time_str; 950 } 951 952 953=item $date_string = getSybaseDate(@tm); 954 955This function returns a Sybase formatted datetime as a string given a time 956structure as returned by the C<time> function. If no arguments 957are supplied, this function returns the current time. If incorrect 958arguments are supplied, this function returns undefined. The date string 959returned is quoted according to Sybase requirements. 960 961=cut 962 963 964 sub getSybaseDate(;@) { 965 #checking if the function is invoked as an instance method. 966 if((defined(ref $_[0])) && ((ref $_[0]) eq "TIGR::Foundation")){ 967 shift; 968 } 969 my @time_val = @_; 970 my $time_str = undef; 971 if (scalar(@time_val) == 0) { 972 @time_val = localtime; 973 } 974 eval { 975 $time_str = strftime "\'%b %d %Y %I:%M%p\'", @time_val; 976 }; 977 return $time_str; 978 } 979 980 981=item $date_string = getMySQLDate(@tm); 982 983This function returns a MySQL formatted datetime as a string given a time 984structure as returned by the C<time> function. If no arguments 985are supplied, this function returns the current time. If incorrect 986arguments are supplied, this function returns undefined. The datetime string 987returned is prequoted according to MySQL requirements. 988 989=cut 990 991 992 sub getMySQLDate(;@) { 993 #checking if the function is invoked as an instance method. 994 if((defined(ref $_[0])) && ((ref $_[0]) eq "TIGR::Foundation")){ 995 shift; 996 } 997 my @time_val = @_; 998 my $time_str = undef; 999 if (scalar(@time_val) == 0) { 1000 @time_val = localtime; 1001 } 1002 $time_str = getISODate(@time_val); 1003 if (defined $time_str) { 1004 $time_str = "\'$time_str\'"; 1005 } 1006 return $time_str; 1007 } 1008 1009 1010=item $date_string = getFilelabelDate(@tm); 1011 1012This function returns the date (not time) as a compressed string 1013suitable for use as part of a file name. The format is YYMMDD. 1014The optional parameter should be a time structure as returned by 1015the C<time> function. If no arguments are supplied, the current time 1016is used. If incorrect arguments are supplied, this function returns 1017undefined. 1018 1019=cut 1020 1021 1022 sub getFilelabelDate(;@) { 1023 #checking if the function is invoked as an instance method. 1024 if((defined(ref $_[0])) && ((ref $_[0]) eq "TIGR::Foundation")){ 1025 shift; 1026 } 1027 my @time_val = @_; 1028 my $time_str = undef; 1029 if (scalar(@time_val) == 0) { 1030 @time_val = localtime; 1031 } 1032 eval { 1033 $time_str = strftime "%y%m%d", @time_val; 1034 }; 1035 return $time_str; 1036 } 1037 1038 1039=item $date_string = $obj_instance->getLogfileDate(@tm); 1040 1041This function returns the datetime as a formatted string 1042suitable for use as a log entry header. The optional parameter 1043should be a time structure as returned by the C<time> function. 1044If no arguments are supplied, this function uses the current time. 1045If incorrect arguments are supplied, this function sets the date/time fields 1046of the log entry string to C< INVALID|XXXXXX|>. 1047 1048=cut 1049 1050 1051 sub getLogfileDate(;@) { 1052 #checking if the function is invoked as an instance method. 1053 if((defined(ref $_[0])) && ((ref $_[0]) eq "TIGR::Foundation")){ 1054 shift; 1055 } 1056 my @time_val = @_; 1057 my $time_str = undef; 1058 my $log_form = undef; 1059 if (scalar(@time_val) == 0) { 1060 @time_val = localtime; 1061 } 1062 eval { 1063 $time_str = strftime("%Y%m%d|%H%M%S|", @time_val); 1064 }; 1065 if (!defined $time_str) { 1066 $time_str = " INVALID|XXXXXX|"; 1067 } 1068 $log_form = $time_str . sprintf("%6d| ", $$); 1069 return $log_form; 1070 } 1071 1072 1073# Functional Class : logging 1074 1075=item $obj_instance->setDebugLevel($new_level); 1076 1077This function sets the level of debug reporting according to C<$new_level>. 1078If the debug level is less than 0, all debug reporting is turned off. 1079It is impossible to turn off error reporting from C<bail()>. If C<$new_level> 1080is undefined, the debug level is set to 0. This function maintains 1081compatibility with C<GetOptions()>, and will accept a second parameter 1082the debug level, provided it is an integer. In such cases, the first parameter 1083is checked only if the second parameter is invalid. By default, the default 1084level is undefined. To turn on debugging, you must invoke this function. 1085 1086=cut 1087 1088 1089 sub setDebugLevel($;$) { 1090 my $self = shift; 1091 my $new_level = shift; 1092 my $getopts_new_level = shift; 1093 1094 if ( 1095 (defined $getopts_new_level) && 1096 ($getopts_new_level =~ /^-?\d+$/) 1097 ) { 1098 $new_level = $getopts_new_level; 1099 } 1100 elsif ( 1101 (!defined $new_level) || 1102 ($new_level !~ /^-?\d+$/) 1103 ) { 1104 $new_level = 0; 1105 $self->logLocal("No or invalid parameter to setDebugLevel(), " . 1106 "setting debug level to 0", 3); 1107 } 1108 1109 if ($new_level < 0) { 1110 $new_level = -1; 1111 } 1112 1113 $self->{debug_level} = $new_level; 1114 $self->logLocal("Set debug level to " . $self->getDebugLevel(), 2); 1115 } 1116 1117 1118=item $level = $obj_instance->getDebugLevel(); 1119 1120This function returns the current debug level. If the current debug 1121level is not defined, this function returns undefined. 1122 1123=cut 1124 1125 1126 sub getDebugLevel() { 1127 my $self = shift; 1128 return $self->{debug_level}; 1129 } 1130 1131 1132=item $obj_instance->setLogFile($log_file); 1133 1134This function sets the log file name for the C<logLocal()> function. 1135B<The programmer should call this function before invoking C<setDebugLevel()>> 1136if the default log file is not to be used. The function takes one parameter, 1137C<$log_file>, which defines the new log file name. If a log file is already 1138open, it is closed. The old log file is not truncated or deleted. 1139Future calls to C<logLocal()> or C<bail()> will log to C<$log_file> if it 1140is successfully opened. If the new log file is not successfully opened, 1141the function will try to open the default log file, F<program_name.log>. 1142If that file cannot be opened, F</tmp/program_name.$process_id.log> will 1143be used. If no log file argument is passed, the function will try to open 1144the default log file. This function is C<GetOptions()> aware; it will accept 1145two parameters, using the second one as the log file and ignoring the first if 1146and only if two parameters are passed. Any other usage specifies the first 1147parameter as the log file name. 1148 1149=cut 1150 1151 1152 sub setLogFile($;$) { 1153 my $self = shift; 1154 my $old_log_file = defined $self->{static_log_file} ? 1155 $self->{static_log_file} : undef; 1156 $self->{static_log_file} = shift; 1157 if (scalar(@_) == 1) { 1158 $self->{static_log_file} = shift; 1159 } 1160 1161 # only consider a new log file that is definable as a file 1162 if ((defined ($self->{static_log_file})) && 1163 ($self->{static_log_file} !~ /^\s*$/)) { 1164 # delete an old log file entry added by "setLogFile" 1165 for (my $idx = 0; 1166 ($idx <= $#{$self->{log_files}}) && defined($old_log_file); 1167 $idx++) { 1168 if ($self->{log_files}[$idx] eq $old_log_file) { 1169 splice @{$self->{log_files}}, $idx, 1; 1170 $old_log_file = undef; 1171 } 1172 } 1173 unshift @{$self->{log_files}}, $self->{static_log_file}; 1174 1175 # initialize the log file variables and file spaces 1176 $self->{msg_file_used} = 0; 1177 $self->{error_file_used} = 0; 1178 $self->cleanLogFILES(); 1179 } 1180 } 1181 1182 1183=item $log_file_name = $obj_instance->getLogFile(); 1184 1185This function returns the name of the log file to be used for printing 1186log messages. If no log file is available, this function returns undefined. 1187 1188=cut 1189 1190 1191 sub getLogFile() { 1192 my $self = shift; 1193 my $return_val = undef; 1194 if ( 1195 (scalar(@{$self->{log_files}}) != 0) && 1196 (defined($self->{log_files}[0])) 1197 ) { 1198 $return_val = $self->{log_files}[0]; 1199 } 1200 return $return_val; 1201 } 1202 1203 1204=item $error_file_name = $obj_instance->getErrorFile(); 1205 1206This function returns the name of the error file to be used for printing 1207error messages. The error file is derived from the log file; a F<.log> 1208extension is replaced by a F<.error> extension. If there is no F<.log> 1209extension, then F<.error> is appended to the log file name. If no 1210log files are defined, this function returns undefined. 1211 1212=cut 1213 1214 1215 sub getErrorFile() { 1216 my $self = shift; 1217 my $return_val = $self->getLogFile(); 1218 if (defined $return_val) { 1219 $return_val =~ s/\.log$//g; 1220 $return_val .= '.error'; 1221 } 1222 return $return_val; 1223 } 1224 1225 1226 # the following private functions are used for logging 1227 1228 1229 # push items onto the debug level stack 1230 sub debugPush() { 1231 my $self = shift; 1232 if (defined ($self->{debug_level})) { 1233 push @{$self->{debug_store}}, $self->{debug_level}; 1234 } 1235 else { 1236 push @{$self->{debug_store}}, "undef"; 1237 } 1238 $self->{debug_level} = undef; 1239 } 1240 1241 1242 # pop items from the debug level stack 1243 sub debugPop() { 1244 my $self = shift; 1245 $self->{debug_level} = pop @{$self->{debug_store}}; 1246 if ( 1247 (!defined ($self->{debug_level})) || 1248 ($self->{debug_level} eq "undef") 1249 ) { 1250 $self->{debug_level} = undef; 1251 } 1252 } 1253 1254 1255 # remove log files 1256 sub removeLogERROR() { 1257 1258 my $self = shift; 1259 $self->debugPush(); 1260 if ( 1261 (defined $self->getErrorFile()) && 1262 (isWritableFile($self->getErrorFile())) 1263 ) { 1264 unlink $self->getErrorFile() or 1265 $self->logLocal("Unable to remove error file " . 1266 $self->getErrorFile(), 3); 1267 } 1268 $self->debugPop(); 1269 } 1270 1271 1272 sub removeLogMSG() { 1273 my $self = shift; 1274 $self->debugPush(); 1275 1276 if ( 1277 (defined $self->getLogFile()) && 1278 (isWritableFile($self->getLogFile())) 1279 ) { 1280 unlink $self->getLogFile() or 1281 $self->logLocal("Unable to remove error file " . 1282 $self->getLogFile(), 3); 1283 } 1284 $self->debugPop(); 1285 } 1286 1287 1288 # invalidate log files 1289 sub invalidateLogFILES() { 1290 my $self = shift; 1291 $self->debugPush(); 1292 if (defined $self->getLogFile()) { 1293 $self->logLocal("Invalidating " . $self->getLogFile(), 2); 1294 shift @{$self->{log_files}}; 1295 $self->{msg_append_flag} = $self->{error_append_flag} = 1296 $self->{log_append_setting}; 1297 $self->{msg_file_used} = $self->{error_file_used} = 0; 1298 $self->cleanLogFILES(); 1299 } 1300 $self->debugPop(); 1301 } 1302 1303 1304 # clean previous log files 1305 sub cleanLogFILES() { 1306 my $self = shift; 1307 if ($self->{log_append_setting} == 0) { 1308 if ($self->{msg_file_used} == 0) { 1309 $self->removeLogMSG(); 1310 } 1311 if ($self->{error_file_used} == 0) { 1312 $self->removeLogERROR(); 1313 } 1314 } 1315 } 1316 1317 1318 # close log files 1319 sub closeLogERROR() { 1320 my $self = shift; 1321 my $return_code = 1; # need to return true for success, false for fail 1322 1323 $self->debugPush(); 1324 if (!close(ERRLOG) && (defined $self->getErrorFile())) { 1325 $self->logLocal("Cannot close " . $self->getErrorFile(), 3); 1326 $return_code = 0; 1327 } 1328 else { 1329 $return_code = 1; 1330 } 1331 $self->{error_file_open_flag} = 0; 1332 $self->debugPop(); 1333 return $return_code; 1334 } 1335 1336 1337 sub closeLogMSG() { 1338 my $self = shift; 1339 my $return_code = 1; # need to return true for success, false for fail 1340 1341 $self->debugPush(); 1342 if (!close(MSGLOG) && (defined $self->getLogFile())) { 1343 $self->logLocal("Cannot close " . $self->getLogFile(), 3); 1344 $return_code = 0; 1345 } 1346 else { 1347 $return_code = 1; 1348 } 1349 $self->{msg_file_open_flag} = 0; 1350 $self->debugPop(); 1351 return $return_code; 1352 } 1353 1354 1355 # open log files 1356 sub openLogERROR() { 1357 my $self = shift; 1358 my $return_code = 1; # need to return true for success, false for fail 1359 1360 $self->debugPush(); 1361 if ((defined $self->getErrorFile()) && 1362 ($self->{error_file_open_flag} == 0)) { 1363 my $fileop; 1364 $self->{error_file_open_flag} = 1; 1365 if ($self->{error_append_flag} == 0) { 1366 $fileop = '>'; 1367 $self->{error_append_flag} = 1; 1368 } 1369 else { 1370 $fileop = '>>'; 1371 } 1372 if (open(ERRLOG, $fileop . $self->getErrorFile())) { 1373 autoflush ERRLOG 1; 1374 } 1375 else { 1376 $self->logLocal("Cannot open " . $self->getErrorFile() . 1377 " for logging", 4); 1378 $self->{error_file_open_flag} = 0; 1379 } 1380 } 1381 $return_code = $self->{error_file_open_flag}; 1382 $self->debugPop(); 1383 1384 # this is 1 if the file stream is open, 0 if not 1385 return $return_code; 1386 } 1387 1388 1389 sub openLogMSG() { 1390 my $self = shift; 1391 my $return_code = 1; # need to return true for success, false for fail 1392 1393 $self->debugPush(); 1394 if ((defined $self->getLogFile()) && ($self->{msg_file_open_flag} == 0)){ 1395 my $fileop; 1396 $self->{msg_file_open_flag} = 1; 1397 if ($self->{msg_append_flag} == 0) { 1398 $fileop = '>'; 1399 $self->{msg_append_flag} = 1; 1400 } 1401 else { 1402 $fileop = '>>'; 1403 } 1404 1405 if (open(MSGLOG, $fileop . $self->getLogFile())) { 1406 autoflush MSGLOG 1; 1407 } 1408 else { 1409 $self->logLocal("Cannot open " . $self->getLogFile() . 1410 " for logging", 4); 1411 $self->{msg_file_open_flag} = 0; 1412 } 1413 } 1414 $return_code = $self->{msg_file_open_flag}; 1415 $self->debugPop(); 1416 1417 # this is 1 if the file stream is open, 0 if not 1418 return $return_code; 1419 } 1420 1421 1422=item $obj_instance->logAppend($log_append_flag); 1423 1424The C<logAppend()> function takes either C<0> or C<1> as a flag to 1425disable or enable log file appending. By default, log files are 1426truncated at the start of program execution or logging. Error files are 1427controlled by this variable as well. Invalid or undefined calls are ignored. 1428Calling this function with a C<0> argument after the log files have started 1429to be written may cause them to be truncated undesirably. This function is 1430C<GetOptions()> compliant; if 2 and only 2 variables are passed, the second 1431option is treated as C<$log_append_flag>. 1432 1433=cut 1434 1435 1436 sub logAppend($;$) { 1437 my $self = shift; 1438 my $log_append_flag = shift; 1439 if (defined $_[0]) { 1440 $log_append_flag = shift; 1441 } 1442 if ( 1443 (defined ($log_append_flag)) && 1444 (($log_append_flag eq "0") || 1445 ($log_append_flag eq "1")) 1446 ) { 1447 $self->{log_append_setting} = $self->{msg_append_flag} = 1448 $self->{error_append_flag} = $log_append_flag; 1449 } 1450 } 1451 1452 1453=item $obj_instance->logLocal($log_message, $log_level); 1454 1455The C<logLocal()> function takes two arguments. The C<$log_message> 1456argument specifies the message to be written to the log file. The 1457C<$log_level> argument specifies the level at which C<$log_message> is printed. 1458The active level of logging is set via the C<setDebugLevel()> function. 1459Only messages at C<$log_level> less than or equal to the active debug 1460level are logged. The default debug level is undefined. Note, a trailing 1461new line, if it exists, is stripped from the log message. 1462 1463=cut 1464 1465 1466 sub logLocal($$) { 1467 my $self = shift; 1468 my $log_message = shift; 1469 my $log_level = shift; 1470 1471 if ((!defined $log_level) || ($log_level =~ /\D/)) { 1472 $log_level = 1; 1473 } 1474 1475 if (defined $log_message) { 1476 chomp $log_message; # strip end new line, if it exists 1477 1478 $log_message = getLogfileDate() . $log_message; 1479 push @{$self->{debug_queue}}, [ $log_message, $log_level ]; 1480 1481 if ((defined ($self->getDebugLevel())) && 1482 ($self->getDebugLevel() > -1)) { 1483 while ( 1484 (defined(my $log_record = $self->{debug_queue}[0])) && 1485 (defined($self->getLogFile())) 1486 ) { 1487 ($log_message, $log_level) = @{$log_record}; 1488 if ( 1489 ( 1490 ($log_level <= $self->getDebugLevel()) && # debug level 1491 ($self->openLogMSG()) && # check log file 1492 (print MSGLOG "$log_message\n") && # print message 1493 ($self->closeLogMSG()) && # close log file 1494 ($self->{msg_file_used} = 1) # log file used 1495 ) || 1496 ( 1497 ($log_level > $self->getDebugLevel()) # bad dbg level 1498 ) 1499 ) { 1500 # log message is successfully processed, so shift it off 1501 shift @{$self->{debug_queue}}; 1502 } 1503 else { 1504 $self->debugPush(); 1505 $self->logLocal("Cannot log message \'$log_message\' to " . 1506 $self->getLogFile() . " = " . $!, 9); 1507 $self->invalidateLogFILES(); 1508 $self->debugPop(); 1509 } 1510 } 1511 } 1512 } 1513 else { 1514 $self->logLocal("logLocal() called without any parameters!",3); 1515 } 1516 1517 while ($#{$self->{debug_queue}} >= $self->{max_debug_queue_size}) { 1518 # expire old entries; this needs to happen if $self->{debug_level} 1519 # is undefined or there is no writable log file, otherwise the 1520 # queue could exhaust RAM. 1521 shift @{$self->{debug_queue}}; 1522 } 1523 } 1524 1525 1526=item $obj_instance->logError($log_message,$flag); 1527 1528The C<logError()> function takes two arguments, the second one being optional. 1529The C<$log_message> argument specifies the message to be written to the error 1530file. If the C<$flag> argument is defined and is non-zero, the C<$log_message> 1531is also written to STDERR. The C<$log_message> is also passed to C<logLocal>. 1532A message passed via logError() will always get logged to the log file 1533regardles of the debug level. Note, a trailing new line, if it exists, is 1534stripped from the log message. 1535 1536=cut 1537 1538 1539 sub logError($;$) { 1540 1541 my $self = shift; 1542 my $log_message = shift; 1543 my $flag = shift; 1544 if (defined $log_message) { 1545 chomp $log_message; # strip end new line, if it exists 1546 $self->logLocal($log_message, 0); 1547 1548 #printing error message to STDERR if flag is non zero. 1549 if((defined($flag)) && ($flag ne '0')) { 1550 print STDERR "$log_message\n"; 1551 } 1552 1553 $log_message = getLogfileDate() . $log_message; 1554 push(@{$self->{error_queue}}, $log_message); 1555 1556 while ( 1557 (defined(my $log_message = $self->{error_queue}[0])) && 1558 (defined($self->getErrorFile())) 1559 ) { 1560 1561 if ( 1562 ($self->openLogERROR()) && 1563 (print ERRLOG "$log_message\n") && 1564 ($self->closeLogERROR()) && 1565 ($self->{error_file_used} = 1) # that is an '=' 1566 ) { 1567 shift @{$self->{error_queue}}; 1568 } 1569 else { 1570 $self->debugPush(); 1571 $self->logLocal("Cannot log message \'$log_message\' to " . 1572 $self->getErrorFile() . " = $!", 6); 1573 $self->invalidateLogFILES(); 1574 $self->debugPop(); 1575 } 1576 } 1577 } 1578 else { 1579 $self->logLocal("logError() called without any parameters!",3); 1580 } 1581 1582 while ($#{$self->{error_queue}} >= $self->{max_debug_queue_size}) { 1583 # expire old entries; this needs to happen if $self->{debug_level} 1584 # is undefined or there is no writable log file, otherwise the 1585 # queue could exhaust RAM. 1586 shift @{$self->{error_queue}}; 1587 } 1588 } 1589 1590 1591=item $obj_instance->bail($log_message); 1592 1593The C<bail()> function takes a single required argument. The C<$log_message> 1594argument specifies the message to be passed to C<logLocal()> and displayed 1595to the screen in using the C<warn> function. All messages passed to C<bail()> 1596are logged regardless of the debug level. The C<bail()> function 1597calls C<exit(1)> to terminate the program. Optionally, a second positive 1598integer argument can be passed as the exit code to use. Note, a trailing 1599new line, if it exists, is stripped from the end of the line. 1600 1601=cut 1602 1603 1604 sub bail($;$) { 1605 my $self = shift; 1606 my $log_message = shift; 1607 my $exit_code = shift; 1608 1609 if ( 1610 (!defined $exit_code) || 1611 ($exit_code !~ /^\d+$/) 1612 ) { 1613 $exit_code = 1; 1614 } 1615 if (defined $log_message) { 1616 chomp $log_message; # strip end new line, if it exists 1617 1618 $self->logError($log_message); 1619 print STDERR $log_message, "\n"; 1620 } 1621 1622 exit $exit_code; 1623 } 1624 1625 1626# Functional Class : modified methods 1627 1628=item $getopts_error_code = $obj_instance->TIGR_GetOptions(@getopts_arguments); 1629 1630This function extends C<Getopt::Long::GetOptions()>. It may be used 1631as C<GetOptions()> is used. Extended functionality eliminates the need 1632to C<eval {}> the block of code containing the function. Further, TIGR 1633standard options, such as C<-help>, are defined implicitly. Using this 1634function promotes proper module behavior. Log and error files from 1635previous runs are removed if the log file append option, C<-appendlog>, 1636is not set to 1. 1637 1638The following options are defined by this function: 1639 1640=over 1641 1642=item -appendlog APPEND_FLAG 1643 1644Passing '1' to this argument turns on log file appending. 1645 1646=item -debug DEBUG_LEVEL 1647 1648Set debugging to DEBUG_LEVEL. 1649 1650=item -logfile LOG_FILE_NAME 1651 1652Set the default TIGR Foundation log file to LOG_FILE_NAME. 1653 1654=item -version, -V 1655 1656Print version information and exit. 1657 1658=item -help, -h 1659 1660Print help information and exit. 1661 1662=item -depend 1663 1664Print dependency information and exit. 1665 1666=back 1667 1668Regular C<GetOptions()> may still be used, however the C<TIGR_GetOptions()> 1669function eliminates some of the confusing issues with setting log files 1670and debug levels. B<The options defined by C<TIGR_GetOptions()> cannot be 1671overridden or recorded>. To get the log file and debug level after parsing 1672the command line, use C<getLogFile()> and C<getDebugLevel()>. C<GetOptions()> 1673default variables, ie. those of the form C<$opt_I<optionname>>, are not 1674supported. This function will return 1 on success. 1675 1676=cut 1677 1678 1679 sub TIGR_GetOptions(@) { 1680 my $self = shift; 1681 my @user_options = @_; 1682 1683 my $appendlog_var = undef; 1684 my $logfile_var = undef; 1685 my $debug_var = undef; 1686 my $version_var = undef; 1687 my $help_var = undef; 1688 my $depend_var = undef; 1689 1690 # these foundation options support the defaults 1691 my @foundation_options = ( 1692 "appendlog=i" => \$appendlog_var, 1693 "logfile=s" => \$logfile_var, 1694 "debug=i" => \$debug_var, 1695 "version|V" => \$version_var, 1696 "help|h" => \$help_var, 1697 "depend" => \$depend_var 1698 ); 1699 1700 Getopt::Long::Configure('no_ignore_case'); 1701 my $getopt_code = eval 'GetOptions (@user_options, @foundation_options)'; 1702 1703 if ((defined $help_var) && ($help_var =~ /^(.*)$/)) { 1704 $self->printHelpInfoAndExit(); 1705 } 1706 1707 if ((defined $version_var) && ($version_var =~ /^(.*)$/)) { 1708 $self->printVersionInfoAndExit(); 1709 } 1710 1711 if ((defined $depend_var) && ($depend_var =~ /^(.*)$/)) { 1712 $self->printDependInfoAndExit(); 1713 } 1714 1715 if ((defined $appendlog_var) && ($appendlog_var =~ /^(.*)$/)) { 1716 $appendlog_var = $1; 1717 $self->logAppend($appendlog_var); 1718 } 1719 1720 if ((defined $logfile_var) && ($logfile_var =~ /^(.*)$/)) { 1721 $logfile_var = $1; 1722 $self->setLogFile($logfile_var); 1723 } 1724 1725 if ((defined $debug_var) && ($debug_var =~ /^(.*)$/)) { 1726 $debug_var = $1; 1727 $self->setDebugLevel($debug_var); 1728 } 1729 1730 # remove old log files, if necessary 1731 for ( 1732 my $file_control_var = 0; 1733 $file_control_var <= $#{$self->{log_files}}; 1734 $file_control_var++ 1735 ) { 1736 $self->cleanLogFILES(); 1737 push(@{$self->{log_files}}, shift @{$self->{log_files}}); 1738 } 1739 return $getopt_code; 1740 } 1741 1742 DESTROY { 1743 my $self = shift; 1744 $self->{finish_time} = time; 1745 my $time_difference = $self->{finish_time} - $self->{start_time}; 1746 my $num_days = int($time_difference / 86400); # there are 86400 sec/day 1747 $time_difference -= $num_days * 86400; 1748 my $num_hours = int($time_difference / 3600); # there are 3600 sec/hour 1749 $time_difference -= $num_hours * 3600; 1750 my $num_min = int($time_difference / 60); # there are 60 sec/hour 1751 $time_difference -= $num_min * 60; 1752 my $num_sec = $time_difference; # the left overs are seconds 1753 my $time_str = sprintf "%03d-%02d:%02d:%02d", $num_days, $num_hours, 1754 $num_min, $num_sec; 1755 $self->logLocal("FINISH: " . $self->getProgramInfo('name') . 1756 ", elapsed ".$time_str ,0); 1757 } 1758} 1759 1760=back 1761 1762=head1 USAGE 1763 1764To use this module, load the C<TIGR::Foundation> package 1765via the C<use> function. Then, create a new instance of the 1766object via the C<new()> method, as shown below. If applicable, 1767C<START> and C<FINISH> log messages are printed when the object 1768is created and destroyed, respectively. It is advisable to 1769keep the instance of the object in scope for the whole program 1770to achieve maximum functionality. 1771 1772An example script using this module follows: 1773 1774 use strict; 1775 use TIGR::Foundation; 1776 1777 my $tfobject = new TIGR::Foundation; 1778 1779 MAIN: 1780 { 1781 # The following dependencies are not used in 1782 # this script, but are provided as an example. 1783 1784 my @DEPEND = ("/usr/bin/tee", "/sbin/stty"); 1785 1786 # The user defined $VERSION variable is usable by Perl. 1787 # The auto defined $REVISION variable stores the RCS/CVS revision 1788 # The user defined $VERSION_STRING reports both. 1789 1790 my $VERSION = '1.0'; 1791 my $REVISION = (qw$Revision: 1.1.1.1 $)[-1]; 1792 my $VERSION_STRING = "$VERSION (Build $REVISION)"; 1793 1794 my $HELP_INFO = "This is my help\n"; 1795 1796 # All of the necessary information must be passed 1797 # to the foundation object instance, as below. 1798 1799 $tfobject->addDependInfo(@DEPEND); 1800 $tfobject->setVersionInfo($VERSION_STRING); 1801 $tfobject->setHelpInfo($HELP_INFO); 1802 1803 my $input_file; 1804 my $output_file; 1805 1806 $tfobject->TIGR_GetOptions("input=s" => \$input_file, 1807 "output=s" => \$output_file); 1808 1809 # GetOptions(), and subsequently TIGR_GetOptions(), leaves 1810 # the variables unchanged if no corresponding command line 1811 # arguments are parsed. The passed variables are checked below. 1812 1813 if (defined $input_file) { 1814 1815 # The log message is written only if debugging is turned on. 1816 # By default, debugging is off. To turn on debugging, use the 1817 # '-debug DEBUG_LEVEL' option on the command line. 1818 # In this example, '-debug 1' would set debugging to level 1 1819 # and report these log messages. 1820 1821 $tfobject->logLocal("My input file is $input_file", 1); 1822 } 1823 1824 print "Hello world", "\n"; 1825 1826 # This case is similar to the previous one above... 1827 if (defined $output_file) { 1828 $tfobject->logLocal("My output file is $output_file.", 1); 1829 } 1830 } 1831 1832=cut 1833 18341; 1835 1836 1837 1838 1839