home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl
- # engine.pl - the CBB 'engine'.
- # This script implements a transaction abstract data type
- # It encapsulates a list a transactions and the functions
- # required to manipulate the transactions.
- #
- # Written by Curtis Olson. Started August 22, 1994.
- #
- # Copyright (C) 1994 - 1997 Curtis L. Olson - curt@sledge.mn.org
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- # $Id: engine.pl,v 2.20 1998/08/14 14:30:11 curt Exp $
- # (Log is kept at end of this file)
-
-
- package CBB;
-
- use strict; # don't take no guff
-
-
- # @INC specifies the installed location of the necessary pieces.
- # It should already be setup by wrapper.pl
-
- require "common.pl";
- require "log.pl";
-
-
- $| = 1; # flush buffers after every write
-
- if ( $CBB::logging != 0 && $CBB::logging != 1) {
- # if not specified elsewhere, turn on logging
- $CBB::logging = 1; # 0 = off, 1 = on
- }
-
- if ( $CBB::debug != 0 && $CBB::debug != 1) {
- # if not specified elsewhere, turn off debugging.
- $CBB::debug = 0; # 0 = off, 1 = on
- }
-
- # Global variables
-
- # %CBB::TRANS - an associative array of transactions and transaction keys
- # @CBB::KEYS - a sorted list of transaction keys (for traversing the trans list)
- # $CBB::sorted_keys - specifies whether the list in @CBB::KEYS is valid
- # $CBB::calced - specified whether the transactions have been properly calculated
- # $CBB::current - specifies the "current" position in the @CBB::KEYS array
- # $CBB::current_file - full name of currently opened transaction file
- # %CBB::BALS - an associative array used to store account information
- # $CBB::version - version number (set in common.pl)
-
-
- &init_trans(); # initialize %CBB::TRANS, @CBB::KEYS, and $CBB::sorted_keys
- open(DEBUG, ">debug") if $CBB::debug;
-
-
- # toggle debugging
- sub debug {
- # in: flag
- # out: flag
-
- my($newdebug) = @_;
-
- if ($newdebug == 1) {
- # turning debugging on
-
- if ($CBB::debug == 1) {
- # already on, do nothing
- } else {
- $CBB::debug = 1;
- open(DEBUG, ">debug");
- }
- } else {
- # turning of debugging
-
- if ($CBB::debug == 0) {
- # already off, do nothing
- } else {
- $CBB::debug = 0;
- close(DEBUG);
- }
- }
-
- return $CBB::debug;
- }
-
-
- # get next available key for a specified date
- sub get_next_key {
- # in: date
- # out: key
-
- my($date) = @_;
- my($count) = 0;
-
- while ( $CBB::TRANS{"$date-".&pad($count)} ) {
- $count++;
- }
-
- return "$date-".&pad($count);
- }
-
-
- # set @CBB::KEYS = sorted list of transaction keys
- sub sort_keys {
- $CBB::sorted_keys = 1;
- $CBB::current = 0;
-
- print DEBUG "sort_keys()\n" if $CBB::debug;
- @CBB::KEYS = sort(keys %CBB::TRANS);
- }
-
-
- # recalculate the transactions
- sub calc_trans {
- my($total, $ntotal, $stotal, $ctotal) = (0.00, 0.00, 0.00, 0.00);
- my($count, $ncount, $scount, $ccount) = (0, 0, 0, 0);
- my($key);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk);
-
- my($current_date) = &raw_date();
-
- $CBB::calced = 1;
-
- print DEBUG "calc_trans()\n" if $CBB::debug;
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- $CBB::BALS{"Current"} = 0.00;
-
- foreach $key (@CBB::KEYS) {
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared,
- $junk) = split(/\t/, $CBB::TRANS{$key});
-
- $total = $total + $credit - $debit;
- $count++;
-
- if ( $date <= $current_date ) {
- $CBB::BALS{"Current"} = $total;
- }
-
- if ( ($cleared eq "x") || ($cleared eq "X") ) {
- $ctotal = $ctotal + $credit - $debit;
- $ccount++;
- } elsif ( $cleared eq "*" ) {
- $stotal = $stotal + $credit - $debit;
- $scount++;
- } else {
- $ntotal = $ntotal + $credit - $debit;
- $ncount++;
- }
-
- $CBB::TRANS{$key} =
- "$date\t$check\t$desc\t$debit\t$credit\t$cat\t$com\t$cleared\t".
- sprintf("%.2f", $total);
- }
-
- $CBB::BALS{"Amount"} = $total;
- $CBB::BALS{"Count"} = $count;
-
- $CBB::BALS{"Xamount"} = $ctotal;
- $CBB::BALS{"Xcount"} = $ccount;
-
- $CBB::BALS{"*amount"} = $stotal;
- $CBB::BALS{"*count"} = $scount;
-
- $CBB::BALS{"Namount"} = $ntotal;
- $CBB::BALS{"Ncount"} = $ncount;
- }
-
-
- # create a transaction (and add to the transaction list)
- sub create_trans {
- # in: transaction
- # out: keyed_transaction
-
- my($trans) = @_;
- my($key);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- &insert_and_update_mem($trans);
-
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $trans);
-
- if ( length($date) == 6 ) {
- # for backwards compatibility ... shouldn't be needed now.
- $date = "19$date";
- }
-
- $key = &get_next_key($date);
-
- $trans = "$date\t$check\t$desc\t$debit\t$credit\t$cat\t$com\t$cleared\t$total";
-
- $CBB::TRANS{$key} = "$trans";
-
- print DEBUG "created: $key\t$trans\n" if $CBB::debug;
-
- return "$key\t$trans";
- }
-
-
- # create a transfer transaction in the current file and the transfer to file
- sub create_xfer {
- # in: transaction
- # out: keyed_transaction
-
- my($trans) = @_;
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $trans);
- my($orig_file) = $CBB::current_file;
- my($to_trans, $to_file, $from_cat);
- my($key, $result);
- my($returned_result);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- print DEBUG "(xfer) current_file = $CBB::current_file\n" if $CBB::debug;
- # determine the "from" category
- $from_cat = "[".&file_basename(&file_root($CBB::current_file))."]";
-
- # determine the "to" file name
- $to_file = $cat;
- chop($to_file);
- $to_file = substr($to_file, 1);
- $to_file = &file_dirname($CBB::current_file)."/$to_file";
- print DEBUG "to file = '$to_file' ($to_file.cbb)\n" if $CBB::debug;
- if ( -e "$to_file.cbb" ) {
- $to_file .= ".cbb";
- } elsif ( -e "$to_file.dir" ) {
- $to_file .= ".dir";
- } else {
- return "error";
- }
-
- print DEBUG "Transfer to $to_file\n" if $CBB::debug;
-
- # create the "to" transaction
- $to_trans = "$date\t$check\t$desc\t".$credit."\t".$debit."\t".
- $from_cat."\t$com\t$cleared\t$total";
-
- # we need special handling here to preserve the .cbb file
- # save the current transactions to a temporary file
- # before loading the "to" account
- $result = &save_trans("$orig_file.$$.tmp");
- return "error" if ( $result eq "error" );
- %CBB::TRANS = (); # clear out any transactions from the current file
-
- # open the "to" account
- $result = &load_trans($to_file);
- return "error" if ( $result eq "error" );
-
- $result = &create_trans($to_trans);
-
- $result = &save_trans($to_file);
-
- $result = &load_cbb_trans("$orig_file.$$.tmp");
- return "error" if ( $result eq "error" );
- unlink("$orig_file.$$.tmp");
- $CBB::current_file = $orig_file;
-
- # create the "from" transaction
- $returned_result = &create_trans($trans);
-
- return "$returned_result";
- }
-
-
- # update a transaction (replace in the transaction list)
- sub update_trans {
- # in: keyed_transaction
- # out: keyed_transaction
-
- my($keyed_trans) = @_;
- my($key, $trans, $result);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- ($key, $trans) = split(/\t/, $keyed_trans, 2);
-
- &delete_trans($key);
- $result = &create_trans($trans);
-
- print DEBUG "updated: $key\n" if $CBB::debug;
- print DEBUG " to: $result\n" if $CBB::debug;
-
- return "$result";
- }
-
-
- # update a transfer transaction (replace in the transaction list)
- sub update_xfer {
- # in: keyed_transaction
- # out: keyed_transaction
-
- my($keyed_trans) = @_;
- my($key, $trans, $result);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- ($key, $trans) = split(/\t/, $keyed_trans, 2);
-
- &delete_xfer($key);
- $result = &create_xfer($trans);
-
- print DEBUG "updated: $key\n" if $CBB::debug;
- print DEBUG " to: $result\n" if $CBB::debug;
-
- return "$result";
- }
-
-
- # delete a transaction given the key
- sub delete_trans {
- # in: key
-
- my($key) = @_;
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- delete $CBB::TRANS{$key};
-
- if ($CBB::current > 0) {
- --$CBB::current;
- }
-
- print DEBUG "deleted: $key\n" if $CBB::debug;
-
- return "ok";
- }
-
- # delete an transfer transaction in the transfer to file
- sub delete_xfer {
- # in: key
-
- my($key) = @_;
- my($orig_file, $orig_current) = ($CBB::current_file, $CBB::current);
- my($count) = 0;
-
- my($to_file, $from_cat, $found_key, $found_trans);
- my($result);
-
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total)
- = split(/\t/, $CBB::TRANS{$key});
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- # determine the "from" category
- $from_cat = "[".&file_basename(&file_root($CBB::current_file))."]";
-
- # determine the "to" file name
- $to_file = $cat;
- chop($to_file);
- $to_file = substr($to_file, 1);
- $to_file = &file_dirname($CBB::current_file)."/$to_file";
- print DEBUG "to file = '$to_file' ($to_file.cbb)\n" if $CBB::debug;
- if ( -e "$to_file.cbb" ) {
- $to_file .= ".cbb";
- } else {
- return "error";
- }
-
- print DEBUG "Deleting transfer to $to_file\n" if $CBB::debug;
-
- # We need special handling here to preserve the .cbb file. Save
- # the current transactions to a temporary file before loading the
- # "to" account.
- $result = &save_trans("$orig_file.$$.tmp");
- return "error" if ( $result eq "error" );
-
- # open the "to" account
- $result = &load_trans($to_file);
- return "error" if ( $result eq "error" );
-
- # now search for the transaction
- while ( $found_trans = $CBB::TRANS{"$date-".&pad($count)} ) {
- my($found_date, $found_check, $found_desc, $found_debit,
- $found_credit, $found_cat, $found_com, $found_cleared,
- $found_total) = split(/\t/, $found_trans);
-
- last if (($found_check eq $check) &&
- ($found_desc eq $desc) &&
- ($found_debit == $credit) &&
- ($found_credit == $debit) &&
- ($found_com eq $com) &&
- ($found_cat eq $from_cat) &&
- ($found_key = "$date-".&pad($count)) );
-
- $count++;
- }
-
- print DEBUG "Found key: $found_key\n" if $CBB::debug;
-
- if ( $found_key ) {
- delete $CBB::TRANS{$found_key};
-
- $CBB::calced = 0;
- $CBB::sorted_keys = 0;
- } else {
- print DEBUG "Transaction not found in $to_file\n" if $CBB::debug;
- }
-
- # now save the "to" account
- $result = &save_trans($to_file);
-
- # revert to orig account
- $result = &load_cbb_trans("$orig_file.$$.tmp");
- return "error" if ( $result eq "error" );
- unlink("$orig_file.$$.tmp");
-
- # restore global variables
- $CBB::current_file = $orig_file;
- $CBB::current = $orig_current;
- $CBB::calced = 0;
- $CBB::sorted_keys = 0;
-
- delete $CBB::TRANS{$key};
-
- if ($CBB::current > 0) {
- --$CBB::current;
- }
-
- print DEBUG "deleted: $key\n" if $CBB::debug;
-
- return "ok";
- }
-
-
- # return the next transaction
- sub next_trans {
- my($trans);
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- ++$CBB::current;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- if ( $trans ) {
- return "$CBB::KEYS[$CBB::current]\t$trans";
- } else {
- return "none";
- }
- }
-
-
- # return the transaction specified by a key
- sub find_trans {
- # uses a binary search so that we can keep $CBB::current current.
- # Yeeeks! I have to think for a change.
- # Hmmm, maybe I should rethink my data structures ... nah. :)
-
- my($key) = @_;
- my($left, $middle, $right) = (0, 0, $#CBB::KEYS);
- my($trans);
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- $trans = "";
-
- while ( $left <= $right ) {
- $middle = int( ($left + $right) / 2 );
- print DEBUG "$left < $middle < $right\n" if $CBB::debug;
- if ( $CBB::KEYS[$middle] lt $key ) {
- $left = $middle + 1;
- print DEBUG " left = middle + 1\n" if $CBB::debug;
- } elsif ( $CBB::KEYS[$middle] gt $key ) {
- $right = $middle - 1;
- print DEBUG " right = middle - 1\n" if $CBB::debug;
- } else {
- # we found it, set $trans to what we want and force an exit of
- # the while loop
- $trans = $CBB::TRANS{$CBB::KEYS[$middle]};
- print DEBUG " found it: $trans\n" if $CBB::debug;
- $CBB::current = $middle;
- $left = $right + 1;
- }
- }
-
- print DEBUG "found: $key\t$trans\n" if $CBB::debug;
-
- if ( $trans ) {
- return "$key\t$trans";
- } else {
- return "none";
- }
- }
-
-
- # returns the current index
- sub get_current_index {
- return ($CBB::current + 1);
- }
-
-
- # return the first transaction
- sub first_trans {
- my($trans);
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- $CBB::current = 0;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- if ( $trans ) {
- return "$CBB::KEYS[$CBB::current]\t$trans";
- } else {
- return "none";
- }
- }
-
-
- # returns the entire transaction list in one big chunk.
- sub all_trans {
- # in: date
- # out: result
-
- my($date_fmt) = @_;
- my($key, $nicecat, $cutcom, $cutdesc, $cutcheck, $nicedate, $checklen);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
- my($day, $month, $year);
-
- $| = 0; # turn off buffer flushing
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- foreach $key (@CBB::KEYS) {
- # print ("$key\t$CBB::TRANS{$key}\n");
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $CBB::TRANS{$key});
-
- if ( length($date) == 6 ) {
- # for backwards compatibility ... shouldn't be needed now.
- ($year, $month, $day) = $date =~ /(\d\d)(\d\d)(\d\d)/;
- $year = "19" . $year;
- } else {
- ($year, $month, $day) = $date =~ /(\d\d\d\d)(\d\d)(\d\d)/
- }
-
- $checklen = length($check);
- if ( $checklen > 5 ) {
- $cutcheck = substr($check, $checklen - 5, 5);
- } else {
- $cutcheck = $check;
- }
-
- if ( $date_fmt == 1 ) {
- $nicedate = "$month/$day/" . substr($year, 2, 2);
- } else {
- $nicedate = "$day.$month." . substr($year, 2, 2);
- }
-
- $cutdesc = substr($desc, 0, 15);
- $cutcom = substr($com, 0, 15);
- if ( $cat =~ m/\|/ ) {
- $nicecat = "-Splits-";
- } else {
- $nicecat = $cat;
- }
- $nicecat = substr($nicecat, 0, 9);
-
- printf("%5s %-8s %-15s %9.2f %9.2f %-1s %10.2f %14s\n",
- $cutcheck, $nicedate, $cutdesc, $debit, $credit, $cleared,
- $total, $key);
- printf("%5s %-8s %-15s %-9s %39s\n", "", "", $cutcom, $nicecat,
- $key);
- }
-
- $| = 1; # turn buffer flushing back on
-
- return "none";
- }
-
- # returns part of the transaction list in one big chunk. (since a date)
- sub part_trans {
- # in: date
- # out: result
-
- my($sdate_fmt) = @_;
- my($left, $middle, $right) = (0, 0, $#CBB::KEYS);
- my($date_fmt, $sdate);
- my($key, $nicecat, $cutcom, $cutdesc, $cutcheck, $nicedate, $checklen);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
- my($day, $month, $year);
-
- # two arguments: data_format and start date
- ($date_fmt, $sdate) = split(" ", $sdate_fmt, 2);
-
- $| = 0; # turn off buffer flushing
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- # look for first key past starting with sdate (borrowed from find_trans)
- $sdate = "$sdate-".&pad(0);
-
- while ( $left <= $right ) {
- $middle = int( ($left + $right) / 2 );
- if ( $CBB::KEYS[$middle] lt $sdate ) {
- $left = $middle + 1;
- } elsif ( $CBB::KEYS[$middle] gt $sdate ) {
- $right = $middle - 1;
- } else {
- # we found it, force an exit of the while loop
- $left = $right + 1;
- }
- }
- if ($CBB::KEYS[$middle] != $sdate) {
- # we found the first past sdate
- $middle = $left;
- }
-
- for (; $middle <= $#CBB::KEYS ; ++$middle) {
- $key=$CBB::KEYS[$middle];
-
- # print ("$key\t$CBB::TRANS{$key}\n");
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $CBB::TRANS{$key});
-
- if ( length($date) == 6 ) {
- # for backwards compatibility ... shouldn't be needed now.
- ($year, $month, $day) = $date =~ /(\d\d)(\d\d)(\d\d)/;
- $year = "19" . $year;
- } else {
- ($year, $month, $day) = $date =~ /(\d\d\d\d)(\d\d)(\d\d)/
- }
-
- $checklen = length($check);
- if ( $checklen > 5 ) {
- $cutcheck = substr($check, $checklen - 5, 5);
- } else {
- $cutcheck = $check;
- }
-
- if ( $date_fmt == 1 ) {
- $nicedate = "$month/$day/" . substr($year, 2, 2);
- } else {
- $nicedate = "$day.$month." . substr($year, 2, 2);
- }
-
- $cutdesc = substr($desc, 0, 15);
- $cutcom = substr($com, 0, 15);
- if ( $cat =~ m/\|/ ) {
- $nicecat = "-Splits-";
- } else {
- $nicecat = $cat;
- }
- $nicecat = substr($nicecat, 0, 9);
-
- printf("%5s %-8s %-15s %9.2f %9.2f %-1s %10.2f %14s\n",
- $cutcheck, $nicedate, $cutdesc, $debit, $credit, $cleared,
- $total, $key);
- printf("%5s %-8s %-15s %-9s %39s\n", "", "", $cutcom, $nicecat,
- $key);
- }
-
- $| = 1; # turn buffer flushing back on
-
- return "none";
- }
-
- # return the first uncleared transaction
- sub first_uncleared_trans {
- my($trans);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk);
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- $CBB::current = 0;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk) =
- split(/\t/, $trans);
- while ( $cleared eq "x" ) {
- ++$CBB::current;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk) =
- split(/\t/, $trans);
- }
-
- if ( $trans ) {
- return "$CBB::KEYS[$CBB::current]\t$trans";
- } else {
- return "none";
- }
- }
-
-
- # return the next uncleared transaction
- sub next_uncleared_trans {
- my($trans);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk);
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- ++$CBB::current;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk) =
- split(/\t/, $trans);
- while ( $cleared eq "x" ) {
- ++$CBB::current;
- $trans = $CBB::TRANS{$CBB::KEYS[$CBB::current]};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $junk) =
- split(/\t/, $trans);
- }
-
- if ( $trans ) {
- return "$CBB::KEYS[$CBB::current]\t$trans";
- } else {
- return "none";
- }
- }
-
-
- # select transaction -- primes a transaction for future clearing
- sub select_trans {
- # in: key
- # out: keyed_transaction
-
- my($key) = @_;
- my($trans);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- $trans = $CBB::TRANS{$key};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $trans);
-
- $cleared = "*";
-
- $CBB::TRANS{$key} =
- "$date\t$check\t$desc\t$debit\t$credit\t$cat\t$com\t$cleared\t$total";
-
- print DEBUG "selected: $key to be cleared\n" if $CBB::debug;
-
- return "$key\t$CBB::TRANS{$key}";
- }
-
-
- # select transaction -- primes a transaction for future clearing
- sub unselect_trans {
- # in: key
- # out: keyed_transaction
-
- my($key) = @_;
- my($trans);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- $trans = $CBB::TRANS{$key};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $trans);
-
- $cleared = "";
-
- $CBB::TRANS{$key} =
- "$date\t$check\t$desc\t$debit\t$credit\t$cat\t$com\t$cleared\t$total";
-
- print DEBUG "unselected: $key will not be cleared\n" if $CBB::debug;
-
- return "$key\t$CBB::TRANS{$key}";
- }
-
-
- # clear all selected transactions
- sub clear_trans {
- my($key, $trans);
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total);
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- foreach $key (@CBB::KEYS) {
- $trans = $CBB::TRANS{$key};
- ($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $trans);
-
- if ( $cleared eq "*" ) {
- $cleared = "x";
-
- $CBB::TRANS{$key} =
- "$date\t$check\t$desc\t$debit\t$credit\t$cat\t$com\t$cleared\t$total";
- }
- }
- }
-
-
- # return the cleared balance (this should be the last statement ending bal)
- sub get_cleared_bal {
- return sprintf("%.2f", $CBB::BALS{"Xamount"});
- }
-
-
- # initialize the transactions data structure
- sub init_trans {
- # out: result
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
- @CBB::KEYS = ();
-
- return "ok";
- }
-
-
- # make a new account
- sub make_acct {
- # in: acct-name acct-desc acct-type
- # out: result
-
- my($name, $desc) = split(/ /, $_[0], 2);
- my($pos, $short_name);
-
- print DEBUG "Make account $name - $desc\n" if $CBB::debug;
- # print "Make account $name - $desc\n";
-
- print DEBUG "Making cbb account\n" if $CBB::debug;
-
- open(SAVE, ">$name.cbb.new");
- close(SAVE);
- unlink("$name.cbb.bak");
- rename("$name.cbb", "$name.cbb.bak");
- rename("$name.cbb.new", "$name.cbb");
-
- $CBB::current_file = "$name.cbb";
- %CBB::TRANS = ();
-
- # Assume we have category already open ... :| ??? :(
-
- # strip leading path from $name
- &insert_cat("[".&file_basename($name)."]\t$desc\t");
-
- # save the categories file before it gets toasted
- &save_cats(&file_dirname($name) . "/categories");
-
- return "ok";
- }
-
-
- # determine the file type and call the correct load routine
- sub load_trans {
- # in: file base
- # out: result
-
- my($file) = @_;
- my($ext) = &file_extension($file);
-
- # print "$ext\n";
- # print &file_root($file) . "\n";
-
- print DEBUG "file extension is: $ext\n" if $CBB::debug;
-
- if ($CBB::cache) {
- no strict 'vars'; # necessary for this special hack
- no strict 'refs';
-
- # save current data to cache
- my($hname) = "ACC_" . &file_basename($CBB::current_file);
- print DEBUG "$hname $CBB::current_file\n" if $CBB::debug;
- %$hname = %CBB::TRANS;
-
- # test if new table already in cache
- $hname = "ACC_" . &file_basename($file);
- print DEBUG "$hname\n" if $CBB::debug;
- if (scalar (%$hname) ) {
- print DEBUG "$hname defined , load from cache\n" if $CBB::debug;
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- %CBB::TRANS = %$hname; # take values from the cache
- &calc_trans();
-
- $CBB::current_file = $file;
-
- return "ok";
- }
- }
-
- return &load_cbb_trans($file);
- }
-
-
- # load the data from a cbb file
- sub load_cbb_trans {
- # in: file name (including .cbb extension)
- # out: result
-
- my($file) = @_;
- my($file_version) = "";
- my($junk);
-
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- print DEBUG "Loading the cbb format file: $file\n" if $CBB::debug;
-
- if ( $CBB::decrypt ne "" ) {
- open(LOAD, "$CBB::decrypt < $file|") || return "error";
- } else {
- open(LOAD, "<$file") || return "error";
- }
-
- %CBB::TRANS = (); # clear out any transactions from the previous file
-
- while ( <LOAD> ) {
- if ( m/^#/ ) {
- # toss the comment (but first check for any goodies.)
- if ( m/version/i ) {
- ($junk, $junk, $junk, $file_version) = split;
- print DEBUG "Data file version = $file_version\n" if $CBB::debug;
- }
- } else {
- if ( $file_version eq "") {
- print DEBUG "no data file version, file encrypted ?" if $CBB::debug;
- close(LOAD);
- return "error";
- }
- chop;
- if ( ! m/\t/ ) {
- s/:/\t/g;
- $_ = &fix_splits($_);
- }
- &create_trans($_);
- }
- }
-
- close(LOAD);
-
- &calc_trans();
-
- $CBB::current_file = $file;
-
- return "ok";
- }
-
-
- sub fix_splits {
- # in: transaction with old two field per record splits
- # out: transaction with new three field per record splits
-
- my($line) = @_;
- my($date, $check, $desc, $debit, $credit, $cat, $com, $cleared, $total) =
- split(/\t/, $line);
- my(@cats, $i, $max, $newcat);
-
- if ( $cat =~ m/\|/ ) {
- @cats = split(/\|/, $cat);
-
- $i = 0;
- $max = ($#cats - 1) / 2;
- $newcat = "|";
-
- while ( $i < $max ) {
- $newcat .= $cats[$i * 2 + 1] . "||" .
- $cats[$i * 2 + 2] . "|";
- $i++;
- }
- } else {
- $newcat = $cat;
- }
-
- return "$date\t$check\t$desc\t$debit\t$credit\t$newcat\t$com\t$cleared\t$total";
- }
-
-
- # load the data from a dbm file
- sub load_dbm_trans {
- # in: file base name
- # out: result
-
- my($file) = @_;
- print DEBUG "Loading the dbm format file: $file\n" if $CBB::debug;
-
- if ( -e "$file" ) {
- $CBB::current_file = $file;
- $CBB::sorted_keys = 0;
- $CBB::calced = 0;
-
- dbmclose(%CBB::TRANS);
- dbmopen(%CBB::TRANS, &file_root($file), 0666) || return "error";
-
- # test to see if this file is <tab> delimited
- &sort_keys();
- # never ever call calc_trans() at this point (or call something that
- # calls it
- if (defined($CBB::TRANS{$CBB::KEYS[0]}) &&
- !($CBB::TRANS{$CBB::KEYS[0]} =~ m/\t/) ) {
- print DEBUG "'$CBB::TRANS{$CBB::KEYS[0]}' = old version of CBB dbm file\n"
- if $CBB::debug;
- return "error - old version of CBB dbm file";
- } else {
- print DEBUG "valid txn: '$CBB::TRANS{$CBB::KEYS[0]}'\n"
- if $CBB::debug;
- }
-
- return "ok";
- } else {
- return "error";
- }
- }
-
-
- # save all the precious data to a file
- sub save_trans {
- # in: file name (including .cbb extension)
- # out: result
-
- my($file) = @_;
- my($auto_save_file, $key);
- my(@trans);
-
- print DEBUG "Saving the cbb format file: $file\n" if $CBB::debug;
-
- if ($CBB::calced == 0) {
- &calc_trans();
- }
-
- if ($CBB::sorted_keys == 0) {
- &sort_keys();
- }
-
- if ( $CBB::encrypt ne "" ) {
- open(SAVE, "|$CBB::encrypt > $file.new") || return "error";
- } else {
- open(SAVE, ">$file.new") || return "error";
- }
-
- # Print some header stuff
- print (SAVE "# CBB Data File -- $file\n");
- print (SAVE "#\n");
- print (SAVE "# CBB Version = $CBB::version_num\n");
- printf (SAVE "# Current Balance = %.2f\n", $CBB::BALS{Current});
- printf (SAVE "# Ending Balance = %.2f\n", $CBB::BALS{Amount});
- print (SAVE "# Transaction Count = $CBB::BALS{Count}\n");
- printf (SAVE "# Cleared Balance = %.2f\n", $CBB::BALS{Xamount});
- print (SAVE "# Cleared Txn Count = $CBB::BALS{Xcount}\n");
- print (SAVE "# Saved on (US Date Fmt) " . &nice_date("1") . " ");
- print (SAVE "by $CBB::user_name\n");
- print (SAVE "#\n");
- print (SAVE "# date check desc debit credit cat com cleared\n");
- print (SAVE "# ---------------------------------------------------\n");
-
- foreach $key (@CBB::KEYS) {
- # strip off last total
- @trans = split(/\t/, $CBB::TRANS{$key});
- print SAVE join ("\t", @trans[0..7]) . "\n";
- }
-
- close(SAVE);
-
- unlink("$file.bak");
- rename("$file", "$file.bak");
- rename("$file.new", "$file");
-
- $auto_save_file = &file_dirname($file) . "#" . &file_basename($file) . "#";
- print DEBUG "auto_save_file = $auto_save_file\n" if $CBB::debug;
- if ( -e $auto_save_file ) {
- unlink("$auto_save_file");
- unlink("$auto_save_file.bak");
- }
-
- return "ok";
- }
-
-
- 1;
-
- # ----------------------------------------------------------------------------
- # $Log: engine.pl,v $
- # Revision 2.20 1998/08/14 14:30:11 curt
- # Patches to the graphs/graphbal script to avoid divide by zero in certain
- # circumstances.
- #
- # Revision 2.19 1998/08/14 14:28:35 curt
- # Added desc-pie graph.
- # Added option to eliminate splash screen.
- # Other misc. tweaks and bug fixes.
- #
- # Revision 2.18 1997/05/06 02:35:14 curt
- # Removed an extranious my()
- #
- # Revision 2.17 1997/05/06 01:00:27 curt
- # Added patches contributed by Martin Schenk <schenkm@ping.at>
- # - Default to umask of 066 so .CBB files get created rw by owner only
- # - Added support for pgp encrypting data files
- # - Added support for displaying only recent parts of files (avoids
- # waiting to load in lots of old txns you don't currently need.)
- # - Added a feature to "cache" whole accounts in the perl engine so
- # that switching between accounts can be faster.
- # - The above options can be turned on/off via the preferrences menu.
- #
- # Revision 2.16 1997/04/12 01:15:24 curt
- # Display current balance rather than ending balance in the account list
- # box. This makes a difference if you like to insert future transactions.
- #
- # Revision 2.15 1997/04/11 20:24:01 curt
- # Automatically insert new transactions into the memorized list.
- #
- # Revision 2.14 1997/04/04 18:41:35 curt
- # Fixed a small bug in editing transfer transactions.
- #
- # Revision 2.13 1997/03/04 03:23:00 curt
- # Fixed bug which caused a transfer transaction to not show up in the list
- # box even though it had been correctly inserted.
- #
- # Revision 2.12 1997/01/18 03:28:42 curt
- # Added "use strict" pragma to enforce good scoping habits.
- #
- # Revision 2.11 1997/01/10 22:03:30 curt
- # Transfer fixups and a few other misc. fixes contributed by
- # Lionel Mallet <Lionel.Mallet@sophia.inria.fr>
- #
- # Revision 2.10 1997/01/02 04:38:32 curt
- # Changes over the 1996 holidays:
- # - Converted listbox to text widget. This allows us to do nice
- # things with alternating background colors, highliting, red
- # negative numbers, etc.
- # - Negative transactions are now drawn in red.
- # - Added a Goto <Today> option.
- # - <Home> & <End> were double bound. Now, listbox can be traversed with
- # <Meta-Home> and <Meta-End>
- #
- # Revision 2.9 1996/12/17 20:15:43 curt
- # Version incremented to 0.70.
- # No longer save running total in .cbb files.
- # Miscellaneous tweaks.
- #
- # Revision 2.8 1996/12/17 14:53:54 curt
- # Updated copyright date.
- #
- # Revision 2.7 1996/12/11 18:33:32 curt
- # Ran a spell checker.
- #
- # Revision 2.6 1996/10/02 19:37:19 curt
- # Replaced instances of hardcoded century (19) with a variable. We need to
- # know the current century in cases where it is not provided and it is
- # assumed to be the current century. Someday I need to figure out how
- # to determine the current century, but I have a couple of years to do it. :-)
- #
- # I still need to fix conf-reports and reports.pl
- #
- # Revision 2.5 1996/09/26 19:48:44 curt
- # Fixed some problems with the newly revamped tab completion code.
- #
- # Revision 2.4 1996/07/30 14:35:33 curt
- # Fixed a typo introduced in previous (field width change).
- #
- # Revision 2.3 1996/07/24 20:17:14 curt
- # Added Arlindo M. L. Oliveira's "total" field with fix for handling higher
- # numbers.
- #
- # Revision 2.2 1996/07/13 02:57:41 curt
- # Version 0.65
- # Packing Changes
- # Documentation changes
- # Changes to handle a value in both debit and credit fields.
- #
- # Revision 2.1 1996/02/27 05:35:40 curt
- # Just stumbling around a bit with cvs ... :-(
- #
- # Revision 2.0 1996/02/27 04:41:53 curt
- # Initial 2.0 revision. (See "Log" files for old history.)
-