|
GnuCash 2.4.99
|
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 ¢ury() . &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 = ¢ury() . &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 = ¢ury() . &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 = ¢ury(); 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 = ¢ury(); 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
1.7.4