summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/ledger.14
-rw-r--r--doc/ledger3.texi231
-rw-r--r--lisp/ldg-test.el15
-rw-r--r--src/account.h11
-rw-r--r--src/accum.h11
-rw-r--r--src/annotate.cc6
-rw-r--r--src/annotate.h9
-rw-r--r--src/commodity.h4
-rw-r--r--src/csv.h4
-rw-r--r--src/draft.cc4
-rw-r--r--src/draft.h16
-rw-r--r--src/expr.h1
-rw-r--r--src/filters.cc15
-rw-r--r--src/filters.h1
-rw-r--r--src/global.cc21
-rw-r--r--src/global.h1
-rw-r--r--src/history.cc7
-rw-r--r--src/iterators.cc8
-rw-r--r--src/iterators.h103
-rw-r--r--src/journal.cc1
-rw-r--r--src/journal.h1
-rw-r--r--src/main.cc1
-rw-r--r--src/pool.cc37
-rw-r--r--src/pstream.h5
-rw-r--r--src/py_journal.cc5
-rw-r--r--src/report.cc9
-rw-r--r--src/report.h23
-rw-r--r--src/scope.h14
-rw-r--r--src/session.cc3
-rw-r--r--src/session.h2
-rw-r--r--src/temps.h4
-rw-r--r--src/textual.cc15
-rw-r--r--src/timelog.cc101
-rw-r--r--src/timelog.h2
-rw-r--r--src/utils.cc110
-rwxr-xr-xtest/LedgerHarness.py7
-rw-r--r--test/baseline/opt-day-break.test12
-rw-r--r--test/baseline/opt-verify-memory.test0
-rwxr-xr-xtest/fullcheck.sh20
-rw-r--r--test/regress/1384C1D8.test27
-rw-r--r--test/regress/14DB77E7.test2
-rw-r--r--test/regress/25A099C9.test42
-rw-r--r--test/regress/96A8E4A1.test10
-rw-r--r--test/regress/9E0E606D.test19
-rw-r--r--test/regress/A8FCC765.dat2
-rw-r--r--test/regress/A8FCC765.test8
-rw-r--r--tools/Makefile.am1
-rwxr-xr-xtools/times.sh4
48 files changed, 716 insertions, 243 deletions
diff --git a/doc/ledger.1 b/doc/ledger.1
index 63017452..9cfa41c0 100644
--- a/doc/ledger.1
+++ b/doc/ledger.1
@@ -1,4 +1,4 @@
-.Dd March 13, 2012
+.Dd March 18, 2012
.Dt ledger 1
.Sh NAME
.Nm ledger
@@ -300,6 +300,7 @@ See
.It Fl \-date-format Ar DATEFMT Pq Fl y
.It Fl \-datetime-format Ar FMT
.It Fl \-date-width Ar INT
+.It Fl \-day-break
.It Fl \-dc
.It Fl \-debug Ar STR
.It Fl \-decimal-comma
@@ -430,6 +431,7 @@ appeared in the original journal file.
.It Fl \-value-expr Ar EXPR
.It Fl \-verbose
.It Fl \-verify
+.It Fl \-verify-memory
.It Fl \-version
.It Fl \-weekly Pq Fl W
.It Fl \-wide Pq Fl w
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
index 726dd22b..8e7c8b50 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -552,6 +552,18 @@ cannot display any currency symbols other than dollar signs ($).
@item @code{-T EXPR} @tab @code{--total} @tab Change the value expression used for ``totals'' column in register and balance reports
@end multitable
+@node Error Checking and Calculation Options
+@subsection Error Checking and Calculation Options
+
+@multitable @columnfractions .1 .25 .65
+@item @strong{Short} @tab @strong{Long} @tab @strong{Description}
+@item @code{} @tab @code{--strict} @tab accounts, tags or commodities not previously declared will cause warnings
+@item @code{} @tab @code{--pedantic} @tab accounts, tags or commodities not previously declared will cause errors
+@item @code{} @tab @code{--check-payees} @tab enable strict and pedantic checking for payees as well as accounts, commodities and tags.
+@item @code{} @tab @code{--immediate} @tab instructs ledger to evaluate calculations immediately rather than lazily
+@end multitable
+
+
@node Output Customization Quick Reference, Grouping Options, Report Filtering Quick Reference, Command Line Quick Reference
@subsection Output Customization
@multitable @columnfractions .15 .4 .45
@@ -559,7 +571,6 @@ cannot display any currency symbols other than dollar signs ($).
@item @code{-n} @tab @code{--collapse} @tab Collapse transactions with multiple postings
@item @code{-s} @tab @code{--subtotal} @tab Report register as a single subtotal
@item @code{-P} @tab @code{--by-payee} @tab Report subtotals by payee
-@item @code{-x} @tab @code{--comm-as-payee} @tab Change the payee of every posting to be the commodity used in that posting
@item @code{-E} @tab @code{--empty} @tab Include empty accounts in report
@item @code{-W} @tab @code{--weekly} @tab Report posting totals by week
@item @code{-Y} @tab @code{--yearly} @tab Report posting totals by year
@@ -1375,6 +1386,7 @@ posting.
* Structuring Your Accounts::
* Commenting on your journal::
* Currency and Commodities::
+* Keeping it Consistent::
@end menu
@node Most Basic Entry, Starting up, Keeping a Journal, Keeping a Journal
@@ -1535,7 +1547,7 @@ transactions. The comments within the transaction must all start with `;'s and
preserved as part of the transaction. The `:'s indicate meta-data and tags
(@pxref{Metadata}).
-@node Currency and Commodities, , Commenting on your journal, Keeping a Journal
+@node Currency and Commodities, Keeping it Consistent, Commenting on your journal, Keeping a Journal
@section Currency and Commodities
@cindex currency
@@ -1710,6 +1722,37 @@ its amount is null.
@node Complete control over commodity pricing, , Fixing Lot Prices, Currency and Commodities
@subsection Complete control over commodity pricing
+@node Keeping it Consistent, , Currency and Commodities, Keeping a Journal
+@section Keeping it Consistent
+
+Sometimes Ledger's flexibility can lead to difficulties. Using a
+freeform text editor to enter transactions makes it easy to keep the
+data, but also easy to enter accounts or payees inconsistently or with
+spelling errors.
+
+In order to combat inconsistency you can define allowable accounts and
+or payees. For simplicity, create a separate text file and enter define
+accounts a payees like
+@smallexample
+account Expenses
+account Expenses:Utilities
+...
+@end smallexample
+Using the @samp{--strict} option will cause Ledger to complain if any accounts are not previously defined:
+@smallexample
+15:27:39 ~/ledger (next) > ledger bal --strict
+Warning: "FinanceData/Master.dat", line 6: Unknown account 'Liabilities:Tithe Owed'
+Warning: "FinanceData/Master.dat", line 8: Unknown account 'Liabilities:Tithe Owed'
+Warning: "FinanceData/Master.dat", line 15: Unknown account 'Allocation:Equities:Domestic'
+@end smallexample
+
+If you have a large Ledger register already created use the @samp{accounts} command to get started:
+@smallexample
+ledger accounts >> Accounts.dat
+@end smallexample
+
+@noindent You will have to edit this file to add the @samp{account} directive.
+
@node Transactions , Building Reports, Keeping a Journal, Top
@@ -1736,7 +1779,6 @@ its amount is null.
* Lot notes::
* Lot value expressions::
* Automated transactions::
-* Keeping it Consistent::
* File Format::
* Archiving Previous Years ::
* Using Emacs::
@@ -2541,7 +2583,7 @@ In most cases, it is simplest to either use explicit amounts in your valuation
expressions, or just pass the arguments down to market after modifying them to
suit your needs.
-@node Automated transactions, Keeping it Consistent, Lot value expressions, Transactions
+@node Automated transactions, File Format, Lot value expressions, Transactions
@section Automated transactions
An automated transaction is a special kind of transaction which adds its
@@ -2818,39 +2860,8 @@ See @ref{Budgeting and Forecasting} for examples and details.
-@node Keeping it Consistent, File Format, Automated transactions, Transactions
-@section Keeping it Consistent
-
-Sometimes Ledger's flexibility can lead to difficulties. Using a
-freeform text editor to enter transactions makes it easy to keep the
-data, but also easy to enter accounts or payees inconsistently or with
-spelling errors.
-
-In order to combat inconsistency you can define allowable accounts and
-or payees. For simplicity, create a separate text file and enter define
-accounts a payees like
-@smallexample
-account Expenses
-account Expenses:Utilities
-...
-@end smallexample
-Using the @samp{--strict} option will cause Ledger to complain if any accounts are not previously defined:
-@smallexample
-15:27:39 ~/ledger (next) > ledger bal --strict
-Warning: "FinanceData/Master.dat", line 6: Unknown account 'Liabilities:Tithe Owed'
-Warning: "FinanceData/Master.dat", line 8: Unknown account 'Liabilities:Tithe Owed'
-Warning: "FinanceData/Master.dat", line 15: Unknown account 'Allocation:Equities:Domestic'
-@end smallexample
-
-If you have a large Ledger register already created use the @samp{accounts} command to get started:
-@smallexample
-ledger accounts >> Accounts.dat
-@end smallexample
-
-@noindent You will have to edit this file to add the @samp{account} directive.
-
-@node File Format, Archiving Previous Years , Keeping it Consistent, Transactions
+@node File Format, Archiving Previous Years , Automated transactions, Transactions
@section File Format for Users
@menu
* File Format Intro::
@@ -2946,6 +2957,49 @@ Command directives must occur at the beginning of a line. Use of ! and
@@ is deprecated.
@item account
+
+The @samp{account} directive supports several optional sub-directives, if they
+immediately follow the account directive and if they begin with whitespace:
+
+@smallexample
+ account Expenses:Food
+ note This account is all about the chicken!
+ alias food
+ payee ^(KFC|Popeyes)$
+ check commodity == "$"
+ assert commodity == "$"
+ eval print("Hello!")
+ default
+@end smallexample
+
+The @samp{note} sub-directive associates a textual note with the account. This can
+be accessed later using the @samp{note} valexpr function in any account context.
+
+The @samp{alias} sub-directive, which can occur multiple times, allows the alias to
+be used in place of the full account name anywhere that account names are
+allowed.
+
+The @samp{payee} sub-directive, which can occur multiple times, provides regexps
+that identify the account if that payee is encountered and an account within
+its transaction ends in the name "Unknown". Example:
+
+@smallexample
+ 2012-02-27 KFC
+ Expenses:Unknown $10.00 ; Read now as "Expenses:Food"
+ Assets:Cash
+@end smallexample
+
+The @samp{check} and @samp{assert} directives warn or error (respectively) if the given
+value expression evaluates to false within the context of any posting.
+
+The @samp{eval} directive evaluates the value expression in the context of the
+account at the time of definition. At the moment this has little value.
+
+The @samp{default} directive specifies that this account should be used as the
+``balancing account'' for any future transactions that contain only a single
+posting.
+
+@item apply account
@c instance_t::master_account_directive
Sets the root for all accounts following the directive. Ledger supports
a hierarchical tree of accounts. It may be convenient to keep two
@@ -2957,7 +3011,7 @@ groups of transaction without manually editing them using the account
directive. For example:
@smallexample
-account Personal
+apply account Personal
2011/11/15 Supermarket
Expenses:Groceries
Assets:Checking
@@ -2965,7 +3019,7 @@ account Personal
Would result in all postings going into
@code{Personal:Expenses:Groceries} and @code{Personal:Assets:hecking}
-until and @code{end account} directive was found.
+until and @code{end apply account} directive was found.
@item alias
@c instance_t::alias_directive
@@ -3048,6 +3102,38 @@ check <VALUE EXPRESSION BOOLEAN RESULT>
@item comment
@c instance_t::comment_directive in textual.cc
Start a block comment, closed by @code{end comment}.
+
+@item commodity
+Pre-declare commodity names. This only has effect if @samp{--strict} or
+@samp{--pedantic} is used (see below).
+
+ commodity $
+ commodity CAD
+
+The @samp{commodity} directive supports several optional sub-directives, if they
+immediately follow the commodity directive and if they begin with whitespace:
+
+@smallexample
+ commodity $
+ note American Dollars
+ format $1,000.00
+ nomarket
+ default
+@end smallexample
+
+The @samp{note} sub-directive associates a textual note with the commodity. At
+present this has no value other than documentation.
+
+The @samp{format} directive gives you a way to tell Ledger how to format this
+commodity. In future using this directive will disable Ledger's observation
+of other ways that commodity is used, and will provide the ``canonical''
+representation.
+
+The @samp{nomarket} directive states that the commodity's price should never be
+auto-downloaded.
+
+The @samp{default} directive marks this as the ``default'' commodity.
+
@item define
@c instance_t::define_directive in textual.cc
Allows you to define value expression for future use. For example:
@@ -3075,26 +3161,31 @@ Include the stated file as if it were part of the current file.
@item payee
@c instance_t::payee_mapping_directive in textual.cc
-Directs Ledger to replace any payee matching a regex with the given
-payee. You may download transactions from your bank that you want to be
-shortened or altered. For example, the the payee for the grocery store
-near me is only one character different than the payee if I buy gasoline
-at the grocery story. I can enter payee mappings that make this very clear:
+The @samp{payee} directive supports one optional sub-directive, if it immediately
+follows the payee directive and if it begins with whitespace:
@smallexample
-payee Supermarket Gas Supermarket 4
-payee Supermarket Groceries Supermarket 1
+ payee KFC
+ alias KENTUCKY FRIED CHICKEN
+@end smallexample
+
+The @samp{alias} directive provides a regexp which, if it matches a parsed payee,
+the declared payee name is substituted:
+
+@smallexample
+ 2012-02-27 KENTUCKY FRIED CHICKEN ; will be read as being 'KFC'
+ ...
@end smallexample
Ledger will display the mapped payees in @code{print} and
@code{register} reports.
-@item tag
+@item apply tag
@c instance_t::tag_directive in textual.cc
Allows you to designate a block of transactions and assign the same tag to all. Tags can have values and may be nested.
@smallexample
-tag hastag
-tag nestedtag: true
+apply tag hastag
+apply tag nestedtag: true
2011/01/25 Tom's Used Cars
Expenses:Auto $ 5,500.00
; :nobudget:
@@ -3104,12 +3195,12 @@ tag nestedtag: true
Expenses:Books $20.00
Liabilities:MasterCard
-end tag nestedtag
+end apply tag nestedtag
2011/12/01 Sale
Assets:Checking:Business $ 30.00
Income:Sales
-end tag hastag
+end apply tag hastag
@end smallexample
@noindent is the equivalent of
@@ -3134,9 +3225,33 @@ end tag hastag
Income:Sales
@end smallexample
-Note that anything following "@code{end tag}" is ignored. placing the
+Note that anything following ``@code{end tag}'' is ignored. placing the
name of the tag that is being closed is a simple way to keep track.
+@item tag
+Pre-declares tag names. This only has effect if @samp{--strict} or
+@item{--pedantic} is used (see below).
+
+@smallexample
+ tag Receipt
+ tag CSV
+@end smallexample
+
+The 'tag' directive supports two optional sub-directives, if they immediately
+follow the tag directive and if they begin with whitespace:
+
+@smallexample
+ tag Receipt
+ check value =~ /pattern/
+ assert value != "foobar"
+@end smallexample
+
+The @samp{check} and @samp{assert} directives warn or error (respectively) if the given
+value expression evaluates to false within the context of any use of the
+related tag. In such a context, ``value'' is bound to the value of the tag
+(which may not be a string if typed-metadata is used!). Such checks or
+assertions are not called if no value is given.
+
@item test
@c instance_t::comment_directive in textual.cc
This is a synonym for @code{comment} and must be closed by and @code{end} tag.
@@ -3784,13 +3899,6 @@ passes a set of scripted commands to Gnuplot. Feel free to modify the
script to your liking, since you may prefer histograms to line plots,
for example.
-@menu
-* Typical plots::
-@end menu
-
-@node Typical plots, , Visualizing with Gnuplot, Visualizing with Gnuplot
-@subsubsection Typical plots
-
Here are some useful plots:
@smallexample
@@ -3924,7 +4032,7 @@ downloads. Unfortunately the file formats, aside form the commas, are
all different. The ledger convert command tried to help as much as it
can.
-Your banks csv files will have field in different orders from other
+Your banks csv files will have fields in different orders from other
banks, so there must be a way to tell Ledger what to expect. Insert a
line at the beginning of the csv file that describes the fields to Ledger.
@@ -5401,7 +5509,7 @@ Tell ledger to use a particular day of the week to start its ``weekly'' summary.
FIX THIS ENTRY
@option{--tail <INT>}
-FIX THIS ENTRY
+report only the last <INT> entries. Only useful ona register report.
@option{total-data}
FIX THIS ENTRY
@@ -5647,9 +5755,6 @@ transaction.
@option{--by-payee} (@option{-P}) reports subtotals by payee.
-@option{--comm-as-payee} (@option{-x}) changes the payee of every
-posting to be the commodity used in that posting. This can be
-useful when combined with other options, such as @option{-s}.
@option{--empty} (@option{-E}) includes even empty accounts in the
@command{balance} report.
diff --git a/lisp/ldg-test.el b/lisp/ldg-test.el
index 77e03026..a1ae3974 100644
--- a/lisp/ldg-test.el
+++ b/lisp/ldg-test.el
@@ -44,12 +44,15 @@
(expand-file-name "test/regress"
ledger-source-directory)))
(ledger-mode)
- (when input
- (insert input))
- (when output
- (insert "\ntest \n")
- (insert output)
- (insert "end test\n"))))))
+ (if input
+ (insert input)
+ (insert "2012-03-17 Payee\n")
+ (insert " Expenses:Food $20\n")
+ (insert " Assets:Cash\n"))
+ (insert "\ntest reg\n")
+ (if output
+ (insert output))
+ (insert "end test\n")))))
(defun ledger-test-run ()
(interactive)
diff --git a/src/account.h b/src/account.h
index 4ddd85e7..fee12595 100644
--- a/src/account.h
+++ b/src/account.h
@@ -189,7 +189,16 @@ public:
posts_cleared_count(0),
posts_last_7_count(0),
posts_last_30_count(0),
- posts_this_month_count(0) {}
+ posts_this_month_count(0) {
+ TRACE_CTOR(account_t::xdata_t::details_t, "");
+ }
+ // A copy copies nothing
+ details_t(const details_t&) {
+ TRACE_CTOR(account_t::xdata_t::details_t, "copy");
+ }
+ ~details_t() throw() {
+ TRACE_DTOR(account_t::xdata_t::details_t);
+ }
details_t& operator+=(const details_t& other);
diff --git a/src/accum.h b/src/accum.h
index dde93c30..628a6b36 100644
--- a/src/accum.h
+++ b/src/accum.h
@@ -51,7 +51,12 @@ protected:
std::string::size_type index;
public:
- straccbuf() : index(0) {}
+ straccbuf() : index(0) {
+ TRACE_CTOR(straccbuf, "");
+ }
+ ~straccbuf() throw() {
+ TRACE_DTOR(straccbuf);
+ }
protected:
virtual std::streamsize xsputn(const char * s, std::streamsize num);
@@ -66,8 +71,12 @@ protected:
public:
straccstream() : std::ostream(0) {
+ TRACE_CTOR(straccstream, "");
rdbuf(&buf);
}
+ ~straccstream() throw() {
+ TRACE_DTOR(straccstream);
+ }
void clear() {
std::ostream::clear();
diff --git a/src/annotate.cc b/src/annotate.cc
index 2b118e76..25f0e582 100644
--- a/src/annotate.cc
+++ b/src/annotate.cc
@@ -56,6 +56,7 @@ bool annotation_t::operator<(const annotation_t& rhs) const
return true;
if (price->commodity().symbol() > rhs.price->commodity().symbol())
return false;
+
if (*price < *rhs.price) return true;
if (*price > *rhs.price) return false;
}
@@ -68,9 +69,12 @@ bool annotation_t::operator<(const annotation_t& rhs) const
if (*tag > *rhs.tag) return false;
}
if (value_expr) {
+ DEBUG("annotate.less", "Comparing (" << value_expr->text()
+ << ") < (" << rhs.value_expr->text());
if (value_expr->text() < rhs.value_expr->text()) return true;
- if (value_expr->text() > rhs.value_expr->text()) return false;
+ //if (value_expr->text() > rhs.value_expr->text()) return false;
}
+
return false;
}
diff --git a/src/annotate.h b/src/annotate.h
index 044ebc4d..163ffac5 100644
--- a/src/annotate.h
+++ b/src/annotate.h
@@ -72,7 +72,7 @@ struct annotation_t : public supports_flags<>,
: supports_flags<>(), price(_price), date(_date), tag(_tag),
value_expr(_value_expr) {
TRACE_CTOR(annotation_t,
- "const optional<amount_t>& + date_t + string + expr_t");
+ "optional<amount_t> + date_t + string + expr_t");
}
annotation_t(const annotation_t& other)
: supports_flags<>(other.flags()),
@@ -91,9 +91,9 @@ struct annotation_t : public supports_flags<>,
bool operator<(const annotation_t& rhs) const;
bool operator==(const annotation_t& rhs) const {
- return (price == rhs.price &&
- date == rhs.date &&
- tag == rhs.tag &&
+ return (price == rhs.price &&
+ date == rhs.date &&
+ tag == rhs.tag &&
(value_expr && rhs.value_expr ?
value_expr->text() == rhs.value_expr->text() :
value_expr == rhs.value_expr));
@@ -228,6 +228,7 @@ protected:
: commodity_t(_ptr->parent_, _ptr->base), ptr(_ptr), details(_details) {
TRACE_CTOR(annotated_commodity_t, "commodity_t *, annotation_t");
annotated = true;
+ qualified_symbol = _ptr->qualified_symbol;
}
public:
diff --git a/src/commodity.h b/src/commodity.h
index 148a3636..ba47a572 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -132,10 +132,10 @@ protected:
static_cast<uint_least16_t>(COMMODITY_STYLE_DECIMAL_COMMA) :
static_cast<uint_least16_t>(COMMODITY_STYLE_DEFAULTS)),
symbol(_symbol), precision(0) {
- TRACE_CTOR(base_t, "const string&");
+ TRACE_CTOR(commodity_t::base_t, "const string&");
}
virtual ~base_t() {
- TRACE_DTOR(base_t);
+ TRACE_DTOR(commodity_t::base_t);
}
#if defined(HAVE_BOOST_SERIALIZATION)
diff --git a/src/csv.h b/src/csv.h
index 24ea9121..d98c0567 100644
--- a/src/csv.h
+++ b/src/csv.h
@@ -91,8 +91,12 @@ public:
cost_mask("cost"),
total_mask("total"),
note_mask("note") {
+ TRACE_CTOR(csv_reader, "parse_context_t&");
read_index(*context.stream.get());
}
+ ~csv_reader() {
+ TRACE_DTOR(csv_reader);
+ }
void read_index(std::istream& in);
string read_field(std::istream& in);
diff --git a/src/draft.cc b/src/draft.cc
index 74a6f4d2..7edf7edc 100644
--- a/src/draft.cc
+++ b/src/draft.cc
@@ -109,12 +109,12 @@ void draft_t::parse_args(const value_t& args)
}
else if (check_for_date &&
bool(weekday = string_to_day_of_week(what[0]))) {
-#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
short dow = static_cast<short>(*weekday);
-#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
#pragma GCC diagnostic pop
#endif
date_t date = CURRENT_DATE() - date_duration(1);
diff --git a/src/draft.h b/src/draft.h
index 41485731..e5d29134 100644
--- a/src/draft.h
+++ b/src/draft.h
@@ -68,12 +68,22 @@ class draft_t : public expr_base_t<value_t>
optional<string> cost_operator;
optional<amount_t> cost;
- post_template_t() : from(false) {}
+ post_template_t() : from(false) {
+ TRACE_CTOR(post_template_t, "");
+ }
+ ~post_template_t() throw() {
+ TRACE_DTOR(post_template_t);
+ }
};
std::list<post_template_t> posts;
- xact_template_t() {}
+ xact_template_t() {
+ TRACE_CTOR(xact_template_t, "");
+ }
+ ~xact_template_t() throw() {
+ TRACE_DTOR(xact_template_t);
+ }
void dump(std::ostream& out) const;
};
@@ -86,7 +96,7 @@ public:
if (! args.empty())
parse_args(args);
}
- virtual ~draft_t() {
+ virtual ~draft_t() throw() {
TRACE_DTOR(draft_t);
}
diff --git a/src/expr.h b/src/expr.h
index 590bdc15..645b5cf9 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -162,7 +162,6 @@ public:
: expr_t(), term(_term), base_expr(expr), merge_operator(merge_op) {
TRACE_CTOR(merged_expr_t, "string, string, string");
}
-
virtual ~merged_expr_t() {
TRACE_DTOR(merged_expr_t);
}
diff --git a/src/filters.cc b/src/filters.cc
index d5cb8ebb..749efc77 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -593,6 +593,7 @@ changed_value_posts::changed_value_posts
report.HANDLER(display_total_).expr),
display_total_expr(report.HANDLER(display_total_).expr),
changed_values_only(report.HANDLED(revalued_only)),
+ historical_prices_only(report.HANDLED(historical)),
for_accounts_report(_for_accounts_report),
show_unrealized(_show_unrealized), last_post(NULL),
display_filter(_display_filter)
@@ -624,9 +625,11 @@ changed_value_posts::changed_value_posts
void changed_value_posts::flush()
{
if (last_post && last_post->date() <= report.terminus.date()) {
- if (! for_accounts_report)
- output_intermediate_prices(*last_post, report.terminus.date());
- output_revaluation(*last_post, report.terminus.date());
+ if (! historical_prices_only) {
+ if (! for_accounts_report)
+ output_intermediate_prices(*last_post, report.terminus.date());
+ output_revaluation(*last_post, report.terminus.date());
+ }
last_post = NULL;
}
item_handler<post_t>::flush();
@@ -807,7 +810,7 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
void changed_value_posts::operator()(post_t& post)
{
if (last_post) {
- if (! for_accounts_report)
+ if (! for_accounts_report && ! historical_prices_only)
output_intermediate_prices(*last_post, post.value_date());
output_revaluation(*last_post, post.value_date());
}
@@ -835,7 +838,7 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
foreach (post_t * post, component_posts) {
date_t date = post->date();
date_t value_date = post->value_date();
-#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
@@ -843,7 +846,7 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
range_start = date;
if (! range_finish || value_date > *range_finish)
range_finish = value_date;
-#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 7
#pragma GCC diagnostic pop
#endif
}
diff --git a/src/filters.h b/src/filters.h
index 1ef92bbe..d73fff86 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -576,6 +576,7 @@ class changed_value_posts : public item_handler<post_t>
expr_t& total_expr;
expr_t& display_total_expr;
bool changed_values_only;
+ bool historical_prices_only;
bool for_accounts_report;
bool show_unrealized;
post_t * last_post;
diff --git a/src/global.cc b/src/global.cc
index d7742161..b5ceb614 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -272,6 +272,7 @@ void global_scope_t::report_options(report_t& report, std::ostream& out)
HANDLER(trace_).report(out);
HANDLER(verbose).report(out);
HANDLER(verify).report(out);
+ HANDLER(verify_memory).report(out);
out << std::endl << "[Session scope options]" << std::endl;
report.session.report_options(out);
@@ -315,6 +316,7 @@ option_t<global_scope_t> * global_scope_t::lookup_option(const char * p)
case 'v':
OPT_(verbose);
else OPT(verify);
+ else OPT(verify_memory);
else OPT(version);
break;
}
@@ -452,29 +454,36 @@ void handle_debug_options(int argc, char * argv[])
if (std::strcmp(argv[i], "--args-only") == 0) {
args_only = true;
}
+ else if (std::strcmp(argv[i], "--verify-memory") == 0) {
+#if defined(VERIFY_ON)
+ verify_enabled = true;
+
+ _log_level = LOG_DEBUG;
+ _log_category = "memory\\.counts";
+#endif
+ }
else if (std::strcmp(argv[i], "--verify") == 0) {
#if defined(VERIFY_ON)
- verify_enabled = true; // global in utils.h
+ verify_enabled = true;
#endif
}
else if (std::strcmp(argv[i], "--verbose") == 0 ||
std::strcmp(argv[i], "-v") == 0) {
#if defined(LOGGING_ON)
- _log_level = LOG_INFO; // global in utils.h
+ _log_level = LOG_INFO;
#endif
}
else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
#if defined(DEBUG_ON)
- _log_level = LOG_DEBUG; // global in utils.h
- _log_category = argv[i + 1]; // global in utils.h
+ _log_level = LOG_DEBUG;
+ _log_category = argv[i + 1];
i++;
#endif
}
else if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
#if defined(TRACING_ON)
- _log_level = LOG_TRACE; // global in utils.h
+ _log_level = LOG_TRACE;
try {
- // global in utils.h
_trace_level = boost::lexical_cast<uint8_t>(argv[i + 1]);
}
catch (const boost::bad_lexical_cast&) {
diff --git a/src/global.h b/src/global.h
index 0c11e025..5786bb89 100644
--- a/src/global.h
+++ b/src/global.h
@@ -158,6 +158,7 @@ See LICENSE file included with the distribution for details and disclaimer.");
OPTION(global_scope_t, trace_);
OPTION(global_scope_t, verbose);
OPTION(global_scope_t, verify);
+ OPTION(global_scope_t, verify_memory);
OPTION_(global_scope_t, version, DO() { // -v
parent->show_version_info(std::cout);
diff --git a/src/history.cc b/src/history.cc
index f1e88401..d94ec647 100644
--- a/src/history.cc
+++ b/src/history.cc
@@ -423,7 +423,12 @@ commodity_history_t::find_price(const commodity_t& source,
template <class Name>
class label_writer {
public:
- label_writer(Name _name) : name(_name) {}
+ label_writer(Name _name) : name(_name) {
+ TRACE_CTOR(label_writer<Name>, "Name");
+ }
+ ~label_writer() throw() {
+ TRACE_DTOR(label_writer<Name>);
+ }
template <class VertexOrEdge>
void operator()(std::ostream& out, const VertexOrEdge& v) const {
diff --git a/src/iterators.cc b/src/iterators.cc
index acbb581f..7cc1291a 100644
--- a/src/iterators.cc
+++ b/src/iterators.cc
@@ -88,7 +88,13 @@ namespace {
create_price_xact(journal_t& _journal, account_t * _account,
temporaries_t& _temps, xacts_list& _xact_temps)
: journal(_journal), account(_account), temps(_temps),
- xact_temps(_xact_temps) {}
+ xact_temps(_xact_temps) {
+ TRACE_CTOR(create_price_xact,
+ "journal_t&, account_t *, temporaries_t&, xacts_list&");
+ }
+ ~create_price_xact() throw() {
+ TRACE_DTOR(create_price_xact);
+ }
void operator()(datetime_t& date, const amount_t& price) {
xact_t * xact;
diff --git a/src/iterators.h b/src/iterators.h
index 5bb9de6f..922ebccd 100644
--- a/src/iterators.h
+++ b/src/iterators.h
@@ -58,7 +58,15 @@ class iterator_facade_base
typedef Value node_base;
public:
- iterator_facade_base() : m_node(NULL) {}
+ iterator_facade_base() : m_node(NULL) {
+ TRACE_CTOR(iterator_facade_base, "");
+ }
+ iterator_facade_base(const iterator_facade_base& i) : m_node(i.m_node) {
+ TRACE_CTOR(iterator_facade_base, "copy");
+ }
+ ~iterator_facade_base() throw() {
+ TRACE_DTOR(iterator_facade_base);
+ }
explicit iterator_facade_base(node_base p) : m_node(p) {}
@@ -87,12 +95,24 @@ class xact_posts_iterator
bool posts_uninitialized;
public:
- xact_posts_iterator() : posts_uninitialized(true) {}
+ xact_posts_iterator() : posts_uninitialized(true) {
+ TRACE_CTOR(xact_posts_iterator, "");
+ }
xact_posts_iterator(xact_t& xact)
: posts_uninitialized(true) {
+ TRACE_CTOR(xact_posts_iterator, "xact_t&");
reset(xact);
}
- ~xact_posts_iterator() throw() {}
+ xact_posts_iterator(const xact_posts_iterator& i)
+ : iterator_facade_base<xact_posts_iterator, post_t *,
+ boost::forward_traversal_tag>(i),
+ posts_i(i.posts_i), posts_end(i.posts_end),
+ posts_uninitialized(i.posts_uninitialized) {
+ TRACE_CTOR(xact_posts_iterator, "copy");
+ }
+ ~xact_posts_iterator() throw() {
+ TRACE_DTOR(xact_posts_iterator);
+ }
void reset(xact_t& xact) {
posts_i = xact.posts.begin();
@@ -121,15 +141,28 @@ public:
bool xacts_uninitialized;
- xacts_iterator() : xacts_uninitialized(true) {}
+ xacts_iterator() : xacts_uninitialized(true) {
+ TRACE_CTOR(xacts_iterator, "");
+ }
xacts_iterator(journal_t& journal) : xacts_uninitialized(false) {
+ TRACE_CTOR(xacts_iterator, "journal_t&");
reset(journal);
}
xacts_iterator(xacts_list::iterator beg,
xacts_list::iterator end) : xacts_uninitialized(false) {
+ TRACE_CTOR(xacts_iterator, "xacts_list::iterator, xacts_list::iterator");
reset(beg, end);
}
- ~xacts_iterator() throw() {}
+ xacts_iterator(const xacts_iterator& i)
+ : iterator_facade_base<xacts_iterator, xact_t *,
+ boost::forward_traversal_tag>(i),
+ xacts_i(i.xacts_i), xacts_end(i.xacts_end),
+ xacts_uninitialized(i.xacts_uninitialized) {
+ TRACE_CTOR(xacts_iterator, "copy");
+ }
+ ~xacts_iterator() throw() {
+ TRACE_DTOR(xacts_iterator);
+ }
void reset(journal_t& journal);
@@ -150,11 +183,22 @@ class journal_posts_iterator
xact_posts_iterator posts;
public:
- journal_posts_iterator() {}
+ journal_posts_iterator() {
+ TRACE_CTOR(journal_posts_iterator, "");
+ }
journal_posts_iterator(journal_t& journal) {
+ TRACE_CTOR(journal_posts_iterator, "journal_t&");
reset(journal);
}
- ~journal_posts_iterator() throw() {}
+ journal_posts_iterator(const journal_posts_iterator& i)
+ : iterator_facade_base<journal_posts_iterator, post_t *,
+ boost::forward_traversal_tag>(i),
+ xacts(i.xacts), posts(i.posts) {
+ TRACE_CTOR(journal_posts_iterator, "copy");
+ }
+ ~journal_posts_iterator() throw() {
+ TRACE_DTOR(journal_posts_iterator);
+ }
void reset(journal_t& journal);
@@ -173,11 +217,23 @@ protected:
temporaries_t temps;
public:
- posts_commodities_iterator() {}
+ posts_commodities_iterator() {
+ TRACE_CTOR(posts_commodities_iterator, "");
+ }
posts_commodities_iterator(journal_t& journal) {
+ TRACE_CTOR(posts_commodities_iterator, "journal_t&");
reset(journal);
}
- ~posts_commodities_iterator() throw() {}
+ posts_commodities_iterator(const posts_commodities_iterator& i)
+ : iterator_facade_base<posts_commodities_iterator, post_t *,
+ boost::forward_traversal_tag>(i),
+ journal_posts(i.journal_posts), xacts(i.xacts), posts(i.posts),
+ xact_temps(i.xact_temps), temps(i.temps) {
+ TRACE_CTOR(posts_commodities_iterator, "copy");
+ }
+ ~posts_commodities_iterator() throw() {
+ TRACE_DTOR(posts_commodities_iterator);
+ }
void reset(journal_t& journal);
@@ -192,12 +248,23 @@ class basic_accounts_iterator
std::list<accounts_map::const_iterator> accounts_end;
public:
- basic_accounts_iterator() {}
+ basic_accounts_iterator() {
+ TRACE_CTOR(basic_accounts_iterator, "");
+ }
basic_accounts_iterator(account_t& account) {
+ TRACE_CTOR(basic_accounts_iterator, "account_t&");
push_back(account);
increment();
}
- ~basic_accounts_iterator() throw() {}
+ basic_accounts_iterator(const basic_accounts_iterator& i)
+ : iterator_facade_base<basic_accounts_iterator, account_t *,
+ boost::forward_traversal_tag>(i),
+ accounts_i(i.accounts_i), accounts_end(i.accounts_end) {
+ TRACE_CTOR(basic_accounts_iterator, "copy");
+ }
+ ~basic_accounts_iterator() throw() {
+ TRACE_DTOR(basic_accounts_iterator);
+ }
void increment();
@@ -225,10 +292,22 @@ public:
sorted_accounts_iterator(account_t& account,
const expr_t& _sort_cmp, bool _flatten_all)
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
+ TRACE_CTOR(sorted_accounts_iterator, "account_t&, expr_t, bool");
push_back(account);
increment();
}
- ~sorted_accounts_iterator() throw() {}
+ sorted_accounts_iterator(const sorted_accounts_iterator& i)
+ : iterator_facade_base<sorted_accounts_iterator, account_t *,
+ boost::forward_traversal_tag>(i),
+ sort_cmp(i.sort_cmp), flatten_all(i.flatten_all),
+ accounts_list(i.accounts_list),
+ sorted_accounts_i(i.sorted_accounts_i),
+ sorted_accounts_end(i.sorted_accounts_end) {
+ TRACE_CTOR(sorted_accounts_iterator, "copy");
+ }
+ ~sorted_accounts_iterator() throw() {
+ TRACE_DTOR(sorted_accounts_iterator);
+ }
void increment();
diff --git a/src/journal.cc b/src/journal.cc
index 37eacdaf..be6a8e51 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -94,6 +94,7 @@ void journal_t::initialize()
was_loaded = false;
force_checking = false;
check_payees = false;
+ day_break = false;
checking_style = CHECK_PERMISSIVE;
}
diff --git a/src/journal.h b/src/journal.h
index ca73c415..759826a0 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -130,6 +130,7 @@ public:
bool was_loaded;
bool force_checking;
bool check_payees;
+ bool day_break;
payee_mappings_t payee_mappings;
account_mappings_t account_mappings;
accounts_map account_aliases;
diff --git a/src/main.cc b/src/main.cc
index 9d2ba311..0130d5c6 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -58,6 +58,7 @@ int main(int argc, char * argv[], char * envp[])
// --verbose ; turns on logging
// --debug CATEGORY ; turns on debug logging
// --trace LEVEL ; turns on trace logging
+ // --memory ; turns on memory usage tracing
handle_debug_options(argc, argv);
#if defined(VERIFY_ON)
IF_VERIFY() initialize_memory_tracing();
diff --git a/src/pool.cc b/src/pool.cc
index 5813c0f6..be26de3b 100644
--- a/src/pool.cc
+++ b/src/pool.cc
@@ -102,7 +102,7 @@ commodity_t * commodity_pool_t::find_or_create(const string& symbol)
commodity_t * commodity_pool_t::alias(const string& name, commodity_t& referent)
{
- commodities_map::const_iterator i = commodities.find(referent.symbol());
+ commodities_map::const_iterator i = commodities.find(referent.base_symbol());
assert(i != commodities.end());
std::pair<commodities_map::iterator, bool> result
@@ -130,20 +130,16 @@ commodity_pool_t::find(const string& symbol, const annotation_t& details)
DEBUG("pool.commodities", "commodity_pool_t::find[ann] "
<< "symbol " << symbol << std::endl << details);
- if (details) {
- annotated_commodities_map::const_iterator i =
- annotated_commodities.find
- (annotated_commodities_map::key_type(symbol, details));
- if (i != annotated_commodities.end()) {
- DEBUG("pool.commodities", "commodity_pool_t::find[ann] found "
- << "symbol " << (*i).second->symbol() << std::endl
- << as_annotated_commodity(*(*i).second.get()).details);
- return (*i).second.get();
- } else {
- return NULL;
- }
+ annotated_commodities_map::const_iterator i =
+ annotated_commodities.find
+ (annotated_commodities_map::key_type(symbol, details));
+ if (i != annotated_commodities.end()) {
+ DEBUG("pool.commodities", "commodity_pool_t::find[ann] found "
+ << "symbol " << (*i).second->base_symbol() << std::endl
+ << as_annotated_commodity(*(*i).second.get()).details);
+ return (*i).second.get();
} else {
- return find(symbol);
+ return NULL;
}
}
@@ -170,10 +166,10 @@ commodity_t *
commodity_pool_t::find_or_create(commodity_t& comm, const annotation_t& details)
{
DEBUG("pool.commodities", "commodity_pool_t::find_or_create[ann:comm] "
- << "symbol " << comm.symbol() << std::endl << details);
+ << "symbol " << comm.base_symbol() << std::endl << details);
if (details) {
- if (commodity_t * ann_comm = find(comm.symbol(), details)) {
+ if (commodity_t * ann_comm = find(comm.base_symbol(), details)) {
assert(ann_comm->annotated && as_annotated_commodity(*ann_comm).details);
return ann_comm;
} else {
@@ -189,7 +185,7 @@ commodity_pool_t::create(commodity_t& comm,
const annotation_t& details)
{
DEBUG("pool.commodities", "commodity_pool_t::create[ann:comm] "
- << "symbol " << comm.symbol() << std::endl << details);
+ << "symbol " << comm.base_symbol() << std::endl << details);
assert(comm);
assert(! comm.has_annotation());
@@ -206,11 +202,8 @@ commodity_pool_t::create(commodity_t& comm,
comm.add_flags(COMMODITY_SAW_ANN_PRICE_FLOAT);
}
- commodity->qualified_symbol = comm.symbol();
- assert(! commodity->qualified_symbol->empty());
-
DEBUG("pool.commodities", "Creating annotated commodity "
- << "symbol " << commodity->symbol()
+ << "symbol " << commodity->base_symbol()
<< std::endl << details);
#if defined(DEBUG_ON)
@@ -218,7 +211,7 @@ commodity_pool_t::create(commodity_t& comm,
#endif
annotated_commodities.insert(annotated_commodities_map::value_type
(annotated_commodities_map::key_type
- (comm.symbol(), details), commodity));
+ (comm.base_symbol(), details), commodity));
#if defined(DEBUG_ON)
assert(result.second);
#endif
diff --git a/src/pstream.h b/src/pstream.h
index a894325d..dfb27056 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -58,6 +58,8 @@ class ptristream : public std::istream
public:
ptrinbuf(char * _ptr, std::size_t _len) : ptr(_ptr), len(_len) {
+ TRACE_CTOR(ptrinbuf, "char *, std::size_t");
+
if (*ptr && len == 0)
len = std::strlen(ptr);
@@ -65,6 +67,9 @@ class ptristream : public std::istream
ptr, // read position
ptr+len); // end position
}
+ ~ptrinbuf() throw() {
+ TRACE_DTOR(ptrinbuf);
+ }
protected:
virtual int_type underflow() {
diff --git a/src/py_journal.cc b/src/py_journal.cc
index 550fb14e..50a52be9 100644
--- a/src/py_journal.cc
+++ b/src/py_journal.cc
@@ -151,8 +151,11 @@ namespace {
collector_wrapper(journal_t& _journal, report_t& base)
: journal(_journal), report(base),
- posts_collector(new collect_posts) {}
+ posts_collector(new collect_posts) {
+ TRACE_CTOR(collector_wrapper, "journal_t&, report_t&");
+ }
~collector_wrapper() {
+ TRACE_DTOR(collector_wrapper);
journal.clear_xdata();
}
diff --git a/src/report.cc b/src/report.cc
index 91de2eb5..28836d0f 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -321,7 +321,12 @@ namespace {
report_t& report;
posts_flusher(post_handler_ptr _handler, report_t& _report)
- : handler(_handler), report(_report) {}
+ : handler(_handler), report(_report) {
+ TRACE_CTOR(posts_flusher, "post_handler_ptr, report_t&");
+ }
+ ~posts_flusher() throw() {
+ TRACE_DTOR(posts_flusher);
+ }
void operator()(const value_t&) {
report.session.journal->clear_xdata();
@@ -1113,7 +1118,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT_(display_);
else OPT(display_amount_);
else OPT(display_total_);
- else OPT_ALT(dow, days-of-week);
+ else OPT_ALT(dow, days_of_week);
else OPT(date_width_);
break;
case 'e':
diff --git a/src/report.h b/src/report.h
index aca4f466..37123377 100644
--- a/src/report.h
+++ b/src/report.h
@@ -119,9 +119,19 @@ public:
explicit report_t(session_t& _session)
: session(_session), terminus(CURRENT_TIME()),
- budget_flags(BUDGET_NO_BUDGET) {}
+ budget_flags(BUDGET_NO_BUDGET) {
+ TRACE_CTOR(report_t, "session_t&");
+ }
+ report_t(const report_t& report)
+ : session(report.session),
+ output_stream(report.output_stream),
+ terminus(report.terminus),
+ budget_flags(report.budget_flags) {
+ TRACE_CTOR(report_t, "copy");
+ }
virtual ~report_t() {
+ TRACE_DTOR(report_t);
output_stream.close();
}
@@ -1045,7 +1055,16 @@ class reporter
public:
reporter(shared_ptr<item_handler<Type> > _handler,
report_t& _report, const string& _whence)
- : handler(_handler), report(_report), whence(_whence) {}
+ : handler(_handler), report(_report), whence(_whence) {
+ TRACE_CTOR(reporter, "item_handler<Type>, report_t&, string");
+ }
+ reporter(const reporter& other)
+ : handler(other.handler), report(other.report), whence(other.whence) {
+ TRACE_CTOR(reporter, "copy");
+ }
+ ~reporter() throw() {
+ TRACE_DTOR(reporter);
+ }
value_t operator()(call_scope_t& args)
{
diff --git a/src/scope.h b/src/scope.h
index 134babb2..9318fc5c 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -142,6 +142,13 @@ private:
class empty_scope_t : public scope_t
{
public:
+ empty_scope_t() {
+ TRACE_CTOR(empty_scope_t, "");
+ }
+ ~empty_scope_t() throw() {
+ TRACE_DTOR(empty_scope_t);
+ }
+
virtual string description() {
return _("<empty>");
}
@@ -683,7 +690,12 @@ class value_scope_t : public child_scope_t
public:
value_scope_t(scope_t& _parent, const value_t& _value)
- : child_scope_t(_parent), value(_value) {}
+ : child_scope_t(_parent), value(_value) {
+ TRACE_CTOR(value_scope_t, "scope_t&, value_t");
+ }
+ ~value_scope_t() throw() {
+ TRACE_DTOR(value_scope_t);
+ }
virtual string description() {
return parent->description();
diff --git a/src/session.cc b/src/session.cc
index 76061de7..5c9e4fd4 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -105,6 +105,8 @@ std::size_t session_t::read_data(const string& master_account)
journal->force_checking = true;
if (HANDLED(check_payees))
journal->check_payees = true;
+ if (HANDLED(day_break))
+ journal->day_break = true;
if (HANDLED(permissive))
journal->checking_style = journal_t::CHECK_PERMISSIVE;
@@ -320,6 +322,7 @@ option_t<session_t> * session_t::lookup_option(const char * p)
case 'd':
OPT(download); // -Q
else OPT(decimal_comma);
+ else OPT(day_break);
break;
case 'e':
OPT(explicit);
diff --git a/src/session.h b/src/session.h
index 962664ef..a0aba91b 100644
--- a/src/session.h
+++ b/src/session.h
@@ -97,6 +97,7 @@ public:
{
HANDLER(cache_).report(out);
HANDLER(check_payees).report(out);
+ HANDLER(day_break).report(out);
HANDLER(download).report(out);
HANDLER(decimal_comma).report(out);
HANDLER(file_).report(out);
@@ -122,6 +123,7 @@ public:
OPTION(session_t, cache_);
OPTION(session_t, check_payees);
+ OPTION(session_t, day_break);
OPTION(session_t, download); // -Q
OPTION_(session_t, decimal_comma, DO() {
diff --git a/src/temps.h b/src/temps.h
index ad4e5672..f41c487c 100644
--- a/src/temps.h
+++ b/src/temps.h
@@ -51,7 +51,11 @@ class temporaries_t
optional<std::list<account_t> > acct_temps;
public:
+ temporaries_t() {
+ TRACE_CTOR(temporaries_t, "");
+ }
~temporaries_t() {
+ TRACE_DTOR(temporaries_t);
clear();
}
diff --git a/src/textual.cc b/src/textual.cc
index 3555ea4d..0cb7fb81 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -486,8 +486,7 @@ void instance_t::clock_out_directive(char * line, bool /*capitalized*/)
n ? n : "",
end ? end : "");
- timelog.clock_out(event);
- context.count++;
+ context.count += timelog.clock_out(event);
}
#endif // TIMELOG_SUPPORT
@@ -983,27 +982,23 @@ void instance_t::account_alias_directive(account_t * account, string alias)
// (account), add a reference to the account in the `account_aliases'
// map, which is used by the post parser to resolve alias references.
trim(alias);
-#if defined(DEBUG_ON)
std::pair<accounts_map::iterator, bool> result =
-#endif
context.journal->account_aliases.insert
(accounts_map::value_type(alias, account));
-#if defined(DEBUG_ON)
- assert(result.second);
-#endif
+ if (! result.second)
+ (*result.first).second = account;
}
void instance_t::alias_directive(char * line)
{
- char * b = next_element(line);
- if (char * e = std::strchr(b, '=')) {
+ if (char * e = std::strchr(line, '=')) {
char * z = e - 1;
while (std::isspace(*z))
*z-- = '\0';
*e++ = '\0';
e = skip_ws(e);
- account_alias_directive(top_account()->find_account(e), b);
+ account_alias_directive(top_account()->find_account(e), line);
}
}
diff --git a/src/timelog.cc b/src/timelog.cc
index 00cefe10..e84e4188 100644
--- a/src/timelog.cc
+++ b/src/timelog.cc
@@ -41,9 +41,43 @@
namespace ledger {
namespace {
- void clock_out_from_timelog(std::list<time_xact_t>& time_xacts,
- time_xact_t out_event,
- parse_context_t& context)
+ void create_timelog_xact(const time_xact_t& in_event,
+ const time_xact_t& out_event,
+ parse_context_t& context)
+ {
+ unique_ptr<xact_t> curr(new xact_t);
+ curr->_date = in_event.checkin.date();
+ curr->code = out_event.desc; // if it wasn't used above
+ curr->payee = in_event.desc;
+ curr->pos = in_event.position;
+
+ if (! in_event.note.empty())
+ curr->append_note(in_event.note.c_str(), *context.scope);
+
+ char buf[32];
+ std::sprintf(buf, "%lds", long((out_event.checkin - in_event.checkin)
+ .total_seconds()));
+ amount_t amt;
+ amt.parse(buf);
+ VERIFY(amt.valid());
+
+ post_t * post = new post_t(in_event.account, amt, POST_VIRTUAL);
+ post->set_state(item_t::CLEARED);
+ post->pos = in_event.position;
+ post->checkin = in_event.checkin;
+ post->checkout = out_event.checkin;
+ curr->add_post(post);
+ in_event.account->add_post(post);
+
+ if (! context.journal->add_xact(curr.get()))
+ throw parse_error(_("Failed to record 'out' timelog transaction"));
+ else
+ curr.release();
+ }
+
+ std::size_t clock_out_from_timelog(std::list<time_xact_t>& time_xacts,
+ time_xact_t out_event,
+ parse_context_t& context)
{
time_xact_t event;
@@ -93,34 +127,35 @@ namespace {
if (! out_event.note.empty() && event.note.empty())
event.note = out_event.note;
- unique_ptr<xact_t> curr(new xact_t);
- curr->_date = event.checkin.date();
- curr->code = out_event.desc; // if it wasn't used above
- curr->payee = event.desc;
- curr->pos = event.position;
-
- if (! event.note.empty())
- curr->append_note(event.note.c_str(), *context.scope);
-
- char buf[32];
- std::sprintf(buf, "%lds", long((out_event.checkin - event.checkin)
- .total_seconds()));
- amount_t amt;
- amt.parse(buf);
- VERIFY(amt.valid());
-
- post_t * post = new post_t(event.account, amt, POST_VIRTUAL);
- post->set_state(item_t::CLEARED);
- post->pos = event.position;
- post->checkin = event.checkin;
- post->checkout = out_event.checkin;
- curr->add_post(post);
- event.account->add_post(post);
-
- if (! context.journal->add_xact(curr.get()))
- throw parse_error(_("Failed to record 'out' timelog transaction"));
- else
- curr.release();
+ if (! context.journal->day_break) {
+ create_timelog_xact(event, out_event, context);
+ return 1;
+ } else {
+ time_xact_t begin(event);
+ std::size_t xact_count = 0;
+
+ while (begin.checkin < out_event.checkin) {
+ DEBUG("timelog", "begin.checkin: " << begin.checkin);
+ datetime_t days_end(begin.checkin.date(), time_duration_t(23, 59, 59));
+ days_end += seconds(1);
+ DEBUG("timelog", "days_end: " << days_end);
+
+ if (out_event.checkin <= days_end) {
+ create_timelog_xact(begin, out_event, context);
+ ++xact_count;
+ break;
+ } else {
+ time_xact_t end(out_event);
+ end.checkin = days_end;
+ DEBUG("timelog", "end.checkin: " << end.checkin);
+ create_timelog_xact(begin, end, context);
+ ++xact_count;
+
+ begin.checkin = end.checkin;
+ }
+ }
+ return xact_count;
+ }
}
} // unnamed namespace
@@ -155,12 +190,12 @@ void time_log_t::clock_in(time_xact_t event)
time_xacts.push_back(event);
}
-void time_log_t::clock_out(time_xact_t event)
+std::size_t time_log_t::clock_out(time_xact_t event)
{
if (time_xacts.empty())
throw std::logic_error(_("Timelog check-out event without a check-in"));
- clock_out_from_timelog(time_xacts, event, context);
+ return clock_out_from_timelog(time_xacts, event, context);
}
} // namespace ledger
diff --git a/src/timelog.h b/src/timelog.h
index ed5a2d36..857952ff 100644
--- a/src/timelog.h
+++ b/src/timelog.h
@@ -98,7 +98,7 @@ public:
}
void clock_in(time_xact_t event);
- void clock_out(time_xact_t event);
+ std::size_t clock_out(time_xact_t event);
void close();
};
diff --git a/src/utils.cc b/src/utils.cc
index 628fb158..5a364008 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -270,13 +270,79 @@ void operator delete[](void * ptr, const std::nothrow_t&) throw() {
namespace ledger {
-inline void report_count_map(std::ostream& out, object_count_map& the_map)
-{
- foreach (object_count_map::value_type& pair, the_map)
- out << " " << std::right << std::setw(12) << pair.second.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.first
- << std::endl;
+namespace {
+ void stream_commified_number(std::ostream& out, std::size_t num)
+ {
+ std::ostringstream buf;
+ std::ostringstream obuf;
+
+ buf << num;
+
+ int integer_digits = 0;
+ // Count the number of integer digits
+ for (const char * p = buf.str().c_str(); *p; p++) {
+ if (*p == '.')
+ break;
+ else if (*p != '-')
+ integer_digits++;
+ }
+
+ for (const char * p = buf.str().c_str(); *p; p++) {
+ if (*p == '.') {
+ obuf << *p;
+ assert(integer_digits <= 3);
+ }
+ else if (*p == '-') {
+ obuf << *p;
+ }
+ else {
+ obuf << *p;
+
+ if (integer_digits > 3 && --integer_digits % 3 == 0)
+ obuf << ',';
+ }
+ }
+
+ out << obuf.str();
+ }
+
+ void stream_memory_size(std::ostream& out, std::size_t size)
+ {
+ std::ostringstream obuf;
+
+ if (size > 10 * 1024 * 1024)
+ obuf << "\033[1m";
+ if (size > 100 * 1024 * 1024)
+ obuf << "\033[31m";
+
+ obuf << std::setw(7);
+
+ if (size < 1024)
+ obuf << size << 'b';
+ else if (size < (1024 * 1024))
+ obuf << int(double(size) / 1024.0) << 'K';
+ else if (size < (1024 * 1024 * 1024))
+ obuf << int(double(size) / (1024.0 * 1024.0)) << 'M';
+ else
+ obuf << int(double(size) / (1024.0 * 1024.0 * 1024.0)) << 'G';
+
+ if (size > 10 * 1024 * 1024)
+ obuf << "\033[0m";
+
+ out << obuf.str();
+ }
+
+ void report_count_map(std::ostream& out, object_count_map& the_map)
+ {
+ foreach (object_count_map::value_type& pair, the_map) {
+ out << " " << std::right << std::setw(12);
+ stream_commified_number(out, pair.second.first);
+ out << " " << std::right << std::setw(7);
+ stream_memory_size(out, pair.second.second);
+ out << " " << std::left << pair.first
+ << std::endl;
+ }
+ }
}
std::size_t current_objects_size()
@@ -354,7 +420,7 @@ void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size)
void report_memory(std::ostream& out, bool report_all)
{
- if (! live_memory || ! memory_tracing_active) return;
+ if (! live_memory) return;
if (live_memory_count->size() > 0) {
out << "NOTE: There may be memory held by Boost "
@@ -366,11 +432,13 @@ void report_memory(std::ostream& out, bool report_all)
if (live_memory->size() > 0) {
out << "Live memory:" << std::endl;
- foreach (const memory_map::value_type& pair, *live_memory)
+ foreach (const memory_map::value_type& pair, *live_memory) {
out << " " << std::right << std::setw(12) << pair.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.second.first
+ << " " << std::right << std::setw(7);
+ stream_memory_size(out, pair.second.second);
+ out << " " << std::left << pair.second.first
<< std::endl;
+ }
}
if (report_all && total_memory_count->size() > 0) {
@@ -386,11 +454,13 @@ void report_memory(std::ostream& out, bool report_all)
if (live_objects->size() > 0) {
out << "Live objects:" << std::endl;
- foreach (const objects_map::value_type& pair, *live_objects)
+ foreach (const objects_map::value_type& pair, *live_objects) {
out << " " << std::right << std::setw(12) << pair.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.second.first
+ << " " << std::right << std::setw(7);
+ stream_memory_size(out, pair.second.second);
+ out << " " << std::left << pair.second.first
<< std::endl;
+ }
}
if (report_all) {
@@ -529,18 +599,6 @@ std::ostringstream _log_buffer;
uint8_t _trace_level;
#endif
-static inline void stream_memory_size(std::ostream& out, std::size_t size)
-{
- if (size < 1024)
- out << size << 'b';
- else if (size < (1024 * 1024))
- out << (double(size) / 1024.0) << 'K';
- else if (size < (1024 * 1024 * 1024))
- out << (double(size) / (1024.0 * 1024.0)) << 'M';
- else
- out << (double(size) / (1024.0 * 1024.0 * 1024.0)) << 'G';
-}
-
static bool logger_has_run = false;
static ptime logger_start;
diff --git a/test/LedgerHarness.py b/test/LedgerHarness.py
index 564a4d32..3477e720 100755
--- a/test/LedgerHarness.py
+++ b/test/LedgerHarness.py
@@ -81,6 +81,13 @@ class LedgerHarness:
command = re.sub('\$ledger', '%s%s %s' % \
(self.ledger, insert, '--args-only'), command)
+ valgrind = '/usr/bin/valgrind'
+ if not os.path.isfile(valgrind):
+ valgrind = '/opt/local/bin/valgrind'
+
+ if os.path.isfile(valgrind) and '--verify' in insert:
+ command = valgrind + ' -q ' + command
+
return Popen(command, shell=True, close_fds=True, env=env,
stdin=PIPE, stdout=PIPE, stderr=PIPE)
diff --git a/test/baseline/opt-day-break.test b/test/baseline/opt-day-break.test
new file mode 100644
index 00000000..18dde546
--- /dev/null
+++ b/test/baseline/opt-day-break.test
@@ -0,0 +1,12 @@
+i 05/10/2011 08:58:37 682
+o 05/12/2011 11:25:21
+
+test reg --base
+11-May-10 (682) 181604s 181604s
+end test
+
+test reg --base --day-break
+11-May-10 (682) 54083s 54083s
+11-May-11 (682) 86400s 140483s
+11-May-12 (682) 41121s 181604s
+end test
diff --git a/test/baseline/opt-verify-memory.test b/test/baseline/opt-verify-memory.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-verify-memory.test
diff --git a/test/fullcheck.sh b/test/fullcheck.sh
index f8c671e0..db63921d 100755
--- a/test/fullcheck.sh
+++ b/test/fullcheck.sh
@@ -2,17 +2,17 @@
VALGRIND=''
if [ -x /usr/bin/valgrind -o -x /opt/local/bin/valgrind ]; then
- VALGRIND=valgrind
+ VALGRIND="valgrind -q"
fi
-export MallocGuardEdges=1
-export MallocScribble=1
-export MallocPreScribble=1
-export MallocCheckHeapStart=100
-export MallocCheckHeapEach=100
-export DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib
-export MALLOC_PROTECT_BEFORE=1
-export MALLOC_FILL_SPACE=1
-export MALLOC_STRICT_SIZE=1
+#export MallocGuardEdges=1
+#export MallocScribble=1
+#export MallocPreScribble=1
+#export MallocCheckHeapStart=100
+#export MallocCheckHeapEach=100
+#export DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib
+#export MALLOC_PROTECT_BEFORE=1
+#export MALLOC_FILL_SPACE=1
+#export MALLOC_STRICT_SIZE=1
exec $VALGRIND $@
diff --git a/test/regress/1384C1D8.test b/test/regress/1384C1D8.test
new file mode 100644
index 00000000..77a07b7a
--- /dev/null
+++ b/test/regress/1384C1D8.test
@@ -0,0 +1,27 @@
+@alias OLD1 = NEW1
+
+2012-01-01 Something
+ OLD1 $10.00
+ Other
+
+!alias OLD2 = NEW2
+
+2012-01-01 Something
+ OLD2 $10.00
+ Other
+
+account NEW3
+ alias OLD3
+
+2012-01-01 Something
+ OLD3 $10.00
+ Other
+
+test bal
+ $10.00 NEW1
+ $10.00 NEW2
+ $10.00 NEW3
+ $-30.00 Other
+--------------------
+ 0
+end test
diff --git a/test/regress/14DB77E7.test b/test/regress/14DB77E7.test
index ee155afb..4d8734f9 100644
--- a/test/regress/14DB77E7.test
+++ b/test/regress/14DB77E7.test
@@ -13,6 +13,6 @@ P 2011-02-01 EUR 0.8576 GBP
test reg income:adse -X GBP -H
11-Jan-31 AdSense earnings Income:AdSense -11.00 EUR -11.00 EUR
-11-Feb-01 Commodities revalued <Revalued> -9.43 GBP -9.43 GBP
+11-Feb-28 Commodities revalued <Revalued> -9.43 GBP -9.43 GBP
11-Feb-28 AdSense earnings Income:AdSense -8.58 GBP -18.01 GBP
end test
diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test
index df4fef1c..a8a93832 100644
--- a/test/regress/25A099C9.test
+++ b/test/regress/25A099C9.test
@@ -1,43 +1,43 @@
-test -f $sourcepath/src/amount.h reg -> 20
+test -f src/amount.h reg -> 20
__ERROR__
-While parsing file "$sourcepath/src/amount.h", line 2:
+While parsing file "src/amount.h", line 2:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 33:
+While parsing file "src/amount.h", line 33:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 37:
+While parsing file "src/amount.h", line 37:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 66:
+While parsing file "src/amount.h", line 66:
Error: No quantity specified for amount
-While parsing file "$sourcepath/src/amount.h", line 69:
+While parsing file "src/amount.h", line 69:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 83:
+While parsing file "src/amount.h", line 83:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 93:
+While parsing file "src/amount.h", line 93:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 99:
+While parsing file "src/amount.h", line 99:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 121:
+While parsing file "src/amount.h", line 121:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 132:
+While parsing file "src/amount.h", line 132:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 693:
+While parsing file "src/amount.h", line 693:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 723:
+While parsing file "src/amount.h", line 723:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 731:
+While parsing file "src/amount.h", line 731:
Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/src/amount.h", line 734:
+While parsing file "src/amount.h", line 734:
Error: Invalid date/time: line amount_t amoun
-While parsing file "$sourcepath/src/amount.h", line 740:
+While parsing file "src/amount.h", line 740:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 746:
+While parsing file "src/amount.h", line 746:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 752:
+While parsing file "src/amount.h", line 752:
Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/src/amount.h", line 758:
+While parsing file "src/amount.h", line 758:
Error: Invalid date/time: line std::ostream&
-While parsing file "$sourcepath/src/amount.h", line 765:
+While parsing file "src/amount.h", line 765:
Error: Invalid date/time: line std::istream&
-While parsing file "$sourcepath/src/amount.h", line 771:
+While parsing file "src/amount.h", line 771:
Error: Unexpected whitespace at beginning of line
end test
diff --git a/test/regress/96A8E4A1.test b/test/regress/96A8E4A1.test
new file mode 100644
index 00000000..93fb55d2
--- /dev/null
+++ b/test/regress/96A8E4A1.test
@@ -0,0 +1,10 @@
+2011-01-31 * Test
+ Expenses:Travel 1 "Spr MegaBonus"
+ Assets:Voucher
+
+test -X EUR -H bal
+ -1 "Spr MegaBonus" Assets:Voucher
+ 1 "Spr MegaBonus" Expenses:Travel
+--------------------
+ 0
+end test
diff --git a/test/regress/9E0E606D.test b/test/regress/9E0E606D.test
new file mode 100644
index 00000000..86b8e36f
--- /dev/null
+++ b/test/regress/9E0E606D.test
@@ -0,0 +1,19 @@
+D 1000.00 GBP
+
+P 2011-02-01 EUR 0.8576 GBP
+P 2011-03-01 EUR 0.8612 GBP
+P 2011-04-01 EUR 0.8510 GBP
+
+2011-01-31 * AdSense earnings
+ Assets:Receivable:AdSense 11.00 EUR
+ Income:AdSense
+
+2011-02-28 * AdSense earnings
+ Assets:Receivable:AdSense 10.00 EUR
+ Income:AdSense
+
+test reg income:ad -X GBP -H
+11-Jan-31 AdSense earnings Income:AdSense -11.00 EUR -11.00 EUR
+11-Feb-28 Commodities revalued <Revalued> -9.43 GBP -9.43 GBP
+11-Feb-28 AdSense earnings Income:AdSense -8.58 GBP -18.01 GBP
+end test
diff --git a/test/regress/A8FCC765.dat b/test/regress/A8FCC765.dat
new file mode 100644
index 00000000..abc51a0a
--- /dev/null
+++ b/test/regress/A8FCC765.dat
@@ -0,0 +1,2 @@
+P 2012-03-16 06:47:12 CAD $2.50
+P 2012-03-17 06:47:12 CAD $3.50
diff --git a/test/regress/A8FCC765.test b/test/regress/A8FCC765.test
new file mode 100644
index 00000000..1adf6053
--- /dev/null
+++ b/test/regress/A8FCC765.test
@@ -0,0 +1,8 @@
+2012-03-17 KFC
+ Expenses:Food 20 CAD
+ Assets:Cash
+
+test pricedb --price-db test/regress/A8FCC765.dat
+P 2012/03/16 06:47:12 CAD $2.5
+P 2012/03/17 06:47:12 CAD $3.5
+end test
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 5d299b05..f1582e50 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -121,6 +121,7 @@ pkginclude_HEADERS = \
src/xact.h \
src/account.h \
src/journal.h \
+ src/context.h \
src/temps.h \
src/archive.h \
src/timelog.h \
diff --git a/tools/times.sh b/tools/times.sh
index 444da993..d15431bc 100755
--- a/tools/times.sh
+++ b/tools/times.sh
@@ -2,5 +2,5 @@
time test/RegressTests.py ./ledger test/regress
time test/RegressTests.py ./ledger test/regress --verify
-time test/RegressTests.py ./ledger test/regress --gmalloc
-time test/RegressTests.py ./ledger test/regress --verify --gmalloc
+#time test/RegressTests.py ./ledger test/regress --gmalloc
+#time test/RegressTests.py ./ledger test/regress --verify --gmalloc