GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
common.pl
Go to the documentation of this file.
1 #!/usr/bin/perl -w
2 # common.pl - common routines shared by many CBB files
3 #
4 # Written by Curtis Olson. Started August 22, 1994.
5 #
6 # Copyright (C) 1994 - 1997 Curtis L. Olson - [email protected]
7 #
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 # $Id$
23 # (Log is kept at end of this file)
24 
25 ## @file
26 # @brief common routines shared by many CBB files
27 # @author Curtis Olson
28 # @date Started August 22, 1994
29 # @cond PERL
30 # ignore the following for doxygen
31 
32 use strict;
33 
34 sub destructive_merge_mangle {
35  my($destination_ref, $source_ref, $comparison, $mangler) = @_;
36  # Merges elements of destination into source according to the
37  # comparison function. Assumes that both source and destination
38  # are already sorted wrt comparison.
39 
40  # mangler is optional, but if provided will be called for each
41  # element of the modified destination with the args
42  # ($destination_ref, $index, $new_item_p). You can check for undef
43  # on the next or previous index values to see if you're inserting at
44  # the end/beginning of the list.
45 
46  # returns the indexes (in the new list) of the txns that were
47  # inserted
48 
49  my @inserted_indices = ();
50  my @source = @$source_ref;
51  my $src_head = shift @source;
52  my $current_splice_pos = 0;
53  my $dest_items_left = scalar(@$destination_ref);
54  my $next_dest = $$destination_ref[$current_splice_pos];
55  while($src_head && $dest_items_left) {
56  if(&$comparison($next_dest, $src_head) == 1) {
57  # i.e. next_dest > src_head
58  splice @$destination_ref, $current_splice_pos, 0, $src_head;
59  push @inserted_indices, $current_splice_pos;
60  &$mangler($destination_ref, $current_splice_pos, 1) if $mangler;
61  $src_head = shift @source;
62  $current_splice_pos++;
63  } else {
64  &$mangler($destination_ref, $current_splice_pos, 0) if $mangler;
65  $current_splice_pos++;
66  $next_dest = $$destination_ref[$current_splice_pos];
67  $dest_items_left--;
68  }
69  }
70  if($src_head) {
71  push @$destination_ref, $src_head, @source;
72  my $tail;
73  foreach $tail ($src_head, @source) {
74  &$mangler($destination_ref, $current_splice_pos, 1) if $mangler;
75  push @inserted_indices, $current_splice_pos;
76  $current_splice_pos++;
77  }
78  } else {
79  # Must be some destination_ref items left.
80  while ($dest_items_left) {
81  &$mangler($destination_ref, $current_splice_pos, 0) if $mangler;
82  $current_splice_pos++;
83  $dest_items_left--;
84  }
85  }
86  return \@inserted_indices;
87 }
88 
89 sub destructive_remove_mangle {
90  my($destination_ref, $source_ref, $comparison, $mangler) = @_;
91 
92  # Removes elements of source from destination according to the
93  # comparison function which is just boolean. Assumes that source
94  # items are in the same order in source_ref as they are in
95  # destination_ref
96 
97  # mangler is optional, but if provided will be called for each item
98  # in the new destination list with the args:
99 
100  # ($killed_p, $destination_ref, $index, $old_item). If killed is true
101  # ($killed_p, $destination_ref, $index). If killed is false
102 
103  # if killed is true, index is the delete pos, while if false, it's
104  # the new index. You can check for undef on the next or previous
105  # index values to see if you're at the end/beginning of the list.
106 
107  my @removed_indices = ();
108  my $old_position = 0;
109  my @source = @$source_ref;
110  my $src_head = shift @source;
111  my $current_splice_pos = 0;
112  my $dest_items_left = scalar(@$destination_ref);
113  my $next_dest = $$destination_ref[$current_splice_pos];
114  while($src_head && $dest_items_left) {
115  if(&$comparison($next_dest, $src_head)) {
116  # found an item to delete.
117  splice @$destination_ref, $current_splice_pos, 1;
118  &$mangler(1, $destination_ref, $current_splice_pos, $src_head)
119  if $mangler;
120  $src_head = shift @source;
121  push @removed_indices, $old_position;
122  } else {
123  &$mangler(0, $destination_ref, $current_splice_pos) if $mangler;
124  $current_splice_pos++;
125  }
126  $old_position++;
127  $dest_items_left--;
128  $next_dest = $$destination_ref[$current_splice_pos];
129  }
130  if($src_head) {
131  print STDERR
132  "Warning: source items left after destructive_remove_mangle\n";
133  }
134  if($mangler && $dest_items_left) {
135  while($dest_items_left) {
136  &$mangler(0, $destination_ref, $current_splice_pos);
137  $current_splice_pos++;
138  $dest_items_left--;
139  }
140  }
141  return \@removed_indices;
142 }
143 
144 sub timestamp {
145  my($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime(time);
146  $month++; # don't want 0 based months.
147  $month = "0" . $month if $month < 10;
148  $mday = "0" . $mday if $mday < 10;
149  $hour = "0" . $hour if $hour < 10;
150  $min = "0" . $min if $min < 10;
151  $sec = "0" . $sec if $sec < 10;
152  $year += 1900;
153 
154  return("$year-$month-$mday-$hour-$min-$sec");
155 }
156 
157 # We need a version number
158 $CBB::version = "Version <not_installed>";
159 ($CBB::junk, $CBB::version_num, $CBB::junk) = split(/ +/, $CBB::version);
160 
161 
162 # Contributed by Christopher Browne, Oct. 24/94
163 sub pad {
164  return sprintf("%02d", $_[0]);
165 }
166 
167 
168 # return the directory of a file name
169 sub file_dirname {
170  my($file) = @_;
171  my($pos);
172 
173  $pos = rindex($file, "/");
174  if ( $pos >= 0 ) {
175  return substr($file, 0, ($pos + 1));
176  } else {
177  return "./";
178  }
179 }
180 
181 
182 # return the base file name
183 sub file_basename {
184  my($file) = @_;
185  my($pos);
186 
187  $pos = rindex($file, "/");
188  return substr($file, ($pos + 1));
189 }
190 
191 
192 # return the file name root (ending at last ".")
193 sub file_root {
194  my($file) = @_;
195  my($pos);
196 
197  $pos = rindex($file, ".");
198  return substr($file, 0, $pos);
199 }
200 
201 
202 # return the file name extension (starting at first ".")
203 sub file_extension {
204  my($file) = @_;
205  my($pos);
206 
207  $pos = rindex($file, ".");
208  return substr($file, ($pos + 1));
209 }
210 
211 
212 # return current date in a nice format
213 sub nice_date {
214  my($date_fmt) = @_;
215 
216  my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
217  localtime(time());
218 
219  # right now we're only going to deal with yyyymmdd. We'll change
220  # this soon.
221 
222  return(sprintf("%04d", 1900 + $year) .
223  sprintf("%02d", $mon + 1) .
224  sprintf("%02d", $mday));
225 
226  #if ( $date_fmt eq 'usa' ) {
227  # return &pad($mon+1) . "/" . &pad($mday) . "/" . &pad($year);
228  #} else {
229  # return &pad($mday) . "." . &pad($mon+1) . "." . &pad($year);
230  #}
231 }
232 
233 
234 # return current date in a raw format
235 sub raw_date {
236  my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
237  localtime(time);
238  return &century() . &pad($year) . &pad($mon+1) . &pad($mday);
239 }
240 
241 # start date: return date in raw format, takes argument of those types:
242 # -[num]m months (eg. "-0m" means only current month, "-1m" means current and last)
243 # -[num]d days (eg. "-10m" means 10 days)
244 # dd.mm.yy[yy] : "international" format
245 # mm/dd/yy[yy] : "us" format
246 # yyyymmdd : "raw" format
247 #
248 # This can get a bit complicated, thank god we don't have to care whether
249 # we return invalid days
250 
251 sub start_date {
252  my($idate) = @_;
253  my($odate, $value);
254  my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
255  localtime(time);
256 
257  $mon = $mon + 1;
258 
259  if ( $idate =~ /^\d{8}$/ ) { # "raw" format
260  $odate = $idate;
261  } elsif ($idate =~ /^-\d{1,2}m$/ ) { # "month" format
262 
263  $value = substr($idate, 1, 3); # a maximum of 99 months !
264  if ($value >= $mon) {
265  $year = $year - 1 - int( ($value - $mon) / 12 );
266  $value = ($value % 12 );
267  }
268  $mon = $mon - $value;
269  if ($mon < 1) {
270  $value = $value + 12;
271  }
272  $odate = &century() . &pad($year) . &pad($mon) . &pad(1);
273 
274  } elsif ($idate =~ /^-\d{1,3}d$/ ) { # "day" format
275 
276  $value = substr($idate, 1, 4); # a maximum of 999 days !
277  if ($value >= $yday) {
278  $year = $year - 1 - int( ($value - $yday) / 360 );
279  $value = ( $value % 360 );
280  }
281  if ($value >= $mday) {
282  $mon = $mon - 1 - int( ($value - $mday) / 30 );
283  if ($mon < 1) {
284  $mon = $mon + 12;
285  }
286  $value = ( $value % 30 );
287  }
288  $mday = $mday - $value;
289  if ($mday < 1) {
290  $mday = $mday + 30;
291  }
292  $odate = &century() . &pad($year) . &pad($mon) . &pad($mday);
293 
294  } elsif ( $idate =~ /^\d{1,2}\/\d{1,2}\/\d{2,4}$/ ) { # "us" format
295 
296  ($mon, $mday, $year) = split(/\//, $idate);
297  if ($year < 100) {
298  $value = &century();
299  } else {
300  $value = $year / 100;
301  }
302  $odate = &pad($value) . &pad($year) . &pad($mon) . &pad($mday);
303 
304  } elsif ( $idate =~ /^\d{1,2}\.\d{1,2}\.\d{2,4}$/ ) { # "int" format
305 
306  ($mday, $mon, $year) = split(/\./, $idate);
307  if ($year < 100) {
308  $value = &century();
309  } else {
310  $value = $year / 100;
311  }
312  $odate = &pad($value) . &pad($year) . &pad($mon) . &pad($mday);
313 
314  } else { # nonsense, give them everything since 1900
315  $odate = "19000101";
316  }
317 
318  return ($odate);
319 }
320 
321 # return the current century in the form 19, 20, 21, etc.
322 # requires the Unix "date" command to be in the path
323 sub century {
324  my($unix_date, $year, $century, $junk);
325 
326  $unix_date = localtime; # e.g. "Thu Oct 3 16:53:37 1996"
327  ($junk, $junk, $junk, $junk, $year) = split(/\s+/, $unix_date);
328  $century = substr($year, 0, 2);
329 
330  return($century);
331 }
332 
333 
334 sub mypwd {
335  my $dir = `pwd`;
336  chomp($dir);
337  return $dir;
338 }
339 
340 
341 1; # need to return a true value
342 __END__
343 
344 ## @endcond
345 # ----------------------------------------------------------------------------
346 # $Log$
347 # Revision 1.1 2000/06/02 09:00:14 peticolas
348 # Rob Browning's patch to add automake.
349 #
350 # Revision 1.2 1999/01/17 17:05:59 linas
351 # patch from [email protected] (Mike Simons)
352 #
353 # Revision 1.1 1998/04/22 03:02:38 linas
354 # CBB conversion tools from Rob Browning
355 #
356 # Revision 1.3 1998/01/24 02:21:24 rlb
357 # Many changes. Hopefully I'll be better about commits now.
358 #
359 # Revision 1.2 1997/10/22 03:46:00 rlb
360 # Working (before txn data stucture switch)
361 #
362 # Revision 1.1 1997/10/10 18:15:53 rlb
363 # Initial submission
364 #
365 # Revision 2.5 1996/12/17 14:53:54 curt
366 # Updated copyright date.
367 #
368 # Revision 2.4 1996/12/14 17:15:21 curt
369 # The great overhaul of December '96.
370 #
371 # Revision 2.3 1996/12/11 18:33:31 curt
372 # Ran a spell checker.
373 #
374 # Revision 2.2 1996/12/08 07:39:58 curt
375 # Rearranged quite a bit of code.
376 # Put most global variables in cbb() structure.
377 #
378 # Revision 2.1 1996/12/07 20:38:14 curt
379 # Renamed *.tk -> *.tcl
380 #
381 # Revision 2.3 1996/09/30 15:14:36 curt
382 # Updated CBB URL, and hardwired wish path.
383 #
384 # Revision 2.2 1996/07/13 02:57:39 curt
385 # Version 0.65
386 # Packing Changes
387 # Documentation changes
388 # Changes to handle a value in both debit and credit fields.
389 #
390 # Revision 2.1 1996/02/27 05:35:38 curt
391 # Just stumbling around a bit with cvs ... :-(
392 #
393 # Revision 2.0 1996/02/27 04:41:50 curt
394 # Initial 2.0 revision. (See "Log" files for old history.)
395 
396 
397 
398 # ----------------------------------------------------------------------------
399 # $Log$
400 # Revision 1.1 2000/06/02 09:00:14 peticolas
401 # Rob Browning's patch to add automake.
402 #
403 # Revision 1.2 1999/01/17 17:05:59 linas
404 # patch from [email protected] (Mike Simons)
405 #
406 # Revision 1.1 1998/04/22 03:02:38 linas
407 # CBB conversion tools from Rob Browning
408 #
409 # Revision 1.3 1998/01/24 02:21:24 rlb
410 # Many changes. Hopefully I'll be better about commits now.
411 #
412 # Revision 1.2 1997/10/22 03:46:00 rlb
413 # Working (before txn data stucture switch)
414 #
415 # Revision 1.1 1997/10/10 18:15:53 rlb
416 # Initial submission
417 #
418 # Revision 2.11 1997/05/06 01:00:26 curt
419 # Added patches contributed by Martin Schenk <[email protected]>
420 # - Default to umask of 066 so .CBB files get created rw by owner only
421 # - Added support for pgp encrypting data files
422 # - Added support for displaying only recent parts of files (avoids
423 # waiting to load in lots of old txns you don't currently need.)
424 # - Added a feature to "cache" whole accounts in the perl engine so
425 # that switching between accounts can be faster.
426 # - The above options can be turned on/off via the preferrences menu.
427 #
428 # Revision 2.10 1997/01/18 03:28:41 curt
429 # Added "use strict" pragma to enforce good scoping habits.
430 #
431 # Revision 2.9 1996/12/17 14:53:54 curt
432 # Updated copyright date.
433 #
434 # Revision 2.8 1996/12/11 18:33:30 curt
435 # Ran a spell checker.
436 #
437 # Revision 2.7 1996/10/03 22:02:25 curt
438 # I found a way in perl to get the century directly, so I was able to
439 # eliminate the dependency on the external Unix date command.
440 #
441 # Revision 2.6 1996/10/03 04:48:59 curt
442 # Fixed an inconsistency in &raw_date() in common.pl (with how it was
443 # called.)
444 #
445 # Version now is 0.67-beta-x
446 #
447 # Revision 2.5 1996/10/03 04:13:39 curt
448 # Refined default century handling code.
449 #
450 # Revision 2.4 1996/10/03 03:52:57 curt
451 # CBB now determines the current century automatically ... no need for it
452 # to be hard coded. Removed all hardcoded instances of the century (especially
453 # in reports.pl and recur.pl)
454 #
455 # Added an optional --debug flag to the invocation of CBB.
456 #
457 # Revision 2.3 1996/10/02 19:37:18 curt
458 # Replaced instances of hardcoded century (19) with a variable. We need to
459 # know the current century in cases where it is not provided and it is
460 # assumed to be the current century. Someday I need to figure out how
461 # to determine the current century, but I have a couple of years to do it. :-)
462 #
463 # I still need to fix conf-reports and reports.pl
464 #
465 # Revision 2.2 1996/07/13 02:57:39 curt
466 # Version 0.65
467 # Packing Changes
468 # Documentation changes
469 # Changes to handle a value in both debit and credit fields.
470 #
471 # Revision 2.1 1996/02/27 05:35:37 curt
472 # Just stumbling around a bit with cvs ... :-(
473 #
474 # Revision 2.0 1996/02/27 04:41:50 curt
475 # Initial 2.0 revision. (See "Log" files for old history.)
476 
477 
478