GnuCash 2.4.99
common.pl
Go to the documentation of this file.
00001 #!/usr/bin/perl -w
00002 #  common.pl - common routines shared by many CBB files
00003 #
00004 #  Written by Curtis Olson.  Started August 22, 1994.
00005 #
00006 #  Copyright (C) 1994 - 1997  Curtis L. Olson  - curt@sledge.mn.org
00007 #
00008 #  This program is free software; you can redistribute it and/or modify
00009 #  it under the terms of the GNU General Public License as published by
00010 #  the Free Software Foundation; either version 2 of the License, or
00011 #  (at your option) any later version.
00012 #
00013 #  This program is distributed in the hope that it will be useful,
00014 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 #  GNU General Public License for more details.
00017 #
00018 #  You should have received a copy of the GNU General Public License
00019 #  along with this program; if not, write to the Free Software
00020 #  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 
00022 # $Id: common.pl 20267 2011-02-10 19:40:38Z cstim $
00023 # (Log is kept at end of this file)
00024 
00025 ## @file
00026 # @brief common routines shared by many CBB files 
00027 # @author Curtis Olson
00028 # @date Started August 22, 1994
00029 # @cond PERL
00030 # ignore the following for doxygen
00031 
00032 use strict;
00033 
00034 sub destructive_merge_mangle {
00035   my($destination_ref, $source_ref, $comparison, $mangler) = @_;
00036   # Merges elements of destination into source according to the
00037   # comparison function.  Assumes that both source and destination
00038   # are already sorted wrt comparison.
00039 
00040   # mangler is optional, but if provided will be called for each
00041   # element of the modified destination with the args
00042   # ($destination_ref, $index, $new_item_p).  You can check for undef
00043   # on the next or previous index values to see if you're inserting at
00044   # the end/beginning of the list.
00045 
00046   # returns the indexes (in the new list) of the txns that were
00047   # inserted
00048 
00049   my @inserted_indices = ();
00050   my @source = @$source_ref;
00051   my $src_head = shift @source;
00052   my $current_splice_pos = 0;
00053   my $dest_items_left = scalar(@$destination_ref);
00054   my $next_dest = $$destination_ref[$current_splice_pos];
00055   while($src_head && $dest_items_left) {
00056     if(&$comparison($next_dest, $src_head) == 1) {
00057       # i.e. next_dest > src_head
00058       splice @$destination_ref, $current_splice_pos, 0, $src_head;
00059       push @inserted_indices, $current_splice_pos;
00060       &$mangler($destination_ref, $current_splice_pos, 1) if $mangler;
00061       $src_head = shift @source;
00062       $current_splice_pos++;
00063     } else {
00064       &$mangler($destination_ref, $current_splice_pos, 0) if $mangler;
00065       $current_splice_pos++;
00066       $next_dest = $$destination_ref[$current_splice_pos];
00067       $dest_items_left--;
00068     }
00069   }
00070   if($src_head) {
00071     push @$destination_ref, $src_head, @source;
00072     my $tail;
00073     foreach $tail ($src_head, @source) {
00074       &$mangler($destination_ref, $current_splice_pos, 1) if $mangler;
00075       push @inserted_indices, $current_splice_pos;
00076       $current_splice_pos++;
00077     }
00078   } else {
00079     # Must be some destination_ref items left.
00080     while ($dest_items_left) {
00081       &$mangler($destination_ref, $current_splice_pos, 0) if $mangler;
00082       $current_splice_pos++;
00083       $dest_items_left--;
00084     }
00085   }
00086   return \@inserted_indices;
00087 }
00088 
00089 sub destructive_remove_mangle {
00090   my($destination_ref, $source_ref, $comparison, $mangler) = @_;
00091 
00092   # Removes elements of source from destination according to the
00093   # comparison function which is just boolean.  Assumes that source
00094   # items are in the same order in source_ref as they are in
00095   # destination_ref
00096 
00097   # mangler is optional, but if provided will be called for each item
00098   # in the new destination list with the args:
00099 
00100   # ($killed_p, $destination_ref, $index, $old_item).  If killed is true
00101   # ($killed_p, $destination_ref, $index).  If killed is false
00102 
00103   # if killed is true, index is the delete pos, while if false, it's
00104   # the new index.  You can check for undef on the next or previous
00105   # index values to see if you're at the end/beginning of the list.
00106 
00107   my @removed_indices = ();
00108   my $old_position = 0;
00109   my @source = @$source_ref;
00110   my $src_head = shift @source;
00111   my $current_splice_pos = 0;
00112   my $dest_items_left = scalar(@$destination_ref);
00113   my $next_dest = $$destination_ref[$current_splice_pos];
00114   while($src_head && $dest_items_left) {
00115     if(&$comparison($next_dest, $src_head)) {
00116       # found an item to delete.
00117       splice @$destination_ref, $current_splice_pos, 1;
00118       &$mangler(1, $destination_ref, $current_splice_pos, $src_head)
00119         if $mangler;
00120       $src_head = shift @source;
00121       push @removed_indices, $old_position;
00122     } else {
00123       &$mangler(0, $destination_ref, $current_splice_pos) if $mangler;
00124       $current_splice_pos++;
00125     }
00126     $old_position++;
00127     $dest_items_left--;
00128     $next_dest = $$destination_ref[$current_splice_pos];
00129   }
00130   if($src_head) {
00131     print STDERR
00132       "Warning: source items left after destructive_remove_mangle\n";
00133   }
00134   if($mangler && $dest_items_left) {
00135     while($dest_items_left) {
00136       &$mangler(0, $destination_ref, $current_splice_pos);
00137       $current_splice_pos++;
00138       $dest_items_left--;
00139     }
00140   }
00141   return \@removed_indices;
00142 }
00143 
00144 sub timestamp {
00145   my($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime(time);
00146   $month++; # don't want 0 based months.
00147   $month = "0" . $month if $month < 10;
00148   $mday = "0" . $mday if $mday < 10;
00149   $hour = "0" . $hour if $hour < 10;
00150   $min = "0" . $min if $min < 10;
00151   $sec = "0" . $sec if $sec < 10;
00152   $year += 1900;
00153 
00154   return("$year-$month-$mday-$hour-$min-$sec");
00155 }
00156 
00157 # We need a version number
00158 $CBB::version = "Version <not_installed>";
00159 ($CBB::junk, $CBB::version_num, $CBB::junk) = split(/ +/, $CBB::version);
00160 
00161 
00162 # Contributed by Christopher Browne, Oct. 24/94
00163 sub pad { 
00164   return sprintf("%02d", $_[0]); 
00165 }
00166 
00167 
00168 # return the directory of a file name 
00169 sub file_dirname {
00170   my($file) = @_;
00171   my($pos);
00172   
00173   $pos = rindex($file, "/");
00174   if ( $pos >= 0 ) {
00175     return substr($file, 0, ($pos + 1));
00176   } else {
00177     return "./";
00178   }
00179 }
00180 
00181 
00182 # return the base file name
00183 sub file_basename {
00184   my($file) = @_;
00185   my($pos);
00186   
00187   $pos = rindex($file, "/");
00188   return substr($file, ($pos + 1));
00189 }
00190 
00191 
00192 # return the file name root (ending at last ".")
00193 sub file_root {
00194   my($file) = @_;
00195   my($pos);
00196   
00197   $pos = rindex($file, ".");
00198   return substr($file, 0, $pos);
00199 }
00200 
00201 
00202 # return the file name extension (starting at first ".")
00203 sub file_extension {
00204   my($file) = @_;
00205   my($pos);
00206   
00207   $pos = rindex($file, ".");
00208   return substr($file, ($pos + 1));
00209 }
00210 
00211 
00212 # return current date in a nice format
00213 sub nice_date {
00214   my($date_fmt) = @_;
00215   
00216   my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 
00217     localtime(time());
00218 
00219   # right now we're only going to deal with yyyymmdd.  We'll change
00220   # this soon.
00221 
00222   return(sprintf("%04d", 1900 + $year) .
00223          sprintf("%02d", $mon + 1) .
00224          sprintf("%02d", $mday)); 
00225 
00226   #if ( $date_fmt eq 'usa' ) {
00227   #  return &pad($mon+1) . "/" . &pad($mday) . "/" . &pad($year);
00228   #} else {
00229   #  return &pad($mday) . "." . &pad($mon+1) . "." . &pad($year);
00230   #}
00231 }
00232 
00233 
00234 # return current date in a raw format
00235 sub raw_date {
00236   my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 
00237     localtime(time);
00238   return &century() . &pad($year) . &pad($mon+1) . &pad($mday);
00239 }
00240 
00241 # start date: return date in raw format, takes argument of those types:
00242 # -[num]m months (eg. "-0m" means only current month, "-1m" means current and last)
00243 # -[num]d days (eg. "-10m" means 10 days)
00244 # dd.mm.yy[yy] : "international" format
00245 # mm/dd/yy[yy] : "us" format
00246 # yyyymmdd     : "raw" format
00247 #
00248 # This can get a bit complicated, thank god we don't have to care whether
00249 # we return invalid days
00250 
00251 sub start_date {
00252   my($idate) = @_;
00253   my($odate, $value);
00254   my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = 
00255     localtime(time);
00256   
00257   $mon = $mon + 1;
00258   
00259   if ( $idate =~ /^\d{8}$/ ) {   # "raw" format
00260     $odate = $idate;
00261   } elsif ($idate =~ /^-\d{1,2}m$/ ) {  # "month" format
00262     
00263     $value = substr($idate, 1, 3);  # a maximum of 99 months !
00264     if ($value >= $mon) {
00265       $year = $year - 1 - int( ($value - $mon) / 12 );
00266       $value = ($value % 12 );
00267     }
00268     $mon = $mon - $value;
00269     if ($mon < 1) {
00270       $value = $value + 12; 
00271     }
00272     $odate = &century() . &pad($year) . &pad($mon) . &pad(1);
00273     
00274   } elsif ($idate =~ /^-\d{1,3}d$/ ) {  # "day" format
00275     
00276     $value = substr($idate, 1, 4);  # a maximum of 999 days !
00277     if ($value >= $yday) {
00278       $year = $year - 1 - int( ($value - $yday) / 360 );
00279       $value = ( $value % 360 );
00280     }
00281     if ($value >= $mday) {
00282       $mon = $mon - 1 - int( ($value - $mday) / 30 );
00283       if ($mon < 1) {
00284         $mon = $mon + 12;
00285       }
00286       $value = ( $value % 30 );
00287     }
00288     $mday = $mday - $value;
00289     if ($mday < 1) {
00290       $mday = $mday + 30;
00291     }
00292     $odate = &century() . &pad($year) . &pad($mon) . &pad($mday);
00293     
00294   } elsif ( $idate =~ /^\d{1,2}\/\d{1,2}\/\d{2,4}$/ ) {   # "us" format
00295     
00296     ($mon, $mday, $year) = split(/\//, $idate);
00297     if ($year < 100) {
00298       $value = &century();
00299     } else {
00300       $value = $year / 100;
00301     }
00302     $odate = &pad($value) . &pad($year) . &pad($mon) . &pad($mday);
00303     
00304   } elsif ( $idate =~ /^\d{1,2}\.\d{1,2}\.\d{2,4}$/ ) {   # "int" format
00305     
00306     ($mday, $mon, $year) = split(/\./, $idate);
00307     if ($year < 100) {
00308       $value = &century();
00309     } else {
00310       $value = $year / 100;
00311     }
00312     $odate = &pad($value) . &pad($year) . &pad($mon) . &pad($mday);
00313     
00314   } else {  # nonsense, give them everything since 1900
00315     $odate = "19000101";
00316   }
00317   
00318   return ($odate);
00319 }
00320 
00321 # return the current century in the form 19, 20, 21, etc.
00322 # requires the Unix "date" command to be in the path
00323 sub century {
00324   my($unix_date, $year, $century, $junk);
00325   
00326   $unix_date = localtime;  # e.g. "Thu Oct  3 16:53:37 1996"
00327   ($junk, $junk, $junk, $junk, $year) = split(/\s+/, $unix_date);
00328   $century = substr($year, 0, 2);
00329   
00330   return($century);
00331 }
00332 
00333 
00334 sub mypwd {
00335   my $dir = `pwd`;
00336   chomp($dir);
00337   return $dir;
00338 }
00339 
00340 
00341 1;        # need to return a true value
00342 __END__
00343 
00344 ## @endcond
00345 # ----------------------------------------------------------------------------
00346 # $Log$
00347 # Revision 1.1  2000/06/02 09:00:14  peticolas
00348 # Rob Browning's patch to add automake.
00349 #
00350 # Revision 1.2  1999/01/17 17:05:59  linas
00351 # patch from  msimons@fsimons01.erols.com (Mike Simons)
00352 #
00353 # Revision 1.1  1998/04/22 03:02:38  linas
00354 # CBB conversion tools from Rob Browning
00355 #
00356 # Revision 1.3  1998/01/24 02:21:24  rlb
00357 # Many changes.  Hopefully I'll be better about commits now.
00358 #
00359 # Revision 1.2  1997/10/22 03:46:00  rlb
00360 # Working (before txn data stucture switch)
00361 #
00362 # Revision 1.1  1997/10/10 18:15:53  rlb
00363 # Initial submission
00364 #
00365 # Revision 2.5  1996/12/17 14:53:54  curt
00366 # Updated copyright date.
00367 #
00368 # Revision 2.4  1996/12/14 17:15:21  curt
00369 # The great overhaul of December '96.
00370 #
00371 # Revision 2.3  1996/12/11 18:33:31  curt
00372 # Ran a spell checker.
00373 #
00374 # Revision 2.2  1996/12/08 07:39:58  curt
00375 # Rearranged quite a bit of code.
00376 # Put most global variables in cbb() structure.
00377 #
00378 # Revision 2.1  1996/12/07 20:38:14  curt
00379 # Renamed *.tk -> *.tcl
00380 #
00381 # Revision 2.3  1996/09/30 15:14:36  curt
00382 # Updated CBB URL, and hardwired wish path.
00383 #
00384 # Revision 2.2  1996/07/13 02:57:39  curt
00385 # Version 0.65
00386 # Packing Changes
00387 # Documentation changes
00388 # Changes to handle a value in both debit and credit fields.
00389 #
00390 # Revision 2.1  1996/02/27  05:35:38  curt
00391 # Just stumbling around a bit with cvs ... :-(
00392 #
00393 # Revision 2.0  1996/02/27  04:41:50  curt
00394 # Initial 2.0 revision.  (See "Log" files for old history.)
00395 
00396 
00397 
00398 # ----------------------------------------------------------------------------
00399 # $Log$
00400 # Revision 1.1  2000/06/02 09:00:14  peticolas
00401 # Rob Browning's patch to add automake.
00402 #
00403 # Revision 1.2  1999/01/17 17:05:59  linas
00404 # patch from  msimons@fsimons01.erols.com (Mike Simons)
00405 #
00406 # Revision 1.1  1998/04/22 03:02:38  linas
00407 # CBB conversion tools from Rob Browning
00408 #
00409 # Revision 1.3  1998/01/24 02:21:24  rlb
00410 # Many changes.  Hopefully I'll be better about commits now.
00411 #
00412 # Revision 1.2  1997/10/22 03:46:00  rlb
00413 # Working (before txn data stucture switch)
00414 #
00415 # Revision 1.1  1997/10/10 18:15:53  rlb
00416 # Initial submission
00417 #
00418 # Revision 2.11  1997/05/06 01:00:26  curt
00419 # Added patches contributed by Martin Schenk <schenkm@ping.at>
00420 # - Default to umask of 066 so .CBB files get created rw by owner only
00421 # - Added support for pgp encrypting data files
00422 # - Added support for displaying only recent parts of files (avoids
00423 #   waiting to load in lots of old txns you don't currently need.)
00424 # - Added a feature to "cache" whole accounts in the perl engine so
00425 #   that switching between accounts can be faster.
00426 # - The above options can be turned on/off via the preferrences menu.
00427 #
00428 # Revision 2.10  1997/01/18 03:28:41  curt
00429 # Added "use strict" pragma to enforce good scoping habits.
00430 #
00431 # Revision 2.9  1996/12/17 14:53:54  curt
00432 # Updated copyright date.
00433 #
00434 # Revision 2.8  1996/12/11 18:33:30  curt
00435 # Ran a spell checker.
00436 #
00437 # Revision 2.7  1996/10/03 22:02:25  curt
00438 # I found a way in perl to get the century directly, so I was able to
00439 # eliminate the dependency on the external Unix date command.
00440 #
00441 # Revision 2.6  1996/10/03 04:48:59  curt
00442 # Fixed an inconsistency in &raw_date() in common.pl (with how it was
00443 # called.)
00444 #
00445 # Version now is 0.67-beta-x
00446 #
00447 # Revision 2.5  1996/10/03 04:13:39  curt
00448 # Refined default century handling code.
00449 #
00450 # Revision 2.4  1996/10/03 03:52:57  curt
00451 # CBB now determines the current century automatically ... no need for it
00452 # to be hard coded.  Removed all hardcoded instances of the century (especially
00453 # in reports.pl and recur.pl)
00454 #
00455 # Added an optional --debug flag to the invocation of CBB.
00456 #
00457 # Revision 2.3  1996/10/02 19:37:18  curt
00458 # Replaced instances of hardcoded century (19) with a variable.  We need to
00459 # know the current century in cases where it is not provided and it is
00460 # assumed to be the current century.  Someday I need to figure out how
00461 # to determine the current century, but I have a couple of years to do it. :-)
00462 #
00463 # I still need to fix conf-reports and reports.pl
00464 #
00465 # Revision 2.2  1996/07/13 02:57:39  curt
00466 # Version 0.65
00467 # Packing Changes
00468 # Documentation changes
00469 # Changes to handle a value in both debit and credit fields.
00470 #
00471 # Revision 2.1  1996/02/27  05:35:37  curt
00472 # Just stumbling around a bit with cvs ... :-(
00473 #
00474 # Revision 2.0  1996/02/27  04:41:50  curt
00475 # Initial 2.0 revision.  (See "Log" files for old history.)
00476 
00477 
00478 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines