Merge branch 'next'
This commit is contained in:
commit
eda6cbd014
91 changed files with 6112 additions and 4751 deletions
15
acprep
15
acprep
|
|
@ -955,7 +955,10 @@ class PrepareBuild(CommandLineApp):
|
|||
else:
|
||||
gcc_version = "42"
|
||||
|
||||
if self.current_flavor == 'debug' or self.current_flavor == 'gcov':
|
||||
if gcc_version != "42":
|
||||
self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1')
|
||||
|
||||
if self.current_flavor == 'debug':
|
||||
if exists('/usr/local/stow/cppunit-gcc%s/include' % gcc_version):
|
||||
self.sys_include_dirs.insert(
|
||||
0, '/usr/local/stow/cppunit-gcc%s/include' % gcc_version)
|
||||
|
|
@ -968,10 +971,11 @@ class PrepareBuild(CommandLineApp):
|
|||
self.sys_library_dirs.insert(
|
||||
0, '/usr/local/stow/icu-gcc%s/lib' % gcc_version)
|
||||
|
||||
self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1')
|
||||
self.configure_args.append('--disable-shared')
|
||||
|
||||
self.options.use_glibcxx_debug = True
|
||||
elif self.current_flavor == 'gcov':
|
||||
self.configure_args.append('--disable-shared')
|
||||
else:
|
||||
self.CXXFLAGS.append('-march=nocona')
|
||||
self.CXXFLAGS.append('-msse3')
|
||||
|
|
@ -1201,7 +1205,7 @@ class PrepareBuild(CommandLineApp):
|
|||
|
||||
self.log.debug('Using gcc version: %s' % gcc_version)
|
||||
|
||||
if self.current_flavor == 'debug' or self.current_flavor == 'gcov':
|
||||
if self.current_flavor == 'debug':
|
||||
if self.options.use_glibcxx_debug:
|
||||
self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags')
|
||||
self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1')
|
||||
|
|
@ -1282,6 +1286,9 @@ class PrepareBuild(CommandLineApp):
|
|||
self.LDFLAGS.append(i)
|
||||
|
||||
def setup_flavor_gcov(self):
|
||||
# NDEBUG is set so that branch coverage ignores the never-taken else
|
||||
# branch inside assert statements.
|
||||
self.CPPFLAGS.append('-DNDEBUG=1')
|
||||
self.CXXFLAGS.append('-g')
|
||||
self.CXXFLAGS.append('-fprofile-arcs')
|
||||
self.CXXFLAGS.append('-ftest-coverage')
|
||||
|
|
@ -1405,7 +1412,7 @@ class PrepareBuild(CommandLineApp):
|
|||
else:
|
||||
make_args.append(arg)
|
||||
|
||||
if self.options.jobs > 1:
|
||||
if self.options.jobs > 1 and self.current_flavor != 'gcov':
|
||||
make_args.append('-j%d' % self.options.jobs)
|
||||
make_args.append('JOBS=%d' % self.options.jobs)
|
||||
|
||||
|
|
|
|||
45
dist/Portfile
vendored
45
dist/Portfile
vendored
|
|
@ -4,26 +4,24 @@
|
|||
PortSystem 1.0
|
||||
|
||||
name ledger-devel
|
||||
version 3.0-20100611
|
||||
version 3.0.0-20100615
|
||||
homepage http://www.newartisans.com/software/ledger.html
|
||||
categories finance accounting reporting
|
||||
categories finance
|
||||
|
||||
description A command-line, double-entry accounting tool.
|
||||
long_description Ledger is a powerful, double-entry accounting system that \
|
||||
is accessed from the UNIX command-line.
|
||||
|
||||
maintainers johnw@newartisans.com
|
||||
maintainers newartisans.com:johnw
|
||||
|
||||
platforms darwin
|
||||
|
||||
use_bzip2 yes
|
||||
master_sites http://ftp.newartisans.com/pub/ledger/:source
|
||||
distname ${name}-${version}
|
||||
distfiles ${distname}${extract.suffix}:source
|
||||
checksums ${distname}${extract.suffix} \
|
||||
md5 0ab9a855719df536a85f7ea5238b8a6e \
|
||||
sha1 e2ee9e2951fd37bac50c91046f097c11294a6e8e \
|
||||
rmd160 72cdfe76add63425b1ade1d03479e837e9f2dafe
|
||||
master_sites http://ftp.newartisans.com/pub/ledger/
|
||||
distname ledger-${version}
|
||||
checksums md5 980e819c4cb68b8777849a44316e0edc \
|
||||
sha1 ff1b281ce6ddfeb5814ce59bd4d69b97ddb21f7e \
|
||||
rmd160 a40e64bf21c9c132619b0921dee0e12299e3938a
|
||||
|
||||
depends_build port:automake \
|
||||
port:autoconf \
|
||||
|
|
@ -35,23 +33,15 @@ depends_lib port:gettext \
|
|||
port:boost \
|
||||
port:libedit
|
||||
|
||||
# gmp and mpfr are not universal
|
||||
universal_variant no
|
||||
|
||||
configure.args --with-extra-includes=${prefix}/include \
|
||||
--with-extra-libs=${prefix}/lib
|
||||
|
||||
build.args DYLD_LIBRARY_PATH=${worksrcpath}/ledger/.libs
|
||||
|
||||
platform darwin 9 {}
|
||||
platform darwin 10 {}
|
||||
|
||||
destroot.args DESTDIR=${destroot}${prefix} \
|
||||
DYLD_LIBRARY_PATH=${worksrcpath}/ledger/.libs \
|
||||
docprefix=${destroot}/share/doc
|
||||
|
||||
post-destroot {}
|
||||
|
||||
variant debug description {Enable debug mode} {
|
||||
configure.args-append --enable-debug=yes
|
||||
}
|
||||
|
|
@ -60,12 +50,10 @@ variant icu description {Enable full Unicode support} {
|
|||
if {[variant_isset python25]} {
|
||||
depends_lib-delete port:boost+python25
|
||||
depends_lib-append port:boost+icu+python25
|
||||
}
|
||||
else if {[variant_isset python26]} {
|
||||
} elsif {[variant_isset python26]} {
|
||||
depends_lib-delete port:boost+python26
|
||||
depends_lib-append port:boost+icu+python26
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
depends_lib-delete port:boost
|
||||
depends_lib-append port:boost+icu
|
||||
}
|
||||
|
|
@ -76,8 +64,7 @@ variant python25 description {build python 2.5 support} conflicts python26 {
|
|||
if {[variant_isset icu]} {
|
||||
depends_lib-delete port:boost+icu
|
||||
depends_lib-append port:boost+icu+python25
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
depends_lib-delete port:boost
|
||||
depends_lib-append port:boost+python25
|
||||
}
|
||||
|
|
@ -89,15 +76,13 @@ variant python26 description {build python 2.6 support} conflicts python25 {
|
|||
if {[variant_isset icu]} {
|
||||
depends_lib-delete port:boost+icu
|
||||
depends_lib-append port:boost+icu+python26
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
depends_lib-delete port:boost
|
||||
depends_lib-append port:boost+python26
|
||||
}
|
||||
depends_lib-append port:python26
|
||||
}
|
||||
|
||||
#livecheck.check regex
|
||||
#livecheck.url ${homepage}
|
||||
#livecheck.regex "Latest Stable Ledger \\(Version (\\d+.\\d+.\\d+)\\)"
|
||||
|
||||
livecheck.check regex
|
||||
livecheck.url [lindex ${master_sites} 0]
|
||||
livecheck.regex ${name}-(\[0-9.-\]+)\\.tar
|
||||
|
|
|
|||
17
doc/NEWS
17
doc/NEWS
|
|
@ -13,6 +13,23 @@ features, please see the manual.
|
|||
To see 2.6 behavior, use "bal -n" in 3.0. The -s option no longer has any
|
||||
effect on balance reports.
|
||||
|
||||
* 2.6.3
|
||||
|
||||
- Minor fixes to allow for compilation with gcc 4.4.
|
||||
|
||||
* 2.6.2
|
||||
|
||||
- Bug fix: Command-line options, such as -O, now override init-file options
|
||||
such as -V.
|
||||
|
||||
- Bug fix: "cat data | ledger -f -" now works.
|
||||
|
||||
- Bug fix: --no-cache is now honored. Previously, it was writing out a cache
|
||||
file named "<none>".
|
||||
|
||||
- Bug fix: Using %.2X in a format string now outputs 2 spaces if the state is
|
||||
cleared.
|
||||
|
||||
* 2.6.1
|
||||
|
||||
- Added the concept of "balance setting transactions":
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.Dd June 15, 2010
|
||||
.Dd June 22, 2010
|
||||
.Dt ledger 1
|
||||
.Sh NAME
|
||||
.Nm ledger
|
||||
|
|
@ -275,6 +275,7 @@ transactions they are contained in. See the manual for more information.
|
|||
.It Fl \-base
|
||||
.It Fl \-basis Pq Fl B
|
||||
.It Fl \-begin Ar DATE Pq Fl b
|
||||
.It Fl \-bold-if Ar EXPR
|
||||
.It Fl \-budget
|
||||
.It Fl \-budget-format Ar FMT
|
||||
.It Fl \-by-payee Pq Fl P
|
||||
|
|
@ -336,6 +337,7 @@ See
|
|||
.It Fl \-help-disp
|
||||
.It Fl \-import Ar STR
|
||||
.It Fl \-init-file Ar FILE
|
||||
.It Fl \-inject Ar STR
|
||||
.It Fl \-input-date-format Ar DATEFMT
|
||||
.It Fl \-invert
|
||||
.It Fl \-last Ar INT
|
||||
|
|
|
|||
322
doc/ledger3.texi
Normal file
322
doc/ledger3.texi
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
|
||||
@setfilename ledger.info
|
||||
@settitle Ledger: Command-Line Accounting
|
||||
|
||||
@dircategory User Applications
|
||||
@copying
|
||||
Copyright (c) 2003-2010, John Wiegley. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of New Artisans LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@end copying
|
||||
|
||||
@documentencoding UTF-8
|
||||
|
||||
@iftex
|
||||
@finalout
|
||||
@end iftex
|
||||
|
||||
@titlepage
|
||||
@title Ledger: Command-Line Accounting
|
||||
@author John Wiegley
|
||||
@end titlepage
|
||||
|
||||
@direntry
|
||||
* Ledger: (ledger). Command-Line Accounting
|
||||
@end direntry
|
||||
|
||||
@contents
|
||||
|
||||
@ifnottex
|
||||
@node Top, , (dir), (dir)
|
||||
@top Overview
|
||||
|
||||
@insertcopying
|
||||
@end ifnottex
|
||||
|
||||
@ifnottex
|
||||
@section Copyright
|
||||
@insertcopying
|
||||
@end ifnottex
|
||||
|
||||
@chapter Introduction
|
||||
|
||||
@chapter Principles of accounting
|
||||
|
||||
@chapter Keeping a journal
|
||||
|
||||
@chapter Basic reporting commands
|
||||
|
||||
@chapter Command-line syntax
|
||||
|
||||
@chapter Journal data format
|
||||
|
||||
This chapter offers a complete description of the journal data format,
|
||||
suitable for implementors in other languages to follow. For users,
|
||||
the chapter on keeping a journal is less extensive, but more typical
|
||||
of common usage (@pxref{Keeping a journal}).
|
||||
|
||||
Data is collected in the form of @dfn{transactions} which occur in one
|
||||
or more @dfn{journal files}. Each transaction, in turn, is made up of
|
||||
one or more @dfn{postings}, which describe how @dfn{amounts} flow from
|
||||
one @dfn{account} to another. Here is an example of the simplest of
|
||||
journal files:
|
||||
|
||||
@example
|
||||
2010/05/31 Just an example
|
||||
Expenses:Some:Account $100.00
|
||||
Income:Another:Account
|
||||
@end example
|
||||
|
||||
In this example, there is a transaction date, a payee, or description
|
||||
of the transaction, and two postings. The postings show movement of
|
||||
one hundred dollars from an account within the Income hierarchy, to
|
||||
the specified expense account. The name and meaning of these accounts
|
||||
in arbitrary, with no preferences implied, although you will find it
|
||||
useful to follow standard accounting practice (@pxref{Principles of
|
||||
accounting}}.
|
||||
|
||||
Since an amount is missing from the second posting, it is assumed to
|
||||
be the inverse of the first. This guarantee the cardinal rule of
|
||||
double-entry accounting: the sum of every transaction must balance to
|
||||
zero, or it is in error. Whenever Ledger encounters a @dfn{null
|
||||
posting} in a transaction, it uses it to balance the remainder.
|
||||
|
||||
It is also typical---though not enforced---to think of the first
|
||||
posting as the destination, and the final as the source. Thus, the
|
||||
amount of the first posting is typically positive. Consider:
|
||||
|
||||
@example
|
||||
2010/05/31 An income transaction
|
||||
Assets:Checking $1,000.00
|
||||
Income:Salary
|
||||
|
||||
2010/05/31 An expense transaction
|
||||
Expenses:Dining $100.00
|
||||
Assets:Checking
|
||||
@end example
|
||||
|
||||
@section Specifying amounts
|
||||
|
||||
The heart of a journal is the amounts it records, and this fact is
|
||||
reflected in the diversity of amount expressions allowed. All of them
|
||||
are covered here, though it must be said that sometimes, there are
|
||||
multiple ways to achieve a desired result.
|
||||
|
||||
@subsection Integer amounts
|
||||
|
||||
In the simplest form, bare decimal numbers are accepted:
|
||||
|
||||
@example
|
||||
2010/05/31 An income transaction
|
||||
Assets:Checking 1000.00
|
||||
Income:Salary
|
||||
@end example
|
||||
|
||||
Such amounts may only use an optional period for a decimal point.
|
||||
These are referred to as @dfn{integer amounts} or @dfn{uncommoditized
|
||||
amounts}. In most ways they are similar to @dfn{commoditized
|
||||
amounts}, but for one signficant difference: They always display in
|
||||
reports with @dfn{full precision}. More on this in a moment. For
|
||||
now, a word must be said about how Ledger stores numbers.
|
||||
|
||||
Every number parsed by Ledger is stored internally as an
|
||||
infinite-precision rational value. Floating-point math is never used,
|
||||
as it cannot be trusted to maintain precision of values. So, in the
|
||||
case of @samp{1000.00} above, the internal value is @samp{100000/100}.
|
||||
|
||||
While rational numbers are great at not losing precision, the question
|
||||
arises: How should they be displayed? A number like @samp{100000/100}
|
||||
is no problem, since it represents a clean decimal fraction. But what
|
||||
about when the number @samp{1/1} is divided by three? How should one
|
||||
print @samp{1/3}, an infinitely repeating decimal?
|
||||
|
||||
Ledger gets around this problem by rendering rationals into decimal at
|
||||
the last possible moment, and only for display. As such, some
|
||||
rounding must, at times, occur. If this rounding would affect the
|
||||
calculation of a running total, special accommodation postings are
|
||||
generated to make you aware it has happened. In practice, it happens
|
||||
rarely, but even then it does not reflect adjustment of the
|
||||
@emph{internal amount}, only the displayed amount.
|
||||
|
||||
What has still not been answered is how Ledger rounds values. Should
|
||||
@samp{1/3} be printed as @samp{0.33} or @samp{0.33333}? For
|
||||
commoditized amounts, the number of decimal places is decided by
|
||||
observing how each commodity is used; but in the case of integer
|
||||
amounts, an arbitrary factor must be chosen. Initially, this factor
|
||||
is six. Thus, @samp{1/3} is printed back as @samp{0.333333}.
|
||||
Further, this rounding factor becomes associated with each particular
|
||||
value, and is carried through mathematical operations. For example,
|
||||
if that particular number were multiplied by itself, the decimal
|
||||
precision of the result would be twelve. Addition and subtraction do
|
||||
not affect precision.
|
||||
|
||||
Since each integer amount retains its own display precision, this is
|
||||
called @dfn{full precision}, as opposed to commoditized amounts, which
|
||||
always look to their commodity to know what precision they should
|
||||
round to, and so use @dfn{commodity precision}.
|
||||
|
||||
@subsection Commoditized amounts
|
||||
|
||||
A @dfn{commoditized amount} is an integer amount which has an
|
||||
associated commodity. This commodity can appear before or after the
|
||||
amount, and may or may not be separated from it by a space. Most
|
||||
characters are allowed in a commodity name, except for the following:
|
||||
|
||||
@itemize
|
||||
@item Any kind of whitespace
|
||||
@item Numerical digits
|
||||
@item Punctuation: @samp{.,;:?!}
|
||||
@item Mathematical and logical operators: @samp{-+*/^&|=}
|
||||
@item Bracketing characters: @samp{<>[](){}}
|
||||
@item The at symbol: @samp{@}
|
||||
@end itemize
|
||||
|
||||
And yet, any of these may appear in a commodity name if it is
|
||||
surrounded by double quotes, for example:
|
||||
|
||||
@example
|
||||
100 "EUN+133"
|
||||
@end example
|
||||
|
||||
If a @dfn{quoted commodity} is found, it is displayed in quotes as
|
||||
well, to avoid any confusion as to which part is the amount, and which
|
||||
part is the commodity.
|
||||
|
||||
Another feature of commoditized amounts is that they are reported back
|
||||
in the same form as parsed. If you specify dollar amounts using
|
||||
@samp{$100}, they will print the same; likewise with @samp{100 $} or
|
||||
@samp{$100.000}. You may even use decimal commas, such as
|
||||
@samp{$100,00}, or thousand-marks, as in @samp{$10,000.00}.
|
||||
|
||||
These display characteristics become associated with the commodity,
|
||||
with the result being that all amounts of the same commodity are
|
||||
reported consistently. Where this is most noticeable is the
|
||||
@dfn{display precision}, which is determined by the most precise value
|
||||
seen for a given commodity. In most cases.
|
||||
|
||||
Ledger makes a distinction by @dfn{observed amounts} and unobserved
|
||||
amounts. An observed amount is critiqued by Ledger to determine how
|
||||
amounts using that commodity should be displayed; unobserved amounts
|
||||
are significant in their value only---no matter how they are
|
||||
specified, it does not change how other amounts in that commodity will
|
||||
be displayed.
|
||||
|
||||
An example of this is found in cost expressions, covered next.
|
||||
|
||||
@section Posting costs
|
||||
|
||||
You have seen how to specify either a commoditized or an integer
|
||||
amount for a posting. But what if the amount you paid for something
|
||||
was in one commodity, and the amount received was another? There are
|
||||
two main ways to express this:
|
||||
|
||||
@example
|
||||
2010/05/31 Farmer's Market
|
||||
Assets:My Larder 100 apples
|
||||
Assets:Checking $20.00
|
||||
@end example
|
||||
|
||||
In this example, you have paid twenty dollars for one hundred apples.
|
||||
The cost to you is twenty cents per apple, and Ledger calculates this
|
||||
implied cost for you. You can also make the cost explicit using a
|
||||
@dfn{cost amount}:
|
||||
|
||||
@example
|
||||
2010/05/31 Farmer's Market
|
||||
Assets:My Larder 100 apples @ $0.200000
|
||||
Assets:Checking
|
||||
@end example
|
||||
|
||||
Here the @dfn{per-unit cost} is given explicitly in the form of a cost
|
||||
amount; and since cost amount are @emph{unobserved}, the use of six
|
||||
decimal places has no effect on how dollar amounts are displayed in
|
||||
the final report. You can also specify the @dfn{total cost}:
|
||||
|
||||
@example
|
||||
2010/05/31 Farmer's Market
|
||||
Assets:My Larder 100 apples @@ $20
|
||||
Assets:Checking
|
||||
@end example
|
||||
|
||||
These three forms have identical meaning. In most cases the first is
|
||||
preferred, but the second two are necessary when more than two
|
||||
postings are involved:
|
||||
|
||||
@example
|
||||
2010/05/31 Farmer's Market
|
||||
Assets:My Larder 100 apples @ $0.200000
|
||||
Assets:My Larder 100 pineapples @ $0.33
|
||||
Assets:My Larder 100 "crab apples" @ $0.04
|
||||
Assets:Checking
|
||||
@end example
|
||||
|
||||
Here the implied cost is @samp{$57.00}, which is entered into the null
|
||||
posting automatically so that the transaction balances.
|
||||
|
||||
@subsection Primary commodities
|
||||
|
||||
In every transaction involving more than one commodity, there is
|
||||
always one which is the @dfn{primary commodity}. This commodity
|
||||
should be thought of as the exchange commodity, or the commodity used
|
||||
to buy and sells units of the other commodity. In the fruit examples
|
||||
above, dollars are the primary commodity. This is decided by Ledger
|
||||
on the placement of the commodity in the transaction:
|
||||
|
||||
@example
|
||||
2010/05/31 Sample Transaction
|
||||
Expenses 100 secondary
|
||||
Assets 50 primary
|
||||
|
||||
2010/05/31 Sample Transaction
|
||||
Expenses 100 secondary @ 0.5 primary
|
||||
Assets
|
||||
|
||||
2010/05/31 Sample Transaction
|
||||
Expenses 100 secondary @@ 50 primary
|
||||
Assets
|
||||
@end example
|
||||
|
||||
The only case where knowledge of primary versus secondary comes into
|
||||
play is in reports that use the @option{-V} or @option{-B} options.
|
||||
With these, only primary commodities are shown.
|
||||
|
||||
If a transaction uses only one commodity, this commodity is also
|
||||
considered a primary. In fact, when Ledger goes about ensures that
|
||||
all transactions balance to zero, it only ever asks this of primary
|
||||
commodities.
|
||||
|
||||
@chapter Report queries
|
||||
|
||||
@chapter Value expressions
|
||||
|
||||
@chapter Format strings
|
||||
|
||||
@chapter Extending with Python
|
||||
|
||||
@bye
|
||||
|
|
@ -626,7 +626,7 @@ void account_t::xdata_t::details_t::update(post_t& post,
|
|||
|
||||
if (gather_all) {
|
||||
accounts_referenced.insert(post.account->fullname());
|
||||
payees_referenced.insert(post.xact->payee);
|
||||
payees_referenced.insert(post.payee());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -743,21 +743,24 @@ amount_t::value(const optional<datetime_t>& moment,
|
|||
optional<price_point_t> point;
|
||||
optional<commodity_t&> comm(in_terms_of);
|
||||
|
||||
if (comm && commodity().referent() == comm->referent()) {
|
||||
return *this;
|
||||
}
|
||||
else if (has_annotation() && annotation().price) {
|
||||
if (has_annotation() && annotation().price) {
|
||||
if (annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
|
||||
point = price_point_t();
|
||||
point->price = *annotation().price;
|
||||
DEBUG("commodity.prices.find",
|
||||
"amount_t::value: fixated price = " << point->price);
|
||||
}
|
||||
else if (! in_terms_of) {
|
||||
else if (! comm) {
|
||||
comm = annotation().price->commodity();
|
||||
}
|
||||
}
|
||||
|
||||
if (! point) {
|
||||
if (comm && commodity().referent() == comm->referent())
|
||||
return *this;
|
||||
|
||||
point = commodity().find_price(comm, moment);
|
||||
|
||||
// Whether a price was found or not, check whether we should attempt
|
||||
// to download a price from the Internet. This is done if (a) no
|
||||
// price was found, or (b) the price is "stale" according to the
|
||||
|
|
|
|||
|
|
@ -166,15 +166,27 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
|
|||
|
||||
commodity_t * new_comm;
|
||||
|
||||
bool keep_price = (what_to_keep.keep_price &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_PRICE_CALCULATED)));
|
||||
bool keep_date = (what_to_keep.keep_date &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_DATE_CALCULATED)));
|
||||
bool keep_tag = (what_to_keep.keep_tag &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_TAG_CALCULATED)));
|
||||
bool keep_price =
|
||||
((what_to_keep.keep_price ||
|
||||
(details.has_flags(ANNOTATION_PRICE_FIXATED) &&
|
||||
has_flags(COMMODITY_SAW_ANN_PRICE_FLOAT) &&
|
||||
has_flags(COMMODITY_SAW_ANN_PRICE_FIXATED))) &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_PRICE_CALCULATED)));
|
||||
bool keep_date =
|
||||
(what_to_keep.keep_date &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_DATE_CALCULATED)));
|
||||
bool keep_tag =
|
||||
(what_to_keep.keep_tag &&
|
||||
(! what_to_keep.only_actuals ||
|
||||
! details.has_flags(ANNOTATION_TAG_CALCULATED)));
|
||||
|
||||
DEBUG("commodity.annotated.strip",
|
||||
"Reducing commodity " << *this << std::endl
|
||||
<< " keep price " << keep_price << " "
|
||||
<< " keep date " << keep_date << " "
|
||||
<< " keep tag " << keep_tag);
|
||||
|
||||
if ((keep_price && details.price) ||
|
||||
(keep_date && details.date) ||
|
||||
|
|
@ -184,12 +196,24 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
|
|||
(referent(), annotation_t(keep_price ? details.price : none,
|
||||
keep_date ? details.date : none,
|
||||
keep_tag ? details.tag : none));
|
||||
} else {
|
||||
new_comm = &referent();
|
||||
|
||||
// Transfer over any relevant annotation flags, as they still apply.
|
||||
if (new_comm->annotated) {
|
||||
annotation_t& new_details(as_annotated_commodity(*new_comm).details);
|
||||
if (keep_price)
|
||||
new_details.add_flags(details.flags() &
|
||||
(ANNOTATION_PRICE_CALCULATED |
|
||||
ANNOTATION_PRICE_FIXATED));
|
||||
if (keep_date)
|
||||
new_details.add_flags(details.flags() & ANNOTATION_DATE_CALCULATED);
|
||||
if (keep_tag)
|
||||
new_details.add_flags(details.flags() & ANNOTATION_TAG_CALCULATED);
|
||||
}
|
||||
|
||||
return *new_comm;
|
||||
}
|
||||
|
||||
assert(new_comm);
|
||||
return *new_comm;
|
||||
return referent();
|
||||
}
|
||||
|
||||
void annotated_commodity_t::write_annotations
|
||||
|
|
|
|||
14
src/chain.cc
14
src/chain.cc
|
|
@ -67,8 +67,8 @@ post_handler_ptr chain_pre_post_handlers(post_handler_ptr base_handler,
|
|||
// future balance.
|
||||
|
||||
if (report.budget_flags != BUDGET_NO_BUDGET) {
|
||||
budget_posts * budget_handler = new budget_posts(handler,
|
||||
report.budget_flags);
|
||||
budget_posts * budget_handler =
|
||||
new budget_posts(handler, report.terminus.date(), report.budget_flags);
|
||||
budget_handler->add_period_xacts(report.session.journal->period_xacts);
|
||||
handler.reset(budget_handler);
|
||||
|
||||
|
|
@ -202,8 +202,8 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
|
|||
// period_posts is like subtotal_posts, but it subtotals according to time
|
||||
// periods rather than totalling everything.
|
||||
//
|
||||
// dow_posts is like period_posts, except that it reports all the posts
|
||||
// that fall on each subsequent day of the week.
|
||||
// day_of_week_posts is like period_posts, except that it reports
|
||||
// all the posts that fall on each subsequent day of the week.
|
||||
if (report.HANDLED(equity))
|
||||
handler.reset(new posts_as_equity(handler, expr));
|
||||
else if (report.HANDLED(subtotal))
|
||||
|
|
@ -211,7 +211,7 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
|
|||
}
|
||||
|
||||
if (report.HANDLED(dow))
|
||||
handler.reset(new dow_posts(handler, expr));
|
||||
handler.reset(new day_of_week_posts(handler, expr));
|
||||
else if (report.HANDLED(by_payee))
|
||||
handler.reset(new by_payee_posts(handler, expr));
|
||||
|
||||
|
|
@ -258,6 +258,10 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
|
|||
if (report.HANDLED(related))
|
||||
handler.reset(new related_posts(handler, report.HANDLED(related_all)));
|
||||
|
||||
if (report.HANDLED(inject_))
|
||||
handler.reset(new inject_posts(handler, report.HANDLED(inject_).str(),
|
||||
report.session.journal->master));
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,16 +164,19 @@ protected:
|
|||
class base_t : public noncopyable, public supports_flags<uint_least16_t>
|
||||
{
|
||||
public:
|
||||
#define COMMODITY_STYLE_DEFAULTS 0x000
|
||||
#define COMMODITY_STYLE_SUFFIXED 0x001
|
||||
#define COMMODITY_STYLE_SEPARATED 0x002
|
||||
#define COMMODITY_STYLE_DECIMAL_COMMA 0x004
|
||||
#define COMMODITY_STYLE_THOUSANDS 0x008
|
||||
#define COMMODITY_NOMARKET 0x010
|
||||
#define COMMODITY_BUILTIN 0x020
|
||||
#define COMMODITY_WALKED 0x040
|
||||
#define COMMODITY_KNOWN 0x080
|
||||
#define COMMODITY_PRIMARY 0x100
|
||||
#define COMMODITY_STYLE_DEFAULTS 0x000
|
||||
#define COMMODITY_STYLE_SUFFIXED 0x001
|
||||
#define COMMODITY_STYLE_SEPARATED 0x002
|
||||
#define COMMODITY_STYLE_DECIMAL_COMMA 0x004
|
||||
#define COMMODITY_STYLE_THOUSANDS 0x008
|
||||
#define COMMODITY_NOMARKET 0x010
|
||||
#define COMMODITY_BUILTIN 0x020
|
||||
#define COMMODITY_WALKED 0x040
|
||||
#define COMMODITY_KNOWN 0x080
|
||||
#define COMMODITY_PRIMARY 0x100
|
||||
#define COMMODITY_SAW_ANNOTATED 0x200
|
||||
#define COMMODITY_SAW_ANN_PRICE_FLOAT 0x400
|
||||
#define COMMODITY_SAW_ANN_PRICE_FIXATED 0x800
|
||||
|
||||
string symbol;
|
||||
amount_t::precision_t precision;
|
||||
|
|
|
|||
|
|
@ -97,18 +97,20 @@ value_t convert_command(call_scope_t& args)
|
|||
}
|
||||
|
||||
bool matched = false;
|
||||
post_map_t::iterator i = post_map.find(- xact->posts.front()->amount);
|
||||
if (i != post_map.end()) {
|
||||
std::list<post_t *>& post_list((*i).second);
|
||||
foreach (post_t * post, post_list) {
|
||||
if (xact->code && post->xact->code &&
|
||||
*xact->code == *post->xact->code) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
else if (xact->actual_date() == post->actual_date()) {
|
||||
matched = true;
|
||||
break;
|
||||
if (! xact->posts.front()->amount.is_null()) {
|
||||
post_map_t::iterator i = post_map.find(- xact->posts.front()->amount);
|
||||
if (i != post_map.end()) {
|
||||
std::list<post_t *>& post_list((*i).second);
|
||||
foreach (post_t * post, post_list) {
|
||||
if (xact->code && post->xact->code &&
|
||||
*xact->code == *post->xact->code) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
else if (xact->actual_date() == post->actual_date()) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@ void expr_t::parse(std::istream& in, const parse_flags_t& flags,
|
|||
in.seekg(start_pos, std::ios::beg);
|
||||
scoped_array<char> buf
|
||||
(new char[static_cast<std::size_t>(end_pos - start_pos) + 1]);
|
||||
in.read(buf.get(), end_pos - start_pos);
|
||||
buf[end_pos - start_pos] = '\0';
|
||||
int len = static_cast<int>(end_pos) - static_cast<int>(start_pos);
|
||||
in.read(buf.get(), len);
|
||||
buf[len] = '\0';
|
||||
set_text(buf.get());
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
120
src/filters.cc
120
src/filters.cc
|
|
@ -266,6 +266,7 @@ void anonymize_posts::operator()(post_t& post)
|
|||
copy_xact_details = true;
|
||||
}
|
||||
xact_t& xact = temps.last_xact();
|
||||
xact.code = none;
|
||||
|
||||
if (copy_xact_details) {
|
||||
xact.copy_details(*post.xact);
|
||||
|
|
@ -523,7 +524,7 @@ display_filter_posts::display_filter_posts(post_handler_ptr handler,
|
|||
bool _show_rounding)
|
||||
: item_handler<post_t>(handler), report(_report),
|
||||
show_rounding(_show_rounding),
|
||||
rounding_account(temps.create_account(_("<Rounding>"))),
|
||||
rounding_account(temps.create_account(_("<Adjustment>"))),
|
||||
revalued_account(temps.create_account(_("<Revalued>")))
|
||||
{
|
||||
TRACE_CTOR(display_filter_posts,
|
||||
|
|
@ -1042,10 +1043,10 @@ void by_payee_posts::flush()
|
|||
|
||||
void by_payee_posts::operator()(post_t& post)
|
||||
{
|
||||
payee_subtotals_map::iterator i = payee_subtotals.find(post.xact->payee);
|
||||
payee_subtotals_map::iterator i = payee_subtotals.find(post.payee());
|
||||
if (i == payee_subtotals.end()) {
|
||||
payee_subtotals_pair
|
||||
temp(post.xact->payee,
|
||||
temp(post.payee(),
|
||||
shared_ptr<subtotal_posts>(new subtotal_posts(handler, amount_expr)));
|
||||
std::pair<payee_subtotals_map::iterator, bool> result
|
||||
= payee_subtotals.insert(temp);
|
||||
|
|
@ -1073,7 +1074,7 @@ void transfer_details::operator()(post_t& post)
|
|||
if (! substitute.is_null()) {
|
||||
switch (which_element) {
|
||||
case SET_DATE:
|
||||
temp.xdata().date = substitute.to_date();
|
||||
temp._date = substitute.to_date();
|
||||
break;
|
||||
|
||||
case SET_ACCOUNT: {
|
||||
|
|
@ -1112,7 +1113,7 @@ void transfer_details::operator()(post_t& post)
|
|||
item_handler<post_t>::operator()(temp);
|
||||
}
|
||||
|
||||
void dow_posts::flush()
|
||||
void day_of_week_posts::flush()
|
||||
{
|
||||
for (int i = 0; i < 7; i++) {
|
||||
foreach (post_t * post, days_of_the_week[i])
|
||||
|
|
@ -1143,20 +1144,44 @@ void budget_posts::report_budget_items(const date_t& date)
|
|||
|
||||
bool reported;
|
||||
do {
|
||||
std::list<pending_posts_list::iterator> posts_to_erase;
|
||||
|
||||
reported = false;
|
||||
foreach (pending_posts_list::value_type& pair, pending_posts) {
|
||||
for (pending_posts_list::iterator i = pending_posts.begin();
|
||||
i != pending_posts.end();
|
||||
i++) {
|
||||
pending_posts_list::value_type& pair(*i);
|
||||
|
||||
optional<date_t> begin = pair.first.start;
|
||||
if (! begin) {
|
||||
if (! pair.first.find_period(date))
|
||||
optional<date_t> range_begin;
|
||||
if (pair.first.range)
|
||||
range_begin = pair.first.range->begin();
|
||||
|
||||
DEBUG("budget.generate", "Finding period for pending post");
|
||||
if (! pair.first.find_period(range_begin ? *range_begin : date))
|
||||
continue;
|
||||
if (! pair.first.start)
|
||||
throw_(std::logic_error,
|
||||
_("Failed to find period for periodic transaction"));
|
||||
begin = pair.first.start;
|
||||
}
|
||||
assert(begin);
|
||||
|
||||
#if defined(DEBUG_ON)
|
||||
DEBUG("budget.generate", "begin = " << *begin);
|
||||
DEBUG("budget.generate", "date = " << date);
|
||||
if (pair.first.finish)
|
||||
DEBUG("budget.generate", "pair.first.finish = " << *pair.first.finish);
|
||||
#endif
|
||||
|
||||
if (*begin <= date &&
|
||||
(! pair.first.finish || *begin < *pair.first.finish)) {
|
||||
post_t& post = *pair.second;
|
||||
|
||||
++pair.first;
|
||||
if (! pair.first.start)
|
||||
posts_to_erase.push_back(i);
|
||||
|
||||
DEBUG("budget.generate", "Reporting budget for "
|
||||
<< post.reported_account()->fullname());
|
||||
|
||||
|
|
@ -1176,14 +1201,14 @@ void budget_posts::report_budget_items(const date_t& date)
|
|||
temp.xdata().add_flags(POST_EXT_COMPOUND);
|
||||
}
|
||||
|
||||
++pair.first;
|
||||
begin = *pair.first.start;
|
||||
|
||||
item_handler<post_t>::operator()(temp);
|
||||
|
||||
reported = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (pending_posts_list::iterator& i, posts_to_erase)
|
||||
pending_posts.erase(i);
|
||||
} while (reported);
|
||||
}
|
||||
|
||||
|
|
@ -1215,6 +1240,14 @@ void budget_posts::operator()(post_t& post)
|
|||
}
|
||||
}
|
||||
|
||||
void budget_posts::flush()
|
||||
{
|
||||
if (flags & BUDGET_BUDGETED)
|
||||
report_budget_items(terminus);
|
||||
|
||||
item_handler<post_t>::flush();
|
||||
}
|
||||
|
||||
void forecast_posts::add_post(const date_interval_t& period, post_t& post)
|
||||
{
|
||||
date_interval_t i(period);
|
||||
|
|
@ -1274,17 +1307,16 @@ void forecast_posts::flush()
|
|||
least = i;
|
||||
}
|
||||
|
||||
date_t& begin = *(*least).first.start;
|
||||
#if !defined(NO_ASSERTS)
|
||||
if ((*least).first.finish)
|
||||
assert(begin < *(*least).first.finish);
|
||||
assert(*(*least).first.start < *(*least).first.finish);
|
||||
#endif
|
||||
|
||||
// If the next date in the series for this periodic posting is more than 5
|
||||
// years beyond the last valid post we generated, drop it from further
|
||||
// consideration.
|
||||
date_t next = *(*least).first.next;
|
||||
assert(next > begin);
|
||||
date_t& next(*(*least).first.next);
|
||||
assert(next > *(*least).first.start);
|
||||
|
||||
if (static_cast<std::size_t>((next - last).days()) >
|
||||
static_cast<std::size_t>(365U) * forecast_years) {
|
||||
|
|
@ -1295,15 +1327,13 @@ void forecast_posts::flush()
|
|||
continue;
|
||||
}
|
||||
|
||||
begin = next;
|
||||
|
||||
// `post' refers to the posting defined in the period transaction. We
|
||||
// make a copy of it within a temporary transaction with the payee
|
||||
// "Forecast transaction".
|
||||
post_t& post = *(*least).second;
|
||||
xact_t& xact = temps.create_xact();
|
||||
xact.payee = _("Forecast transaction");
|
||||
xact._date = begin;
|
||||
xact._date = next;
|
||||
post_t& temp = temps.copy_post(post, xact);
|
||||
|
||||
// Submit the generated posting
|
||||
|
|
@ -1338,6 +1368,60 @@ void forecast_posts::flush()
|
|||
item_handler<post_t>::flush();
|
||||
}
|
||||
|
||||
inject_posts::inject_posts(post_handler_ptr handler,
|
||||
const string& tag_list,
|
||||
account_t * master)
|
||||
: item_handler<post_t>(handler)
|
||||
{
|
||||
TRACE_CTOR(inject_posts, "post_handler_ptr, string");
|
||||
|
||||
scoped_array<char> buf(new char[tag_list.length() + 1]);
|
||||
std::strcpy(buf.get(), tag_list.c_str());
|
||||
|
||||
for (char * q = std::strtok(buf.get(), ",");
|
||||
q;
|
||||
q = std::strtok(NULL, ",")) {
|
||||
|
||||
std::list<string> account_names;
|
||||
split_string(q, ':', account_names);
|
||||
account_t * account =
|
||||
create_temp_account_from_path(account_names, temps, master);
|
||||
account->add_flags(ACCOUNT_GENERATED);
|
||||
|
||||
tags_list.push_back
|
||||
(tags_list_pair(q, tag_mapping_pair(account, tag_injected_set())));
|
||||
}
|
||||
}
|
||||
|
||||
void inject_posts::operator()(post_t& post)
|
||||
{
|
||||
foreach (tags_list_pair& pair, tags_list) {
|
||||
optional<value_t> tag_value = post.get_tag(pair.first, false);
|
||||
if (! tag_value &&
|
||||
pair.second.second.find(post.xact) == pair.second.second.end()) {
|
||||
// When checking if the transaction has the tag, only inject once
|
||||
// per transaction.
|
||||
pair.second.second.insert(post.xact);
|
||||
tag_value = post.xact->get_tag(pair.first);
|
||||
}
|
||||
|
||||
if (tag_value) {
|
||||
xact_t& xact = temps.copy_xact(*post.xact);
|
||||
xact._date = post.date();
|
||||
xact.add_flags(ITEM_GENERATED);
|
||||
post_t& temp = temps.copy_post(post, xact);
|
||||
|
||||
temp.account = pair.second.first;
|
||||
temp.amount = tag_value->to_amount();
|
||||
temp.add_flags(ITEM_GENERATED);
|
||||
|
||||
item_handler<post_t>::operator()(temp);
|
||||
}
|
||||
}
|
||||
|
||||
item_handler<post_t>::operator()(post);
|
||||
}
|
||||
|
||||
pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
|
||||
accounts_iterator& iter,
|
||||
const optional<predicate_t>& _pred,
|
||||
|
|
|
|||
|
|
@ -813,19 +813,19 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class dow_posts : public subtotal_posts
|
||||
class day_of_week_posts : public subtotal_posts
|
||||
{
|
||||
posts_list days_of_the_week[7];
|
||||
|
||||
dow_posts();
|
||||
day_of_week_posts();
|
||||
|
||||
public:
|
||||
dow_posts(post_handler_ptr handler, expr_t& amount_expr)
|
||||
day_of_week_posts(post_handler_ptr handler, expr_t& amount_expr)
|
||||
: subtotal_posts(handler, amount_expr) {
|
||||
TRACE_CTOR(dow_posts, "post_handler_ptr, bool");
|
||||
TRACE_CTOR(day_of_week_posts, "post_handler_ptr, bool");
|
||||
}
|
||||
virtual ~dow_posts() throw() {
|
||||
TRACE_DTOR(dow_posts);
|
||||
virtual ~day_of_week_posts() throw() {
|
||||
TRACE_DTOR(day_of_week_posts);
|
||||
}
|
||||
|
||||
virtual void flush();
|
||||
|
|
@ -882,14 +882,16 @@ class budget_posts : public generate_posts
|
|||
#define BUDGET_WRAP_VALUES 0x04
|
||||
|
||||
uint_least8_t flags;
|
||||
date_t terminus;
|
||||
|
||||
budget_posts();
|
||||
|
||||
public:
|
||||
budget_posts(post_handler_ptr handler,
|
||||
uint_least8_t _flags = BUDGET_BUDGETED)
|
||||
: generate_posts(handler), flags(_flags) {
|
||||
TRACE_CTOR(budget_posts, "post_handler_ptr, uint_least8_t");
|
||||
date_t _terminus,
|
||||
uint_least8_t _flags = BUDGET_BUDGETED)
|
||||
: generate_posts(handler), flags(_flags), terminus(_terminus) {
|
||||
TRACE_CTOR(budget_posts, "post_handler_ptr, date_t, uint_least8_t");
|
||||
}
|
||||
virtual ~budget_posts() throw() {
|
||||
TRACE_DTOR(budget_posts);
|
||||
|
|
@ -897,6 +899,7 @@ public:
|
|||
|
||||
void report_budget_items(const date_t& date);
|
||||
|
||||
virtual void flush();
|
||||
virtual void operator()(post_t& post);
|
||||
};
|
||||
|
||||
|
|
@ -929,6 +932,26 @@ class forecast_posts : public generate_posts
|
|||
}
|
||||
};
|
||||
|
||||
class inject_posts : public item_handler<post_t>
|
||||
{
|
||||
typedef std::set<xact_t *> tag_injected_set;
|
||||
typedef std::pair<account_t *, tag_injected_set> tag_mapping_pair;
|
||||
typedef std::pair<string, tag_mapping_pair> tags_list_pair;
|
||||
|
||||
std::list<tags_list_pair> tags_list;
|
||||
temporaries_t temps;
|
||||
|
||||
public:
|
||||
inject_posts(post_handler_ptr handler, const string& tag_list,
|
||||
account_t * master);
|
||||
|
||||
virtual ~inject_posts() throw() {
|
||||
TRACE_DTOR(inject_posts);
|
||||
}
|
||||
|
||||
virtual void operator()(post_t& post);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Account filters
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ string format_t::truncate(const unistring& ustr,
|
|||
else
|
||||
adjust = std::size_t
|
||||
(std::ceil(double(overflow) *
|
||||
((double(*i + counter) * double(iteration)) /
|
||||
((double(*i + counter*3) * double(iteration)) /
|
||||
(double(len_minus_last) - double(counter)))));
|
||||
DEBUG("format.abbrev", "Weight calc: (" << overflow
|
||||
<< " * (((" << *i << " + " << counter << ") * "
|
||||
|
|
|
|||
43
src/item.cc
43
src/item.cc
|
|
@ -37,7 +37,7 @@ namespace ledger {
|
|||
|
||||
bool item_t::use_effective_date = false;
|
||||
|
||||
bool item_t::has_tag(const string& tag) const
|
||||
bool item_t::has_tag(const string& tag, bool) const
|
||||
{
|
||||
DEBUG("item.meta", "Checking if item has tag: " << tag);
|
||||
if (! metadata) {
|
||||
|
|
@ -57,7 +57,7 @@ bool item_t::has_tag(const string& tag) const
|
|||
}
|
||||
|
||||
bool item_t::has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask) const
|
||||
const optional<mask_t>& value_mask, bool) const
|
||||
{
|
||||
if (metadata) {
|
||||
foreach (const string_map::value_type& data, *metadata) {
|
||||
|
|
@ -72,7 +72,7 @@ bool item_t::has_tag(const mask_t& tag_mask,
|
|||
return false;
|
||||
}
|
||||
|
||||
optional<value_t> item_t::get_tag(const string& tag) const
|
||||
optional<value_t> item_t::get_tag(const string& tag, bool) const
|
||||
{
|
||||
DEBUG("item.meta", "Getting item tag: " << tag);
|
||||
if (metadata) {
|
||||
|
|
@ -87,7 +87,8 @@ optional<value_t> item_t::get_tag(const string& tag) const
|
|||
}
|
||||
|
||||
optional<value_t> item_t::get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask) const
|
||||
const optional<mask_t>& value_mask,
|
||||
bool) const
|
||||
{
|
||||
if (metadata) {
|
||||
foreach (const string_map::value_type& data, *metadata) {
|
||||
|
|
@ -138,26 +139,26 @@ void item_t::parse_tags(const char * p,
|
|||
scope_t& scope,
|
||||
bool overwrite_existing)
|
||||
{
|
||||
if (const char * b = std::strchr(p, '[')) {
|
||||
if (*(b + 1) != '\0' &&
|
||||
(std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
|
||||
if (const char * e = std::strchr(p, ']')) {
|
||||
char buf[256];
|
||||
std::strncpy(buf, b + 1, e - b - 1);
|
||||
buf[e - b - 1] = '\0';
|
||||
if (! std::strchr(p, ':')) {
|
||||
if (const char * b = std::strchr(p, '[')) {
|
||||
if (*(b + 1) != '\0' &&
|
||||
(std::isdigit(*(b + 1)) || *(b + 1) == '=')) {
|
||||
if (const char * e = std::strchr(p, ']')) {
|
||||
char buf[256];
|
||||
std::strncpy(buf, b + 1, e - b - 1);
|
||||
buf[e - b - 1] = '\0';
|
||||
|
||||
if (char * p = std::strchr(buf, '=')) {
|
||||
*p++ = '\0';
|
||||
_date_eff = parse_date(p);
|
||||
if (char * p = std::strchr(buf, '=')) {
|
||||
*p++ = '\0';
|
||||
_date_eff = parse_date(p);
|
||||
}
|
||||
if (buf[0])
|
||||
_date = parse_date(buf);
|
||||
}
|
||||
if (buf[0])
|
||||
_date = parse_date(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! std::strchr(p, ':'))
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_array<char> buf(new char[std::strlen(p) + 1]);
|
||||
|
||||
|
|
@ -165,6 +166,7 @@ void item_t::parse_tags(const char * p,
|
|||
|
||||
string tag;
|
||||
bool by_value = false;
|
||||
bool first = true;
|
||||
for (char * q = std::strtok(buf.get(), " \t");
|
||||
q;
|
||||
q = std::strtok(NULL, " \t")) {
|
||||
|
|
@ -190,7 +192,7 @@ void item_t::parse_tags(const char * p,
|
|||
(*i).second.second = true;
|
||||
}
|
||||
}
|
||||
else if (q[len - 1] == ':') { // a metadata setting
|
||||
else if (first && q[len - 1] == ':') { // a metadata setting
|
||||
int index = 1;
|
||||
if (q[len - 2] == ':') {
|
||||
by_value = true;
|
||||
|
|
@ -198,6 +200,7 @@ void item_t::parse_tags(const char * p,
|
|||
}
|
||||
tag = string(q, len - index);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
20
src/item.h
20
src/item.h
|
|
@ -149,13 +149,17 @@ public:
|
|||
return ! (*this == xact);
|
||||
}
|
||||
|
||||
virtual bool has_tag(const string& tag) const;
|
||||
virtual bool has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none) const;
|
||||
virtual bool has_tag(const string& tag,
|
||||
bool inherit = true) const;
|
||||
virtual bool has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none,
|
||||
bool inherit = true) const;
|
||||
|
||||
virtual optional<value_t> get_tag(const string& tag) const;
|
||||
virtual optional<value_t> get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none) const;
|
||||
virtual optional<value_t> get_tag(const string& tag,
|
||||
bool inherit = true) const;
|
||||
virtual optional<value_t> get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none,
|
||||
bool inherit = true) const;
|
||||
|
||||
virtual string_map::iterator
|
||||
set_tag(const string& tag,
|
||||
|
|
@ -171,6 +175,10 @@ public:
|
|||
|
||||
static bool use_effective_date;
|
||||
|
||||
virtual bool has_date() const {
|
||||
return _date;
|
||||
}
|
||||
|
||||
virtual date_t date() const {
|
||||
assert(_date);
|
||||
if (use_effective_date)
|
||||
|
|
|
|||
|
|
@ -228,7 +228,8 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
|
|||
if ((! flat && to_display > 1) ||
|
||||
((flat || to_display != 1 ||
|
||||
account.has_xflags(ACCOUNT_EXT_VISITED)) &&
|
||||
(report.HANDLED(empty) || report.fn_display_total(call_scope)) &&
|
||||
(report.HANDLED(empty) ||
|
||||
report.display_value(report.fn_display_total(call_scope))) &&
|
||||
disp_pred(bound_scope))) {
|
||||
account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
|
||||
DEBUG("account.display", "Marking account as TO_DISPLAY");
|
||||
|
|
@ -313,9 +314,9 @@ void report_payees::flush()
|
|||
|
||||
void report_payees::operator()(post_t& post)
|
||||
{
|
||||
std::map<string, std::size_t>::iterator i = payees.find(post.xact->payee);
|
||||
std::map<string, std::size_t>::iterator i = payees.find(post.payee());
|
||||
if (i == payees.end())
|
||||
payees.insert(payees_pair(post.xact->payee, 1));
|
||||
payees.insert(payees_pair(post.payee(), 1));
|
||||
else
|
||||
(*i).second++;
|
||||
}
|
||||
|
|
|
|||
20
src/pool.cc
20
src/pool.cc
|
|
@ -172,12 +172,21 @@ commodity_pool_t::create(commodity_t& comm,
|
|||
const string& mapping_key)
|
||||
{
|
||||
assert(comm);
|
||||
assert(! comm.has_annotation());
|
||||
assert(details);
|
||||
assert(! mapping_key.empty());
|
||||
|
||||
std::auto_ptr<commodity_t> commodity
|
||||
(new annotated_commodity_t(&comm, details));
|
||||
|
||||
comm.add_flags(COMMODITY_SAW_ANNOTATED);
|
||||
if (details.price) {
|
||||
if (details.has_flags(ANNOTATION_PRICE_FIXATED))
|
||||
comm.add_flags(COMMODITY_SAW_ANN_PRICE_FIXATED);
|
||||
else
|
||||
comm.add_flags(COMMODITY_SAW_ANN_PRICE_FLOAT);
|
||||
}
|
||||
|
||||
commodity->qualified_symbol = comm.symbol();
|
||||
assert(! commodity->qualified_symbol->empty());
|
||||
|
||||
|
|
@ -254,7 +263,13 @@ commodity_pool_t::exchange(const amount_t& amount,
|
|||
|
||||
DEBUG("commodity.prices.add", "exchange: per-unit-cost = " << per_unit_cost);
|
||||
|
||||
if (! per_unit_cost.is_realzero())
|
||||
// Do not record commodity exchanges where amount's commodity has a
|
||||
// fixated price, since this does not establish a market value for the
|
||||
// base commodity.
|
||||
if (! per_unit_cost.is_realzero() &&
|
||||
(current_annotation == NULL ||
|
||||
! (current_annotation->price &&
|
||||
current_annotation->has_flags(ANNOTATION_PRICE_FIXATED))))
|
||||
exchange(commodity, per_unit_cost, moment ? *moment : CURRENT_TIME());
|
||||
|
||||
cost_breakdown_t breakdown;
|
||||
|
|
@ -276,6 +291,9 @@ commodity_pool_t::exchange(const amount_t& amount,
|
|||
moment->date() : optional<date_t>(), tag);
|
||||
|
||||
annotation.add_flags(ANNOTATION_PRICE_CALCULATED);
|
||||
if (current_annotation &&
|
||||
current_annotation->has_flags(ANNOTATION_PRICE_FIXATED))
|
||||
annotation.add_flags(ANNOTATION_PRICE_FIXATED);
|
||||
if (moment)
|
||||
annotation.add_flags(ANNOTATION_DATE_CALCULATED);
|
||||
if (tag)
|
||||
|
|
|
|||
28
src/post.cc
28
src/post.cc
|
|
@ -39,40 +39,42 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
bool post_t::has_tag(const string& tag) const
|
||||
bool post_t::has_tag(const string& tag, bool inherit) const
|
||||
{
|
||||
if (item_t::has_tag(tag))
|
||||
return true;
|
||||
if (xact)
|
||||
if (inherit && xact)
|
||||
return xact->has_tag(tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool post_t::has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask) const
|
||||
const optional<mask_t>& value_mask,
|
||||
bool inherit) const
|
||||
{
|
||||
if (item_t::has_tag(tag_mask, value_mask))
|
||||
return true;
|
||||
if (xact)
|
||||
if (inherit && xact)
|
||||
return xact->has_tag(tag_mask, value_mask);
|
||||
return false;
|
||||
}
|
||||
|
||||
optional<value_t> post_t::get_tag(const string& tag) const
|
||||
optional<value_t> post_t::get_tag(const string& tag, bool inherit) const
|
||||
{
|
||||
if (optional<value_t> value = item_t::get_tag(tag))
|
||||
return value;
|
||||
if (xact)
|
||||
if (inherit && xact)
|
||||
return xact->get_tag(tag);
|
||||
return none;
|
||||
}
|
||||
|
||||
optional<value_t> post_t::get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask) const
|
||||
const optional<mask_t>& value_mask,
|
||||
bool inherit) const
|
||||
{
|
||||
if (optional<value_t> value = item_t::get_tag(tag_mask, value_mask))
|
||||
return value;
|
||||
if (xact)
|
||||
if (inherit && xact)
|
||||
return xact->get_tag(tag_mask, value_mask);
|
||||
return none;
|
||||
}
|
||||
|
|
@ -123,6 +125,14 @@ optional<date_t> post_t::effective_date() const
|
|||
return date;
|
||||
}
|
||||
|
||||
string post_t::payee() const
|
||||
{
|
||||
if (optional<value_t> post_payee = get_tag(_("Payee")))
|
||||
return post_payee->as_string();
|
||||
else
|
||||
return xact->payee;
|
||||
}
|
||||
|
||||
namespace {
|
||||
value_t get_this(post_t& post) {
|
||||
return scope_value(&post);
|
||||
|
|
@ -160,7 +170,7 @@ namespace {
|
|||
}
|
||||
|
||||
value_t get_payee(post_t& post) {
|
||||
return string_value(post.xact->payee);
|
||||
return string_value(post.payee());
|
||||
}
|
||||
|
||||
value_t get_note(post_t& post) {
|
||||
|
|
|
|||
18
src/post.h
18
src/post.h
|
|
@ -99,19 +99,25 @@ public:
|
|||
TRACE_DTOR(post_t);
|
||||
}
|
||||
|
||||
virtual bool has_tag(const string& tag) const;
|
||||
virtual bool has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none) const;
|
||||
virtual bool has_tag(const string& tag,
|
||||
bool inherit = true) const;
|
||||
virtual bool has_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none,
|
||||
bool inherit = true) const;
|
||||
|
||||
virtual optional<value_t> get_tag(const string& tag) const;
|
||||
virtual optional<value_t> get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none) const;
|
||||
virtual optional<value_t> get_tag(const string& tag,
|
||||
bool inherit = true) const;
|
||||
virtual optional<value_t> get_tag(const mask_t& tag_mask,
|
||||
const optional<mask_t>& value_mask = none,
|
||||
bool inherit = true) const;
|
||||
|
||||
virtual date_t value_date() const;
|
||||
virtual date_t date() const;
|
||||
virtual date_t actual_date() const;
|
||||
virtual optional<date_t> effective_date() const;
|
||||
|
||||
string payee() const;
|
||||
|
||||
bool must_balance() const {
|
||||
return ! has_flags(POST_VIRTUAL) || has_flags(POST_MUST_BALANCE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,26 +200,23 @@ value_t query_command(call_scope_t& args)
|
|||
args.value().dump(out);
|
||||
out << std::endl << std::endl;
|
||||
|
||||
query_t query(args.value(), report.what_to_keep());
|
||||
if (query) {
|
||||
query_t query(args.value(), report.what_to_keep(),
|
||||
! report.HANDLED(collapse));
|
||||
if (query.has_query(query_t::QUERY_LIMIT)) {
|
||||
call_scope_t sub_args(static_cast<scope_t&>(args));
|
||||
sub_args.push_back(string_value(query.text()));
|
||||
sub_args.push_back(string_value(query.get_query(query_t::QUERY_LIMIT)));
|
||||
|
||||
parse_command(sub_args);
|
||||
}
|
||||
|
||||
if (query.tokens_remaining()) {
|
||||
if (query.has_query(query_t::QUERY_SHOW)) {
|
||||
out << std::endl << _("====== Display predicate ======")
|
||||
<< std::endl << std::endl;
|
||||
|
||||
query.parse_again();
|
||||
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
|
||||
disp_sub_args.push_back(string_value(query.get_query(query_t::QUERY_SHOW)));
|
||||
|
||||
if (query) {
|
||||
call_scope_t disp_sub_args(static_cast<scope_t&>(args));
|
||||
disp_sub_args.push_back(string_value(query.text()));
|
||||
|
||||
parse_command(disp_sub_args);
|
||||
}
|
||||
parse_command(disp_sub_args);
|
||||
}
|
||||
|
||||
return NULL_VALUE;
|
||||
|
|
|
|||
|
|
@ -37,10 +37,4 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
predicate_t::predicate_t(const query_t& other)
|
||||
: expr_t(other), what_to_keep(other.what_to_keep)
|
||||
{
|
||||
TRACE_CTOR(predicate_t, "query_t");
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -48,8 +48,6 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
class query_t;
|
||||
|
||||
class predicate_t : public expr_t
|
||||
{
|
||||
public:
|
||||
|
|
@ -63,15 +61,21 @@ public:
|
|||
: expr_t(other), what_to_keep(other.what_to_keep) {
|
||||
TRACE_CTOR(predicate_t, "copy");
|
||||
}
|
||||
predicate_t(const query_t& other);
|
||||
|
||||
predicate_t(const string& str, const keep_details_t& _what_to_keep,
|
||||
const parse_flags_t& flags = PARSE_DEFAULT)
|
||||
predicate_t(ptr_op_t _ptr,
|
||||
const keep_details_t& _what_to_keep,
|
||||
scope_t * _context = NULL)
|
||||
: expr_t(_ptr, _context), what_to_keep(_what_to_keep) {
|
||||
TRACE_CTOR(predicate_t, "ptr_op_t, keep_details_t, scope_t *");
|
||||
}
|
||||
predicate_t(const string& str,
|
||||
const keep_details_t& _what_to_keep,
|
||||
const parse_flags_t& flags = PARSE_DEFAULT)
|
||||
: expr_t(str, flags), what_to_keep(_what_to_keep) {
|
||||
TRACE_CTOR(predicate_t, "string, keep_details_t, parse_flags_t");
|
||||
}
|
||||
predicate_t(std::istream& in, const keep_details_t& _what_to_keep,
|
||||
const parse_flags_t& flags = PARSE_DEFAULT)
|
||||
predicate_t(std::istream& in,
|
||||
const keep_details_t& _what_to_keep,
|
||||
const parse_flags_t& flags = PARSE_DEFAULT)
|
||||
: expr_t(in, flags), what_to_keep(_what_to_keep) {
|
||||
TRACE_CTOR(predicate_t, "std::istream&, keep_details_t, parse_flags_t");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ namespace {
|
|||
}
|
||||
|
||||
if (post->assigned_amount)
|
||||
amtbuf << " = " << post->assigned_amount;
|
||||
amtbuf << " = " << *post->assigned_amount;
|
||||
|
||||
string trailer = amtbuf.str();
|
||||
out << trailer;
|
||||
|
|
|
|||
207
src/query.cc
207
src/query.cc
|
|
@ -53,7 +53,12 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
|
|||
}
|
||||
}
|
||||
|
||||
resume:
|
||||
switch (*arg_i) {
|
||||
case '\0':
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '"':
|
||||
case '/': {
|
||||
|
|
@ -84,13 +89,17 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
|
|||
if (multiple_args && consume_next_arg) {
|
||||
consume_next_arg = false;
|
||||
token_t tok(token_t::TERM, string(arg_i, arg_end));
|
||||
prev_arg_i = arg_i;
|
||||
arg_i = arg_end;
|
||||
return tok;
|
||||
}
|
||||
|
||||
resume:
|
||||
bool consume_next = false;
|
||||
switch (*arg_i) {
|
||||
case '\0':
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
|
|
@ -121,15 +130,20 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
|
|||
string::const_iterator beg = arg_i;
|
||||
for (; arg_i != arg_end; ++arg_i) {
|
||||
switch (*arg_i) {
|
||||
case '\0':
|
||||
assert(false);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\r':
|
||||
if (! consume_whitespace)
|
||||
if (! multiple_args && ! consume_whitespace)
|
||||
goto test_ident;
|
||||
else
|
||||
ident.push_back(*arg_i);
|
||||
break;
|
||||
|
||||
case '(':
|
||||
case ')':
|
||||
case '&':
|
||||
|
|
@ -170,20 +184,16 @@ test_ident:
|
|||
return token_t(token_t::TOK_META);
|
||||
else if (ident == "data")
|
||||
return token_t(token_t::TOK_META);
|
||||
else if (ident == "show") {
|
||||
// The "show" keyword is special, and separates a limiting predicate
|
||||
// from a display predicate.
|
||||
DEBUG("pred.show", "string = " << (*begin).as_string());
|
||||
return token_t(token_t::END_REACHED);
|
||||
}
|
||||
#if 0
|
||||
// jww (2009-11-06): This is disabled for the time being.
|
||||
else if (ident == "date") {
|
||||
// The date keyword takes the whole of the next string as its argument.
|
||||
consume_whitespace = true;
|
||||
return token_t(token_t::TOK_DATE);
|
||||
}
|
||||
#endif
|
||||
else if (ident == "show")
|
||||
return token_t(token_t::TOK_SHOW);
|
||||
else if (ident == "bold")
|
||||
return token_t(token_t::TOK_BOLD);
|
||||
else if (ident == "for")
|
||||
return token_t(token_t::TOK_FOR);
|
||||
else if (ident == "since")
|
||||
return token_t(token_t::TOK_SINCE);
|
||||
else if (ident == "until")
|
||||
return token_t(token_t::TOK_UNTIL);
|
||||
else if (ident == "expr") {
|
||||
// The expr keyword takes the whole of the next string as its argument.
|
||||
consume_next_arg = true;
|
||||
|
|
@ -238,10 +248,15 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
|
|||
|
||||
lexer_t::token_t tok = lexer.next_token();
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_SHOW:
|
||||
case lexer_t::token_t::TOK_BOLD:
|
||||
case lexer_t::token_t::TOK_FOR:
|
||||
case lexer_t::token_t::TOK_SINCE:
|
||||
case lexer_t::token_t::TOK_UNTIL:
|
||||
case lexer_t::token_t::END_REACHED:
|
||||
lexer.push_token(tok);
|
||||
break;
|
||||
|
||||
case lexer_t::token_t::TOK_DATE:
|
||||
case lexer_t::token_t::TOK_CODE:
|
||||
case lexer_t::token_t::TOK_PAYEE:
|
||||
case lexer_t::token_t::TOK_NOTE:
|
||||
|
|
@ -257,41 +272,6 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
|
|||
case lexer_t::token_t::TERM:
|
||||
assert(tok.value);
|
||||
switch (tok_context) {
|
||||
case lexer_t::token_t::TOK_DATE: {
|
||||
expr_t::ptr_op_t ident = new expr_t::op_t(expr_t::op_t::IDENT);
|
||||
ident->set_ident("date");
|
||||
|
||||
date_interval_t interval(*tok.value);
|
||||
|
||||
if (interval.start) {
|
||||
node = new expr_t::op_t(expr_t::op_t::O_GTE);
|
||||
node->set_left(ident);
|
||||
|
||||
expr_t::ptr_op_t arg1 = new expr_t::op_t(expr_t::op_t::VALUE);
|
||||
arg1->set_value(*interval.start);
|
||||
node->set_right(arg1);
|
||||
}
|
||||
|
||||
if (interval.finish) {
|
||||
expr_t::ptr_op_t lt = new expr_t::op_t(expr_t::op_t::O_LT);
|
||||
lt->set_left(ident);
|
||||
|
||||
expr_t::ptr_op_t arg1 = new expr_t::op_t(expr_t::op_t::VALUE);
|
||||
arg1->set_value(*interval.finish);
|
||||
lt->set_right(arg1);
|
||||
|
||||
if (node) {
|
||||
expr_t::ptr_op_t prev(node);
|
||||
node = new expr_t::op_t(expr_t::op_t::O_AND);
|
||||
node->set_left(prev);
|
||||
node->set_right(lt);
|
||||
} else {
|
||||
node = lt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_EXPR:
|
||||
node = expr_t(*tok.value).get_op();
|
||||
break;
|
||||
|
|
@ -357,7 +337,7 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
|
|||
break;
|
||||
|
||||
case lexer_t::token_t::LPAREN:
|
||||
node = parse_query_expr(tok_context);
|
||||
node = parse_query_expr(tok_context, true);
|
||||
tok = lexer.next_token();
|
||||
if (tok.kind != lexer_t::token_t::RPAREN)
|
||||
tok.expected(')');
|
||||
|
|
@ -447,18 +427,121 @@ query_t::parser_t::parse_or_expr(lexer_t::token_t::kind_t tok_context)
|
|||
}
|
||||
|
||||
expr_t::ptr_op_t
|
||||
query_t::parser_t::parse_query_expr(lexer_t::token_t::kind_t tok_context)
|
||||
query_t::parser_t::parse_query_expr(lexer_t::token_t::kind_t tok_context,
|
||||
bool subexpression)
|
||||
{
|
||||
if (expr_t::ptr_op_t node = parse_or_expr(tok_context)) {
|
||||
if (expr_t::ptr_op_t next = parse_query_expr(tok_context)) {
|
||||
expr_t::ptr_op_t prev(node);
|
||||
node = new expr_t::op_t(expr_t::op_t::O_OR);
|
||||
node->set_left(prev);
|
||||
node->set_right(next);
|
||||
expr_t::ptr_op_t limiter;
|
||||
|
||||
while (expr_t::ptr_op_t next = parse_or_expr(tok_context)) {
|
||||
if (! limiter) {
|
||||
limiter = next;
|
||||
} else {
|
||||
expr_t::ptr_op_t prev(limiter);
|
||||
limiter = new expr_t::op_t(expr_t::op_t::O_OR);
|
||||
limiter->set_left(prev);
|
||||
limiter->set_right(next);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
return expr_t::ptr_op_t();
|
||||
|
||||
if (! subexpression) {
|
||||
if (limiter)
|
||||
query_map.insert
|
||||
(query_map_t::value_type
|
||||
(QUERY_LIMIT, predicate_t(limiter, what_to_keep).print_to_str()));
|
||||
|
||||
lexer_t::token_t tok = lexer.peek_token();
|
||||
while (tok.kind != lexer_t::token_t::END_REACHED) {
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_SHOW: {
|
||||
lexer.next_token();
|
||||
|
||||
expr_t::ptr_op_t node;
|
||||
while (expr_t::ptr_op_t next = parse_or_expr(tok_context)) {
|
||||
if (! node) {
|
||||
node = next;
|
||||
} else {
|
||||
expr_t::ptr_op_t prev(node);
|
||||
node = new expr_t::op_t(expr_t::op_t::O_OR);
|
||||
node->set_left(prev);
|
||||
node->set_right(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (node)
|
||||
query_map.insert
|
||||
(query_map_t::value_type
|
||||
(QUERY_SHOW, predicate_t(node, what_to_keep).print_to_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_BOLD: {
|
||||
lexer.next_token();
|
||||
|
||||
expr_t::ptr_op_t node = parse_or_expr(tok_context);
|
||||
while (expr_t::ptr_op_t next = parse_or_expr(tok_context)) {
|
||||
expr_t::ptr_op_t prev(node);
|
||||
node = new expr_t::op_t(expr_t::op_t::O_OR);
|
||||
node->set_left(prev);
|
||||
node->set_right(next);
|
||||
}
|
||||
|
||||
if (node)
|
||||
query_map.insert
|
||||
(query_map_t::value_type
|
||||
(QUERY_BOLD, predicate_t(node, what_to_keep).print_to_str()));
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_FOR:
|
||||
case lexer_t::token_t::TOK_SINCE:
|
||||
case lexer_t::token_t::TOK_UNTIL: {
|
||||
tok = lexer.next_token();
|
||||
|
||||
string for_string;
|
||||
|
||||
if (tok.kind == lexer_t::token_t::TOK_SINCE)
|
||||
for_string = "since";
|
||||
else if (tok.kind == lexer_t::token_t::TOK_UNTIL)
|
||||
for_string = "until";
|
||||
|
||||
lexer.consume_next_arg = true;
|
||||
tok = lexer.peek_token();
|
||||
|
||||
while (tok.kind != lexer_t::token_t::END_REACHED) {
|
||||
tok = lexer.next_token();
|
||||
assert(tok.kind == lexer_t::token_t::TERM);
|
||||
|
||||
if (*tok.value == "show" || *tok.value == "bold" ||
|
||||
*tok.value == "for" || *tok.value == "since" ||
|
||||
*tok.value == "until") {
|
||||
lexer.token_cache = lexer_t::token_t();
|
||||
lexer.arg_i = lexer.prev_arg_i;
|
||||
lexer.consume_next_arg = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! for_string.empty())
|
||||
for_string += " ";
|
||||
for_string += *tok.value;
|
||||
|
||||
lexer.consume_next_arg = true;
|
||||
tok = lexer.peek_token();
|
||||
}
|
||||
|
||||
if (! for_string.empty())
|
||||
query_map.insert(query_map_t::value_type(QUERY_FOR, for_string));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
tok = lexer.peek_token();
|
||||
}
|
||||
}
|
||||
|
||||
return limiter;
|
||||
}
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
108
src/query.h
108
src/query.h
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
namespace ledger {
|
||||
|
||||
class query_t : public predicate_t
|
||||
class query_t
|
||||
{
|
||||
protected:
|
||||
class parser_t;
|
||||
|
|
@ -60,6 +60,7 @@ public:
|
|||
value_t::sequence_t::const_iterator begin;
|
||||
value_t::sequence_t::const_iterator end;
|
||||
|
||||
string::const_iterator prev_arg_i;
|
||||
string::const_iterator arg_i;
|
||||
string::const_iterator arg_end;
|
||||
|
||||
|
|
@ -81,7 +82,6 @@ public:
|
|||
TOK_OR,
|
||||
TOK_EQ,
|
||||
|
||||
TOK_DATE,
|
||||
TOK_CODE,
|
||||
TOK_PAYEE,
|
||||
TOK_NOTE,
|
||||
|
|
@ -89,6 +89,12 @@ public:
|
|||
TOK_META,
|
||||
TOK_EXPR,
|
||||
|
||||
TOK_SHOW,
|
||||
TOK_BOLD,
|
||||
TOK_FOR,
|
||||
TOK_SINCE,
|
||||
TOK_UNTIL,
|
||||
|
||||
TERM,
|
||||
|
||||
END_REACHED
|
||||
|
|
@ -131,13 +137,17 @@ public:
|
|||
case TOK_AND: return "TOK_AND";
|
||||
case TOK_OR: return "TOK_OR";
|
||||
case TOK_EQ: return "TOK_EQ";
|
||||
case TOK_DATE: return "TOK_DATE";
|
||||
case TOK_CODE: return "TOK_CODE";
|
||||
case TOK_PAYEE: return "TOK_PAYEE";
|
||||
case TOK_NOTE: return "TOK_NOTE";
|
||||
case TOK_ACCOUNT: return "TOK_ACCOUNT";
|
||||
case TOK_META: return "TOK_META";
|
||||
case TOK_EXPR: return "TOK_EXPR";
|
||||
case TOK_SHOW: return "TOK_SHOW";
|
||||
case TOK_BOLD: return "TOK_BOLD";
|
||||
case TOK_FOR: return "TOK_FOR";
|
||||
case TOK_SINCE: return "TOK_SINCE";
|
||||
case TOK_UNTIL: return "TOK_UNTIL";
|
||||
case TERM: return string("TERM(") + *value + ")";
|
||||
case END_REACHED: return "END_REACHED";
|
||||
}
|
||||
|
|
@ -153,13 +163,17 @@ public:
|
|||
case TOK_AND: return "and";
|
||||
case TOK_OR: return "or";
|
||||
case TOK_EQ: return "=";
|
||||
case TOK_DATE: return "date";
|
||||
case TOK_CODE: return "code";
|
||||
case TOK_PAYEE: return "payee";
|
||||
case TOK_NOTE: return "note";
|
||||
case TOK_ACCOUNT: return "account";
|
||||
case TOK_META: return "meta";
|
||||
case TOK_EXPR: return "expr";
|
||||
case TOK_SHOW: return "show";
|
||||
case TOK_BOLD: return "bold";
|
||||
case TOK_FOR: return "for";
|
||||
case TOK_SINCE: return "since";
|
||||
case TOK_UNTIL: return "until";
|
||||
|
||||
case END_REACHED: return "<EOF>";
|
||||
|
||||
|
|
@ -197,8 +211,7 @@ public:
|
|||
arg_i(lexer.arg_i), arg_end(lexer.arg_end),
|
||||
consume_whitespace(lexer.consume_whitespace),
|
||||
consume_next_arg(lexer.consume_next_arg),
|
||||
multiple_args(lexer.multiple_args),
|
||||
token_cache(lexer.token_cache)
|
||||
multiple_args(lexer.multiple_args), token_cache(lexer.token_cache)
|
||||
{
|
||||
TRACE_CTOR(query_t::lexer_t, "copy");
|
||||
}
|
||||
|
|
@ -218,24 +231,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
enum kind_t {
|
||||
QUERY_LIMIT,
|
||||
QUERY_SHOW,
|
||||
QUERY_BOLD,
|
||||
QUERY_FOR
|
||||
};
|
||||
|
||||
typedef std::map<kind_t, string> query_map_t;
|
||||
|
||||
protected:
|
||||
class parser_t
|
||||
{
|
||||
friend class query_t;
|
||||
|
||||
value_t args;
|
||||
lexer_t lexer;
|
||||
value_t args;
|
||||
lexer_t lexer;
|
||||
keep_details_t what_to_keep;
|
||||
query_map_t query_map;
|
||||
|
||||
expr_t::ptr_op_t parse_query_term(lexer_t::token_t::kind_t tok_context);
|
||||
expr_t::ptr_op_t parse_unary_expr(lexer_t::token_t::kind_t tok_context);
|
||||
expr_t::ptr_op_t parse_and_expr(lexer_t::token_t::kind_t tok_context);
|
||||
expr_t::ptr_op_t parse_or_expr(lexer_t::token_t::kind_t tok_context);
|
||||
expr_t::ptr_op_t parse_query_expr(lexer_t::token_t::kind_t tok_context);
|
||||
expr_t::ptr_op_t parse_query_expr(lexer_t::token_t::kind_t tok_context,
|
||||
bool subexpression = false);
|
||||
|
||||
public:
|
||||
parser_t(const value_t& _args, bool multiple_args = true)
|
||||
: args(_args), lexer(args.begin(), args.end(), multiple_args) {
|
||||
TRACE_CTOR(query_t::parser_t, "");
|
||||
parser_t(const value_t& _args,
|
||||
const keep_details_t& _what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true)
|
||||
: args(_args), lexer(args.begin(), args.end(), multiple_args),
|
||||
what_to_keep(_what_to_keep) {
|
||||
TRACE_CTOR(query_t::parser_t, "value_t, keep_details_t, bool");
|
||||
}
|
||||
parser_t(const parser_t& parser)
|
||||
: args(parser.args), lexer(parser.lexer) {
|
||||
|
|
@ -245,8 +273,8 @@ protected:
|
|||
TRACE_DTOR(query_t::parser_t);
|
||||
}
|
||||
|
||||
expr_t::ptr_op_t parse() {
|
||||
return parse_query_expr(lexer_t::token_t::TOK_ACCOUNT);
|
||||
expr_t::ptr_op_t parse(bool subexpression = false) {
|
||||
return parse_query_expr(lexer_t::token_t::TOK_ACCOUNT, subexpression);
|
||||
}
|
||||
|
||||
bool tokens_remaining() {
|
||||
|
|
@ -257,55 +285,61 @@ protected:
|
|||
};
|
||||
|
||||
optional<parser_t> parser;
|
||||
query_map_t predicates;
|
||||
|
||||
public:
|
||||
query_t() {
|
||||
TRACE_CTOR(query_t, "");
|
||||
}
|
||||
query_t(const query_t& other)
|
||||
: predicate_t(other) {
|
||||
: parser(other.parser), predicates(other.predicates) {
|
||||
TRACE_CTOR(query_t, "copy");
|
||||
}
|
||||
query_t(const string& arg,
|
||||
const keep_details_t& _what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true)
|
||||
: predicate_t(_what_to_keep) {
|
||||
TRACE_CTOR(query_t, "string, keep_details_t");
|
||||
query_t(const string& arg,
|
||||
const keep_details_t& what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true) {
|
||||
TRACE_CTOR(query_t, "string, keep_details_t, bool");
|
||||
if (! arg.empty()) {
|
||||
value_t temp(string_value(arg));
|
||||
parse_args(temp.to_sequence(), multiple_args);
|
||||
parse_args(temp.to_sequence(), what_to_keep, multiple_args);
|
||||
}
|
||||
}
|
||||
query_t(const value_t& args,
|
||||
const keep_details_t& _what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true)
|
||||
: predicate_t(_what_to_keep) {
|
||||
TRACE_CTOR(query_t, "value_t, keep_details_t");
|
||||
query_t(const value_t& args,
|
||||
const keep_details_t& what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true) {
|
||||
TRACE_CTOR(query_t, "value_t, keep_details_t, bool");
|
||||
if (! args.empty())
|
||||
parse_args(args, multiple_args);
|
||||
parse_args(args, what_to_keep, multiple_args);
|
||||
}
|
||||
virtual ~query_t() {
|
||||
TRACE_DTOR(query_t);
|
||||
}
|
||||
|
||||
void parse_args(const value_t& args, bool multiple_args = true) {
|
||||
expr_t::ptr_op_t
|
||||
parse_args(const value_t& args,
|
||||
const keep_details_t& what_to_keep = keep_details_t(),
|
||||
bool multiple_args = true,
|
||||
bool subexpression = false) {
|
||||
if (! parser)
|
||||
parser = parser_t(args, multiple_args);
|
||||
ptr = parser->parse(); // expr_t::ptr
|
||||
parser = parser_t(args, what_to_keep, multiple_args);
|
||||
return parser->parse(subexpression);
|
||||
}
|
||||
|
||||
void parse_again() {
|
||||
assert(parser);
|
||||
ptr = parser->parse(); // expr_t::ptr
|
||||
bool has_query(const kind_t& id) const {
|
||||
return parser && parser->query_map.find(id) != parser->query_map.end();
|
||||
}
|
||||
string get_query(const kind_t& id) const {
|
||||
if (parser) {
|
||||
query_map_t::const_iterator i = parser->query_map.find(id);
|
||||
if (i != parser->query_map.end())
|
||||
return (*i).second;
|
||||
}
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
bool tokens_remaining() {
|
||||
return parser && parser->tokens_remaining();
|
||||
}
|
||||
|
||||
virtual string text() {
|
||||
return print_to_str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ledger
|
||||
|
|
|
|||
|
|
@ -145,26 +145,8 @@ void report_t::normalize_options(const string& verb)
|
|||
// using -b or -e). Then, if no _duration_ was specified (such as monthly),
|
||||
// then ignore the period since the begin/end are the only interesting
|
||||
// details.
|
||||
if (HANDLED(period_)) {
|
||||
date_interval_t interval(HANDLER(period_).str());
|
||||
|
||||
optional<date_t> begin = interval.begin();
|
||||
optional<date_t> end = interval.end();
|
||||
|
||||
if (! HANDLED(begin_) && begin) {
|
||||
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
if (! HANDLED(end_) && end) {
|
||||
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
|
||||
if (! interval.duration)
|
||||
HANDLER(period_).off();
|
||||
else if (! HANDLED(sort_all_))
|
||||
HANDLER(sort_xacts_).on_only(string("?normalize"));
|
||||
}
|
||||
if (HANDLED(period_))
|
||||
normalize_period();
|
||||
|
||||
// If -j or -J were specified, set the appropriate format string now so as
|
||||
// to avoid option ordering issues were we to have done it during the
|
||||
|
|
@ -254,24 +236,52 @@ void report_t::normalize_options(const string& verb)
|
|||
}
|
||||
}
|
||||
|
||||
void report_t::normalize_period()
|
||||
{
|
||||
date_interval_t interval(HANDLER(period_).str());
|
||||
|
||||
optional<date_t> begin = interval.begin();
|
||||
optional<date_t> end = interval.end();
|
||||
|
||||
if (! HANDLED(begin_) && begin) {
|
||||
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
if (! HANDLED(end_) && end) {
|
||||
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
|
||||
HANDLER(limit_).on(string("?normalize"), predicate);
|
||||
}
|
||||
|
||||
if (! interval.duration)
|
||||
HANDLER(period_).off();
|
||||
else if (! HANDLED(sort_all_))
|
||||
HANDLER(sort_xacts_).on_only(string("?normalize"));
|
||||
}
|
||||
|
||||
void report_t::parse_query_args(const value_t& args, const string& whence)
|
||||
{
|
||||
query_t query(args, what_to_keep());
|
||||
if (query) {
|
||||
HANDLER(limit_).on(whence, query.text());
|
||||
|
||||
DEBUG("report.predicate",
|
||||
"Predicate = " << HANDLER(limit_).str());
|
||||
if (query.has_query(query_t::QUERY_LIMIT)) {
|
||||
HANDLER(limit_).on(whence, query.get_query(query_t::QUERY_LIMIT));
|
||||
DEBUG("report.predicate", "Limit predicate = " << HANDLER(limit_).str());
|
||||
}
|
||||
|
||||
if (query.tokens_remaining()) {
|
||||
query.parse_again();
|
||||
if (query) {
|
||||
HANDLER(display_).on(whence, query.text());
|
||||
if (query.has_query(query_t::QUERY_SHOW)) {
|
||||
HANDLER(display_).on(whence, query.get_query(query_t::QUERY_SHOW));
|
||||
DEBUG("report.predicate", "Display predicate = " << HANDLER(display_).str());
|
||||
}
|
||||
|
||||
DEBUG("report.predicate",
|
||||
"Display predicate = " << HANDLER(display_).str());
|
||||
}
|
||||
if (query.has_query(query_t::QUERY_BOLD)) {
|
||||
HANDLER(bold_if_).set_expr(whence, query.get_query(query_t::QUERY_BOLD));
|
||||
DEBUG("report.predicate", "Bolding predicate = " << HANDLER(bold_if_).str());
|
||||
}
|
||||
|
||||
if (query.has_query(query_t::QUERY_FOR)) {
|
||||
HANDLER(period_).on(whence, query.get_query(query_t::QUERY_FOR));
|
||||
DEBUG("report.predicate", "Report period = " << HANDLER(period_).str());
|
||||
|
||||
normalize_period(); // it needs normalization
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,6 +438,15 @@ void report_t::commodities_report(post_handler_ptr handler)
|
|||
session.journal->clear_xdata();
|
||||
}
|
||||
|
||||
value_t report_t::display_value(const value_t& val)
|
||||
{
|
||||
value_t temp(val.strip_annotations(what_to_keep()));
|
||||
if (HANDLED(base))
|
||||
return temp;
|
||||
else
|
||||
return temp.unreduced();
|
||||
}
|
||||
|
||||
value_t report_t::fn_amount_expr(call_scope_t& scope)
|
||||
{
|
||||
return HANDLER(amount_).expr.calc(scope);
|
||||
|
|
@ -448,6 +467,14 @@ value_t report_t::fn_display_total(call_scope_t& scope)
|
|||
return HANDLER(display_total_).expr.calc(scope);
|
||||
}
|
||||
|
||||
value_t report_t::fn_should_bold(call_scope_t& scope)
|
||||
{
|
||||
if (HANDLED(bold_if_))
|
||||
return HANDLER(bold_if_).expr.calc(scope);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
value_t report_t::fn_market(call_scope_t& args)
|
||||
{
|
||||
optional<datetime_t> moment = (args.has<datetime_t>(1) ?
|
||||
|
|
@ -533,11 +560,7 @@ value_t report_t::fn_print(call_scope_t& args)
|
|||
|
||||
value_t report_t::fn_scrub(call_scope_t& args)
|
||||
{
|
||||
value_t temp(args.value().strip_annotations(what_to_keep()));
|
||||
if (HANDLED(base))
|
||||
return temp;
|
||||
else
|
||||
return temp.unreduced();
|
||||
return display_value(args.value());
|
||||
}
|
||||
|
||||
value_t report_t::fn_rounded(call_scope_t& args)
|
||||
|
|
@ -900,6 +923,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
|||
else OPT(base);
|
||||
else OPT_ALT(basis, cost);
|
||||
else OPT_(begin_);
|
||||
else OPT(bold_if_);
|
||||
else OPT(budget);
|
||||
else OPT(by_payee);
|
||||
break;
|
||||
|
|
@ -955,6 +979,7 @@ option_t<report_t> * report_t::lookup_option(const char * p)
|
|||
break;
|
||||
case 'i':
|
||||
OPT(invert);
|
||||
else OPT(inject_);
|
||||
break;
|
||||
case 'j':
|
||||
OPT_CH(amount_data);
|
||||
|
|
@ -1220,6 +1245,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
|
|||
return MAKE_FUNCTOR(report_t::fn_scrub);
|
||||
else if (is_eq(p, "strip"))
|
||||
return MAKE_FUNCTOR(report_t::fn_strip);
|
||||
else if (is_eq(p, "should_bold"))
|
||||
return MAKE_FUNCTOR(report_t::fn_should_bold);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
|
|
|
|||
71
src/report.h
71
src/report.h
|
|
@ -126,6 +126,7 @@ public:
|
|||
}
|
||||
|
||||
void normalize_options(const string& verb);
|
||||
void normalize_period();
|
||||
void parse_query_args(const value_t& args, const string& whence);
|
||||
|
||||
void posts_report(post_handler_ptr handler);
|
||||
|
|
@ -134,10 +135,13 @@ public:
|
|||
void accounts_report(acct_handler_ptr handler);
|
||||
void commodities_report(post_handler_ptr handler);
|
||||
|
||||
value_t display_value(const value_t& val);
|
||||
|
||||
value_t fn_amount_expr(call_scope_t& scope);
|
||||
value_t fn_total_expr(call_scope_t& scope);
|
||||
value_t fn_display_amount(call_scope_t& scope);
|
||||
value_t fn_display_total(call_scope_t& scope);
|
||||
value_t fn_should_bold(call_scope_t& scope);
|
||||
value_t fn_market(call_scope_t& scope);
|
||||
value_t fn_get_at(call_scope_t& scope);
|
||||
value_t fn_is_seq(call_scope_t& scope);
|
||||
|
|
@ -260,6 +264,7 @@ public:
|
|||
HANDLER(group_by_).report(out);
|
||||
HANDLER(group_title_format_).report(out);
|
||||
HANDLER(head_).report(out);
|
||||
HANDLER(inject_).report(out);
|
||||
HANDLER(invert).report(out);
|
||||
HANDLER(limit_).report(out);
|
||||
HANDLER(lot_dates).report(out);
|
||||
|
|
@ -376,9 +381,13 @@ public:
|
|||
|
||||
OPTION__(report_t, balance_format_, CTOR(report_t, balance_format_) {
|
||||
on(none,
|
||||
"%(justify(scrub(display_total), 20, 20 + prepend_width, true, color))"
|
||||
"%(ansify_if("
|
||||
" justify(scrub(display_total), 20, 20 + prepend_width, true, color),"
|
||||
" bold if should_bold))"
|
||||
" %(!options.flat ? depth_spacer : \"\")"
|
||||
"%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
|
||||
"%-(ansify_if("
|
||||
" ansify_if(partial_account(options.flat), blue if color),"
|
||||
" bold if should_bold))\n%/"
|
||||
"%$1\n%/"
|
||||
"--------------------\n");
|
||||
});
|
||||
|
|
@ -402,6 +411,18 @@ public:
|
|||
parent->HANDLER(limit_).on(string("--begin"), predicate);
|
||||
});
|
||||
|
||||
OPTION__
|
||||
(report_t, bold_if_,
|
||||
expr_t expr;
|
||||
CTOR(report_t, bold_if_) {}
|
||||
void set_expr(const optional<string>& whence, const string& str) {
|
||||
expr = str;
|
||||
on(whence, str);
|
||||
}
|
||||
DO_(args) {
|
||||
set_expr(args.get<string>(0), args.get<string>(1));
|
||||
});
|
||||
|
||||
OPTION_(report_t, budget, DO() {
|
||||
parent->budget_flags |= BUDGET_BUDGETED;
|
||||
});
|
||||
|
|
@ -616,6 +637,7 @@ public:
|
|||
});
|
||||
|
||||
OPTION(report_t, head_);
|
||||
OPTION(report_t, inject_);
|
||||
|
||||
OPTION_(report_t, invert, DO() {
|
||||
parent->HANDLER(amount_).set_expr(string("--invert"), "-amount");
|
||||
|
|
@ -804,20 +826,37 @@ public:
|
|||
|
||||
OPTION__(report_t, register_format_, CTOR(report_t, register_format_) {
|
||||
on(none,
|
||||
"%(ansify_if(justify(format_date(date), date_width), green "
|
||||
" if color & date > today))"
|
||||
" %(ansify_if(justify(truncated(payee, payee_width), payee_width), "
|
||||
" bold if color & !cleared & actual))"
|
||||
" %(ansify_if(justify(truncated(display_account, account_width, "
|
||||
" abbrev_len), account_width), blue if color))"
|
||||
" %(justify(scrub(display_amount), amount_width, "
|
||||
" 3 + meta_width + date_width + payee_width + account_width"
|
||||
" + amount_width + prepend_width, true, color))"
|
||||
" %(justify(scrub(display_total), total_width, "
|
||||
" 4 + meta_width + date_width + payee_width + account_width"
|
||||
" + amount_width + total_width + prepend_width, true, color))\n%/"
|
||||
"%(justify(\" \", 2 + date_width + payee_width))"
|
||||
"%$3 %$4 %$5\n");
|
||||
"%(ansify_if("
|
||||
" ansify_if(justify(format_date(date), date_width),"
|
||||
" green if color and date > today),"
|
||||
" bold if should_bold))"
|
||||
" %(ansify_if("
|
||||
" ansify_if(justify(truncated(payee, payee_width), payee_width), "
|
||||
" bold if color and !cleared and actual),"
|
||||
" bold if should_bold))"
|
||||
" %(ansify_if("
|
||||
" ansify_if(justify(truncated(display_account, account_width, "
|
||||
" abbrev_len), account_width),"
|
||||
" blue if color),"
|
||||
" bold if should_bold))"
|
||||
" %(ansify_if("
|
||||
" justify(scrub(display_amount), amount_width, "
|
||||
" 3 + meta_width + date_width + payee_width"
|
||||
" + account_width + amount_width + prepend_width,"
|
||||
" true, color),"
|
||||
" bold if should_bold))"
|
||||
" %(ansify_if("
|
||||
" justify(scrub(display_total), total_width, "
|
||||
" 4 + meta_width + date_width + payee_width"
|
||||
" + account_width + amount_width + total_width"
|
||||
" + prepend_width, true, color),"
|
||||
" bold if should_bold))\n%/"
|
||||
"%(justify(\" \", date_width))"
|
||||
" %(ansify_if("
|
||||
" justify(truncated(has_tag(\"Payee\") ? payee : \" \", "
|
||||
" payee_width), payee_width),"
|
||||
" bold if should_bold))"
|
||||
" %$3 %$4 %$5\n");
|
||||
});
|
||||
|
||||
OPTION(report_t, related); // -r
|
||||
|
|
|
|||
|
|
@ -602,7 +602,7 @@ inline scope_t * call_scope_t::get<scope_t *>(std::size_t index, bool) {
|
|||
template <>
|
||||
inline expr_t::ptr_op_t
|
||||
call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) {
|
||||
return resolve(index, value_t::ANY).as_any<expr_t::ptr_op_t>();
|
||||
return args[index].as_any<expr_t::ptr_op_t>();
|
||||
}
|
||||
|
||||
class value_scope_t : public scope_t
|
||||
|
|
|
|||
|
|
@ -161,14 +161,16 @@ void session_t::read_journal_files()
|
|||
if (HANDLED(master_account_))
|
||||
master_account = HANDLER(master_account_).str();
|
||||
|
||||
std::size_t count = read_data(master_account);
|
||||
if (count == 0)
|
||||
throw_(parse_error,
|
||||
_("Failed to locate any transactions; did you specify a valid file with -f?"));
|
||||
#if defined(DEBUG_ON)
|
||||
std::size_t count =
|
||||
#endif
|
||||
read_data(master_account);
|
||||
|
||||
INFO_FINISH(journal);
|
||||
|
||||
#if defined(DEBUG_ON)
|
||||
INFO("Found " << count << " transactions");
|
||||
#endif
|
||||
}
|
||||
|
||||
void session_t::close_journal_files()
|
||||
|
|
|
|||
|
|
@ -534,9 +534,13 @@ void instance_t::automated_xact_directive(char * line)
|
|||
bool reveal_context = true;
|
||||
|
||||
try {
|
||||
std::auto_ptr<auto_xact_t> ae
|
||||
(new auto_xact_t(query_t(string(skip_ws(line + 1)),
|
||||
keep_details_t(true, true, true), false)));
|
||||
query_t query;
|
||||
keep_details_t keeper(true, true, true);
|
||||
expr_t::ptr_op_t expr =
|
||||
query.parse_args(string_value(skip_ws(line + 1)).to_sequence(),
|
||||
keeper, false, true);
|
||||
|
||||
std::auto_ptr<auto_xact_t> ae(new auto_xact_t(predicate_t(expr, keeper)));
|
||||
ae->pos = position_t();
|
||||
ae->pos->pathname = pathname;
|
||||
ae->pos->beg_pos = line_beg_pos;
|
||||
|
|
@ -715,10 +719,10 @@ void instance_t::include_directive(char * line)
|
|||
mask_t glob;
|
||||
#if BOOST_VERSION >= 103700
|
||||
path parent_path = filename.parent_path();
|
||||
glob.assign_glob(filename.filename());
|
||||
glob.assign_glob('^' + filename.filename() + '$');
|
||||
#else // BOOST_VERSION >= 103700
|
||||
path parent_path = filename.branch_path();
|
||||
glob.assign_glob(filename.leaf());
|
||||
glob.assign_glob('^' + filename.leaf() + '$');
|
||||
#endif // BOOST_VERSION >= 103700
|
||||
|
||||
bool files_found = false;
|
||||
|
|
|
|||
209
src/times.cc
209
src/times.cc
|
|
@ -310,7 +310,14 @@ string_to_month_of_year(const std::string& str)
|
|||
|
||||
datetime_t parse_datetime(const char * str)
|
||||
{
|
||||
datetime_t when = input_datetime_io->parse(str);
|
||||
char buf[128];
|
||||
std::strcpy(buf, str);
|
||||
|
||||
for (char * p = buf; *p; p++)
|
||||
if (*p == '.' || *p == '-')
|
||||
*p = '/';
|
||||
|
||||
datetime_t when = input_datetime_io->parse(buf);
|
||||
if (when.is_not_a_date_time())
|
||||
throw_(date_error, _("Invalid date/time: %1") << str);
|
||||
return when;
|
||||
|
|
@ -401,6 +408,8 @@ class date_parser_t
|
|||
TOK_A_MONTH,
|
||||
TOK_A_WDAY,
|
||||
|
||||
TOK_AGO,
|
||||
TOK_HENCE,
|
||||
TOK_SINCE,
|
||||
TOK_UNTIL,
|
||||
TOK_IN,
|
||||
|
|
@ -498,6 +507,8 @@ class date_parser_t
|
|||
out << date_specifier_t::day_of_week_type
|
||||
(boost::get<date_time::weekdays>(*value));
|
||||
break;
|
||||
case TOK_AGO: return "ago";
|
||||
case TOK_HENCE: return "hence";
|
||||
case TOK_SINCE: return "since";
|
||||
case TOK_UNTIL: return "until";
|
||||
case TOK_IN: return "in";
|
||||
|
|
@ -545,6 +556,8 @@ class date_parser_t
|
|||
case TOK_A_YEAR: out << "TOK_A_YEAR"; break;
|
||||
case TOK_A_MONTH: out << "TOK_A_MONTH"; break;
|
||||
case TOK_A_WDAY: out << "TOK_A_WDAY"; break;
|
||||
case TOK_AGO: out << "TOK_AGO"; break;
|
||||
case TOK_HENCE: out << "TOK_HENCE"; break;
|
||||
case TOK_SINCE: out << "TOK_SINCE"; break;
|
||||
case TOK_UNTIL: out << "TOK_UNTIL"; break;
|
||||
case TOK_IN: out << "TOK_IN"; break;
|
||||
|
|
@ -638,17 +651,182 @@ private:
|
|||
void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok,
|
||||
date_specifier_t& specifier)
|
||||
{
|
||||
date_t today = CURRENT_DATE();
|
||||
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_DATE:
|
||||
specifier = boost::get<date_specifier_t>(*tok.value);
|
||||
break;
|
||||
|
||||
case lexer_t::token_t::TOK_INT:
|
||||
specifier.day =
|
||||
date_specifier_t::day_type(boost::get<unsigned short>(*tok.value));
|
||||
case lexer_t::token_t::TOK_INT: {
|
||||
unsigned short amount = boost::get<unsigned short>(*tok.value);
|
||||
int8_t adjust = 0;
|
||||
|
||||
tok = lexer.peek_token();
|
||||
lexer_t::token_t::kind_t kind = tok.kind;
|
||||
switch (kind) {
|
||||
case lexer_t::token_t::TOK_YEAR:
|
||||
case lexer_t::token_t::TOK_YEARS:
|
||||
case lexer_t::token_t::TOK_QUARTER:
|
||||
case lexer_t::token_t::TOK_QUARTERS:
|
||||
case lexer_t::token_t::TOK_MONTH:
|
||||
case lexer_t::token_t::TOK_MONTHS:
|
||||
case lexer_t::token_t::TOK_WEEK:
|
||||
case lexer_t::token_t::TOK_WEEKS:
|
||||
case lexer_t::token_t::TOK_DAY:
|
||||
case lexer_t::token_t::TOK_DAYS:
|
||||
lexer.next_token();
|
||||
tok = lexer.next_token();
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_AGO:
|
||||
adjust = -1;
|
||||
break;
|
||||
case lexer_t::token_t::TOK_HENCE:
|
||||
adjust = 1;
|
||||
break;
|
||||
default:
|
||||
tok.unexpected();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
date_t when(today);
|
||||
|
||||
switch (kind) {
|
||||
case lexer_t::token_t::TOK_YEAR:
|
||||
case lexer_t::token_t::TOK_YEARS:
|
||||
when += gregorian::years(amount * adjust);
|
||||
break;
|
||||
case lexer_t::token_t::TOK_QUARTER:
|
||||
case lexer_t::token_t::TOK_QUARTERS: {
|
||||
date_t temp =
|
||||
date_duration_t::find_nearest(today, date_duration_t::QUARTERS);
|
||||
when += gregorian::months(amount * 3 * adjust);
|
||||
break;
|
||||
}
|
||||
case lexer_t::token_t::TOK_MONTH:
|
||||
case lexer_t::token_t::TOK_MONTHS:
|
||||
when += gregorian::months(amount * adjust);
|
||||
break;
|
||||
case lexer_t::token_t::TOK_WEEK:
|
||||
case lexer_t::token_t::TOK_WEEKS:
|
||||
when += gregorian::weeks(amount * adjust);
|
||||
break;
|
||||
case lexer_t::token_t::TOK_DAY:
|
||||
case lexer_t::token_t::TOK_DAYS:
|
||||
when += gregorian::days(amount * adjust);
|
||||
break;
|
||||
default:
|
||||
specifier.day = date_specifier_t::day_type(amount);
|
||||
break;
|
||||
}
|
||||
|
||||
if (adjust)
|
||||
specifier = date_specifier_t(when);
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_THIS:
|
||||
case lexer_t::token_t::TOK_NEXT:
|
||||
case lexer_t::token_t::TOK_LAST: {
|
||||
int8_t adjust = 0;
|
||||
if (tok.kind == lexer_t::token_t::TOK_NEXT)
|
||||
adjust = 1;
|
||||
else if (tok.kind == lexer_t::token_t::TOK_LAST)
|
||||
adjust = -1;
|
||||
|
||||
tok = lexer.next_token();
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_A_MONTH: {
|
||||
date_t temp(today.year(),
|
||||
boost::get<date_time::months_of_year>(*tok.value), 1);
|
||||
temp += gregorian::years(adjust);
|
||||
specifier =
|
||||
date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
|
||||
temp.month());
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_A_WDAY: {
|
||||
date_t temp =
|
||||
date_duration_t::find_nearest(today, date_duration_t::WEEKS);
|
||||
while (temp.day_of_week() !=
|
||||
boost::get<date_time::months_of_year>(*tok.value))
|
||||
temp += gregorian::days(1);
|
||||
temp += gregorian::days(7 * adjust);
|
||||
specifier = date_specifier_t(temp);
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_YEAR: {
|
||||
date_t temp(today);
|
||||
temp += gregorian::years(adjust);
|
||||
specifier =
|
||||
date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()));
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_QUARTER: {
|
||||
date_t base =
|
||||
date_duration_t::find_nearest(today, date_duration_t::QUARTERS);
|
||||
date_t temp;
|
||||
if (adjust < 0) {
|
||||
temp = base + gregorian::months(3 * adjust);
|
||||
}
|
||||
else if (adjust == 0) {
|
||||
temp = base + gregorian::months(3);
|
||||
}
|
||||
else if (adjust > 0) {
|
||||
base += gregorian::months(3 * adjust);
|
||||
temp = base + gregorian::months(3 * adjust);
|
||||
}
|
||||
specifier = date_specifier_t(adjust < 0 ? temp : base);
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_WEEK: {
|
||||
date_t base =
|
||||
date_duration_t::find_nearest(today, date_duration_t::WEEKS);
|
||||
date_t temp;
|
||||
if (adjust < 0) {
|
||||
temp = base + gregorian::days(7 * adjust);
|
||||
}
|
||||
else if (adjust == 0) {
|
||||
temp = base + gregorian::days(7);
|
||||
}
|
||||
else if (adjust > 0) {
|
||||
base += gregorian::days(7 * adjust);
|
||||
temp = base + gregorian::days(7 * adjust);
|
||||
}
|
||||
specifier = date_specifier_t(adjust < 0 ? temp : base);
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_DAY: {
|
||||
date_t temp(today);
|
||||
temp += gregorian::days(adjust);
|
||||
specifier = date_specifier_t(temp);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
case lexer_t::token_t::TOK_MONTH: {
|
||||
date_t temp(today);
|
||||
temp += gregorian::months(adjust);
|
||||
specifier =
|
||||
date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
|
||||
temp.month());
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case lexer_t::token_t::TOK_A_YEAR:
|
||||
specifier.year = boost::get<date_specifier_t::year_type>(*tok.value);
|
||||
specifier.year = boost::get<date_specifier_t::year_type>(*tok.value);
|
||||
break;
|
||||
case lexer_t::token_t::TOK_A_MONTH:
|
||||
specifier.month =
|
||||
|
|
@ -662,13 +840,13 @@ void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok,
|
|||
break;
|
||||
|
||||
case lexer_t::token_t::TOK_TODAY:
|
||||
specifier = date_specifier_t(CURRENT_DATE());
|
||||
specifier = date_specifier_t(today);
|
||||
break;
|
||||
case lexer_t::token_t::TOK_TOMORROW:
|
||||
specifier = date_specifier_t(CURRENT_DATE() + gregorian::days(1));
|
||||
specifier = date_specifier_t(today + gregorian::days(1));
|
||||
break;
|
||||
case lexer_t::token_t::TOK_YESTERDAY:
|
||||
specifier = date_specifier_t(CURRENT_DATE() - gregorian::days(1));
|
||||
specifier = date_specifier_t(today - gregorian::days(1));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -784,6 +962,9 @@ date_interval_t date_parser_t::parse()
|
|||
date_t base(today);
|
||||
date_t end(today);
|
||||
|
||||
if (! adjust)
|
||||
adjust = 1;
|
||||
|
||||
tok = lexer.next_token();
|
||||
switch (tok.kind) {
|
||||
case lexer_t::token_t::TOK_YEARS:
|
||||
|
|
@ -1231,6 +1412,8 @@ bool date_interval_t::find_period(const date_t& date)
|
|||
DEBUG("times.interval", "true: start = " << *start);
|
||||
DEBUG("times.interval", "true: end_of_duration = " << *end_of_duration);
|
||||
|
||||
resolve_end();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1281,7 +1464,11 @@ void date_interval_t::dump(std::ostream& out)
|
|||
if (duration)
|
||||
out << _("duration: ") << duration->to_string() << std::endl;
|
||||
|
||||
stabilize(begin());
|
||||
optional<date_t> when(begin());
|
||||
if (! when)
|
||||
when = CURRENT_DATE();
|
||||
|
||||
stabilize(when);
|
||||
|
||||
out << std::endl
|
||||
<< _("--- After stabilization ---") << std::endl;
|
||||
|
|
@ -1401,6 +1588,10 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
|
|||
string_to_day_of_week(term)) {
|
||||
return token_t(token_t::TOK_A_WDAY, token_t::content_t(*wday));
|
||||
}
|
||||
else if (term == _("ago"))
|
||||
return token_t(token_t::TOK_AGO);
|
||||
else if (term == _("hence"))
|
||||
return token_t(token_t::TOK_HENCE);
|
||||
else if (term == _("from") || term == _("since"))
|
||||
return token_t(token_t::TOK_SINCE);
|
||||
else if (term == _("to") || term == _("until"))
|
||||
|
|
|
|||
|
|
@ -68,14 +68,14 @@ inline bool is_valid(const date_t& moment) {
|
|||
extern optional<datetime_t> epoch;
|
||||
|
||||
#ifdef BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK
|
||||
#define TRUE_CURRENT_TIME() (boost::posix_time::microsec_clock::universal_time())
|
||||
#define TRUE_CURRENT_TIME() (boost::posix_time::microsec_clock::local_time())
|
||||
#define CURRENT_TIME() (epoch ? *epoch : TRUE_CURRENT_TIME())
|
||||
#else
|
||||
#define TRUE_CURRENT_TIME() (boost::posix_time::second_clock::universal_time())
|
||||
#define TRUE_CURRENT_TIME() (boost::posix_time::second_clock::local_time())
|
||||
#define CURRENT_TIME() (epoch ? *epoch : TRUE_CURRENT_TIME())
|
||||
#endif
|
||||
#define CURRENT_DATE() \
|
||||
(epoch ? epoch->date() : boost::gregorian::day_clock::universal_day())
|
||||
(epoch ? epoch->date() : boost::gregorian::day_clock::local_day())
|
||||
|
||||
extern date_time::weekdays start_of_week;
|
||||
|
||||
|
|
|
|||
20
src/value.cc
20
src/value.cc
|
|
@ -901,13 +901,10 @@ bool value_t::is_less_than(const value_t& val) const
|
|||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
case AMOUNT: {
|
||||
if (val.is_nonzero())
|
||||
break;
|
||||
|
||||
bool no_amounts = true;
|
||||
foreach (const balance_t::amounts_map::value_type& pair,
|
||||
as_balance().amounts) {
|
||||
if (pair.second >= 0L)
|
||||
if (pair.second >= val)
|
||||
return false;
|
||||
no_amounts = false;
|
||||
}
|
||||
|
|
@ -927,12 +924,9 @@ bool value_t::is_less_than(const value_t& val) const
|
|||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
case AMOUNT: {
|
||||
if (val.is_nonzero())
|
||||
break;
|
||||
|
||||
bool no_amounts = true;
|
||||
foreach (const value_t& value, as_sequence()) {
|
||||
if (value >= 0L)
|
||||
if (value >= val)
|
||||
return false;
|
||||
no_amounts = false;
|
||||
}
|
||||
|
|
@ -1023,13 +1017,10 @@ bool value_t::is_greater_than(const value_t& val) const
|
|||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
case AMOUNT: {
|
||||
if (val.is_nonzero())
|
||||
break;
|
||||
|
||||
bool no_amounts = true;
|
||||
foreach (const balance_t::amounts_map::value_type& pair,
|
||||
as_balance().amounts) {
|
||||
if (pair.second <= 0L)
|
||||
if (pair.second <= val)
|
||||
return false;
|
||||
no_amounts = false;
|
||||
}
|
||||
|
|
@ -1049,12 +1040,9 @@ bool value_t::is_greater_than(const value_t& val) const
|
|||
switch (val.type()) {
|
||||
case INTEGER:
|
||||
case AMOUNT: {
|
||||
if (val.is_nonzero())
|
||||
break;
|
||||
|
||||
bool no_amounts = true;
|
||||
foreach (const value_t& value, as_sequence()) {
|
||||
if (value <= 0L)
|
||||
if (value <= val)
|
||||
return false;
|
||||
no_amounts = false;
|
||||
}
|
||||
|
|
|
|||
117
src/xact.cc
117
src/xact.cc
|
|
@ -124,27 +124,13 @@ bool xact_base_t::finalize()
|
|||
amount_t& p(post->cost ? *post->cost : post->amount);
|
||||
if (! p.is_null()) {
|
||||
DEBUG("xact.finalize", "post must balance = " << p.reduced());
|
||||
if (! post->cost && post->amount.has_annotation() &&
|
||||
post->amount.annotation().price) {
|
||||
// If the amount has no cost, but is annotated with a per-unit
|
||||
// price, use the price times the amount as the cost
|
||||
post->cost = (*post->amount.annotation().price *
|
||||
post->amount).unrounded();
|
||||
DEBUG("xact.finalize",
|
||||
"annotation price = " << *post->amount.annotation().price);
|
||||
DEBUG("xact.finalize", "amount = " << post->amount);
|
||||
DEBUG("xact.finalize", "priced cost = " << *post->cost);
|
||||
post->add_flags(POST_COST_CALCULATED);
|
||||
add_or_set_value(balance, post->cost->rounded().reduced());
|
||||
} else {
|
||||
// If the amount was a cost, it very likely has the "keep_precision"
|
||||
// flag set, meaning commodity display precision is ignored when
|
||||
// displaying the amount. We never want this set for the balance,
|
||||
// so we must clear the flag in a temporary to avoid it propagating
|
||||
// into the balance.
|
||||
add_or_set_value(balance, p.keep_precision() ?
|
||||
p.rounded().reduced() : p.reduced());
|
||||
}
|
||||
// If the amount was a cost, it very likely has the
|
||||
// "keep_precision" flag set, meaning commodity display precision
|
||||
// is ignored when displaying the amount. We never want this set
|
||||
// for the balance, so we must clear the flag in a temporary to
|
||||
// avoid it propagating into the balance.
|
||||
add_or_set_value(balance, p.keep_precision() ?
|
||||
p.rounded().reduced() : p.reduced());
|
||||
}
|
||||
else if (null_post) {
|
||||
throw_(std::logic_error,
|
||||
|
|
@ -173,14 +159,15 @@ bool xact_base_t::finalize()
|
|||
add_post(null_post);
|
||||
}
|
||||
|
||||
if (balance.is_balance() &&
|
||||
if (! null_post && balance.is_balance() &&
|
||||
balance.as_balance().amounts.size() == 2) {
|
||||
// When an xact involves two different commodities (regardless of how
|
||||
// many posts there are) determine the conversion ratio by dividing the
|
||||
// total value of one commodity by the total value of the other. This
|
||||
// establishes the per-unit cost for this post for both commodities.
|
||||
|
||||
DEBUG("xact.finalize", "there were exactly two commodities");
|
||||
DEBUG("xact.finalize",
|
||||
"there were exactly two commodities, and no null post");
|
||||
|
||||
bool saw_cost = false;
|
||||
post_t * top_post = NULL;
|
||||
|
|
@ -268,55 +255,65 @@ bool xact_base_t::finalize()
|
|||
|
||||
posts_list copy(posts);
|
||||
|
||||
foreach (post_t * post, copy) {
|
||||
if (! post->cost)
|
||||
continue;
|
||||
if (has_date()) {
|
||||
foreach (post_t * post, copy) {
|
||||
if (! post->cost)
|
||||
continue;
|
||||
|
||||
if (post->amount.commodity() == post->cost->commodity())
|
||||
throw_(balance_error,
|
||||
_("A posting's cost must be of a different commodity than its amount"));
|
||||
if (post->amount.commodity() == post->cost->commodity())
|
||||
throw_(balance_error,
|
||||
_("A posting's cost must be of a different commodity than its amount"));
|
||||
|
||||
cost_breakdown_t breakdown =
|
||||
commodity_pool_t::current_pool->exchange
|
||||
cost_breakdown_t breakdown =
|
||||
commodity_pool_t::current_pool->exchange
|
||||
(post->amount, *post->cost, false,
|
||||
datetime_t(date(), time_duration(0, 0, 0, 0)));
|
||||
|
||||
if (post->amount.has_annotation() &&
|
||||
breakdown.basis_cost.commodity() == breakdown.final_cost.commodity()) {
|
||||
if (amount_t gain_loss = breakdown.basis_cost - breakdown.final_cost) {
|
||||
DEBUG("xact.finalize", "gain_loss = " << gain_loss);
|
||||
gain_loss.in_place_round();
|
||||
DEBUG("xact.finalize", "gain_loss rounds to = " << gain_loss);
|
||||
if (post->amount.has_annotation() && post->amount.annotation().price) {
|
||||
if (breakdown.basis_cost.commodity() == breakdown.final_cost.commodity()) {
|
||||
if (amount_t gain_loss = breakdown.basis_cost - breakdown.final_cost) {
|
||||
DEBUG("xact.finalize", "gain_loss = " << gain_loss);
|
||||
gain_loss.in_place_round();
|
||||
DEBUG("xact.finalize", "gain_loss rounds to = " << gain_loss);
|
||||
|
||||
if (post->must_balance())
|
||||
add_or_set_value(balance, gain_loss.reduced());
|
||||
if (post->must_balance())
|
||||
add_or_set_value(balance, gain_loss.reduced());
|
||||
|
||||
account_t * account;
|
||||
if (gain_loss.sign() > 0)
|
||||
account = journal->find_account(_("Equity:Capital Gains"));
|
||||
else
|
||||
account = journal->find_account(_("Equity:Capital Losses"));
|
||||
account_t * account;
|
||||
if (gain_loss.sign() > 0)
|
||||
account = journal->find_account(_("Equity:Capital Gains"));
|
||||
else
|
||||
account = journal->find_account(_("Equity:Capital Losses"));
|
||||
|
||||
post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
|
||||
p->set_state(post->state());
|
||||
if (post->has_flags(POST_VIRTUAL)) {
|
||||
DEBUG("xact.finalize", "gain_loss came from a virtual post");
|
||||
p->add_flags(post->flags() & (POST_VIRTUAL | POST_MUST_BALANCE));
|
||||
post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
|
||||
p->set_state(post->state());
|
||||
if (post->has_flags(POST_VIRTUAL)) {
|
||||
DEBUG("xact.finalize", "gain_loss came from a virtual post");
|
||||
p->add_flags(post->flags() & (POST_VIRTUAL | POST_MUST_BALANCE));
|
||||
}
|
||||
add_post(p);
|
||||
DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
|
||||
} else {
|
||||
DEBUG("xact.finalize", "gain_loss would have displayed as zero");
|
||||
}
|
||||
}
|
||||
add_post(p);
|
||||
DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
|
||||
} else {
|
||||
DEBUG("xact.finalize", "gain_loss would have display as zero");
|
||||
if (post->amount.has_annotation()) {
|
||||
if (breakdown.amount.has_annotation())
|
||||
breakdown.amount.annotation().tag = post->amount.annotation().tag;
|
||||
else
|
||||
breakdown.amount.annotate
|
||||
(annotation_t(none, none, post->amount.annotation().tag));
|
||||
}
|
||||
post->amount = breakdown.amount;
|
||||
DEBUG("xact.finalize", "added breakdown, balance = " << balance);
|
||||
}
|
||||
} else {
|
||||
post->amount = breakdown.amount;
|
||||
DEBUG("xact.finalize", "added breakdown, balance = " << balance);
|
||||
}
|
||||
|
||||
if (post->has_flags(POST_COST_FIXATED) &&
|
||||
post->amount.has_annotation() && post->amount.annotation().price) {
|
||||
DEBUG("xact.finalize", "fixating annotation price");
|
||||
post->amount.annotation().add_flags(ANNOTATION_PRICE_FIXATED);
|
||||
if (post->has_flags(POST_COST_FIXATED) &&
|
||||
post->amount.has_annotation() && post->amount.annotation().price) {
|
||||
DEBUG("xact.finalize", "fixating annotation price");
|
||||
post->amount.annotation().add_flags(ANNOTATION_PRICE_FIXATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
121
test/CheckComments.py
Normal file
121
test/CheckComments.py
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
ok = 100.0
|
||||
if sys.argv[1] == '-l':
|
||||
ok = float(sys.argv[2])
|
||||
sys.argv = [sys.argv[0]] + sys.argv[3:]
|
||||
|
||||
debug = False
|
||||
if sys.argv[1] == '-v':
|
||||
debug = True
|
||||
sys.argv = [sys.argv[0]] + sys.argv[2:]
|
||||
|
||||
errors = 0
|
||||
|
||||
for path in sys.argv[1:]:
|
||||
other_depth = 0
|
||||
brace_depth = 0
|
||||
code_count = 0
|
||||
comment_count = 0
|
||||
long_comment = None
|
||||
long_comments = {}
|
||||
kind = "function"
|
||||
function_name = "<unknown>"
|
||||
ctor_dtor = False
|
||||
linenum = 0
|
||||
|
||||
fd = open(path, 'r')
|
||||
for line in fd.readlines():
|
||||
linenum += 1
|
||||
|
||||
match = re.search('/\*\*(.*)', line)
|
||||
if match:
|
||||
long_comment = re.sub('\s+', '', match.group(1))
|
||||
continue
|
||||
elif long_comment:
|
||||
match = re.search('(.*)\*/', line)
|
||||
if match:
|
||||
long_comment += re.sub('\s+', '', match.group(1))
|
||||
comment_count = len(long_comment)
|
||||
long_comment = None
|
||||
else:
|
||||
long_comment += re.sub('\s+', '', line[:-1])
|
||||
continue
|
||||
|
||||
if brace_depth == 0:
|
||||
match = re.search('(namespace|enum|class|struct|union)', line)
|
||||
if match:
|
||||
kind = match.group(1)
|
||||
if debug: print "kind =", kind
|
||||
elif kind == "function":
|
||||
match = re.search('(\S+)\(', line)
|
||||
if match:
|
||||
function_name = match.group(1)
|
||||
long_comments[function_name] = comment_count
|
||||
comment_count = 0
|
||||
if debug: print "name found %s" % function_name
|
||||
|
||||
if re.search('{', line) and not re.search('@{', line):
|
||||
if kind == "function":
|
||||
brace_depth += 1
|
||||
if debug: print "brace_depth =", brace_depth
|
||||
else:
|
||||
other_depth += 1
|
||||
kind = "function"
|
||||
if debug: print "other_depth =", other_depth
|
||||
|
||||
if re.search('}', line) and not re.search('@}', line):
|
||||
if brace_depth > 0:
|
||||
brace_depth -= 1
|
||||
if debug: print "brace_depth =", brace_depth
|
||||
|
||||
if brace_depth == 0:
|
||||
if debug: print "function done"
|
||||
if function_name in long_comments:
|
||||
comment_count += long_comments[function_name]
|
||||
if code_count == 0:
|
||||
percent = ok
|
||||
print "%7s %4d/%4d %s:%d: %s" % \
|
||||
("empty", comment_count, code_count,
|
||||
os.path.basename(path), linenum,
|
||||
function_name)
|
||||
errors += 1
|
||||
else:
|
||||
percent = 100.0 * (float(comment_count) /
|
||||
float(code_count))
|
||||
if percent < ok and not ctor_dtor:
|
||||
print "%6.0f%% %4d/%4d %s:%d: %s" % \
|
||||
(percent, comment_count, code_count,
|
||||
os.path.basename(path), linenum,
|
||||
function_name)
|
||||
errors += 1
|
||||
code_count = 0
|
||||
comment_count = 0
|
||||
kind = "function"
|
||||
function_name = "<unknown>"
|
||||
ctor_dtor = False
|
||||
else:
|
||||
other_depth -= 1
|
||||
if debug: print "other_depth =", other_depth
|
||||
|
||||
if brace_depth > 0:
|
||||
if re.search("TRACE_[CD]TOR", line):
|
||||
ctor_dtor = True
|
||||
|
||||
line = re.sub('\s+', '', line[:-1])
|
||||
|
||||
match = re.search('//(.*)', line)
|
||||
if match:
|
||||
comment = match.group(1)
|
||||
line = re.sub('//.*', '', line)
|
||||
else:
|
||||
comment = None
|
||||
|
||||
if line:
|
||||
code_count += len(line)
|
||||
if comment:
|
||||
comment_count += len(comment)
|
||||
|
||||
sys.exit(errors)
|
||||
87
test/CheckTests.py
Executable file
87
test/CheckTests.py
Executable file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
from os.path import *
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
ledger_binary = sys.argv[1]
|
||||
source_topdir = sys.argv[2]
|
||||
|
||||
documented_options = []
|
||||
for line in open(join(source_topdir, 'doc', 'ledger.1')):
|
||||
match = re.match('\.It Fl \\\\-([-A-Za-z]+)', line)
|
||||
if match:
|
||||
option = match.group(1)
|
||||
if option not in documented_options:
|
||||
documented_options.append(option)
|
||||
|
||||
pipe = Popen('%s --debug option.names parse true' % ledger_binary,
|
||||
shell=True, stdout=PIPE, stderr=PIPE)
|
||||
errors = 0
|
||||
|
||||
untested_options = [
|
||||
'anon',
|
||||
'args-only',
|
||||
'cache',
|
||||
'debug',
|
||||
'download',
|
||||
'file',
|
||||
'force-color',
|
||||
'force-pager',
|
||||
'full-help',
|
||||
'help',
|
||||
'help-calc',
|
||||
'help-comm',
|
||||
'help-disp',
|
||||
'import',
|
||||
'init-file',
|
||||
'no-color',
|
||||
'options',
|
||||
'price-db',
|
||||
'price-exp',
|
||||
'revalued-total',
|
||||
'script',
|
||||
'seed',
|
||||
'trace',
|
||||
'verbose',
|
||||
'verify',
|
||||
'version'
|
||||
]
|
||||
|
||||
for line in pipe.stderr:
|
||||
match = re.search('\[DEBUG\] Option: (.*)', line)
|
||||
if match:
|
||||
option = match.group(1)
|
||||
|
||||
option = re.sub('_', '-', option)
|
||||
option = re.sub('-$', '', option)
|
||||
|
||||
if option not in untested_options and \
|
||||
not exists(join(source_topdir, 'test', 'baseline',
|
||||
'opt-%s.test' % option)):
|
||||
print "Baseline test missing for --%s" % option
|
||||
errors += 1
|
||||
|
||||
if option not in documented_options:
|
||||
print "Man page entry missing for --%s" % option
|
||||
errors += 1
|
||||
else:
|
||||
documented_options.remove(option)
|
||||
|
||||
known_alternates = [
|
||||
'cost',
|
||||
'first',
|
||||
'import',
|
||||
'last',
|
||||
'leeway',
|
||||
'period-sort'
|
||||
]
|
||||
|
||||
for option in documented_options:
|
||||
if option not in known_alternates:
|
||||
print "Man page entry for unknown option --%s" % option
|
||||
|
||||
sys.exit(errors)
|
||||
|
|
@ -130,6 +130,7 @@ def run_gen_test(i):
|
|||
harness.success()
|
||||
else:
|
||||
harness.failure()
|
||||
return harness.failed
|
||||
|
||||
if multiproc:
|
||||
pool = Pool(jobs*2)
|
||||
|
|
@ -137,7 +138,7 @@ else:
|
|||
pool = None
|
||||
|
||||
if pool:
|
||||
pool.map(run_gen_test, range(beg_range, end_range))
|
||||
harness.failed = sum(pool.map(run_gen_test, range(beg_range, end_range)))
|
||||
else:
|
||||
for i in range(beg_range, end_range):
|
||||
run_gen_test(i)
|
||||
|
|
@ -145,4 +146,5 @@ else:
|
|||
if pool:
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
harness.exit()
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class RegressFile(object):
|
|||
def read_section(self):
|
||||
lines = []
|
||||
line = self.fd.readline()
|
||||
while not self.is_directive(line):
|
||||
while line and not self.is_directive(line):
|
||||
lines.append(self.transform_line(line))
|
||||
line = self.fd.readline()
|
||||
return (lines, line)
|
||||
|
|
@ -154,18 +154,22 @@ class RegressFile(object):
|
|||
if not use_stdin:
|
||||
os.remove(tempdata[1])
|
||||
|
||||
def run_tests(self, pool):
|
||||
def run_tests(self):
|
||||
test = self.read_test()
|
||||
while test:
|
||||
if pool:
|
||||
pool.apply_async(RegressFile.run_test, (self, test,))
|
||||
else:
|
||||
self.run_test(test)
|
||||
self.run_test(test)
|
||||
test = self.read_test(test)
|
||||
return harness.failed
|
||||
|
||||
def close(self):
|
||||
self.fd.close()
|
||||
|
||||
def do_test(path):
|
||||
entry = RegressFile(path)
|
||||
failed = entry.run_tests()
|
||||
entry.close()
|
||||
return failed
|
||||
|
||||
if __name__ == '__main__':
|
||||
if multiproc:
|
||||
pool = Pool(jobs*2)
|
||||
|
|
@ -173,17 +177,19 @@ if __name__ == '__main__':
|
|||
pool = None
|
||||
|
||||
if os.path.isdir(tests):
|
||||
for test_file in os.listdir(tests):
|
||||
if re.search('\.test$', test_file):
|
||||
entry = RegressFile(os.path.join(tests, test_file))
|
||||
entry.run_tests(pool)
|
||||
entry.close()
|
||||
tests = [os.path.join(tests, x)
|
||||
for x in os.listdir(tests) if x.endswith('.test')]
|
||||
if pool:
|
||||
harness.failed = sum(pool.map(do_test, tests, 1))
|
||||
else:
|
||||
harness.failed = sum(map(do_test, tests))
|
||||
else:
|
||||
entry = RegressFile(tests)
|
||||
entry.run_tests(pool)
|
||||
entry.run_tests()
|
||||
entry.close()
|
||||
|
||||
if pool:
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
harness.exit()
|
||||
|
|
|
|||
|
|
@ -22,3 +22,15 @@ P 1990/02/15 12:00:00 FOO $3
|
|||
90-Feb-20 Payee Expenses:Gas $300 $800
|
||||
>>>2
|
||||
=== 0
|
||||
reg
|
||||
<<<
|
||||
fixed XCD $0.374531835206
|
||||
|
||||
2008/04/08 KFC
|
||||
Expenses:Food XCD 43.00
|
||||
Assets:Cash
|
||||
|
||||
end fixed
|
||||
>>>
|
||||
08-Apr-08 KFC Expenses:Food XCD 43.00 XCD 43.00
|
||||
Assets:Cash XCD -43.00 0
|
||||
|
|
|
|||
0
test/baseline/opt-actual-dates.test
Normal file
0
test/baseline/opt-actual-dates.test
Normal file
|
|
@ -1,4 +1,4 @@
|
|||
reg --add-budget books cards
|
||||
reg --add-budget books cards --now=2009/12/31
|
||||
<<<
|
||||
~ monthly
|
||||
Expenses:Books $10.00
|
||||
|
|
|
|||
0
test/baseline/opt-bold-if.test
Normal file
0
test/baseline/opt-bold-if.test
Normal file
0
test/baseline/opt-budget-format.test
Normal file
0
test/baseline/opt-budget-format.test
Normal file
|
|
@ -1,4 +1,4 @@
|
|||
reg --budget books
|
||||
reg --budget books --now=2009/12/31
|
||||
<<<
|
||||
~ monthly
|
||||
Expenses:Books $10.00
|
||||
|
|
|
|||
22
test/baseline/opt-budget_only.test
Normal file
22
test/baseline/opt-budget_only.test
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
reg income --budget --now=2010/06/20
|
||||
<<<
|
||||
~ Monthly since 2010/01/01
|
||||
Expenses:Bills:Rent $873.00
|
||||
Expenses:Household $200.00
|
||||
Income:Salary -$2491.60
|
||||
Assets:Bank:Checking
|
||||
|
||||
~ biweekly from 2010/02/23
|
||||
Expenses:Bills:Housecleaning $85.00
|
||||
Assets:Bank:Checking
|
||||
|
||||
2010/06/22 c897683b
|
||||
Expenses:Household $100.00
|
||||
Assets:Bank:Checking
|
||||
>>>
|
||||
10-Jan-01 Budget transaction Income:Salary $2491.60 $2491.60
|
||||
10-Feb-01 Budget transaction Income:Salary $2491.60 $4983.20
|
||||
10-Mar-01 Budget transaction Income:Salary $2491.60 $7474.80
|
||||
10-Apr-01 Budget transaction Income:Salary $2491.60 $9966.40
|
||||
10-May-01 Budget transaction Income:Salary $2491.60 $12458.00
|
||||
10-Jun-01 Budget transaction Income:Salary $2491.60 $14949.60
|
||||
111
test/baseline/opt-budget_range.test
Normal file
111
test/baseline/opt-budget_range.test
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
reg --now=2010/02 --sort=date exp --budget
|
||||
<<<
|
||||
~ monthly
|
||||
Expenses:Food $100
|
||||
Expenses:Movies $20
|
||||
Assets:Cash
|
||||
|
||||
~ monthly from 2009
|
||||
Expenses:Food $101
|
||||
Expenses:Movies $21
|
||||
Assets:Cash
|
||||
|
||||
~ monthly to 2010
|
||||
Expenses:Food $102
|
||||
Expenses:Movies $22
|
||||
Assets:Cash
|
||||
|
||||
~ monthly from 2009 to 2010
|
||||
Expenses:Food $103
|
||||
Expenses:Movies $23
|
||||
Assets:Cash
|
||||
|
||||
2009/06/05 Grocery
|
||||
Expenses:Food $5
|
||||
Assets:Cash
|
||||
>>>
|
||||
09-Jan-01 Budget transaction Expenses:Food $-101 $-101
|
||||
09-Jan-01 Budget transaction Expenses:Movies $-21 $-122
|
||||
09-Jan-01 Budget transaction Expenses:Food $-103 $-225
|
||||
09-Jan-01 Budget transaction Expenses:Movies $-23 $-248
|
||||
09-Feb-01 Budget transaction Expenses:Food $-101 $-349
|
||||
09-Feb-01 Budget transaction Expenses:Movies $-21 $-370
|
||||
09-Feb-01 Budget transaction Expenses:Food $-103 $-473
|
||||
09-Feb-01 Budget transaction Expenses:Movies $-23 $-496
|
||||
09-Mar-01 Budget transaction Expenses:Food $-101 $-597
|
||||
09-Mar-01 Budget transaction Expenses:Movies $-21 $-618
|
||||
09-Mar-01 Budget transaction Expenses:Food $-103 $-721
|
||||
09-Mar-01 Budget transaction Expenses:Movies $-23 $-744
|
||||
09-Apr-01 Budget transaction Expenses:Food $-101 $-845
|
||||
09-Apr-01 Budget transaction Expenses:Movies $-21 $-866
|
||||
09-Apr-01 Budget transaction Expenses:Food $-103 $-969
|
||||
09-Apr-01 Budget transaction Expenses:Movies $-23 $-992
|
||||
09-May-01 Budget transaction Expenses:Food $-101 $-1093
|
||||
09-May-01 Budget transaction Expenses:Movies $-21 $-1114
|
||||
09-May-01 Budget transaction Expenses:Food $-103 $-1217
|
||||
09-May-01 Budget transaction Expenses:Movies $-23 $-1240
|
||||
09-Jun-01 Budget transaction Expenses:Food $-100 $-1340
|
||||
09-Jun-01 Budget transaction Expenses:Movies $-20 $-1360
|
||||
09-Jun-01 Budget transaction Expenses:Food $-102 $-1462
|
||||
09-Jun-01 Budget transaction Expenses:Movies $-22 $-1484
|
||||
09-Jun-01 Budget transaction Expenses:Food $-101 $-1585
|
||||
09-Jun-01 Budget transaction Expenses:Movies $-21 $-1606
|
||||
09-Jun-01 Budget transaction Expenses:Food $-103 $-1709
|
||||
09-Jun-01 Budget transaction Expenses:Movies $-23 $-1732
|
||||
09-Jun-05 Grocery Expenses:Food $5 $-1727
|
||||
09-Jul-01 Budget transaction Expenses:Food $-100 $-1827
|
||||
09-Jul-01 Budget transaction Expenses:Movies $-20 $-1847
|
||||
09-Jul-01 Budget transaction Expenses:Food $-101 $-1948
|
||||
09-Jul-01 Budget transaction Expenses:Movies $-21 $-1969
|
||||
09-Jul-01 Budget transaction Expenses:Food $-102 $-2071
|
||||
09-Jul-01 Budget transaction Expenses:Movies $-22 $-2093
|
||||
09-Jul-01 Budget transaction Expenses:Food $-103 $-2196
|
||||
09-Jul-01 Budget transaction Expenses:Movies $-23 $-2219
|
||||
09-Aug-01 Budget transaction Expenses:Food $-100 $-2319
|
||||
09-Aug-01 Budget transaction Expenses:Movies $-20 $-2339
|
||||
09-Aug-01 Budget transaction Expenses:Food $-101 $-2440
|
||||
09-Aug-01 Budget transaction Expenses:Movies $-21 $-2461
|
||||
09-Aug-01 Budget transaction Expenses:Food $-102 $-2563
|
||||
09-Aug-01 Budget transaction Expenses:Movies $-22 $-2585
|
||||
09-Aug-01 Budget transaction Expenses:Food $-103 $-2688
|
||||
09-Aug-01 Budget transaction Expenses:Movies $-23 $-2711
|
||||
09-Sep-01 Budget transaction Expenses:Food $-100 $-2811
|
||||
09-Sep-01 Budget transaction Expenses:Movies $-20 $-2831
|
||||
09-Sep-01 Budget transaction Expenses:Food $-101 $-2932
|
||||
09-Sep-01 Budget transaction Expenses:Movies $-21 $-2953
|
||||
09-Sep-01 Budget transaction Expenses:Food $-102 $-3055
|
||||
09-Sep-01 Budget transaction Expenses:Movies $-22 $-3077
|
||||
09-Sep-01 Budget transaction Expenses:Food $-103 $-3180
|
||||
09-Sep-01 Budget transaction Expenses:Movies $-23 $-3203
|
||||
09-Oct-01 Budget transaction Expenses:Food $-100 $-3303
|
||||
09-Oct-01 Budget transaction Expenses:Movies $-20 $-3323
|
||||
09-Oct-01 Budget transaction Expenses:Food $-101 $-3424
|
||||
09-Oct-01 Budget transaction Expenses:Movies $-21 $-3445
|
||||
09-Oct-01 Budget transaction Expenses:Food $-102 $-3547
|
||||
09-Oct-01 Budget transaction Expenses:Movies $-22 $-3569
|
||||
09-Oct-01 Budget transaction Expenses:Food $-103 $-3672
|
||||
09-Oct-01 Budget transaction Expenses:Movies $-23 $-3695
|
||||
09-Nov-01 Budget transaction Expenses:Food $-100 $-3795
|
||||
09-Nov-01 Budget transaction Expenses:Movies $-20 $-3815
|
||||
09-Nov-01 Budget transaction Expenses:Food $-101 $-3916
|
||||
09-Nov-01 Budget transaction Expenses:Movies $-21 $-3937
|
||||
09-Nov-01 Budget transaction Expenses:Food $-102 $-4039
|
||||
09-Nov-01 Budget transaction Expenses:Movies $-22 $-4061
|
||||
09-Nov-01 Budget transaction Expenses:Food $-103 $-4164
|
||||
09-Nov-01 Budget transaction Expenses:Movies $-23 $-4187
|
||||
09-Dec-01 Budget transaction Expenses:Food $-100 $-4287
|
||||
09-Dec-01 Budget transaction Expenses:Movies $-20 $-4307
|
||||
09-Dec-01 Budget transaction Expenses:Food $-101 $-4408
|
||||
09-Dec-01 Budget transaction Expenses:Movies $-21 $-4429
|
||||
09-Dec-01 Budget transaction Expenses:Food $-102 $-4531
|
||||
09-Dec-01 Budget transaction Expenses:Movies $-22 $-4553
|
||||
09-Dec-01 Budget transaction Expenses:Food $-103 $-4656
|
||||
09-Dec-01 Budget transaction Expenses:Movies $-23 $-4679
|
||||
10-Jan-01 Budget transaction Expenses:Food $-100 $-4779
|
||||
10-Jan-01 Budget transaction Expenses:Movies $-20 $-4799
|
||||
10-Jan-01 Budget transaction Expenses:Food $-101 $-4900
|
||||
10-Jan-01 Budget transaction Expenses:Movies $-21 $-4921
|
||||
10-Feb-01 Budget transaction Expenses:Food $-100 $-5021
|
||||
10-Feb-01 Budget transaction Expenses:Movies $-20 $-5041
|
||||
10-Feb-01 Budget transaction Expenses:Food $-101 $-5142
|
||||
10-Feb-01 Budget transaction Expenses:Movies $-21 $-5163
|
||||
0
test/baseline/opt-cleared-format.test
Normal file
0
test/baseline/opt-cleared-format.test
Normal file
|
|
@ -4,8 +4,8 @@ reg --account=commodity
|
|||
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
|
||||
Income:Dividends:Vanguard:VMMXX $-0.35
|
||||
>>>1
|
||||
07-Feb-02 RD VMMXX VM:As:Inve:Vangu:VMMXX 0.350 VMMXX 0.350 VMMXX
|
||||
07-Feb-02 RD VMMXX $:In:Divi:Vangua:VMMXX $-0.35 $-0.35
|
||||
07-Feb-02 RD VMMXX VM:As:Inv:Vangua:VMMXX 0.350 VMMXX 0.350 VMMXX
|
||||
07-Feb-02 RD VMMXX $:In:Div:Vanguar:VMMXX $-0.35 $-0.35
|
||||
0.350 VMMXX
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
0
test/baseline/opt-count.test
Normal file
0
test/baseline/opt-count.test
Normal file
0
test/baseline/opt-date.test
Normal file
0
test/baseline/opt-date.test
Normal file
0
test/baseline/opt-datetime-format.test
Normal file
0
test/baseline/opt-datetime-format.test
Normal file
0
test/baseline/opt-decimal-comma.test
Normal file
0
test/baseline/opt-decimal-comma.test
Normal file
|
|
@ -24,13 +24,13 @@ reg --empty
|
|||
Assets:Cash $-10.00 0
|
||||
08-Jan-01 January Expenses:One:Books $10.00 $10.00
|
||||
Expenses:One:Two:Books $10.00 $20.00
|
||||
Expe:On:Tw:Three:Books $10.00 $30.00
|
||||
Ex:One:Two:Three:Books $10.00 $30.00
|
||||
Assets:Cash $-30.00 0
|
||||
08-Jan-01 January Assets:Cash 0 0
|
||||
Income:Books 0 0
|
||||
08-Jan-01 January Assets:Cash $30.00 $30.00
|
||||
Income:One:Books $-10.00 $20.00
|
||||
Income:One:Two:Books $-10.00 $10.00
|
||||
Inc:On:Two:Three:Books $-10.00 0
|
||||
In:One:Two:Three:Books $-10.00 0
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
0
test/baseline/opt-forecast-years.test
Normal file
0
test/baseline/opt-forecast-years.test
Normal file
64
test/baseline/opt-forecast_only.test
Normal file
64
test/baseline/opt-forecast_only.test
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
reg --forecast 'date <[2011]' --now=2010/06/21
|
||||
<<<
|
||||
~ Monthly since 2010/01/01
|
||||
Expenses:Bills:Rent $873.00
|
||||
Expenses:Household $200.00
|
||||
Income:Salary -$2491.60
|
||||
Assets:Bank:Checking
|
||||
|
||||
~ biweekly from 2010/02/23
|
||||
Expenses:Bills:Housecleaning $85.00
|
||||
Assets:Bank:Checking
|
||||
>>>
|
||||
10-Jul-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Jul-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Jul-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Jul-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Jun-27 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jun-27 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Jul-11 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jul-11 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Aug-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Aug-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Aug-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Aug-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Jul-25 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jul-25 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Aug-08 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Aug-08 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Sep-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Sep-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Sep-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Sep-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Aug-22 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Aug-22 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Sep-05 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Sep-05 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Oct-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Oct-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Oct-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Sep-19 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Sep-19 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-03 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-03 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Nov-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Nov-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Nov-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Nov-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Oct-17 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-17 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-31 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-31 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Nov-14 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Nov-14 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Dec-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Dec-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Dec-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Nov-28 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Nov-28 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-12 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Dec-12 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-26 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Dec-26 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
0
test/baseline/opt-generated.test
Normal file
0
test/baseline/opt-generated.test
Normal file
0
test/baseline/opt-group-by.test
Normal file
0
test/baseline/opt-group-by.test
Normal file
0
test/baseline/opt-group-title-format.test
Normal file
0
test/baseline/opt-group-title-format.test
Normal file
0
test/baseline/opt-inject.test
Normal file
0
test/baseline/opt-inject.test
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -4,24 +4,22 @@ D 1.0000s
|
|||
|
||||
2006/03/14 Opening Balances
|
||||
Assets:Tajer 1339829c @ 1.86590975416s
|
||||
Assets:Gruulmorg 248720c {10.051463493s}
|
||||
Assets:Gruulmorg 248720c @ 10.051463493s
|
||||
Equity:Gold -5000000s
|
||||
>>>1
|
||||
1339829c {1.86590975416s} [2006/03/14]
|
||||
1339829c {1.86590975416s} [2006/03/14]
|
||||
248720c {10.051463493s}
|
||||
248720c {10.051463493s} [2006/03/14]
|
||||
1339829c {1.86590975416s} [2006/03/14]
|
||||
248720c {10.051463493s}
|
||||
248720c {10.051463493s} [2006/03/14]
|
||||
-1388.9h
|
||||
>>>2
|
||||
=== 0
|
||||
reg --format '%(justify(scrub(total_expr), 40, 40, true))\n' --lots-actual
|
||||
>>>1
|
||||
1339829c
|
||||
1339829c
|
||||
248720c {10.051463493s}
|
||||
1339829c
|
||||
248720c {10.051463493s}
|
||||
1588549c
|
||||
1588549c
|
||||
-1388.9h
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -356,8 +356,8 @@ D 1.00G
|
|||
Assets:Tajer
|
||||
|
||||
2006/03/17 Player: raev
|
||||
Assets:Tajer:Items "Wildheart Belt" 1 {30G}
|
||||
Assets:Tajer:Items "Ace of Warlords" -2 {15G}
|
||||
Assets:Tajer:Items "Wildheart Belt" 1 @ 30G
|
||||
Assets:Tajer:Items "Ace of Warlords" -2 @ 15G
|
||||
|
||||
2006/03/17 Auction House
|
||||
Expenses:Fees:Auction 7482c
|
||||
|
|
@ -609,8 +609,8 @@ D 1.00G
|
|||
Assets:Tajer -1.20s 0
|
||||
06-Mar-14 Puldoost Assets:Tajer 8.00G 8.00G
|
||||
Expenses:Items -8.00G 0
|
||||
06-Mar-14 Auction House Assets:Wyshona:Items 1.25G 1.25G
|
||||
Assets:Tajer:Items -1.25G 0
|
||||
06-Mar-14 Auction House Assets:Wyshona:Items "Plans: Wildthorn Mail" 1 "Plans: Wildthorn Mail" 1
|
||||
Assets:Tajer:Items "Plans: Wildthorn Mail" -1 0
|
||||
06-Mar-15 Auction House Assets:Tajer 45.00s 45.00s
|
||||
Assets:Tajer 2.59s 47.59s
|
||||
Assets:Bids -47.59s 0
|
||||
|
|
@ -680,11 +680,17 @@ D 1.00G
|
|||
Assets:Tajer:Items -119.58G 0
|
||||
Income:Brokering -54.58G -54.58G
|
||||
Equity:Capital Gains 54.58G 0
|
||||
06-Mar-16 Auction House Assets:Wyshona:Items 2.11G 2.11G
|
||||
Assets:Wyshona:Items 2.30G 4.40G
|
||||
Assets:Wyshona:Items 1.00G 5.40G
|
||||
Assets:Wyshona:Items 1.50G 6.90G
|
||||
Assets:Tajer:Items -6.90G 0
|
||||
06-Mar-16 Auction House Assets:Wyshona:Items "Plans: Mithril Shield Spike" 1 "Plans: Mithril Shield Spike" 1
|
||||
Assets:Wyshona:Items "Plans: Mithril Shield Spike" 1 "Plans: Mithril Shield Spike" 2
|
||||
Assets:Wyshona:Items "Recipe: Elixir of Giant Growth" 1 "Plans: Mithril Shield Spike" 2
|
||||
"Recipe: Elixir of Giant Growth" 1
|
||||
Assets:Wyshona:Items "Recipe: Elixir of Giant Growth" 1 "Plans: Mithril Shield Spike" 2
|
||||
"Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Plans: Mithril Shield Spike" -1 "Plans: Mithril Shield Spike" 1
|
||||
"Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Plans: Mithril Shield Spike" -1 "Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Recipe: Elixir of Giant Growth" -1 "Recipe: Elixir of Giant Growth" 1
|
||||
Assets:Tajer:Items "Recipe: Elixir of Giant Growth" -1 0
|
||||
06-Mar-16 Player Assets:Tajer 4.00G 4.00G
|
||||
Equity:Gold -4.00G 0
|
||||
06-Mar-16 Auction House Assets:Wyshona 13.41G 13.41G
|
||||
|
|
@ -718,8 +724,8 @@ D 1.00G
|
|||
Assets:Tajer -30.00G 0
|
||||
06-Mar-16 Auction House Assets:Gruulmorg:Items 30.00G 30.00G
|
||||
Assets:Gruulmorg -30.00G 0
|
||||
06-Mar-16 Transfer Assets:Tajer:Items 30.00G 30.00G
|
||||
Assets:Gruulmorg:Items -30.00G 0
|
||||
06-Mar-16 Transfer Assets:Tajer:Items "Ace of Warlords" 2 "Ace of Warlords" 2
|
||||
Assets:Gruulmorg:Items "Ace of Warlords" -2 0
|
||||
06-Mar-16 Post Expenses:Fees:Mail 60c 60c
|
||||
Assets:Gruulmorg -60c 0
|
||||
06-Mar-16 Post Expenses:Fees:Mail 1.20s 1.20s
|
||||
|
|
|
|||
|
|
@ -356,8 +356,8 @@ D 1.00G
|
|||
Assets:Tajer
|
||||
|
||||
2006/03/17 Player: raev
|
||||
Assets:Tajer:Items "Wildheart Belt" 1 {30G}
|
||||
Assets:Tajer:Items "Ace of Warlords" -2 {15G}
|
||||
Assets:Tajer:Items "Wildheart Belt" 1 @ 30G
|
||||
Assets:Tajer:Items "Ace of Warlords" -2 @ 15G
|
||||
|
||||
2006/03/17 Auction House
|
||||
Expenses:Fees:Auction 7482c
|
||||
|
|
@ -610,8 +610,8 @@ D 1.00G
|
|||
Assets:Tajer -120c 0
|
||||
06-Mar-14 Puldoost Assets:Tajer 80000c 80000c
|
||||
Expenses:Items -80000c 0
|
||||
06-Mar-14 Auction House Assets:Wyshona:Items 12500c 12500c
|
||||
Assets:Tajer:Items -12500c 0
|
||||
06-Mar-14 Auction House Assets:Wyshona:Items "Plans: Wildthorn Mail" 1 "Plans: Wildthorn Mail" 1
|
||||
Assets:Tajer:Items "Plans: Wildthorn Mail" -1 0
|
||||
06-Mar-15 Auction House Assets:Tajer 4500c 4500c
|
||||
Assets:Tajer 259c 4759c
|
||||
Assets:Bids -4759c 0
|
||||
|
|
@ -681,11 +681,17 @@ D 1.00G
|
|||
Assets:Tajer:Items -1195768c 0
|
||||
Income:Brokering -545768c -545768c
|
||||
Equity:Capital Gains 545768c 0
|
||||
06-Mar-16 Auction House Assets:Wyshona:Items 21050c 21050c
|
||||
Assets:Wyshona:Items 23000c 44050c
|
||||
Assets:Wyshona:Items 10000c 54050c
|
||||
Assets:Wyshona:Items 15000c 69050c
|
||||
Assets:Tajer:Items -69050c 0
|
||||
06-Mar-16 Auction House Assets:Wyshona:Items "Plans: Mithril Shield Spike" 1 "Plans: Mithril Shield Spike" 1
|
||||
Assets:Wyshona:Items "Plans: Mithril Shield Spike" 1 "Plans: Mithril Shield Spike" 2
|
||||
Assets:Wyshona:Items "Recipe: Elixir of Giant Growth" 1 "Plans: Mithril Shield Spike" 2
|
||||
"Recipe: Elixir of Giant Growth" 1
|
||||
Assets:Wyshona:Items "Recipe: Elixir of Giant Growth" 1 "Plans: Mithril Shield Spike" 2
|
||||
"Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Plans: Mithril Shield Spike" -1 "Plans: Mithril Shield Spike" 1
|
||||
"Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Plans: Mithril Shield Spike" -1 "Recipe: Elixir of Giant Growth" 2
|
||||
Assets:Tajer:Items "Recipe: Elixir of Giant Growth" -1 "Recipe: Elixir of Giant Growth" 1
|
||||
Assets:Tajer:Items "Recipe: Elixir of Giant Growth" -1 0
|
||||
06-Mar-16 Player Assets:Tajer 40000c 40000c
|
||||
Equity:Gold -40000c 0
|
||||
06-Mar-16 Auction House Assets:Wyshona 134100c 134100c
|
||||
|
|
@ -719,8 +725,8 @@ D 1.00G
|
|||
Assets:Tajer -300030c 0
|
||||
06-Mar-16 Auction House Assets:Gruulmorg:Items 300000c 300000c
|
||||
Assets:Gruulmorg -300000c 0
|
||||
06-Mar-16 Transfer Assets:Tajer:Items 300000c 300000c
|
||||
Assets:Gruulmorg:Items -300000c 0
|
||||
06-Mar-16 Transfer Assets:Tajer:Items "Ace of Warlords" 2 "Ace of Warlords" 2
|
||||
Assets:Gruulmorg:Items "Ace of Warlords" -2 0
|
||||
06-Mar-16 Post Expenses:Fees:Mail 60c 60c
|
||||
Assets:Gruulmorg -60c 0
|
||||
06-Mar-16 Post Expenses:Fees:Mail 120c 120c
|
||||
|
|
|
|||
0
test/baseline/opt-meta-width.test
Normal file
0
test/baseline/opt-meta-width.test
Normal file
0
test/baseline/opt-meta.test
Normal file
0
test/baseline/opt-meta.test
Normal file
0
test/baseline/opt-no-rounding.test
Normal file
0
test/baseline/opt-no-rounding.test
Normal file
0
test/baseline/opt-no-titles.test
Normal file
0
test/baseline/opt-no-titles.test
Normal file
0
test/baseline/opt-now.test
Normal file
0
test/baseline/opt-now.test
Normal file
|
|
@ -22,11 +22,11 @@ reg --account=payee
|
|||
>>>1
|
||||
08-Jan-01 January January:Expenses:Books $10.00 $10.00
|
||||
08-Jan-01 January January:Assets:Cash $-10.00 0
|
||||
08-Jan-31 End of January End of J:Expense:Books $10.00 $10.00
|
||||
08-Jan-31 End of January End of :Expenses:Books $10.00 $10.00
|
||||
08-Jan-31 End of January End of Jan:Assets:Cash $-10.00 0
|
||||
08-Feb-01 February Februar:Expenses:Books $20.00 $20.00
|
||||
08-Feb-01 February February:Assets:Cash $-20.00 0
|
||||
08-Feb-28 End of February End of F:Expense:Books $20.00 $20.00
|
||||
08-Feb-28 End of February End of :Expenses:Books $20.00 $20.00
|
||||
08-Feb-28 End of February End of Feb:Assets:Cash $-20.00 0
|
||||
08-Mar-01 March March:Expenses:Books $30.00 $30.00
|
||||
08-Mar-01 March March:Assets:Cash $-30.00 0
|
||||
|
|
|
|||
0
test/baseline/opt-pivot.test
Normal file
0
test/baseline/opt-pivot.test
Normal file
0
test/baseline/opt-prepend-format.test
Normal file
0
test/baseline/opt-prepend-format.test
Normal file
0
test/baseline/opt-prepend-width.test
Normal file
0
test/baseline/opt-prepend-width.test
Normal file
12
test/regress/15230B79.test
Normal file
12
test/regress/15230B79.test
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
reg
|
||||
<<<
|
||||
2010-04-02 Opening balance
|
||||
Assets:A 14.75 EUR
|
||||
Assets:B 2.84 GBP
|
||||
Equity:Opening balance
|
||||
>>>
|
||||
10-Apr-02 Opening balance Assets:A 14.75 EUR 14.75 EUR
|
||||
Assets:B 2.84 GBP 14.75 EUR
|
||||
2.84 GBP
|
||||
Equity:Opening balance -14.75 EUR 2.84 GBP
|
||||
Equity:Opening balance -2.84 GBP 0
|
||||
17
test/regress/56BBE69B.test
Normal file
17
test/regress/56BBE69B.test
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
bal
|
||||
<<<
|
||||
D 1000.00 USD
|
||||
|
||||
2010-01-07 * Put money in
|
||||
Assets:A -20.00 EUR
|
||||
Equity:Opening balances
|
||||
|
||||
2010-01-11 * Purchase
|
||||
Assets:A 20.00 EUR @@ 25.00 USD
|
||||
Expenses:B
|
||||
>>>
|
||||
20.00 EUR Equity:Opening balances
|
||||
-25.00 USD Expenses:B
|
||||
--------------------
|
||||
20.00 EUR
|
||||
-25.00 USD
|
||||
24
test/regress/620F0674.test
Normal file
24
test/regress/620F0674.test
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
reg bank --forecast "d<=[next year]" -d "d>=[this month] & d<=[next year]" --sort d --now=2010/06/20
|
||||
<<<
|
||||
~ Monthly since 2010/01/01
|
||||
Expenses:Bills:Rent $873.00
|
||||
Expenses:Household $200.00
|
||||
Income:Salary -$2491.60
|
||||
Assets:Bank:Checking
|
||||
|
||||
~ biweekly from 2010/02/23
|
||||
Expenses:Bills:Housecleaning $85.00
|
||||
Assets:Bank:Checking
|
||||
|
||||
2010/06/22 c897683b
|
||||
ad738623:d317da42:0e30a690 A2079.00
|
||||
208b135f:c84cc2a7:a336b63a A199.00
|
||||
45435ee9:2d8ee712:ee7e46b1:0f0e7e54:f5dbec59
|
||||
>>>
|
||||
10-Jul-01 Forecast transaction Assets:Bank:Checking $1418.60 $1418.60
|
||||
10-Aug-01 Forecast transaction Assets:Bank:Checking $1418.60 $2837.20
|
||||
10-Sep-01 Forecast transaction Assets:Bank:Checking $1418.60 $4255.80
|
||||
10-Oct-01 Forecast transaction Assets:Bank:Checking $1418.60 $5674.40
|
||||
10-Nov-01 Forecast transaction Assets:Bank:Checking $1418.60 $7093.00
|
||||
10-Dec-01 Forecast transaction Assets:Bank:Checking $1418.60 $8511.60
|
||||
11-Jan-01 Forecast transaction Assets:Bank:Checking $1418.60 $9930.20
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
bal --flat food:out
|
||||
bal --flat food:out --now=2009/12/31
|
||||
<<<
|
||||
~ Monthly
|
||||
Expenses:Auto:Fuel $120.00
|
||||
|
|
@ -13,8 +13,8 @@ bal --flat food:out
|
|||
$50.00 Expenses:Food:Out
|
||||
>>>2
|
||||
=== 0
|
||||
bal --flat --budget food:out
|
||||
bal --flat --budget food:out --now=2009/12/31
|
||||
>>>1
|
||||
$-50.00 Expenses:Food:Out
|
||||
$-150.00 Expenses:Food:Out
|
||||
>>>2
|
||||
=== 0
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ reg -B
|
|||
Expenses:Bank:Fees 2.73
|
||||
Liabilities:Mastercard
|
||||
>>>1
|
||||
09-Jun-03 Westjet Expen:Transportati:Air 676.017377 676.017377
|
||||
09-Jun-03 Westjet Expe:Transportatio:Air 676.017377 676.017377
|
||||
Expenses:Bank:Fees 2.73 678.747377
|
||||
Liabilities:Mastercard -678.747377 0
|
||||
>>>2
|
||||
|
|
|
|||
33
test/regress/C0212EAC.test
Normal file
33
test/regress/C0212EAC.test
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
reg
|
||||
<<<
|
||||
2007-01-01 Opening balances
|
||||
Assets:Cash 10.00 EUR
|
||||
Equity:Opening balances
|
||||
|
||||
2008-01-01 Buy 5.00 GBP
|
||||
Assets:Cash 5.00 GBP @ 1.4 EUR
|
||||
Assets:Checking
|
||||
|
||||
2009-01-01 Sell 5.00 GBP for 7.50 EUR that I bought for 7.00 EUR
|
||||
Assets:Cash -5.00 GBP {=1.4 EUR} @ 1.5 EUR
|
||||
Assets:Checking 7.50 EUR
|
||||
Income:Gain
|
||||
|
||||
P 2009-02-01 00:00:00 GBP 1.5 EUR
|
||||
>>>
|
||||
07-Jan-01 Opening balances Assets:Cash 10.00 EUR 10.00 EUR
|
||||
Equit:Opening balances -10.00 EUR 0
|
||||
08-Jan-01 Buy 5.00 GBP Assets:Cash 5.00 GBP 5.00 GBP
|
||||
Assets:Checking -7.00 EUR -7.00 EUR
|
||||
5.00 GBP
|
||||
09-Jan-01 Sell 5.00 GBP for 7.. Assets:Cash -5.00 GBP {=1.40 EUR} -7.00 EUR
|
||||
5.00 GBP
|
||||
-5.00 GBP {=1.40 EUR}
|
||||
Assets:Checking 7.50 EUR 0.50 EUR
|
||||
5.00 GBP
|
||||
-5.00 GBP {=1.40 EUR}
|
||||
Income:Gain -0.50 EUR 5.00 GBP
|
||||
-5.00 GBP {=1.40 EUR}
|
||||
Equity:Capital Gains 0.50 EUR 0.50 EUR
|
||||
5.00 GBP
|
||||
-5.00 GBP {=1.40 EUR}
|
||||
72
test/regress/D2829FC4.test
Normal file
72
test/regress/D2829FC4.test
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
reg --forecast 'date<[2011]' --now=2010/06/20
|
||||
<<<
|
||||
~ Monthly since 2010/01/01
|
||||
Expenses:Bills:Rent $873.00
|
||||
Expenses:Household $200.00
|
||||
Income:Salary -$2491.60
|
||||
Assets:Bank:Checking
|
||||
|
||||
~ biweekly from 2010/02/23
|
||||
Expenses:Bills:Housecleaning $85.00
|
||||
Assets:Bank:Checking
|
||||
|
||||
2010/06/22 c897683b
|
||||
ad738623:d317da42:0e30a690 A2079.00
|
||||
208b135f:c84cc2a7:a336b63a A199.00
|
||||
45435ee9:2d8ee712:ee7e46b1:0f0e7e54:f5dbec59
|
||||
>>>
|
||||
10-Jun-22 c897683b ad738:d317da4:0e30a690 A2079.00 A2079.00
|
||||
208b1:c84cc2a:a336b63a A199.00 A2278.00
|
||||
45:2d:ee:0f0e:f5dbec59 A-2278.00 0
|
||||
10-Jul-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Jul-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Jul-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Jul-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Jun-27 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jun-27 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Jul-11 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jul-11 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Aug-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Aug-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Aug-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Aug-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Jul-25 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Jul-25 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Aug-08 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Aug-08 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Sep-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Sep-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Sep-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Sep-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Aug-22 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Aug-22 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Sep-05 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Sep-05 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Oct-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Oct-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Oct-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Sep-19 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Sep-19 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-03 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-03 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Nov-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Nov-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Nov-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Nov-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Oct-17 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-17 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Oct-31 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Oct-31 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Nov-14 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Nov-14 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-01 Forecast transaction Expenses:Bills:Rent $873.00 $873.00
|
||||
10-Dec-01 Forecast transaction Expenses:Household $200.00 $1073.00
|
||||
10-Dec-01 Forecast transaction Income:Salary $-2491.60 $-1418.60
|
||||
10-Dec-01 Forecast transaction Assets:Bank:Checking $1418.60 0
|
||||
10-Nov-28 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Nov-28 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-12 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Dec-12 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
10-Dec-26 Forecast transaction Exp:Bill:Housecleaning $85.00 $85.00
|
||||
10-Dec-26 Forecast transaction Assets:Bank:Checking $-85.00 0
|
||||
|
|
@ -11,7 +11,7 @@ reg
|
|||
Expenses:Financial:Fees
|
||||
>>>1
|
||||
07-Dec-31 Cost basis for: RED.. As:In:RBC-:Account-RSP 4.00 RHT 4.00 RHT
|
||||
Equ:Opening-Balan:Cost -689.87 CAD -689.87 CAD
|
||||
Eq:Opening-Balanc:Cost -689.87 CAD -689.87 CAD
|
||||
4.00 RHT
|
||||
08-Jan-03 Sell -- RHT -- RED .. As:In:RBC-:Account-RSP -4.00 RHT -689.87 CAD
|
||||
Ex:Financi:Commissions 9.95 USD -689.87 CAD
|
||||
|
|
|
|||
45
test/run
Executable file
45
test/run
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/bin/bash
|
||||
|
||||
LEDGER=ledger
|
||||
ARGS="--args-only --no-color --columns=80"
|
||||
|
||||
output_only=false
|
||||
update_test=false
|
||||
if [[ "$1" == "-v" ]]; then
|
||||
output_only=true
|
||||
shift 1
|
||||
elif [[ "$1" == "-u" ]]; then
|
||||
update_test=true
|
||||
shift 1
|
||||
fi
|
||||
|
||||
COMMAND=$(perl -ne 'print unless /^<<</ .. eof();' $1)
|
||||
|
||||
if [[ $output_only == false && $update_test == false ]]; then
|
||||
perl -ne 'print unless 1 .. /^>>>/ or /^(===|>>>2)/ .. eof();' $1 > /tmp/expected.$$
|
||||
fi
|
||||
|
||||
perl -ne 'print unless 1 .. /^<<</ or /^>>>/ .. eof();' $1 \
|
||||
| eval "$LEDGER -f - -o /tmp/received.$$ $ARGS $COMMAND"
|
||||
|
||||
if [[ $update_test == true ]]; then
|
||||
if [[ -f /tmp/received.$$ ]]; then
|
||||
perl -ne 'print if 1 .. /^>>>/;' $1 > /tmp/command.$$
|
||||
perl -ne 'print if /^(===|>>>2)/ .. eof();' $1 > /tmp/epilog.$$
|
||||
cat /tmp/command.$$ /tmp/received.$$ /tmp/epilog.$$ > replace.$$
|
||||
mv replace.$$ $1
|
||||
/bin/rm -f /tmp/command.$$ /tmp/received.$$ /tmp/epilog.$$
|
||||
echo Test updated.
|
||||
fi
|
||||
|
||||
elif [[ $output_only == false ]]; then
|
||||
if [[ -f /tmp/expected.$$ && -f /tmp/received.$$ ]]; then
|
||||
diff -w -U3 /tmp/expected.$$ /tmp/received.$$ && echo Test passed.
|
||||
fi
|
||||
else
|
||||
if [[ -f /tmp/received.$$ ]]; then
|
||||
cat /tmp/received.$$
|
||||
fi
|
||||
fi
|
||||
|
||||
/bin/rm -f /tmp/expected.$$ /tmp/received.$$
|
||||
|
|
@ -63,7 +63,7 @@ void ValueExprTestCase::testPredicateTokenizer2()
|
|||
args.push_back(string_value("foo and bar"));
|
||||
|
||||
#ifndef NOT_FOR_PYTHON
|
||||
query_t::lexer_t tokens(args.begin(), args.end());
|
||||
query_t::lexer_t tokens(args.begin(), args.end(), false);
|
||||
|
||||
assertEqual(query_t::lexer_t::token_t::TERM, tokens.next_token().kind);
|
||||
assertEqual(query_t::lexer_t::token_t::TOK_AND, tokens.next_token().kind);
|
||||
|
|
@ -119,7 +119,7 @@ void ValueExprTestCase::testPredicateTokenizer5()
|
|||
args.push_back(string_value("bar)"));
|
||||
|
||||
#ifndef NOT_FOR_PYTHON
|
||||
query_t::lexer_t tokens(args.begin(), args.end());
|
||||
query_t::lexer_t tokens(args.begin(), args.end(), false);
|
||||
|
||||
assertEqual(query_t::lexer_t::token_t::LPAREN, tokens.next_token().kind);
|
||||
assertEqual(query_t::lexer_t::token_t::TERM, tokens.next_token().kind);
|
||||
|
|
@ -168,7 +168,7 @@ void ValueExprTestCase::testPredicateTokenizer8()
|
|||
args.push_back(string_value("expr 'foo and bar'"));
|
||||
|
||||
#ifndef NOT_FOR_PYTHON
|
||||
query_t::lexer_t tokens(args.begin(), args.end());
|
||||
query_t::lexer_t tokens(args.begin(), args.end(), false);
|
||||
|
||||
assertEqual(query_t::lexer_t::token_t::TOK_EXPR, tokens.next_token().kind);
|
||||
assertEqual(query_t::lexer_t::token_t::TERM, tokens.next_token().kind);
|
||||
|
|
@ -318,7 +318,7 @@ void ValueExprTestCase::testPredicateTokenizer16()
|
|||
args.push_back(string_value("and bar|baz"));
|
||||
|
||||
#ifndef NOT_FOR_PYTHON
|
||||
query_t::lexer_t tokens(args.begin(), args.end());
|
||||
query_t::lexer_t tokens(args.begin(), args.end(), false);
|
||||
|
||||
assertEqual(query_t::lexer_t::token_t::TERM, tokens.next_token().kind);
|
||||
assertEqual(query_t::lexer_t::token_t::TOK_AND, tokens.next_token().kind);
|
||||
|
|
|
|||
|
|
@ -247,7 +247,8 @@ endif
|
|||
|
||||
######################################################################
|
||||
|
||||
TESTS = RegressTests BaselineTests ManualTests ConfirmTests GenerateTests
|
||||
TESTS = RegressTests BaselineTests ManualTests ConfirmTests \
|
||||
GenerateTests
|
||||
|
||||
if HAVE_CPPUNIT
|
||||
TESTS += \
|
||||
|
|
@ -258,6 +259,10 @@ TESTS += \
|
|||
ReportTests
|
||||
endif
|
||||
|
||||
if DEBUG
|
||||
TESTS += CheckTests
|
||||
endif
|
||||
|
||||
if HAVE_BOOST_PYTHON
|
||||
TESTS += PyUnitTests
|
||||
endif
|
||||
|
|
@ -409,6 +414,12 @@ GenerateTests: $(srcdir)/test/GenerateTests.py
|
|||
echo "$(PYTHON) $(srcdir)/test/GenerateTests.py -j$(JOBS) $(top_builddir)/ledger$(EXEEXT) $(srcdir) 1 ${1:-20} \"\$$@\"" > $@
|
||||
chmod 755 $@
|
||||
|
||||
CheckTests_SOURCES = test/CheckTests.py
|
||||
|
||||
CheckTests:
|
||||
echo "$(PYTHON) $(srcdir)/test/CheckTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) \"\$$@\"" > $@
|
||||
chmod 755 $@
|
||||
|
||||
FULLCHECK=$(srcdir)/test/fullcheck.sh
|
||||
|
||||
if HAVE_CPPUNIT
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ fi
|
|||
|
||||
rm -fr ~/Products/ledger-proof
|
||||
|
||||
time ./acprep --enable-cache --enable-doxygen \
|
||||
--universal -j16 --warn proof 2>&1 | \
|
||||
time ./acprep --enable-doxygen --universal -j16 --warn proof 2>&1 | \
|
||||
tee ~/Desktop/proof.log
|
||||
|
||||
if egrep -q '(ERROR|CRITICAL)' ~/Desktop/proof.log; then
|
||||
|
|
@ -26,9 +25,13 @@ if egrep -q '(ERROR|CRITICAL)' ~/Desktop/proof.log; then
|
|||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Ledger proof build succeeded"
|
||||
echo $VERSION > ~/Products/last-proofed
|
||||
mv ~/Desktop/proof.log /tmp
|
||||
|
||||
cd ~/Products/ledger-proof/debug; make docs
|
||||
cd ~/Products/ledger-proof/gcov; make report
|
||||
|
||||
echo "Ledger proof build succeeded"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
31
tools/push
31
tools/push
|
|
@ -2,17 +2,38 @@
|
|||
|
||||
set -e
|
||||
|
||||
ACPREP="./acprep --universal -j16 --warn opt"
|
||||
|
||||
(cd plan/data; git push)
|
||||
(cd plan; git commit -a -m "Update TODO files" && git push)
|
||||
|
||||
git checkout next
|
||||
|
||||
perl -i -pe "s/([-abgrc][0-9]*)?\\]\\)/-$(date +%Y%m%d)])/;" version.m4
|
||||
git add version.m4
|
||||
echo git commit -m "v$(cat version.m4 | sed 's/.*\[//' | sed 's/\].*//')"
|
||||
|
||||
git checkout master
|
||||
git merge --no-ff next
|
||||
git checkout next
|
||||
git rebase master
|
||||
git push
|
||||
|
||||
git checkout master
|
||||
./acprep --enable-cache --universal -j16 --warn opt upload
|
||||
cp -p ~/Products/ledger/opt/ledger ~/bin
|
||||
./acprep --enable-cache --universal -j16 --warn opt make speedtest 2>&1 \
|
||||
| tee build/last-speed.txt
|
||||
mv *.dmg* build
|
||||
$ACPREP upload
|
||||
$ACPREP make dist
|
||||
|
||||
scp ~/Products/ledger/opt/ledger-*.tar.* jw:/srv/ftp/pub/ledger
|
||||
openssl md5 *.dmg* ~/Products/ledger/opt/ledger-*.tar.* > build/CHECKSUMS.txt
|
||||
openssl sha1 *.dmg* ~/Products/ledger/opt/ledger-*.tar.* >> build/CHECKSUMS.txt
|
||||
openssl rmd160 *.dmg* ~/Products/ledger/opt/ledger-*.tar.* >> build/CHECKSUMS.txt
|
||||
perl -i -pe 's/\/.*\///;' build/CHECKSUMS.txt
|
||||
scp build/CHECKSUMS.txt jw:/srv/ftp/pub/ledger
|
||||
|
||||
rsync -az --delete ~/Products/ledger-proof/gcov/doc/report/ jw:/srv/ftp/pub/ledger/lcov/
|
||||
|
||||
$ACPREP make speedtest 2>&1 | tee build/last-speed.txt
|
||||
|
||||
mv *.dmg* ~/Products/ledger/opt/ledger-*.tar.* build
|
||||
|
||||
git checkout next
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd ~/src/ledger
|
||||
/bin/rm -fr ~/Products/ledger/opt
|
||||
./acprep --no-python -j16 opt make check
|
||||
|
||||
./acprep -j16 opt update || exit 0
|
||||
|
||||
COMMIT=$(git describe --long --all)
|
||||
|
||||
SPEEDS=$(./acprep --no-python -j16 opt make speedtest 2>&1 \
|
||||
SPEEDS=$(./acprep -j16 opt make speedtest 2>&1 \
|
||||
| grep "Finished executing command" \
|
||||
| awk '{print $1}' \
|
||||
| xargs)
|
||||
|
||||
echo $COMMIT,$(echo $SPEEDS | sed 's/ /,/g') >> speed.log
|
||||
echo $COMMIT,$(echo $SPEEDS | sed 's/ /,/g') >> ~/src/ledger/speed.log
|
||||
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
m4_define([VERSION_NUMBER], [3.0.0-20100615])
|
||||
m4_define([VERSION_NUMBER], [3.0.0-20100623])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue