summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore72
-rw-r--r--README-1ST25
-rw-r--r--README.textile13
-rwxr-xr-xacprep330
-rw-r--r--contrib/vim/compiler/ledger.vim13
-rw-r--r--contrib/vim/ftplugin/ledger.vim374
-rw-r--r--contrib/vim/syntax/ledger.vim58
-rw-r--r--dist/Portfile89
-rw-r--r--doc/NEWS45
-rw-r--r--doc/README4
-rw-r--r--doc/grammar.y22
-rw-r--r--doc/ledger.149
-rw-r--r--doc/ledger.texi45
-rw-r--r--doc/ledger3.texi322
-rw-r--r--lib/Makefile118
m---------lib/utfcpp0
-rw-r--r--lisp/ldg-complete.el190
-rw-r--r--lisp/ldg-exec.el16
-rw-r--r--lisp/ldg-mode.el62
-rw-r--r--lisp/ldg-post.el98
-rw-r--r--lisp/ldg-reconcile.el76
-rw-r--r--lisp/ldg-regex.el250
-rw-r--r--lisp/ldg-register.el54
-rw-r--r--lisp/ldg-report.el198
-rw-r--r--lisp/ldg-state.el240
-rw-r--r--lisp/ldg-texi.el128
-rw-r--r--lisp/ldg-xact.el12
-rw-r--r--lisp/ledger.el934
-rw-r--r--lisp/timeclock.el950
-rwxr-xr-xpython/demo.py4
-rw-r--r--src/account.cc149
-rw-r--r--src/account.h98
-rw-r--r--src/accum.cc26
-rw-r--r--src/accum.h6
-rw-r--r--src/amount.cc416
-rw-r--r--src/amount.h38
-rw-r--r--src/annotate.cc120
-rw-r--r--src/annotate.h30
-rw-r--r--src/archive.cc48
-rw-r--r--src/archive.h2
-rw-r--r--src/balance.cc51
-rw-r--r--src/balance.h68
-rw-r--r--src/chain.cc140
-rw-r--r--src/chain.h10
-rw-r--r--src/commodity.cc408
-rw-r--r--src/commodity.h124
-rw-r--r--src/compare.cc14
-rw-r--r--src/compare.h6
-rw-r--r--src/convert.cc84
-rw-r--r--src/csv.cc66
-rw-r--r--src/draft.cc469
-rw-r--r--src/emacs.cc6
-rw-r--r--src/error.cc25
-rw-r--r--src/error.h54
-rw-r--r--src/expr.cc106
-rw-r--r--src/expr.h34
-rw-r--r--src/exprbase.h26
-rw-r--r--src/filters.cc773
-rw-r--r--src/filters.h270
-rw-r--r--src/flags.h4
-rw-r--r--src/format.cc416
-rw-r--r--src/format.h45
-rw-r--r--src/generate.cc88
-rw-r--r--src/generate.h36
-rw-r--r--src/global.cc78
-rw-r--r--src/global.h21
-rw-r--r--src/interactive.cc198
-rw-r--r--src/interactive.h164
-rw-r--r--src/item.cc185
-rw-r--r--src/item.h72
-rw-r--r--src/iterators.cc94
-rw-r--r--src/iterators.h8
-rw-r--r--src/journal.cc18
-rw-r--r--src/journal.h44
-rw-r--r--src/lookup.cc184
-rw-r--r--src/lookup.h4
-rw-r--r--src/main.cc88
-rw-r--r--src/mask.cc10
-rw-r--r--src/mask.h10
-rw-r--r--src/op.cc360
-rw-r--r--src/op.h56
-rw-r--r--src/option.cc110
-rw-r--r--src/option.h112
-rw-r--r--src/org.cc200
-rw-r--r--src/org.h94
-rw-r--r--src/output.cc81
-rw-r--r--src/output.h14
-rw-r--r--src/parser.cc401
-rw-r--r--src/parser.h36
-rw-r--r--src/pool.cc180
-rw-r--r--src/pool.h52
-rw-r--r--src/post.cc271
-rw-r--r--src/post.h105
-rw-r--r--src/precmd.cc70
-rw-r--r--src/predicate.cc6
-rw-r--r--src/predicate.h28
-rw-r--r--src/print.cc185
-rw-r--r--src/print.h11
-rw-r--r--src/pstream.h30
-rw-r--r--src/py_account.cc64
-rw-r--r--src/py_amount.cc89
-rw-r--r--src/py_balance.cc36
-rw-r--r--src/py_commodity.cc192
-rw-r--r--src/py_format.cc6
-rw-r--r--src/py_item.cc62
-rw-r--r--src/py_journal.cc86
-rw-r--r--src/py_post.cc84
-rw-r--r--src/py_times.cc26
-rw-r--r--src/py_utils.cc42
-rw-r--r--src/py_value.cc70
-rw-r--r--src/py_xact.cc36
-rw-r--r--src/pyfstream.h12
-rw-r--r--src/pyinterp.cc110
-rw-r--r--src/pyinterp.h11
-rw-r--r--src/pyutils.h22
-rw-r--r--src/query.cc317
-rw-r--r--src/query.h273
-rw-r--r--src/quotes.cc34
-rw-r--r--src/quotes.h2
-rw-r--r--src/report.cc825
-rw-r--r--src/report.h386
-rw-r--r--src/scope.cc27
-rw-r--r--src/scope.h432
-rw-r--r--src/session.cc137
-rw-r--r--src/session.h23
-rw-r--r--src/stats.cc14
-rw-r--r--src/stream.cc18
-rw-r--r--src/stream.h2
-rw-r--r--src/system.hh.in6
-rw-r--r--src/temps.cc10
-rw-r--r--src/temps.h4
-rw-r--r--src/textual.cc796
-rw-r--r--src/timelog.cc41
-rw-r--r--src/timelog.h18
-rw-r--r--src/times.cc1211
-rw-r--r--src/times.h160
-rw-r--r--src/token.cc157
-rw-r--r--src/token.h95
-rw-r--r--src/unistring.h24
-rw-r--r--src/utils.cc100
-rw-r--r--src/utils.h170
-rw-r--r--src/value.cc580
-rw-r--r--src/value.h233
-rw-r--r--src/xact.cc558
-rw-r--r--src/xact.h74
-rw-r--r--src/xml.cc22
-rw-r--r--test/CheckComments.py121
-rwxr-xr-xtest/CheckTests.py87
-rwxr-xr-xtest/GenerateTests.py45
-rwxr-xr-xtest/LedgerHarness.py21
-rwxr-xr-xtest/RegressTests.py74
-rw-r--r--test/UnitTests.cc4
-rw-r--r--test/UnitTests.h14
-rw-r--r--test/baseline/feat-check.test18
-rw-r--r--test/baseline/feat-fixated-prices.test12
-rw-r--r--test/baseline/opt-abbrev-len.test4
-rw-r--r--test/baseline/opt-account.test4
-rw-r--r--test/baseline/opt-actual-dates.test0
-rw-r--r--test/baseline/opt-add-budget.test2
-rw-r--r--test/baseline/opt-amount-width.test4
-rw-r--r--test/baseline/opt-amount.test4
-rw-r--r--test/baseline/opt-anon.test11
-rw-r--r--test/baseline/opt-bold-if.test0
-rw-r--r--test/baseline/opt-budget-format.test0
-rw-r--r--test/baseline/opt-budget.test2
-rw-r--r--test/baseline/opt-budget_only.test22
-rw-r--r--test/baseline/opt-budget_range.test111
-rw-r--r--test/baseline/opt-cleared-format.test0
-rw-r--r--test/baseline/opt-collapse-if-zero.test4
-rw-r--r--test/baseline/opt-columns.test4
-rw-r--r--test/baseline/opt-commodity-as-account.test4
-rw-r--r--test/baseline/opt-commodity-as-payee.test4
-rw-r--r--test/baseline/opt-count.test0
-rw-r--r--test/baseline/opt-date-format.test4
-rw-r--r--test/baseline/opt-date-width.test4
-rw-r--r--test/baseline/opt-date.test0
-rw-r--r--test/baseline/opt-datetime-format.test0
-rw-r--r--test/baseline/opt-decimal-comma.test0
-rw-r--r--test/baseline/opt-forecast-while.test74
-rw-r--r--test/baseline/opt-forecast-years.test0
-rw-r--r--test/baseline/opt-forecast_only.test64
-rw-r--r--test/baseline/opt-gain.test12
-rw-r--r--test/baseline/opt-generated.test0
-rw-r--r--test/baseline/opt-group-by.test0
-rw-r--r--test/baseline/opt-group-title-format.test0
-rw-r--r--test/baseline/opt-inject.test0
-rw-r--r--test/baseline/opt-input-date-format.test4
-rw-r--r--test/baseline/opt-invert.test4
-rw-r--r--test/baseline/opt-lot-dates.test1703
-rw-r--r--test/baseline/opt-lot-prices.test2297
-rw-r--r--test/baseline/opt-lots-actual.test22
-rw-r--r--test/baseline/opt-lots.test2549
-rw-r--r--test/baseline/opt-lots_basis.test28
-rw-r--r--test/baseline/opt-lots_basis_base.test28
-rw-r--r--test/baseline/opt-market.test14
-rw-r--r--test/baseline/opt-meta-width.test14
-rw-r--r--test/baseline/opt-meta.test14
-rw-r--r--test/baseline/opt-no-rounding.test0
-rw-r--r--test/baseline/opt-no-titles.test0
-rw-r--r--test/baseline/opt-now.test4
-rw-r--r--test/baseline/opt-output.test4
-rw-r--r--test/baseline/opt-pager.test4
-rw-r--r--test/baseline/opt-payee-as-account.test10
-rw-r--r--test/baseline/opt-payee-width.test4
-rw-r--r--test/baseline/opt-payee.test4
-rw-r--r--test/baseline/opt-pivot.test0
-rw-r--r--test/baseline/opt-prepend-format.test17
-rw-r--r--test/baseline/opt-prepend-width.test17
-rw-r--r--test/baseline/opt-quantity.test4
-rw-r--r--test/baseline/opt-revalued.test14
-rw-r--r--test/baseline/opt-sort-all.test28
-rw-r--r--test/baseline/opt-sort-xacts.test76
-rw-r--r--test/baseline/opt-sort.test166
-rw-r--r--test/baseline/opt-subtotal.test4
-rw-r--r--test/baseline/opt-total-width.test4
-rw-r--r--test/baseline/opt-total.test4
-rw-r--r--test/regress/04C5E1CA.test4
-rw-r--r--test/regress/13965214.test16
-rw-r--r--test/regress/15230B79.test12
-rw-r--r--test/regress/1D275740.test4
-rw-r--r--test/regress/25A099C9.test8
-rw-r--r--test/regress/3AB70168.test6
-rw-r--r--test/regress/56BBE69B.test17
-rw-r--r--test/regress/5FBF2ED8.test18
-rw-r--r--test/regress/620F0674.test24
-rw-r--r--test/regress/727B2DF8.test6
-rw-r--r--test/regress/7C44010B.test30
-rw-r--r--test/regress/8254755E.test6
-rw-r--r--test/regress/86D2BDC4.test4
-rw-r--r--test/regress/9EB10714.test43
-rw-r--r--test/regress/A28CF697.test9
-rw-r--r--test/regress/C0212EAC.test33
-rw-r--r--test/regress/D2829FC4.test72
-rw-r--r--test/regress/D943AE0F.test2
-rw-r--r--test/regress/E4C9A8EA.test12
-rw-r--r--test/regress/E627C594.test2
-rw-r--r--test/regress/F559EC12.test2
-rwxr-xr-xtest/run45
-rw-r--r--test/unit/t_amount.cc42
-rw-r--r--test/unit/t_commodity.cc10
-rw-r--r--test/unit/t_expr.cc8
-rw-r--r--test/unit/t_times.cc4
-rw-r--r--tools/Makefile.am75
-rw-r--r--tools/configure.ac81
-rw-r--r--tools/excludes1
-rwxr-xr-xtools/pre-commit6
-rwxr-xr-xtools/proof16
-rwxr-xr-xtools/push28
-rwxr-xr-xtools/speed-test.sh16
-rw-r--r--version.m41
250 files changed, 16018 insertions, 12744 deletions
diff --git a/.gitignore b/.gitignore
index 8eb4ebbb..5451d1e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,58 +1,38 @@
-.timestamp
+*.[oa]
*.backup
*.elc
+*.l[oa]
*.pyc
*~
+.timestamp
+/*.tar.bz2
+/*.tar.gz
+/.deps/
+/.libs/
/ABOUT-NLS
+/BaselineTests
+/Doxyfile.gen
+/Makefile
/Makefile.am
/Makefile.in
+/PyUnitTests
+/RegressionTests
/TAGS
/acconf.h.in
/aclocal.m4
/autogen.sh
/autom4te.cache/
/config.guess
+/config.h
/config.h.in
+/config.log
/config.rpath
+/config.status
/config.sub
/configure
/configure.ac
-/depcomp
-/elisp-comp
-/install-sh
-/intl/
-/ledger
-/ltmain.sh
-/m4/
-/make.sh
-/missing
-/po/
-/py-compile
-/src/system.hh.gch
-/texinfo.tex
-/version.m4
-
-*.[oa]
-*.l[oa]
-/*.tar.bz2
-/*.tar.gz
-/.deps/
-/.libs/
-/BaselineTests
-/Doxyfile.gen
-/Makefile
-/PyUnitTests
-/RegressionTests
-/config.h
-/config.log
-/config.status
/data_tests
-/doc/.dirstamp
-/doc/html/
-/doc/latex/
-/doc/ledger.info
-/doc/refman.pdf
-/doc/report/
+/depcomp
/doc/*.aux
/doc/*.cp
/doc/*.fn
@@ -63,15 +43,33 @@
/doc/*.toc
/doc/*.tp
/doc/*.vr
+/doc/.dirstamp
+/doc/html/
+/doc/latex/
+/doc/ledger.info
+/doc/refman.pdf
+/doc/report/
+/elisp-comp
/expr_tests
+/install-sh
+/intl/
+/ledger
/libtool
+/ltmain.sh
+/m4/
+/make.sh
/math_tests
+/missing
+/mkinstalldirs
+/po/
+/py-compile
/report_tests
/shave
/shave-libtool
+/src/system.hh.gch
/stamp-h1
/test/python/
+/texinfo.tex
/tmpcvs*/
/tmpwrk*/
/util_tests
-/mkinstalldirs
diff --git a/README-1ST b/README-1ST
index a56e4782..88174308 100644
--- a/README-1ST
+++ b/README-1ST
@@ -1,6 +1,4 @@
-===============================================================================
-
README FIRST!!!
To build this code after doing a Git clone, run:
@@ -11,18 +9,9 @@ If you try to configure and build on your own, you are almost certainly going
to run into problems. In future, you can run this command again and again,
and it will keep you updated to the very latest version.
-===============================================================================
-
- NOTE FOR MAC OS X USERS
-
-To build and install Ledger on the Mac requires several dependencies. If you
-are a MacPorts user, you can install these dependencies very simply using:
-
- $ ./acprep dependencies
-
-Once this is done, I recommend building both debug and optimized versions of
-Ledger, in a subdirectory of your source tree named 'build' (which acprep will
-manage for you, you simply need to make it):
+I further recommend building both debug and optimized versions of Ledger, in a
+subdirectory of your source tree named 'build' (which acprep will manage for
+you, you simply need to create it):
$ mkdir build
$ ./acprep opt make
@@ -33,7 +22,13 @@ available for testing and more useful bug reports.
===============================================================================
- IF YOU HAVE CONFIGURE OR BUILD PROBLEMS
+ IF YOU HAVE CONFIGURE OR BUILD PROBLEMS
+
+To build and install Ledger requires several dependencies on various
+platforms. You can install these dependencies very simply for most of them
+using:
+
+ $ ./acprep dependencies
The first order of business if acprep update doesn't work is to find out where
things went wrong. So follow these steps to produce a bug report I can track
diff --git a/README.textile b/README.textile
index 2a730746..e96a46b0 100644
--- a/README.textile
+++ b/README.textile
@@ -33,9 +33,10 @@ The *BETA* is what I prefer people use, since I still have a chance to fix
major bugs that you find. Just e-mail me, or post to the mailing list,
they'll become a part of my work list.
-|*CURRENT*|@git checkout master@|
-|*BETA*|@git checkout -b maint origin/maint@|
-|*RELEASE*|@git checkout v2.6.1@|
+|*RELEASE*|@git checkout v2.6.3@|
+|*CURRENT*|@git checkout maint@|
+|*BETA*|@git checkout -b master origin/master@|
+|*ALPHA*|@git checkout -b next origin/next@|
There are also several topic branches which contain experimental features,
though none of these are guaranteed to compile. Best to chat with me on
@@ -105,10 +106,10 @@ If you're going to be build on Ubuntu, @sudo apt-get install ...@ the
following packages (current as of Ubuntu Hardy):
<pre>
-sudo apt-get install build-essential libtool autoconf automake \
+sudo apt-get install build-essential libtool autoconf automake \
zlib1g-dev libbz2-dev python-dev bjam cvs gettext libgmp3-dev \
- libmpfr-dev libboost1.35-dev libboost-regex1.35-dev \
- libboost-date-time1.35-dev libboost-filesystem1.35-dev \
+ libmpfr-dev libboost1.35-dev libboost-regex1.35-dev \
+ libboost-date-time1.35-dev libboost-filesystem1.35-dev \
libboost-python1.35-dev texinfo lcov sloccount
</pre>
diff --git a/acprep b/acprep
index f48649eb..381ee032 100755
--- a/acprep
+++ b/acprep
@@ -44,6 +44,7 @@ search_prefixes = [ '/opt/local',
class BoostInfo(object):
log = None
suffix = ""
+ file_suffix = ".so"
home_path = "/usr"
include_path = "include"
library_path = "lib"
@@ -52,13 +53,14 @@ class BoostInfo(object):
def __init__(self, log):
self.log = log
- def configure(self, suffix = None, home_path = None,
+ def configure(self, suffix = None, file_suffix = None, home_path = None,
include_path = None, library_path = None):
path = library_path or self.library_path
if not isabs(path):
path = join(home_path or self.home_path, path)
if not exists(path) or not isdir(path) or \
- not self.check_for_boost_regex_lib(path, suffix or self.suffix):
+ not self.check_for_boost_regex_lib(path, suffix or self.suffix,
+ file_suffix or self.file_suffix):
return False
path = include_path or self.include_path
@@ -72,6 +74,9 @@ class BoostInfo(object):
if suffix:
self.log.debug('Setting Boost suffix to => ' + suffix)
self.suffix = suffix
+ if file_suffix:
+ self.log.debug('Setting Boost file suffix to => ' + file_suffix)
+ self.file_suffix = file_suffix
if home_path:
self.log.debug('Setting Boost home to => ' + home_path)
self.home_path = home_path
@@ -90,6 +95,10 @@ class BoostInfo(object):
self.log.debug('Saw option --boost or --boost-suffix')
self.suffix = value
+ def option_boost_file_suffix(self, option=None, opt_str=None, value=None, parser=None):
+ self.log.debug('Saw option --boost-file-suffix')
+ self.file_suffix = value
+
def option_boost_home(self, option=None, opt_str=None, value=None, parser=None):
self.log.debug('Saw option --boost-home')
self.home_path = value
@@ -104,21 +113,25 @@ class BoostInfo(object):
def inform_boost_details(self):
self.log.info('Boost was found here:')
+ self.log.info('Boost home path => ' + self.home_path)
self.log.info('Boost include path => ' + self.include_directory())
self.log.info('Boost library path => ' + self.library_directory())
- self.log.info('Boost suffix => ' + self.suffix)
+ self.log.info('Boost suffix => ' + self.suffix)
+ self.log.info('Boost file suffix => ' + self.file_suffix)
def find_boost_in_directory(self, path):
if exists(path) and isdir(path):
for entry in reversed(sorted(os.listdir(path))):
if re.search('boost_regex', entry):
- self.log.info('Found a Boost library: ' + entry)
+ self.log.info('Found a Boost library: ' + join(path, entry))
- match = re.match('libboost_regex([^.]*)\.(a|so|dylib)', entry)
+ match = re.match('libboost_regex([^.]*)(\.(a|so|dylib))', entry)
if match:
suffix = match.group(1)
+ file_suffix = match.group(2)
self.log.info('Found a Boost suffix => ' + suffix)
- return suffix
+ self.log.info('Found a Boost file suffix => ' + file_suffix)
+ return [suffix, file_suffix]
else:
self.log.debug('The directory "%s" is not valid, skipping' % path)
return None
@@ -126,22 +139,24 @@ class BoostInfo(object):
def locate_boost(self):
lib64_dirs = map(lambda x: join(x, 'lib64'), search_prefixes)
lib_dirs = map(lambda x: join(x, 'lib'), search_prefixes)
+ result = None
for path in lib64_dirs + lib_dirs:
self.log.info('Looking for Boost in %s...' % path)
- self.suffix = self.find_boost_in_directory(path)
- if self.suffix is not None:
+ result = self.find_boost_in_directory(path)
+ if result is not None:
+ self.suffix, self.file_suffix = result
+ self.library_path = path
self.home_path = dirname(path)
self.configured = True
self.inform_boost_details()
break
- if self.suffix is None:
- self.log.error("Boost not found, try --boost-home (and --boost-suffix)")
+ if result is None:
+ self.log.error("Boost not found, try --boost-home (and --boost-suffix, --boost-file-suffix)")
sys.exit(1)
- def check_for_boost_regex_lib(self, path, suffix):
+ def check_for_boost_regex_lib(self, path, suffix, file_suffix):
regex_lib = join(path, 'libboost_regex' + suffix)
- return (exists(regex_lib + '.a') or exists(regex_lib + '.lib') or
- exists(regex_lib + '.so') or exists(regex_lib + '.dylib'))
+ return exists(regex_lib + file_suffix)
def check_for_boost_regex_hpp(self, path):
regex_hpp = join(path, 'boost/regex.hpp')
@@ -152,6 +167,11 @@ class BoostInfo(object):
self.locate_boost()
return self.suffix
+ def get_file_suffix(self):
+ if not self.configured:
+ self.locate_boost()
+ return self.file_suffix
+
def include_directory(self):
if not self.configured:
self.locate_boost()
@@ -184,7 +204,7 @@ class BoostInfo(object):
self.log.error("Boost library directory '%s' not found, use --boost-include" % path)
sys.exit(1)
- if not self.check_for_boost_regex_lib(path, self.suffix):
+ if not self.check_for_boost_regex_lib(path, self.suffix, self.file_suffix):
self.log.error("Could not find Boost library 'boost_regex' in '%s'; use --boost-* flags" % path)
sys.exit(1)
@@ -214,9 +234,10 @@ class BoostInfo(object):
class CommandLineApp(object):
"Base class for building command line applications."
- force_exit = True # If true, always ends run() with sys.exit()
- log_handler = None
- darwin_gcc = False
+ force_exit = True # If true, always ends run() with sys.exit()
+ log_handler = None
+ darwin_gcc = False
+ boost_version = "1_45"
options = {
'debug': False,
@@ -336,7 +357,7 @@ class CommandLineApp(object):
exit_code = self.handleMainException()
if self.options.debug:
raise
-
+
if self.force_exit:
sys.exit(exit_code)
return exit_code
@@ -355,6 +376,7 @@ class PrepareBuild(CommandLineApp):
self.current_ver = None
#self.current_flavor = 'default'
self.current_flavor = 'debug'
+ self.prefix_dir = None
self.products_dir = None
self.build_dir = self.source_dir
self.configure_args = ['--with-included-gettext', '--enable-python']
@@ -412,10 +434,14 @@ class PrepareBuild(CommandLineApp):
action="callback", type="string",
callback=self.boost_info.option_boost_suffix,
help='Set Boost library suffix (ex: "--boost=-mt")')
- op.add_option('', '--boost-sufix', metavar='BOOST_SUFFIX',
+ op.add_option('', '--boost-suffix', metavar='BOOST_SUFFIX',
action="callback", type="string",
callback=self.boost_info.option_boost_suffix,
help='Set Boost library suffix (ex: "--boost-suffix=-mt")')
+ op.add_option('', '--boost-file-suffix', metavar='BOOST_FILE_SUFFIX',
+ action="callback", type="string",
+ callback=self.boost_info.option_boost_file_suffix,
+ help='Set Boost library file suffix (ex: "--boost-file-suffix=.so")')
op.add_option('', '--boost-home', metavar='BOOST_HOME',
action="callback", type="string",
callback=self.boost_info.option_boost_home,
@@ -435,6 +461,9 @@ class PrepareBuild(CommandLineApp):
op.add_option('', '--force', action="callback",
callback=self.option_force,
help="Perform every action, without checking")
+ op.add_option('', '--clang', action='store_true',
+ dest='use_clang', default=False,
+ help='Use the Clang C++ compiler')
op.add_option('', '--glibcxx-debug', action='store_true',
dest='use_glibcxx_debug', default=False,
help='Define _GLIBCXX_DEBUG=1 during compilation')
@@ -456,9 +485,18 @@ class PrepareBuild(CommandLineApp):
op.add_option('', '--no-python', action='store_true', dest='no_python',
default=False,
help='Do not enable Python support by default')
+ op.add_option('', '--enable-cache', action='store_true',
+ dest='enable_cache', default=False,
+ help='Enable use of Boost.Serialization (--cache)')
+ op.add_option('', '--enable-doxygen', action='store_true',
+ dest='enable_doxygen', default=False,
+ help='Enable use of Doxygen to build ref manual ("make docs")')
op.add_option('', '--universal', action='store_true',
dest='universal', default=False,
help='Attempt to build universal binaries')
+ op.add_option('', '--gcc45', action='store_true',
+ dest='gcc45', default=False,
+ help='Require the use of gcc 4.5')
op.add_option('', '--output', metavar='DIR', action="callback",
callback=self.option_output,
help='Build in the specified directory')
@@ -468,6 +506,9 @@ class PrepareBuild(CommandLineApp):
op.add_option('', '--pic', action="callback",
callback=self.option_pic,
help='Compile with explicit PIC support')
+ op.add_option('', '--prefix', metavar='DIR', action="callback",
+ callback=self.option_prefix, type="string",
+ help='Use custom installation prefix')
op.add_option('', '--products', metavar='DIR', action="callback",
callback=self.option_products,
help='Collect all build products in this directory')
@@ -550,6 +591,12 @@ class PrepareBuild(CommandLineApp):
# Determine information about the surroundings #
#########################################################################
+ def prefix_directory(self):
+ if self.prefix_dir:
+ return self.prefix_dir
+ else:
+ return None
+
def default_products_directory(self):
if self.envvars['LEDGER_PRODUCTS']:
return self.envvars['LEDGER_PRODUCTS']
@@ -589,17 +636,13 @@ class PrepareBuild(CommandLineApp):
def current_version(self):
if not self.current_ver:
- if self.git_working_tree():
- #date = self.get_stdout('git', 'log', '--format=%ci', '-1', 'HEAD')
- #date = re.sub(" [-+][0-9][0-9][0-9][0-9]$", "", date)
- #when = datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
- #self.current_ver = when.strftime("%Y%m%d_%H%M%S")
- #commit = self.get_stdout('git', 'log', '--format=%h', 'HEAD^..HEAD')
- #self.current_ver += "_" + commit
- tag = self.get_stdout('git', 'describe', '--all', '--long')
- self.current_ver = re.sub('heads/', '', tag)
- else:
- self.current_ver = "no-git"
+ version_m4 = open('version.m4', 'r')
+ for line in version_m4.readlines():
+ match = re.match('m4_define\(\[VERSION_NUMBER\], \[([0-9.]+[-abgrc0-9]*)\]\)',
+ line)
+ assert(match)
+ self.current_ver = match.group(1)
+ version_m4.close()
return self.current_ver
def need_to_prepare_autotools(self):
@@ -612,7 +655,7 @@ class PrepareBuild(CommandLineApp):
self.should_clean = True
return 'because acprep is newer than Makefile.in'
elif self.isnewer('configure.ac', 'configure'):
- return 'because confgure.ac is newer than configure'
+ return 'because configure.ac is newer than configure'
elif self.isnewer('Makefile.am', 'Makefile.in'):
return 'because Makefile.am is newer than Makefile.in'
return False
@@ -631,12 +674,15 @@ class PrepareBuild(CommandLineApp):
self.log.info("Source directory => " + self.source_dir)
self.log.info("Need to run autogen.sh => " +
str(self.need_to_prepare_autotools()))
+ if self.prefix_directory():
+ self.log.info("Installation prefix => " + self.prefix_directory())
self.log.info("Products directory => " + self.products_directory())
self.log.info("Build directory => " + self.build_directory())
self.log.info("Need to run configure => " +
str(self.need_to_run_configure()))
self.log.info("Use _GLIBCXX_DEBUG => " +
- str(self.options.use_glibcxx_debug))
+ str(self.options.use_glibcxx_debug
+ and not self.options.use_clang))
self.log.info("Use pre-compiled headers => " +
str('--enable-pch' in conf_args))
@@ -656,7 +702,7 @@ class PrepareBuild(CommandLineApp):
def phase_sloc(self, *args):
self.log.info('Executing phase: sloc')
- self.execute('sloccount', 'src', 'python', 'lisp', 'test')
+ self.execute('sloccount', 'src', 'python', 'lisp', 'test')
#########################################################################
# Configure source tree using autogen #
@@ -680,13 +726,6 @@ class PrepareBuild(CommandLineApp):
POTFILES_in.write('\n')
POTFILES_in.close()
- def phase_version(self, *args):
- self.log.info('Executing phase: version')
- version_m4 = open('version.m4', 'w')
- version_m4.write("m4_define([VERSION_NUMBER], [%s])\n" %
- self.current_version())
- version_m4.close()
-
def copytimes(self, src, dest):
os.utime(dest, (os.stat(src)[ST_ATIME], os.stat(src)[ST_MTIME]))
@@ -720,7 +759,6 @@ class PrepareBuild(CommandLineApp):
reason = self.need_to_prepare_autotools()
if reason:
self.log.info('autogen.sh must be run ' + reason)
- self.phase_version()
self.phase_autogen()
self.phase_gettext()
self.phase_aclocal()
@@ -880,9 +918,16 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def setup_system_directories(self):
+ boost_include = self.boost_info.include_directory()
+ boost_library = self.boost_info.library_directory()
+
+ if re.match('/opt/local', self.boost_info.home_path):
+ self.log.debug("Setting Python home to /opt/local based on Boost's location")
+ self.envvars['PYTHON_HOME'] = '/opt/local'
+
# Each of these becomes '-isystem <name>'
for path in ['/usr/local/include',
- self.boost_info.include_directory(),
+ boost_include,
'%s/include/python%s' %
(self.envvars['PYTHON_HOME'],
self.envvars['PYTHON_VERSION'].strip()),
@@ -900,7 +945,7 @@ class PrepareBuild(CommandLineApp):
% (self.envvars['PYTHON_HOME'],
self.envvars['PYTHON_VERSION'].strip()),
'/opt/local/lib',
- self.boost_info.library_directory(),
+ boost_library,
'/sw/lib']:
if exists(path) and isdir(path) and \
path not in self.sys_library_dirs:
@@ -908,19 +953,46 @@ class PrepareBuild(CommandLineApp):
self.sys_library_dirs.append(path)
def setup_for_johnw(self):
- if self.current_flavor == 'debug' or self.current_flavor == 'gcov':
- if exists('/usr/local/stow/cppunit/include'):
- self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit/include')
- self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit/lib')
+ if self.options.use_clang:
+ self.boost_inc_ident = "clang"
+ self.boost_lib_ident = "29"
- if exists('/usr/local/stow/icu/include'):
- self.sys_include_dirs.insert(0, '/usr/local/stow/icu/include')
- self.sys_library_dirs.insert(0, '/usr/local/stow/icu/lib')
+ self.log.debug('Using Clang ident: %s/%s' %
+ (self.boost_inc_ident, self.boost_lib_ident))
+ else:
+ match = re.search('gcc-mp-([0-9]+)\.([0-9]+)', self.envvars['CC'])
+ if match:
+ self.boost_inc_ident = "gcc" + match.group(1) + match.group(2)
+ self.boost_lib_ident = "x" + self.boost_inc_ident
+ else:
+ self.boost_inc_ident = "gcc42"
+ self.boost_lib_ident = "xgcc42"
+
+ self.log.debug('Using Boost ident: %s/%s' %
+ (self.boost_inc_ident, self.boost_lib_ident))
+ if self.boost_lib_ident != "xgcc42":
self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1')
+
+ if self.current_flavor == 'debug':
+ if exists('/usr/local/stow/cppunit-%s/include' % self.boost_inc_ident):
+ self.sys_include_dirs.insert(
+ 0, '/usr/local/stow/cppunit-%s/include' % self.boost_inc_ident)
+ self.sys_library_dirs.insert(
+ 0, '/usr/local/stow/cppunit-%s/lib' % self.boost_inc_ident)
+
+ if exists('/usr/local/stow/icu-%s/include' % self.boost_inc_ident):
+ self.sys_include_dirs.insert(
+ 0, '/usr/local/stow/icu-%s/include' % self.boost_inc_ident)
+ self.sys_library_dirs.insert(
+ 0, '/usr/local/stow/icu-%s/lib' % self.boost_inc_ident)
+
self.configure_args.append('--disable-shared')
- self.options.use_glibcxx_debug = True
+ if not self.options.use_clang:
+ 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')
@@ -928,10 +1000,6 @@ class PrepareBuild(CommandLineApp):
self.locate_darwin_libraries()
def setup_for_system(self):
- if exists('/Users/johnw/Projects/ledger/plan/TODO'):
- self.setup_for_johnw()
- self.setup_system_directories()
-
system = self.get_stdout('uname', '-s')
self.log.info('System type is => ' + system)
@@ -953,13 +1021,25 @@ class PrepareBuild(CommandLineApp):
self.CXXFLAGS.append('-pthread')
elif system == 'Darwin':
- if (self.current_flavor == 'opt' or \
+ if self.options.use_clang:
+ self.envvars['CC'] = 'clang'
+ self.envvars['CXX'] = 'clang++'
+ self.envvars['LD'] = 'llvm-ld'
+ elif (self.current_flavor == 'opt' or \
self.current_flavor == 'default') and \
+ not self.options.gcc45 and \
exists('/usr/bin/g++-4.2'):
self.envvars['CC'] = '/usr/bin/gcc-4.2'
self.envvars['CXX'] = '/usr/bin/g++-4.2'
self.envvars['LD'] = '/usr/bin/g++-4.2'
self.darwin_gcc = True
+ elif exists('/opt/local/bin/g++-mp-4.5'):
+ self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.5'
+ if exists('/Users/johnw/bin/gfilt'):
+ self.envvars['CXX'] = '/Users/johnw/bin/gfilt'
+ else:
+ self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.5'
+ self.envvars['LD'] = '/opt/local/bin/g++-mp-4.5'
elif exists('/opt/local/bin/g++-mp-4.4'):
self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.4'
self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.4'
@@ -977,6 +1057,15 @@ class PrepareBuild(CommandLineApp):
# g++ 4.0.1 cannot use PCH headers on OS X 10.5
self.option_no_pch()
+ if self.options.enable_doxygen:
+ self.configure_args.append('--enable-doxygen')
+ if self.options.enable_cache:
+ self.configure_args.append('--enable-cache')
+
+ if exists('/Users/johnw/Projects/ledger/plan/TODO'):
+ self.setup_for_johnw()
+ self.setup_system_directories()
+
if '--enable-pch' not in self.configure_args and \
(exists('/opt/local/bin/ccache') or \
exists('/usr/local/bin/ccache')):
@@ -1041,7 +1130,7 @@ class PrepareBuild(CommandLineApp):
self.configure_args.append('--enable-pch')
- self.CXXFLAGS.append('-fpch-deps')
+ self.LDFLAGS.append('-fpch-deps')
self.CXXFLAGS.append('-Wconversion')
#self.CXXFLAGS.append('-Wold-style-cast')
@@ -1073,35 +1162,39 @@ class PrepareBuild(CommandLineApp):
def option_warn(self, option=None, opt_str=None, value=None, parser=None):
self.log.debug('Saw option --warn')
- self.CXXFLAGS.append('-ansi')
- self.CXXFLAGS.append('-pedantic')
- self.CXXFLAGS.append('-pedantic-errors')
- self.CXXFLAGS.append('-Wall')
- self.CXXFLAGS.append('-Winvalid-pch')
- self.CXXFLAGS.append('-Wextra')
- self.CXXFLAGS.append('-Wcast-align')
- self.CXXFLAGS.append('-Wcast-qual')
- self.CXXFLAGS.append('-Wfloat-equal')
- self.CXXFLAGS.append('-Wmissing-field-initializers')
- self.CXXFLAGS.append('-Wno-endif-labels')
- self.CXXFLAGS.append('-Woverloaded-virtual')
- self.CXXFLAGS.append('-Wsign-compare')
- self.CXXFLAGS.append('-Wsign-promo')
- self.CXXFLAGS.append('-Wstrict-null-sentinel')
- self.CXXFLAGS.append('-Wwrite-strings')
- self.CXXFLAGS.append('-Wno-old-style-cast')
- self.CXXFLAGS.append('-Wno-deprecated')
- self.CXXFLAGS.append('-Wno-strict-aliasing')
- self.CXXFLAGS.append('-Werror')
+ self.CXXFLAGS.append('-ansi')
+ self.CXXFLAGS.append('-pedantic')
+ self.CXXFLAGS.append('-pedantic-errors')
+ self.CXXFLAGS.append('-Wall')
+ self.CXXFLAGS.append('-Winvalid-pch')
+ self.CXXFLAGS.append('-Wextra')
+ self.CXXFLAGS.append('-Wcast-align')
+ self.CXXFLAGS.append('-Wcast-qual')
+ self.CXXFLAGS.append('-Wfloat-equal')
+ self.CXXFLAGS.append('-Wmissing-field-initializers')
+ self.CXXFLAGS.append('-Wno-endif-labels')
+ self.CXXFLAGS.append('-Woverloaded-virtual')
+ self.CXXFLAGS.append('-Wsign-compare')
+ self.CXXFLAGS.append('-Wsign-promo')
+ #self.CXXFLAGS.append('-Wstrict-null-sentinel')
+ self.CXXFLAGS.append('-Wwrite-strings')
+ self.CXXFLAGS.append('-Wno-old-style-cast')
+ self.CXXFLAGS.append('-Wno-deprecated')
+ self.CXXFLAGS.append('-Wno-strict-aliasing')
+ self.CXXFLAGS.append('-Werror')
def option_pic(self, option=None, opt_str=None, value=None, parser=None):
self.log.debug('Saw option --pic')
- self.CXXFLAGS.append('-fPIC')
+ self.CXXFLAGS.append('-fPIC')
def option_output(self, option=None, opt_str=None, value=None, parser=None):
self.log.debug('Saw option --output')
self.build_dir = value
+ def option_prefix(self, option=None, opt_str=None, value=None, parser=None):
+ self.log.debug('Saw option --prefix')
+ self.prefix_dir = value
+
def option_products(self, option=None, opt_str=None, value=None, parser=None):
self.log.debug('Saw option --products')
self.products_dir = value
@@ -1128,32 +1221,48 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def locate_darwin_libraries(self):
- if self.current_flavor == 'debug' or self.current_flavor == 'gcov':
- if self.options.use_glibcxx_debug:
+ if self.current_flavor == 'debug':
+ if self.options.use_glibcxx_debug and not self.options.use_clang:
self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags')
self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1')
- if self.boost_info.configure(home_path = '/usr/local/stow/boost_1_43_0',
- suffix = '-xgcc44-sd-1_43',
- include_path = 'include/boost-1_43'):
+ if self.boost_info.configure(
+ home_path = '/usr/local/stow/boost_%s_0-%s' % \
+ (self.boost_version, self.boost_inc_ident),
+ suffix = '-%s-sd-%s' % \
+ (self.boost_lib_ident, self.boost_version),
+ file_suffix = '.dylib',
+ include_path = 'include/boost-%s' % self.boost_version):
pass
- elif self.boost_info.configure(home_path = '/usr/local/stow/boost_1_43_0',
- suffix = '-xgcc44-d-1_43',
- include_path = 'include/boost-1_43'):
+ elif self.boost_info.configure(
+ home_path = '/usr/local/stow/boost_%s_0-%s' % \
+ (self.boost_version, self.boost_inc_ident),
+ suffix = '-%s-d-%s' % \
+ (self.boost_lib_ident, self.boost_version),
+ file_suffix = '.dylib',
+ include_path = 'include/boost-%s' % self.boost_version):
pass
- elif self.boost_info.configure(suffix = '-d'):
+ elif self.boost_info.configure(suffix = '-d', file_suffix = '.dylib'):
pass
else:
if self.boost_info.configure():
pass
- elif self.boost_info.configure(home_path = '/usr/local/stow/boost_1_43_0',
- suffix = '-xgcc44-s-1_43',
- include_path = 'include/boost-1_43'):
+ elif self.boost_info.configure(
+ home_path = '/usr/local/stow/boost_%s_0-%s' % \
+ (self.boost_version, self.boost_inc_ident),
+ suffix = '-%s-s-%s' % \
+ (self.boost_lib_ident, self.boost_version),
+ file_suffix = '.dylib',
+ include_path = 'include/boost-%s' % self.boost_version):
pass
- elif self.boost_info.configure(home_path = '/usr/local/stow/boost_1_43_0',
- suffix = '-xgcc44-1_43',
- include_path = 'include/boost-1_43'):
+ elif self.boost_info.configure(
+ home_path = '/usr/local/stow/boost_%s_0-%s' % \
+ (self.boost_version, self.boost_inc_ident),
+ suffix = '-%s-%s' % \
+ (self.boost_lib_ident, self.boost_version),
+ file_suffix = '.dylib',
+ include_path = 'include/boost-%s' % self.boost_version):
pass
def setup_flavor_default(self):
@@ -1168,27 +1277,34 @@ class PrepareBuild(CommandLineApp):
def setup_flavor_opt(self):
self.CPPFLAGS.append('-DNDEBUG=1')
+ for i in ['-O3', '-fomit-frame-pointer']:
+ self.CXXFLAGS.append(i)
+ self.CFLAGS.append(i)
+ self.LDFLAGS.append(i)
+ #if self.options.gcc45:
+ # for i in ['-flto']:
+ # self.CXXFLAGS.append(i)
+ # self.CFLAGS.append(i)
+ # self.LDFLAGS.append(i)
if self.darwin_gcc:
self.option_no_pch()
if '--disable-shared' in self.configure_args:
self.configure_args.remove('--disable-shared')
self.configure_args.append('--disable-dependency-tracking')
- for i in ['-fast']:
- self.CXXFLAGS.append(i)
- self.CFLAGS.append(i)
- self.LDFLAGS.append(i)
if self.options.universal:
+ for i in ['-fast']:
+ self.CXXFLAGS.append(i)
+ self.CFLAGS.append(i)
+ self.LDFLAGS.append(i)
for i in ['-arch', 'i386', '-arch', 'x86_64']:
self.CXXFLAGS.append(i)
self.CFLAGS.append(i)
self.LDFLAGS.append(i)
- else:
- for i in ['-O3', '-fomit-frame-pointer']:
- self.CXXFLAGS.append(i)
- self.CFLAGS.append(i)
- 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')
@@ -1231,6 +1347,9 @@ class PrepareBuild(CommandLineApp):
conf_args.append('--with-boost-suffix=%s' %
self.boost_info.get_suffix())
+ if self.prefix_directory():
+ conf_args.append('--prefix=%s' % self.prefix_directory())
+
return (environ, conf_args + self.configure_args)
def need_to_run_configure(self):
@@ -1309,8 +1428,9 @@ 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)
self.log.debug('Configure arguments => ' + str(config_args))
self.log.debug('Makefile arguments => ' + str(make_args))
@@ -1425,6 +1545,7 @@ class PrepareBuild(CommandLineApp):
self.build_dir = None # use the build/ tree
self.current_flavor = flavor
self.option_release()
+ self.prefix_dir = None
if reset and exists(self.build_directory()) and \
isdir(self.build_directory()):
@@ -1492,6 +1613,7 @@ class PrepareBuild(CommandLineApp):
self.configure_flavor('default', reset=False)
self.log.info('=== Testing default ===')
self.phase_make('fullcheck')
+ self.phase_make('docs')
self.log.info('=== Building final distcheck ===')
self.phase_distcheck()
@@ -1589,7 +1711,7 @@ your options. Here are some real-world examples:
./acprep
./acprep opt -- make -j3
- ./acprep -- --enable-doxygen"""
+ ./acprep --enable-doxygen"""
sys.exit(0)
PrepareBuild().run()
diff --git a/contrib/vim/compiler/ledger.vim b/contrib/vim/compiler/ledger.vim
index 33b019cb..e9e98a8e 100644
--- a/contrib/vim/compiler/ledger.vim
+++ b/contrib/vim/compiler/ledger.vim
@@ -12,20 +12,17 @@ if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args>
endif
-if ! exists("g:ledger_bin") || ! executable(g:ledger_bin)
- if executable('ledger')
- let g:ledger_bin = 'ledger'
- else
- echoerr "ledger command not found. Set g:ledger_bin or extend $PATH."
- finish
- endif
+" default value will be set in ftplugin
+if ! exists("g:ledger_bin") || empty(g:ledger_bin) || ! executable(split(g:ledger_bin, '\s')[0])
+ finish
endif
" %-G throws away blank lines, everything else is assumed to be part of a
" multi-line error message.
CompilerSet errorformat=%-G,%EWhile\ parsing\ file\ \"%f\"\\,\ line\ %l:%.%#,%ZError:\ %m,%C%.%#
+CompilerSet errorformat+=%tarning:\ \"%f\"\\,\ line\ %l:\ %m
" unfortunately there is no 'check file' command,
" so we will just use a query that returns no results. ever.
-exe 'CompilerSet makeprg='.g:ledger_bin.'\ -f\ %\ reg\ not\ ''.*''\ \>\ /dev/null'
+exe 'CompilerSet makeprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ -f\ %\ reg\ not\ ''.*''\ \>\ /dev/null'
diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim
index d75a6869..d1c8e1a9 100644
--- a/contrib/vim/ftplugin/ledger.vim
+++ b/contrib/vim/ftplugin/ledger.vim
@@ -12,7 +12,7 @@ let b:did_ftplugin = 1
let b:undo_ftplugin = "setlocal ".
\ "foldmethod< foldtext< ".
- \ "include< comments< omnifunc< "
+ \ "include< comments< omnifunc< formatprg<"
" don't fill fold lines --> cleaner look
setl fillchars="fold: "
@@ -22,6 +22,21 @@ setl include=^!include
setl comments=b:;
setl omnifunc=LedgerComplete
+" set location of ledger binary for checking and auto-formatting
+if ! exists("g:ledger_bin") || empty(g:ledger_bin) || ! executable(split(g:ledger_bin, '\s')[0])
+ if executable('ledger')
+ let g:ledger_bin = 'ledger'
+ else
+ unlet g:ledger_bin
+ echoerr "ledger command not found. Set g:ledger_bin or extend $PATH ".
+ \ "to enable error checking and auto-formatting."
+ endif
+endif
+
+if exists("g:ledger_bin")
+ exe 'setl formatprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ -f\ -\ print'
+endif
+
" You can set a maximal number of columns the fold text (excluding amount)
" will use by overriding g:ledger_maxwidth in your .vimrc.
" When maxwidth is zero, the amount will be displayed at the far right side
@@ -92,7 +107,7 @@ function! LedgerFoldText() "{{{1
\ '\(^\s\+\|\s\+$\)', '', 'g')
" number of columns foldtext can use
- let columns = s:get_columns(0)
+ let columns = s:get_columns()
if g:ledger_maxwidth
let columns = min([columns, g:ledger_maxwidth])
endif
@@ -107,9 +122,9 @@ function! LedgerFoldText() "{{{1
let foldtext .= repeat(' ', filen - (folen%filen))
let foldtext .= repeat(g:ledger_fillstring,
- \ s:get_columns(0)/filen)
+ \ s:get_columns()/filen)
else
- let foldtext .= repeat(' ', s:get_columns(0))
+ let foldtext .= repeat(' ', s:get_columns())
endif
" we don't use slices[:5], because that messes up multibyte characters
@@ -123,37 +138,8 @@ function! LedgerComplete(findstart, base) "{{{1
let lnum = line('.')
let line = getline('.')
let lastcol = col('.') - 2
- if line =~ '^\d' "{{{2 (date / payee / description)
- let b:compl_context = 'payee'
- return -1
- elseif line =~ '^\s\+;' "{{{2 (metadata / tags)
- let b:compl_context = 'meta-tag'
- let first_possible = matchend(line, '^\s\+;')
-
- " find first column of text to be replaced
- let firstcol = lastcol
- while firstcol >= 0
- if firstcol <= first_possible
- " Stop before the ';' don't ever include it
- let firstcol = first_possible
- break
- elseif line[firstcol] =~ ':'
- " Stop before first ':'
- let firstcol += 1
- break
- endif
-
- let firstcol -= 1
- endwhile
-
- " strip whitespace starting from firstcol
- let end_of_whitespace = matchend(line, '^\s\+', firstcol)
- if end_of_whitespace != -1
- let firstcol = end_of_whitespace
- endif
-
- return firstcol
- elseif line =~ '^\s\+' "{{{2 (account)
+ let b:compl_context = ''
+ if line =~ '^\s\+[^[:blank:];]' "{{{2 (account)
let b:compl_context = 'account'
if matchend(line, '^\s\+\%(\S \S\|\S\)\+') <= lastcol
" only allow completion when in or at end of account name
@@ -176,16 +162,12 @@ function! LedgerComplete(findstart, base) "{{{1
let results = LedgerFindInTree(LedgerGetAccountHierarchy(), hierarchy)
" sort by alphabet and reverse because it will get reversed one more time
- let results = reverse(sort(results))
if g:ledger_detailed_first
- let results = sort(results, 's:sort_accounts_by_depth')
+ let results = reverse(sort(results, 's:sort_accounts_by_depth'))
+ else
+ let results = sort(results)
endif
- call add(results, a:base)
- return reverse(results)
- elseif b:compl_context == 'meta-tag' "{{{2
- unlet! b:compl_context
- let results = [a:base]
- call extend(results, sort(s:filter_items(keys(LedgerGetTags()), a:base)))
+ call insert(results, a:base)
return results
else "}}}
unlet! b:compl_context
@@ -228,52 +210,306 @@ function! LedgerGetAccountHierarchy() "{{{1
return hierarchy
endf "}}}
-function! LedgerGetTags() "{{{1
- let alltags = {}
- let metalines = s:grep_buffer('^\s\+;\s*\zs.*$')
- for line in metalines
- " (spaces at beginning are stripped by matchstr!)
- if line[0] == ':'
- " multiple tags
- for val in split(line, ':')
- if val !~ '^\s*$'
- let name = s:strip_spaces(val)
- let alltags[name] = get(alltags, name, [])
- endif
- endfor
- elseif line =~ '^.*:.*$'
- " line with tag=value
- let name = s:strip_spaces(split(line, ':')[0])
- let val = s:strip_spaces(join(split(line, ':')[1:], ':'))
- let values = get(alltags, name, [])
- call add(values, val)
- let alltags[name] = values
+function! LedgerToggleTransactionState(lnum, ...)
+ if a:0 == 1
+ let chars = a:1
+ else
+ let chars = ' *'
+ endif
+ let trans = s:transaction.from_lnum(a:lnum)
+ if empty(trans)
+ return
+ endif
+
+ let old = has_key(trans, 'state') ? trans['state'] : ' '
+ let i = stridx(chars, old) + 1
+ let new = chars[i >= len(chars) ? 0 : i]
+
+ call trans.set_state(new)
+
+ call setline(trans['head'], trans.format_head())
+endf
+
+function! LedgerSetTransactionState(lnum, char) "{{{1
+ " modifies or sets the state of the transaction at the cursor,
+ " removing the state alltogether if a:char is empty
+ let trans = s:transaction.from_lnum(a:lnum)
+ if empty(trans)
+ return
+ endif
+
+ call trans.set_state(a:char)
+
+ call setline(trans['head'], trans.format_head())
+endf "}}}
+
+function! LedgerSetDate(lnum, type, ...) "{{{1
+ let time = a:0 == 1 ? a:1 : localtime()
+ let trans = s:transaction.from_lnum(a:lnum)
+ if empty(trans)
+ return
+ endif
+
+ let formatted = strftime('%Y/%m/%d', time)
+ if has_key(trans, 'date') && ! empty(trans['date'])
+ let date = split(trans['date'], '=')
+ else
+ let date = [formatted]
+ endif
+
+ if a:type ==? 'actual'
+ let date[0] = formatted
+ elseif a:type ==? 'effective'
+ if time < 0
+ " remove effective date
+ let date = [date[0]]
+ else
+ " set effective date
+ if len(date) >= 2
+ let date[1] = formatted
+ else
+ call add(date, formatted)
+ endif
endif
+ endif
+
+ let trans['date'] = join(date, '=')
+
+ call setline(trans['head'], trans.format_head())
+endf "}}}
+
+let s:transaction = {} "{{{1
+function! s:transaction.new() dict
+ return copy(s:transaction)
+endf
+
+function! s:transaction.from_lnum(lnum) dict "{{{2
+ let [head, tail] = s:get_transaction_extents(a:lnum)
+ if ! head
+ return {}
+ endif
+
+ let trans = copy(s:transaction)
+ let trans['head'] = head
+ let trans['tail'] = tail
+
+ let parts = split(getline(head), '\s\+')
+ if parts[0] ==# '~'
+ let trans['expr'] = join(parts[1:])
+ return trans
+ elseif parts[0] !~ '^\d'
+ " this case is avoided in s:get_transaction_extents(),
+ " but we'll check anyway.
+ return {}
+ endif
+
+ for part in parts
+ if ! has_key(trans, 'date') && part =~ '^\d'
+ let trans['date'] = part
+ elseif ! has_key(trans, 'code') && part =~ '^([^)]*)$'
+ let trans['code'] = part[1:-2]
+ elseif ! has_key(trans, 'state') && part =~ '^[[:punct:]]$'
+ " the first character by itself is assumed to be the state of the transaction.
+ let trans['state'] = part
+ else
+ " everything after date/code or state belongs to the description
+ break
+ endif
+ call remove(parts, 0)
endfor
- return alltags
+
+ " FIXME: this will break comments at the end of this 'head' line
+ " they need 2 spaces in front of the semicolon
+ let trans['description'] = join(parts)
+ return trans
endf "}}}
+function! s:transaction.set_state(char) dict "{{{2
+ if has_key(self, 'state') && a:char =~ '^\s*$'
+ call remove(self, 'state')
+ else
+ let self['state'] = a:char
+ endif
+endf "}}}
+
+function! s:transaction.parse_body(...) dict "{{{2
+ if a:0 == 2
+ let head = a:1
+ let tail = a:2
+ elseif a:0 == 0
+ let head = self['head']
+ let tail = self['tail']
+ else
+ throw "wrong number of arguments for parse_body()"
+ return []
+ endif
+
+ if ! head || tail <= head
+ return []
+ endif
+
+ let lnum = head
+ let tags = {}
+ let postings = []
+ while lnum <= tail
+ let line = split(getline(lnum), '\s*\%(\t\| \);', 1)
+
+ if line[0] =~ '^\s\+[^[:blank:];]'
+ " posting
+ " FIXME: replaces original spacing in amount with single spaces
+ let parts = split(line[0], '\%(\t\| \)\s*')
+ call add(postings, {'account': parts[0], 'amount': join(parts[1:], ' ')})
+ end
+
+ " where are tags to be stored?
+ if empty(postings)
+ " they belong to the transaction
+ let tag_container = tags
+ else
+ " they belong to last posting
+ if ! has_key(postings[-1], 'tags')
+ let postings[-1]['tags'] = {}
+ endif
+ let tag_container = postings[-1]['tags']
+ endif
+
+ let comment = join(line[1:], ' ;')
+ if comment =~ '^\s*:'
+ " tags without values
+ for t in s:findall(comment, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:')
+ let tag_container[t] = ''
+ endfor
+ elseif comment =~ '^\s*[^:[:blank:]][^:]\+:'
+ " tag with value
+ let key = matchstr(comment, '^\s*\zs[^:]\+\ze:')
+ if ! empty(key)
+ let val = matchstr(comment, ':\s*\zs.*\ze\s*$')
+ let tag_container[key] = val
+ endif
+ endif
+ let lnum += 1
+ endw
+ return [tags, postings]
+endf "}}}
+
+function! s:transaction.format_head() dict "{{{2
+ if has_key(self, 'expr')
+ return '~ '.self['expr']
+ endif
+
+ let parts = []
+ if has_key(self, 'date') | call add(parts, self['date']) | endif
+ if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif
+ if has_key(self, 'state') | call add(parts, self['state']) | endif
+ if has_key(self, 'description') | call add(parts, self['description']) | endif
+ return join(parts)
+endf "}}}
+"}}}
+
" Helper functions {{{1
+function! s:get_transactions(...) "{{{2
+ if a:0 == 2
+ let lnum = a:1
+ let end = a:2
+ elseif a:0 == 0
+ let lnum = 1
+ let end = line('$')
+ else
+ throw "wrong number of arguments for get_transactions()"
+ return []
+ endif
+
+ " safe view / position
+ let view = winsaveview()
+ let fe = &foldenable
+ set nofoldenable
+
+ let transactions = []
+ call cursor(lnum, 0)
+ while lnum && lnum <= end
+ let trans = s:transaction.from_lnum(lnum)
+ if ! empty(trans)
+ call add(transactions, trans)
+ call cursor(trans['tail'], 0)
+ endif
+ let lnum = search('^[~[:digit:]]\S\+', 'cW')
+ endw
+
+ " restore view / position
+ let &foldenable = fe
+ call winrestview(view)
+
+ return transactions
+endf "}}}
+
+function! s:get_transaction_extents(lnum) "{{{2
+ if ! (indent(a:lnum) || getline(a:lnum) =~ '^[~[:digit:]]\S\+')
+ " only do something if lnum is in a transaction
+ return [0, 0]
+ endif
+
+ " safe view / position
+ let view = winsaveview()
+ let fe = &foldenable
+ set nofoldenable
+
+ call cursor(a:lnum, 0)
+ let head = search('^[~[:digit:]]\S\+', 'bcnW')
+ let tail = search('^[^;[:blank:]]\S\+', 'nW')
+ let tail = tail > head ? tail - 1 : line('$')
+
+ " restore view / position
+ let &foldenable = fe
+ call winrestview(view)
+
+ return head ? [head, tail] : [0, 0]
+endf "}}}
+
+function! s:findall(text, rx) " {{{2
+ " returns all the matches in a string,
+ " there will be overlapping matches according to :help match()
+ let matches = []
+
+ while 1
+ let m = matchstr(a:text, a:rx, 0, len(matches)+1)
+ if empty(m)
+ break
+ endif
+
+ call add(matches, m)
+ endw
+
+ return matches
+endf "}}}
+
" return length of string with fix for multibyte characters
function! s:multibyte_strlen(text) "{{{2
return strlen(substitute(a:text, ".", "x", "g"))
endfunction "}}}
" get # of visible/usable columns in current window
-function! s:get_columns(win) "{{{2
+function! s:get_columns() " {{{2
" As long as vim doesn't provide a command natively,
" we have to compute the available columns.
" see :help todo.txt -> /Add argument to winwidth()/
- " FIXME: Although this will propably never be used with debug mode enabled
- " this should take the signs column into account (:help sign.txt)
- let columns = (winwidth(a:win) == 0 ? 80 : winwidth(a:win)) - &foldcolumn
+
+ let columns = (winwidth(0) == 0 ? 80 : winwidth(0)) - &foldcolumn
if &number
" line('w$') is the line number of the last line
let columns -= max([len(line('w$'))+1, &numberwidth])
endif
+
+ " are there any signs/is the sign column displayed?
+ redir => signs
+ silent execute 'sign place buffer='.string(bufnr("%"))
+ redir END
+ if signs =~# 'id='
+ let columns -= 2
+ endif
+
return columns
-endfunction "}}}
+endf "}}}
" remove spaces at start and end of string
function! s:strip_spaces(text) "{{{2
diff --git a/contrib/vim/syntax/ledger.vim b/contrib/vim/syntax/ledger.vim
index 61f9a2e5..d4097e2b 100644
--- a/contrib/vim/syntax/ledger.vim
+++ b/contrib/vim/syntax/ledger.vim
@@ -28,43 +28,39 @@ syntax clear
" DATE[=EDATE] [*|!] [(CODE)] DESC <-- first line of transaction
" ACCOUNT AMOUNT [; NOTE] <-- posting
-" region: a transaction containing postings
-syn region transNorm start=/^[[:digit:]~]/ skip=/^\s/ end=/^/
- \ fold keepend transparent contains=transDate,Metadata,Posting
-syn match transDate /^\d\S\+/ contained
-syn match Metadata /^\s\+;.*/ contained contains=MetadataTag
-syn match Comment /^;.*$/
+syn region ledgerTransaction start=/^[[:digit:]~]/ skip=/^\s/ end=/^/
+ \ fold keepend transparent contains=ledgerTransactionDate,ledgerMetadata,ledgerPosting
+syn match ledgerTransactionDate /^\d\S\+/ contained
+syn match ledgerPosting /^\s\+[^[:blank:];][^;]*\ze\%($\|;\)/
+ \ contained transparent contains=ledgerAccount,ledgerMetadata
" every space in an account name shall be surrounded by two non-spaces
" every account name ends with a tab, two spaces or the end of the line
-syn match Account /^\s\+\zs\%(\S \S\|\S\)\+\ze\%([ ]\{2,}\|\t\s*\|\s*$\)/ contained
-syn match Posting /^\s\+[^[:blank:];].*$/ contained transparent contains=Account,Amount
-" FIXME: add other symbols?
-let s:currency = '\([$€£¢]\|\w\+\)'
-let s:figures = '\d\+\([.,]\d\+\)*'
-let s:amount = '-\?\('.s:figures.'\s*'.s:currency.'\|'.s:currency.'\s*'.s:figures.'\)'
-exe 'syn match Amount /'.s:amount.'/ contained'
-syn match MetadataTag /:[^:]\+:/hs=s+1,he=e-1 contained
-syn match MetadataTag /;\s*\zs[^:]\+\ze:[^:]\+$/ contained
+syn match ledgerAccount /^\s\+\zs\%(\S \S\|\S\)\+\ze\%( \|\t\|\s*$\)/ contained
-syn region TagStack
- \ matchgroup=TagPush start=/^tag\>/
- \ matchgroup=TagPop end=/^pop\>/
- \ contains=TagHead,TagStack,transNorm
-syn match TagHead /\%(^tag\s\+\)\@<=\S.*$/ contained contains=tagKey transparent
-syn match TagKey /:[^:]\+:/hs=s+1,he=e-1 contained
-syn match TagKey /\%(^tag\s\+\)\@<=[^:]\+\ze:[^:]\+$/ contained
+syn match ledgerComment /^;.*$/
+" comments at eol must be preceeded by at least 2 spaces / 1 tab
+syn region ledgerMetadata start=/\%( \|\t\|^\s\+\);/ skip=/^\s\+;/ end=/^/
+ \ keepend contained contains=ledgerTag,ledgerTypedTag
+syn match ledgerTag /:[^:]\+:/hs=s+1,he=e-1 contained
+syn match ledgerTag /\%(\%(;\|^tag\)[^:]\+\)\@<=[^:]\+:\ze[^:]\+$/ contained
+syn match ledgerTypedTag /\%(\%(;\|^tag\)[^:]\+\)\@<=[^:]\+::\ze[^:]\+$/ contained
-highlight default link transDate Constant
-highlight default link Metadata Tag
-highlight default link MetadataTag Type
-highlight default link TagPop Tag
-highlight default link TagPush Tag
-highlight default link TagKey Type
-highlight default link Amount Number
-highlight default link Account Identifier
+syn region ledgerTagStack
+ \ matchgroup=ledgerTagPush start=/^tag\>/
+ \ matchgroup=ledgerTagPop end=/^pop\>/
+ \ contains=ledgerTagHead,ledgerTagStack,ledgerTransaction,ledgerComment
+syn match ledgerTagHead /\%(^tag\s\+\)\@<=\S.*$/ contained contains=ledgerTag transparent
+
+highlight default link ledgerTransactionDate Constant
+highlight default link ledgerMetadata Tag
+highlight default link ledgerTypedTag Keyword
+highlight default link ledgerTag Type
+highlight default link ledgerTagPop Tag
+highlight default link ledgerTagPush Tag
+highlight default link ledgerAccount Identifier
" syncinc is easy: search for the first transaction.
syn sync clear
-syn sync match ledgerSync grouphere transNorm "^[[:digit:]~]"
+syn sync match ledgerSync grouphere ledgerTransaction "^[[:digit:]~]"
let b:current_syntax = "ledger"
diff --git a/dist/Portfile b/dist/Portfile
index c7305e96..3388c936 100644
--- a/dist/Portfile
+++ b/dist/Portfile
@@ -3,75 +3,86 @@
PortSystem 1.0
-name ledger
-version 3.0
+name ledger-devel
+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.
+ is accessed from the UNIX command-line.
-maintainers johnw@newartisans.com
+maintainers newartisans.com:johnw
platforms darwin
-use_bzip2 no
-master_sites ftp://ftp.newartisans.com/pub/ledger/:source
-distname ${name}-${version}
-distfiles ${distname}${extract.suffix}:source
-checksums ${distname}${extract.suffix} \
- md5 7d2ebb3fbc0ca14e34f4aada9fe764a0 \
- sha1 d00ca4d61f28793c22be892411491d5ff48f156b \
- rmd160 e6ef6e0acfa125a88927ac399ec8e37fbbe1fe66
+use_bzip2 yes
+master_sites http://ftp.newartisans.com/pub/ledger/
+distname ledger-${version}
+checksums md5 980e819c4cb68b8777849a44316e0edc \
+ sha1 ff1b281ce6ddfeb5814ce59bd4d69b97ddb21f7e \
+ rmd160 a40e64bf21c9c132619b0921dee0e12299e3938a
depends_build port:automake \
port:autoconf \
port:libtool
-depends_lib port:gmp \
+depends_lib port:gettext \
+ port:gmp \
port:mpfr \
- port:boost
+ port:boost \
+ port:libedit
-configure.args --with-extra-includes=${prefix}/include \
+configure.args --with-extra-includes=${prefix}/include \
--with-extra-libs=${prefix}/lib
-#patchfiles patch-admin-libtool.m4.in.diff \
-# patch-ledger-ProjectFile.cpp.diff
-
build.args DYLD_LIBRARY_PATH=${worksrcpath}/ledger/.libs
-platform darwin 9 {}
-
destroot.args DESTDIR=${destroot}${prefix} \
DYLD_LIBRARY_PATH=${worksrcpath}/ledger/.libs \
docprefix=${destroot}/share/doc
-post-destroot {}
-
-variant ofx description {Allow reading of OFX data files} {
- depends_lib-append port:libofx
-}
-
variant debug description {Enable debug mode} {
configure.args-append --enable-debug=yes
}
+variant icu description {Enable full Unicode support} {
+ if {[variant_isset python25]} {
+ depends_lib-delete port:boost+python25
+ depends_lib-append port:boost+icu+python25
+ } elsif {[variant_isset python26]} {
+ depends_lib-delete port:boost+python26
+ depends_lib-append port:boost+icu+python26
+ } else {
+ depends_lib-delete port:boost
+ depends_lib-append port:boost+icu
+ }
+}
+
variant python25 description {build python 2.5 support} conflicts python26 {
- set pyversion 2.5
- depends_lib-delete port:boost
- depends_lib-append port:boost+python25 \
- port:python[strsed ${pyversion} {g/[.]//}]
+ set pyversion 2.5
+ if {[variant_isset icu]} {
+ depends_lib-delete port:boost+icu
+ depends_lib-append port:boost+icu+python25
+ } else {
+ depends_lib-delete port:boost
+ depends_lib-append port:boost+python25
+ }
+ depends_lib-append port:python25
}
variant python26 description {build python 2.6 support} conflicts python25 {
- set pyversion 2.6
- depends_lib-delete port:boost
- depends_lib-append port:boost+python26 \
- port:python[strsed ${pyversion} {g/[.]//}]
+ set pyversion 2.6
+ if {[variant_isset icu]} {
+ depends_lib-delete port:boost+icu
+ depends_lib-append port:boost+icu+python26
+ } 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
diff --git a/doc/NEWS b/doc/NEWS
index d640f445..1d4826dc 100644
--- a/doc/NEWS
+++ b/doc/NEWS
@@ -1,4 +1,4 @@
- Ledger NEWS
+ Ledger NEWS
* 3.0
@@ -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":
@@ -291,7 +308,7 @@ features, please see the manual.
monthly costs report, for example, because it makes the
following command possible:
- ledger -M --only "a>100" reg ^Expenses:Food
+ ledger -M --only "a>100" reg ^Expenses:Food
This shows only *months* whose amount is greater than 100. If
--limit had been used, it would have been a monthly summary of
@@ -303,7 +320,7 @@ features, please see the manual.
This predicate does not constrain calculation, but only display.
Consider the same command as above:
- ledger -M --display "a>100" reg ^Expenses:Food
+ ledger -M --display "a>100" reg ^Expenses:Food
This displays only lines whose amount is greater than 100, *yet
the running total still includes amounts from all transactions*.
@@ -311,7 +328,7 @@ features, please see the manual.
the current month's checking register while still giving a
correct ending balance:
- ledger --display "d>[this month]" reg Checking
+ ledger --display "d>[this month]" reg Checking
Note that these predicates can be combined. Here is a report that
considers only food bills whose individual cost is greater than
@@ -320,8 +337,8 @@ features, please see the manual.
retain an accurate running total with respect to the entire ledger
file:
- ledger -M --limit "a>20" --only "a>200" \
- --display "year == yearof([last year])" reg ^Expenses:Food
+ ledger -M --limit "a>20" --only "a>200" \
+ --display "year == yearof([last year])" reg ^Expenses:Food
- Added new "--descend AMOUNT" and "--descend-if VALEXPR" reporting
options. For any reports that display valued transactions (i.e.,
@@ -398,12 +415,12 @@ features, please see the manual.
G gain_total
U(x) abs(x)
S(x) quant(x), quantity(x)
- comm(x), commodity(x)
- setcomm(x,y), set_commodity(x,y)
+ comm(x), commodity(x)
+ setcomm(x,y), set_commodity(x,y)
A(x) mean(x), avg(x), average(x)
P(x,y) val(x,y), value(x,y)
- min(x,y)
- max(x,y)
+ min(x,y)
+ max(x,y)
- There are new "parse" and "expr" commands, whose argument is a
single value expression. Ledger will simply print out the result of
@@ -554,10 +571,10 @@ features, please see the manual.
the following is now supported, which wasn't previously:
2004/06/21 Adjustment
- Retirement 100 FUNDA
- Retirement 200 FUNDB
- Retirement 300 FUNDC
- Equity:Adjustments
+ Retirement 100 FUNDA
+ Retirement 200 FUNDB
+ Retirement 300 FUNDC
+ Equity:Adjustments
- Fixed several bugs relating to QIF parsing, budgeting and
forecasting.
diff --git a/doc/README b/doc/README
index 8f83ef39..190436a2 100644
--- a/doc/README
+++ b/doc/README
@@ -1,7 +1,7 @@
- Welcome to Ledger
+ Welcome to Ledger
- the command-line accounting program
+ the command-line accounting program
Introduction
============
diff --git a/doc/grammar.y b/doc/grammar.y
index 018e7391..9a5f740b 100644
--- a/doc/grammar.y
+++ b/doc/grammar.y
@@ -53,7 +53,7 @@ journal_item:
whitespace:
EOL |
WHITESPACE EOL |
- ';' TEXT EOL | /* these next four are all ignored */
+ ';' TEXT EOL | /* these next four are all ignored */
'*' TEXT EOL |
;
@@ -70,23 +70,23 @@ word_directive:
"end" |
"alias" STRING '=' TEXT |
"def" TEXT |
- TEXT WHITESPACE TEXT /* looked up in session (aka maybe Python) */
+ TEXT WHITESPACE TEXT /* looked up in session (aka maybe Python) */
;
char_directive:
- 'i' date time TEXT | /* a timeclock.el "check in" */
+ 'i' date time TEXT | /* a timeclock.el "check in" */
'I' date time TEXT |
- 'o' date time TEXT | /* a timeclock.el "check out" */
+ 'o' date time TEXT | /* a timeclock.el "check out" */
'O' date time TEXT |
'h' TEXT EOL |
'b' TEXT EOL |
- 'D' amount | /* sets display parameters for a commodity */
- 'A' TEXT | /* sets the "default balancing account" */
- 'C' commodity '=' amount | /* specifies a commodity conversion */
+ 'D' amount | /* sets display parameters for a commodity */
+ 'A' TEXT | /* sets the "default balancing account" */
+ 'C' commodity '=' amount | /* specifies a commodity conversion */
'P' date time commodity amount | /* a pricing history xact */
- 'N' commodity | /* commodity's price is never downloaded */
- 'Y' INT4 | /* sets the default year for date parsing */
- '-' '-' STRING TEXT | /* specify command-line options in the file */
+ 'N' commodity | /* commodity's price is never downloaded */
+ 'Y' INT4 | /* sets the default year for date parsing */
+ '-' '-' STRING TEXT | /* specify command-line options in the file */
;
date: INT4 date_sep INT2 date_sep INT2 ;
@@ -210,7 +210,7 @@ values_opt:
price_opt: price | /* epsilon */ ;
price:
'@' amount_expr |
- '@@' amount_expr /* in this case, it's the whole price */
+ '@@' amount_expr /* in this case, it's the whole price */
;
account:
diff --git a/doc/ledger.1 b/doc/ledger.1
index 5a91ceb2..5a3bd6db 100644
--- a/doc/ledger.1
+++ b/doc/ledger.1
@@ -1,4 +1,4 @@
-.Dd February 2, 2010
+.Dd June 22, 2010
.Dt ledger 1
.Sh NAME
.Nm ledger
@@ -53,7 +53,7 @@ Also show accounts whose total is zero.
Rather than display a hierarchical tree, flatten the report to show subtotals
for only accounts matching
.Ar report-query .
-.It Fl \-no\-total
+.It Fl \-no-total
Suppress the summary total shown at the bottom of the report (when not zero).
.El
.Pp
@@ -263,6 +263,7 @@ transactions they are contained in. See the manual for more information.
.It Fl \-account Ar STR
.It Fl \-account-width Ar INT
.It Fl \-actual Pq Fl L
+.It Fl \-actual-dates
.It Fl \-add-budget
.It Fl \-amount Ar EXPR Pq Fl t
.It Fl \-amount-data Pq Fl j
@@ -274,9 +275,13 @@ 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
+.It Fl \-cache Ar FILE
.It Fl \-cleared Pq Fl C
+.It Fl \-cleared-format Ar FMT
.It Fl \-collapse Pq Fl n
.It Fl \-collapse-if-zero
.It Fl \-color
@@ -284,12 +289,16 @@ transactions they are contained in. See the manual for more information.
.It Fl \-cost
See
.Fl \-basis .
+.It Fl \-count
.It Fl \-csv-format Ar FMT
.It Fl \-current Pq Fl c
.It Fl \-daily
+.It Fl \-date Ar EXPR
.It Fl \-date-format Ar DATEFMT Pq Fl y
+.It Fl \-datetime-format Ar FMT
.It Fl \-date-width Ar INT
.It Fl \-debug Ar STR
+.It Fl \-decimal-comma
.It Fl \-depth Ar INT
.It Fl \-deviation Pq Fl D
.It Fl \-display Ar EXPR Pq Fl d
@@ -308,14 +317,27 @@ See
See
.Fl \-head .
.It Fl \-flat
+.It Fl \-force-color
+.It Fl \-force-pager
.It Fl \-forecast-while Ar EXPR
(Also
.Fl \-forecast
).
+.It Fl \-forecast-years Ar INT
.It Fl \-format Ar FMT Pq Fl F
+.It Fl \-full-help
.It Fl \-gain Pq Fl G
+.It Fl \-generated
+.It Fl \-group-by Ar EXPR
+.It Fl \-group-title-format Ar FMT
.It Fl \-head Ar INT
+.It Fl \-help
+.It Fl \-help-calc
+.It Fl \-help-comm
+.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
@@ -329,26 +351,37 @@ See
.It Fl \-lots
.It Fl \-lots-actual
.It Fl \-market Pq Fl V
+.It Fl \-master-account Ar STR
+.It Fl \-meta Ar EXPR
+.It Fl \-meta-width Ar INT
.It Fl \-monthly Pq Fl M
+.It Fl \-no-color
+.It Fl \-no-rounding
+.It Fl \-no-titles
+.It Fl \-no-total
+.It Fl \-now Ar DATE
.It Fl \-only Ar EXPR
+.It Fl \-options
.It Fl \-output Ar FILE Pq Fl o
.It Fl \-pager Ar STR
+.It Fl \-payee
.It Fl \-payee-width Ar INT
.It Fl \-pending
-.It Fl \-percentage Pq Fl \%
+.It Fl \-percent Pq Fl \%
.It Fl \-period Ar PERIOD Pq Fl p
.It Fl \-period-sort
.It Fl \-pivot Ar STR
.It Fl \-plot-amount-format Ar FMT
.It Fl \-plot-total-format Ar FMT
+.It Fl \-prepend-format Ar FMT
+.It Fl \-prepend-width Ar INT
.It Fl \-price Pq Fl I
.It Fl \-price-db Ar FILE
.It Fl \-price-exp Ar STR
See
.Fl \-leeway .
.It Fl \-prices-format Ar FMT
-.It Fl \-pricesdb-format Ar FMT
-.It Fl \-print-format Ar FMT
+.It Fl \-pricedb-format Ar FMT
.It Fl \-quantity Pq Fl O
.It Fl \-quarterly
.It Fl \-raw
@@ -365,9 +398,6 @@ appeared in the original journal file.
.It Fl \-revalued-total Ar EXPR
.It Fl \-seed Ar INT
.It Fl \-script
-.It Fl \-set-account Ar EXPR
-.It Fl \-set-payee Ar EXPR
-.It Fl \-set-price Ar EXPR
.It Fl \-sort Ar EXPR Pq Fl S
.It Fl \-sort-all
.It Fl \-sort-xacts
@@ -382,6 +412,9 @@ appeared in the original journal file.
.It Fl \-truncate
.It Fl \-unbudgeted
.It Fl \-uncleared Pq Fl U
+.It Fl \-unrealized
+.It Fl \-unrealized-gains
+.It Fl \-unrealized-losses
.It Fl \-unround
.It Fl \-verbose
.It Fl \-verify
diff --git a/doc/ledger.texi b/doc/ledger.texi
index 0a0224dc..ac7bfc5f 100644
--- a/doc/ledger.texi
+++ b/doc/ledger.texi
@@ -35,7 +35,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@end copying
-@documentencoding utf-8
+@documentencoding UTF-8
@iftex
@finalout
@@ -122,27 +122,13 @@ general ledger you need to record a payment to Pacific Bell for your
monthly phone bill. The cost is $23.00, let's say, and you want to
pay it from your checking account. In the general ledger you need to
say where the money came from, in addition to where it's going to.
-The transaction might look like this:
+Such a transaction might look like this:
@smallexample
-9/29 BAL Pacific Bell $-200.00 $-200.00
- Equity:Opening Balances $200.00
-9/29 BAL Checking $100.00 $100.00
- Equity:Opening Balances $-100.00
-9/29 100 Pacific Bell $23.00 $223.00
- Checking $-23.00 $77.00
+9/29 Pacific Bell $23.00 $23.00
+ Checking $-23.00 0
@end smallexample
-The first line shows a payment to Pacific Bell for $23.00. Because
-there is no ``balance'' in a general ledger---it's always zero---we
-write in the total balance of all payments to ``Pacific Bell'', which
-now is $223.00 (previously the balance was $200.00). This is done by
-looking at the last transaction for ``Pacific Bell'' in the ledger, adding
-$23.00 to that amount, and writing the total in the balance column.
-And the money came from ``Checking''---a withdrawal of $23.00---which
-leaves the ending balance in ``Checking'' at $77.00. This is a very
-manual procedure; but that's where computers come in...
-
The posting must balance to $0: $23 went to Pacific Bell, $23 came
from Checking. There is nothing left over to be accounted for, since
the money has simply moved from one account to another. This is the
@@ -174,16 +160,8 @@ formatting as the ledger program wishes to see them:
@smallexample
2004/09/29 Pacific Bell
- Payable:Pacific Bell $-200.00
- Equity:Opening Balances
-
-2004/09/29 Checking
- Accounts:Checking $100.00
- Equity:Opening Balances
-
-2004/09/29 Pacific Bell
- Payable:Pacific Bell $23.00
- Accounts:Checking
+ Expenses:Pacific Bell $23.00
+ Assets:Checking
@end smallexample
The account balances and registers in this file, if saved as
@@ -503,8 +481,8 @@ and exits. This is useful for sending bug reports, to let the author
know which version of ledger you are using.
@option{--file FILE} (@option{-f FILE}) reads FILE as a ledger file.
-This command may be used multiple times. FILE may also be a list of
-file names separated by colons. Typically, the environment variable
+This command may be used multiple times.
+Typically, the environment variable
@env{LEDGER_FILE} is set, rather than using this command-line option.
@option{--output FILE} (@option{-o FILE}) redirects output from any
@@ -514,11 +492,12 @@ output.
@option{--init-file FILE} (@option{-i FILE}) causes FILE to be read by
ledger before any other ledger file. This file may not contain any
postings, but it may contain option settings. To specify options
-in the init file, use the same syntax as the command-line. Here's an
-example init file:
+in the init file, use the same syntax as the command-line, but put each
+option on it's own line. Here's an example init file:
@smallexample
--price-db ~/finance/.pricedb
+--cache /tmp/ledger-cache
; ~/.ledgerrc ends here
@end smallexample
@@ -829,6 +808,8 @@ option settings in the file @file{~/.ledgerrc}, for example:
@example
--cache /tmp/.mycache
+--pager /bin/cat
+
@end example
@node Period expressions, Format strings, Options, Quick Reference
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
new file mode 100644
index 00000000..1f875764
--- /dev/null
+++ b/doc/ledger3.texi
@@ -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
diff --git a/lib/Makefile b/lib/Makefile
index 14605176..3f399e58 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -2,32 +2,59 @@
# This is only important if you intend to produce a Ledger binary for
# installation.
-STOW_ROOT = /usr/local/stow
-PRODUCTS = $(HOME)/Products
-
-CC = gcc-mp-4.4
-CXX = g++-mp-4.4
-LD = gcc-mp-4.4
-CPPFLAGS = -D_GLIBCXX_DEBUG=1 -D_GLIBCXX_FULLY_DYNAMIC_STRING=1
-CFLAGS = $(CPPFLAGS) -g
-LDFLAGS = -g
-
-BOOST_VERSION = 1_43_0
-BOOST_SOURCE = boost_$(BOOST_VERSION)
-BOOST_TOOLSET = darwin
-BOOST_DEFINES = define=_GLIBCXX_DEBUG=1 define=_GLIBCXX_FULLY_DYNAMIC_STRING=1
-#BOOST_FLAGS = --architecture=x86 --address_model=32_64
-BOOST_FLAGS = --toolset=$(BOOST_TOOLSET) \
- --build-type=complete --layout=versioned \
- $(BOOST_DEFINES)
-ICU_FLAGS = -sHAVE_ICU=1 -sICU_PATH=$(STOW_ROOT)/icu
-
-all: boost-build cppunit-build icu-build boost-icu-build
-
-boost-build:
+STOW_ROOT = /usr/local/stow
+PRODUCTS = $(HOME)/Products
+
+CC = gcc-mp-4.5
+ifeq ($(CC),clang)
+CXX = clang++
+LD = llvm-ld
+DIR_SUFFIX = clang
+OPTJ =
+else
+CXX = g++-mp-4.5
+LD = gcc-mp-4.5
+DIR_SUFFIX = gcc45
+OPTJ = #-j16
+endif
+CPPFLAGS = -D_GLIBCXX_FULLY_DYNAMIC_STRING=1
+ifneq ($(CC),clang)
+CPPFLAGS += -D_GLIBCXX_DEBUG=1
+endif
+CFLAGS = $(CPPFLAGS) -g
+LDFLAGS = -g
+
+BOOST_VERSION = 1_45_0
+BOOST_SOURCE = boost-release
+BOOST_DEFINES = define=_GLIBCXX_FULLY_DYNAMIC_STRING=1
+ifeq ($(CC),clang)
+BOOST_TOOLSET = clang
+else
+BOOST_TOOLSET = darwin
+BOOST_DEFINES = define=_GLIBCXX_DEBUG=1
+endif
+#BOOST_FLAGS = --architecture=x86 --address_model=32_64
+BOOST_FLAGS = --toolset=$(BOOST_TOOLSET) \
+ --build-type=complete --layout=versioned \
+ $(BOOST_DEFINES)
+BOOST_DIR = boost_$(BOOST_VERSION)-$(DIR_SUFFIX)
+BOOST_STOW = $(STOW_ROOT)/$(BOOST_DIR)
+BOOST_BUILD = $(PRODUCTS)/$(BOOST_DIR)
+ICU_FLAGS = -sHAVE_ICU=1 -sICU_PATH=$(STOW_ROOT)/icu
+BOOST_ICU_DIR = boost_$(BOOST_VERSION)-icu-$(DIR_SUFFIX)
+BOOST_ICU_STOW = $(STOW_ROOT)/$(BOOST_ICU_DIR)
+BOOST_ICU_BUILD = $(PRODUCTS)/$(BOOST_ICU_DIR)
+
+all: boost-build cppunit-build #icu-build boost-icu-build
+
+prepare-boost:
+ perl -i -pe 's/local command = \[ common\.get-invocation-command darwin : g\+\+ : \$$\(command\) \] ;/local command = [ common.get-invocation-command darwin : g++ : $(CXX) ] ;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam
+ perl -i -pe 's/flags darwin\.compile OPTIONS : -no-cpp-precomp -gdwarf-2 ;/flags darwin\.compile OPTIONS : -gdwarf-2 ;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam
+
+boost-build: prepare-boost
(cd $(BOOST_SOURCE) && \
- bjam debug --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION) \
- --build-dir=$(PRODUCTS)/boost_$(BOOST_VERSION) \
+ sh bootstrap.sh && \
+ ./bjam $(OPTJ) debug --prefix=$(BOOST_STOW) --build-dir=$(BOOST_BUILD) \
$(BOOST_FLAGS) install)
cppunit-build:
@@ -37,23 +64,34 @@ cppunit-build:
CFLAGS="$(CFLAGS)" \
LDFLAGS="$(LDFLAGS)" \
CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \
- --prefix=$(STOW_ROOT)/cppunit \
+ --prefix=$(STOW_ROOT)/cppunit-$(DIR_SUFFIX) \
--disable-doxygen --disable-dot && \
make install)
-icu-build:
+#icu-build:
+# -(cd icu/source; make distclean)
+# (cd icu/source; sh autogen.sh; \
+# ./configure CPPFLAGS="$(CPPFLAGS)" \
+# CFLAGS="$(CFLAGS)" \
+# LDFLAGS="$(LDFLAGS)" \
+# CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \
+# --enable-static --enable-debug \
+# --prefix=$(STOW_ROOT)/icu-$(DIR_SUFFIX) && \
+# make install)
+#
+#boost-icu-build:
+# (cd $(BOOST_SOURCE) && \
+# bjam debug --prefix=$(BOOST_ICU_STOW) --build-dir=$(BOOST_ICU_BUILD) \
+# $(BOOST_FLAGS) $(ICU_FLAGS) install)
+
+clean:
+ -rm -fr $(BOOST_STOW) $(BOOST_BUILD)
+ -rm -fr $(BOOST_ICU_STOW) $(BOOST_ICU_BUILD)
+ -rm -fr $(STOW_ROOT)/cppunit-$(DIR_SUFFIX)
+ -rm -fr $(STOW_ROOT)/icu-$(DIR_SUFFIX)
+ -(cd cppunit; make distclean)
-(cd icu/source; make distclean)
- (cd icu/source; sh autogen.sh; \
- ./configure CPPFLAGS="$(CPPFLAGS)" \
- CFLAGS="$(CFLAGS)" \
- LDFLAGS="$(LDFLAGS)" \
- CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \
- --enable-static --enable-debug \
- --prefix=$(STOW_ROOT)/icu && \
- make install)
-boost-icu-build:
- (cd $(BOOST_SOURCE) && \
- bjam debug --prefix=$(STOW_ROOT)/boost_$(BOOST_VERSION)-icu \
- --build-dir=$(PRODUCTS)/boost_$(BOOST_VERSION)-icu \
- $(BOOST_FLAGS) $(ICU_FLAGS) install)
+lib-clean:
+ -(cd cppunit; make distclean)
+ -(cd icu/source; make distclean)
diff --git a/lib/utfcpp b/lib/utfcpp
-Subproject 200cf64535a8a2545414e993349f6c87c8dd64b
+Subproject e1100092ff1b6f9d0fd6af9c4f38360989f05e7
diff --git a/lisp/ldg-complete.el b/lisp/ldg-complete.el
index 33a734b3..7b4b0471 100644
--- a/lisp/ldg-complete.el
+++ b/lisp/ldg-complete.el
@@ -8,46 +8,46 @@
(let ((here (point)))
(goto-char (line-beginning-position))
(cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+")
- (goto-char (match-end 0))
- 'entry)
- ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)")
- (goto-char (match-beginning 2))
- 'transaction)
- ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+")
- (goto-char (match-end 0))
- 'entry)
- (t
- (ignore (goto-char here))))))
+ (goto-char (match-end 0))
+ 'entry)
+ ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)")
+ (goto-char (match-beginning 2))
+ 'transaction)
+ ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+")
+ (goto-char (match-end 0))
+ 'entry)
+ (t
+ (ignore (goto-char here))))))
(defun ledger-parse-arguments ()
"Parse whitespace separated arguments in the current region."
(let* ((info (save-excursion
- (cons (ledger-thing-at-point) (point))))
- (begin (cdr info))
- (end (point))
- begins args)
+ (cons (ledger-thing-at-point) (point))))
+ (begin (cdr info))
+ (end (point))
+ begins args)
(save-excursion
(goto-char begin)
(when (< (point) end)
- (skip-chars-forward " \t\n")
- (setq begins (cons (point) begins))
- (setq args (cons (buffer-substring-no-properties
- (car begins) end)
- args)))
+ (skip-chars-forward " \t\n")
+ (setq begins (cons (point) begins))
+ (setq args (cons (buffer-substring-no-properties
+ (car begins) end)
+ args)))
(cons (reverse args) (reverse begins)))))
(defun ledger-entries ()
(let ((origin (point))
- entries-list)
+ entries-list)
(save-excursion
(goto-char (point-min))
(while (re-search-forward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
- (unless (and (>= origin (match-beginning 0))
- (< origin (match-end 0)))
- (setq entries-list (cons (match-string-no-properties 3)
- entries-list)))))
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (unless (and (>= origin (match-beginning 0))
+ (< origin (match-end 0)))
+ (setq entries-list (cons (match-string-no-properties 3)
+ entries-list)))))
(pcomplete-uniqify-list (nreverse entries-list))))
(defvar ledger-account-tree nil)
@@ -58,99 +58,99 @@
(setq ledger-account-tree (list t))
(goto-char (point-min))
(while (re-search-forward
- "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t)
- (unless (and (>= origin (match-beginning 0))
- (< origin (match-end 0)))
- (setq account-path (match-string-no-properties 2))
- (setq elements (split-string account-path ":"))
- (let ((root ledger-account-tree))
- (while elements
- (let ((entry (assoc (car elements) root)))
- (if entry
- (setq root (cdr entry))
- (setq entry (cons (car elements) (list t)))
- (nconc root (list entry))
- (setq root (cdr entry))))
- (setq elements (cdr elements)))))))))
+ "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t)
+ (unless (and (>= origin (match-beginning 0))
+ (< origin (match-end 0)))
+ (setq account-path (match-string-no-properties 2))
+ (setq elements (split-string account-path ":"))
+ (let ((root ledger-account-tree))
+ (while elements
+ (let ((entry (assoc (car elements) root)))
+ (if entry
+ (setq root (cdr entry))
+ (setq entry (cons (car elements) (list t)))
+ (nconc root (list entry))
+ (setq root (cdr entry))))
+ (setq elements (cdr elements)))))))))
(defun ledger-accounts ()
(ledger-find-accounts)
(let* ((current (caar (ledger-parse-arguments)))
- (elements (and current (split-string current ":")))
- (root ledger-account-tree)
- (prefix nil))
+ (elements (and current (split-string current ":")))
+ (root ledger-account-tree)
+ (prefix nil))
(while (cdr elements)
(let ((entry (assoc (car elements) root)))
- (if entry
- (setq prefix (concat prefix (and prefix ":")
- (car elements))
- root (cdr entry))
- (setq root nil elements nil)))
+ (if entry
+ (setq prefix (concat prefix (and prefix ":")
+ (car elements))
+ root (cdr entry))
+ (setq root nil elements nil)))
(setq elements (cdr elements)))
(and root
- (sort
- (mapcar (function
- (lambda (x)
- (let ((term (if prefix
- (concat prefix ":" (car x))
- (car x))))
- (if (> (length (cdr x)) 1)
- (concat term ":")
- term))))
- (cdr root))
- 'string-lessp))))
+ (sort
+ (mapcar (function
+ (lambda (x)
+ (let ((term (if prefix
+ (concat prefix ":" (car x))
+ (car x))))
+ (if (> (length (cdr x)) 1)
+ (concat term ":")
+ term))))
+ (cdr root))
+ 'string-lessp))))
(defun ledger-complete-at-point ()
"Do appropriate completion for the thing at point"
(interactive)
(while (pcomplete-here
- (if (eq (save-excursion
- (ledger-thing-at-point)) 'entry)
- (if (null current-prefix-arg)
- (ledger-entries) ; this completes against entry names
- (progn
- (let ((text (buffer-substring (line-beginning-position)
- (line-end-position))))
- (delete-region (line-beginning-position)
- (line-end-position))
- (condition-case err
- (ledger-add-entry text t)
- ((error)
- (insert text))))
- (forward-line)
- (goto-char (line-end-position))
- (search-backward ";" (line-beginning-position) t)
- (skip-chars-backward " \t0123456789.,")
- (throw 'pcompleted t)))
- (ledger-accounts)))))
+ (if (eq (save-excursion
+ (ledger-thing-at-point)) 'entry)
+ (if (null current-prefix-arg)
+ (ledger-entries) ; this completes against entry names
+ (progn
+ (let ((text (buffer-substring (line-beginning-position)
+ (line-end-position))))
+ (delete-region (line-beginning-position)
+ (line-end-position))
+ (condition-case err
+ (ledger-add-entry text t)
+ ((error)
+ (insert text))))
+ (forward-line)
+ (goto-char (line-end-position))
+ (search-backward ";" (line-beginning-position) t)
+ (skip-chars-backward " \t0123456789.,")
+ (throw 'pcompleted t)))
+ (ledger-accounts)))))
(defun ledger-fully-complete-entry ()
"Do appropriate completion for the thing at point"
(interactive)
(let ((name (caar (ledger-parse-arguments)))
- xacts)
+ xacts)
(save-excursion
(when (eq 'entry (ledger-thing-at-point))
- (when (re-search-backward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t)
- (forward-line)
- (while (looking-at "^\\s-+")
- (setq xacts (cons (buffer-substring-no-properties
- (line-beginning-position)
- (line-end-position))
- xacts))
- (forward-line))
- (setq xacts (nreverse xacts)))))
+ (when (re-search-backward
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (forward-line)
+ (while (looking-at "^\\s-+")
+ (setq xacts (cons (buffer-substring-no-properties
+ (line-beginning-position)
+ (line-end-position))
+ xacts))
+ (forward-line))
+ (setq xacts (nreverse xacts)))))
(when xacts
(save-excursion
- (insert ?\n)
- (while xacts
- (insert (car xacts) ?\n)
- (setq xacts (cdr xacts))))
+ (insert ?\n)
+ (while xacts
+ (insert (car xacts) ?\n)
+ (setq xacts (cdr xacts))))
(forward-line)
(goto-char (line-end-position))
(if (re-search-backward "\\(\t\\| [ \t]\\)" nil t)
- (goto-char (match-end 0))))))
+ (goto-char (match-end 0))))))
(provide 'ldg-complete)
diff --git a/lisp/ldg-exec.el b/lisp/ldg-exec.el
index 3881f8e9..bf3565b4 100644
--- a/lisp/ldg-exec.el
+++ b/lisp/ldg-exec.el
@@ -12,15 +12,15 @@
(if (null ledger-binary-path)
(error "The variable `ledger-binary-path' has not been set"))
(let ((buf (or input-buffer (current-buffer)))
- (outbuf (or output-buffer
- (generate-new-buffer " *ledger-tmp*"))))
+ (outbuf (or output-buffer
+ (generate-new-buffer " *ledger-tmp*"))))
(with-current-buffer buf
(let ((coding-system-for-write 'utf-8)
- (coding-system-for-read 'utf-8))
- (apply #'call-process-region
- (append (list (point-min) (point-max)
- ledger-binary-path nil outbuf nil "-f" "-")
- args)))
+ (coding-system-for-read 'utf-8))
+ (apply #'call-process-region
+ (append (list (point-min) (point-max)
+ ledger-binary-path nil outbuf nil "-f" "-")
+ args)))
outbuf)))
(defun ledger-exec-read (&optional input-buffer &rest args)
@@ -28,7 +28,7 @@
(apply #'ledger-exec-ledger input-buffer nil "emacs" args)
(goto-char (point-min))
(prog1
- (read (current-buffer))
+ (read (current-buffer))
(kill-buffer (current-buffer)))))
(provide 'ldg-exec)
diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el
index 973b891c..3e9a9106 100644
--- a/lisp/ldg-mode.el
+++ b/lisp/ldg-mode.el
@@ -5,13 +5,13 @@
(defvar bold 'bold)
(defvar ledger-font-lock-keywords
- '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face)
- ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold)
- ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)"
+ '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face)
+ ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold)
+ ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)"
;; 2 font-lock-type-face)
("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*:
- ]+?:[^]);
- ]+?\\([])]\\)?\\)\\( \\| \\|$\\)"
+ ]+?:[^]);
+ ]+?\\([])]\\)?\\)\\( \\| \\|$\\)"
2 font-lock-keyword-face)
("^\\([~=].+\\)" 1 font-lock-function-name-face)
("^\\([A-Za-z]+ .+\\)" 1 font-lock-function-name-face))
@@ -30,7 +30,7 @@
(if (boundp 'font-lock-defaults)
(set (make-local-variable 'font-lock-defaults)
- '(ledger-font-lock-keywords nil t)))
+ '(ledger-font-lock-keywords nil t)))
(set (make-local-variable 'pcomplete-parse-arguments-function)
'ledger-parse-arguments)
@@ -56,58 +56,58 @@
"Say whether time value T1 is less than time value T2."
(or (< (car t1) (car t2))
(and (= (car t1) (car t2))
- (< (nth 1 t1) (nth 1 t2)))))
+ (< (nth 1 t1) (nth 1 t2)))))
(defun ledger-time-subtract (t1 t2)
"Subtract two time values.
Return the difference in the format of a time value."
(let ((borrow (< (cadr t1) (cadr t2))))
(list (- (car t1) (car t2) (if borrow 1 0))
- (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
+ (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
(defun ledger-find-slot (moment)
(catch 'found
(ledger-iterate-entries
(function
(lambda (start date mark desc)
- (if (ledger-time-less-p moment date)
- (throw 'found t)))))))
+ (if (ledger-time-less-p moment date)
+ (throw 'found t)))))))
(defun ledger-add-entry (entry-text &optional insert-at-point)
(interactive "sEntry: ")
(let* ((args (with-temp-buffer
- (insert entry-text)
- (eshell-parse-arguments (point-min) (point-max))))
- (ledger-buf (current-buffer))
- exit-code)
+ (insert entry-text)
+ (eshell-parse-arguments (point-min) (point-max))))
+ (ledger-buf (current-buffer))
+ exit-code)
(unless insert-at-point
(let ((date (car args)))
- (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
- (setq date
- (encode-time 0 0 0 (string-to-number (match-string 3 date))
- (string-to-number (match-string 2 date))
- (string-to-number (match-string 1 date)))))
- (ledger-find-slot date)))
+ (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
+ (setq date
+ (encode-time 0 0 0 (string-to-number (match-string 3 date))
+ (string-to-number (match-string 2 date))
+ (string-to-number (match-string 1 date)))))
+ (ledger-find-slot date)))
(save-excursion
(insert
(with-temp-buffer
- (setq exit-code
- (apply #'ledger-run-ledger ledger-buf "entry"
- (mapcar 'eval args)))
- (goto-char (point-min))
- (if (looking-at "Error: ")
- (error (buffer-string))
- (buffer-string)))
+ (setq exit-code
+ (apply #'ledger-run-ledger ledger-buf "entry"
+ (mapcar 'eval args)))
+ (goto-char (point-min))
+ (if (looking-at "Error: ")
+ (error (buffer-string))
+ (buffer-string)))
"\n"))))
(defun ledger-current-entry-bounds ()
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
+ (re-search-backward "^[0-9]" nil t))
(let ((beg (point)))
- (while (not (eolp))
- (forward-line))
- (cons (copy-marker beg) (point-marker))))))
+ (while (not (eolp))
+ (forward-line))
+ (cons (copy-marker beg) (point-marker))))))
(defun ledger-delete-current-entry ()
(interactive)
diff --git a/lisp/ldg-post.el b/lisp/ldg-post.el
index 492f9467..da4a2806 100644
--- a/lisp/ldg-post.el
+++ b/lisp/ldg-post.el
@@ -26,14 +26,14 @@
(defun ledger-post-all-accounts ()
(let ((origin (point))
- (ledger-post-list nil)
- account elements)
+ (ledger-post-list nil)
+ account elements)
(save-excursion
(goto-char (point-min))
(while (re-search-forward ledger-post-line-regexp nil t)
- (unless (and (>= origin (match-beginning 0))
- (< origin (match-end 0)))
- (add-to-list 'ledger-post-list (ledger-regex-post-line-account))))
+ (unless (and (>= origin (match-beginning 0))
+ (< origin (match-end 0)))
+ (add-to-list 'ledger-post-list (ledger-regex-post-line-account))))
(nreverse ledger-post-list))))
(declare-function iswitchb-read-buffer "iswitchb"
@@ -47,9 +47,9 @@ to choose from."
(cond
(ledger-post-use-iswitchb
(let* ((iswitchb-use-virtual-buffers nil)
- (iswitchb-make-buflist-hook
- (lambda ()
- (setq iswitchb-temp-buflist choices))))
+ (iswitchb-make-buflist-hook
+ (lambda ()
+ (setq iswitchb-temp-buflist choices))))
(iswitchb-read-buffer prompt)))
(ledger-post-use-ido
(ido-completing-read prompt choices))
@@ -61,26 +61,26 @@ to choose from."
(defun ledger-post-pick-account ()
(interactive)
(let* ((account
- (ledger-post-completing-read
- "Account: " (or ledger-post-current-list
- (setq ledger-post-current-list
- (ledger-post-all-accounts)))))
- (account-len (length account))
- (pos (point)))
+ (ledger-post-completing-read
+ "Account: " (or ledger-post-current-list
+ (setq ledger-post-current-list
+ (ledger-post-all-accounts)))))
+ (account-len (length account))
+ (pos (point)))
(goto-char (line-beginning-position))
(when (re-search-forward ledger-post-line-regexp (line-end-position) t)
(let ((existing-len (length (ledger-regex-post-line-account))))
- (goto-char (match-beginning ledger-regex-post-line-group-account))
- (delete-region (match-beginning ledger-regex-post-line-group-account)
- (match-end ledger-regex-post-line-group-account))
- (insert account)
- (cond
- ((> existing-len account-len)
- (insert (make-string (- existing-len account-len) ? )))
- ((< existing-len account-len)
- (dotimes (n (- account-len existing-len))
- (if (looking-at "[ \t]\\( [ \t]\\|\t\\)")
- (delete-char 1)))))))
+ (goto-char (match-beginning ledger-regex-post-line-group-account))
+ (delete-region (match-beginning ledger-regex-post-line-group-account)
+ (match-end ledger-regex-post-line-group-account))
+ (insert account)
+ (cond
+ ((> existing-len account-len)
+ (insert (make-string (- existing-len account-len) ? )))
+ ((< existing-len account-len)
+ (dotimes (n (- account-len existing-len))
+ (if (looking-at "[ \t]\\( [ \t]\\|\t\\)")
+ (delete-char 1)))))))
(goto-char pos)))
(defun ledger-next-amount (&optional end)
@@ -88,7 +88,7 @@ to choose from."
(goto-char (match-beginning 0))
(skip-syntax-forward " ")
(- (or (match-end 4)
- (match-end 3)) (point))))
+ (match-end 3)) (point))))
(defun ledger-align-amounts (&optional column)
"Align amounts in the current region.
@@ -98,24 +98,24 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
(setq column ledger-post-amount-alignment-column))
(save-excursion
(let* ((mark-first (< (mark) (point)))
- (begin (if mark-first (mark) (point)))
- (end (if mark-first (point-marker) (mark-marker)))
- offset)
+ (begin (if mark-first (mark) (point)))
+ (end (if mark-first (point-marker) (mark-marker)))
+ offset)
(goto-char begin)
(while (setq offset (ledger-next-amount end))
- (let ((col (current-column))
- (target-col (- column offset))
- adjust)
- (setq adjust (- target-col col))
- (if (< col target-col)
- (insert (make-string (- target-col col) ? ))
- (move-to-column target-col)
- (if (looking-back " ")
- (delete-char (- col target-col))
- (skip-chars-forward "^ \t")
- (delete-horizontal-space)
- (insert " ")))
- (forward-line))))))
+ (let ((col (current-column))
+ (target-col (- column offset))
+ adjust)
+ (setq adjust (- target-col col))
+ (if (< col target-col)
+ (insert (make-string (- target-col col) ? ))
+ (move-to-column target-col)
+ (if (looking-back " ")
+ (delete-char (- col target-col))
+ (skip-chars-forward "^ \t")
+ (delete-horizontal-space)
+ (insert " ")))
+ (forward-line))))))
(defun ledger-post-align-amount ()
(interactive)
@@ -130,7 +130,7 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
(when (< end (line-end-position))
(goto-char (line-beginning-position))
(if (looking-at ledger-post-line-regexp)
- (ledger-post-align-amount)))))
+ (ledger-post-align-amount)))))
(defun ledger-post-edit-amount ()
(interactive)
@@ -139,12 +139,12 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
(goto-char (match-end ledger-regex-post-line-group-account))
(when (re-search-forward "[-.,0-9]+" (line-end-position) t)
(let ((val (match-string 0)))
- (goto-char (match-beginning 0))
- (delete-region (match-beginning 0) (match-end 0))
- (calc)
- (while (string-match "," val)
- (setq val (replace-match "" nil nil val)))
- (calc-eval val 'push)))))
+ (goto-char (match-beginning 0))
+ (delete-region (match-beginning 0) (match-end 0))
+ (calc)
+ (while (string-match "," val)
+ (setq val (replace-match "" nil nil val)))
+ (calc-eval val 'push)))))
(defun ledger-post-prev-xact ()
(interactive)
diff --git a/lisp/ldg-reconcile.el b/lisp/ldg-reconcile.el
index 3be882f4..baeadc33 100644
--- a/lisp/ldg-reconcile.el
+++ b/lisp/ldg-reconcile.el
@@ -5,41 +5,41 @@
(defun ledger-display-balance ()
(let ((buffer ledger-buf)
- (account ledger-acct))
+ (account ledger-acct))
(with-temp-buffer
(let ((exit-code (ledger-run-ledger buffer "-C" "balance" account)))
- (if (/= 0 exit-code)
- (message "Error determining cleared balance")
- (goto-char (1- (point-max)))
- (goto-char (line-beginning-position))
- (delete-horizontal-space)
- (message "Cleared balance = %s"
- (buffer-substring-no-properties (point)
- (line-end-position))))))))
+ (if (/= 0 exit-code)
+ (message "Error determining cleared balance")
+ (goto-char (1- (point-max)))
+ (goto-char (line-beginning-position))
+ (delete-horizontal-space)
+ (message "Cleared balance = %s"
+ (buffer-substring-no-properties (point)
+ (line-end-position))))))))
(defun ledger-reconcile-toggle ()
(interactive)
(let ((where (get-text-property (point) 'where))
- (account ledger-acct)
- (inhibit-read-only t)
- cleared)
+ (account ledger-acct)
+ (inhibit-read-only t)
+ cleared)
(when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin"))
(with-current-buffer ledger-buf
- (goto-char (cdr where))
- (setq cleared (ledger-toggle-current 'pending)))
+ (goto-char (cdr where))
+ (setq cleared (ledger-toggle-current 'pending)))
(if cleared
- (add-text-properties (line-beginning-position)
- (line-end-position)
- (list 'face 'bold))
- (remove-text-properties (line-beginning-position)
- (line-end-position)
- (list 'face))))
+ (add-text-properties (line-beginning-position)
+ (line-end-position)
+ (list 'face 'bold))
+ (remove-text-properties (line-beginning-position)
+ (line-end-position)
+ (list 'face))))
(forward-line)))
(defun ledger-reconcile-refresh ()
(interactive)
(let ((inhibit-read-only t)
- (line (count-lines (point-min) (point))))
+ (line (count-lines (point-min) (point))))
(erase-buffer)
(ledger-do-reconcile)
(set-buffer-modified-p t)
@@ -49,9 +49,9 @@
(defun ledger-reconcile-refresh-after-save ()
(let ((buf (get-buffer "*Reconcile*")))
(if buf
- (with-current-buffer buf
- (ledger-reconcile-refresh)
- (set-buffer-modified-p nil)))))
+ (with-current-buffer buf
+ (ledger-reconcile-refresh)
+ (set-buffer-modified-p nil)))))
(defun ledger-reconcile-add ()
(interactive)
@@ -64,12 +64,12 @@
(let ((where (get-text-property (point) 'where)))
(when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin"))
(with-current-buffer ledger-buf
- (goto-char (cdr where))
- (ledger-delete-current-entry))
+ (goto-char (cdr where))
+ (ledger-delete-current-entry))
(let ((inhibit-read-only t))
- (goto-char (line-beginning-position))
- (delete-region (point) (1+ (line-end-position)))
- (set-buffer-modified-p t)))))
+ (goto-char (line-beginning-position))
+ (delete-region (point) (1+ (line-end-position)))
+ (set-buffer-modified-p t)))))
(defun ledger-reconcile-visit ()
(interactive)
@@ -95,12 +95,12 @@
(goto-char (point-min))
(while (not (eobp))
(let ((where (get-text-property (point) 'where))
- (face (get-text-property (point) 'face)))
- (if (and (eq face 'bold)
- (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")))
- (with-current-buffer ledger-buf
- (goto-char (cdr where))
- (ledger-toggle-current 'cleared))))
+ (face (get-text-property (point) 'face)))
+ (if (and (eq face 'bold)
+ (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")))
+ (with-current-buffer ledger-buf
+ (goto-char (cdr where))
+ (ledger-toggle-current 'cleared))))
(forward-line 1)))
(ledger-reconcile-save))
@@ -110,12 +110,12 @@
(defun ledger-reconcile (account)
(interactive "sAccount to reconcile: ")
(let ((buf (current-buffer))
- (rbuf (get-buffer "*Reconcile*")))
+ (rbuf (get-buffer "*Reconcile*")))
(if rbuf
- (kill-buffer rbuf))
+ (kill-buffer rbuf))
(add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save)
(with-current-buffer
- (pop-to-buffer (get-buffer-create "*Reconcile*"))
+ (pop-to-buffer (get-buffer-create "*Reconcile*"))
(ledger-reconcile-mode)
(set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-acct) account)
diff --git a/lisp/ldg-regex.el b/lisp/ldg-regex.el
index 93ef6b09..1c6b8f06 100644
--- a/lisp/ldg-regex.el
+++ b/lisp/ldg-regex.el
@@ -6,112 +6,112 @@
(defmacro ledger-define-regexp (name regex docs &rest args)
"Simplify the creation of a Ledger regex and helper functions."
(let ((defs
- (list
- `(defconst
- ,(intern (concat "ledger-" (symbol-name name) "-regexp"))
- ,(eval regex))))
- (addend 0) last-group)
+ (list
+ `(defconst
+ ,(intern (concat "ledger-" (symbol-name name) "-regexp"))
+ ,(eval regex))))
+ (addend 0) last-group)
(if (null args)
- (progn
- (nconc
- defs
- (list
- `(defconst
- ,(intern
- (concat "ledger-regex-" (symbol-name name) "-group"))
- 1)))
- (nconc
- defs
- (list
- `(defconst
- ,(intern (concat "ledger-regex-" (symbol-name name)
- "-group--count"))
- 1)))
- (nconc
- defs
- (list
- `(defmacro
- ,(intern (concat "ledger-regex-" (symbol-name name)))
- (&optional string)
- ,(format "Return the match string for the %s" name)
- (match-string
- ,(intern (concat "ledger-regex-" (symbol-name name)
- "-group"))
- string)))))
+ (progn
+ (nconc
+ defs
+ (list
+ `(defconst
+ ,(intern
+ (concat "ledger-regex-" (symbol-name name) "-group"))
+ 1)))
+ (nconc
+ defs
+ (list
+ `(defconst
+ ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-group--count"))
+ 1)))
+ (nconc
+ defs
+ (list
+ `(defmacro
+ ,(intern (concat "ledger-regex-" (symbol-name name)))
+ (&optional string)
+ ,(format "Return the match string for the %s" name)
+ (match-string
+ ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-group"))
+ string)))))
(dolist (arg args)
- (let (var grouping target)
- (if (symbolp arg)
- (setq var arg target arg)
- (assert (listp arg))
- (if (= 2 (length arg))
- (setq var (car arg)
- target (cadr arg))
- (setq var (car arg)
- grouping (cadr arg)
- target (caddr arg))))
-
- (if (and last-group
- (not (eq last-group (or grouping target))))
- (incf addend
- (symbol-value
- (intern-soft (concat "ledger-regex-"
- (symbol-name last-group)
- "-group--count")))))
- (nconc
- defs
- (list
- `(defconst
- ,(intern (concat "ledger-regex-" (symbol-name name)
- "-group-" (symbol-name var)))
- ,(+ addend
- (symbol-value
- (intern-soft
- (if grouping
- (concat "ledger-regex-" (symbol-name grouping)
- "-group-" (symbol-name target))
- (concat "ledger-regex-" (symbol-name target)
- "-group"))))))))
- (nconc
- defs
- (list
- `(defmacro
- ,(intern (concat "ledger-regex-" (symbol-name name)
- "-" (symbol-name var)))
- (&optional string)
- ,(format "Return the sub-group match for the %s %s."
- name var)
- (match-string
- ,(intern (concat "ledger-regex-" (symbol-name name)
- "-group-" (symbol-name var)))
- string))))
-
- (setq last-group (or grouping target))))
+ (let (var grouping target)
+ (if (symbolp arg)
+ (setq var arg target arg)
+ (assert (listp arg))
+ (if (= 2 (length arg))
+ (setq var (car arg)
+ target (cadr arg))
+ (setq var (car arg)
+ grouping (cadr arg)
+ target (caddr arg))))
+
+ (if (and last-group
+ (not (eq last-group (or grouping target))))
+ (incf addend
+ (symbol-value
+ (intern-soft (concat "ledger-regex-"
+ (symbol-name last-group)
+ "-group--count")))))
+ (nconc
+ defs
+ (list
+ `(defconst
+ ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-group-" (symbol-name var)))
+ ,(+ addend
+ (symbol-value
+ (intern-soft
+ (if grouping
+ (concat "ledger-regex-" (symbol-name grouping)
+ "-group-" (symbol-name target))
+ (concat "ledger-regex-" (symbol-name target)
+ "-group"))))))))
+ (nconc
+ defs
+ (list
+ `(defmacro
+ ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-" (symbol-name var)))
+ (&optional string)
+ ,(format "Return the sub-group match for the %s %s."
+ name var)
+ (match-string
+ ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-group-" (symbol-name var)))
+ string))))
+
+ (setq last-group (or grouping target))))
(nconc defs
- (list
- `(defconst ,(intern (concat "ledger-regex-" (symbol-name name)
- "-group--count"))
- ,(length args)))))
+ (list
+ `(defconst ,(intern (concat "ledger-regex-" (symbol-name name)
+ "-group--count"))
+ ,(length args)))))
(cons 'progn defs)))
(put 'ledger-define-regexp 'lisp-indent-function 1)
(ledger-define-regexp date
- (let ((sep '(or ?- (any ?. ?/)))) ; can't do (any ?- ?. ?/) due to bug
+ (let ((sep '(or ?- (any ?. ?/)))) ; can't do (any ?- ?. ?/) due to bug
(rx (group
- (and (? (= 4 num)
- (eval sep))
- (and num (? num))
- (eval sep)
- (and num (? num))))))
+ (and (? (= 4 num)
+ (eval sep))
+ (and num (? num))
+ (eval sep)
+ (and num (? num))))))
"Match a single date, in its 'written' form.")
(ledger-define-regexp full-date
(macroexpand
`(rx (and (regexp ,ledger-date-regexp)
- (? (and ?= (regexp ,ledger-date-regexp))))))
+ (? (and ?= (regexp ,ledger-date-regexp))))))
"Match a compound date, of the form ACTUAL=EFFECTIVE"
(actual date)
(effective date))
@@ -126,7 +126,7 @@
(ledger-define-regexp long-space
(rx (and (*? blank)
- (or (and ? (or ? ?\t)) ?\t)))
+ (or (and ? (or ? ?\t)) ?\t)))
"Match a \"long space\".")
(ledger-define-regexp note
@@ -136,24 +136,24 @@
(ledger-define-regexp end-note
(macroexpand
`(rx (and (regexp ,ledger-long-space-regexp) ?\;
- (regexp ,ledger-note-regexp))))
+ (regexp ,ledger-note-regexp))))
"")
(ledger-define-regexp full-note
(macroexpand
`(rx (and line-start (+ blank)
- ?\; (regexp ,ledger-note-regexp))))
+ ?\; (regexp ,ledger-note-regexp))))
"")
(ledger-define-regexp xact-line
(macroexpand
`(rx (and line-start
- (regexp ,ledger-full-date-regexp)
- (? (and (+ blank) (regexp ,ledger-state-regexp)))
- (? (and (+ blank) (regexp ,ledger-code-regexp)))
- (+ blank) (+? nonl)
- (? (regexp ,ledger-end-note-regexp))
- line-end)))
+ (regexp ,ledger-full-date-regexp)
+ (? (and (+ blank) (regexp ,ledger-state-regexp)))
+ (? (and (+ blank) (regexp ,ledger-code-regexp)))
+ (+ blank) (+? nonl)
+ (? (regexp ,ledger-end-note-regexp))
+ line-end)))
"Match a transaction's first line (and optional notes)."
(actual-date full-date actual)
(effective-date full-date effective)
@@ -172,8 +172,8 @@
(ledger-define-regexp full-account
(macroexpand
`(rx (and (regexp ,ledger-account-kind-regexp)
- (regexp ,ledger-account-regexp)
- (? (any ?\] ?\))))))
+ (regexp ,ledger-account-regexp)
+ (? (any ?\] ?\))))))
""
(kind account-kind)
(name account))
@@ -181,50 +181,50 @@
(ledger-define-regexp commodity
(rx (group
(or (and ?\" (+ (not (any ?\"))) ?\")
- (not (any blank ?\n
- digit
- ?- ?\[ ?\]
- ?. ?, ?\; ?+ ?* ?/ ?^ ?? ?: ?& ?| ?! ?=
- ?\< ?\> ?\{ ?\} ?\( ?\) ?@)))))
+ (not (any blank ?\n
+ digit
+ ?- ?\[ ?\]
+ ?. ?, ?\; ?+ ?* ?/ ?^ ?? ?: ?& ?| ?! ?=
+ ?\< ?\> ?\{ ?\} ?\( ?\) ?@)))))
"")
(ledger-define-regexp amount
(rx (group
(and (? ?-)
- (and (+ digit)
- (*? (and (any ?. ?,) (+ digit))))
- (? (and (any ?. ?,) (+ digit))))))
+ (and (+ digit)
+ (*? (and (any ?. ?,) (+ digit))))
+ (? (and (any ?. ?,) (+ digit))))))
"")
(ledger-define-regexp commoditized-amount
(macroexpand
`(rx (group
- (or (and (regexp ,ledger-commodity-regexp)
- (*? blank)
- (regexp ,ledger-amount-regexp))
- (and (regexp ,ledger-amount-regexp)
- (*? blank)
- (regexp ,ledger-commodity-regexp))))))
+ (or (and (regexp ,ledger-commodity-regexp)
+ (*? blank)
+ (regexp ,ledger-amount-regexp))
+ (and (regexp ,ledger-amount-regexp)
+ (*? blank)
+ (regexp ,ledger-commodity-regexp))))))
"")
(ledger-define-regexp commodity-annotations
(macroexpand
`(rx (* (+ blank)
- (or (and ?\{ (regexp ,ledger-commoditized-amount-regexp) ?\})
- (and ?\[ (regexp ,ledger-date-regexp) ?\])
- (and ?\( (not (any ?\))) ?\))))))
+ (or (and ?\{ (regexp ,ledger-commoditized-amount-regexp) ?\})
+ (and ?\[ (regexp ,ledger-date-regexp) ?\])
+ (and ?\( (not (any ?\))) ?\))))))
"")
(ledger-define-regexp cost
(macroexpand
`(rx (and (or "@" "@@") (+ blank)
- (regexp ,ledger-commoditized-amount-regexp))))
+ (regexp ,ledger-commoditized-amount-regexp))))
"")
(ledger-define-regexp balance-assertion
(macroexpand
`(rx (and ?= (+ blank)
- (regexp ,ledger-commoditized-amount-regexp))))
+ (regexp ,ledger-commoditized-amount-regexp))))
"")
(ledger-define-regexp full-amount
@@ -234,12 +234,12 @@
(ledger-define-regexp post-line
(macroexpand
`(rx (and line-start (+ blank)
- (? (and (regexp ,ledger-state-regexp) (* blank)))
- (regexp ,ledger-full-account-regexp)
- (? (and (regexp ,ledger-long-space-regexp)
- (regexp ,ledger-full-amount-regexp)))
- (? (regexp ,ledger-end-note-regexp))
- line-end)))
+ (? (and (regexp ,ledger-state-regexp) (* blank)))
+ (regexp ,ledger-full-account-regexp)
+ (? (and (regexp ,ledger-long-space-regexp)
+ (regexp ,ledger-full-amount-regexp)))
+ (? (regexp ,ledger-end-note-regexp))
+ line-end)))
""
state
(account-kind full-account kind)
diff --git a/lisp/ldg-register.el b/lisp/ldg-register.el
index 02e50de9..7b5c0d0a 100644
--- a/lisp/ldg-register.el
+++ b/lisp/ldg-register.el
@@ -25,29 +25,29 @@
(dolist (post posts)
(let ((index 1))
(dolist (xact (nthcdr 5 post))
- (let ((beg (point))
- (where
- (with-current-buffer data-buffer
- (cons
- (nth 0 post)
- (if ledger-clear-whole-entries
- (save-excursion
- (goto-line (nth 1 post))
- (point-marker))
- (save-excursion
- (goto-line (nth 0 xact))
- (point-marker)))))))
- (insert (format ledger-register-line-format
- (format-time-string ledger-register-date-format
- (nth 2 post))
- (nth 4 post) (nth 1 xact) (nth 2 xact)))
- (if (nth 3 xact)
- (set-text-properties beg (1- (point))
- (list 'face 'ledger-register-pending-face
- 'where where))
- (set-text-properties beg (1- (point))
- (list 'where where))))
- (setq index (1+ index)))))
+ (let ((beg (point))
+ (where
+ (with-current-buffer data-buffer
+ (cons
+ (nth 0 post)
+ (if ledger-clear-whole-entries
+ (save-excursion
+ (goto-line (nth 1 post))
+ (point-marker))
+ (save-excursion
+ (goto-line (nth 0 xact))
+ (point-marker)))))))
+ (insert (format ledger-register-line-format
+ (format-time-string ledger-register-date-format
+ (nth 2 post))
+ (nth 4 post) (nth 1 xact) (nth 2 xact)))
+ (if (nth 3 xact)
+ (set-text-properties beg (1- (point))
+ (list 'face 'ledger-register-pending-face
+ 'where where))
+ (set-text-properties beg (1- (point))
+ (list 'where where))))
+ (setq index (1+ index)))))
(goto-char (point-min))
)
@@ -55,10 +55,10 @@
(let ((buf (or data-buffer (current-buffer))))
(with-current-buffer (get-buffer-create "*ledger-register*")
(let ((pos (point))
- (inhibit-read-only t))
- (erase-buffer)
- (ledger-register-render buf (apply #'ledger-exec-read buf args))
- (goto-char pos))
+ (inhibit-read-only t))
+ (erase-buffer)
+ (ledger-register-render buf (apply #'ledger-exec-read buf args))
+ (goto-char pos))
(set-buffer-modified-p nil)
(toggle-read-only t)
(display-buffer (current-buffer) t))))
diff --git a/lisp/ldg-report.el b/lisp/ldg-report.el
index 6fc74f1d..5a668847 100644
--- a/lisp/ldg-report.el
+++ b/lisp/ldg-report.el
@@ -15,7 +15,7 @@ the substitution. See the documentation of the individual functions
in that variable for more information on the behavior of each
specifier."
:type '(repeat (list (string :tag "Report Name")
- (string :tag "Command Line")))
+ (string :tag "Command Line")))
:group 'ledger)
(defcustom ledger-report-format-specifiers
@@ -73,8 +73,8 @@ text that should replace the format specifier."
The empty string and unknown names are allowed."
(completing-read "Report name: "
- ledger-reports nil nil nil
- 'ledger-report-name-prompt-history nil))
+ ledger-reports nil nil nil
+ 'ledger-report-name-prompt-history nil))
(defun ledger-report (report-name edit)
"Run a user-specified report from `ledger-reports'.
@@ -93,18 +93,18 @@ used to generate the buffer, navigating the buffer, etc."
(interactive
(progn
(when (and (buffer-modified-p)
- (y-or-n-p "Buffer modified, save it? "))
+ (y-or-n-p "Buffer modified, save it? "))
(save-buffer))
(let ((rname (ledger-report-read-name))
- (edit (not (null current-prefix-arg))))
+ (edit (not (null current-prefix-arg))))
(list rname edit))))
(let ((buf (current-buffer))
- (rbuf (get-buffer ledger-report-buffer-name))
- (wcfg (current-window-configuration)))
+ (rbuf (get-buffer ledger-report-buffer-name))
+ (wcfg (current-window-configuration)))
(if rbuf
- (kill-buffer rbuf))
+ (kill-buffer rbuf))
(with-current-buffer
- (pop-to-buffer (get-buffer-create ledger-report-buffer-name))
+ (pop-to-buffer (get-buffer-create ledger-report-buffer-name))
(ledger-report-mode)
(set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-report-name) report-name)
@@ -137,8 +137,8 @@ If name exists, returns the object naming the report, otherwise returns nil."
(defun ledger-report-read-command (report-cmd)
"Read the command line to create a report."
(read-from-minibuffer "Report command line: "
- (if (null report-cmd) "ledger " report-cmd)
- nil nil 'ledger-report-cmd-prompt-history))
+ (if (null report-cmd) "ledger " report-cmd)
+ nil nil 'ledger-report-cmd-prompt-history))
(defun ledger-report-ledger-file-format-specifier ()
"Substitute the full path to master or current ledger file
@@ -165,9 +165,9 @@ end of a ledger file which is included in some other file."
(defun ledger-read-string-with-default (prompt default)
(let ((default-prompt (concat prompt
- (if default
- (concat " (" default "): ")
- ": "))))
+ (if default
+ (concat " (" default "): ")
+ ": "))))
(read-string default-prompt nil nil default)))
(defun ledger-report-payee-format-specifier ()
@@ -191,26 +191,26 @@ the default."
;; It is intended completion should be available on existing account
;; names, but it remains to be implemented.
(let* ((context (ledger-context-at-point))
- (default
- (if (eq (ledger-context-line-type context) 'acct-transaction)
- (regexp-quote (ledger-context-field-value context 'account))
- nil)))
+ (default
+ (if (eq (ledger-context-line-type context) 'acct-transaction)
+ (regexp-quote (ledger-context-field-value context 'account))
+ nil)))
(ledger-read-string-with-default "Account" default)))
(defun ledger-report-expand-format-specifiers (report-cmd)
(let ((expanded-cmd report-cmd))
(while (string-match "%(\\([^)]*\\))" expanded-cmd)
(let* ((specifier (match-string 1 expanded-cmd))
- (f (cdr (assoc specifier ledger-report-format-specifiers))))
- (if f
- (setq expanded-cmd (replace-match
- (save-match-data
- (with-current-buffer ledger-buf
- (shell-quote-argument (funcall f))))
- t t expanded-cmd))
- (progn
- (set-window-configuration ledger-original-window-cfg)
- (error "Invalid ledger report format specifier '%s'" specifier)))))
+ (f (cdr (assoc specifier ledger-report-format-specifiers))))
+ (if f
+ (setq expanded-cmd (replace-match
+ (save-match-data
+ (with-current-buffer ledger-buf
+ (shell-quote-argument (funcall f))))
+ t t expanded-cmd))
+ (progn
+ (set-window-configuration ledger-original-window-cfg)
+ (error "Invalid ledger report format specifier '%s'" specifier)))))
expanded-cmd))
(defun ledger-report-cmd (report-name edit)
@@ -222,18 +222,18 @@ the default."
(setq report-cmd (ledger-report-expand-format-specifiers report-cmd))
(set (make-local-variable 'ledger-report-cmd) report-cmd)
(or (string-empty-p report-name)
- (ledger-report-name-exists report-name)
- (ledger-reports-add report-name report-cmd)
- (ledger-reports-custom-save))
+ (ledger-report-name-exists report-name)
+ (ledger-reports-add report-name report-cmd)
+ (ledger-reports-custom-save))
report-cmd))
(defun ledger-do-report (cmd)
"Run a report command line."
(goto-char (point-min))
(insert (format "Report: %s\n" ledger-report-name)
- (format "Command: %s\n" cmd)
- (make-string (- (window-width) 1) ?=)
- "\n")
+ (format "Command: %s\n" cmd)
+ (make-string (- (window-width) 1) ?=)
+ "\n")
(shell-command cmd t nil))
(defun ledger-report-goto ()
@@ -241,7 +241,7 @@ the default."
(interactive)
(let ((rbuf (get-buffer ledger-report-buffer-name)))
(if (not rbuf)
- (error "There is no ledger report buffer"))
+ (error "There is no ledger report buffer"))
(pop-to-buffer rbuf)
(shrink-window-if-larger-than-buffer)))
@@ -277,7 +277,7 @@ the default."
(let ((name ""))
(while (string-empty-p name)
(setq name (read-from-minibuffer "Report name: " nil nil nil
- 'ledger-report-name-prompt-history)))
+ 'ledger-report-name-prompt-history)))
name))
(defun ledger-report-save ()
@@ -290,15 +290,15 @@ the default."
(while (setq existing-name (ledger-report-name-exists ledger-report-name))
(cond ((y-or-n-p (format "Overwrite existing report named '%s' "
- ledger-report-name))
- (when (string-equal
- ledger-report-cmd
- (car (cdr (assq existing-name ledger-reports))))
- (error "Current command is identical to existing saved one"))
- (setq ledger-reports
- (assq-delete-all existing-name ledger-reports)))
- (t
- (setq ledger-report-name (ledger-report-read-new-name)))))
+ ledger-report-name))
+ (when (string-equal
+ ledger-report-cmd
+ (car (cdr (assq existing-name ledger-reports))))
+ (error "Current command is identical to existing saved one"))
+ (setq ledger-reports
+ (assq-delete-all existing-name ledger-reports)))
+ (t
+ (setq ledger-report-name (ledger-report-read-new-name)))))
(ledger-reports-add ledger-report-name ledger-report-cmd)
(ledger-reports-custom-save)))
@@ -333,24 +333,24 @@ the default."
Assumes point is at beginning of line, and the pos argument specifies
where the \"users\" point was."
(let ((linfo (assoc line-type ledger-line-config))
- found field fields)
+ found field fields)
(dolist (re-info (nth 1 linfo))
(let ((re (nth 0 re-info))
- (names (nth 1 re-info)))
- (unless found
- (when (looking-at re)
- (setq found t)
- (dotimes (i (length names))
- (when (nth i names)
- (setq fields (append fields
- (list
- (list (nth i names)
- (match-string-no-properties (1+ i))
- (match-beginning (1+ i))))))))
- (dolist (f fields)
- (and (nth 1 f)
- (>= pos (nth 2 f))
- (setq field (nth 0 f))))))))
+ (names (nth 1 re-info)))
+ (unless found
+ (when (looking-at re)
+ (setq found t)
+ (dotimes (i (length names))
+ (when (nth i names)
+ (setq fields (append fields
+ (list
+ (list (nth i names)
+ (match-string-no-properties (1+ i))
+ (match-beginning (1+ i))))))))
+ (dolist (f fields)
+ (and (nth 1 f)
+ (>= pos (nth 2 f))
+ (setq field (nth 0 f))))))))
(list line-type field fields)))
(defun ledger-context-at-point ()
@@ -363,40 +363,40 @@ the fields in the line in a association list."
(save-excursion
(beginning-of-line)
(let ((first-char (char-after)))
- (cond ((equal (point) (line-end-position))
- '(empty-line nil nil))
- ((memq first-char '(?\ ?\t))
- (ledger-extract-context-info 'acct-transaction pos))
- ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
- (ledger-extract-context-info 'entry pos))
- ((equal first-char ?\=)
- '(automated-entry nil nil))
- ((equal first-char ?\~)
- '(period-entry nil nil))
- ((equal first-char ?\!)
- '(command-directive))
- ((equal first-char ?\;)
- '(comment nil nil))
- ((equal first-char ?Y)
- '(default-year nil nil))
- ((equal first-char ?P)
- '(commodity-price nil nil))
- ((equal first-char ?N)
- '(price-ignored-commodity nil nil))
- ((equal first-char ?D)
- '(default-commodity nil nil))
- ((equal first-char ?C)
- '(commodity-conversion nil nil))
- ((equal first-char ?i)
- '(timeclock-i nil nil))
- ((equal first-char ?o)
- '(timeclock-o nil nil))
- ((equal first-char ?b)
- '(timeclock-b nil nil))
- ((equal first-char ?h)
- '(timeclock-h nil nil))
- (t
- '(unknown nil nil)))))))
+ (cond ((equal (point) (line-end-position))
+ '(empty-line nil nil))
+ ((memq first-char '(?\ ?\t))
+ (ledger-extract-context-info 'acct-transaction pos))
+ ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
+ (ledger-extract-context-info 'entry pos))
+ ((equal first-char ?\=)
+ '(automated-entry nil nil))
+ ((equal first-char ?\~)
+ '(period-entry nil nil))
+ ((equal first-char ?\!)
+ '(command-directive))
+ ((equal first-char ?\;)
+ '(comment nil nil))
+ ((equal first-char ?Y)
+ '(default-year nil nil))
+ ((equal first-char ?P)
+ '(commodity-price nil nil))
+ ((equal first-char ?N)
+ '(price-ignored-commodity nil nil))
+ ((equal first-char ?D)
+ '(default-commodity nil nil))
+ ((equal first-char ?C)
+ '(commodity-conversion nil nil))
+ ((equal first-char ?i)
+ '(timeclock-i nil nil))
+ ((equal first-char ?o)
+ '(timeclock-o nil nil))
+ ((equal first-char ?b)
+ '(timeclock-b nil nil))
+ ((equal first-char ?h)
+ '(timeclock-h nil nil))
+ (t
+ '(unknown nil nil)))))))
(defun ledger-context-other-line (offset)
"Return a list describing context of line offset for existing position.
@@ -406,8 +406,8 @@ specified line, returns nil."
(save-excursion
(let ((left (forward-line offset)))
(if (not (equal left 0))
- nil
- (ledger-context-at-point)))))
+ nil
+ (ledger-context-at-point)))))
(defun ledger-context-line-type (context-info)
(nth 0 context-info))
@@ -444,5 +444,5 @@ specified line, returns nil."
(setq i (- i 1)))
(let ((context-info (ledger-context-other-line i)))
(if (eq (ledger-context-line-type context-info) 'entry)
- (ledger-context-field-value context-info 'payee)
- nil))))
+ (ledger-context-field-value context-info 'payee)
+ nil))))
diff --git a/lisp/ldg-state.el b/lisp/ldg-state.el
index 945d72fe..6a841621 100644
--- a/lisp/ldg-state.el
+++ b/lisp/ldg-state.el
@@ -6,28 +6,28 @@
(defun ledger-toggle-state (state &optional style)
(if (not (null state))
(if (and style (eq style 'cleared))
- 'cleared)
+ 'cleared)
(if (and style (eq style 'pending))
- 'pending
+ 'pending
'cleared)))
(defun ledger-entry-state ()
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
+ (re-search-backward "^[0-9]" nil t))
(skip-chars-forward "0-9./=")
(skip-syntax-forward " ")
(cond ((looking-at "!\\s-*") 'pending)
- ((looking-at "\\*\\s-*") 'cleared)
- (t nil)))))
+ ((looking-at "\\*\\s-*") 'cleared)
+ (t nil)))))
(defun ledger-transaction-state ()
(save-excursion
(goto-char (line-beginning-position))
(skip-syntax-forward " ")
(cond ((looking-at "!\\s-*") 'pending)
- ((looking-at "\\*\\s-*") 'cleared)
- (t (ledger-entry-state)))))
+ ((looking-at "\\*\\s-*") 'cleared)
+ (t (ledger-entry-state)))))
(defun ledger-toggle-current-transaction (&optional style)
"Toggle the cleared status of the transaction under point.
@@ -42,129 +42,129 @@ formatting, but doing so causes inline math expressions to be
dropped."
(interactive)
(let ((bounds (ledger-current-entry-bounds))
- clear cleared)
+ clear cleared)
;; Uncompact the entry, to make it easier to toggle the
;; transaction
(save-excursion
(goto-char (car bounds))
(skip-chars-forward "0-9./= \t")
(setq cleared (and (member (char-after) '(?\* ?\!))
- (char-after)))
+ (char-after)))
(when cleared
- (let ((here (point)))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (if (search-forward " " (line-end-position) t)
- (insert (make-string width ? ))))))
- (forward-line)
- (while (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (insert cleared " ")
- (if (search-forward " " (line-end-position) t)
- (delete-char 2))
- (forward-line))))
+ (let ((here (point)))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (if (search-forward " " (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (forward-line)
+ (while (looking-at "[ \t]")
+ (skip-chars-forward " \t")
+ (insert cleared " ")
+ (if (search-forward " " (line-end-position) t)
+ (delete-char 2))
+ (forward-line))))
;; Toggle the individual transaction
(save-excursion
(goto-char (line-beginning-position))
(when (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (let ((here (point))
- (cleared (member (char-after) '(?\* ?\!))))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (save-excursion
- (if (search-forward " " (line-end-position) t)
- (insert (make-string width ? ))))))
- (let (inserted)
- (if cleared
- (if (and style (eq style 'cleared))
- (progn
- (insert "* ")
- (setq inserted t)))
- (if (and style (eq style 'pending))
- (progn
- (insert "! ")
- (setq inserted t))
- (progn
- (insert "* ")
- (setq inserted t))))
- (if (and inserted
- (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t))
- (cond
- ((looking-at "\t")
- (delete-char 1))
- ((looking-at " [ \t]")
- (delete-char 2))
- ((looking-at " ")
- (delete-char 1))))
- (setq clear inserted)))))
+ (skip-chars-forward " \t")
+ (let ((here (point))
+ (cleared (member (char-after) '(?\* ?\!))))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (save-excursion
+ (if (search-forward " " (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (let (inserted)
+ (if cleared
+ (if (and style (eq style 'cleared))
+ (progn
+ (insert "* ")
+ (setq inserted t)))
+ (if (and style (eq style 'pending))
+ (progn
+ (insert "! ")
+ (setq inserted t))
+ (progn
+ (insert "* ")
+ (setq inserted t))))
+ (if (and inserted
+ (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t))
+ (cond
+ ((looking-at "\t")
+ (delete-char 1))
+ ((looking-at " [ \t]")
+ (delete-char 2))
+ ((looking-at " ")
+ (delete-char 1))))
+ (setq clear inserted)))))
;; Clean up the entry so that it displays minimally
(save-excursion
(goto-char (car bounds))
(forward-line)
(let ((first t)
- (state ? )
- (hetero nil))
- (while (and (not hetero) (looking-at "[ \t]"))
- (skip-chars-forward " \t")
- (let ((cleared (if (member (char-after) '(?\* ?\!))
- (char-after)
- ? )))
- (if first
- (setq state cleared
- first nil)
- (if (/= state cleared)
- (setq hetero t))))
- (forward-line))
- (when (and (not hetero) (/= state ? ))
- (goto-char (car bounds))
- (forward-line)
- (while (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (let ((here (point)))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (if (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t)
- (insert (make-string width ? ))))))
- (forward-line))
- (goto-char (car bounds))
- (skip-chars-forward "0-9./= \t")
- (insert state " ")
- (if (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t)
- (cond
- ((looking-at "\t")
- (delete-char 1))
- ((looking-at " [ \t]")
- (delete-char 2))
- ((looking-at " ")
- (delete-char 1)))))))
+ (state ? )
+ (hetero nil))
+ (while (and (not hetero) (looking-at "[ \t]"))
+ (skip-chars-forward " \t")
+ (let ((cleared (if (member (char-after) '(?\* ?\!))
+ (char-after)
+ ? )))
+ (if first
+ (setq state cleared
+ first nil)
+ (if (/= state cleared)
+ (setq hetero t))))
+ (forward-line))
+ (when (and (not hetero) (/= state ? ))
+ (goto-char (car bounds))
+ (forward-line)
+ (while (looking-at "[ \t]")
+ (skip-chars-forward " \t")
+ (let ((here (point)))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (if (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (forward-line))
+ (goto-char (car bounds))
+ (skip-chars-forward "0-9./= \t")
+ (insert state " ")
+ (if (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t)
+ (cond
+ ((looking-at "\t")
+ (delete-char 1))
+ ((looking-at " [ \t]")
+ (delete-char 2))
+ ((looking-at " ")
+ (delete-char 1)))))))
clear))
(defun ledger-toggle-current (&optional style)
(interactive)
(if (or ledger-clear-whole-entries
- (eq 'entry (ledger-thing-at-point)))
+ (eq 'entry (ledger-thing-at-point)))
(progn
- (save-excursion
- (forward-line)
- (goto-char (line-beginning-position))
- (while (and (not (eolp))
- (save-excursion
- (not (eq 'entry (ledger-thing-at-point)))))
- (if (looking-at "\\s-+[*!]")
- (ledger-toggle-current-transaction nil))
- (forward-line)
- (goto-char (line-beginning-position))))
- (ledger-toggle-current-entry style))
+ (save-excursion
+ (forward-line)
+ (goto-char (line-beginning-position))
+ (while (and (not (eolp))
+ (save-excursion
+ (not (eq 'entry (ledger-thing-at-point)))))
+ (if (looking-at "\\s-+[*!]")
+ (ledger-toggle-current-transaction nil))
+ (forward-line)
+ (goto-char (line-beginning-position))))
+ (ledger-toggle-current-entry style))
(ledger-toggle-current-transaction style)))
(defun ledger-toggle-current-entry (&optional style)
@@ -172,18 +172,18 @@ dropped."
(let (clear)
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
- (skip-chars-forward "0-9./=")
- (delete-horizontal-space)
- (if (member (char-after) '(?\* ?\!))
- (progn
- (delete-char 1)
- (if (and style (eq style 'cleared))
- (insert " *")))
- (if (and style (eq style 'pending))
- (insert " ! ")
- (insert " * "))
- (setq clear t))))
+ (re-search-backward "^[0-9]" nil t))
+ (skip-chars-forward "0-9./=")
+ (delete-horizontal-space)
+ (if (member (char-after) '(?\* ?\!))
+ (progn
+ (delete-char 1)
+ (if (and style (eq style 'cleared))
+ (insert " *")))
+ (if (and style (eq style 'pending))
+ (insert " ! ")
+ (insert " * "))
+ (setq clear t))))
clear))
(provide 'ldg-state)
diff --git a/lisp/ldg-texi.el b/lisp/ldg-texi.el
index 982ea0ed..b0334099 100644
--- a/lisp/ldg-texi.el
+++ b/lisp/ldg-texi.el
@@ -2,16 +2,36 @@
(defvar ledger-sample-doc-path "/Users/johnw/src/ledger/doc/sample.dat")
(defvar ledger-normalization-args "--args-only --columns 80")
+(defun ledger-update-test ()
+ (interactive)
+ (goto-char (point-min))
+ (let ((command (buffer-substring (point-min) (line-end-position)))
+ input)
+ (re-search-forward "^<<<\n")
+ (let ((beg (point)) end)
+ (re-search-forward "^>>>")
+ (setq end (match-beginning 0))
+ (forward-line 1)
+ (let ((output-beg (point)))
+ (re-search-forward "^>>>")
+ (goto-char (match-beginning 0))
+ (delete-region output-beg (point))
+ (apply #'call-process-region
+ beg end (expand-file-name "~/Products/ledger/debug/ledger")
+ nil t nil
+ "-f" "-" "--args-only" "--columns=80" "--no-color"
+ (split-string command " "))))))
+
(defun ledger-texi-write-test (name command input output &optional category)
(let ((buf (current-buffer)))
(with-current-buffer (find-file-noselect
- (expand-file-name (concat name ".test") category))
+ (expand-file-name (concat name ".test") category))
(erase-buffer)
(let ((case-fold-search nil))
- (if (string-match "\\$LEDGER\\s-+" command)
- (setq command (replace-match "" t t command)))
- (if (string-match " -f \\$\\([-a-z]+\\)" command)
- (setq command (replace-match "" t t command))))
+ (if (string-match "\\$LEDGER\\s-+" command)
+ (setq command (replace-match "" t t command)))
+ (if (string-match " -f \\$\\([-a-z]+\\)" command)
+ (setq command (replace-match "" t t command))))
(insert command ?\n)
(insert "<<<" ?\n)
(insert input)
@@ -21,13 +41,13 @@
(insert "=== 0" ?\n)
(save-buffer)
(unless (eq buf (current-buffer))
- (kill-buffer (current-buffer))))))
+ (kill-buffer (current-buffer))))))
(defun ledger-texi-update-test ()
(interactive)
(let ((details (ledger-texi-test-details))
- (name (file-name-sans-extension
- (file-name-nondirectory (buffer-file-name)))))
+ (name (file-name-sans-extension
+ (file-name-nondirectory (buffer-file-name)))))
(ledger-texi-write-test
name (nth 0 details)
(nth 1 details)
@@ -39,30 +59,30 @@
(defun ledger-texi-test-details ()
(goto-char (point-min))
(let ((command (buffer-substring (point) (line-end-position)))
- input output)
+ input output)
(re-search-forward "^<<<")
(let ((input-beg (1+ (match-end 0))))
(re-search-forward "^>>>1")
(let ((output-beg (1+ (match-end 0))))
- (setq input (buffer-substring input-beg (match-beginning 0)))
- (re-search-forward "^>>>2")
- (setq output (buffer-substring output-beg (match-beginning 0)))
- (list command input output)))))
+ (setq input (buffer-substring input-beg (match-beginning 0)))
+ (re-search-forward "^>>>2")
+ (setq output (buffer-substring output-beg (match-beginning 0)))
+ (list command input output)))))
(defun ledger-texi-expand-command (command data-file)
(if (string-match "\\$LEDGER" command)
(replace-match (format "%s -f \"%s\" %s" ledger-path
- data-file ledger-normalization-args) t t command)
+ data-file ledger-normalization-args) t t command)
(concat (format "%s -f \"%s\" %s " ledger-path
- data-file ledger-normalization-args) command)))
+ data-file ledger-normalization-args) command)))
(defun ledger-texi-invoke-command (command)
(with-temp-buffer (shell-command command t (current-buffer))
(if (= (point-min) (point-max))
- (progn
- (push-mark nil t)
- (message "Command '%s' yielded no result at %d" command (point))
- (ding))
+ (progn
+ (push-mark nil t)
+ (message "Command '%s' yielded no result at %d" command (point))
+ (ding))
(buffer-string))))
(defun ledger-texi-write-test-data (name input)
@@ -79,43 +99,43 @@
(goto-char (point-min))
(while (re-search-forward "^@c \\(\\(?:sm\\)?ex\\) \\(\\S-+\\): \\(.*\\)" nil t)
(let ((section (match-string 1))
- (example-name (match-string 2))
- (command (match-string 3)) expanded-command
- (data-file ledger-sample-doc-path)
- input output)
- (goto-char (match-end 0))
- (forward-line)
- (when (looking-at "@\\(\\(?:small\\)?example\\)")
- (let ((beg (point)))
- (re-search-forward "^@end \\(\\(?:small\\)?example\\)")
- (delete-region beg (1+ (point)))))
+ (example-name (match-string 2))
+ (command (match-string 3)) expanded-command
+ (data-file ledger-sample-doc-path)
+ input output)
+ (goto-char (match-end 0))
+ (forward-line)
+ (when (looking-at "@\\(\\(?:small\\)?example\\)")
+ (let ((beg (point)))
+ (re-search-forward "^@end \\(\\(?:small\\)?example\\)")
+ (delete-region beg (1+ (point)))))
- (when (let ((case-fold-search nil))
- (string-match " -f \\$\\([-a-z]+\\)" command))
- (let ((label (match-string 1 command)))
- (setq command (replace-match "" t t command))
- (save-excursion
- (goto-char (point-min))
- (search-forward (format "@c data: %s" label))
- (re-search-forward "@\\(\\(?:small\\)?example\\)")
- (forward-line)
- (let ((beg (point)))
- (re-search-forward "@end \\(\\(?:small\\)?example\\)")
- (setq data-file (ledger-texi-write-test-data
- (format "%s.dat" label)
- (buffer-substring-no-properties
- beg (match-beginning 0))))))))
+ (when (let ((case-fold-search nil))
+ (string-match " -f \\$\\([-a-z]+\\)" command))
+ (let ((label (match-string 1 command)))
+ (setq command (replace-match "" t t command))
+ (save-excursion
+ (goto-char (point-min))
+ (search-forward (format "@c data: %s" label))
+ (re-search-forward "@\\(\\(?:small\\)?example\\)")
+ (forward-line)
+ (let ((beg (point)))
+ (re-search-forward "@end \\(\\(?:small\\)?example\\)")
+ (setq data-file (ledger-texi-write-test-data
+ (format "%s.dat" label)
+ (buffer-substring-no-properties
+ beg (match-beginning 0))))))))
- (let ((section-name (if (string= section "smex")
- "smallexample"
- "example"))
- (output (ledger-texi-invoke-command
- (ledger-texi-expand-command command data-file))))
- (insert "@" section-name ?\n output
- "@end " section-name ?\n))
+ (let ((section-name (if (string= section "smex")
+ "smallexample"
+ "example"))
+ (output (ledger-texi-invoke-command
+ (ledger-texi-expand-command command data-file))))
+ (insert "@" section-name ?\n output
+ "@end " section-name ?\n))
- ;; Update the regression test associated with this example
- (ledger-texi-write-test example-name command input output
- "../test/manual")))))
+ ;; Update the regression test associated with this example
+ (ledger-texi-write-test example-name command input output
+ "../test/manual")))))
(provide 'ldg-texi)
diff --git a/lisp/ldg-xact.el b/lisp/ldg-xact.el
index 5945632a..e1f165a7 100644
--- a/lisp/ldg-xact.el
+++ b/lisp/ldg-xact.el
@@ -9,12 +9,12 @@
nil
(function
(lambda ()
- (if (re-search-forward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
- (goto-char (match-beginning 0))
- (goto-char (point-max)))))
+ (if (re-search-forward
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (goto-char (match-beginning 0))
+ (goto-char (point-max)))))
(function
(lambda ()
- (forward-paragraph))))))
+ (forward-paragraph))))))
diff --git a/lisp/ledger.el b/lisp/ledger.el
index 0e2f4b11..25bb485b 100644
--- a/lisp/ledger.el
+++ b/lisp/ledger.el
@@ -107,7 +107,7 @@ the substitution. See the documentation of the individual functions
in that variable for more information on the behavior of each
specifier."
:type '(repeat (list (string :tag "Report Name")
- (string :tag "Command Line")))
+ (string :tag "Command Line")))
:group 'ledger)
(defcustom ledger-report-format-specifiers
@@ -128,13 +128,13 @@ text that should replace the format specifier."
(defvar bold 'bold)
(defvar ledger-font-lock-keywords
- '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face)
- ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold)
- ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)"
+ '(("\\( \\| \\|^\\)\\(;.*\\)" 2 font-lock-comment-face)
+ ("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([^*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" 2 bold)
+ ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)"
;; 2 font-lock-type-face)
("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*:
- ]+?:[^]);
- ]+?\\([])]\\)?\\)\\( \\| \\|$\\)"
+ ]+?:[^]);
+ ]+?\\([])]\\)?\\)\\( \\| \\|$\\)"
2 font-lock-keyword-face)
("^\\([~=].+\\)" 1 font-lock-function-name-face)
("^\\([A-Za-z]+ .+\\)" 1 font-lock-function-name-face))
@@ -155,88 +155,88 @@ customizable to ease retro-entry.")
(defun ledger-iterate-entries (callback)
(goto-char (point-min))
(let* ((now (current-time))
- (current-year (nth 5 (decode-time now))))
+ (current-year (nth 5 (decode-time now))))
(while (not (eobp))
(when (looking-at
- (concat "\\(Y\\s-+\\([0-9]+\\)\\|"
- "\\([0-9]\\{4\\}+\\)?[./]?"
- "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+"
- "\\(\\*\\s-+\\)?\\(.+\\)\\)"))
- (let ((found (match-string 2)))
- (if found
- (setq current-year (string-to-number found))
- (let ((start (match-beginning 0))
- (year (match-string 3))
- (month (string-to-number (match-string 4)))
- (day (string-to-number (match-string 5)))
- (mark (match-string 6))
- (desc (match-string 7)))
- (if (and year (> (length year) 0))
- (setq year (string-to-number year)))
- (funcall callback start
- (encode-time 0 0 0 day month
- (or year current-year))
- mark desc)))))
+ (concat "\\(Y\\s-+\\([0-9]+\\)\\|"
+ "\\([0-9]\\{4\\}+\\)?[./]?"
+ "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+"
+ "\\(\\*\\s-+\\)?\\(.+\\)\\)"))
+ (let ((found (match-string 2)))
+ (if found
+ (setq current-year (string-to-number found))
+ (let ((start (match-beginning 0))
+ (year (match-string 3))
+ (month (string-to-number (match-string 4)))
+ (day (string-to-number (match-string 5)))
+ (mark (match-string 6))
+ (desc (match-string 7)))
+ (if (and year (> (length year) 0))
+ (setq year (string-to-number year)))
+ (funcall callback start
+ (encode-time 0 0 0 day month
+ (or year current-year))
+ mark desc)))))
(forward-line))))
(defun ledger-time-less-p (t1 t2)
"Say whether time value T1 is less than time value T2."
(or (< (car t1) (car t2))
(and (= (car t1) (car t2))
- (< (nth 1 t1) (nth 1 t2)))))
+ (< (nth 1 t1) (nth 1 t2)))))
(defun ledger-time-subtract (t1 t2)
"Subtract two time values.
Return the difference in the format of a time value."
(let ((borrow (< (cadr t1) (cadr t2))))
(list (- (car t1) (car t2) (if borrow 1 0))
- (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
+ (- (+ (if borrow 65536 0) (cadr t1)) (cadr t2)))))
(defun ledger-find-slot (moment)
(catch 'found
(ledger-iterate-entries
(function
(lambda (start date mark desc)
- (if (ledger-time-less-p moment date)
- (throw 'found t)))))))
+ (if (ledger-time-less-p moment date)
+ (throw 'found t)))))))
(defun ledger-add-entry (entry-text &optional insert-at-point)
(interactive
(list
(read-string "Entry: " (concat ledger-year "/" ledger-month "/"))))
(let* ((args (with-temp-buffer
- (insert entry-text)
- (eshell-parse-arguments (point-min) (point-max))))
- (ledger-buf (current-buffer))
- exit-code)
+ (insert entry-text)
+ (eshell-parse-arguments (point-min) (point-max))))
+ (ledger-buf (current-buffer))
+ exit-code)
(unless insert-at-point
(let ((date (car args)))
- (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
- (setq date
- (encode-time 0 0 0 (string-to-number (match-string 3 date))
- (string-to-number (match-string 2 date))
- (string-to-number (match-string 1 date)))))
- (ledger-find-slot date)))
+ (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
+ (setq date
+ (encode-time 0 0 0 (string-to-number (match-string 3 date))
+ (string-to-number (match-string 2 date))
+ (string-to-number (match-string 1 date)))))
+ (ledger-find-slot date)))
(save-excursion
(insert
(with-temp-buffer
- (setq exit-code
- (apply #'ledger-run-ledger ledger-buf "entry"
- (mapcar 'eval args)))
- (goto-char (point-min))
- (if (looking-at "Error: ")
- (error (buffer-string))
- (buffer-string)))
+ (setq exit-code
+ (apply #'ledger-run-ledger ledger-buf "entry"
+ (mapcar 'eval args)))
+ (goto-char (point-min))
+ (if (looking-at "Error: ")
+ (error (buffer-string))
+ (buffer-string)))
"\n"))))
(defun ledger-current-entry-bounds ()
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
+ (re-search-backward "^[0-9]" nil t))
(let ((beg (point)))
- (while (not (eolp))
- (forward-line))
- (cons (copy-marker beg) (point-marker))))))
+ (while (not (eolp))
+ (forward-line))
+ (cons (copy-marker beg) (point-marker))))))
(defun ledger-delete-current-entry ()
(interactive)
@@ -248,18 +248,18 @@ Return the difference in the format of a time value."
(let (clear)
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
- (skip-chars-forward "0-9./=")
- (delete-horizontal-space)
- (if (member (char-after) '(?\* ?\!))
- (progn
- (delete-char 1)
- (if (and style (eq style 'cleared))
- (insert " *")))
- (if (and style (eq style 'pending))
- (insert " ! ")
- (insert " * "))
- (setq clear t))))
+ (re-search-backward "^[0-9]" nil t))
+ (skip-chars-forward "0-9./=")
+ (delete-horizontal-space)
+ (if (member (char-after) '(?\* ?\!))
+ (progn
+ (delete-char 1)
+ (if (and style (eq style 'cleared))
+ (insert " *")))
+ (if (and style (eq style 'pending))
+ (insert " ! ")
+ (insert " * "))
+ (setq clear t))))
clear))
(defun ledger-move-to-next-field ()
@@ -268,28 +268,28 @@ Return the difference in the format of a time value."
(defun ledger-toggle-state (state &optional style)
(if (not (null state))
(if (and style (eq style 'cleared))
- 'cleared)
+ 'cleared)
(if (and style (eq style 'pending))
- 'pending
+ 'pending
'cleared)))
(defun ledger-entry-state ()
(save-excursion
(when (or (looking-at "^[0-9]")
- (re-search-backward "^[0-9]" nil t))
+ (re-search-backward "^[0-9]" nil t))
(skip-chars-forward "0-9./=")
(skip-syntax-forward " ")
(cond ((looking-at "!\\s-*") 'pending)
- ((looking-at "\\*\\s-*") 'cleared)
- (t nil)))))
+ ((looking-at "\\*\\s-*") 'cleared)
+ (t nil)))))
(defun ledger-transaction-state ()
(save-excursion
(goto-char (line-beginning-position))
(skip-syntax-forward " ")
(cond ((looking-at "!\\s-*") 'pending)
- ((looking-at "\\*\\s-*") 'cleared)
- (t (ledger-entry-state)))))
+ ((looking-at "\\*\\s-*") 'cleared)
+ (t (ledger-entry-state)))))
(defun ledger-toggle-current-transaction (&optional style)
"Toggle the cleared status of the transaction under point.
@@ -304,129 +304,129 @@ formatting, but doing so causes inline math expressions to be
dropped."
(interactive)
(let ((bounds (ledger-current-entry-bounds))
- clear cleared)
+ clear cleared)
;; Uncompact the entry, to make it easier to toggle the
;; transaction
(save-excursion
(goto-char (car bounds))
(skip-chars-forward "0-9./= \t")
(setq cleared (and (member (char-after) '(?\* ?\!))
- (char-after)))
+ (char-after)))
(when cleared
- (let ((here (point)))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (if (search-forward " " (line-end-position) t)
- (insert (make-string width ? ))))))
- (forward-line)
- (while (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (insert cleared " ")
- (if (search-forward " " (line-end-position) t)
- (delete-char 2))
- (forward-line))))
+ (let ((here (point)))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (if (search-forward " " (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (forward-line)
+ (while (looking-at "[ \t]")
+ (skip-chars-forward " \t")
+ (insert cleared " ")
+ (if (search-forward " " (line-end-position) t)
+ (delete-char 2))
+ (forward-line))))
;; Toggle the individual transaction
(save-excursion
(goto-char (line-beginning-position))
(when (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (let ((here (point))
- (cleared (member (char-after) '(?\* ?\!))))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (save-excursion
- (if (search-forward " " (line-end-position) t)
- (insert (make-string width ? ))))))
- (let (inserted)
- (if cleared
- (if (and style (eq style 'cleared))
- (progn
- (insert "* ")
- (setq inserted t)))
- (if (and style (eq style 'pending))
- (progn
- (insert "! ")
- (setq inserted t))
- (progn
- (insert "* ")
- (setq inserted t))))
- (if (and inserted
- (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t))
- (cond
- ((looking-at "\t")
- (delete-char 1))
- ((looking-at " [ \t]")
- (delete-char 2))
- ((looking-at " ")
- (delete-char 1))))
- (setq clear inserted)))))
+ (skip-chars-forward " \t")
+ (let ((here (point))
+ (cleared (member (char-after) '(?\* ?\!))))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (save-excursion
+ (if (search-forward " " (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (let (inserted)
+ (if cleared
+ (if (and style (eq style 'cleared))
+ (progn
+ (insert "* ")
+ (setq inserted t)))
+ (if (and style (eq style 'pending))
+ (progn
+ (insert "! ")
+ (setq inserted t))
+ (progn
+ (insert "* ")
+ (setq inserted t))))
+ (if (and inserted
+ (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t))
+ (cond
+ ((looking-at "\t")
+ (delete-char 1))
+ ((looking-at " [ \t]")
+ (delete-char 2))
+ ((looking-at " ")
+ (delete-char 1))))
+ (setq clear inserted)))))
;; Clean up the entry so that it displays minimally
(save-excursion
(goto-char (car bounds))
(forward-line)
(let ((first t)
- (state ? )
- (hetero nil))
- (while (and (not hetero) (looking-at "[ \t]"))
- (skip-chars-forward " \t")
- (let ((cleared (if (member (char-after) '(?\* ?\!))
- (char-after)
- ? )))
- (if first
- (setq state cleared
- first nil)
- (if (/= state cleared)
- (setq hetero t))))
- (forward-line))
- (when (and (not hetero) (/= state ? ))
- (goto-char (car bounds))
- (forward-line)
- (while (looking-at "[ \t]")
- (skip-chars-forward " \t")
- (let ((here (point)))
- (skip-chars-forward "*! ")
- (let ((width (- (point) here)))
- (when (> width 0)
- (delete-region here (point))
- (if (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t)
- (insert (make-string width ? ))))))
- (forward-line))
- (goto-char (car bounds))
- (skip-chars-forward "0-9./= \t")
- (insert state " ")
- (if (re-search-forward "\\(\t\\| [ \t]\\)"
- (line-end-position) t)
- (cond
- ((looking-at "\t")
- (delete-char 1))
- ((looking-at " [ \t]")
- (delete-char 2))
- ((looking-at " ")
- (delete-char 1)))))))
+ (state ? )
+ (hetero nil))
+ (while (and (not hetero) (looking-at "[ \t]"))
+ (skip-chars-forward " \t")
+ (let ((cleared (if (member (char-after) '(?\* ?\!))
+ (char-after)
+ ? )))
+ (if first
+ (setq state cleared
+ first nil)
+ (if (/= state cleared)
+ (setq hetero t))))
+ (forward-line))
+ (when (and (not hetero) (/= state ? ))
+ (goto-char (car bounds))
+ (forward-line)
+ (while (looking-at "[ \t]")
+ (skip-chars-forward " \t")
+ (let ((here (point)))
+ (skip-chars-forward "*! ")
+ (let ((width (- (point) here)))
+ (when (> width 0)
+ (delete-region here (point))
+ (if (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t)
+ (insert (make-string width ? ))))))
+ (forward-line))
+ (goto-char (car bounds))
+ (skip-chars-forward "0-9./= \t")
+ (insert state " ")
+ (if (re-search-forward "\\(\t\\| [ \t]\\)"
+ (line-end-position) t)
+ (cond
+ ((looking-at "\t")
+ (delete-char 1))
+ ((looking-at " [ \t]")
+ (delete-char 2))
+ ((looking-at " ")
+ (delete-char 1)))))))
clear))
(defun ledger-toggle-current (&optional style)
(interactive)
(if (or ledger-clear-whole-entries
- (eq 'entry (ledger-thing-at-point)))
+ (eq 'entry (ledger-thing-at-point)))
(progn
- (save-excursion
- (forward-line)
- (goto-char (line-beginning-position))
- (while (and (not (eolp))
- (save-excursion
- (not (eq 'entry (ledger-thing-at-point)))))
- (if (looking-at "\\s-+[*!]")
- (ledger-toggle-current-transaction nil))
- (forward-line)
- (goto-char (line-beginning-position))))
- (ledger-toggle-current-entry style))
+ (save-excursion
+ (forward-line)
+ (goto-char (line-beginning-position))
+ (while (and (not (eolp))
+ (save-excursion
+ (not (eq 'entry (ledger-thing-at-point)))))
+ (if (looking-at "\\s-+[*!]")
+ (ledger-toggle-current-transaction nil))
+ (forward-line)
+ (goto-char (line-beginning-position))))
+ (ledger-toggle-current-entry style))
(ledger-toggle-current-transaction style)))
(defvar ledger-mode-abbrev-table)
@@ -440,7 +440,7 @@ dropped."
(if (boundp 'font-lock-defaults)
(set (make-local-variable 'font-lock-defaults)
- '(ledger-font-lock-keywords nil t)))
+ '(ledger-font-lock-keywords nil t)))
(set (make-local-variable 'pcomplete-parse-arguments-function)
'ledger-parse-arguments)
@@ -475,41 +475,41 @@ dropped."
(defun ledger-display-balance ()
(let ((buffer ledger-buf)
- (account ledger-acct))
+ (account ledger-acct))
(with-temp-buffer
(let ((exit-code (ledger-run-ledger buffer "-C" "balance" account)))
- (if (/= 0 exit-code)
- (message "Error determining cleared balance")
- (goto-char (1- (point-max)))
- (goto-char (line-beginning-position))
- (delete-horizontal-space)
- (message "Cleared balance = %s"
- (buffer-substring-no-properties (point)
- (line-end-position))))))))
+ (if (/= 0 exit-code)
+ (message "Error determining cleared balance")
+ (goto-char (1- (point-max)))
+ (goto-char (line-beginning-position))
+ (delete-horizontal-space)
+ (message "Cleared balance = %s"
+ (buffer-substring-no-properties (point)
+ (line-end-position))))))))
(defun ledger-reconcile-toggle ()
(interactive)
(let ((where (get-text-property (point) 'where))
- (account ledger-acct)
- (inhibit-read-only t)
- cleared)
+ (account ledger-acct)
+ (inhibit-read-only t)
+ cleared)
(when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin"))
(with-current-buffer ledger-buf
- (goto-char (cdr where))
- (setq cleared (ledger-toggle-current 'pending)))
+ (goto-char (cdr where))
+ (setq cleared (ledger-toggle-current 'pending)))
(if cleared
- (add-text-properties (line-beginning-position)
- (line-end-position)
- (list 'face 'bold))
- (remove-text-properties (line-beginning-position)
- (line-end-position)
- (list 'face))))
+ (add-text-properties (line-beginning-position)
+ (line-end-position)
+ (list 'face 'bold))
+ (remove-text-properties (line-beginning-position)
+ (line-end-position)
+ (list 'face))))
(forward-line)))
(defun ledger-reconcile-refresh ()
(interactive)
(let ((inhibit-read-only t)
- (line (count-lines (point-min) (point))))
+ (line (count-lines (point-min) (point))))
(erase-buffer)
(ledger-do-reconcile)
(set-buffer-modified-p t)
@@ -519,9 +519,9 @@ dropped."
(defun ledger-reconcile-refresh-after-save ()
(let ((buf (get-buffer "*Reconcile*")))
(if buf
- (with-current-buffer buf
- (ledger-reconcile-refresh)
- (set-buffer-modified-p nil)))))
+ (with-current-buffer buf
+ (ledger-reconcile-refresh)
+ (set-buffer-modified-p nil)))))
(defun ledger-reconcile-add ()
(interactive)
@@ -534,12 +534,12 @@ dropped."
(let ((where (get-text-property (point) 'where)))
(when (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin"))
(with-current-buffer ledger-buf
- (goto-char (cdr where))
- (ledger-delete-current-entry))
+ (goto-char (cdr where))
+ (ledger-delete-current-entry))
(let ((inhibit-read-only t))
- (goto-char (line-beginning-position))
- (delete-region (point) (1+ (line-end-position)))
- (set-buffer-modified-p t)))))
+ (goto-char (line-beginning-position))
+ (delete-region (point) (1+ (line-end-position)))
+ (set-buffer-modified-p t)))))
(defun ledger-reconcile-visit ()
(interactive)
@@ -565,53 +565,53 @@ dropped."
(goto-char (point-min))
(while (not (eobp))
(let ((where (get-text-property (point) 'where))
- (face (get-text-property (point) 'face)))
- (if (and (eq face 'bold)
- (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")))
- (with-current-buffer ledger-buf
- (goto-char (cdr where))
- (ledger-toggle-current 'cleared))))
+ (face (get-text-property (point) 'face)))
+ (if (and (eq face 'bold)
+ (or (equal (car where) "<stdin>") (equal (car where) "/dev/stdin")))
+ (with-current-buffer ledger-buf
+ (goto-char (cdr where))
+ (ledger-toggle-current 'cleared))))
(forward-line 1)))
(ledger-reconcile-save))
(defun ledger-do-reconcile ()
(let* ((buf ledger-buf)
- (account ledger-acct)
- (items
- (with-temp-buffer
- (let ((exit-code
- (ledger-run-ledger buf "--uncleared" "emacs" account)))
- (when (= 0 exit-code)
- (goto-char (point-min))
- (unless (eobp)
- (unless (looking-at "(")
- (error (buffer-string)))
- (read (current-buffer))))))))
+ (account ledger-acct)
+ (items
+ (with-temp-buffer
+ (let ((exit-code
+ (ledger-run-ledger buf "--uncleared" "emacs" account)))
+ (when (= 0 exit-code)
+ (goto-char (point-min))
+ (unless (eobp)
+ (unless (looking-at "(")
+ (error (buffer-string)))
+ (read (current-buffer))))))))
(dolist (item items)
(let ((index 1))
- (dolist (xact (nthcdr 5 item))
- (let ((beg (point))
- (where
- (with-current-buffer buf
- (cons
- (nth 0 item)
- (if ledger-clear-whole-entries
- (save-excursion
- (goto-line (nth 1 item))
- (point-marker))
- (save-excursion
- (goto-line (nth 0 xact))
- (point-marker)))))))
- (insert (format "%s %-30s %-25s %15s\n"
- (format-time-string "%m/%d" (nth 2 item))
- (nth 4 item) (nth 1 xact) (nth 2 xact)))
- (if (nth 3 xact)
- (set-text-properties beg (1- (point))
- (list 'face 'bold
- 'where where))
- (set-text-properties beg (1- (point))
- (list 'where where))))
- (setq index (1+ index)))))
+ (dolist (xact (nthcdr 5 item))
+ (let ((beg (point))
+ (where
+ (with-current-buffer buf
+ (cons
+ (nth 0 item)
+ (if ledger-clear-whole-entries
+ (save-excursion
+ (goto-line (nth 1 item))
+ (point-marker))
+ (save-excursion
+ (goto-line (nth 0 xact))
+ (point-marker)))))))
+ (insert (format "%s %-30s %-25s %15s\n"
+ (format-time-string "%m/%d" (nth 2 item))
+ (nth 4 item) (nth 1 xact) (nth 2 xact)))
+ (if (nth 3 xact)
+ (set-text-properties beg (1- (point))
+ (list 'face 'bold
+ 'where where))
+ (set-text-properties beg (1- (point))
+ (list 'where where))))
+ (setq index (1+ index)))))
(goto-char (point-min))
(set-buffer-modified-p nil)
(toggle-read-only t)))
@@ -619,12 +619,12 @@ dropped."
(defun ledger-reconcile (account)
(interactive "sAccount to reconcile: ")
(let ((buf (current-buffer))
- (rbuf (get-buffer "*Reconcile*")))
+ (rbuf (get-buffer "*Reconcile*")))
(if rbuf
- (kill-buffer rbuf))
+ (kill-buffer rbuf))
(add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save)
(with-current-buffer
- (pop-to-buffer (get-buffer-create "*Reconcile*"))
+ (pop-to-buffer (get-buffer-create "*Reconcile*"))
(ledger-reconcile-mode)
(set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-acct) account)
@@ -681,24 +681,24 @@ dropped."
Assumes point is at beginning of line, and the pos argument specifies
where the \"users\" point was."
(let ((linfo (assoc line-type ledger-line-config))
- found field fields)
+ found field fields)
(dolist (re-info (nth 1 linfo))
(let ((re (nth 0 re-info))
- (names (nth 1 re-info)))
- (unless found
- (when (looking-at re)
- (setq found t)
- (dotimes (i (length names))
- (when (nth i names)
- (setq fields (append fields
- (list
- (list (nth i names)
- (match-string-no-properties (1+ i))
- (match-beginning (1+ i))))))))
- (dolist (f fields)
- (and (nth 1 f)
- (>= pos (nth 2 f))
- (setq field (nth 0 f))))))))
+ (names (nth 1 re-info)))
+ (unless found
+ (when (looking-at re)
+ (setq found t)
+ (dotimes (i (length names))
+ (when (nth i names)
+ (setq fields (append fields
+ (list
+ (list (nth i names)
+ (match-string-no-properties (1+ i))
+ (match-beginning (1+ i))))))))
+ (dolist (f fields)
+ (and (nth 1 f)
+ (>= pos (nth 2 f))
+ (setq field (nth 0 f))))))))
(list line-type field fields)))
(defun ledger-context-at-point ()
@@ -711,40 +711,40 @@ the fields in the line in a association list."
(save-excursion
(beginning-of-line)
(let ((first-char (char-after)))
- (cond ((equal (point) (line-end-position))
- '(empty-line nil nil))
- ((memq first-char '(?\ ?\t))
- (ledger-extract-context-info 'acct-transaction pos))
- ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
- (ledger-extract-context-info 'entry pos))
- ((equal first-char ?\=)
- '(automated-entry nil nil))
- ((equal first-char ?\~)
- '(period-entry nil nil))
- ((equal first-char ?\!)
- '(command-directive))
- ((equal first-char ?\;)
- '(comment nil nil))
- ((equal first-char ?Y)
- '(default-year nil nil))
- ((equal first-char ?P)
- '(commodity-price nil nil))
- ((equal first-char ?N)
- '(price-ignored-commodity nil nil))
- ((equal first-char ?D)
- '(default-commodity nil nil))
- ((equal first-char ?C)
- '(commodity-conversion nil nil))
- ((equal first-char ?i)
- '(timeclock-i nil nil))
- ((equal first-char ?o)
- '(timeclock-o nil nil))
- ((equal first-char ?b)
- '(timeclock-b nil nil))
- ((equal first-char ?h)
- '(timeclock-h nil nil))
- (t
- '(unknown nil nil)))))))
+ (cond ((equal (point) (line-end-position))
+ '(empty-line nil nil))
+ ((memq first-char '(?\ ?\t))
+ (ledger-extract-context-info 'acct-transaction pos))
+ ((memq first-char '(?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9))
+ (ledger-extract-context-info 'entry pos))
+ ((equal first-char ?\=)
+ '(automated-entry nil nil))
+ ((equal first-char ?\~)
+ '(period-entry nil nil))
+ ((equal first-char ?\!)
+ '(command-directive))
+ ((equal first-char ?\;)
+ '(comment nil nil))
+ ((equal first-char ?Y)
+ '(default-year nil nil))
+ ((equal first-char ?P)
+ '(commodity-price nil nil))
+ ((equal first-char ?N)
+ '(price-ignored-commodity nil nil))
+ ((equal first-char ?D)
+ '(default-commodity nil nil))
+ ((equal first-char ?C)
+ '(commodity-conversion nil nil))
+ ((equal first-char ?i)
+ '(timeclock-i nil nil))
+ ((equal first-char ?o)
+ '(timeclock-o nil nil))
+ ((equal first-char ?b)
+ '(timeclock-b nil nil))
+ ((equal first-char ?h)
+ '(timeclock-h nil nil))
+ (t
+ '(unknown nil nil)))))))
(defun ledger-context-other-line (offset)
"Return a list describing context of line offset for existing position.
@@ -754,8 +754,8 @@ specified line, returns nil."
(save-excursion
(let ((left (forward-line offset)))
(if (not (equal left 0))
- nil
- (ledger-context-at-point)))))
+ nil
+ (ledger-context-at-point)))))
(defun ledger-context-line-type (context-info)
(nth 0 context-info))
@@ -792,8 +792,8 @@ specified line, returns nil."
(setq i (- i 1)))
(let ((context-info (ledger-context-other-line i)))
(if (eq (ledger-context-line-type context-info) 'entry)
- (ledger-context-field-value context-info 'payee)
- nil))))
+ (ledger-context-field-value context-info 'payee)
+ nil))))
;; Ledger report mode
@@ -832,8 +832,8 @@ specified line, returns nil."
The empty string and unknown names are allowed."
(completing-read "Report name: "
- ledger-reports nil nil nil
- 'ledger-report-name-prompt-history nil))
+ ledger-reports nil nil nil
+ 'ledger-report-name-prompt-history nil))
(defun ledger-report (report-name edit)
"Run a user-specified report from `ledger-reports'.
@@ -852,18 +852,18 @@ used to generate the buffer, navigating the buffer, etc."
(interactive
(progn
(when (and (buffer-modified-p)
- (y-or-n-p "Buffer modified, save it? "))
+ (y-or-n-p "Buffer modified, save it? "))
(save-buffer))
(let ((rname (ledger-report-read-name))
- (edit (not (null current-prefix-arg))))
+ (edit (not (null current-prefix-arg))))
(list rname edit))))
(let ((buf (current-buffer))
- (rbuf (get-buffer ledger-report-buffer-name))
- (wcfg (current-window-configuration)))
+ (rbuf (get-buffer ledger-report-buffer-name))
+ (wcfg (current-window-configuration)))
(if rbuf
- (kill-buffer rbuf))
+ (kill-buffer rbuf))
(with-current-buffer
- (pop-to-buffer (get-buffer-create ledger-report-buffer-name))
+ (pop-to-buffer (get-buffer-create ledger-report-buffer-name))
(ledger-report-mode)
(set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-report-name) report-name)
@@ -896,8 +896,8 @@ If name exists, returns the object naming the report, otherwise returns nil."
(defun ledger-report-read-command (report-cmd)
"Read the command line to create a report."
(read-from-minibuffer "Report command line: "
- (if (null report-cmd) "ledger " report-cmd)
- nil nil 'ledger-report-cmd-prompt-history))
+ (if (null report-cmd) "ledger " report-cmd)
+ nil nil 'ledger-report-cmd-prompt-history))
(defun ledger-report-ledger-file-format-specifier ()
"Substitute the full path to master or current ledger file
@@ -909,9 +909,9 @@ otherwise the current buffer file is used."
(defun ledger-read-string-with-default (prompt default)
(let ((default-prompt (concat prompt
- (if default
- (concat " (" default "): ")
- ": "))))
+ (if default
+ (concat " (" default "): ")
+ ": "))))
(read-string default-prompt nil nil default)))
(defun ledger-report-payee-format-specifier ()
@@ -935,26 +935,26 @@ the default."
;; It is intended completion should be available on existing account
;; names, but it remains to be implemented.
(let* ((context (ledger-context-at-point))
- (default
- (if (eq (ledger-context-line-type context) 'acct-transaction)
- (regexp-quote (ledger-context-field-value context 'account))
- nil)))
+ (default
+ (if (eq (ledger-context-line-type context) 'acct-transaction)
+ (regexp-quote (ledger-context-field-value context 'account))
+ nil)))
(ledger-read-string-with-default "Account" default)))
(defun ledger-report-expand-format-specifiers (report-cmd)
(let ((expanded-cmd report-cmd))
(while (string-match "%(\\([^)]*\\))" expanded-cmd)
(let* ((specifier (match-string 1 expanded-cmd))
- (f (cdr (assoc specifier ledger-report-format-specifiers))))
- (if f
- (setq expanded-cmd (replace-match
- (save-match-data
- (with-current-buffer ledger-buf
- (shell-quote-argument (funcall f))))
- t t expanded-cmd))
- (progn
- (set-window-configuration ledger-original-window-cfg)
- (error "Invalid ledger report format specifier '%s'" specifier)))))
+ (f (cdr (assoc specifier ledger-report-format-specifiers))))
+ (if f
+ (setq expanded-cmd (replace-match
+ (save-match-data
+ (with-current-buffer ledger-buf
+ (shell-quote-argument (funcall f))))
+ t t expanded-cmd))
+ (progn
+ (set-window-configuration ledger-original-window-cfg)
+ (error "Invalid ledger report format specifier '%s'" specifier)))))
expanded-cmd))
(defun ledger-report-cmd (report-name edit)
@@ -966,18 +966,18 @@ the default."
(setq report-cmd (ledger-report-expand-format-specifiers report-cmd))
(set (make-local-variable 'ledger-report-cmd) report-cmd)
(or (string-empty-p report-name)
- (ledger-report-name-exists report-name)
- (ledger-reports-add report-name report-cmd)
- (ledger-reports-custom-save))
+ (ledger-report-name-exists report-name)
+ (ledger-reports-add report-name report-cmd)
+ (ledger-reports-custom-save))
report-cmd))
(defun ledger-do-report (cmd)
"Run a report command line."
(goto-char (point-min))
(insert (format "Report: %s\n" ledger-report-name)
- (format "Command: %s\n" cmd)
- (make-string (- (window-width) 1) ?=)
- "\n")
+ (format "Command: %s\n" cmd)
+ (make-string (- (window-width) 1) ?=)
+ "\n")
(shell-command cmd t nil))
(defun ledger-report-goto ()
@@ -985,7 +985,7 @@ the default."
(interactive)
(let ((rbuf (get-buffer ledger-report-buffer-name)))
(if (not rbuf)
- (error "There is no ledger report buffer"))
+ (error "There is no ledger report buffer"))
(pop-to-buffer rbuf)
(shrink-window-if-larger-than-buffer)))
@@ -1021,7 +1021,7 @@ the default."
(let ((name ""))
(while (string-empty-p name)
(setq name (read-from-minibuffer "Report name: " nil nil nil
- 'ledger-report-name-prompt-history)))
+ 'ledger-report-name-prompt-history)))
name))
(defun ledger-report-save ()
@@ -1034,15 +1034,15 @@ the default."
(while (setq existing-name (ledger-report-name-exists ledger-report-name))
(cond ((y-or-n-p (format "Overwrite existing report named '%s' "
- ledger-report-name))
- (when (string-equal
- ledger-report-cmd
- (car (cdr (assq existing-name ledger-reports))))
- (error "Current command is identical to existing saved one"))
- (setq ledger-reports
- (assq-delete-all existing-name ledger-reports)))
- (t
- (setq ledger-report-name (ledger-report-read-new-name)))))
+ ledger-report-name))
+ (when (string-equal
+ ledger-report-cmd
+ (car (cdr (assq existing-name ledger-reports))))
+ (error "Current command is identical to existing saved one"))
+ (setq ledger-reports
+ (assq-delete-all existing-name ledger-reports)))
+ (t
+ (setq ledger-report-name (ledger-report-read-new-name)))))
(ledger-reports-add ledger-report-name ledger-report-cmd)
(ledger-reports-custom-save)))
@@ -1053,46 +1053,46 @@ the default."
(let ((here (point)))
(goto-char (line-beginning-position))
(cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+")
- (goto-char (match-end 0))
- 'entry)
- ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)")
- (goto-char (match-beginning 2))
- 'transaction)
- ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+")
- (goto-char (match-end 0))
- 'entry)
- (t
- (ignore (goto-char here))))))
+ (goto-char (match-end 0))
+ 'entry)
+ ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)")
+ (goto-char (match-beginning 2))
+ 'transaction)
+ ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+")
+ (goto-char (match-end 0))
+ 'entry)
+ (t
+ (ignore (goto-char here))))))
(defun ledger-parse-arguments ()
"Parse whitespace separated arguments in the current region."
(let* ((info (save-excursion
- (cons (ledger-thing-at-point) (point))))
- (begin (cdr info))
- (end (point))
- begins args)
+ (cons (ledger-thing-at-point) (point))))
+ (begin (cdr info))
+ (end (point))
+ begins args)
(save-excursion
(goto-char begin)
(when (< (point) end)
- (skip-chars-forward " \t\n")
- (setq begins (cons (point) begins))
- (setq args (cons (buffer-substring-no-properties
- (car begins) end)
- args)))
+ (skip-chars-forward " \t\n")
+ (setq begins (cons (point) begins))
+ (setq args (cons (buffer-substring-no-properties
+ (car begins) end)
+ args)))
(cons (reverse args) (reverse begins)))))
(defun ledger-entries ()
(let ((origin (point))
- entries-list)
+ entries-list)
(save-excursion
(goto-char (point-min))
(while (re-search-forward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
- (unless (and (>= origin (match-beginning 0))
- (< origin (match-end 0)))
- (setq entries-list (cons (match-string-no-properties 3)
- entries-list)))))
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (unless (and (>= origin (match-beginning 0))
+ (< origin (match-end 0)))
+ (setq entries-list (cons (match-string-no-properties 3)
+ entries-list)))))
(pcomplete-uniqify-list (nreverse entries-list))))
(defvar ledger-account-tree nil)
@@ -1103,100 +1103,100 @@ the default."
(setq ledger-account-tree (list t))
(goto-char (point-min))
(while (re-search-forward
- "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t)
- (unless (and (>= origin (match-beginning 0))
- (< origin (match-end 0)))
- (setq account-path (match-string-no-properties 2))
- (setq elements (split-string account-path ":"))
- (let ((root ledger-account-tree))
- (while elements
- (let ((entry (assoc (car elements) root)))
- (if entry
- (setq root (cdr entry))
- (setq entry (cons (car elements) (list t)))
- (nconc root (list entry))
- (setq root (cdr entry))))
- (setq elements (cdr elements)))))))))
+ "^[ \t]+\\([*!]\\s-+\\)?[[(]?\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)" nil t)
+ (unless (and (>= origin (match-beginning 0))
+ (< origin (match-end 0)))
+ (setq account-path (match-string-no-properties 2))
+ (setq elements (split-string account-path ":"))
+ (let ((root ledger-account-tree))
+ (while elements
+ (let ((entry (assoc (car elements) root)))
+ (if entry
+ (setq root (cdr entry))
+ (setq entry (cons (car elements) (list t)))
+ (nconc root (list entry))
+ (setq root (cdr entry))))
+ (setq elements (cdr elements)))))))))
(defun ledger-accounts ()
(ledger-find-accounts)
(let* ((current (caar (ledger-parse-arguments)))
- (elements (and current (split-string current ":")))
- (root ledger-account-tree)
- (prefix nil))
+ (elements (and current (split-string current ":")))
+ (root ledger-account-tree)
+ (prefix nil))
(while (cdr elements)
(let ((entry (assoc (car elements) root)))
- (if entry
- (setq prefix (concat prefix (and prefix ":")
- (car elements))
- root (cdr entry))
- (setq root nil elements nil)))
+ (if entry
+ (setq prefix (concat prefix (and prefix ":")
+ (car elements))
+ root (cdr entry))
+ (setq root nil elements nil)))
(setq elements (cdr elements)))
(and root
- (sort
- (mapcar (function
- (lambda (x)
- (let ((term (if prefix
- (concat prefix ":" (car x))
- (car x))))
- (if (> (length (cdr x)) 1)
- (concat term ":")
- term))))
- (cdr root))
- 'string-lessp))))
+ (sort
+ (mapcar (function
+ (lambda (x)
+ (let ((term (if prefix
+ (concat prefix ":" (car x))
+ (car x))))
+ (if (> (length (cdr x)) 1)
+ (concat term ":")
+ term))))
+ (cdr root))
+ 'string-lessp))))
(defun ledger-complete-at-point ()
"Do appropriate completion for the thing at point"
(interactive)
(while (pcomplete-here
- (if (eq (save-excursion
- (ledger-thing-at-point)) 'entry)
- (if (null current-prefix-arg)
- (ledger-entries) ; this completes against entry names
- (progn
- (let ((text (buffer-substring (line-beginning-position)
- (line-end-position))))
- (delete-region (line-beginning-position)
- (line-end-position))
- (condition-case err
- (ledger-add-entry text t)
- ((error)
- (insert text))))
- (forward-line)
- (goto-char (line-end-position))
- (search-backward ";" (line-beginning-position) t)
- (skip-chars-backward " \t0123456789.,")
- (throw 'pcompleted t)))
- (ledger-accounts)))))
+ (if (eq (save-excursion
+ (ledger-thing-at-point)) 'entry)
+ (if (null current-prefix-arg)
+ (ledger-entries) ; this completes against entry names
+ (progn
+ (let ((text (buffer-substring (line-beginning-position)
+ (line-end-position))))
+ (delete-region (line-beginning-position)
+ (line-end-position))
+ (condition-case err
+ (ledger-add-entry text t)
+ ((error)
+ (insert text))))
+ (forward-line)
+ (goto-char (line-end-position))
+ (search-backward ";" (line-beginning-position) t)
+ (skip-chars-backward " \t0123456789.,")
+ (throw 'pcompleted t)))
+ (ledger-accounts)))))
(defun ledger-fully-complete-entry ()
"Do appropriate completion for the thing at point"
(interactive)
(let ((name (caar (ledger-parse-arguments)))
- xacts)
+ xacts)
(save-excursion
(when (eq 'entry (ledger-thing-at-point))
- (when (re-search-backward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t)
- (forward-line)
- (while (looking-at "^\\s-+")
- (setq xacts (cons (buffer-substring-no-properties
- (line-beginning-position)
- (line-end-position))
- xacts))
- (forward-line))
- (setq xacts (nreverse xacts)))))
+ (when (re-search-backward
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ (regexp-quote name) "\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (forward-line)
+ (while (looking-at "^\\s-+")
+ (setq xacts (cons (buffer-substring-no-properties
+ (line-beginning-position)
+ (line-end-position))
+ xacts))
+ (forward-line))
+ (setq xacts (nreverse xacts)))))
(when xacts
(save-excursion
- (insert ?\n)
- (while xacts
- (insert (car xacts) ?\n)
- (setq xacts (cdr xacts))))
+ (insert ?\n)
+ (while xacts
+ (insert (car xacts) ?\n)
+ (setq xacts (cdr xacts))))
(forward-line)
(goto-char (line-end-position))
(if (re-search-backward "\\(\t\\| [ \t]\\)" nil t)
- (goto-char (match-end 0))))))
+ (goto-char (match-end 0))))))
;; A sample function for $ users
@@ -1205,7 +1205,7 @@ the default."
(goto-char (match-beginning 0))
(skip-syntax-forward " ")
(- (or (match-end 4)
- (match-end 3)) (point))))
+ (match-end 3)) (point))))
(defun ledger-align-amounts (&optional column)
"Align amounts in the current region.
@@ -1215,24 +1215,24 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
(setq column 52))
(save-excursion
(let* ((mark-first (< (mark) (point)))
- (begin (if mark-first (mark) (point)))
- (end (if mark-first (point-marker) (mark-marker)))
- offset)
+ (begin (if mark-first (mark) (point)))
+ (end (if mark-first (point-marker) (mark-marker)))
+ offset)
(goto-char begin)
(while (setq offset (ledger-next-amount end))
- (let ((col (current-column))
- (target-col (- column offset))
- adjust)
- (setq adjust (- target-col col))
- (if (< col target-col)
- (insert (make-string (- target-col col) ? ))
- (move-to-column target-col)
- (if (looking-back " ")
- (delete-char (- col target-col))
- (skip-chars-forward "^ \t")
- (delete-horizontal-space)
- (insert " ")))
- (forward-line))))))
+ (let ((col (current-column))
+ (target-col (- column offset))
+ adjust)
+ (setq adjust (- target-col col))
+ (if (< col target-col)
+ (insert (make-string (- target-col col) ? ))
+ (move-to-column target-col)
+ (if (looking-back " ")
+ (delete-char (- col target-col))
+ (skip-chars-forward "^ \t")
+ (delete-horizontal-space)
+ (insert " ")))
+ (forward-line))))))
(defalias 'ledger-align-dollars 'ledger-align-amounts)
@@ -1247,14 +1247,14 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
nil
(function
(lambda ()
- (if (re-search-forward
- (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
- "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
- (goto-char (match-beginning 0))
- (goto-char (point-max)))))
+ (if (re-search-forward
+ (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+"
+ "\\(.+?\\)\\(\t\\|\n\\| [ \t]\\)") nil t)
+ (goto-char (match-beginning 0))
+ (goto-char (point-max)))))
(function
(lambda ()
- (forward-paragraph))))))
+ (forward-paragraph))))))
;; General helper functions
@@ -1269,13 +1269,13 @@ This is done so that the last digit falls in COLUMN, which defaults to 52."
(t
(let ((buf (current-buffer)))
(with-current-buffer buffer
- (let ((coding-system-for-write 'utf-8)
- (coding-system-for-read 'utf-8))
- (apply #'call-process-region
- (append (list (point-min) (point-max)
- ledger-binary-path ledger-delete-after
- buf nil "-f" "-")
- args))))))))
+ (let ((coding-system-for-write 'utf-8)
+ (coding-system-for-read 'utf-8))
+ (apply #'call-process-region
+ (append (list (point-min) (point-max)
+ ledger-binary-path ledger-delete-after
+ buf nil "-f" "-")
+ args))))))))
(defun ledger-run-ledger-and-delete (buffer &rest args)
(let ((ledger-delete-after t))
diff --git a/lisp/timeclock.el b/lisp/timeclock.el
index 03159e94..2cafa8eb 100644
--- a/lisp/timeclock.el
+++ b/lisp/timeclock.el
@@ -135,10 +135,10 @@ that day has a length that is different from the norm."
"*If non-nil, ask if the user wants to clock out before exiting Emacs.
This variable only has effect if set with \\[customize]."
:set (lambda (symbol value)
- (if value
- (add-hook 'kill-emacs-query-functions 'timeclock-query-out)
- (remove-hook 'kill-emacs-query-functions 'timeclock-query-out))
- (setq timeclock-ask-before-exiting value))
+ (if value
+ (add-hook 'kill-emacs-query-functions 'timeclock-query-out)
+ (remove-hook 'kill-emacs-query-functions 'timeclock-query-out))
+ (setq timeclock-ask-before-exiting value))
:type 'boolean
:group 'timeclock)
@@ -160,27 +160,27 @@ while timeclock information is being displayed in the modeline has no
effect. You should call the function `timeclock-modeline-display' with
a positive argument to force an update."
:set (lambda (symbol value)
- (let ((currently-displaying
- (and (boundp 'timeclock-modeline-display)
- timeclock-modeline-display)))
- ;; if we're changing to the state that
- ;; `timeclock-modeline-display' is already using, don't
- ;; bother toggling it. This happens on the initial loading
- ;; of timeclock.el.
- (if (and currently-displaying
- (or (and value
- (boundp 'display-time-hook)
- (memq 'timeclock-update-modeline
- display-time-hook))
- (and (not value)
- timeclock-update-timer)))
- (setq currently-displaying nil))
- (and currently-displaying
- (set-variable 'timeclock-modeline-display nil))
- (setq timeclock-use-display-time value)
- (and currently-displaying
- (set-variable 'timeclock-modeline-display t))
- timeclock-use-display-time))
+ (let ((currently-displaying
+ (and (boundp 'timeclock-modeline-display)
+ timeclock-modeline-display)))
+ ;; if we're changing to the state that
+ ;; `timeclock-modeline-display' is already using, don't
+ ;; bother toggling it. This happens on the initial loading
+ ;; of timeclock.el.
+ (if (and currently-displaying
+ (or (and value
+ (boundp 'display-time-hook)
+ (memq 'timeclock-update-modeline
+ display-time-hook))
+ (and (not value)
+ timeclock-update-timer)))
+ (setq currently-displaying nil))
+ (and currently-displaying
+ (set-variable 'timeclock-modeline-display nil))
+ (setq timeclock-use-display-time value)
+ (and currently-displaying
+ (set-variable 'timeclock-modeline-display t))
+ timeclock-use-display-time))
:type 'boolean
:group 'timeclock
:require 'time)
@@ -281,39 +281,39 @@ display (non-nil means on)."
(setq timeclock-mode-string "")
(or global-mode-string (setq global-mode-string '("")))
(let ((on-p (if arg
- (> (prefix-numeric-value arg) 0)
- (not timeclock-modeline-display))))
+ (> (prefix-numeric-value arg) 0)
+ (not timeclock-modeline-display))))
(if on-p
- (progn
- (or (memq 'timeclock-mode-string global-mode-string)
- (setq global-mode-string
- (append global-mode-string '(timeclock-mode-string))))
- (unless (memq 'timeclock-update-modeline timeclock-event-hook)
- (add-hook 'timeclock-event-hook 'timeclock-update-modeline))
- (when timeclock-update-timer
- (cancel-timer timeclock-update-timer)
- (setq timeclock-update-timer nil))
- (if (boundp 'display-time-hook)
- (remove-hook 'display-time-hook 'timeclock-update-modeline))
- (if timeclock-use-display-time
- (progn
- ;; Update immediately so there is a visible change
- ;; on calling this function.
- (if display-time-mode (timeclock-update-modeline)
- (message "Activate `display-time-mode' to see \
+ (progn
+ (or (memq 'timeclock-mode-string global-mode-string)
+ (setq global-mode-string
+ (append global-mode-string '(timeclock-mode-string))))
+ (unless (memq 'timeclock-update-modeline timeclock-event-hook)
+ (add-hook 'timeclock-event-hook 'timeclock-update-modeline))
+ (when timeclock-update-timer
+ (cancel-timer timeclock-update-timer)
+ (setq timeclock-update-timer nil))
+ (if (boundp 'display-time-hook)
+ (remove-hook 'display-time-hook 'timeclock-update-modeline))
+ (if timeclock-use-display-time
+ (progn
+ ;; Update immediately so there is a visible change
+ ;; on calling this function.
+ (if display-time-mode (timeclock-update-modeline)
+ (message "Activate `display-time-mode' to see \
timeclock information"))
- (add-hook 'display-time-hook 'timeclock-update-modeline))
- (setq timeclock-update-timer
- (run-at-time nil 60 'timeclock-update-modeline))))
+ (add-hook 'display-time-hook 'timeclock-update-modeline))
+ (setq timeclock-update-timer
+ (run-at-time nil 60 'timeclock-update-modeline))))
(setq global-mode-string
- (delq 'timeclock-mode-string global-mode-string))
+ (delq 'timeclock-mode-string global-mode-string))
(remove-hook 'timeclock-event-hook 'timeclock-update-modeline)
(if (boundp 'display-time-hook)
- (remove-hook 'display-time-hook
- 'timeclock-update-modeline))
+ (remove-hook 'display-time-hook
+ 'timeclock-update-modeline))
(when timeclock-update-timer
- (cancel-timer timeclock-update-timer)
- (setq timeclock-update-timer nil)))
+ (cancel-timer timeclock-update-timer)
+ (setq timeclock-update-timer nil)))
(force-mode-line-update)
(setq timeclock-modeline-display on-p)))
@@ -323,8 +323,8 @@ timeclock information"))
"Toggle modeline display of time remaining.
You must modify via \\[customize] for this variable to have an effect."
:set (lambda (symbol value)
- (setq timeclock-modeline-display
- (timeclock-modeline-display (or value 0))))
+ (setq timeclock-modeline-display
+ (timeclock-modeline-display (or value 0))))
:type 'boolean
:group 'timeclock
:require 'timeclock)
@@ -349,34 +349,34 @@ interactively -- call the function `timeclock-get-project-function' to
discover the name of the project."
(interactive
(list (and current-prefix-arg
- (if (numberp current-prefix-arg)
- (* current-prefix-arg 60 60)
- 0))))
+ (if (numberp current-prefix-arg)
+ (* current-prefix-arg 60 60)
+ 0))))
(if (equal (car timeclock-last-event) "i")
(error "You've already clocked in!")
(unless timeclock-last-event
(timeclock-reread-log))
;; Either no log file, or day has rolled over.
(unless (and timeclock-last-event
- (equal (timeclock-time-to-date
- (cadr timeclock-last-event))
- (timeclock-time-to-date (current-time))))
+ (equal (timeclock-time-to-date
+ (cadr timeclock-last-event))
+ (timeclock-time-to-date (current-time))))
(let ((workday (or (and (numberp arg) arg)
- (and arg 0)
- (and timeclock-get-workday-function
- (funcall timeclock-get-workday-function))
- timeclock-workday)))
- (run-hooks 'timeclock-first-in-hook)
- ;; settle the discrepancy for the new day
- (setq timeclock-discrepancy
- (- (or timeclock-discrepancy 0) workday))
- (if (not (= workday timeclock-workday))
- (timeclock-log "h" (and (numberp arg)
- (number-to-string arg))))))
+ (and arg 0)
+ (and timeclock-get-workday-function
+ (funcall timeclock-get-workday-function))
+ timeclock-workday)))
+ (run-hooks 'timeclock-first-in-hook)
+ ;; settle the discrepancy for the new day
+ (setq timeclock-discrepancy
+ (- (or timeclock-discrepancy 0) workday))
+ (if (not (= workday timeclock-workday))
+ (timeclock-log "h" (and (numberp arg)
+ (number-to-string arg))))))
(timeclock-log "i" (or project
- (and timeclock-get-project-function
- (or find-project (interactive-p))
- (funcall timeclock-get-project-function))))
+ (and timeclock-get-project-function
+ (or find-project (interactive-p))
+ (funcall timeclock-get-project-function))))
(run-hooks 'timeclock-in-hook)))
;;;###autoload
@@ -397,12 +397,12 @@ discover the reason."
(timeclock-log
(if arg "O" "o")
(or reason
- (and timeclock-get-reason-function
- (or find-reason (interactive-p))
- (funcall timeclock-get-reason-function))))
+ (and timeclock-get-reason-function
+ (or find-reason (interactive-p))
+ (funcall timeclock-get-reason-function))))
(run-hooks 'timeclock-out-hook)
(if arg
- (run-hooks 'timeclock-done-hook))))
+ (run-hooks 'timeclock-done-hook))))
;; Should today-only be removed in favour of timeclock-relative? - gm
(defsubst timeclock-workday-remaining (&optional today-only)
@@ -412,8 +412,8 @@ If TODAY-ONLY is non-nil, the value returned will be relative only to
the time worked today, and not to past time."
(let ((discrep (timeclock-find-discrep)))
(if discrep
- (- (if today-only (cadr discrep)
- (car discrep)))
+ (- (if today-only (cadr discrep)
+ (car discrep)))
0.0)))
;;;###autoload
@@ -424,24 +424,24 @@ If TODAY-ONLY is non-nil, the display will be relative only to time
worked today, ignoring the time worked on previous days."
(interactive "P")
(let ((remainder (timeclock-workday-remaining)) ; today-only?
- (last-in (equal (car timeclock-last-event) "i"))
- status)
+ (last-in (equal (car timeclock-last-event) "i"))
+ status)
(setq status
- (format "Currently %s since %s (%s), %s %s, leave at %s"
- (if last-in "IN" "OUT")
- (if show-seconds
- (format-time-string "%-I:%M:%S %p"
- (nth 1 timeclock-last-event))
- (format-time-string "%-I:%M %p"
- (nth 1 timeclock-last-event)))
- (or (nth 2 timeclock-last-event)
- (if last-in "**UNKNOWN**" "workday over"))
- (timeclock-seconds-to-string remainder show-seconds t)
- (if (> remainder 0)
- "remaining" "over")
- (timeclock-when-to-leave-string show-seconds today-only)))
+ (format "Currently %s since %s (%s), %s %s, leave at %s"
+ (if last-in "IN" "OUT")
+ (if show-seconds
+ (format-time-string "%-I:%M:%S %p"
+ (nth 1 timeclock-last-event))
+ (format-time-string "%-I:%M %p"
+ (nth 1 timeclock-last-event)))
+ (or (nth 2 timeclock-last-event)
+ (if last-in "**UNKNOWN**" "workday over"))
+ (timeclock-seconds-to-string remainder show-seconds t)
+ (if (> remainder 0)
+ "remaining" "over")
+ (timeclock-when-to-leave-string show-seconds today-only)))
(if (interactive-p)
- (message status)
+ (message status)
status)))
;;;###autoload
@@ -477,7 +477,7 @@ Returns the new value of `timeclock-discrepancy'."
timeclock-discrepancy)
(defun timeclock-seconds-to-string (seconds &optional show-seconds
- reverse-leader)
+ reverse-leader)
"Convert SECONDS into a compact time string.
If SHOW-SECONDS is non-nil, make the resolution of the return string
include the second count. If REVERSE-LEADER is non-nil, it means to
@@ -486,14 +486,14 @@ This is used when negative time values have an inverted meaning (such
as with time remaining, where negative time really means overtime)."
(if show-seconds
(format "%s%d:%02d:%02d"
- (if (< seconds 0) (if reverse-leader "+" "-") "")
- (truncate (/ (abs seconds) 60 60))
- (% (truncate (/ (abs seconds) 60)) 60)
- (% (truncate (abs seconds)) 60))
+ (if (< seconds 0) (if reverse-leader "+" "-") "")
+ (truncate (/ (abs seconds) 60 60))
+ (% (truncate (/ (abs seconds) 60)) 60)
+ (% (truncate (abs seconds)) 60))
(format "%s%d:%02d"
- (if (< seconds 0) (if reverse-leader "+" "-") "")
- (truncate (/ (abs seconds) 60 60))
- (% (truncate (/ (abs seconds) 60)) 60))))
+ (if (< seconds 0) (if reverse-leader "+" "-") "")
+ (truncate (/ (abs seconds) 60 60))
+ (% (truncate (/ (abs seconds) 60)) 60))))
(defsubst timeclock-currently-in-p ()
"Return non-nil if the user is currently clocked in."
@@ -501,7 +501,7 @@ as with time remaining, where negative time really means overtime)."
;;;###autoload
(defun timeclock-workday-remaining-string (&optional show-seconds
- today-only)
+ today-only)
"Return a string representing the amount of time left today.
Display second resolution if SHOW-SECONDS is non-nil. If TODAY-ONLY
is non-nil, the display will be relative only to time worked today.
@@ -509,10 +509,10 @@ See `timeclock-relative' for more information about the meaning of
\"relative to today\"."
(interactive)
(let ((string (timeclock-seconds-to-string
- (timeclock-workday-remaining today-only)
- show-seconds t)))
+ (timeclock-workday-remaining today-only)
+ show-seconds t)))
(if (interactive-p)
- (message string)
+ (message string)
string)))
(defsubst timeclock-workday-elapsed ()
@@ -522,7 +522,7 @@ time worked. The default is to return only the time that has elapsed
so far today."
(let ((discrep (timeclock-find-discrep)))
(if discrep
- (nth 2 discrep)
+ (nth 2 discrep)
0.0)))
;;;###autoload
@@ -532,9 +532,9 @@ Display seconds resolution if SHOW-SECONDS is non-nil. If RELATIVE is
non-nil, the amount returned will be relative to past time worked."
(interactive)
(let ((string (timeclock-seconds-to-string (timeclock-workday-elapsed)
- show-seconds)))
+ show-seconds)))
(if (interactive-p)
- (message string)
+ (message string)
string)))
(defsubst timeclock-time-to-seconds (time)
@@ -546,8 +546,8 @@ non-nil, the amount returned will be relative to past time worked."
(defsubst timeclock-seconds-to-time (seconds)
"Convert SECONDS (a floating point number) to an Emacs time structure."
(list (floor seconds 65536)
- (floor (mod seconds 65536))
- (floor (* (- seconds (ffloor seconds)) 1000000))))
+ (floor (mod seconds 65536))
+ (floor (* (- seconds (ffloor seconds)) 1000000))))
;; Should today-only be removed in favour of timeclock-relative? - gm
(defsubst timeclock-when-to-leave (&optional today-only)
@@ -557,15 +557,15 @@ the time worked today, and not to past time."
(timeclock-seconds-to-time
(- (timeclock-time-to-seconds (current-time))
(let ((discrep (timeclock-find-discrep)))
- (if discrep
- (if today-only
- (cadr discrep)
- (car discrep))
- 0.0)))))
+ (if discrep
+ (if today-only
+ (cadr discrep)
+ (car discrep))
+ 0.0)))))
;;;###autoload
(defun timeclock-when-to-leave-string (&optional show-seconds
- today-only)
+ today-only)
"Return a string representing the end of today's workday.
This string is relative to the value of `timeclock-workday'. If
SHOW-SECONDS is non-nil, the value printed/returned will include
@@ -574,12 +574,12 @@ relative only to the time worked today, and not to past time."
;; Should today-only be removed in favour of timeclock-relative? - gm
(interactive)
(let* ((then (timeclock-when-to-leave today-only))
- (string
- (if show-seconds
- (format-time-string "%-I:%M:%S %p" then)
- (format-time-string "%-I:%M %p" then))))
+ (string
+ (if show-seconds
+ (format-time-string "%-I:%M:%S %p" then)
+ (format-time-string "%-I:%M %p" then))))
(if (interactive-p)
- (message string)
+ (message string)
string)))
;;; Internal Functions:
@@ -591,17 +591,17 @@ relative only to the time worked today, and not to past time."
"A version of `completing-read' that works on both Emacs and XEmacs."
(if (featurep 'xemacs)
(let ((str (completing-read prompt alist)))
- (if (or (null str) (= (length str) 0))
- default
- str))
+ (if (or (null str) (= (length str) 0))
+ default
+ str))
(completing-read prompt alist nil nil nil nil default)))
(defun timeclock-ask-for-project ()
"Ask the user for the project they are clocking into."
(timeclock-completing-read
(format "Clock into which project (default \"%s\"): "
- (or timeclock-last-project
- (car timeclock-project-list)))
+ (or timeclock-last-project
+ (car timeclock-project-list)))
(mapcar 'list timeclock-project-list)
(or timeclock-last-project
(car timeclock-project-list))))
@@ -611,7 +611,7 @@ relative only to the time worked today, and not to past time."
(defun timeclock-ask-for-reason ()
"Ask the user for the reason they are clocking out."
(timeclock-completing-read "Reason for clocking out: "
- (mapcar 'list timeclock-reason-list)))
+ (mapcar 'list timeclock-reason-list)))
(defun timeclock-update-modeline ()
"Update the `timeclock-mode-string' displayed in the modeline.
@@ -619,22 +619,22 @@ The value of `timeclock-relative' affects the display as described in
that variable's documentation."
(interactive)
(let ((remainder (timeclock-workday-remaining (not timeclock-relative)))
- (last-in (equal (car timeclock-last-event) "i")))
+ (last-in (equal (car timeclock-last-event) "i")))
(when (and (< remainder 0)
- (not (and timeclock-day-over
- (equal timeclock-day-over
- (timeclock-time-to-date
- (current-time))))))
+ (not (and timeclock-day-over
+ (equal timeclock-day-over
+ (timeclock-time-to-date
+ (current-time))))))
(setq timeclock-day-over
- (timeclock-time-to-date (current-time)))
+ (timeclock-time-to-date (current-time)))
(run-hooks 'timeclock-day-over-hook))
(setq timeclock-mode-string
- (propertize
- (format " %c%s%c "
- (if last-in ?< ?[)
- (timeclock-seconds-to-string remainder nil t)
- (if last-in ?> ?]))
- 'help-echo "timeclock: time remaining"))))
+ (propertize
+ (format " %c%s%c "
+ (if last-in ?< ?[)
+ (timeclock-seconds-to-string remainder nil t)
+ (if last-in ?> ?]))
+ 'help-echo "timeclock: time remaining"))))
(put 'timeclock-mode-string 'risky-local-variable t)
@@ -645,24 +645,24 @@ being logged for. Normally only \"in\" events specify a project."
(with-current-buffer (find-file-noselect timeclock-file)
(goto-char (point-max))
(if (not (bolp))
- (insert "\n"))
+ (insert "\n"))
(let ((now (current-time)))
(insert code " "
- (format-time-string "%Y/%m/%d %H:%M:%S" now)
- (or (and project
- (stringp project)
- (> (length project) 0)
- (concat " " project))
- "")
- "\n")
+ (format-time-string "%Y/%m/%d %H:%M:%S" now)
+ (or (and project
+ (stringp project)
+ (> (length project) 0)
+ (concat " " project))
+ "")
+ "\n")
(if (equal (downcase code) "o")
- (setq timeclock-last-period
- (- (timeclock-time-to-seconds now)
- (timeclock-time-to-seconds
- (cadr timeclock-last-event)))
- timeclock-discrepancy
- (+ timeclock-discrepancy
- timeclock-last-period)))
+ (setq timeclock-last-period
+ (- (timeclock-time-to-seconds now)
+ (timeclock-time-to-seconds
+ (cadr timeclock-last-event)))
+ timeclock-discrepancy
+ (+ timeclock-discrepancy
+ timeclock-last-period)))
(setq timeclock-last-event (list code now project)))
(save-buffer)
(run-hooks 'timeclock-event-hook)
@@ -670,21 +670,21 @@ being logged for. Normally only \"in\" events specify a project."
(defvar timeclock-moment-regexp
(concat "\\([bhioO]\\)\\s-+"
- "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)\\s-+"
- "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)[ \t]*" "\\([^\n]*\\)"))
+ "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)\\s-+"
+ "\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\)[ \t]*" "\\([^\n]*\\)"))
(defsubst timeclock-read-moment ()
"Read the moment under point from the timelog."
(if (looking-at timeclock-moment-regexp)
(let ((code (match-string 1))
- (year (string-to-number (match-string 2)))
- (mon (string-to-number (match-string 3)))
- (mday (string-to-number (match-string 4)))
- (hour (string-to-number (match-string 5)))
- (min (string-to-number (match-string 6)))
- (sec (string-to-number (match-string 7)))
- (project (match-string 8)))
- (list code (encode-time sec min hour mday mon year) project))))
+ (year (string-to-number (match-string 2)))
+ (mon (string-to-number (match-string 3)))
+ (mday (string-to-number (match-string 4)))
+ (hour (string-to-number (match-string 5)))
+ (min (string-to-number (match-string 6)))
+ (sec (string-to-number (match-string 7)))
+ (project (match-string 8)))
+ (list code (encode-time sec min hour mday mon year) project))))
(defun timeclock-last-period (&optional moment)
"Return the value of the last event period.
@@ -695,8 +695,8 @@ This is only provided for coherency when used by
`timeclock-discrepancy'."
(if (equal (car timeclock-last-event) "i")
(- (timeclock-time-to-seconds (or moment (current-time)))
- (timeclock-time-to-seconds
- (cadr timeclock-last-event)))
+ (timeclock-time-to-seconds
+ (cadr timeclock-last-event)))
timeclock-last-period))
(defsubst timeclock-entry-length (entry)
@@ -741,9 +741,9 @@ This is only provided for coherency when used by
(let (projects)
(while entry-list
(let ((project (timeclock-entry-project (car entry-list))))
- (if projects
- (add-to-list 'projects project)
- (setq projects (list project))))
+ (if projects
+ (add-to-list 'projects project)
+ (setq projects (list project))))
(setq entry-list (cdr entry-list)))
projects))
@@ -805,11 +805,11 @@ This is only provided for coherency when used by
(let (projects)
(while day-list
(let ((projs (timeclock-day-projects (car day-list))))
- (while projs
- (if projects
- (add-to-list 'projects (car projs))
- (setq projects (list (car projs))))
- (setq projs (cdr projs))))
+ (while projs
+ (if projects
+ (add-to-list 'projects (car projs))
+ (setq projects (list (car projs))))
+ (setq projs (cdr projs))))
(setq day-list (cdr day-list)))
projects))
@@ -822,10 +822,10 @@ This is only provided for coherency when used by
(defun timeclock-day-list (&optional log-data)
(let ((alist (timeclock-day-alist log-data))
- day-list)
+ day-list)
(while alist
(setq day-list (cons (cdar alist) day-list)
- alist (cdr alist)))
+ alist (cdr alist)))
day-list))
(defsubst timeclock-project-alist (&optional log-data)
@@ -963,73 +963,73 @@ lists:
See the documentation for the given function if more info is needed."
(let* ((log-data (list 0.0 nil nil))
- (now (current-time))
- (todays-date (timeclock-time-to-date now))
- last-date-limited last-date-seconds last-date
- (line 0) last beg day entry event)
+ (now (current-time))
+ (todays-date (timeclock-time-to-date now))
+ last-date-limited last-date-seconds last-date
+ (line 0) last beg day entry event)
(with-temp-buffer
(insert-file-contents (or filename timeclock-file))
(when recent-only
- (goto-char (point-max))
- (unless (re-search-backward "^b\\s-+" nil t)
- (goto-char (point-min))))
+ (goto-char (point-max))
+ (unless (re-search-backward "^b\\s-+" nil t)
+ (goto-char (point-min))))
(while (or (setq event (timeclock-read-moment))
- (and beg (not last)
- (setq last t event (list "o" now))))
- (setq line (1+ line))
- (cond ((equal (car event) "b")
- (setcar log-data (string-to-number (nth 2 event))))
- ((equal (car event) "h")
- (setq last-date-limited (timeclock-time-to-date (cadr event))
- last-date-seconds (* (string-to-number (nth 2 event))
- 3600.0)))
- ((equal (car event) "i")
- (if beg
- (error "Error in format of timelog file, line %d" line)
- (setq beg t))
- (setq entry (list (cadr event) nil
- (and (> (length (nth 2 event)) 0)
- (nth 2 event))))
- (let ((date (timeclock-time-to-date (cadr event))))
- (if (and last-date
- (not (equal date last-date)))
- (progn
- (setcar (cdr log-data)
- (cons (cons last-date day)
- (cadr log-data)))
- (setq day (list (and last-date-limited
- last-date-seconds))))
- (unless day
- (setq day (list (and last-date-limited
- last-date-seconds)))))
- (setq last-date date
- last-date-limited nil)))
- ((equal (downcase (car event)) "o")
- (if (not beg)
- (error "Error in format of timelog file, line %d" line)
- (setq beg nil))
- (setcar (cdr entry) (cadr event))
- (let ((desc (and (> (length (nth 2 event)) 0)
- (nth 2 event))))
- (if desc
- (nconc entry (list (nth 2 event))))
- (if (equal (car event) "O")
- (nconc entry (if desc
- (list t)
- (list nil t))))
- (nconc day (list entry))
- (setq desc (nth 2 entry))
- (let ((proj (assoc desc (nth 2 log-data))))
- (if (null proj)
- (setcar (cddr log-data)
- (cons (cons desc (list entry))
- (car (cddr log-data))))
- (nconc (cdr proj) (list entry)))))))
- (forward-line))
+ (and beg (not last)
+ (setq last t event (list "o" now))))
+ (setq line (1+ line))
+ (cond ((equal (car event) "b")
+ (setcar log-data (string-to-number (nth 2 event))))
+ ((equal (car event) "h")
+ (setq last-date-limited (timeclock-time-to-date (cadr event))
+ last-date-seconds (* (string-to-number (nth 2 event))
+ 3600.0)))
+ ((equal (car event) "i")
+ (if beg
+ (error "Error in format of timelog file, line %d" line)
+ (setq beg t))
+ (setq entry (list (cadr event) nil
+ (and (> (length (nth 2 event)) 0)
+ (nth 2 event))))
+ (let ((date (timeclock-time-to-date (cadr event))))
+ (if (and last-date
+ (not (equal date last-date)))
+ (progn
+ (setcar (cdr log-data)
+ (cons (cons last-date day)
+ (cadr log-data)))
+ (setq day (list (and last-date-limited
+ last-date-seconds))))
+ (unless day
+ (setq day (list (and last-date-limited
+ last-date-seconds)))))
+ (setq last-date date
+ last-date-limited nil)))
+ ((equal (downcase (car event)) "o")
+ (if (not beg)
+ (error "Error in format of timelog file, line %d" line)
+ (setq beg nil))
+ (setcar (cdr entry) (cadr event))
+ (let ((desc (and (> (length (nth 2 event)) 0)
+ (nth 2 event))))
+ (if desc
+ (nconc entry (list (nth 2 event))))
+ (if (equal (car event) "O")
+ (nconc entry (if desc
+ (list t)
+ (list nil t))))
+ (nconc day (list entry))
+ (setq desc (nth 2 entry))
+ (let ((proj (assoc desc (nth 2 log-data))))
+ (if (null proj)
+ (setcar (cddr log-data)
+ (cons (cons desc (list entry))
+ (car (cddr log-data))))
+ (nconc (cdr proj) (list entry)))))))
+ (forward-line))
(if day
- (setcar (cdr log-data)
- (cons (cons last-date day)
- (cadr log-data))))
+ (setcar (cdr log-data)
+ (cons (cons last-date day)
+ (cadr log-data))))
log-data)))
(defun timeclock-find-discrep ()
@@ -1050,82 +1050,82 @@ discrepancy, today's discrepancy, and the time worked today."
;; days (cdr days)))
;; total)
(let* ((now (current-time))
- (todays-date (timeclock-time-to-date now))
- (first t) (accum 0) (elapsed 0)
- event beg last-date avg
- last-date-limited last-date-seconds)
+ (todays-date (timeclock-time-to-date now))
+ (first t) (accum 0) (elapsed 0)
+ event beg last-date avg
+ last-date-limited last-date-seconds)
(unless timeclock-discrepancy
(when (file-readable-p timeclock-file)
- (setq timeclock-project-list nil
- timeclock-last-project nil
- timeclock-reason-list nil
- timeclock-elapsed 0)
- (with-temp-buffer
- (insert-file-contents timeclock-file)
- (goto-char (point-max))
- (unless (re-search-backward "^b\\s-+" nil t)
- (goto-char (point-min)))
- (while (setq event (timeclock-read-moment))
- (cond ((equal (car event) "b")
- (setq accum (string-to-number (nth 2 event))))
- ((equal (car event) "h")
- (setq last-date-limited
- (timeclock-time-to-date (cadr event))
- last-date-seconds
- (* (string-to-number (nth 2 event)) 3600.0)))
- ((equal (car event) "i")
- (when (and (nth 2 event)
- (> (length (nth 2 event)) 0))
- (add-to-list 'timeclock-project-list (nth 2 event))
- (setq timeclock-last-project (nth 2 event)))
- (let ((date (timeclock-time-to-date (cadr event))))
- (if (if last-date
- (not (equal date last-date))
- first)
- (setq first nil
- accum (- accum (if last-date-limited
- last-date-seconds
- timeclock-workday))))
- (setq last-date date
- last-date-limited nil)
- (if beg
- (error "Error in format of timelog file!")
- (setq beg (timeclock-time-to-seconds (cadr event))))))
- ((equal (downcase (car event)) "o")
- (if (and (nth 2 event)
- (> (length (nth 2 event)) 0))
- (add-to-list 'timeclock-reason-list (nth 2 event)))
- (if (not beg)
- (error "Error in format of timelog file!")
- (setq timeclock-last-period
- (- (timeclock-time-to-seconds (cadr event)) beg)
- accum (+ timeclock-last-period accum)
- beg nil))
- (if (equal last-date todays-date)
- (setq timeclock-elapsed
- (+ timeclock-last-period timeclock-elapsed)))))
- (setq timeclock-last-event event
- timeclock-last-event-workday
- (if (equal (timeclock-time-to-date now) last-date-limited)
- last-date-seconds
- timeclock-workday))
- (forward-line))
- (setq timeclock-discrepancy accum))))
+ (setq timeclock-project-list nil
+ timeclock-last-project nil
+ timeclock-reason-list nil
+ timeclock-elapsed 0)
+ (with-temp-buffer
+ (insert-file-contents timeclock-file)
+ (goto-char (point-max))
+ (unless (re-search-backward "^b\\s-+" nil t)
+ (goto-char (point-min)))
+ (while (setq event (timeclock-read-moment))
+ (cond ((equal (car event) "b")
+ (setq accum (string-to-number (nth 2 event))))
+ ((equal (car event) "h")
+ (setq last-date-limited
+ (timeclock-time-to-date (cadr event))
+ last-date-seconds
+ (* (string-to-number (nth 2 event)) 3600.0)))
+ ((equal (car event) "i")
+ (when (and (nth 2 event)
+ (> (length (nth 2 event)) 0))
+ (add-to-list 'timeclock-project-list (nth 2 event))
+ (setq timeclock-last-project (nth 2 event)))
+ (let ((date (timeclock-time-to-date (cadr event))))
+ (if (if last-date
+ (not (equal date last-date))
+ first)
+ (setq first nil
+ accum (- accum (if last-date-limited
+ last-date-seconds
+ timeclock-workday))))
+ (setq last-date date
+ last-date-limited nil)
+ (if beg
+ (error "Error in format of timelog file!")
+ (setq beg (timeclock-time-to-seconds (cadr event))))))
+ ((equal (downcase (car event)) "o")
+ (if (and (nth 2 event)
+ (> (length (nth 2 event)) 0))
+ (add-to-list 'timeclock-reason-list (nth 2 event)))
+ (if (not beg)
+ (error "Error in format of timelog file!")
+ (setq timeclock-last-period
+ (- (timeclock-time-to-seconds (cadr event)) beg)
+ accum (+ timeclock-last-period accum)
+ beg nil))
+ (if (equal last-date todays-date)
+ (setq timeclock-elapsed
+ (+ timeclock-last-period timeclock-elapsed)))))
+ (setq timeclock-last-event event
+ timeclock-last-event-workday
+ (if (equal (timeclock-time-to-date now) last-date-limited)
+ last-date-seconds
+ timeclock-workday))
+ (forward-line))
+ (setq timeclock-discrepancy accum))))
(unless timeclock-last-event-workday
(setq timeclock-last-event-workday timeclock-workday))
(setq accum (or timeclock-discrepancy 0)
- elapsed (or timeclock-elapsed elapsed))
+ elapsed (or timeclock-elapsed elapsed))
(if timeclock-last-event
- (if (equal (car timeclock-last-event) "i")
- (let ((last-period (timeclock-last-period now)))
- (setq accum (+ accum last-period)
- elapsed (+ elapsed last-period)))
- (if (not (equal (timeclock-time-to-date
- (cadr timeclock-last-event))
- (timeclock-time-to-date now)))
- (setq accum (- accum timeclock-last-event-workday)))))
+ (if (equal (car timeclock-last-event) "i")
+ (let ((last-period (timeclock-last-period now)))
+ (setq accum (+ accum last-period)
+ elapsed (+ elapsed last-period)))
+ (if (not (equal (timeclock-time-to-date
+ (cadr timeclock-last-event))
+ (timeclock-time-to-date now)))
+ (setq accum (- accum timeclock-last-event-workday)))))
(list accum (- elapsed timeclock-last-event-workday)
- elapsed)))
+ elapsed)))
;;; A reporting function that uses timeclock-log-data
@@ -1141,13 +1141,13 @@ If optional argument TIME is non-nil, use that instead of the current time."
(defun timeclock-geometric-mean (l)
"Compute the geometric mean of the values in the list L."
(let ((total 0)
- (count 0))
+ (count 0))
(while l
(setq total (+ total (car l))
- count (1+ count)
- l (cdr l)))
+ count (1+ count)
+ l (cdr l)))
(if (> count 0)
- (/ total count)
+ (/ total count)
0)))
(defun timeclock-generate-report (&optional html-p)
@@ -1156,71 +1156,71 @@ By default, the report is in plain text, but if the optional argument
HTML-P is non-nil, HTML markup is added."
(interactive)
(let ((log (timeclock-log-data))
- (today (timeclock-day-base)))
+ (today (timeclock-day-base)))
(if html-p (insert "<p>"))
(insert "Currently ")
(let ((project (nth 2 timeclock-last-event))
- (begin (nth 1 timeclock-last-event))
- done)
+ (begin (nth 1 timeclock-last-event))
+ done)
(if (timeclock-currently-in-p)
- (insert "IN")
- (if (or (null project) (= (length project) 0))
- (progn (insert "Done Working Today")
- (setq done t))
- (insert "OUT")))
+ (insert "IN")
+ (if (or (null project) (= (length project) 0))
+ (progn (insert "Done Working Today")
+ (setq done t))
+ (insert "OUT")))
(unless done
- (insert " since " (format-time-string "%Y/%m/%d %-I:%M %p" begin))
- (if html-p
- (insert "<br>\n<b>")
- (insert "\n*"))
- (if (timeclock-currently-in-p)
- (insert "Working on "))
- (if html-p
- (insert project "</b><br>\n")
- (insert project "*\n"))
- (let ((proj-data (cdr (assoc project (timeclock-project-alist log))))
- (two-weeks-ago (timeclock-seconds-to-time
- (- (timeclock-time-to-seconds today)
- (* 2 7 24 60 60))))
- two-week-len today-len)
- (while proj-data
- (if (not (time-less-p
- (timeclock-entry-begin (car proj-data)) today))
- (setq today-len (timeclock-entry-list-length proj-data)
- proj-data nil)
- (if (and (null two-week-len)
- (not (time-less-p
- (timeclock-entry-begin (car proj-data))
- two-weeks-ago)))
- (setq two-week-len (timeclock-entry-list-length proj-data)))
- (setq proj-data (cdr proj-data))))
- (if (null two-week-len)
- (setq two-week-len today-len))
- (if html-p (insert "<p>"))
- (if today-len
- (insert "\nTime spent on this task today: "
- (timeclock-seconds-to-string today-len)
- ". In the last two weeks: "
- (timeclock-seconds-to-string two-week-len))
- (if two-week-len
- (insert "\nTime spent on this task in the last two weeks: "
- (timeclock-seconds-to-string two-week-len))))
- (if html-p (insert "<br>"))
- (insert "\n"
- (timeclock-seconds-to-string (timeclock-workday-elapsed))
- " worked today, "
- (timeclock-seconds-to-string (timeclock-workday-remaining))
- " remaining, done at "
- (timeclock-when-to-leave-string) "\n")))
+ (insert " since " (format-time-string "%Y/%m/%d %-I:%M %p" begin))
+ (if html-p
+ (insert "<br>\n<b>")
+ (insert "\n*"))
+ (if (timeclock-currently-in-p)
+ (insert "Working on "))
+ (if html-p
+ (insert project "</b><br>\n")
+ (insert project "*\n"))
+ (let ((proj-data (cdr (assoc project (timeclock-project-alist log))))
+ (two-weeks-ago (timeclock-seconds-to-time
+ (- (timeclock-time-to-seconds today)
+ (* 2 7 24 60 60))))
+ two-week-len today-len)
+ (while proj-data
+ (if (not (time-less-p
+ (timeclock-entry-begin (car proj-data)) today))
+ (setq today-len (timeclock-entry-list-length proj-data)
+ proj-data nil)
+ (if (and (null two-week-len)
+ (not (time-less-p
+ (timeclock-entry-begin (car proj-data))
+ two-weeks-ago)))
+ (setq two-week-len (timeclock-entry-list-length proj-data)))
+ (setq proj-data (cdr proj-data))))
+ (if (null two-week-len)
+ (setq two-week-len today-len))
+ (if html-p (insert "<p>"))
+ (if today-len
+ (insert "\nTime spent on this task today: "
+ (timeclock-seconds-to-string today-len)
+ ". In the last two weeks: "
+ (timeclock-seconds-to-string two-week-len))
+ (if two-week-len
+ (insert "\nTime spent on this task in the last two weeks: "
+ (timeclock-seconds-to-string two-week-len))))
+ (if html-p (insert "<br>"))
+ (insert "\n"
+ (timeclock-seconds-to-string (timeclock-workday-elapsed))
+ " worked today, "
+ (timeclock-seconds-to-string (timeclock-workday-remaining))
+ " remaining, done at "
+ (timeclock-when-to-leave-string) "\n")))
(if html-p (insert "<p>"))
(insert "\nThere have been "
- (number-to-string
- (length (timeclock-day-alist log)))
- " days of activity, starting "
- (caar (last (timeclock-day-alist log))))
+ (number-to-string
+ (length (timeclock-day-alist log)))
+ " days of activity, starting "
+ (caar (last (timeclock-day-alist log))))
(if html-p (insert "</p>"))
(when html-p
- (insert "<p>
+ (insert "<p>
<table>
<td width=\"25\"><br></td><td>
<table border=1 cellpadding=3>
@@ -1231,111 +1231,111 @@ HTML-P is non-nil, HTML markup is added."
<th>-6 mons</th>
<th>-1 year</th>
</tr>")
- (let* ((day-list (timeclock-day-list))
- (thirty-days-ago (timeclock-seconds-to-time
- (- (timeclock-time-to-seconds today)
- (* 30 24 60 60))))
- (three-months-ago (timeclock-seconds-to-time
- (- (timeclock-time-to-seconds today)
- (* 90 24 60 60))))
- (six-months-ago (timeclock-seconds-to-time
- (- (timeclock-time-to-seconds today)
- (* 180 24 60 60))))
- (one-year-ago (timeclock-seconds-to-time
- (- (timeclock-time-to-seconds today)
- (* 365 24 60 60))))
- (time-in (vector (list t) (list t) (list t) (list t) (list t)))
- (time-out (vector (list t) (list t) (list t) (list t) (list t)))
- (breaks (vector (list t) (list t) (list t) (list t) (list t)))
- (workday (vector (list t) (list t) (list t) (list t) (list t)))
- (lengths (vector '(0 0) thirty-days-ago three-months-ago
- six-months-ago one-year-ago)))
- ;; collect statistics from complete timelog
- (while day-list
- (let ((i 0) (l 5))
- (while (< i l)
- (unless (time-less-p
- (timeclock-day-begin (car day-list))
- (aref lengths i))
- (let ((base (timeclock-time-to-seconds
- (timeclock-day-base
- (timeclock-day-begin (car day-list))))))
- (nconc (aref time-in i)
- (list (- (timeclock-time-to-seconds
- (timeclock-day-begin (car day-list)))
- base)))
- (let ((span (timeclock-day-span (car day-list)))
- (len (timeclock-day-length (car day-list)))
- (req (timeclock-day-required (car day-list))))
- ;; If the day's actual work length is less than
- ;; 70% of its span, then likely the exit time
- ;; and break amount are not worthwhile adding to
- ;; the statistic
- (when (and (> span 0)
- (> (/ (float len) (float span)) 0.70))
- (nconc (aref time-out i)
- (list (- (timeclock-time-to-seconds
- (timeclock-day-end (car day-list)))
- base)))
- (nconc (aref breaks i) (list (- span len))))
- (if req
- (setq len (+ len (- timeclock-workday req))))
- (nconc (aref workday i) (list len)))))
- (setq i (1+ i))))
- (setq day-list (cdr day-list)))
- ;; average statistics
- (let ((i 0) (l 5))
- (while (< i l)
- (aset time-in i (timeclock-geometric-mean
- (cdr (aref time-in i))))
- (aset time-out i (timeclock-geometric-mean
- (cdr (aref time-out i))))
- (aset breaks i (timeclock-geometric-mean
- (cdr (aref breaks i))))
- (aset workday i (timeclock-geometric-mean
- (cdr (aref workday i))))
- (setq i (1+ i))))
- ;; Output the HTML table
- (insert "<tr>\n")
- (insert "<td align=\"center\">Time in</td>\n")
- (let ((i 0) (l 5))
- (while (< i l)
- (insert "<td align=\"right\">"
- (timeclock-seconds-to-string (aref time-in i))
- "</td>\n")
- (setq i (1+ i))))
- (insert "</tr>\n")
-
- (insert "<tr>\n")
- (insert "<td align=\"center\">Time out</td>\n")
- (let ((i 0) (l 5))
- (while (< i l)
- (insert "<td align=\"right\">"
- (timeclock-seconds-to-string (aref time-out i))
- "</td>\n")
- (setq i (1+ i))))
- (insert "</tr>\n")
-
- (insert "<tr>\n")
- (insert "<td align=\"center\">Break</td>\n")
- (let ((i 0) (l 5))
- (while (< i l)
- (insert "<td align=\"right\">"
- (timeclock-seconds-to-string (aref breaks i))
- "</td>\n")
- (setq i (1+ i))))
- (insert "</tr>\n")
-
- (insert "<tr>\n")
- (insert "<td align=\"center\">Workday</td>\n")
- (let ((i 0) (l 5))
- (while (< i l)
- (insert "<td align=\"right\">"
- (timeclock-seconds-to-string (aref workday i))
- "</td>\n")
- (setq i (1+ i))))
- (insert "</tr>\n"))
- (insert "<tfoot>
+ (let* ((day-list (timeclock-day-list))
+ (thirty-days-ago (timeclock-seconds-to-time
+ (- (timeclock-time-to-seconds today)
+ (* 30 24 60 60))))
+ (three-months-ago (timeclock-seconds-to-time
+ (- (timeclock-time-to-seconds today)
+ (* 90 24 60 60))))
+ (six-months-ago (timeclock-seconds-to-time
+ (- (timeclock-time-to-seconds today)
+ (* 180 24 60 60))))
+ (one-year-ago (timeclock-seconds-to-time
+ (- (timeclock-time-to-seconds today)
+ (* 365 24 60 60))))
+ (time-in (vector (list t) (list t) (list t) (list t) (list t)))
+ (time-out (vector (list t) (list t) (list t) (list t) (list t)))
+ (breaks (vector (list t) (list t) (list t) (list t) (list t)))
+ (workday (vector (list t) (list t) (list t) (list t) (list t)))
+ (lengths (vector '(0 0) thirty-days-ago three-months-ago
+ six-months-ago one-year-ago)))
+ ;; collect statistics from complete timelog
+ (while day-list
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (unless (time-less-p
+ (timeclock-day-begin (car day-list))
+ (aref lengths i))
+ (let ((base (timeclock-time-to-seconds
+ (timeclock-day-base
+ (timeclock-day-begin (car day-list))))))
+ (nconc (aref time-in i)
+ (list (- (timeclock-time-to-seconds
+ (timeclock-day-begin (car day-list)))
+ base)))
+ (let ((span (timeclock-day-span (car day-list)))
+ (len (timeclock-day-length (car day-list)))
+ (req (timeclock-day-required (car day-list))))
+ ;; If the day's actual work length is less than
+ ;; 70% of its span, then likely the exit time
+ ;; and break amount are not worthwhile adding to
+ ;; the statistic
+ (when (and (> span 0)
+ (> (/ (float len) (float span)) 0.70))
+ (nconc (aref time-out i)
+ (list (- (timeclock-time-to-seconds
+ (timeclock-day-end (car day-list)))
+ base)))
+ (nconc (aref breaks i) (list (- span len))))
+ (if req
+ (setq len (+ len (- timeclock-workday req))))
+ (nconc (aref workday i) (list len)))))
+ (setq i (1+ i))))
+ (setq day-list (cdr day-list)))
+ ;; average statistics
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (aset time-in i (timeclock-geometric-mean
+ (cdr (aref time-in i))))
+ (aset time-out i (timeclock-geometric-mean
+ (cdr (aref time-out i))))
+ (aset breaks i (timeclock-geometric-mean
+ (cdr (aref breaks i))))
+ (aset workday i (timeclock-geometric-mean
+ (cdr (aref workday i))))
+ (setq i (1+ i))))
+ ;; Output the HTML table
+ (insert "<tr>\n")
+ (insert "<td align=\"center\">Time in</td>\n")
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (insert "<td align=\"right\">"
+ (timeclock-seconds-to-string (aref time-in i))
+ "</td>\n")
+ (setq i (1+ i))))
+ (insert "</tr>\n")
+
+ (insert "<tr>\n")
+ (insert "<td align=\"center\">Time out</td>\n")
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (insert "<td align=\"right\">"
+ (timeclock-seconds-to-string (aref time-out i))
+ "</td>\n")
+ (setq i (1+ i))))
+ (insert "</tr>\n")
+
+ (insert "<tr>\n")
+ (insert "<td align=\"center\">Break</td>\n")
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (insert "<td align=\"right\">"
+ (timeclock-seconds-to-string (aref breaks i))
+ "</td>\n")
+ (setq i (1+ i))))
+ (insert "</tr>\n")
+
+ (insert "<tr>\n")
+ (insert "<td align=\"center\">Workday</td>\n")
+ (let ((i 0) (l 5))
+ (while (< i l)
+ (insert "<td align=\"right\">"
+ (timeclock-seconds-to-string (aref workday i))
+ "</td>\n")
+ (setq i (1+ i))))
+ (insert "</tr>\n"))
+ (insert "<tfoot>
<td colspan=\"6\" align=\"center\">
<i>These are approximate figures</i></td>
</tfoot>
diff --git a/python/demo.py b/python/demo.py
index 7b4003f3..88931b17 100755
--- a/python/demo.py
+++ b/python/demo.py
@@ -67,8 +67,8 @@ assert not 'CAD' in comms
# want all amounts to default to the European-style, set the static variable
# `european_by_default'.
-eur.add_flags(ledger.COMMODITY_STYLE_EUROPEAN)
-assert eur.has_flags(ledger.COMMODITY_STYLE_EUROPEAN)
+eur.add_flags(ledger.COMMODITY_STYLE_DECIMAL_COMMA)
+assert eur.has_flags(ledger.COMMODITY_STYLE_DECIMAL_COMMA)
assert not eur.has_flags(ledger.COMMODITY_STYLE_THOUSANDS)
comms.european_by_default = True
diff --git a/src/account.cc b/src/account.cc
index 37ff83f3..3e0ad086 100644
--- a/src/account.cc
+++ b/src/account.cc
@@ -34,7 +34,6 @@
#include "account.h"
#include "post.h"
#include "xact.h"
-#include "interactive.h"
namespace ledger {
@@ -44,14 +43,14 @@ account_t::~account_t()
foreach (accounts_map::value_type& pair, accounts) {
if (! pair.second->has_flags(ACCOUNT_TEMP) ||
- has_flags(ACCOUNT_TEMP)) {
+ has_flags(ACCOUNT_TEMP)) {
checked_delete(pair.second);
}
}
}
account_t * account_t::find_account(const string& name,
- const bool auto_create)
+ const bool auto_create)
{
accounts_map::const_iterator i = accounts.find(name);
if (i != accounts.end())
@@ -111,7 +110,7 @@ namespace {
foreach (accounts_map::value_type& pair, account->accounts)
if (account_t * a = find_account_re_(pair.second, regexp))
- return a;
+ return a;
return NULL;
}
@@ -122,6 +121,20 @@ account_t * account_t::find_account_re(const string& regexp)
return find_account_re_(this, mask_t(regexp));
}
+void account_t::add_post(post_t * post)
+{
+ posts.push_back(post);
+
+ // Adding a new post changes the possible totals that may have been
+ // computed before.
+ if (xdata_) {
+ xdata_->self_details.gathered = false;
+ xdata_->self_details.calculated = false;
+ xdata_->family_details.gathered = false;
+ xdata_->family_details.calculated = false;
+ }
+}
+
bool account_t::remove_post(post_t * post)
{
assert(! posts.empty());
@@ -135,13 +148,13 @@ string account_t::fullname() const
if (! _fullname.empty()) {
return _fullname;
} else {
- const account_t * first = this;
- string fullname = name;
+ const account_t * first = this;
+ string fullname = name;
while (first->parent) {
first = first->parent;
if (! first->name.empty())
- fullname = first->name + ":" + fullname;
+ fullname = first->name + ":" + fullname;
}
_fullname = fullname;
@@ -161,7 +174,7 @@ string account_t::partial_name(bool flat) const
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
assert(count > 0);
if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
- break;
+ break;
}
pname = acct->name + ":" + pname;
}
@@ -175,15 +188,31 @@ std::ostream& operator<<(std::ostream& out, const account_t& account)
}
namespace {
- value_t get_partial_name(call_scope_t& scope)
+ value_t get_partial_name(call_scope_t& args)
{
- in_context_t<account_t> env(scope, "&b");
- return string_value(env->partial_name(env.has(0) ?
- env.get<bool>(0) : false));
- }
-
- value_t get_account(account_t& account) { // this gets the name
- return string_value(account.fullname());
+ return string_value(args.context<account_t>()
+ .partial_name(args.has<bool>(0) &&
+ args.get<bool>(0)));
+ }
+
+ value_t get_account(call_scope_t& args) { // this gets the name
+ account_t& account(args.context<account_t>());
+ if (args.has<string>(0)) {
+ account_t * acct = account.parent;
+ for (; acct && acct->parent; acct = acct->parent) ;
+ if (args[0].is_string())
+ return scope_value(acct->find_account(args.get<string>(0), false));
+ else if (args[0].is_mask())
+ return scope_value(acct->find_account_re(args.get<mask_t>(0).str()));
+ else
+ return NULL_VALUE;
+ }
+ else if (args.type_context() == value_t::SCOPE) {
+ return scope_value(&account);
+ }
+ else {
+ return string_value(account.fullname());
+ }
}
value_t get_account_base(account_t& account) {
@@ -230,12 +259,12 @@ namespace {
{
std::size_t depth = 0;
for (const account_t * acct = account.parent;
- acct && acct->parent;
- acct = acct->parent) {
+ acct && acct->parent;
+ acct = acct->parent) {
std::size_t count = acct->children_with_flags(ACCOUNT_EXT_TO_DISPLAY);
assert(count > 0);
if (count > 1 || acct->has_xflags(ACCOUNT_EXT_TO_DISPLAY))
- depth++;
+ depth++;
}
std::ostringstream out;
@@ -251,47 +280,43 @@ namespace {
}
template <value_t (*Func)(account_t&)>
- value_t get_wrapper(call_scope_t& scope) {
- return (*Func)(find_scope<account_t>(scope));
+ value_t get_wrapper(call_scope_t& args) {
+ return (*Func)(args.context<account_t>());
}
value_t get_parent(account_t& account) {
- return value_t(static_cast<scope_t *>(account.parent));
+ return scope_value(account.parent);
}
- value_t fn_any(call_scope_t& scope)
+ value_t fn_any(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- account_t& account(find_scope<account_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ account_t& account(args.context<account_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, account.posts) {
- bind_scope_t bound_scope(scope, *p);
- if (expr.calc(bound_scope).to_boolean())
- return true;
+ bind_scope_t bound_scope(args, *p);
+ if (expr->calc(bound_scope, args.locus, args.depth).to_boolean())
+ return true;
}
return false;
}
- value_t fn_all(call_scope_t& scope)
+ value_t fn_all(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- account_t& account(find_scope<account_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ account_t& account(args.context<account_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, account.posts) {
- bind_scope_t bound_scope(scope, *p);
- if (! expr.calc(bound_scope).to_boolean())
- return false;
+ bind_scope_t bound_scope(args, *p);
+ if (! expr->calc(bound_scope, args.locus, args.depth).to_boolean())
+ return false;
}
return true;
}
}
expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return NULL;
@@ -301,7 +326,7 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind,
if (name[1] == '\0' || name == "amount")
return WRAP_FUNCTOR(get_wrapper<&get_amount>);
else if (name == "account")
- return WRAP_FUNCTOR(get_wrapper<&get_account>);
+ return WRAP_FUNCTOR(&get_account);
else if (name == "account_base")
return WRAP_FUNCTOR(get_wrapper<&get_account_base>);
else if (name == "addr")
@@ -407,7 +432,7 @@ bool account_t::children_with_xdata() const
{
foreach (const accounts_map::value_type& pair, accounts)
if (pair.second->has_xdata() ||
- pair.second->children_with_xdata())
+ pair.second->children_with_xdata())
return true;
return false;
@@ -420,7 +445,7 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
foreach (const accounts_map::value_type& pair, accounts)
if (pair.second->has_xflags(flags) ||
- pair.second->children_with_flags(flags))
+ pair.second->children_with_flags(flags))
count++;
// Although no immediately children were visited, if any progeny at all were
@@ -434,11 +459,11 @@ std::size_t account_t::children_with_flags(xdata_t::flags_t flags) const
account_t::xdata_t::details_t&
account_t::xdata_t::details_t::operator+=(const details_t& other)
{
- posts_count += other.posts_count;
- posts_virtuals_count += other.posts_virtuals_count;
- posts_cleared_count += other.posts_cleared_count;
- posts_last_7_count += other.posts_last_7_count;
- posts_last_30_count += other.posts_last_30_count;
+ posts_count += other.posts_count;
+ posts_virtuals_count += other.posts_virtuals_count;
+ posts_cleared_count += other.posts_cleared_count;
+ posts_last_7_count += other.posts_last_7_count;
+ posts_last_30_count += other.posts_last_30_count;
posts_this_month_count += other.posts_this_month_count;
if (! is_valid(earliest_post) ||
@@ -461,9 +486,9 @@ account_t::xdata_t::details_t::operator+=(const details_t& other)
filenames.insert(other.filenames.begin(), other.filenames.end());
accounts_referenced.insert(other.accounts_referenced.begin(),
- other.accounts_referenced.end());
+ other.accounts_referenced.end());
payees_referenced.insert(other.payees_referenced.begin(),
- other.payees_referenced.end());
+ other.payees_referenced.end());
return *this;
}
@@ -487,10 +512,10 @@ value_t account_t::amount(const optional<expr_t&>& expr) const
for (; i != posts.end(); i++) {
if ((*i)->xdata().has_flags(POST_EXT_VISITED)) {
- if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
- (*i)->add_to_value(xdata_->self_details.total, expr);
- (*i)->xdata().add_flags(POST_EXT_CONSIDERED);
- }
+ if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
+ (*i)->add_to_value(xdata_->self_details.total, expr);
+ (*i)->xdata().add_flags(POST_EXT_CONSIDERED);
+ }
}
xdata_->self_details.last_post = i;
}
@@ -502,10 +527,10 @@ value_t account_t::amount(const optional<expr_t&>& expr) const
for (; i != xdata_->reported_posts.end(); i++) {
if ((*i)->xdata().has_flags(POST_EXT_VISITED)) {
- if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
- (*i)->add_to_value(xdata_->self_details.total, expr);
- (*i)->xdata().add_flags(POST_EXT_CONSIDERED);
- }
+ if (! (*i)->xdata().has_flags(POST_EXT_CONSIDERED)) {
+ (*i)->add_to_value(xdata_->self_details.total, expr);
+ (*i)->xdata().add_flags(POST_EXT_CONSIDERED);
+ }
}
xdata_->self_details.last_reported_post = i;
}
@@ -525,7 +550,7 @@ value_t account_t::total(const optional<expr_t&>& expr) const
foreach (const accounts_map::value_type& pair, accounts) {
temp = pair.second->total(expr);
if (! temp.is_null())
- add_or_set_value(xdata_->family_details.total, temp);
+ add_or_set_value(xdata_->family_details.total, temp);
}
temp = amount(expr);
@@ -562,7 +587,7 @@ account_t::family_details(bool gather_all) const
}
void account_t::xdata_t::details_t::update(post_t& post,
- bool gather_all)
+ bool gather_all)
{
posts_count++;
@@ -592,16 +617,16 @@ void account_t::xdata_t::details_t::update(post_t& post,
posts_cleared_count++;
if (! is_valid(earliest_cleared_post) ||
- post.date() < earliest_cleared_post)
+ post.date() < earliest_cleared_post)
earliest_cleared_post = post.date();
if (! is_valid(latest_cleared_post) ||
- post.date() > latest_cleared_post)
+ post.date() > latest_cleared_post)
latest_cleared_post = post.date();
}
if (gather_all) {
accounts_referenced.insert(post.account->fullname());
- payees_referenced.insert(post.xact->payee);
+ payees_referenced.insert(post.payee());
}
}
diff --git a/src/account.h b/src/account.h
index 0a3a75e4..7a632b35 100644
--- a/src/account.h
+++ b/src/account.h
@@ -55,24 +55,24 @@ typedef std::map<const string, account_t *> accounts_map;
class account_t : public supports_flags<>, public scope_t
{
-#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
-#define ACCOUNT_KNOWN 0x01
-#define ACCOUNT_TEMP 0x02 // account is a temporary object
-#define ACCOUNT_GENERATED 0x04 // account never actually existed
+#define ACCOUNT_NORMAL 0x00 // no flags at all, a basic account
+#define ACCOUNT_KNOWN 0x01
+#define ACCOUNT_TEMP 0x02 // account is a temporary object
+#define ACCOUNT_GENERATED 0x04 // account never actually existed
public:
- account_t * parent;
- string name;
+ account_t * parent;
+ string name;
optional<string> note;
unsigned short depth;
- accounts_map accounts;
- posts_list posts;
+ accounts_map accounts;
+ posts_list posts;
mutable string _fullname;
account_t(account_t * _parent = NULL,
- const string& _name = "",
- const optional<string>& _note = none)
+ const string& _name = "",
+ const optional<string>& _note = none)
: supports_flags<>(), scope_t(), parent(_parent),
name(_name), note(_note),
depth(static_cast<unsigned short>(parent ? parent->depth + 1 : 0)) {
@@ -89,6 +89,10 @@ public:
}
~account_t();
+ virtual string description() {
+ return string(_("account ")) + fullname();
+ }
+
operator string() const {
return fullname();
}
@@ -107,7 +111,7 @@ public:
account_t * find_account_re(const string& regexp);
typedef transform_iterator<function<account_t *(accounts_map::value_type&)>,
- accounts_map::iterator>
+ accounts_map::iterator>
accounts_map_seconds_iterator;
accounts_map_seconds_iterator accounts_begin() {
@@ -119,9 +123,7 @@ public:
(accounts.end(), bind(&accounts_map::value_type::second, _1));
}
- void add_post(post_t * post) {
- posts.push_back(post);
- }
+ void add_post(post_t * post);
bool remove_post(post_t * post);
posts_list::iterator posts_begin() {
@@ -132,7 +134,7 @@ public:
}
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
bool valid() const;
@@ -140,50 +142,50 @@ public:
struct xdata_t : public supports_flags<>
{
-#define ACCOUNT_EXT_SORT_CALC 0x01
+#define ACCOUNT_EXT_SORT_CALC 0x01
#define ACCOUNT_EXT_HAS_NON_VIRTUALS 0x02
#define ACCOUNT_EXT_HAS_UNB_VIRTUALS 0x04
#define ACCOUNT_EXT_AUTO_VIRTUALIZE 0x08
#define ACCOUNT_EXT_VISITED 0x10
#define ACCOUNT_EXT_MATCHING 0x20
-#define ACCOUNT_EXT_TO_DISPLAY 0x40
-#define ACCOUNT_EXT_DISPLAYED 0x80
+#define ACCOUNT_EXT_TO_DISPLAY 0x40
+#define ACCOUNT_EXT_DISPLAYED 0x80
struct details_t
{
- value_t total;
- bool calculated;
- bool gathered;
-
- std::size_t posts_count;
- std::size_t posts_virtuals_count;
- std::size_t posts_cleared_count;
- std::size_t posts_last_7_count;
- std::size_t posts_last_30_count;
- std::size_t posts_this_month_count;
-
- date_t earliest_post;
- date_t earliest_cleared_post;
- date_t latest_post;
- date_t latest_cleared_post;
-
- std::set<path> filenames;
- std::set<string> accounts_referenced;
- std::set<string> payees_referenced;
+ value_t total;
+ bool calculated;
+ bool gathered;
+
+ std::size_t posts_count;
+ std::size_t posts_virtuals_count;
+ std::size_t posts_cleared_count;
+ std::size_t posts_last_7_count;
+ std::size_t posts_last_30_count;
+ std::size_t posts_this_month_count;
+
+ date_t earliest_post;
+ date_t earliest_cleared_post;
+ date_t latest_post;
+ date_t latest_cleared_post;
+
+ std::set<path> filenames;
+ std::set<string> accounts_referenced;
+ std::set<string> payees_referenced;
optional<posts_list::const_iterator> last_post;
optional<posts_list::const_iterator> last_reported_post;
details_t()
- : calculated(false),
- gathered(false),
+ : calculated(false),
+ gathered(false),
- posts_count(0),
- posts_virtuals_count(0),
- posts_cleared_count(0),
- posts_last_7_count(0),
- posts_last_30_count(0),
- posts_this_month_count(0) {}
+ posts_count(0),
+ posts_virtuals_count(0),
+ posts_cleared_count(0),
+ posts_last_7_count(0),
+ posts_last_30_count(0),
+ posts_this_month_count(0) {}
details_t& operator+=(const details_t& other);
@@ -202,9 +204,9 @@ public:
}
xdata_t(const xdata_t& other)
: supports_flags<>(other.flags()),
- self_details(other.self_details),
- family_details(other.family_details),
- sort_values(other.sort_values)
+ self_details(other.self_details),
+ family_details(other.family_details),
+ sort_values(other.sort_values)
{
TRACE_CTOR(account_t::xdata_t, "copy");
}
diff --git a/src/accum.cc b/src/accum.cc
index 62e36deb..157f459d 100644
--- a/src/accum.cc
+++ b/src/accum.cc
@@ -40,8 +40,6 @@ std::streamsize straccbuf::xsputn(const char * s, std::streamsize num)
if (index == 0) {
// The first item received is the format string
str = std::string(s, num);
- index++;
- return num;
}
else {
std::ostringstream buf;
@@ -51,26 +49,26 @@ std::streamsize straccbuf::xsputn(const char * s, std::streamsize num)
bool matched = false;
for (const char * p = str.c_str(); *p; p++) {
if (*p == '%') {
- const char * q = p + 1;
- if (*q && *q != '%' && std::isdigit(*q) &&
- std::string::size_type(*q - '0') == index) {
- p++;
- buf << std::string(s, num);
- matched = true;
- } else {
- buf << *p;
- }
+ const char * q = p + 1;
+ if (*q && *q != '%' && std::isdigit(*q) &&
+ std::string::size_type(*q - '0') == index) {
+ p++;
+ buf << std::string(s, num);
+ matched = true;
+ } else {
+ buf << *p;
+ }
} else {
- buf << *p;
+ buf << *p;
}
}
if (! matched)
buf << std::string(s, num);
str = buf.str();
- index++;
- return num;
}
+ index++;
+ return num;
}
} // namespace ledger
diff --git a/src/accum.h b/src/accum.h
index 94e79948..236a7714 100644
--- a/src/accum.h
+++ b/src/accum.h
@@ -47,7 +47,7 @@ namespace ledger {
class straccbuf : public std::streambuf
{
protected:
- std::string str; // accumulator
+ std::string str; // accumulator
std::string::size_type index;
public:
@@ -70,6 +70,8 @@ public:
}
void clear() {
+ std::ostream::clear();
+ buf.pubseekoff(0, ios_base::beg);
buf.str.clear();
buf.index = 0;
}
@@ -79,7 +81,7 @@ public:
}
};
-#define ACCUM(obj) (static_cast<straccstream&>(obj).str())
+#define ACCUM(obj) (static_cast<const straccstream&>(obj).str())
} // namespace ledger
diff --git a/src/amount.cc b/src/amount.cc
index 7eb94442..d5b7f03d 100644
--- a/src/amount.cc
+++ b/src/amount.cc
@@ -56,8 +56,8 @@ struct amount_t::bigint_t : public supports_flags<>
#define BIGINT_BULK_ALLOC 0x01
#define BIGINT_KEEP_PREC 0x02
- mpq_t val;
- precision_t prec;
+ mpq_t val;
+ precision_t prec;
uint_least32_t refc;
#define MP(bigint) ((bigint)->val)
@@ -68,7 +68,7 @@ struct amount_t::bigint_t : public supports_flags<>
}
bigint_t(const bigint_t& other)
: supports_flags<>(static_cast<uint_least8_t>
- (other.flags() & ~BIGINT_BULK_ALLOC)),
+ (other.flags() & ~BIGINT_BULK_ALLOC)),
prec(other.prec), refc(1) {
TRACE_CTOR(bigint_t, "copy");
mpq_init(val);
@@ -87,7 +87,7 @@ struct amount_t::bigint_t : public supports_flags<>
}
if (flags() & ~(BIGINT_BULK_ALLOC | BIGINT_KEEP_PREC)) {
DEBUG("ledger.validate",
- "amount_t::bigint_t: flags() & ~(BULK_ALLOC | KEEP_PREC)");
+ "amount_t::bigint_t: flags() & ~(BULK_ALLOC | KEEP_PREC)");
return false;
}
return true;
@@ -111,18 +111,18 @@ private:
bool amount_t::is_initialized = false;
namespace {
- void stream_out_mpq(std::ostream& out,
- mpq_t quant,
- amount_t::precision_t precision,
- int zeros_prec = -1,
- const optional<commodity_t&>& comm = none)
+ void stream_out_mpq(std::ostream& out,
+ mpq_t quant,
+ amount_t::precision_t precision,
+ int zeros_prec = -1,
+ const optional<commodity_t&>& comm = none)
{
char * buf = NULL;
try {
IF_DEBUG("amount.convert") {
- char * tbuf = mpq_get_str(NULL, 10, quant);
- DEBUG("amount.convert", "Rational to convert = " << tbuf);
- std::free(tbuf);
+ char * tbuf = mpq_get_str(NULL, 10, quant);
+ DEBUG("amount.convert", "Rational to convert = " << tbuf);
+ std::free(tbuf);
}
// Convert the rational number to a floating-point, extending the
@@ -131,7 +131,7 @@ namespace {
mp_prec_t num_prec = mpz_sizeinbase(mpq_numref(quant), 2);
num_prec += amount_t::extend_by_digits*64;
if (num_prec < MPFR_PREC_MIN)
- num_prec = MPFR_PREC_MIN;
+ num_prec = MPFR_PREC_MIN;
DEBUG("amount.convert", "num prec = " << num_prec);
mpfr_set_prec(tempfnum, num_prec);
@@ -140,7 +140,7 @@ namespace {
mp_prec_t den_prec = mpz_sizeinbase(mpq_denref(quant), 2);
den_prec += amount_t::extend_by_digits*64;
if (den_prec < MPFR_PREC_MIN)
- den_prec = MPFR_PREC_MIN;
+ den_prec = MPFR_PREC_MIN;
DEBUG("amount.convert", "den prec = " << den_prec);
mpfr_set_prec(tempfden, den_prec);
@@ -150,73 +150,73 @@ namespace {
mpfr_div(tempfb, tempfnum, tempfden, GMP_RNDN);
if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0)
- throw_(amount_error,
- _("Cannot output amount to a floating-point representation"));
-
+ throw_(amount_error,
+ _("Cannot output amount to a floating-point representation"));
+
DEBUG("amount.convert", "mpfr_print = " << buf
- << " (precision " << precision
- << ", zeros_prec " << zeros_prec << ")");
+ << " (precision " << precision
+ << ", zeros_prec " << zeros_prec << ")");
if (zeros_prec >= 0) {
- string::size_type index = std::strlen(buf);
- string::size_type point = 0;
- for (string::size_type i = 0; i < index; i++) {
- if (buf[i] == '.') {
- point = i;
- break;
- }
- }
- if (point > 0) {
- while (--index >= (point + 1 + zeros_prec) && buf[index] == '0')
- buf[index] = '\0';
- if (index >= (point + zeros_prec) && buf[index] == '.')
- buf[index] = '\0';
- }
+ string::size_type index = std::strlen(buf);
+ string::size_type point = 0;
+ for (string::size_type i = 0; i < index; i++) {
+ if (buf[i] == '.') {
+ point = i;
+ break;
+ }
+ }
+ if (point > 0) {
+ while (--index >= (point + 1 + zeros_prec) && buf[index] == '0')
+ buf[index] = '\0';
+ if (index >= (point + zeros_prec) && buf[index] == '.')
+ buf[index] = '\0';
+ }
}
if (comm) {
- int integer_digits = 0;
- if (comm && comm->has_flags(COMMODITY_STYLE_THOUSANDS)) {
- // Count the number of integer digits
- for (const char * p = buf; *p; p++) {
- if (*p == '.')
- break;
- else if (*p != '-')
- integer_digits++;
- }
- }
-
- for (const char * p = buf; *p; p++) {
- if (*p == '.') {
- if (commodity_t::decimal_comma_by_default ||
- (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA)))
- out << ',';
- else
- out << *p;
- assert(integer_digits <= 3);
- }
- else if (*p == '-') {
- out << *p;
- }
- else {
- out << *p;
-
- if (integer_digits > 3 && --integer_digits % 3 == 0) {
- if (commodity_t::decimal_comma_by_default ||
- (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA)))
- out << '.';
- else
- out << ',';
- }
- }
- }
+ int integer_digits = 0;
+ if (comm && comm->has_flags(COMMODITY_STYLE_THOUSANDS)) {
+ // Count the number of integer digits
+ for (const char * p = buf; *p; p++) {
+ if (*p == '.')
+ break;
+ else if (*p != '-')
+ integer_digits++;
+ }
+ }
+
+ for (const char * p = buf; *p; p++) {
+ if (*p == '.') {
+ if (commodity_t::decimal_comma_by_default ||
+ (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA)))
+ out << ',';
+ else
+ out << *p;
+ assert(integer_digits <= 3);
+ }
+ else if (*p == '-') {
+ out << *p;
+ }
+ else {
+ out << *p;
+
+ if (integer_digits > 3 && --integer_digits % 3 == 0) {
+ if (commodity_t::decimal_comma_by_default ||
+ (comm && comm->has_flags(COMMODITY_STYLE_DECIMAL_COMMA)))
+ out << '.';
+ else
+ out << ',';
+ }
+ }
+ }
} else {
- out << buf;
+ out << buf;
}
}
catch (...) {
if (buf != NULL)
- mpfr_free_str(buf);
+ mpfr_free_str(buf);
throw;
}
if (buf != NULL)
@@ -288,7 +288,7 @@ void amount_t::_copy(const amount_t& amt)
} else {
quantity = amt.quantity;
DEBUG("amounts.refs",
- quantity << " refc++, now " << (quantity->refc + 1));
+ quantity << " refc++, now " << (quantity->refc + 1));
quantity->refc++;
}
}
@@ -391,8 +391,8 @@ int amount_t::compare(const amount_t& amt) const
if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity())
throw_(amount_error,
- _("Cannot compare amounts with different commodities: %1 and %2")
- << commodity().symbol() << amt.commodity().symbol());
+ _("Cannot compare amounts with different commodities: %1 and %2")
+ << commodity().symbol() << amt.commodity().symbol());
return mpq_cmp(MP(quantity), MP(amt.quantity));
}
@@ -426,9 +426,9 @@ amount_t& amount_t::operator+=(const amount_t& amt)
if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity())
throw_(amount_error,
- _("Adding amounts with different commodities: %1 != %2")
- << (has_commodity() ? commodity().symbol() : _("NONE"))
- << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
+ _("Adding amounts with different commodities: %1 != %2")
+ << (has_commodity() ? commodity().symbol() : _("NONE"))
+ << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
_dup();
@@ -457,9 +457,9 @@ amount_t& amount_t::operator-=(const amount_t& amt)
if (has_commodity() && amt.has_commodity() &&
commodity() != amt.commodity())
throw_(amount_error,
- _("Subtracting amounts with different commodities: %1 != %2")
- << (has_commodity() ? commodity().symbol() : _("NONE"))
- << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
+ _("Subtracting amounts with different commodities: %1 != %2")
+ << (has_commodity() ? commodity().symbol() : _("NONE"))
+ << (amt.has_commodity() ? amt.commodity().symbol() : _("NONE")));
_dup();
@@ -527,7 +527,7 @@ amount_t& amount_t::operator/=(const amount_t& amt)
mpq_div(MP(quantity), MP(quantity), MP(amt.quantity));
quantity->prec =
static_cast<precision_t>(quantity->prec + amt.quantity->prec +
- extend_by_digits);
+ extend_by_digits);
if (! has_commodity())
commodity_ = amt.commodity_;
@@ -550,7 +550,7 @@ amount_t::precision_t amount_t::precision() const
{
if (! quantity)
throw_(amount_error,
- _("Cannot determine precision of an uninitialized amount"));
+ _("Cannot determine precision of an uninitialized amount"));
return quantity->prec;
}
@@ -559,7 +559,7 @@ bool amount_t::keep_precision() const
{
if (! quantity)
throw_(amount_error,
- _("Cannot determine if precision of an uninitialized amount is kept"));
+ _("Cannot determine if precision of an uninitialized amount is kept"));
return quantity->has_flags(BIGINT_KEEP_PREC);
}
@@ -568,7 +568,7 @@ void amount_t::set_keep_precision(const bool keep) const
{
if (! quantity)
throw_(amount_error,
- _("Cannot set whether to keep the precision of an uninitialized amount"));
+ _("Cannot set whether to keep the precision of an uninitialized amount"));
if (keep)
quantity->add_flags(BIGINT_KEEP_PREC);
@@ -580,7 +580,7 @@ amount_t::precision_t amount_t::display_precision() const
{
if (! quantity)
throw_(amount_error,
- _("Cannot determine display precision of an uninitialized amount"));
+ _("Cannot determine display precision of an uninitialized amount"));
commodity_t& comm(commodity());
@@ -632,7 +632,7 @@ void amount_t::in_place_truncate()
_dup();
DEBUG("amount.truncate",
- "Truncating " << *this << " to precision " << display_precision());
+ "Truncating " << *this << " to precision " << display_precision());
std::ostringstream out;
stream_out_mpq(out, MP(quantity), display_precision());
@@ -704,9 +704,9 @@ void amount_t::in_place_unreduce()
if (! quantity)
throw_(amount_error, _("Cannot unreduce an uninitialized amount"));
- amount_t temp = *this;
- commodity_t * comm = commodity_;
- bool shifted = false;
+ amount_t temp = *this;
+ commodity_t * comm = commodity_;
+ bool shifted = false;
while (comm && comm->larger()) {
amount_t next_temp = temp / comm->larger()->number();
@@ -724,55 +724,61 @@ void amount_t::in_place_unreduce()
}
optional<amount_t>
-amount_t::value(const bool primary_only,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of) const
+amount_t::value(const optional<datetime_t>& moment,
+ const optional<commodity_t&>& in_terms_of) const
{
if (quantity) {
#if defined(DEBUG_ON)
DEBUG("commodity.prices.find",
- "amount_t::value of " << commodity().symbol());
+ "amount_t::value of " << commodity().symbol());
if (moment)
DEBUG("commodity.prices.find",
- "amount_t::value: moment = " << *moment);
+ "amount_t::value: moment = " << *moment);
if (in_terms_of)
DEBUG("commodity.prices.find",
- "amount_t::value: in_terms_of = " << in_terms_of->symbol());
+ "amount_t::value: in_terms_of = " << in_terms_of->symbol());
#endif
if (has_commodity() &&
- (! primary_only || ! commodity().has_flags(COMMODITY_PRIMARY))) {
- if (in_terms_of &&
- commodity().referent() == in_terms_of->referent()) {
- return *this;
+ (in_terms_of || ! commodity().has_flags(COMMODITY_PRIMARY))) {
+ optional<price_point_t> point;
+ optional<commodity_t&> comm(in_terms_of);
+
+ 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 (! comm) {
+ comm = annotation().price->commodity();
+ }
}
- else if (has_annotation() && annotation().price &&
- annotation().has_flags(ANNOTATION_PRICE_FIXATED)) {
- amount_t price(*annotation().price);
- price.multiply(*this, true);
- price.in_place_round();
- return price;
+
+ 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
+ // setting of --price-exp.
+ if (point)
+ point = commodity().check_for_updated_price(point, moment, comm);
}
- else {
- optional<price_point_t> point =
- commodity().find_price(in_terms_of, 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 setting of --price-exp.
- point = commodity().check_for_updated_price(point, moment,
- in_terms_of);
- if (point) {
- amount_t price(point->price);
- price.multiply(*this, true);
- price.in_place_round();
- return price;
- }
+
+ if (point) {
+ amount_t price(point->price);
+ price.multiply(*this, true);
+ price.in_place_round();
+ return price;
}
}
} else {
throw_(amount_error,
- _("Cannot determine value of an uninitialized amount"));
+ _("Cannot determine value of an uninitialized amount"));
}
return none;
}
@@ -810,7 +816,7 @@ bool amount_t::is_zero() const
return true;
}
else if (mpz_cmp(mpq_numref(MP(quantity)),
- mpq_denref(MP(quantity))) > 0) {
+ mpq_denref(MP(quantity))) > 0) {
DEBUG("amount.is_zero", "Numerator is larger than the denominator");
return false;
}
@@ -822,9 +828,9 @@ bool amount_t::is_zero() const
string output = out.str();
if (! output.empty()) {
- for (const char * p = output.c_str(); *p; p++)
- if (*p != '0' && *p != '.' && *p != '-')
- return false;
+ for (const char * p = output.c_str(); *p; p++)
+ if (*p != '0' && *p != '.' && *p != '-')
+ return false;
}
return true;
}
@@ -860,7 +866,7 @@ bool amount_t::fits_in_long() const
commodity_t& amount_t::commodity() const
{
return (has_commodity() ?
- *commodity_ : *commodity_pool_t::current_pool->null_commodity);
+ *commodity_ : *commodity_pool_t::current_pool->null_commodity);
}
bool amount_t::has_commodity() const
@@ -870,13 +876,13 @@ bool amount_t::has_commodity() const
void amount_t::annotate(const annotation_t& details)
{
- commodity_t * this_base;
+ commodity_t * this_base;
annotated_commodity_t * this_ann = NULL;
if (! quantity)
throw_(amount_error, _("Cannot annotate the commodity of an uninitialized amount"));
else if (! has_commodity())
- return; // ignore attempt to annotate a "bare commodity
+ return; // ignore attempt to annotate a "bare commodity
if (commodity().has_annotation()) {
this_ann = &as_annotated_commodity(commodity());
@@ -887,7 +893,7 @@ void amount_t::annotate(const annotation_t& details)
assert(this_base);
DEBUG("amounts.commodities", "Annotating commodity for amount "
- << *this << std::endl << details);
+ << *this << std::endl << details);
if (commodity_t * ann_comm =
this_base->pool().find_or_create(*this_base, details))
@@ -904,10 +910,10 @@ bool amount_t::has_annotation() const
{
if (! quantity)
throw_(amount_error,
- _("Cannot determine if an uninitialized amount's commodity is annotated"));
+ _("Cannot determine if an uninitialized amount's commodity is annotated"));
assert(! has_commodity() || ! commodity().has_annotation() ||
- as_annotated_commodity(commodity()).details);
+ as_annotated_commodity(commodity()).details);
return has_commodity() && commodity().has_annotation();
}
@@ -915,11 +921,11 @@ annotation_t& amount_t::annotation()
{
if (! quantity)
throw_(amount_error,
- _("Cannot return commodity annotation details of an uninitialized amount"));
+ _("Cannot return commodity annotation details of an uninitialized amount"));
if (! commodity().has_annotation())
throw_(amount_error,
- _("Request for annotation details from an unannotated amount"));
+ _("Request for annotation details from an unannotated amount"));
annotated_commodity_t& ann_comm(as_annotated_commodity(commodity()));
return ann_comm.details;
@@ -929,7 +935,7 @@ amount_t amount_t::strip_annotations(const keep_details_t& what_to_keep) const
{
if (! quantity)
throw_(amount_error,
- _("Cannot strip commodity annotations from an uninitialized amount"));
+ _("Cannot strip commodity annotations from an uninitialized amount"));
if (! what_to_keep.keep_all(commodity())) {
amount_t t(*this);
@@ -946,7 +952,7 @@ namespace {
char buf[256];
char c = peek_next_nonws(in);
READ_INTO(in, buf, 255, c,
- std::isdigit(c) || c == '-' || c == '.' || c == ',');
+ std::isdigit(c) || c == '-' || c == '.' || c == ',');
string::size_type len = std::strlen(buf);
while (len > 0 && ! std::isdigit(buf[len - 1])) {
@@ -968,7 +974,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
string symbol;
string quant;
annotation_t details;
- bool negative = false;
+ bool negative = false;
commodity_t::flags_t comm_flags = COMMODITY_STYLE_DEFAULTS;
@@ -985,28 +991,30 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) {
if (std::isspace(n))
- comm_flags |= COMMODITY_STYLE_SEPARATED;
+ comm_flags |= COMMODITY_STYLE_SEPARATED;
commodity_t::parse_symbol(in, symbol);
if (! symbol.empty())
- comm_flags |= COMMODITY_STYLE_SUFFIXED;
+ comm_flags |= COMMODITY_STYLE_SUFFIXED;
- if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n'))
- details.parse(in);
+ if (! flags.has_flags(PARSE_NO_ANNOT) &&
+ ! in.eof() && ((n = static_cast<char>(in.peek())) != '\n'))
+ details.parse(in);
}
} else {
commodity_t::parse_symbol(in, symbol);
if (! in.eof() && ((n = static_cast<char>(in.peek())) != '\n')) {
if (std::isspace(static_cast<char>(in.peek())))
- comm_flags |= COMMODITY_STYLE_SEPARATED;
+ comm_flags |= COMMODITY_STYLE_SEPARATED;
parse_quantity(in, quant);
- if (! quant.empty() && ! in.eof() &&
- ((n = static_cast<char>(in.peek())) != '\n'))
- details.parse(in);
+ if (! flags.has_flags(PARSE_NO_ANNOT) &&
+ ! quant.empty() && ! in.eof() &&
+ ((n = static_cast<char>(in.peek())) != '\n'))
+ details.parse(in);
}
}
@@ -1056,7 +1064,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (details)
commodity_ =
- commodity_pool_t::current_pool->find_or_create(*commodity_, details);
+ commodity_pool_t::current_pool->find_or_create(*commodity_, details);
}
// Quickly scan through and verify the correctness of the amount's use of
@@ -1080,59 +1088,59 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
if (ch == '.') {
if (no_more_periods)
- throw_(amount_error, _("Too many periods in amount"));
+ throw_(amount_error, _("Too many periods in amount"));
if (decimal_comma_style) {
- if (decimal_offset % 3 != 0)
- throw_(amount_error, _("Incorrect use of thousand-mark period"));
- comm_flags |= COMMODITY_STYLE_THOUSANDS;
- no_more_commas = true;
+ if (decimal_offset % 3 != 0)
+ throw_(amount_error, _("Incorrect use of thousand-mark period"));
+ comm_flags |= COMMODITY_STYLE_THOUSANDS;
+ no_more_commas = true;
} else {
- if (last_comma != string::npos) {
- decimal_comma_style = true;
- if (decimal_offset % 3 != 0)
- throw_(amount_error, _("Incorrect use of thousand-mark period"));
- } else {
- no_more_periods = true;
- new_quantity->prec = decimal_offset;
- decimal_offset = 0;
- }
+ if (last_comma != string::npos) {
+ decimal_comma_style = true;
+ if (decimal_offset % 3 != 0)
+ throw_(amount_error, _("Incorrect use of thousand-mark period"));
+ } else {
+ no_more_periods = true;
+ new_quantity->prec = decimal_offset;
+ decimal_offset = 0;
+ }
}
if (last_period == string::npos)
- last_period = string_index;
+ last_period = string_index;
}
else if (ch == ',') {
if (no_more_commas)
- throw_(amount_error, _("Too many commas in amount"));
+ throw_(amount_error, _("Too many commas in amount"));
if (decimal_comma_style) {
- if (last_period != string::npos) {
- throw_(amount_error, _("Incorrect use of decimal comma"));
- } else {
- no_more_commas = true;
- new_quantity->prec = decimal_offset;
- decimal_offset = 0;
- }
+ if (last_period != string::npos) {
+ throw_(amount_error, _("Incorrect use of decimal comma"));
+ } else {
+ no_more_commas = true;
+ new_quantity->prec = decimal_offset;
+ decimal_offset = 0;
+ }
} else {
- if (decimal_offset % 3 != 0) {
- if (last_comma != string::npos ||
- last_period != string::npos) {
- throw_(amount_error, _("Incorrect use of thousand-mark comma"));
- } else {
- decimal_comma_style = true;
- no_more_commas = true;
- new_quantity->prec = decimal_offset;
- decimal_offset = 0;
- }
- } else {
- comm_flags |= COMMODITY_STYLE_THOUSANDS;
- no_more_periods = true;
- }
+ if (decimal_offset % 3 != 0) {
+ if (last_comma != string::npos ||
+ last_period != string::npos) {
+ throw_(amount_error, _("Incorrect use of thousand-mark comma"));
+ } else {
+ decimal_comma_style = true;
+ no_more_commas = true;
+ new_quantity->prec = decimal_offset;
+ decimal_offset = 0;
+ }
+ } else {
+ comm_flags |= COMMODITY_STYLE_THOUSANDS;
+ no_more_periods = true;
+ }
}
if (last_comma == string::npos)
- last_comma = string_index;
+ last_comma = string_index;
}
else {
decimal_offset++;
@@ -1160,11 +1168,11 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
string::size_type len = quant.length();
scoped_array<char> buf(new char[len + 1]);
const char * p = quant.c_str();
- char * t = buf.get();
+ char * t = buf.get();
while (*p) {
if (*p == ',' || *p == '.')
- p++;
+ p++;
*t++ = *p++;
}
*t = '\0';
@@ -1190,7 +1198,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
quantity = new_quantity.release();
if (! flags.has_flags(PARSE_NO_REDUCE))
- in_place_reduce(); // will not throw an exception
+ in_place_reduce(); // will not throw an exception
VERIFY(valid());
@@ -1198,7 +1206,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
}
void amount_t::parse_conversion(const string& larger_str,
- const string& smaller_str)
+ const string& smaller_str)
{
amount_t larger, smaller;
@@ -1210,13 +1218,13 @@ void amount_t::parse_conversion(const string& larger_str,
if (larger.commodity()) {
larger.commodity().set_smaller(smaller);
larger.commodity().add_flags(smaller.commodity().flags() |
- COMMODITY_NOMARKET);
+ COMMODITY_NOMARKET);
}
if (smaller.commodity())
smaller.commodity().set_larger(larger);
}
-void amount_t::print(std::ostream& _out) const
+void amount_t::print(std::ostream& _out, const uint_least8_t flags) const
{
VERIFY(valid());
@@ -1230,23 +1238,23 @@ void amount_t::print(std::ostream& _out) const
commodity_t& comm(commodity());
if (! comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
- comm.print(out);
+ comm.print(out, flags & AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES);
if (comm.has_flags(COMMODITY_STYLE_SEPARATED))
out << " ";
}
stream_out_mpq(out, MP(quantity), display_precision(),
- comm ? commodity().precision() : 0, comm);
+ comm ? commodity().precision() : 0, comm);
if (comm.has_flags(COMMODITY_STYLE_SUFFIXED)) {
if (comm.has_flags(COMMODITY_STYLE_SEPARATED))
out << " ";
- comm.print(out);
+ comm.print(out, flags & AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES);
}
// If there are any annotations associated with this commodity, output them
// now.
- comm.write_annotations(out);
+ comm.write_annotations(out, flags & AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS);
// Things are output to a string first, so that if anyone has specified a
// width or fill for _out, it will be applied to the entire amount string,
@@ -1322,7 +1330,7 @@ void serialize(Archive& ar, MP_RAT& mpq, const unsigned int /* version */)
template <class Archive>
void serialize(Archive& ar, long unsigned int& integer,
- const unsigned int /* version */)
+ const unsigned int /* version */)
{
ar & make_binary_object(&integer, sizeof(long unsigned int));
}
@@ -1333,23 +1341,23 @@ void serialize(Archive& ar, long unsigned int& integer,
BOOST_CLASS_EXPORT(ledger::annotated_commodity_t)
template void boost::serialization::serialize(boost::archive::binary_iarchive&,
- MP_INT&, const unsigned int);
+ MP_INT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_oarchive&,
- MP_INT&, const unsigned int);
+ MP_INT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_iarchive&,
- MP_RAT&, const unsigned int);
+ MP_RAT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_oarchive&,
- MP_RAT&, const unsigned int);
+ MP_RAT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_iarchive&,
- long unsigned int&,
- const unsigned int);
+ long unsigned int&,
+ const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_oarchive&,
- long unsigned int&,
- const unsigned int);
+ long unsigned int&,
+ const unsigned int);
template void ledger::amount_t::serialize(boost::archive::binary_iarchive&,
- const unsigned int);
+ const unsigned int);
template void ledger::amount_t::serialize(boost::archive::binary_oarchive&,
- const unsigned int);
+ const unsigned int);
#endif // HAVE_BOOST_SERIALIZATION
diff --git a/src/amount.h b/src/amount.h
index 49f33417..8a2ebf04 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -60,8 +60,8 @@
namespace ledger {
class commodity_t;
-class annotation_t;
-class keep_details_t;
+struct annotation_t;
+struct keep_details_t;
DECLARE_EXCEPTION(amount_error, std::runtime_error);
@@ -72,7 +72,7 @@ enum parse_flags_enum_t {
PARSE_NO_MIGRATE = 0x04,
PARSE_NO_REDUCE = 0x08,
PARSE_NO_ASSIGN = 0x10,
- PARSE_NO_DATES = 0x20,
+ PARSE_NO_ANNOT = 0x20,
PARSE_OP_CONTEXT = 0x40,
PARSE_SOFT_FAIL = 0x80
};
@@ -91,9 +91,9 @@ typedef basic_flags_t<parse_flags_enum_t, uint_least8_t> parse_flags_t;
*/
class amount_t
: public ordered_field_operators<amount_t,
- ordered_field_operators<amount_t, double,
- ordered_field_operators<amount_t, unsigned long,
- ordered_field_operators<amount_t, long> > > >
+ ordered_field_operators<amount_t, double,
+ ordered_field_operators<amount_t, unsigned long,
+ ordered_field_operators<amount_t, long> > > >
{
public:
/** Ready the amount subsystem for use.
@@ -125,8 +125,8 @@ protected:
struct bigint_t;
- bigint_t * quantity;
- commodity_t * commodity_;
+ bigint_t * quantity;
+ commodity_t * commodity_;
public:
/** @name Constructors
@@ -399,9 +399,8 @@ public:
$100.00.
*/
optional<amount_t>
- value(const bool primary_only = true,
- const optional<datetime_t>& moment = none,
- const optional<commodity_t&>& in_terms_of = none) const;
+ value(const optional<datetime_t>& moment = none,
+ const optional<commodity_t&>& in_terms_of = none) const;
amount_t price() const;
@@ -647,16 +646,16 @@ public:
parse(string, flags_t) also parses an amount from a string.
*/
bool parse(std::istream& in,
- const parse_flags_t& flags = PARSE_DEFAULT);
+ const parse_flags_t& flags = PARSE_DEFAULT);
bool parse(const string& str,
- const parse_flags_t& flags = PARSE_DEFAULT) {
+ const parse_flags_t& flags = PARSE_DEFAULT) {
std::istringstream stream(str);
bool result = parse(stream, flags);
return result;
}
static void parse_conversion(const string& larger_str,
- const string& smaller_str);
+ const string& smaller_str);
/*@}*/
@@ -677,7 +676,14 @@ public:
true, the full internal precision of the amount is displayed, regardless
of its commodity's display precision.
*/
- void print(std::ostream& out) const;
+#define AMOUNT_PRINT_NO_FLAGS 0x00
+#define AMOUNT_PRINT_RIGHT_JUSTIFY 0x01
+#define AMOUNT_PRINT_COLORIZE 0x02
+#define AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS 0x04
+#define AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES 0x08
+
+ void print(std::ostream& out,
+ const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const;
/*@}*/
@@ -754,7 +760,7 @@ inline std::istream& operator>>(std::istream& in, amount_t& amt) {
}
void to_xml(std::ostream& out, const amount_t& amt,
- bool commodity_details = false);
+ bool commodity_details = false);
} // namespace ledger
diff --git a/src/annotate.cc b/src/annotate.cc
index feb3b3ca..33c0aebb 100644
--- a/src/annotate.cc
+++ b/src/annotate.cc
@@ -47,59 +47,50 @@ void annotation_t::parse(std::istream& in)
char c = peek_next_nonws(in);
if (c == '{') {
if (price)
- throw_(amount_error, _("Commodity specifies more than one price"));
+ throw_(amount_error, _("Commodity specifies more than one price"));
in.get(c);
c = peek_next_nonws(in);
if (c == '=') {
- in.get(c);
- add_flags(ANNOTATION_PRICE_FIXATED);
+ in.get(c);
+ add_flags(ANNOTATION_PRICE_FIXATED);
}
READ_INTO(in, buf, 255, c, c != '}');
if (c == '}')
- in.get(c);
+ in.get(c);
else
- throw_(amount_error, _("Commodity price lacks closing brace"));
+ throw_(amount_error, _("Commodity price lacks closing brace"));
amount_t temp;
temp.parse(buf, PARSE_NO_MIGRATE);
DEBUG("commodity.annotations", "Parsed annotation price: " << temp);
-
- // Since this price will maintain its own precision, make sure
- // it is at least as large as the base commodity, since the user
- // may have only specified {$1} or something similar.
-
- if (temp.has_commodity() &&
- temp.precision() > temp.commodity().precision())
- temp = temp.rounded(); // no need to retain individual precision
-
price = temp;
}
else if (c == '[') {
if (date)
- throw_(amount_error, _("Commodity specifies more than one date"));
+ throw_(amount_error, _("Commodity specifies more than one date"));
in.get(c);
READ_INTO(in, buf, 255, c, c != ']');
if (c == ']')
- in.get(c);
+ in.get(c);
else
- throw_(amount_error, _("Commodity date lacks closing bracket"));
+ throw_(amount_error, _("Commodity date lacks closing bracket"));
date = parse_date(buf);
}
else if (c == '(') {
if (tag)
- throw_(amount_error, _("Commodity specifies more than one tag"));
+ throw_(amount_error, _("Commodity specifies more than one tag"));
in.get(c);
READ_INTO(in, buf, 255, c, c != ')');
if (c == ')')
- in.get(c);
+ in.get(c);
else
- throw_(amount_error, _("Commodity tag lacks closing parenthesis"));
+ throw_(amount_error, _("Commodity tag lacks closing parenthesis"));
tag = buf;
}
@@ -113,30 +104,34 @@ void annotation_t::parse(std::istream& in)
#if defined(DEBUG_ON)
if (SHOW_DEBUG("amounts.commodities") && *this) {
DEBUG("amounts.commodities",
- "Parsed commodity annotations: " << std::endl << *this);
+ "Parsed commodity annotations: " << std::endl << *this);
}
#endif
}
-void annotation_t::print(std::ostream& out, bool keep_base) const
+void annotation_t::print(std::ostream& out, bool keep_base,
+ bool no_computed_annotations) const
{
- if (price)
+ if (price &&
+ (! no_computed_annotations || ! has_flags(ANNOTATION_PRICE_CALCULATED)))
out << " {"
- << (has_flags(ANNOTATION_PRICE_FIXATED) ? "=" : "")
- << (keep_base ? *price : price->unreduced()).rounded()
- << '}';
+ << (has_flags(ANNOTATION_PRICE_FIXATED) ? "=" : "")
+ << (keep_base ? *price : price->unreduced())
+ << '}';
- if (date)
+ if (date &&
+ (! no_computed_annotations || ! has_flags(ANNOTATION_DATE_CALCULATED)))
out << " [" << format_date(*date, FMT_WRITTEN) << ']';
- if (tag)
+ if (tag &&
+ (! no_computed_annotations || ! has_flags(ANNOTATION_TAG_CALCULATED)))
out << " (" << *tag << ')';
}
bool keep_details_t::keep_all(const commodity_t& comm) const
{
return (! comm.has_annotation() ||
- (keep_price && keep_date && keep_tag && ! only_actuals));
+ (keep_price && keep_date && keep_tag && ! only_actuals));
}
bool keep_details_t::keep_any(const commodity_t& comm) const
@@ -164,22 +159,34 @@ commodity_t&
annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
{
DEBUG("commodity.annotated.strip",
- "Reducing commodity " << *this << std::endl
- << " keep price " << what_to_keep.keep_price << " "
- << " keep date " << what_to_keep.keep_date << " "
- << " keep tag " << what_to_keep.keep_tag);
+ "Reducing commodity " << *this << std::endl
+ << " keep price " << what_to_keep.keep_price << " "
+ << " keep date " << what_to_keep.keep_date << " "
+ << " keep tag " << what_to_keep.keep_tag);
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) ||
@@ -187,19 +194,32 @@ annotated_commodity_t::strip_annotations(const keep_details_t& what_to_keep)
{
new_comm = pool().find_or_create
(referent(), annotation_t(keep_price ? details.price : none,
- keep_date ? details.date : none,
- keep_tag ? details.tag : none));
- } else {
- new_comm = &referent();
+ keep_date ? details.date : none,
+ keep_tag ? details.tag : none));
+
+ // 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(std::ostream& out) const
+void annotated_commodity_t::write_annotations
+ (std::ostream& out, bool no_computed_annotations) const
{
- details.print(out, pool().keep_base);
+ details.print(out, pool().keep_base, no_computed_annotations);
}
} // namespace ledger
diff --git a/src/annotate.h b/src/annotate.h
index 6ef26476..b590ca45 100644
--- a/src/annotate.h
+++ b/src/annotate.h
@@ -49,7 +49,7 @@
namespace ledger {
struct annotation_t : public supports_flags<>,
- public equality_comparable<annotation_t>
+ public equality_comparable<annotation_t>
{
#define ANNOTATION_PRICE_CALCULATED 0x01
#define ANNOTATION_PRICE_FIXATED 0x02
@@ -61,8 +61,8 @@ struct annotation_t : public supports_flags<>,
optional<string> tag;
explicit annotation_t(const optional<amount_t>& _price = none,
- const optional<date_t>& _date = none,
- const optional<string>& _tag = none)
+ const optional<date_t>& _date = none,
+ const optional<string>& _tag = none)
: supports_flags<>(), price(_price), date(_date), tag(_tag) {
TRACE_CTOR(annotation_t, "const optional<amount_t>& + date_t + string");
}
@@ -81,13 +81,14 @@ struct annotation_t : public supports_flags<>,
bool operator==(const annotation_t& rhs) const {
return (price == rhs.price &&
- date == rhs.date &&
- tag == rhs.tag);
+ date == rhs.date &&
+ tag == rhs.tag);
}
void parse(std::istream& in);
- void print(std::ostream& out, bool keep_base = false) const;
+ void print(std::ostream& out, bool keep_base = false,
+ bool no_computed_annotations = false) const;
bool valid() const {
assert(*this);
@@ -141,9 +142,9 @@ struct keep_details_t
bool only_actuals;
explicit keep_details_t(bool _keep_price = false,
- bool _keep_date = false,
- bool _keep_tag = false,
- bool _only_actuals = false)
+ bool _keep_date = false,
+ bool _keep_tag = false,
+ bool _only_actuals = false)
: keep_price(_keep_price),
keep_date(_keep_date),
keep_tag(_keep_tag),
@@ -187,7 +188,7 @@ private:
};
inline std::ostream& operator<<(std::ostream& out,
- const annotation_t& details) {
+ const annotation_t& details) {
details.print(out);
return out;
}
@@ -195,8 +196,8 @@ inline std::ostream& operator<<(std::ostream& out,
class annotated_commodity_t
: public commodity_t,
public equality_comparable<annotated_commodity_t,
- equality_comparable2<annotated_commodity_t, commodity_t,
- noncopyable> >
+ equality_comparable2<annotated_commodity_t, commodity_t,
+ noncopyable> >
{
protected:
friend class commodity_pool_t;
@@ -204,7 +205,7 @@ protected:
commodity_t * ptr;
explicit annotated_commodity_t(commodity_t * _ptr,
- const annotation_t& _details)
+ const annotation_t& _details)
: commodity_t(_ptr->parent_, _ptr->base), ptr(_ptr), details(_details) {
TRACE_CTOR(annotated_commodity_t, "commodity_t *, annotation_t");
annotated = true;
@@ -230,7 +231,8 @@ public:
}
virtual commodity_t& strip_annotations(const keep_details_t& what_to_keep);
- virtual void write_annotations(std::ostream& out) const;
+ virtual void write_annotations(std::ostream& out,
+ bool no_computed_annotations = false) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
diff --git a/src/archive.cc b/src/archive.cc
index e7fc072e..28760512 100644
--- a/src/archive.cc
+++ b/src/archive.cc
@@ -59,9 +59,9 @@ BOOST_CLASS_EXPORT(ledger::auto_xact_t)
BOOST_CLASS_EXPORT(ledger::period_xact_t)
template void ledger::journal_t::serialize(boost::archive::binary_oarchive&,
- const unsigned int);
+ const unsigned int);
template void ledger::journal_t::serialize(boost::archive::binary_iarchive&,
- const unsigned int);
+ const unsigned int);
namespace ledger {
namespace {
@@ -113,7 +113,7 @@ bool archive_t::read_header()
iarchive >> *this;
DEBUG("archive.journal",
- "Version number: " << std::hex << ARCHIVE_VERSION << std::dec);
+ "Version number: " << std::hex << ARCHIVE_VERSION << std::dec);
DEBUG("archive.journal", "Number of sources: " << sources.size());
#if defined(DEBUG_ON)
@@ -152,7 +152,7 @@ bool archive_t::should_load(const std::list<path>& data_files)
if (data_files.size() != sources.size()) {
DEBUG("archive.journal", "No, number of sources doesn't match: "
- << data_files.size() << " != " << sources.size());
+ << data_files.size() << " != " << sources.size());
return false;
}
@@ -171,23 +171,23 @@ bool archive_t::should_load(const std::list<path>& data_files)
DEBUG("archive.journal", "Comparing against source file: " << *i.filename);
if (*i.filename == p) {
- if (! exists(*i.filename)) {
- DEBUG("archive.journal",
- "No, a referent source no longer exists: " << *i.filename);
- return false;
- }
-
- if (i.modtime != posix_time::from_time_t(last_write_time(p))) {
- DEBUG("archive.journal", "No, a source's modtime has changed: " << p);
- return false;
- }
-
- if (i.size != file_size(p)) {
- DEBUG("archive.journal", "No, a source's size has changed: " << p);
- return false;
- }
-
- found++;
+ if (! exists(*i.filename)) {
+ DEBUG("archive.journal",
+ "No, a referent source no longer exists: " << *i.filename);
+ return false;
+ }
+
+ if (i.modtime != posix_time::from_time_t(last_write_time(p))) {
+ DEBUG("archive.journal", "No, a source's modtime has changed: " << p);
+ return false;
+ }
+
+ if (i.size != file_size(p)) {
+ DEBUG("archive.journal", "No, a source's size has changed: " << p);
+ return false;
+ }
+
+ found++;
}
}
}
@@ -225,7 +225,7 @@ bool archive_t::should_save(journal_t& journal)
if (! exists(*i.filename)) {
DEBUG("archive.journal",
- "No, a source no longer exists: " << *i.filename);
+ "No, a source no longer exists: " << *i.filename);
return false;
}
@@ -258,11 +258,11 @@ void archive_t::save(journal_t& journal)
boost::archive::binary_oarchive oa(stream);
DEBUG("archive.journal", "Creating archive with version "
- << std::hex << ARCHIVE_VERSION << std::dec);
+ << std::hex << ARCHIVE_VERSION << std::dec);
oa << *this;
DEBUG("archive.journal",
- "Archiving journal with " << sources.size() << " sources");
+ "Archiving journal with " << sources.size() << " sources");
oa << journal;
INFO_FINISH(archive);
diff --git a/src/archive.h b/src/archive.h
index e954cd3e..1ebf3496 100644
--- a/src/archive.h
+++ b/src/archive.h
@@ -48,7 +48,7 @@ namespace ledger {
class archive_t
{
- path file;
+ path file;
std::list<journal_t::fileinfo_t> sources;
diff --git a/src/balance.cc b/src/balance.cc
index 9b39a49a..7ce9d994 100644
--- a/src/balance.cc
+++ b/src/balance.cc
@@ -35,7 +35,7 @@
#include "commodity.h"
#include "annotate.h"
#include "pool.h"
-#include "unistring.h" // for justify()
+#include "unistring.h" // for justify()
namespace ledger {
@@ -71,7 +71,7 @@ balance_t& balance_t::operator+=(const amount_t& amt)
{
if (amt.is_null())
throw_(balance_error,
- _("Cannot add an uninitialized amount to a balance"));
+ _("Cannot add an uninitialized amount to a balance"));
if (amt.is_realzero())
return *this;
@@ -96,7 +96,7 @@ balance_t& balance_t::operator-=(const amount_t& amt)
{
if (amt.is_null())
throw_(balance_error,
- _("Cannot subtract an uninitialized amount from a balance"));
+ _("Cannot subtract an uninitialized amount from a balance"));
if (amt.is_realzero())
return *this;
@@ -116,7 +116,7 @@ balance_t& balance_t::operator*=(const amount_t& amt)
{
if (amt.is_null())
throw_(balance_error,
- _("Cannot multiply a balance by an uninitialized amount"));
+ _("Cannot multiply a balance by an uninitialized amount"));
if (is_realzero()) {
;
@@ -138,12 +138,12 @@ balance_t& balance_t::operator*=(const amount_t& amt)
amounts.begin()->second *= amt;
else
throw_(balance_error,
- _("Cannot multiply a balance with annotated commodities by a commoditized amount"));
+ _("Cannot multiply a balance with annotated commodities by a commoditized amount"));
}
else {
assert(amounts.size() > 1);
throw_(balance_error,
- _("Cannot multiply a multi-commodity balance by a commoditized amount"));
+ _("Cannot multiply a multi-commodity balance by a commoditized amount"));
}
return *this;
}
@@ -152,7 +152,7 @@ balance_t& balance_t::operator/=(const amount_t& amt)
{
if (amt.is_null())
throw_(balance_error,
- _("Cannot divide a balance by an uninitialized amount"));
+ _("Cannot divide a balance by an uninitialized amount"));
if (is_realzero()) {
;
@@ -174,27 +174,25 @@ balance_t& balance_t::operator/=(const amount_t& amt)
amounts.begin()->second /= amt;
else
throw_(balance_error,
- _("Cannot divide a balance with annotated commodities by a commoditized amount"));
+ _("Cannot divide a balance with annotated commodities by a commoditized amount"));
}
else {
assert(amounts.size() > 1);
throw_(balance_error,
- _("Cannot divide a multi-commodity balance by a commoditized amount"));
+ _("Cannot divide a multi-commodity balance by a commoditized amount"));
}
return *this;
}
optional<balance_t>
-balance_t::value(const bool primary_only,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of) const
+balance_t::value(const optional<datetime_t>& moment,
+ const optional<commodity_t&>& in_terms_of) const
{
balance_t temp;
bool resolved = false;
foreach (const amounts_map::value_type& pair, amounts) {
- if (optional<amount_t> val = pair.second.value(primary_only, moment,
- in_terms_of)) {
+ if (optional<amount_t> val = pair.second.value(moment, in_terms_of)) {
temp += *val;
resolved = true;
} else {
@@ -225,11 +223,11 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
// Try stripping annotations before giving an error.
balance_t temp(strip_annotations(keep_details_t()));
if (temp.amounts.size() == 1)
- return temp.commodity_amount(commodity);
+ return temp.commodity_amount(commodity);
throw_(amount_error,
- _("Requested amount of a balance with multiple commodities: %1")
- << temp);
+ _("Requested amount of a balance with multiple commodities: %1")
+ << temp);
}
}
else if (amounts.size() > 0) {
@@ -252,11 +250,10 @@ balance_t::strip_annotations(const keep_details_t& what_to_keep) const
return temp;
}
-void balance_t::print(std::ostream& out,
- const int first_width,
- const int latter_width,
- const bool right_justify,
- const bool colorize) const
+void balance_t::print(std::ostream& out,
+ const int first_width,
+ const int latter_width,
+ const uint_least8_t flags) const
{
bool first = true;
int lwidth = latter_width;
@@ -272,7 +269,7 @@ void balance_t::print(std::ostream& out,
sorted.push_back(&pair.second);
std::stable_sort(sorted.begin(), sorted.end(),
- commodity_t::compare_by_commodity());
+ commodity_t::compare_by_commodity());
foreach (const amount_t * amount, sorted) {
int width;
@@ -285,14 +282,14 @@ void balance_t::print(std::ostream& out,
}
std::ostringstream buf;
- buf << *amount;
- justify(out, buf.str(), width, right_justify,
- colorize && amount->sign() < 0);
+ amount->print(buf, flags);
+ justify(out, buf.str(), width, flags & AMOUNT_PRINT_RIGHT_JUSTIFY,
+ flags & AMOUNT_PRINT_COLORIZE && amount->sign() < 0);
}
if (first) {
out.width(first_width);
- if (right_justify)
+ if (flags & AMOUNT_PRINT_RIGHT_JUSTIFY)
out << std::right;
else
out << std::left;
diff --git a/src/balance.h b/src/balance.h
index 5c00c55a..ac22f3e7 100644
--- a/src/balance.h
+++ b/src/balance.h
@@ -65,19 +65,19 @@ DECLARE_EXCEPTION(balance_error, std::runtime_error);
*/
class balance_t
: public equality_comparable<balance_t,
- equality_comparable<balance_t, amount_t,
- equality_comparable<balance_t, double,
- equality_comparable<balance_t, unsigned long,
- equality_comparable<balance_t, long,
- additive<balance_t,
- additive<balance_t, amount_t,
- additive<balance_t, double,
- additive<balance_t, unsigned long,
- additive<balance_t, long,
- multiplicative<balance_t, amount_t,
- multiplicative<balance_t, double,
- multiplicative<balance_t, unsigned long,
- multiplicative<balance_t, long> > > > > > > > > > > > > >
+ equality_comparable<balance_t, amount_t,
+ equality_comparable<balance_t, double,
+ equality_comparable<balance_t, unsigned long,
+ equality_comparable<balance_t, long,
+ additive<balance_t,
+ additive<balance_t, amount_t,
+ additive<balance_t, double,
+ additive<balance_t, unsigned long,
+ additive<balance_t, long,
+ multiplicative<balance_t, amount_t,
+ multiplicative<balance_t, double,
+ multiplicative<balance_t, unsigned long,
+ multiplicative<balance_t, long> > > > > > > > > > > > > >
{
public:
typedef std::map<commodity_t *, amount_t> amounts_map;
@@ -111,7 +111,7 @@ public:
TRACE_CTOR(balance_t, "const amount_t&");
if (amt.is_null())
throw_(balance_error,
- _("Cannot initialize a balance from an uninitialized amount"));
+ _("Cannot initialize a balance from an uninitialized amount"));
if (! amt.is_realzero())
amounts.insert(amounts_map::value_type(&amt.commodity(), amt));
}
@@ -153,7 +153,7 @@ public:
balance_t& operator=(const amount_t& amt) {
if (amt.is_null())
throw_(balance_error,
- _("Cannot assign an uninitialized amount to a balance"));
+ _("Cannot assign an uninitialized amount to a balance"));
amounts.clear();
if (! amt.is_realzero())
@@ -187,17 +187,17 @@ public:
bool operator==(const balance_t& bal) const {
amounts_map::const_iterator i, j;
for (i = amounts.begin(), j = bal.amounts.begin();
- i != amounts.end() && j != bal.amounts.end();
- i++, j++) {
+ i != amounts.end() && j != bal.amounts.end();
+ i++, j++) {
if (! (i->first == j->first && i->second == j->second))
- return false;
+ return false;
}
return i == amounts.end() && j == bal.amounts.end();
}
bool operator==(const amount_t& amt) const {
if (amt.is_null())
throw_(balance_error,
- _("Cannot compare a balance to an uninitialized amount"));
+ _("Cannot compare a balance to an uninitialized amount"));
if (amt.is_realzero())
return amounts.empty();
@@ -384,9 +384,8 @@ public:
}
optional<balance_t>
- value(const bool primary_only = false,
- const optional<datetime_t>& moment = none,
- const optional<commodity_t&>& in_terms_of = none) const;
+ value(const optional<datetime_t>& moment = none,
+ const optional<commodity_t&>& in_terms_of = none) const;
balance_t price() const;
@@ -418,7 +417,7 @@ public:
foreach (const amounts_map::value_type& pair, amounts)
if (pair.second.is_nonzero())
- return true;
+ return true;
return false;
}
@@ -428,7 +427,7 @@ public:
foreach (const amounts_map::value_type& pair, amounts)
if (! pair.second.is_zero())
- return false;
+ return false;
return true;
}
@@ -438,7 +437,7 @@ public:
foreach (const amounts_map::value_type& pair, amounts)
if (! pair.second.is_realzero())
- return false;
+ return false;
return true;
}
@@ -469,7 +468,7 @@ public:
return amounts.begin()->second;
else
throw_(balance_error,
- _("Cannot convert a balance with multiple commodities to an amount"));
+ _("Cannot convert a balance with multiple commodities to an amount"));
return amount_t();
}
@@ -530,11 +529,10 @@ public:
* relative amounts of those commodities. There is no option to
* change this behavior.
*/
- void print(std::ostream& out,
- const int first_width = -1,
- const int latter_width = -1,
- const bool right_justify = false,
- const bool colorize = false) const;
+ void print(std::ostream& out,
+ const int first_width = -1,
+ const int latter_width = -1,
+ const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const;
/**
* Debugging methods. There are two methods defined to help with
@@ -552,9 +550,9 @@ public:
bool first = true;
foreach (const amounts_map::value_type& pair, amounts) {
if (first)
- first = false;
+ first = false;
else
- out << ", ";
+ out << ", ";
pair.second.print(out);
}
out << ")";
@@ -563,8 +561,8 @@ public:
bool valid() const {
foreach (const amounts_map::value_type& pair, amounts)
if (! pair.second.valid()) {
- DEBUG("ledger.validate", "balance_t: ! pair.second.valid()");
- return false;
+ DEBUG("ledger.validate", "balance_t: ! pair.second.valid()");
+ return false;
}
return true;
}
diff --git a/src/chain.cc b/src/chain.cc
index 86d35f14..67f2c8d5 100644
--- a/src/chain.cc
+++ b/src/chain.cc
@@ -40,7 +40,7 @@
namespace ledger {
post_handler_ptr chain_pre_post_handlers(post_handler_ptr base_handler,
- report_t& report)
+ report_t& report)
{
post_handler_ptr handler(base_handler);
@@ -52,11 +52,11 @@ post_handler_ptr chain_pre_post_handlers(post_handler_ptr base_handler,
// This filter_posts will only pass through posts matching the `predicate'.
if (report.HANDLED(limit_)) {
DEBUG("report.predicate",
- "Report predicate expression = " << report.HANDLER(limit_).str());
+ "Report predicate expression = " << report.HANDLER(limit_).str());
handler.reset(new filter_posts
- (handler, predicate_t(report.HANDLER(limit_).str(),
- report.what_to_keep()),
- report));
+ (handler, predicate_t(report.HANDLER(limit_).str(),
+ report.what_to_keep()),
+ report));
}
// budget_posts takes a set of posts from a data file and uses them to
@@ -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);
@@ -78,42 +78,42 @@ post_handler_ptr chain_pre_post_handlers(post_handler_ptr base_handler,
// the filter get reported.
if (report.HANDLED(limit_))
handler.reset(new filter_posts
- (handler, predicate_t(report.HANDLER(limit_).str(),
- report.what_to_keep()),
- report));
+ (handler, predicate_t(report.HANDLER(limit_).str(),
+ report.what_to_keep()),
+ report));
}
else if (report.HANDLED(forecast_while_)) {
forecast_posts * forecast_handler
= new forecast_posts(handler,
- predicate_t(report.HANDLER(forecast_while_).str(),
- report.what_to_keep()),
- report,
- report.HANDLED(forecast_years_) ?
- static_cast<std::size_t>
- (report.HANDLER(forecast_years_).value.to_long()) :
- 5UL);
+ predicate_t(report.HANDLER(forecast_while_).str(),
+ report.what_to_keep()),
+ report,
+ report.HANDLED(forecast_years_) ?
+ static_cast<std::size_t>
+ (report.HANDLER(forecast_years_).value.to_long()) :
+ 5UL);
forecast_handler->add_period_xacts(report.session.journal->period_xacts);
handler.reset(forecast_handler);
// See above, under budget_posts.
if (report.HANDLED(limit_))
handler.reset(new filter_posts
- (handler, predicate_t(report.HANDLER(limit_).str(),
- report.what_to_keep()),
- report));
+ (handler, predicate_t(report.HANDLER(limit_).str(),
+ report.what_to_keep()),
+ report));
}
return handler;
}
post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
- report_t& report,
- bool for_accounts_report)
+ report_t& report,
+ bool for_accounts_report)
{
- post_handler_ptr handler(base_handler);
- predicate_t display_predicate;
- predicate_t only_predicate;
- rounding_error_posts * rounding_handler = NULL;
+ post_handler_ptr handler(base_handler);
+ predicate_t display_predicate;
+ predicate_t only_predicate;
+ display_filter_posts * display_filter = NULL;
assert(report.HANDLED(amount_));
expr_t& expr(report.HANDLER(amount_).expr);
@@ -123,34 +123,34 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
// Make sure only forecast postings which match are allowed through
if (report.HANDLED(forecast_while_)) {
handler.reset(new filter_posts
- (handler, predicate_t(report.HANDLER(forecast_while_).str(),
- report.what_to_keep()),
- report));
+ (handler, predicate_t(report.HANDLER(forecast_while_).str(),
+ report.what_to_keep()),
+ report));
}
// truncate_xacts cuts off a certain number of _xacts_ from being
// displayed. It does not affect calculation.
if (report.HANDLED(head_) || report.HANDLED(tail_))
handler.reset
- (new truncate_xacts(handler,
- report.HANDLED(head_) ?
- report.HANDLER(head_).value.to_int() : 0,
- report.HANDLED(tail_) ?
- report.HANDLER(tail_).value.to_int() : 0));
+ (new truncate_xacts(handler,
+ report.HANDLED(head_) ?
+ report.HANDLER(head_).value.to_int() : 0,
+ report.HANDLED(tail_) ?
+ report.HANDLER(tail_).value.to_int() : 0));
// changed_value_posts adds virtual posts to the list to account for changes
// in market value of commodities, which otherwise would affect the running
// total unpredictably.
- if (report.HANDLED(revalued) && ! report.HANDLED(no_rounding)) {
- rounding_handler = new rounding_error_posts(handler, report);
- handler.reset(rounding_handler);
- }
+ display_filter = new display_filter_posts(handler, report,
+ report.HANDLED(revalued) &&
+ ! report.HANDLED(no_rounding));
+ handler.reset(display_filter);
// filter_posts will only pass through posts matching the
// `display_predicate'.
if (report.HANDLED(display_)) {
display_predicate = predicate_t(report.HANDLER(display_).str(),
- report.what_to_keep());
+ report.what_to_keep());
handler.reset(new filter_posts(handler, display_predicate, report));
}
}
@@ -161,21 +161,21 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
if (report.HANDLED(revalued) &&
(! for_accounts_report || report.HANDLED(unrealized)))
handler.reset(new changed_value_posts(handler, report, for_accounts_report,
- report.HANDLED(unrealized),
- rounding_handler));
+ report.HANDLED(unrealized),
+ display_filter));
// calc_posts computes the running total. When this appears will determine,
// for example, whether filtered posts are included or excluded from the
// running total.
handler.reset(new calc_posts(handler, expr, (! for_accounts_report ||
- (report.HANDLED(revalued) &&
- report.HANDLED(unrealized)))));
+ (report.HANDLED(revalued) &&
+ report.HANDLED(unrealized)))));
// filter_posts will only pass through posts matching the
// `secondary_predicate'.
if (report.HANDLED(only_)) {
only_predicate = predicate_t(report.HANDLER(only_).str(),
- report.what_to_keep());
+ report.what_to_keep());
handler.reset(new filter_posts(handler, only_predicate, report));
}
@@ -184,23 +184,17 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
// value expression.
if (report.HANDLED(sort_)) {
if (report.HANDLED(sort_xacts_))
- handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str()));
+ handler.reset(new sort_xacts(handler, report.HANDLER(sort_).str()));
else
- handler.reset(new sort_posts(handler, report.HANDLER(sort_).str()));
- }
-#if 0
- else if (! report.HANDLED(period_) &&
- ! report.HANDLED(unsorted)) {
- handler.reset(new sort_posts(handler, "date"));
+ handler.reset(new sort_posts(handler, report.HANDLER(sort_).str()));
}
-#endif
// collapse_posts causes xacts with multiple posts to appear as xacts
// with a subtotaled post for each commodity used.
if (report.HANDLED(collapse))
handler.reset(new collapse_posts(handler, report, expr,
- display_predicate, only_predicate,
- report.HANDLED(collapse_if_zero)));
+ display_predicate, only_predicate,
+ report.HANDLED(collapse_if_zero)));
// subtotal_posts combines all the posts it receives into one subtotal
// xact, which has one post for each commodity in each account.
@@ -208,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))
@@ -217,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));
@@ -225,37 +219,37 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler,
// weekly or monthly.
if (report.HANDLED(period_)) {
handler.reset(new interval_posts(handler, expr,
- report.HANDLER(period_).str(),
- report.HANDLED(exact),
- report.HANDLED(empty)));
+ report.HANDLER(period_).str(),
+ report.HANDLED(exact),
+ report.HANDLED(empty)));
handler.reset(new sort_posts(handler, "date"));
}
if (report.HANDLED(date_))
handler.reset(new transfer_details(handler, transfer_details::SET_DATE,
- report.session.journal->master,
- report.HANDLER(date_).str(),
- report));
+ report.session.journal->master,
+ report.HANDLER(date_).str(),
+ report));
if (report.HANDLED(account_)) {
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.journal->master,
- report.HANDLER(account_).str(),
- report));
+ report.session.journal->master,
+ report.HANDLER(account_).str(),
+ report));
}
else if (report.HANDLED(pivot_)) {
string pivot = report.HANDLER(pivot_).str();
pivot = string("\"") + pivot + ":\" + tag(\"" + pivot + "\")";
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
- report.session.journal->master, pivot,
- report));
+ report.session.journal->master, pivot,
+ report));
}
if (report.HANDLED(payee_))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
- report.session.journal->master,
- report.HANDLER(payee_).str(),
- report));
+ report.session.journal->master,
+ report.HANDLER(payee_).str(),
+ report));
// related_posts will pass along all posts related to the post received. If
// the `related_all' handler is on, then all the xact's posts are passed;
@@ -264,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;
}
diff --git a/src/chain.h b/src/chain.h
index 1a50a077..7bd76712 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -94,17 +94,17 @@ class report_t;
post_handler_ptr
chain_pre_post_handlers(post_handler_ptr base_handler,
- report_t& report);
+ report_t& report);
post_handler_ptr
chain_post_handlers(post_handler_ptr base_handler,
- report_t& report,
- bool for_accounts_report = false);
+ report_t& report,
+ bool for_accounts_report = false);
inline post_handler_ptr
chain_handlers(post_handler_ptr handler,
- report_t& report,
- bool for_accounts_report = false) {
+ report_t& report,
+ bool for_accounts_report = false) {
handler = chain_post_handlers(handler, report, for_accounts_report);
handler = chain_pre_post_handlers(handler, report);
return handler;
diff --git a/src/commodity.cc b/src/commodity.cc
index e45332b2..81183b25 100644
--- a/src/commodity.cc
+++ b/src/commodity.cc
@@ -41,13 +41,13 @@ namespace ledger {
bool commodity_t::decimal_comma_by_default = false;
void commodity_t::history_t::add_price(commodity_t& source,
- const datetime_t& date,
- const amount_t& price,
- const bool reflexive)
+ const datetime_t& date,
+ const amount_t& price,
+ const bool reflexive)
{
DEBUG("commodity.prices.add", "add_price to " << source
- << (reflexive ? " (secondary)" : " (primary)")
- << " : " << date << ", " << price);
+ << (reflexive ? " (secondary)" : " (primary)")
+ << " : " << date << ", " << price);
history_map::iterator i = prices.find(date);
if (i != prices.end()) {
@@ -64,7 +64,7 @@ void commodity_t::history_t::add_price(commodity_t& source,
price.commodity().add_price(date, inverse, false);
} else {
DEBUG("commodity.prices.add",
- "marking commodity " << source.symbol() << " as primary");
+ "marking commodity " << source.symbol() << " as primary");
source.add_flags(COMMODITY_PRIMARY);
}
}
@@ -81,15 +81,15 @@ bool commodity_t::history_t::remove_price(const datetime_t& date)
void commodity_t::varied_history_t::
add_price(commodity_t& source,
- const datetime_t& date,
- const amount_t& price,
- const bool reflexive)
+ const datetime_t& date,
+ const amount_t& price,
+ const bool reflexive)
{
optional<history_t&> hist = history(price.commodity());
if (! hist) {
std::pair<history_by_commodity_map::iterator, bool> result
= histories.insert(history_by_commodity_map::value_type
- (&price.commodity(), history_t()));
+ (&price.commodity(), history_t()));
assert(result.second);
hist = (*result.first).second;
@@ -100,7 +100,7 @@ void commodity_t::varied_history_t::
}
bool commodity_t::varied_history_t::remove_price(const datetime_t& date,
- commodity_t& comm)
+ commodity_t& comm)
{
DEBUG("commodity.prices.add", "varied_remove_price: " << date << ", " << comm);
@@ -111,21 +111,21 @@ bool commodity_t::varied_history_t::remove_price(const datetime_t& date,
optional<price_point_t>
commodity_t::history_t::find_price(const optional<datetime_t>& moment,
- const optional<datetime_t>& oldest
+ const optional<datetime_t>& oldest
#if defined(DEBUG_ON)
- , const int indent
+ , const int indent
#endif
- ) const
+ ) const
{
price_point_t point;
bool found = false;
#if defined(DEBUG_ON)
-#define DEBUG_INDENT(cat, indent) \
- do { \
- if (SHOW_DEBUG(cat)) \
- for (int i = 0; i < indent; i++) \
- ledger::_log_buffer << " "; \
+#define DEBUG_INDENT(cat, indent) \
+ do { \
+ if (SHOW_DEBUG(cat)) \
+ for (int i = 0; i < indent; i++) \
+ ledger::_log_buffer << " "; \
} while (false)
#else
#define DEBUG_INDENT(cat, indent)
@@ -171,15 +171,15 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
} else {
point.when = (*i).first;
if (*moment < point.when) {
- if (i != prices.begin()) {
- --i;
- point.when = (*i).first;
- point.price = (*i).second;
- found = true;
- }
+ if (i != prices.begin()) {
+ --i;
+ point.when = (*i).first;
+ point.price = (*i).second;
+ found = true;
+ }
} else {
- point.price = (*i).second;
- found = true;
+ point.price = (*i).second;
+ found = true;
}
DEBUG_INDENT("commodity.prices.find", indent);
@@ -205,23 +205,23 @@ commodity_t::history_t::find_price(const optional<datetime_t>& moment,
else {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
- "returning price: " << point.when << ", " << point.price);
+ "returning price: " << point.when << ", " << point.price);
return point;
}
}
optional<price_point_t>
commodity_t::varied_history_t::find_price(const commodity_t& source,
- const optional<commodity_t&>& commodity,
- const optional<datetime_t>& moment,
- const optional<datetime_t>& oldest
+ const optional<commodity_t&>& commodity,
+ const optional<datetime_t>& moment,
+ const optional<datetime_t>& oldest
#if defined(DEBUG_ON)
- , const int indent
+ , const int indent
#endif
- ) const
+ ) const
{
optional<price_point_t> point;
- optional<datetime_t> limit = oldest;
+ optional<datetime_t> limit = oldest;
#if defined(VERIFY_ON)
if (commodity) {
@@ -264,67 +264,63 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
if (comm == source)
continue;
- // Only value secondary commodities in terms of primary ones
- if (! commodity && ! comm.has_flags(COMMODITY_PRIMARY))
- continue;
-
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
- "searching for price via commodity '" << comm << "'");
+ "searching for price via commodity '" << comm << "'");
point = hist.second.find_price(moment, limit
#if defined(DEBUG_ON)
- , indent + 2
+ , indent + 2
#endif
- );
+ );
assert(! point || point->price.commodity() == comm);
if (point) {
optional<price_point_t> xlat;
if (commodity && comm != *commodity) {
- DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", "looking for translation price");
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find", "looking for translation price");
- xlat = comm.find_price(commodity, moment, limit, true
+ xlat = comm.find_price(commodity, moment, limit, true
#if defined(DEBUG_ON)
- , indent + 2
+ , indent + 2
#endif
- );
- if (xlat) {
- DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", "found translated price "
- << xlat->price << " from " << xlat->when);
-
- point->price = xlat->price * point->price;
- if (xlat->when < point->when) {
- point->when = xlat->when;
-
- DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find",
- "adjusting date of result back to " << point->when);
- }
- } else {
- DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find", "saw no translated price there");
- continue;
- }
+ );
+ if (xlat) {
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find", "found translated price "
+ << xlat->price << " from " << xlat->when);
+
+ point->price = xlat->price * point->price;
+ if (xlat->when < point->when) {
+ point->when = xlat->when;
+
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find",
+ "adjusting date of result back to " << point->when);
+ }
+ } else {
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find", "saw no translated price there");
+ continue;
+ }
}
assert(! commodity || point->price.commodity() == *commodity);
DEBUG_INDENT("commodity.prices.find", indent + 1);
DEBUG("commodity.prices.find",
- "saw a price there: " << point->price << " from " << point->when);
+ "saw a price there: " << point->price << " from " << point->when);
if (! limit || point->when > *limit) {
- limit = point->when;
- best = *point;
- found = true;
+ limit = point->when;
+ best = *point;
+ found = true;
- DEBUG_INDENT("commodity.prices.find", indent + 1);
- DEBUG("commodity.prices.find",
- "search limit adjusted to " << *limit);
+ DEBUG_INDENT("commodity.prices.find", indent + 1);
+ DEBUG("commodity.prices.find",
+ "search limit adjusted to " << *limit);
}
} else {
DEBUG_INDENT("commodity.prices.find", indent + 1);
@@ -335,7 +331,7 @@ commodity_t::varied_history_t::find_price(const commodity_t& source,
if (found) {
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.download",
- "found price " << best.price << " from " << best.when);
+ "found price " << best.price << " from " << best.when);
return best;
}
return none;
@@ -362,16 +358,15 @@ commodity_t::varied_history_t::history(const optional<commodity_t&>& commodity)
optional<price_point_t>
commodity_t::find_price(const optional<commodity_t&>& commodity,
- const optional<datetime_t>& moment,
- const optional<datetime_t>& oldest,
- const bool nested
+ const optional<datetime_t>& moment,
+ const optional<datetime_t>& oldest,
+ const bool nested
#if defined(DEBUG_ON)
- , const int indent
+ , const int indent
#endif
- ) const
+ ) const
{
- if (! has_flags(COMMODITY_WALKED) && base->varied_history &&
- (commodity || ! has_flags(COMMODITY_PRIMARY))) {
+ if (! has_flags(COMMODITY_WALKED) && base->varied_history) {
optional<base_t::time_and_commodity_t> pair;
#if defined(VERIFY_ON)
optional<price_point_t> checkpoint;
@@ -380,26 +375,26 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
if (! nested) {
pair = base_t::time_and_commodity_t
- (base_t::optional_time_pair_t(moment, oldest),
- commodity ? &(*commodity) : NULL);
+ (base_t::optional_time_pair_t(moment, oldest),
+ commodity ? &(*commodity) : NULL);
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find", "looking for memoized args: "
- << (moment ? format_datetime(*moment) : "NONE") << ", "
- << (oldest ? format_datetime(*oldest) : "NONE") << ", "
- << (commodity ? commodity->symbol() : "NONE"));
+ << (moment ? format_datetime(*moment) : "NONE") << ", "
+ << (oldest ? format_datetime(*oldest) : "NONE") << ", "
+ << (commodity ? commodity->symbol() : "NONE"));
base_t::memoized_price_map::iterator i = base->price_map.find(*pair);
if (i != base->price_map.end()) {
- DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find", "found! returning: "
- << ((*i).second ? (*i).second->price : amount_t(0L)));
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find", "found! returning: "
+ << ((*i).second ? (*i).second->price : amount_t(0L)));
#if defined(VERIFY_ON)
- IF_VERIFY() {
- found = true;
- checkpoint = (*i).second;
- } else
+ IF_VERIFY() {
+ found = true;
+ checkpoint = (*i).second;
+ } else
#endif // defined(VERIFY_ON)
- return (*i).second;
+ return (*i).second;
}
}
@@ -411,11 +406,11 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
DEBUG("commodity.prices.find", "manually finding price...");
point = base->varied_history->find_price(*this, commodity,
- moment, oldest
+ moment, oldest
#if defined(DEBUG_ON)
- , indent
+ , indent
#endif
- );
+ );
}
catch (...) {
const_cast<commodity_t&>(*this).drop_flags(COMMODITY_WALKED);
@@ -432,19 +427,19 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
if (! nested && pair) {
if (base->price_map.size() > base_t::max_price_map_size) {
- DEBUG_INDENT("commodity.prices.find", indent);
- DEBUG("commodity.prices.find",
- "price map has grown too large, clearing it by half");
+ DEBUG_INDENT("commodity.prices.find", indent);
+ DEBUG("commodity.prices.find",
+ "price map has grown too large, clearing it by half");
- for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
- base->price_map.erase(base->price_map.begin());
+ for (std::size_t i = 0; i < base_t::max_price_map_size >> 1; i++)
+ base->price_map.erase(base->price_map.begin());
}
DEBUG_INDENT("commodity.prices.find", indent);
DEBUG("commodity.prices.find",
- "remembered: " << (point ? point->price : amount_t(0L)));
+ "remembered: " << (point ? point->price : amount_t(0L)));
base->price_map.insert
- (base_t::memoized_price_map::value_type(*pair, point));
+ (base_t::memoized_price_map::value_type(*pair, point));
}
return point;
}
@@ -453,8 +448,8 @@ commodity_t::find_price(const optional<commodity_t&>& commodity,
optional<price_point_t>
commodity_t::check_for_updated_price(const optional<price_point_t>& point,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of)
+ const optional<datetime_t>& moment,
+ const optional<commodity_t&>& in_terms_of)
{
if (pool().get_quotes && ! has_flags(COMMODITY_NOMARKET)) {
bool exceeds_leeway = true;
@@ -462,28 +457,28 @@ commodity_t::check_for_updated_price(const optional<price_point_t>& point,
if (point) {
time_duration_t::sec_type seconds_diff;
if (moment) {
- seconds_diff = (*moment - point->when).total_seconds();
- DEBUG("commodity.download", "moment = " << *moment);
- DEBUG("commodity.download", "slip.moment = " << seconds_diff);
+ seconds_diff = (*moment - point->when).total_seconds();
+ DEBUG("commodity.download", "moment = " << *moment);
+ DEBUG("commodity.download", "slip.moment = " << seconds_diff);
} else {
- seconds_diff = (TRUE_CURRENT_TIME() - point->when).total_seconds();
- DEBUG("commodity.download", "slip.now = " << seconds_diff);
+ seconds_diff = (TRUE_CURRENT_TIME() - point->when).total_seconds();
+ DEBUG("commodity.download", "slip.now = " << seconds_diff);
}
DEBUG("commodity.download", "leeway = " << pool().quote_leeway);
if (seconds_diff < pool().quote_leeway)
- exceeds_leeway = false;
+ exceeds_leeway = false;
}
if (exceeds_leeway) {
DEBUG("commodity.download",
- "attempting to download a more current quote...");
+ "attempting to download a more current quote...");
if (optional<price_point_t> quote =
- pool().get_commodity_quote(*this, in_terms_of)) {
- if (! in_terms_of ||
- (quote->price.has_commodity() &&
- quote->price.commodity() == *in_terms_of))
- return quote;
+ pool().get_commodity_quote(*this, in_terms_of)) {
+ if (! in_terms_of ||
+ (quote->price.has_commodity() &&
+ quote->price.commodity() == *in_terms_of))
+ return quote;
}
}
}
@@ -495,16 +490,32 @@ commodity_t::operator bool() const
return this != pool().null_commodity;
}
-bool commodity_t::symbol_needs_quotes(const string& symbol)
-{
- foreach (char ch, symbol)
- if (std::isspace(ch) || std::isdigit(ch) || ch == '-' || ch == '.')
- return true;
+namespace {
+ // Invalid commodity characters:
+ // SPACE, TAB, NEWLINE, RETURN
+ // 0-9 . , ; : ? ! - + * / ^ & | =
+ // < > { } [ ] ( ) @
- return false;
-}
+ static int invalid_chars[256] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
+ /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
-namespace {
bool is_reserved_token(const char * buf)
{
switch (buf[0]) {
@@ -529,33 +540,17 @@ namespace {
}
}
-void commodity_t::parse_symbol(std::istream& in, string& symbol)
+bool commodity_t::symbol_needs_quotes(const string& symbol)
{
- // Invalid commodity characters:
- // SPACE, TAB, NEWLINE, RETURN
- // 0-9 . , ; : ? ! - + * / ^ & | =
- // < > { } [ ] ( ) @
+ foreach (char ch, symbol)
+ if (invalid_chars[static_cast<unsigned char>(ch)])
+ return true;
- static int invalid_chars[256] = {
- /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
- /* 00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- /* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 20 */ 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- /* 40 */ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,
- /* 60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
- /* 80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* a0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* b0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* c0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* d0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* e0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* f0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
+ return false;
+}
+void commodity_t::parse_symbol(std::istream& in, string& symbol)
+{
istream_pos_type pos = in.tellg();
char buf[256];
@@ -573,43 +568,43 @@ void commodity_t::parse_symbol(std::istream& in, string& symbol)
while (_p - buf < 255 && in.good() && ! in.eof() && c != '\n') {
std::size_t bytes = 0;
std::ptrdiff_t size = _p - buf;
- unsigned char d = c;
+ unsigned char d = c;
// Check for the start of a UTF-8 multi-byte encoded string
if (d >= 192 && d <= 223 && size < 254)
- bytes = 2;
+ bytes = 2;
else if (d >= 224 && d <= 239 && size < 253)
- bytes = 3;
+ bytes = 3;
else if (d >= 240 && d <= 247 && size < 252)
- bytes = 4;
+ bytes = 4;
else if (d >= 248 && d <= 251 && size < 251)
- bytes = 5;
+ bytes = 5;
else if (d >= 252 && d <= 253 && size < 250)
- bytes = 6;
+ bytes = 6;
else if (d >= 254) // UTF-8 encoding error
- break;
-
- if (bytes > 0) { // we're looking at a UTF-8 encoding
- for (std::size_t i = 0; i < bytes; i++) {
- in.get(c);
- if (in.bad() || in.eof())
- throw_(amount_error, _("Invalid UTF-8 encoding for commodity name"));
- *_p++ = c;
- }
+ break;
+
+ if (bytes > 0) { // we're looking at a UTF-8 encoding
+ for (std::size_t i = 0; i < bytes; i++) {
+ in.get(c);
+ if (in.bad() || in.eof())
+ throw_(amount_error, _("Invalid UTF-8 encoding for commodity name"));
+ *_p++ = c;
+ }
}
else if (invalid_chars[static_cast<unsigned char>(c)]) {
- break;
+ break;
}
else {
- in.get(c);
- if (in.eof())
- break;
- if (c == '\\') {
- in.get(c);
- if (in.eof())
- throw_(amount_error, _("Backslash at end of commodity name"));
- }
- *_p++ = c;
+ in.get(c);
+ if (in.eof())
+ break;
+ if (c == '\\') {
+ in.get(c);
+ if (in.eof())
+ throw_(amount_error, _("Backslash at end of commodity name"));
+ }
+ *_p++ = c;
}
c = static_cast<char>(in.peek());
@@ -647,11 +642,26 @@ void commodity_t::parse_symbol(char *& p, string& symbol)
throw_(amount_error, _("Failed to parse commodity"));
}
+void commodity_t::print(std::ostream& out, bool elide_quotes) const
+{
+ string sym = symbol();
+ if (elide_quotes && has_flags(COMMODITY_STYLE_SEPARATED) &&
+ ! sym.empty() && sym[0] == '"' &&
+ ! std::strchr(sym.c_str(), ' ')) {
+ string subsym(sym, 1, sym.length() - 2);
+ if (! all(subsym, is_digit()))
+ out << subsym;
+ else
+ out << sym;
+ } else
+ out << sym;
+}
+
bool commodity_t::valid() const
{
if (symbol().empty() && this != pool().null_commodity) {
DEBUG("ledger.validate",
- "commodity_t: symbol().empty() && this != null_commodity");
+ "commodity_t: symbol().empty() && this != null_commodity");
return false;
}
@@ -669,7 +679,7 @@ bool commodity_t::valid() const
}
bool commodity_t::compare_by_commodity::operator()(const amount_t * left,
- const amount_t * right) const
+ const amount_t * right) const
{
commodity_t& leftcomm(left->commodity());
commodity_t& rightcomm(right->commodity());
@@ -701,14 +711,14 @@ bool commodity_t::compare_by_commodity::operator()(const amount_t * left,
amount_t rightprice(*arightcomm.details.price);
if (leftprice.commodity() == rightprice.commodity()) {
- return (leftprice - rightprice).sign() < 0;
+ return (leftprice - rightprice).sign() < 0;
} else {
- // Since we have two different amounts, there's really no way
- // to establish a true sorting order; we'll just do it based
- // on the numerical values.
- leftprice.clear_commodity();
- rightprice.clear_commodity();
- return (leftprice - rightprice).sign() < 0;
+ // Since we have two different amounts, there's really no way
+ // to establish a true sorting order; we'll just do it based
+ // on the numerical values.
+ leftprice.clear_commodity();
+ rightprice.clear_commodity();
+ return (leftprice - rightprice).sign() < 0;
}
}
@@ -719,7 +729,7 @@ bool commodity_t::compare_by_commodity::operator()(const amount_t * left,
if (aleftcomm.details.date && arightcomm.details.date) {
gregorian::date_duration diff =
- *aleftcomm.details.date - *arightcomm.details.date;
+ *aleftcomm.details.date - *arightcomm.details.date;
return diff.is_negative();
}
@@ -737,7 +747,7 @@ bool commodity_t::compare_by_commodity::operator()(const amount_t * left,
}
void to_xml(std::ostream& out, const commodity_t& comm,
- bool commodity_details)
+ bool commodity_details)
{
push_xml x(out, "commodity", true);
@@ -763,21 +773,21 @@ void to_xml(std::ostream& out, const commodity_t& comm,
push_xml y(out, "varied-history");
foreach (const commodity_t::history_by_commodity_map::value_type& pair,
- comm.varied_history()->histories) {
- {
- push_xml z(out, "symbol");
- out << y.guard(pair.first->symbol());
- }
- {
- push_xml z(out, "history");
-
- foreach (const commodity_t::history_map::value_type& inner_pair,
- pair.second.prices) {
- push_xml w(out, "price-point");
- to_xml(out, inner_pair.first);
- to_xml(out, inner_pair.second);
- }
- }
+ comm.varied_history()->histories) {
+ {
+ push_xml z(out, "symbol");
+ out << y.guard(pair.first->symbol());
+ }
+ {
+ push_xml z(out, "history");
+
+ foreach (const commodity_t::history_map::value_type& inner_pair,
+ pair.second.prices) {
+ push_xml w(out, "price-point");
+ to_xml(out, inner_pair.first);
+ to_xml(out, inner_pair.second);
+ }
+ }
}
}
}
diff --git a/src/commodity.h b/src/commodity.h
index d8aad10d..fcd26da0 100644
--- a/src/commodity.h
+++ b/src/commodity.h
@@ -49,7 +49,7 @@
namespace ledger {
-class keep_details_t;
+struct keep_details_t;
class commodity_pool_t;
DECLARE_EXCEPTION(commodity_error, std::runtime_error);
@@ -59,6 +59,10 @@ struct price_point_t
datetime_t when;
amount_t price;
+ price_point_t() {}
+ price_point_t(datetime_t _when, amount_t _price)
+ : when(_when), price(_price) {}
+
bool operator==(const price_point_t& other) const {
return when == other.when && price == other.price;
}
@@ -88,19 +92,19 @@ public:
{
history_map prices;
- void add_price(commodity_t& source,
- const datetime_t& date,
- const amount_t& price,
- const bool reflexive = true);
+ void add_price(commodity_t& source,
+ const datetime_t& date,
+ const amount_t& price,
+ const bool reflexive = true);
bool remove_price(const datetime_t& date);
optional<price_point_t>
find_price(const optional<datetime_t>& moment = none,
- const optional<datetime_t>& oldest = none
+ const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
- , const int indent = 0
+ , const int indent = 0
#endif
- ) const;
+ ) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
@@ -121,21 +125,21 @@ public:
{
history_by_commodity_map histories;
- void add_price(commodity_t& source,
- const datetime_t& date,
- const amount_t& price,
- const bool reflexive = true);
+ void add_price(commodity_t& source,
+ const datetime_t& date,
+ const amount_t& price,
+ const bool reflexive = true);
bool remove_price(const datetime_t& date, commodity_t& commodity);
optional<price_point_t>
- find_price(const commodity_t& source,
- const optional<commodity_t&>& commodity = none,
- const optional<datetime_t>& moment = none,
- const optional<datetime_t>& oldest = none
+ find_price(const commodity_t& source,
+ const optional<commodity_t&>& commodity = none,
+ const optional<datetime_t>& moment = none,
+ const optional<datetime_t>& oldest = none
#if defined(DEBUG_ON)
- , const int indent = 0
+ , const int indent = 0
#endif
- ) const;
+ ) const;
optional<history_t&>
history(const optional<commodity_t&>& commodity = none);
@@ -160,31 +164,34 @@ 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
-
- string symbol;
+#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;
- optional<string> name;
- optional<string> note;
+ optional<string> name;
+ optional<string> note;
optional<varied_history_t> varied_history;
- optional<amount_t> smaller;
- optional<amount_t> larger;
+ optional<amount_t> smaller;
+ optional<amount_t> larger;
typedef std::pair<optional<datetime_t>,
- optional<datetime_t> > optional_time_pair_t;
+ optional<datetime_t> > optional_time_pair_t;
typedef std::pair<optional_time_pair_t,
- commodity_t *> time_and_commodity_t;
+ commodity_t *> time_and_commodity_t;
typedef std::map<time_and_commodity_t,
- optional<price_point_t> > memoized_price_map;
+ optional<price_point_t> > memoized_price_map;
static const std::size_t max_price_map_size = 16;
mutable memoized_price_map price_map;
@@ -194,10 +201,10 @@ protected:
public:
explicit base_t(const string& _symbol)
: supports_flags<uint_least16_t>
- (commodity_t::decimal_comma_by_default ?
- static_cast<uint_least16_t>(COMMODITY_STYLE_DECIMAL_COMMA) :
- static_cast<uint_least16_t>(COMMODITY_STYLE_DEFAULTS)),
- symbol(_symbol), precision(0), searched(false) {
+ (commodity_t::decimal_comma_by_default ?
+ static_cast<uint_least16_t>(COMMODITY_STYLE_DECIMAL_COMMA) :
+ static_cast<uint_least16_t>(COMMODITY_STYLE_DEFAULTS)),
+ symbol(_symbol), precision(0), searched(false) {
TRACE_CTOR(base_t, "const string&");
}
virtual ~base_t() {
@@ -233,10 +240,10 @@ protected:
commodity_pool_t * parent_;
optional<string> qualified_symbol;
optional<string> mapping_key_;
- bool annotated;
+ bool annotated;
- explicit commodity_t(commodity_pool_t * _parent,
- const shared_ptr<base_t>& _base)
+ explicit commodity_t(commodity_pool_t * _parent,
+ const shared_ptr<base_t>& _base)
: delegates_flags<uint_least16_t>(*_base.get()), base(_base),
parent_(_parent), annotated(false) {
TRACE_CTOR(commodity_t, "commodity_pool_t *, shared_ptr<base_t>");
@@ -273,7 +280,7 @@ public:
virtual commodity_t& strip_annotations(const keep_details_t&) {
return *this;
}
- virtual void write_annotations(std::ostream&) const {}
+ virtual void write_annotations(std::ostream&, bool) const {}
commodity_pool_t& pool() const {
return *parent_;
@@ -345,36 +352,36 @@ public:
// base->varied_history object.
void add_price(const datetime_t& date, const amount_t& price,
- const bool reflexive = true) {
+ const bool reflexive = true) {
if (! base->varied_history)
base->varied_history = varied_history_t();
base->varied_history->add_price(*this, date, price, reflexive);
DEBUG("commodity.prices.find", "Price added, clearing price_map");
- base->price_map.clear(); // a price was added, invalid the map
+ base->price_map.clear(); // a price was added, invalid the map
}
bool remove_price(const datetime_t& date, commodity_t& commodity) {
if (base->varied_history) {
base->varied_history->remove_price(date, commodity);
DEBUG("commodity.prices.find", "Price removed, clearing price_map");
- base->price_map.clear(); // a price was added, invalid the map
+ base->price_map.clear(); // a price was added, invalid the map
}
return false;
}
optional<price_point_t>
find_price(const optional<commodity_t&>& commodity = none,
- const optional<datetime_t>& moment = none,
- const optional<datetime_t>& oldest = none,
- const bool nested = false
+ const optional<datetime_t>& moment = none,
+ const optional<datetime_t>& oldest = none,
+ const bool nested = false
#if defined(DEBUG_ON)
- , const int indent = 0
+ , const int indent = 0
#endif
- ) const;
+ ) const;
optional<price_point_t>
check_for_updated_price(const optional<price_point_t>& point,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of);
+ const optional<datetime_t>& moment,
+ const optional<commodity_t&>& in_terms_of);
// Methods related to parsing, reading, writing, etc., the commodity
// itself.
@@ -387,10 +394,7 @@ public:
return temp;
}
- void print(std::ostream& out) const {
- out << symbol();
- }
-
+ void print(std::ostream& out, bool elide_quotes = false) const;
bool valid() const;
struct compare_by_commodity {
@@ -431,7 +435,7 @@ inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {
}
void to_xml(std::ostream& out, const commodity_t& comm,
- bool commodity_details = false);
+ bool commodity_details = false);
} // namespace ledger
diff --git a/src/compare.cc b/src/compare.cc
index f3c13cea..12114c7d 100644
--- a/src/compare.cc
+++ b/src/compare.cc
@@ -39,11 +39,13 @@
namespace ledger {
void push_sort_value(std::list<sort_value_t>& sort_values,
- expr_t::ptr_op_t node, scope_t& scope)
+ expr_t::ptr_op_t node, scope_t& scope)
{
if (node->kind == expr_t::op_t::O_CONS) {
- push_sort_value(sort_values, node->left(), scope);
- push_sort_value(sort_values, node->right(), scope);
+ while (node && node->kind == expr_t::op_t::O_CONS) {
+ push_sort_value(sort_values, node->left(), scope);
+ node = node->right();
+ }
} else {
bool inverted = false;
@@ -54,11 +56,11 @@ void push_sort_value(std::list<sort_value_t>& sort_values,
sort_values.push_back(sort_value_t());
sort_values.back().inverted = inverted;
- sort_values.back().value = expr_t(node).calc(scope).simplified();
+ sort_values.back().value = expr_t(node).calc(scope).simplified();
if (sort_values.back().value.is_null())
throw_(calc_error,
- _("Could not determine sorting value based an expression"));
+ _("Could not determine sorting value based an expression"));
}
}
@@ -106,7 +108,7 @@ bool compare_items<account_t>::operator()(account_t * left, account_t * right)
}
DEBUG("value.sort", "Comparing accounts " << left->fullname()
- << " <> " << right->fullname());
+ << " <> " << right->fullname());
return sort_value_is_less_than(lxdata.sort_values, rxdata.sort_values);
}
diff --git a/src/compare.h b/src/compare.h
index eeecd7cf..0ba9d424 100644
--- a/src/compare.h
+++ b/src/compare.h
@@ -50,7 +50,7 @@ class post_t;
class account_t;
void push_sort_value(std::list<sort_value_t>& sort_values,
- expr_t::ptr_op_t node, scope_t& scope);
+ expr_t::ptr_op_t node, scope_t& scope);
template <typename T>
class compare_items
@@ -84,14 +84,14 @@ bool compare_items<T>::operator()(T * left, T * right)
{
assert(left); assert(right);
return sort_value_is_less_than(find_sort_values(left),
- find_sort_values(right));
+ find_sort_values(right));
}
template <>
bool compare_items<post_t>::operator()(post_t * left, post_t * right);
template <>
bool compare_items<account_t>::operator()(account_t * left,
- account_t * right);
+ account_t * right);
} // namespace ledger
diff --git a/src/convert.cc b/src/convert.cc
index adb82dd4..5d3f23fa 100644
--- a/src/convert.cc
+++ b/src/convert.cc
@@ -34,7 +34,6 @@
#include "convert.h"
#include "csv.h"
#include "scope.h"
-#include "interactive.h"
#include "iterators.h"
#include "report.h"
#include "xact.h"
@@ -43,11 +42,10 @@
namespace ledger {
-value_t convert_command(call_scope_t& scope)
+value_t convert_command(call_scope_t& args)
{
- interactive_t args(scope, "s");
- report_t& report(find_scope<report_t>(scope));
- journal_t& journal(*report.session.journal.get());
+ report_t& report(args.context<report_t>());
+ journal_t& journal(*report.session.journal.get());
string bucket_name;
if (report.HANDLED(account_))
@@ -69,16 +67,16 @@ value_t convert_command(call_scope_t& scope)
xact_posts_iterator xact_iter(*xact);
while ((post = xact_iter()) != NULL) {
if (post->account == bucket)
- break;
+ break;
}
if (post) {
post_map_t::iterator i = post_map.find(post->amount);
if (i == post_map.end()) {
- std::list<post_t *> post_list;
- post_list.push_back(post);
- post_map.insert(post_map_t::value_type(post->amount, post_list));
+ std::list<post_t *> post_list;
+ post_list.push_back(post);
+ post_map.insert(post_map_t::value_type(post->amount, post_list));
} else {
- (*i).second.push_back(post);
+ (*i).second.push_back(post);
}
}
}
@@ -95,54 +93,56 @@ value_t convert_command(call_scope_t& scope)
while (xact_t * xact = reader.read_xact(journal, bucket)) {
if (report.HANDLED(invert)) {
foreach (post_t * post, xact->posts)
- post->amount.in_place_negate();
+ post->amount.in_place_negate();
}
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;
+ }
+ }
}
}
if (matched) {
DEBUG("convert.csv", "Ignored xact with code: " << *xact->code);
- checked_delete(xact); // ignore it
+ checked_delete(xact); // ignore it
}
else {
if (xact->posts.front()->account == NULL) {
- xacts_iterator xi;
- xi.xacts_i = current_xacts.begin();
- xi.xacts_end = current_xacts.end();
- xi.xacts_uninitialized = false;
-
- // jww (2010-03-07): Bind this logic to an option: --auto-match
- if (account_t * acct =
- lookup_probable_account(xact->payee, xi, bucket).second)
- xact->posts.front()->account = acct;
- else
- xact->posts.front()->account = unknown;
+ xacts_iterator xi;
+ xi.xacts_i = current_xacts.begin();
+ xi.xacts_end = current_xacts.end();
+ xi.xacts_uninitialized = false;
+
+ // jww (2010-03-07): Bind this logic to an option: --auto-match
+ if (account_t * acct =
+ lookup_probable_account(xact->payee, xi, bucket).second)
+ xact->posts.front()->account = acct;
+ else
+ xact->posts.front()->account = unknown;
}
if (! journal.add_xact(xact)) {
- checked_delete(xact);
- throw_(std::runtime_error,
- _("Failed to finalize derived transaction (check commodities)"));
+ checked_delete(xact);
+ throw_(std::runtime_error,
+ _("Failed to finalize derived transaction (check commodities)"));
}
else {
- xact_posts_iterator xact_iter(*xact);
- while (post_t * post = xact_iter())
- formatter(*post);
+ xact_posts_iterator xact_iter(*xact);
+ while (post_t * post = xact_iter())
+ formatter(*post);
}
}
}
diff --git a/src/csv.cc b/src/csv.cc
index 5a74232f..dd5ca935 100644
--- a/src/csv.cc
+++ b/src/csv.cc
@@ -51,29 +51,29 @@ string csv_reader::read_field(std::istream& in)
while (in.good() && ! in.eof()) {
in.get(x);
if (x == '\\') {
- in.get(x);
+ in.get(x);
}
else if (x == '"' && in.peek() == '"') {
- in.get(x);
+ in.get(x);
}
else if (x == c) {
- if (x == '|')
- in.unget();
- else if (in.peek() == ',')
- in.get(c);
- break;
+ if (x == '|')
+ in.unget();
+ else if (in.peek() == ',')
+ in.get(c);
+ break;
}
if (x != '\0')
- field += x;
+ field += x;
}
}
else {
while (in.good() && ! in.eof()) {
in.get(c);
if (c == ',')
- break;
+ break;
if (c != '\0')
- field += c;
+ field += c;
}
}
trim(field);
@@ -144,7 +144,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
xact->set_state(item_t::CLEARED);
- xact->pos = position_t();
+ xact->pos = position_t();
xact->pos->pathname = "jww (2010-03-05): unknown";
xact->pos->beg_pos = in.tellg();
xact->pos->beg_line = 0;
@@ -153,7 +153,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
post->xact = xact.get();
#if 0
- post->pos = position_t();
+ post->pos = position_t();
post->pos->pathname = pathname;
post->pos->beg_pos = line_beg_pos;
post->pos->beg_line = linenum;
@@ -163,7 +163,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
post->set_state(item_t::CLEARED);
post->account = NULL;
- int n = 0;
+ int n = 0;
amount_t amt;
string total;
@@ -173,12 +173,12 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
switch (index[n]) {
case FIELD_DATE:
if (field.empty())
- goto restart;
+ goto restart;
try {
- xact->_date = parse_date(field);
+ xact->_date = parse_date(field);
}
catch (date_error&) {
- goto restart;
+ goto restart;
}
break;
@@ -188,21 +188,21 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
case FIELD_CODE:
if (! field.empty())
- xact->code = field;
+ xact->code = field;
break;
case FIELD_PAYEE: {
bool found = false;
foreach (payee_mapping_t& value, journal.payee_mappings) {
- DEBUG("csv.mappings", "Looking for payee mapping: " << value.first);
- if (value.first.match(field)) {
- xact->payee = value.second;
- found = true;
- break;
- }
+ DEBUG("csv.mappings", "Looking for payee mapping: " << value.first);
+ if (value.first.match(field)) {
+ xact->payee = value.second;
+ found = true;
+ break;
+ }
}
if (! found)
- xact->payee = field;
+ xact->payee = field;
break;
}
@@ -210,8 +210,8 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
std::istringstream amount_str(field);
amt.parse(amount_str, PARSE_NO_REDUCE);
if (! amt.has_commodity() &&
- commodity_pool_t::current_pool->default_commodity)
- amt.set_commodity(*commodity_pool_t::current_pool->default_commodity);
+ commodity_pool_t::current_pool->default_commodity)
+ amt.set_commodity(*commodity_pool_t::current_pool->default_commodity);
post->amount = amt;
break;
}
@@ -220,9 +220,9 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
std::istringstream amount_str(field);
amt.parse(amount_str, PARSE_NO_REDUCE);
if (! amt.has_commodity() &&
- commodity_pool_t::current_pool->default_commodity)
- amt.set_commodity
- (*commodity_pool_t::current_pool->default_commodity);
+ commodity_pool_t::current_pool->default_commodity)
+ amt.set_commodity
+ (*commodity_pool_t::current_pool->default_commodity);
post->cost = amt;
break;
}
@@ -237,7 +237,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
case FIELD_UNKNOWN:
if (! names[n].empty() && ! field.empty())
- xact->set_tag(names[n], field);
+ xact->set_tag(names[n], string_value(field));
break;
}
n++;
@@ -245,7 +245,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
#if 0
xact->set_tag(_("Imported"),
- string(format_date(CURRENT_DATE(), FMT_WRITTEN)));
+ string(format_date(CURRENT_DATE(), FMT_WRITTEN)));
xact->set_tag(_("Original"), string(line));
xact->set_tag(_("SHA1"), string(sha1sum(line)));
#endif
@@ -268,7 +268,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
post->xact = xact.get();
#if 0
- post->pos = position_t();
+ post->pos = position_t();
post->pos->pathname = pathname;
post->pos->beg_pos = line_beg_pos;
post->pos->beg_line = linenum;
@@ -285,7 +285,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket)
std::istringstream assigned_amount_str(total);
amt.parse(assigned_amount_str, PARSE_NO_REDUCE);
if (! amt.has_commodity() &&
- commodity_pool_t::current_pool->default_commodity)
+ commodity_pool_t::current_pool->default_commodity)
amt.set_commodity(*commodity_pool_t::current_pool->default_commodity);
post->assigned_amount = amt;
}
diff --git a/src/draft.cc b/src/draft.cc
index 69dc7025..ba78fc42 100644
--- a/src/draft.cc
+++ b/src/draft.cc
@@ -57,45 +57,45 @@ void draft_t::xact_template_t::dump(std::ostream& out) const
if (payee_mask.empty())
out << _("Payee mask: INVALID (template expression will cause an error)")
- << std::endl;
+ << std::endl;
else
out << _("Payee mask: ") << payee_mask << std::endl;
if (posts.empty()) {
out << std::endl
- << _("<Posting copied from last related transaction>")
- << std::endl;
+ << _("<Posting copied from last related transaction>")
+ << std::endl;
} else {
bool has_only_from = true;
bool has_only_to = true;
foreach (const post_template_t& post, posts) {
if (post.from)
- has_only_to = false;
+ has_only_to = false;
else
- has_only_from = false;
+ has_only_from = false;
}
foreach (const post_template_t& post, posts) {
straccstream accum;
out << std::endl
- << ACCUM(accum << _("[Posting \"%1\"]")
- << (post.from ? _("from") : _("to")))
- << std::endl;
+ << ACCUM(accum << _("[Posting \"%1\"]")
+ << (post.from ? _("from") : _("to")))
+ << std::endl;
if (post.account_mask)
- out << _(" Account mask: ") << *post.account_mask << std::endl;
+ out << _(" Account mask: ") << *post.account_mask << std::endl;
else if (post.from)
- out << _(" Account mask: <use last of last related accounts>") << std::endl;
+ out << _(" Account mask: <use last of last related accounts>") << std::endl;
else
- out << _(" Account mask: <use first of last related accounts>") << std::endl;
+ out << _(" Account mask: <use first of last related accounts>") << std::endl;
if (post.amount)
- out << _(" Amount: ") << *post.amount << std::endl;
+ out << _(" Amount: ") << *post.amount << std::endl;
if (post.cost)
- out << _(" Cost: ") << *post.cost_operator
- << " " << *post.cost << std::endl;
+ out << _(" Cost: ") << *post.cost_operator
+ << " " << *post.cost << std::endl;
}
}
}
@@ -104,7 +104,7 @@ void draft_t::parse_args(const value_t& args)
{
regex date_mask(_("([0-9]+(?:[-/.][0-9]+)?(?:[-/.][0-9]+))?"));
smatch what;
- bool check_for_date = true;
+ bool check_for_date = true;
tmpl = xact_template_t();
@@ -116,16 +116,16 @@ void draft_t::parse_args(const value_t& args)
for (; begin != end; begin++) {
if (check_for_date &&
- regex_match((*begin).to_string(), what, date_mask)) {
+ regex_match((*begin).to_string(), what, date_mask)) {
tmpl->date = parse_date(what[0]);
check_for_date = false;
}
else if (check_for_date &&
- bool(weekday = string_to_day_of_week(what[0]))) {
+ bool(weekday = string_to_day_of_week(what[0]))) {
short dow = static_cast<short>(*weekday);
date_t date = CURRENT_DATE() - date_duration(1);
while (date.day_of_week() != dow)
- date -= date_duration(1);
+ date -= date_duration(1);
tmpl->date = date;
check_for_date = false;
}
@@ -133,81 +133,80 @@ void draft_t::parse_args(const value_t& args)
string arg = (*begin).to_string();
if (arg == "at") {
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- tmpl->payee_mask = (*++begin).to_string();
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ tmpl->payee_mask = (*++begin).to_string();
}
else if (arg == "to" || arg == "from") {
- if (! post || post->account_mask) {
- tmpl->posts.push_back(xact_template_t::post_template_t());
- post = &tmpl->posts.back();
- }
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- post->account_mask = mask_t((*++begin).to_string());
- post->from = arg == "from";
+ if (! post || post->account_mask) {
+ tmpl->posts.push_back(xact_template_t::post_template_t());
+ post = &tmpl->posts.back();
+ }
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ post->account_mask = mask_t((*++begin).to_string());
+ post->from = arg == "from";
}
else if (arg == "on") {
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- tmpl->date = parse_date((*++begin).to_string());
- check_for_date = false;
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ tmpl->date = parse_date((*++begin).to_string());
+ check_for_date = false;
}
else if (arg == "code") {
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- tmpl->code = (*++begin).to_string();
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ tmpl->code = (*++begin).to_string();
}
else if (arg == "note") {
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- tmpl->note = (*++begin).to_string();
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ tmpl->note = (*++begin).to_string();
}
else if (arg == "rest") {
- ; // just ignore this argument
+ ; // just ignore this argument
}
else if (arg == "@" || arg == "@@") {
- amount_t cost;
- post->cost_operator = arg;
- if (begin == end)
- throw std::runtime_error(_("Invalid xact command arguments"));
- arg = (*++begin).to_string();
- if (! cost.parse(arg, PARSE_SOFT_FAIL | PARSE_NO_MIGRATE))
- throw std::runtime_error(_("Invalid xact command arguments"));
- post->cost = cost;
+ amount_t cost;
+ post->cost_operator = arg;
+ if (begin == end)
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ arg = (*++begin).to_string();
+ if (! cost.parse(arg, PARSE_SOFT_FAIL | PARSE_NO_MIGRATE))
+ throw std::runtime_error(_("Invalid xact command arguments"));
+ post->cost = cost;
}
else {
- // Without a preposition, it is either:
- //
- // A payee, if we have not seen one
- // An account or an amount, if we have
- // An account if an amount has just been seen
- // An amount if an account has just been seen
-
- if (tmpl->payee_mask.empty()) {
- tmpl->payee_mask = arg;
- }
- else {
- amount_t amt;
- optional<mask_t> account;
-
- if (! amt.parse(arg, PARSE_SOFT_FAIL | PARSE_NO_MIGRATE))
- account = mask_t(arg);
-
- if (! post ||
- (account && post->account_mask) ||
- (! account && post->amount)) {
- tmpl->posts.push_back(xact_template_t::post_template_t());
- post = &tmpl->posts.back();
- }
-
- if (account) {
- post->from = false;
- post->account_mask = account;
- } else {
- post->amount = amt;
- }
- }
+ // Without a preposition, it is either:
+ //
+ // A payee, if we have not seen one
+ // An account or an amount, if we have
+ // An account if an amount has just been seen
+ // An amount if an account has just been seen
+
+ if (tmpl->payee_mask.empty()) {
+ tmpl->payee_mask = arg;
+ } else {
+ amount_t amt;
+ optional<mask_t> account;
+
+ if (! amt.parse(arg, PARSE_SOFT_FAIL | PARSE_NO_MIGRATE))
+ account = mask_t(arg);
+
+ if (! post ||
+ (account && post->account_mask) ||
+ (! account && post->amount)) {
+ tmpl->posts.push_back(xact_template_t::post_template_t());
+ post = &tmpl->posts.back();
+ }
+
+ if (account) {
+ post->account_mask = account;
+ } else {
+ post->amount = amt;
+ post = NULL; // an amount concludes this posting
+ }
+ }
}
}
}
@@ -218,14 +217,14 @@ void draft_t::parse_args(const value_t& args)
// A single account at the end of the line is the "from" account
if (tmpl->posts.size() > 1 &&
- tmpl->posts.back().account_mask && ! tmpl->posts.back().amount)
+ tmpl->posts.back().account_mask && ! tmpl->posts.back().amount)
tmpl->posts.back().from = true;
foreach (xact_template_t::post_template_t& post, tmpl->posts) {
if (post.from)
- has_only_to = false;
+ has_only_to = false;
else
- has_only_from = false;
+ has_only_from = false;
}
if (has_only_from) {
@@ -252,28 +251,28 @@ xact_t * draft_t::insert(journal_t& journal)
xacts_iterator xi(journal);
if (xact_t * xact = lookup_probable_account(tmpl->payee_mask.str(), xi).first) {
- DEBUG("derive.xact", "Found payee by lookup: transaction on line "
- << xact->pos->beg_line);
+ DEBUG("draft.xact", "Found payee by lookup: transaction on line "
+ << xact->pos->beg_line);
matching = xact;
} else {
for (xacts_list::reverse_iterator j = journal.xacts.rbegin();
- j != journal.xacts.rend();
- j++) {
+ j != journal.xacts.rend();
+ j++) {
if (tmpl->payee_mask.match((*j)->payee)) {
- matching = *j;
- DEBUG("derive.xact",
- "Found payee match: transaction on line " << (*j)->pos->beg_line);
- break;
+ matching = *j;
+ DEBUG("draft.xact",
+ "Found payee match: transaction on line " << (*j)->pos->beg_line);
+ break;
}
}
}
if (! tmpl->date) {
added->_date = CURRENT_DATE();
- DEBUG("derive.xact", "Setting date to current date");
+ DEBUG("draft.xact", "Setting date to current date");
} else {
added->_date = tmpl->date;
- DEBUG("derive.xact", "Setting date to template date: " << *tmpl->date);
+ DEBUG("draft.xact", "Setting date to template date: " << *tmpl->date);
}
added->set_state(item_t::UNCLEARED);
@@ -284,48 +283,48 @@ xact_t * draft_t::insert(journal_t& journal)
//added->note = matching->note;
#if defined(DEBUG_ON)
- DEBUG("derive.xact", "Setting payee from match: " << added->payee);
+ DEBUG("draft.xact", "Setting payee from match: " << added->payee);
//if (added->code)
- // DEBUG("derive.xact", "Setting code from match: " << *added->code);
+ // DEBUG("draft.xact", "Setting code from match: " << *added->code);
//if (added->note)
- // DEBUG("derive.xact", "Setting note from match: " << *added->note);
+ // DEBUG("draft.xact", "Setting note from match: " << *added->note);
#endif
} else {
added->payee = tmpl->payee_mask.str();
- DEBUG("derive.xact", "Setting payee from template: " << added->payee);
+ DEBUG("draft.xact", "Setting payee from template: " << added->payee);
}
if (tmpl->code) {
added->code = tmpl->code;
- DEBUG("derive.xact", "Now setting code from template: " << *added->code);
+ DEBUG("draft.xact", "Now setting code from template: " << *added->code);
}
if (tmpl->note) {
added->note = tmpl->note;
- DEBUG("derive.xact", "Now setting note from template: " << *added->note);
+ DEBUG("draft.xact", "Now setting note from template: " << *added->note);
}
if (tmpl->posts.empty()) {
if (matching) {
- DEBUG("derive.xact", "Template had no postings, copying from match");
+ DEBUG("draft.xact", "Template had no postings, copying from match");
foreach (post_t * post, matching->posts) {
- added->add_post(new post_t(*post));
- added->posts.back()->set_state(item_t::UNCLEARED);
+ added->add_post(new post_t(*post));
+ added->posts.back()->set_state(item_t::UNCLEARED);
}
} else {
throw_(std::runtime_error,
- _("No accounts, and no past transaction matching '%1'")
- << tmpl->payee_mask);
+ _("No accounts, and no past transaction matching '%1'")
+ << tmpl->payee_mask);
}
} else {
- DEBUG("derive.xact", "Template had postings");
+ DEBUG("draft.xact", "Template had postings");
bool any_post_has_amount = false;
foreach (xact_template_t::post_template_t& post, tmpl->posts) {
if (post.amount) {
- DEBUG("derive.xact", " and at least one has an amount specified");
- any_post_has_amount = true;
- break;
+ DEBUG("draft.xact", " and at least one has an amount specified");
+ any_post_has_amount = true;
+ break;
}
}
@@ -335,171 +334,171 @@ xact_t * draft_t::insert(journal_t& journal)
commodity_t * found_commodity = NULL;
if (matching) {
- if (post.account_mask) {
- DEBUG("derive.xact",
- "Looking for matching posting based on account mask");
-
- foreach (post_t * x, matching->posts) {
- if (post.account_mask->match(x->account->fullname())) {
- new_post.reset(new post_t(*x));
- DEBUG("derive.xact",
- "Founding posting from line " << x->pos->beg_line);
- break;
- }
- }
- } else {
- if (post.from) {
- for (posts_list::reverse_iterator j = matching->posts.rbegin();
- j != matching->posts.rend();
- j++) {
- if ((*j)->must_balance()) {
- new_post.reset(new post_t(**j));
- DEBUG("derive.xact",
- "Copied last real posting from matching");
- break;
- }
- }
- } else {
- for (posts_list::iterator j = matching->posts.begin();
- j != matching->posts.end();
- j++) {
- if ((*j)->must_balance()) {
- new_post.reset(new post_t(**j));
- DEBUG("derive.xact",
- "Copied first real posting from matching");
- break;
- }
- }
- }
- }
+ if (post.account_mask) {
+ DEBUG("draft.xact",
+ "Looking for matching posting based on account mask");
+
+ foreach (post_t * x, matching->posts) {
+ if (post.account_mask->match(x->account->fullname())) {
+ new_post.reset(new post_t(*x));
+ DEBUG("draft.xact",
+ "Founding posting from line " << x->pos->beg_line);
+ break;
+ }
+ }
+ } else {
+ if (post.from) {
+ for (posts_list::reverse_iterator j = matching->posts.rbegin();
+ j != matching->posts.rend();
+ j++) {
+ if ((*j)->must_balance()) {
+ new_post.reset(new post_t(**j));
+ DEBUG("draft.xact",
+ "Copied last real posting from matching");
+ break;
+ }
+ }
+ } else {
+ for (posts_list::iterator j = matching->posts.begin();
+ j != matching->posts.end();
+ j++) {
+ if ((*j)->must_balance()) {
+ new_post.reset(new post_t(**j));
+ DEBUG("draft.xact",
+ "Copied first real posting from matching");
+ break;
+ }
+ }
+ }
+ }
}
if (! new_post.get()) {
- new_post.reset(new post_t);
- DEBUG("derive.xact", "New posting was NULL, creating a blank one");
+ new_post.reset(new post_t);
+ DEBUG("draft.xact", "New posting was NULL, creating a blank one");
}
if (! new_post->account) {
- DEBUG("derive.xact", "New posting still needs an account");
+ DEBUG("draft.xact", "New posting still needs an account");
- if (post.account_mask) {
- DEBUG("derive.xact", "The template has an account mask");
+ if (post.account_mask) {
+ DEBUG("draft.xact", "The template has an account mask");
- account_t * acct = NULL;
- if (! acct) {
- acct = journal.find_account_re(post.account_mask->str());
+ account_t * acct = NULL;
+ if (! acct) {
+ acct = journal.find_account_re(post.account_mask->str());
#if defined(DEBUG_ON)
- if (acct)
- DEBUG("derive.xact", "Found account as a regular expression");
+ if (acct)
+ DEBUG("draft.xact", "Found account as a regular expression");
#endif
- }
- if (! acct) {
- acct = journal.find_account(post.account_mask->str());
+ }
+ if (! acct) {
+ acct = journal.find_account(post.account_mask->str());
#if defined(DEBUG_ON)
- if (acct)
- DEBUG("derive.xact", "Found (or created) account by name");
+ if (acct)
+ DEBUG("draft.xact", "Found (or created) account by name");
#endif
- }
-
- // Find out the default commodity to use by looking at the last
- // commodity used in that account
- for (xacts_list::reverse_iterator j = journal.xacts.rbegin();
- j != journal.xacts.rend();
- j++) {
- foreach (post_t * x, (*j)->posts) {
- if (x->account == acct && ! x->amount.is_null()) {
- new_post.reset(new post_t(*x));
- DEBUG("derive.xact",
- "Found account in journal postings, setting new posting");
- break;
- }
- }
- }
-
- new_post->account = acct;
- DEBUG("derive.xact",
- "Set new posting's account to: " << acct->fullname());
- } else {
- if (post.from) {
- new_post->account = journal.find_account(_("Liabilities:Unknown"));
- DEBUG("derive.xact",
- "Set new posting's account to: Liabilities:Unknown");
- } else {
- new_post->account = journal.find_account(_("Expenses:Unknown"));
- DEBUG("derive.xact",
- "Set new posting's account to: Expenses:Unknown");
- }
- }
+ }
+
+ // Find out the default commodity to use by looking at the last
+ // commodity used in that account
+ for (xacts_list::reverse_iterator j = journal.xacts.rbegin();
+ j != journal.xacts.rend();
+ j++) {
+ foreach (post_t * x, (*j)->posts) {
+ if (x->account == acct && ! x->amount.is_null()) {
+ new_post.reset(new post_t(*x));
+ DEBUG("draft.xact",
+ "Found account in journal postings, setting new posting");
+ break;
+ }
+ }
+ }
+
+ new_post->account = acct;
+ DEBUG("draft.xact",
+ "Set new posting's account to: " << acct->fullname());
+ } else {
+ if (post.from) {
+ new_post->account = journal.find_account(_("Liabilities:Unknown"));
+ DEBUG("draft.xact",
+ "Set new posting's account to: Liabilities:Unknown");
+ } else {
+ new_post->account = journal.find_account(_("Expenses:Unknown"));
+ DEBUG("draft.xact",
+ "Set new posting's account to: Expenses:Unknown");
+ }
+ }
}
assert(new_post->account);
if (new_post.get() && ! new_post->amount.is_null()) {
- found_commodity = &new_post->amount.commodity();
-
- if (any_post_has_amount) {
- new_post->amount = amount_t();
- DEBUG("derive.xact", "New posting has an amount, but we cleared it");
- } else {
- any_post_has_amount = true;
- DEBUG("derive.xact", "New posting has an amount, and we're using it");
- }
+ found_commodity = &new_post->amount.commodity();
+
+ if (any_post_has_amount) {
+ new_post->amount = amount_t();
+ DEBUG("draft.xact", "New posting has an amount, but we cleared it");
+ } else {
+ any_post_has_amount = true;
+ DEBUG("draft.xact", "New posting has an amount, and we're using it");
+ }
}
if (post.amount) {
- new_post->amount = *post.amount;
- DEBUG("derive.xact", "Copied over posting amount");
+ new_post->amount = *post.amount;
+ DEBUG("draft.xact", "Copied over posting amount");
- if (post.from) {
- new_post->amount.in_place_negate();
- DEBUG("derive.xact", "Negated new posting amount");
- }
+ if (post.from) {
+ new_post->amount.in_place_negate();
+ DEBUG("draft.xact", "Negated new posting amount");
+ }
}
if (post.cost) {
- if (post.cost->sign() < 0)
- throw parse_error(_("A posting's cost may not be negative"));
-
- post.cost->in_place_unround();
-
- if (*post.cost_operator == "@") {
- // For the sole case where the cost might be uncommoditized,
- // guarantee that the commodity of the cost after multiplication
- // is the same as it was before.
- commodity_t& cost_commodity(post.cost->commodity());
- *post.cost *= new_post->amount;
- post.cost->set_commodity(cost_commodity);
- }
- else if (new_post->amount.sign() < 0) {
- new_post->cost->in_place_negate();
- }
-
- new_post->cost = *post.cost;
- DEBUG("derive.xact", "Copied over posting cost");
+ if (post.cost->sign() < 0)
+ throw parse_error(_("A posting's cost may not be negative"));
+
+ post.cost->in_place_unround();
+
+ if (*post.cost_operator == "@") {
+ // For the sole case where the cost might be uncommoditized,
+ // guarantee that the commodity of the cost after multiplication
+ // is the same as it was before.
+ commodity_t& cost_commodity(post.cost->commodity());
+ *post.cost *= new_post->amount;
+ post.cost->set_commodity(cost_commodity);
+ }
+ else if (new_post->amount.sign() < 0) {
+ new_post->cost->in_place_negate();
+ }
+
+ new_post->cost = *post.cost;
+ DEBUG("draft.xact", "Copied over posting cost");
}
if (found_commodity &&
- ! new_post->amount.is_null() &&
- ! new_post->amount.has_commodity()) {
- new_post->amount.set_commodity(*found_commodity);
- DEBUG("derive.xact", "Set posting amount commodity to: "
- << new_post->amount.commodity());
-
- new_post->amount = new_post->amount.rounded();
- DEBUG("derive.xact",
- "Rounded posting amount to: " << new_post->amount);
+ ! new_post->amount.is_null() &&
+ ! new_post->amount.has_commodity()) {
+ new_post->amount.set_commodity(*found_commodity);
+ DEBUG("draft.xact", "Set posting amount commodity to: "
+ << new_post->amount.commodity());
+
+ new_post->amount = new_post->amount.rounded();
+ DEBUG("draft.xact",
+ "Rounded posting amount to: " << new_post->amount);
}
added->add_post(new_post.release());
added->posts.back()->account->add_post(added->posts.back());
added->posts.back()->set_state(item_t::UNCLEARED);
- DEBUG("derive.xact", "Added new posting to derived entry");
+ DEBUG("draft.xact", "Added new posting to derived entry");
}
}
if (! journal.add_xact(added.get()))
throw_(std::runtime_error,
- _("Failed to finalize derived transaction (check commodities)"));
+ _("Failed to finalize derived transaction (check commodities)"));
return added.release();
}
diff --git a/src/emacs.cc b/src/emacs.cc
index 3c8bb256..7abdfd7f 100644
--- a/src/emacs.cc
+++ b/src/emacs.cc
@@ -42,11 +42,11 @@ void format_emacs_posts::write_xact(xact_t& xact)
{
if (xact.pos)
out << "\"" << xact.pos->pathname << "\" "
- << xact.pos->beg_line << " ";
+ << xact.pos->beg_line << " ";
else
out << "\"\" " << -1 << " ";
- tm when = gregorian::to_tm(xact.date());
+ tm when = gregorian::to_tm(xact.date());
std::time_t date = std::mktime(&when);
out << "(" << (date / 65536) << " " << (date % 65536) << " 0) ";
@@ -86,7 +86,7 @@ void format_emacs_posts::operator()(post_t& post)
out << " (" << -1 << " ";
out << "\"" << post.reported_account()->fullname() << "\" \""
- << post.amount << "\"";
+ << post.amount << "\"";
switch (post.state()) {
case item_t::CLEARED:
diff --git a/src/error.cc b/src/error.cc
index cfc91ff1..39ac63ea 100644
--- a/src/error.cc
+++ b/src/error.cc
@@ -43,6 +43,7 @@ std::ostringstream _desc_buffer;
string error_context()
{
string context = _ctxt_buffer.str();
+ _ctxt_buffer.clear();
_ctxt_buffer.str("");
return context;
}
@@ -54,9 +55,9 @@ string file_context(const path& file, const std::size_t line)
return buf.str();
}
-string line_context(const string& line,
- const string::size_type pos,
- const string::size_type end_pos)
+string line_context(const string& line,
+ const string::size_type pos,
+ const string::size_type end_pos)
{
std::ostringstream buf;
buf << " " << line << "\n";
@@ -65,24 +66,24 @@ string line_context(const string& line,
buf << " ";
if (end_pos == 0) {
for (string::size_type i = 0; i < pos; i += 1)
- buf << " ";
+ buf << " ";
buf << "^";
} else {
for (string::size_type i = 0; i < end_pos; i += 1) {
- if (i >= pos)
- buf << "^";
- else
- buf << " ";
+ if (i >= pos)
+ buf << "^";
+ else
+ buf << " ";
}
}
}
return buf.str();
}
-string source_context(const path& file,
- const istream_pos_type pos,
- const istream_pos_type end_pos,
- const string& prefix)
+string source_context(const path& file,
+ const istream_pos_type pos,
+ const istream_pos_type end_pos,
+ const string& prefix)
{
const std::streamoff len = end_pos - pos;
if (! len || file == path("/dev/stdin"))
diff --git a/src/error.h b/src/error.h
index 0d33f020..b9960b03 100644
--- a/src/error.h
+++ b/src/error.h
@@ -51,52 +51,54 @@ extern std::ostringstream _desc_buffer;
template <typename T>
inline void throw_func(const string& message) {
+ _desc_buffer.clear();
_desc_buffer.str("");
throw T(message);
}
-#define throw_(cls, msg) \
- ((_desc_buffer << ACCUM(_desc_accum << msg)), \
- _desc_accum.clear(), \
+#define throw_(cls, msg) \
+ ((_desc_buffer << ACCUM(_desc_accum << msg)), \
+ _desc_accum.clear(), \
throw_func<cls>(_desc_buffer.str()))
inline void warning_func(const string& message) {
std::cerr << "Warning: " << message << std::endl;
+ _desc_buffer.clear();
_desc_buffer.str("");
}
-#define warning_(msg) \
- ((_desc_buffer << ACCUM(_desc_accum << msg)), \
- _desc_accum.clear(), \
+#define warning_(msg) \
+ ((_desc_buffer << ACCUM(_desc_accum << msg)), \
+ _desc_accum.clear(), \
warning_func(_desc_buffer.str()))
-extern straccstream _ctxt_accum;
+extern straccstream _ctxt_accum;
extern std::ostringstream _ctxt_buffer;
-#define add_error_context(msg) \
- ((long(_ctxt_buffer.tellp()) == 0) ? \
- ((_ctxt_buffer << ACCUM(_ctxt_accum << msg)), \
- _ctxt_accum.clear()) : \
- ((_ctxt_buffer << std::endl << ACCUM(_ctxt_accum << msg)), \
+#define add_error_context(msg) \
+ ((long(_ctxt_buffer.tellp()) == 0) ? \
+ ((_ctxt_buffer << ACCUM(_ctxt_accum << msg)), \
+ _ctxt_accum.clear()) : \
+ ((_ctxt_buffer << std::endl << ACCUM(_ctxt_accum << msg)), \
_ctxt_accum.clear()))
string error_context();
string file_context(const path& file, std::size_t line);
-string line_context(const string& line,
- const string::size_type pos = 0,
- const string::size_type end_pos = 0);
-
-string source_context(const path& file,
- const istream_pos_type pos,
- const istream_pos_type end_pos,
- const string& prefix = "");
-
-#define DECLARE_EXCEPTION(name, kind) \
- class name : public kind { \
- public: \
- explicit name(const string& why) throw() : kind(why) {} \
- virtual ~name() throw() {} \
+string line_context(const string& line,
+ const string::size_type pos = 0,
+ const string::size_type end_pos = 0);
+
+string source_context(const path& file,
+ const istream_pos_type pos,
+ const istream_pos_type end_pos,
+ const string& prefix = "");
+
+#define DECLARE_EXCEPTION(name, kind) \
+ class name : public kind { \
+ public: \
+ explicit name(const string& why) throw() : kind(why) {} \
+ virtual ~name() throw() {} \
}
} // namespace ledger
diff --git a/src/expr.cc b/src/expr.cc
index f3a30de6..b3d4abcd 100644
--- a/src/expr.cc
+++ b/src/expr.cc
@@ -33,11 +33,12 @@
#include "expr.h"
#include "parser.h"
+#include "scope.h"
namespace ledger {
void expr_t::parse(std::istream& in, const parse_flags_t& flags,
- const optional<string>& original_string)
+ const optional<string>& original_string)
{
parser_t parser;
istream_pos_type start_pos = in.tellg();
@@ -52,8 +53,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 {
@@ -76,33 +78,38 @@ value_t expr_t::real_calc(scope_t& scope)
try {
return ptr->calc(scope, &locus);
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (locus) {
- add_error_context(_("While evaluating value expression:"));
- add_error_context(op_context(ptr, locus));
-
- if (SHOW_INFO()) {
- add_error_context(_("The value expression tree was:"));
- std::ostringstream buf;
- ptr->dump(buf, 0);
-
- std::istringstream in(buf.str());
- std::ostringstream out;
- char linebuf[1024];
- bool first = true;
- while (in.good() && ! in.eof()) {
- in.getline(linebuf, 1023);
- std::streamsize len = in.gcount();
- if (len > 0) {
- if (first)
- first = false;
- else
- out << '\n';
- out << " " << linebuf;
- }
- }
- add_error_context(out.str());
- }
+ string current_context = error_context();
+
+ add_error_context(_("While evaluating value expression:"));
+ add_error_context(op_context(ptr, locus));
+
+ if (SHOW_INFO()) {
+ add_error_context(_("The value expression tree was:"));
+ std::ostringstream buf;
+ ptr->dump(buf, 0);
+
+ std::istringstream in(buf.str());
+ std::ostringstream out;
+ char linebuf[1024];
+ bool first = true;
+ while (in.good() && ! in.eof()) {
+ in.getline(linebuf, 1023);
+ std::streamsize len = in.gcount();
+ if (len > 0) {
+ if (first)
+ first = false;
+ else
+ out << '\n';
+ out << " " << linebuf;
+ }
+ }
+ add_error_context(out.str());
+ }
+
+ if (! current_context.empty())
+ add_error_context(current_context);
}
throw;
}
@@ -156,4 +163,45 @@ void expr_t::dump(std::ostream& out) const
if (ptr) ptr->dump(out, 0);
}
+value_t source_command(call_scope_t& args)
+{
+ std::istream * in = NULL;
+ scoped_ptr<ifstream> stream;
+ string pathname;
+
+ if (args.has(0)) {
+ pathname = args.get<string>(0);
+ stream.reset(new ifstream(path(pathname)));
+ in = stream.get();
+ } else {
+ pathname = "<stdin>";
+ in = &std::cin;
+ }
+
+ symbol_scope_t file_locals(args);
+ std::size_t linenum = 0;
+ char buf[4096];
+ istream_pos_type pos;
+
+ while (in->good() && ! in->eof()) {
+ pos = in->tellg();
+ in->getline(buf, 4095);
+ linenum++;
+
+ char * p = skip_ws(buf);
+ if (*p && *p != ';') {
+ try {
+ expr_t(p).calc(file_locals);
+ }
+ catch (const std::exception&) {
+ add_error_context(_("While parsing value expression on line %1:")
+ << linenum);
+ add_error_context(source_context(pathname, pos, in->tellg(), "> "));
+ }
+ }
+ }
+
+ return true;
+}
+
} // namespace ledger
diff --git a/src/expr.h b/src/expr.h
index 09285966..a3ae5669 100644
--- a/src/expr.h
+++ b/src/expr.h
@@ -56,9 +56,8 @@ class expr_t : public expr_base_t<value_t>
public:
class op_t;
- typedef intrusive_ptr<op_t> ptr_op_t;
+ typedef intrusive_ptr<op_t> ptr_op_t;
typedef intrusive_ptr<const op_t> const_ptr_op_t;
-
protected:
ptr_op_t ptr;
@@ -112,13 +111,13 @@ public:
return parse(stream, flags, str);
}
- virtual void parse(std::istream& in,
- const parse_flags_t& flags = PARSE_DEFAULT,
- const optional<string>& original_string = none);
+ virtual void parse(std::istream& in,
+ const parse_flags_t& flags = PARSE_DEFAULT,
+ const optional<string>& original_string = none);
virtual void compile(scope_t& scope);
virtual value_t real_calc(scope_t& scope);
- bool is_constant() const;
+ bool is_constant() const;
value_t& constant_value();
const value_t& constant_value() const;
bool is_function() const;
@@ -142,6 +141,29 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
+/**
+ * Dealing with expr pointers tucked into value objects.
+ */
+inline bool is_expr(const value_t& val) {
+ return val.is_any() && val.as_any().type() == typeid(expr_t::ptr_op_t);
+}
+inline expr_t::ptr_op_t as_expr(const value_t& val) {
+ VERIFY(val.is_any());
+ return val.as_any<expr_t::ptr_op_t>();
+}
+inline void set_expr(value_t& val, expr_t::ptr_op_t op) {
+ val.set_any(op);
+}
+inline value_t expr_value(expr_t::ptr_op_t op) {
+ value_t temp;
+ temp.set_any(op);
+ return temp;
+}
+
+class call_scope_t;
+
+value_t source_command(call_scope_t& scope);
+
} // namespace ledger
#endif // _EXPR_H
diff --git a/src/exprbase.h b/src/exprbase.h
index cf81a0a7..83ef34ff 100644
--- a/src/exprbase.h
+++ b/src/exprbase.h
@@ -78,7 +78,7 @@ public:
protected:
scope_t * context;
string str;
- bool compiled;
+ bool compiled;
virtual result_type real_calc(scope_t& scope) = 0;
@@ -117,7 +117,7 @@ public:
return str;
}
void set_text(const string& txt) {
- str = txt;
+ str = txt;
compiled = false;
}
@@ -126,16 +126,16 @@ public:
return parse(stream, flags, str);
}
virtual void parse(std::istream&,
- const parse_flags_t& = PARSE_DEFAULT,
- const optional<string>& original_string = none) {
+ const parse_flags_t& = PARSE_DEFAULT,
+ const optional<string>& original_string = none) {
set_text(original_string ? *original_string : "<stream>");
}
-
- void mark_uncompiled() {
+
+ virtual void mark_uncompiled() {
compiled = false;
}
- void recompile(scope_t& scope) {
+ void recompile(scope_t& scope) {
compiled = false;
compile(scope);
}
@@ -157,21 +157,23 @@ public:
if (! compiled) {
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
- DEBUG("expr.compile", "Before compilation:");
- dump(*_log_stream);
+ DEBUG("expr.compile", "Before compilation:");
+ dump(*_log_stream);
}
#endif // defined(DEBUG_ON)
+ DEBUG("expr.calc.when", "Compiling: " << str);
compile(scope);
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
- DEBUG("expr.compile", "After compilation:");
- dump(*_log_stream);
+ DEBUG("expr.compile", "After compilation:");
+ dump(*_log_stream);
}
#endif // defined(DEBUG_ON)
}
+ DEBUG("expr.calc.when", "Calculating: " << str);
return real_calc(scope);
}
@@ -247,7 +249,7 @@ private:
template <typename ResultType>
std::ostream& operator<<(std::ostream& out,
- const expr_base_t<ResultType>& expr) {
+ const expr_base_t<ResultType>& expr) {
expr.print(out);
return out;
}
diff --git a/src/filters.cc b/src/filters.cc
index e5c5275c..1dd410d3 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -36,6 +36,7 @@
#include "journal.h"
#include "report.h"
#include "compare.h"
+#include "pool.h"
namespace ledger {
@@ -75,7 +76,7 @@ void post_splitter::operator()(post_t& post)
(*i).second.push_back(&post);
} else {
std::pair<value_to_posts_map::iterator, bool> inserted
- = posts_map.insert(value_to_posts_map::value_type(result, posts_list()));
+ = posts_map.insert(value_to_posts_map::value_type(result, posts_list()));
assert(inserted.second);
(*inserted.first).second.push_back(&post);
}
@@ -83,7 +84,7 @@ void post_splitter::operator()(post_t& post)
}
pass_down_posts::pass_down_posts(post_handler_ptr handler,
- posts_iterator& iter)
+ posts_iterator& iter)
: item_handler<post_t>(handler)
{
TRACE_CTOR(pass_down_posts, "post_handler_ptr, posts_iterator");
@@ -92,7 +93,7 @@ pass_down_posts::pass_down_posts(post_handler_ptr handler,
try {
item_handler<post_t>::operator()(*post);
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
add_error_context(item_context(*post, _("While handling posting")));
throw;
}
@@ -128,16 +129,16 @@ void truncate_xacts::flush()
bool print = false;
if (head_count) {
if (head_count > 0 && i < head_count)
- print = true;
+ print = true;
else if (head_count < 0 && i >= - head_count)
- print = true;
+ print = true;
}
if (! print && tail_count) {
if (tail_count > 0 && l - i <= tail_count)
- print = true;
+ print = true;
else if (tail_count < 0 && l - i > - tail_count)
- print = true;
+ print = true;
}
if (print)
@@ -172,7 +173,7 @@ void truncate_xacts::operator()(post_t& post)
void sort_posts::post_accumulated_posts()
{
std::stable_sort(posts.begin(), posts.end(),
- compare_items<post_t>(sort_order));
+ compare_items<post_t>(sort_order));
foreach (post_t * post, posts) {
post->xdata().drop_flags(POST_EXT_SORT_CALC);
@@ -184,30 +185,30 @@ void sort_posts::post_accumulated_posts()
namespace {
void split_string(const string& str, const char ch,
- std::list<string>& strings)
+ std::list<string>& strings)
{
const char * b = str.c_str();
for (const char * p = b; *p; p++) {
if (*p == ch) {
- strings.push_back(string(b, p - b));
- b = p + 1;
+ strings.push_back(string(b, p - b));
+ b = p + 1;
}
}
strings.push_back(string(b));
}
account_t * create_temp_account_from_path(std::list<string>& account_names,
- temporaries_t& temps,
- account_t * master)
+ temporaries_t& temps,
+ account_t * master)
{
account_t * new_account = NULL;
foreach (const string& name, account_names) {
if (new_account) {
- new_account = new_account->find_account(name);
+ new_account = new_account->find_account(name);
} else {
- new_account = master->find_account(name, false);
- if (! new_account)
- new_account = &temps.create_account(name, master);
+ new_account = master->find_account(name, false);
+ if (! new_account)
+ new_account = &temps.create_account(name, master);
}
}
@@ -216,11 +217,48 @@ namespace {
}
}
+void anonymize_posts::render_commodity(amount_t& amt)
+{
+ commodity_t& comm(amt.commodity());
+
+ std::size_t id;
+ bool newly_added = false;
+
+ commodity_index_map::iterator i = comms.find(&comm);
+ if (i == comms.end()) {
+ id = next_comm_id++;
+ newly_added = true;
+ comms.insert(commodity_index_map::value_type(&comm, id));
+ } else {
+ id = (*i).second;
+ }
+
+ std::ostringstream buf;
+ do {
+ buf << static_cast<char>('A' + (id % 26));
+ id /= 26;
+ }
+ while (id > 0);
+
+ if (amt.has_annotation())
+ amt.set_commodity
+ (*commodity_pool_t::current_pool->find_or_create(buf.str(),
+ amt.annotation()));
+ else
+ amt.set_commodity
+ (*commodity_pool_t::current_pool->find_or_create(buf.str()));
+
+ if (newly_added) {
+ amt.commodity().set_flags(comm.flags());
+ amt.commodity().set_precision(comm.precision());
+ }
+}
+
void anonymize_posts::operator()(post_t& post)
{
- SHA1 sha;
- uint_least32_t message_digest[5];
- bool copy_xact_details = false;
+ SHA1 sha;
+ unsigned int message_digest[5];
+ bool copy_xact_details = false;
if (last_xact != post.xact) {
temps.copy_xact(*post.xact);
@@ -228,12 +266,17 @@ 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);
+ std::ostringstream buf;
+ buf << reinterpret_cast<uintmax_t>(post.xact->payee.c_str())
+ << integer_gen() << post.xact->payee.c_str();
+
sha.Reset();
- sha << post.xact->payee.c_str();
+ sha << buf.str().c_str();
sha.Result(message_digest);
xact.payee = to_hex(message_digest);
@@ -245,8 +288,11 @@ void anonymize_posts::operator()(post_t& post)
for (account_t * acct = post.account;
acct;
acct = acct->parent) {
+ std::ostringstream buf;
+ buf << integer_gen() << acct << acct->fullname();
+
sha.Reset();
- sha << acct->name.c_str();
+ sha << buf.str().c_str();
sha.Result(message_digest);
account_names.push_front(to_hex(message_digest));
@@ -258,6 +304,18 @@ void anonymize_posts::operator()(post_t& post)
temp.note = none;
temp.add_flags(POST_ANONYMIZED);
+ render_commodity(temp.amount);
+ if (temp.amount.has_annotation()) {
+ temp.amount.annotation().tag = none;
+ if (temp.amount.annotation().price)
+ render_commodity(*temp.amount.annotation().price);
+ }
+
+ if (temp.cost)
+ render_commodity(*temp.cost);
+ if (temp.assigned_amount)
+ render_commodity(*temp.assigned_amount);
+
(*handler)(temp);
}
@@ -289,18 +347,16 @@ void calc_posts::operator()(post_t& post)
}
namespace {
- typedef function<void (post_t&)> post_functor_t;
-
- void handle_value(const value_t& value,
- account_t * account,
- xact_t * xact,
- temporaries_t& temps,
- post_handler_ptr handler,
- const date_t& date = date_t(),
- const value_t& total = value_t(),
- const bool direct_amount = false,
- const bool mark_visited = false,
- const optional<post_functor_t>& functor = none)
+ void handle_value(const value_t& value,
+ account_t * account,
+ xact_t * xact,
+ temporaries_t& temps,
+ post_handler_ptr handler,
+ const date_t& date = date_t(),
+ const bool act_date_p = true,
+ const value_t& total = value_t(),
+ const bool direct_amount = false,
+ const bool mark_visited = false)
{
post_t& post = temps.create_post(*xact, account);
post.add_flags(ITEM_GENERATED);
@@ -309,18 +365,22 @@ namespace {
// such. This allows subtotal reports to show "(Account)" for accounts
// that contain only virtual posts.
if (account && account->has_xdata() &&
- account->xdata().has_flags(ACCOUNT_EXT_AUTO_VIRTUALIZE)) {
+ account->xdata().has_flags(ACCOUNT_EXT_AUTO_VIRTUALIZE)) {
if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_NON_VIRTUALS)) {
- post.add_flags(POST_VIRTUAL);
- if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS))
- post.add_flags(POST_MUST_BALANCE);
+ post.add_flags(POST_VIRTUAL);
+ if (! account->xdata().has_flags(ACCOUNT_EXT_HAS_UNB_VIRTUALS))
+ post.add_flags(POST_MUST_BALANCE);
}
}
post_t::xdata_t& xdata(post.xdata());
- if (is_valid(date))
- xdata.date = date;
+ if (is_valid(date)) {
+ if (act_date_p)
+ xdata.date = date;
+ else
+ xdata.value_date = date;
+ }
value_t temp(value);
@@ -353,9 +413,6 @@ namespace {
if (direct_amount)
xdata.add_flags(POST_EXT_DIRECT_AMT);
- if (functor)
- (*functor)(post);
-
DEBUG("filters.changed_value.rounding", "post.amount = " << post.amount);
(*handler)(post);
@@ -388,25 +445,32 @@ void collapse_posts::report_subtotal()
}
else {
date_t earliest_date;
+ date_t latest_date;
foreach (post_t * post, component_posts) {
- date_t reported = post->date();
- if (! is_valid(earliest_date) ||
- reported < earliest_date)
- earliest_date = reported;
+ date_t date = post->date();
+ date_t value_date = post->value_date();
+ if (! is_valid(earliest_date) || date < earliest_date)
+ earliest_date = date;
+ if (! is_valid(latest_date) || value_date > latest_date)
+ latest_date = value_date;
}
xact_t& xact = temps.create_xact();
- xact.payee = last_xact->payee;
- xact._date = (is_valid(earliest_date) ?
- earliest_date : last_xact->_date);
+ xact.payee = last_xact->payee;
+ xact._date = (is_valid(earliest_date) ?
+ earliest_date : last_xact->_date);
DEBUG("filters.collapse", "Pseudo-xact date = " << *xact._date);
-
- handle_value(/* value= */ subtotal,
- /* account= */ &totals_account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler);
+ DEBUG("filters.collapse", "earliest date = " << earliest_date);
+ DEBUG("filters.collapse", "latest date = " << latest_date);
+
+ handle_value(/* value= */ subtotal,
+ /* account= */ &totals_account,
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ latest_date,
+ /* act_date_p= */ false);
}
component_posts.clear();
@@ -438,27 +502,16 @@ void related_posts::flush()
{
if (posts.size() > 0) {
foreach (post_t * post, posts) {
- if (post->xact) {
- foreach (post_t * r_post, post->xact->posts) {
- post_t::xdata_t& xdata(r_post->xdata());
- if (! xdata.has_flags(POST_EXT_HANDLED) &&
- (! xdata.has_flags(POST_EXT_RECEIVED) ?
- ! r_post->has_flags(ITEM_GENERATED | POST_VIRTUAL) :
- also_matching)) {
- xdata.add_flags(POST_EXT_HANDLED);
- item_handler<post_t>::operator()(*r_post);
- }
- }
- } else {
- // This code should only be reachable from the "output"
- // command, since that is the only command which attempts to
- // output auto or period xacts.
- post_t::xdata_t& xdata(post->xdata());
- if (! xdata.has_flags(POST_EXT_HANDLED) &&
- ! post->has_flags(ITEM_GENERATED)) {
- xdata.add_flags(POST_EXT_HANDLED);
- item_handler<post_t>::operator()(*post);
- }
+ assert(post->xact);
+ foreach (post_t * r_post, post->xact->posts) {
+ post_t::xdata_t& xdata(r_post->xdata());
+ if (! xdata.has_flags(POST_EXT_HANDLED) &&
+ (! xdata.has_flags(POST_EXT_RECEIVED) ?
+ ! r_post->has_flags(ITEM_GENERATED | POST_VIRTUAL) :
+ also_matching)) {
+ xdata.add_flags(POST_EXT_HANDLED);
+ item_handler<post_t>::operator()(*r_post);
+ }
}
}
}
@@ -466,84 +519,104 @@ void related_posts::flush()
item_handler<post_t>::flush();
}
-rounding_error_posts::rounding_error_posts(post_handler_ptr handler,
- report_t& _report)
+display_filter_posts::display_filter_posts(post_handler_ptr handler,
+ report_t& _report,
+ bool _show_rounding)
: item_handler<post_t>(handler), report(_report),
- rounding_account(temps.create_account(_("<Rounding>")))
+ show_rounding(_show_rounding),
+ rounding_account(temps.create_account(_("<Adjustment>"))),
+ revalued_account(temps.create_account(_("<Revalued>")))
{
- TRACE_CTOR(rounding_error_posts, "post_handler_ptr, report_t&");
+ TRACE_CTOR(display_filter_posts,
+ "post_handler_ptr, report_t&, account_t&, bool");
display_amount_expr = report.HANDLER(display_amount_).expr;
display_total_expr = report.HANDLER(display_total_).expr;
}
-void rounding_error_posts::output_rounding(post_t& post)
+bool display_filter_posts::output_rounding(post_t& post)
{
bind_scope_t bound_scope(report, post);
- value_t new_display_total(display_total_expr.calc(bound_scope));
+ value_t new_display_total;
+
+ if (show_rounding) {
+ new_display_total = display_total_expr.calc(bound_scope);
- DEBUG("filters.changed_value.rounding",
- "rounding.new_display_total = " << new_display_total);
+ DEBUG("filters.changed_value.rounding",
+ "rounding.new_display_total = " << new_display_total);
+ }
- if (! last_display_total.is_null()) {
- if (value_t repriced_amount = display_amount_expr.calc(bound_scope)) {
+ // Allow the posting to be displayed if:
+ // 1. It's display_amount would display as non-zero
+ // 2. The --empty option was specified
+ // 3. The account of the posting is <Revalued>
+
+ if (post.account == &revalued_account) {
+ if (show_rounding)
+ last_display_total = new_display_total;
+ return true;
+ }
+
+ if (value_t repriced_amount = display_amount_expr.calc(bound_scope)) {
+ if (! last_display_total.is_null()) {
DEBUG("filters.changed_value.rounding",
- "rounding.repriced_amount = " << repriced_amount);
+ "rounding.repriced_amount = " << repriced_amount);
value_t precise_display_total(new_display_total.truncated() -
- repriced_amount.truncated());
+ repriced_amount.truncated());
DEBUG("filters.changed_value.rounding",
- "rounding.precise_display_total = " << precise_display_total);
+ "rounding.precise_display_total = " << precise_display_total);
DEBUG("filters.changed_value.rounding",
- "rounding.last_display_total = " << last_display_total);
+ "rounding.last_display_total = " << last_display_total);
if (value_t diff = precise_display_total - last_display_total) {
- DEBUG("filters.changed_value.rounding",
- "rounding.diff = " << diff);
-
- xact_t& xact = temps.create_xact();
- xact.payee = _("Commodity rounding");
- xact._date = post.date();
-
- handle_value(/* value= */ diff,
- /* account= */ &rounding_account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler,
- /* date= */ *xact._date,
- /* total= */ precise_display_total,
- /* direct_amount= */ true);
+ DEBUG("filters.changed_value.rounding",
+ "rounding.diff = " << diff);
+
+ handle_value(/* value= */ diff,
+ /* account= */ &rounding_account,
+ /* xact= */ post.xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ date_t(),
+ /* act_date_p= */ true,
+ /* total= */ precise_display_total,
+ /* direct_amount= */ true);
}
- }
+ }
+ if (show_rounding)
+ last_display_total = new_display_total;
+ return true;
+ } else {
+ return report.HANDLED(empty);
}
- last_display_total = new_display_total;
}
-void rounding_error_posts::operator()(post_t& post)
+void display_filter_posts::operator()(post_t& post)
{
- output_rounding(post);
-
- item_handler<post_t>::operator()(post);
+ if (output_rounding(post))
+ item_handler<post_t>::operator()(post);
}
changed_value_posts::changed_value_posts
- (post_handler_ptr handler,
- report_t& _report,
- bool _for_accounts_report,
- bool _show_unrealized,
- rounding_error_posts * _rounding_handler)
+ (post_handler_ptr handler,
+ report_t& _report,
+ bool _for_accounts_report,
+ bool _show_unrealized,
+ display_filter_posts * _display_filter)
: item_handler<post_t>(handler), report(_report),
for_accounts_report(_for_accounts_report),
show_unrealized(_show_unrealized), last_post(NULL),
- revalued_account(temps.create_account(_("<Revalued>"))),
- rounding_handler(_rounding_handler)
+ revalued_account(_display_filter ? _display_filter->revalued_account :
+ temps.create_account(_("<Revalued>"))),
+ display_filter(_display_filter)
{
TRACE_CTOR(changed_value_posts, "post_handler_ptr, report_t&, bool");
- total_expr = (report.HANDLED(revalued_total_) ?
- report.HANDLER(revalued_total_).expr :
- report.HANDLER(display_total_).expr);
+ total_expr = (report.HANDLED(revalued_total_) ?
+ report.HANDLER(revalued_total_).expr :
+ report.HANDLER(display_total_).expr);
display_total_expr = report.HANDLER(display_total_).expr;
changed_values_only = report.HANDLED(revalued_only);
@@ -593,49 +666,51 @@ void changed_value_posts::output_revaluation(post_t& post, const date_t& date)
post.xdata().date = date_t();
DEBUG("filters.changed_value",
- "output_revaluation(last_total) = " << last_total);
+ "output_revaluation(last_total) = " << last_total);
DEBUG("filters.changed_value",
- "output_revaluation(repriced_total) = " << repriced_total);
+ "output_revaluation(repriced_total) = " << repriced_total);
if (! last_total.is_null()) {
if (value_t diff = repriced_total - last_total) {
DEBUG("filters.changed_value", "output_revaluation(strip(diff)) = "
- << diff.strip_annotations(report.what_to_keep()));
+ << diff.strip_annotations(report.what_to_keep()));
xact_t& xact = temps.create_xact();
xact.payee = _("Commodities revalued");
- xact._date = is_valid(date) ? date : post.date();
+ xact._date = is_valid(date) ? date : post.value_date();
if (! for_accounts_report) {
- handle_value
- (/* value= */ diff,
- /* account= */ &revalued_account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler,
- /* date= */ *xact._date,
- /* total= */ repriced_total);
+ handle_value
+ (/* value= */ diff,
+ /* account= */ &revalued_account,
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ *xact._date,
+ /* act_date_p= */ true,
+ /* total= */ repriced_total);
}
else if (show_unrealized) {
- handle_value
- (/* value= */ - diff,
- /* account= */ (diff < 0L ?
- losses_equity_account :
- gains_equity_account),
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler,
- /* date= */ *xact._date,
- /* total= */ value_t(),
- /* direct_amount= */ false,
- /* mark_visited= */ true);
+ handle_value
+ (/* value= */ - diff,
+ /* account= */ (diff < 0L ?
+ losses_equity_account :
+ gains_equity_account),
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ *xact._date,
+ /* act_date_p= */ true,
+ /* total= */ value_t(),
+ /* direct_amount= */ false,
+ /* mark_visited= */ true);
}
}
}
}
-void changed_value_posts::output_intermediate_prices(post_t& post,
- const date_t& current)
+void changed_value_posts::output_intermediate_prices(post_t& post,
+ const date_t& current)
{
// To fix BZ#199, examine the balance of last_post and determine whether the
// price of that amount changed after its date and before the new post's
@@ -649,7 +724,7 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
xact_t& xact(temps.create_xact());
xact.payee = _("Commodities revalued");
- xact._date = is_valid(current) ? current : post.date();
+ xact._date = is_valid(current) ? current : post.value_date();
post_t& temp(temps.copy_post(post, xact));
temp.add_flags(ITEM_GENERATED);
@@ -703,24 +778,24 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
commodity_t::history_map all_prices;
foreach (const balance_t::amounts_map::value_type& amt_comm,
- display_total.as_balance().amounts) {
+ display_total.as_balance().amounts) {
if (optional<commodity_t::varied_history_t&> hist =
- amt_comm.first->varied_history()) {
- foreach
- (const commodity_t::history_by_commodity_map::value_type& comm_hist,
- hist->histories) {
- foreach (const commodity_t::history_map::value_type& price,
- comm_hist.second.prices) {
- if (price.first.date() > post.date() &&
- price.first.date() < current) {
- DEBUG("filters.revalued", post.date() << " < "
- << price.first.date() << " < " << current);
- DEBUG("filters.revalued", "inserting "
- << price.second << " at " << price.first.date());
- all_prices.insert(price);
- }
- }
- }
+ amt_comm.first->varied_history()) {
+ foreach
+ (const commodity_t::history_by_commodity_map::value_type& comm_hist,
+ hist->histories) {
+ foreach (const commodity_t::history_map::value_type& price,
+ comm_hist.second.prices) {
+ if (price.first.date() > post.value_date() &&
+ price.first.date() < current) {
+ DEBUG("filters.revalued", post.value_date() << " < "
+ << price.first.date() << " < " << current);
+ DEBUG("filters.revalued", "inserting "
+ << price.second << " at " << price.first.date());
+ all_prices.insert(price);
+ }
+ }
+ }
}
}
@@ -733,7 +808,7 @@ void changed_value_posts::output_intermediate_prices(post_t& post,
// This insert will fail if a later price has already been inserted
// for that date.
DEBUG("filters.revalued",
- "re-inserting " << price.second << " at " << price.first.date());
+ "re-inserting " << price.second << " at " << price.first.date());
pricing_dates.insert(date_map::value_type(price.first.date(), true));
}
@@ -755,8 +830,8 @@ void changed_value_posts::operator()(post_t& post)
{
if (last_post) {
if (! for_accounts_report)
- output_intermediate_prices(*last_post, post.date());
- output_revaluation(*last_post, post.date());
+ output_intermediate_prices(*last_post, post.value_date());
+ output_revaluation(*last_post, post.value_date());
}
if (changed_values_only)
@@ -769,8 +844,8 @@ void changed_value_posts::operator()(post_t& post)
last_post = &post;
}
-void subtotal_posts::report_subtotal(const char * spec_fmt,
- const optional<date_interval_t>& interval)
+void subtotal_posts::report_subtotal(const char * spec_fmt,
+ const optional<date_interval_t>& interval)
{
if (component_posts.empty())
return;
@@ -780,11 +855,12 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
if (! range_start || ! range_finish) {
foreach (post_t * post, component_posts) {
- date_t date = post->date();
+ date_t date = post->date();
+ date_t value_date = post->value_date();
if (! range_start || date < *range_start)
- range_start = date;
- if (! range_finish || date > *range_finish)
- range_finish = date;
+ range_start = date;
+ if (! range_finish || value_date > *range_finish)
+ range_finish = value_date;
}
}
component_posts.clear();
@@ -795,7 +871,7 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
}
else if (date_format) {
out_date << "- " << format_date(*range_finish, FMT_CUSTOM,
- date_format->c_str());
+ date_format->c_str());
}
else {
out_date << "- " << format_date(*range_finish);
@@ -806,11 +882,13 @@ void subtotal_posts::report_subtotal(const char * spec_fmt,
xact._date = *range_start;
foreach (values_map::value_type& pair, values)
- handle_value(/* value= */ pair.second.value,
- /* account= */ pair.second.account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler);
+ handle_value(/* value= */ pair.second.value,
+ /* account= */ pair.second.account,
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ *range_finish,
+ /* act_date_p= */ false);
values.clear();
}
@@ -869,25 +947,25 @@ void interval_posts::operator()(post_t& post)
report_subtotal(last_interval);
if (generate_empty_posts) {
- for (++last_interval; interval != last_interval; ++last_interval) {
- // Generate a null posting, so the intervening periods can be
- // seen when -E is used, or if the calculated amount ends up being
- // non-zero
- xact_t& null_xact = temps.create_xact();
- null_xact._date = last_interval.inclusive_end();
-
- post_t& null_post = temps.create_post(null_xact, &empty_account);
- null_post.add_flags(POST_CALCULATED);
- null_post.amount = 0L;
-
- last_post = &null_post;
- subtotal_posts::operator()(null_post);
-
- report_subtotal(last_interval);
- }
- assert(interval == last_interval);
+ for (++last_interval; interval != last_interval; ++last_interval) {
+ // Generate a null posting, so the intervening periods can be
+ // seen when -E is used, or if the calculated amount ends up being
+ // non-zero
+ xact_t& null_xact = temps.create_xact();
+ null_xact._date = last_interval.inclusive_end();
+
+ post_t& null_post = temps.create_post(null_xact, &empty_account);
+ null_post.add_flags(POST_CALCULATED);
+ null_post.amount = 0L;
+
+ last_post = &null_post;
+ subtotal_posts::operator()(null_post);
+
+ report_subtotal(last_interval);
+ }
+ assert(interval == last_interval);
} else {
- last_interval = interval;
+ last_interval = interval;
}
} else {
last_interval = interval;
@@ -918,18 +996,22 @@ void posts_as_equity::report_subtotal()
foreach (values_map::value_type& pair, values) {
if (pair.second.value.is_balance()) {
foreach (const balance_t::amounts_map::value_type& amount_pair,
- pair.second.value.as_balance().amounts)
- handle_value(/* value= */ amount_pair.second,
- /* account= */ pair.second.account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler);
+ pair.second.value.as_balance().amounts)
+ handle_value(/* value= */ amount_pair.second,
+ /* account= */ pair.second.account,
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ finish,
+ /* act_date_p= */ false);
} else {
- handle_value(/* value= */ pair.second.value,
- /* account= */ pair.second.account,
- /* xact= */ &xact,
- /* temps= */ temps,
- /* handler= */ handler);
+ handle_value(/* value= */ pair.second.value,
+ /* account= */ pair.second.account,
+ /* xact= */ &xact,
+ /* temps= */ temps,
+ /* handler= */ handler,
+ /* date= */ finish,
+ /* act_date_p= */ false);
}
total += pair.second.value;
}
@@ -937,7 +1019,7 @@ void posts_as_equity::report_subtotal()
if (total.is_balance()) {
foreach (const balance_t::amounts_map::value_type& pair,
- total.as_balance().amounts) {
+ total.as_balance().amounts) {
post_t& balance_post = temps.create_post(xact, balance_account);
balance_post.amount = - pair.second;
(*handler)(balance_post);
@@ -961,11 +1043,11 @@ 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,
- shared_ptr<subtotal_posts>(new subtotal_posts(handler, amount_expr)));
+ 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);
@@ -992,28 +1074,28 @@ 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: {
string account_name = substitute.to_string();
if (! account_name.empty() &&
- account_name[account_name.length() - 1] != ':') {
- account_t * prev_account = temp.account;
- temp.account->remove_post(&temp);
-
- account_name += ':';
- account_name += prev_account->fullname();
-
- std::list<string> account_names;
- split_string(account_name, ':', account_names);
- temp.account = create_temp_account_from_path(account_names, temps,
- xact.journal->master);
- temp.account->add_post(&temp);
-
- temp.account->add_flags(prev_account->flags());
- if (prev_account->has_xdata())
- temp.account->xdata().add_flags(prev_account->xdata().flags());
+ account_name[account_name.length() - 1] != ':') {
+ account_t * prev_account = temp.account;
+ temp.account->remove_post(&temp);
+
+ account_name += ':';
+ account_name += prev_account->fullname();
+
+ std::list<string> account_names;
+ split_string(account_name, ':', account_names);
+ temp.account = create_temp_account_from_path(account_names, temps,
+ xact.journal->master);
+ temp.account->add_post(&temp);
+
+ temp.account->add_flags(prev_account->flags());
+ if (prev_account->has_xdata())
+ temp.account->xdata().add_flags(prev_account->xdata().flags());
}
break;
}
@@ -1031,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])
@@ -1062,48 +1144,71 @@ 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))
- throw_(std::runtime_error,
- _("Something odd has happened at date %1") << date);
- begin = pair.first.start;
+ 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.finish || *begin < *pair.first.finish)) {
+ post_t& post = *pair.second;
- DEBUG("budget.generate", "Reporting budget for "
- << post.reported_account()->fullname());
+ ++pair.first;
+ if (! pair.first.start)
+ posts_to_erase.push_back(i);
- xact_t& xact = temps.create_xact();
- xact.payee = _("Budget transaction");
- xact._date = begin;
+ DEBUG("budget.generate", "Reporting budget for "
+ << post.reported_account()->fullname());
- post_t& temp = temps.copy_post(post, xact);
- temp.amount.in_place_negate();
+ xact_t& xact = temps.create_xact();
+ xact.payee = _("Budget transaction");
+ xact._date = begin;
- if (flags & BUDGET_WRAP_VALUES) {
- value_t seq;
- seq.push_back(0L);
- seq.push_back(temp.amount);
+ post_t& temp = temps.copy_post(post, xact);
+ temp.amount.in_place_negate();
- temp.xdata().compound_value = seq;
- temp.xdata().add_flags(POST_EXT_COMPOUND);
- }
+ if (flags & BUDGET_WRAP_VALUES) {
+ value_t seq;
+ seq.push_back(0L);
+ seq.push_back(temp.amount);
- ++pair.first;
- begin = *pair.first.start;
+ temp.xdata().compound_value = seq;
+ temp.xdata().add_flags(POST_EXT_COMPOUND);
+ }
- item_handler<post_t>::operator()(temp);
+ item_handler<post_t>::operator()(temp);
- reported = true;
+ reported = true;
}
}
+
+ foreach (pending_posts_list::iterator& i, posts_to_erase)
+ pending_posts.erase(i);
} while (reported);
}
@@ -1113,14 +1218,14 @@ void budget_posts::operator()(post_t& post)
foreach (pending_posts_list::value_type& pair, pending_posts) {
for (account_t * acct = post.reported_account();
- acct;
- acct = acct->parent) {
+ acct;
+ acct = acct->parent) {
if (acct == (*pair.second).reported_account()) {
- post_in_budget = true;
- // Report the post as if it had occurred in the parent account.
- if (post.reported_account() != acct)
- post.set_reported_account(acct);
- goto handle;
+ post_in_budget = true;
+ // Report the post as if it had occurred in the parent account.
+ if (post.reported_account() != acct)
+ post.set_reported_account(acct);
+ goto handle;
}
}
}
@@ -1135,20 +1240,26 @@ 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)
{
- generate_posts::add_post(period, post);
+ date_interval_t i(period);
+ if (! i.start && ! i.find_period(CURRENT_DATE()))
+ return;
- // Advance the period's interval until it is at or beyond the current date.
- date_interval_t& i = pending_posts.back().first;
- if (! i.start) {
- if (! i.find_period(CURRENT_DATE()))
- throw_(std::runtime_error, _("Something odd has happened"));
+ generate_posts::add_post(i, post);
+
+ // Advance the period's interval until it is at or beyond the current
+ // date.
+ while (*i.start < CURRENT_DATE())
++i;
- } else {
- while (*i.start < CURRENT_DATE())
- ++i;
- }
}
void forecast_posts::flush()
@@ -1188,50 +1299,48 @@ void forecast_posts::flush()
// period contains the earliest starting date.
pending_posts_list::iterator least = pending_posts.begin();
for (pending_posts_list::iterator i = ++pending_posts.begin();
- i != pending_posts.end();
- i++) {
+ i != pending_posts.end();
+ i++) {
+ assert((*i).first.start);
+ assert((*least).first.start);
if (*(*i).first.start < *(*least).first.start)
- least = i;
+ 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) {
+ static_cast<std::size_t>(365U) * forecast_years) {
DEBUG("filters.forecast",
- "Forecast transaction exceeds " << forecast_years
- << " years beyond today");
+ "Forecast transaction exceeds " << forecast_years
+ << " years beyond today");
pending_posts.erase(least);
continue;
}
- begin = next;
- ++(*least).first;
-
// `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.payee = _("Forecast transaction");
+ xact._date = next;
post_t& temp = temps.copy_post(post, xact);
// Submit the generated posting
DEBUG("filters.forecast",
- "Forecast transaction: " << temp.date()
- << " " << temp.account->fullname()
- << " " << temp.amount);
+ "Forecast transaction: " << temp.date()
+ << " " << temp.account->fullname()
+ << " " << temp.amount);
item_handler<post_t>::operator()(temp);
// If the generated posting matches the user's report query, check whether
@@ -1241,20 +1350,82 @@ void forecast_posts::flush()
DEBUG("filters.forecast", " matches report query");
bind_scope_t bound_scope(context, temp);
if (! pred(bound_scope)) {
- DEBUG("filters.forecast", " fails to match continuation criteria");
- pending_posts.erase(least);
- continue;
+ DEBUG("filters.forecast", " fails to match continuation criteria");
+ pending_posts.erase(least);
+ continue;
}
}
+
+ // Increment the 'least', but remove it from pending_posts if it
+ // exceeds its own boundaries.
+ ++(*least).first;
+ if (! (*least).first.start) {
+ pending_posts.erase(least);
+ continue;
+ }
}
item_handler<post_t>::flush();
}
-pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
- accounts_iterator& iter,
- const optional<predicate_t>& _pred,
- const optional<scope_t&>& _context)
+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,
+ const optional<scope_t&>& _context)
: item_handler<account_t>(handler), pred(_pred), context(_context)
{
TRACE_CTOR(pass_down_accounts, "acct_handler_ptr, accounts_iterator, ...");
@@ -1265,7 +1436,7 @@ pass_down_accounts::pass_down_accounts(acct_handler_ptr handler,
} else {
bind_scope_t bound_scope(*context, *account);
if ((*pred)(bound_scope))
- item_handler<account_t>::operator()(*account);
+ item_handler<account_t>::operator()(*account);
}
}
diff --git a/src/filters.h b/src/filters.h
index 22b27c5d..08dd18d5 100644
--- a/src/filters.h
+++ b/src/filters.h
@@ -62,21 +62,21 @@ public:
typedef function<void (const value_t&)> custom_flusher_t;
protected:
- value_to_posts_map posts_map;
- post_handler_ptr post_chain;
- report_t& report;
- expr_t group_by_expr;
- custom_flusher_t preflush_func;
+ value_to_posts_map posts_map;
+ post_handler_ptr post_chain;
+ report_t& report;
+ expr_t group_by_expr;
+ custom_flusher_t preflush_func;
optional<custom_flusher_t> postflush_func;
public:
post_splitter(post_handler_ptr _post_chain,
- report_t& _report,
- expr_t _group_by_expr)
+ report_t& _report,
+ expr_t _group_by_expr)
: post_chain(_post_chain), report(_report),
- group_by_expr(_group_by_expr),
- preflush_func(bind(&post_splitter::print_title, this, _1)) {
+ group_by_expr(_group_by_expr) {
TRACE_CTOR(post_splitter, "scope_t&, post_handler_ptr, expr_t");
+ preflush_func = bind(&post_splitter::print_title, this, _1);
}
virtual ~post_splitter() {
TRACE_DTOR(post_splitter);
@@ -192,7 +192,7 @@ class truncate_xacts : public item_handler<post_t>
public:
truncate_xacts(post_handler_ptr handler,
- int _head_count, int _tail_count)
+ int _head_count, int _tail_count)
: item_handler<post_t>(handler),
head_count(_head_count), tail_count(_tail_count),
completed(false), xacts_seen(0), last_xact(NULL) {
@@ -267,12 +267,12 @@ public:
sort_xacts(post_handler_ptr handler, const expr_t& _sort_order)
: sorter(handler, _sort_order) {
TRACE_CTOR(sort_xacts,
- "post_handler_ptr, const value_expr&");
+ "post_handler_ptr, const value_expr&");
}
sort_xacts(post_handler_ptr handler, const string& _sort_order)
: sorter(handler, _sort_order) {
TRACE_CTOR(sort_xacts,
- "post_handler_ptr, const string&");
+ "post_handler_ptr, const string&");
}
virtual ~sort_xacts() {
TRACE_DTOR(sort_xacts);
@@ -308,9 +308,9 @@ class filter_posts : public item_handler<post_t>
filter_posts();
public:
- filter_posts(post_handler_ptr handler,
- const predicate_t& predicate,
- scope_t& _context)
+ filter_posts(post_handler_ptr handler,
+ const predicate_t& predicate,
+ scope_t& _context)
: item_handler<post_t>(handler), pred(predicate), context(_context) {
TRACE_CTOR(filter_posts, "post_handler_ptr, predicate_t, scope_t&");
}
@@ -334,20 +334,33 @@ public:
class anonymize_posts : public item_handler<post_t>
{
- temporaries_t temps;
- xact_t * last_xact;
+ typedef std::map<commodity_t *, std::size_t> commodity_index_map;
+ typedef variate_generator<mt19937&, uniform_int<> > int_generator_t;
+
+ temporaries_t temps;
+ commodity_index_map comms;
+ std::size_t next_comm_id;
+ xact_t * last_xact;
+ mt19937 rnd_gen;
+ uniform_int<> integer_range;
+ int_generator_t integer_gen;
anonymize_posts();
public:
anonymize_posts(post_handler_ptr handler)
- : item_handler<post_t>(handler), last_xact(NULL) {
+ : item_handler<post_t>(handler), next_comm_id(0), last_xact(NULL),
+ rnd_gen(static_cast<unsigned int>(static_cast<uintmax_t>(std::time(0)))),
+ integer_range(1, 2000000000L),
+ integer_gen(rnd_gen, integer_range) {
TRACE_CTOR(anonymize_posts, "post_handler_ptr");
}
virtual ~anonymize_posts() {
TRACE_DTOR(anonymize_posts);
}
+ void render_commodity(amount_t& amt);
+
virtual void operator()(post_t& post);
virtual void clear() {
@@ -368,8 +381,8 @@ class calc_posts : public item_handler<post_t>
public:
calc_posts(post_handler_ptr handler,
- expr_t& _amount_expr,
- bool _calc_running_total = false)
+ expr_t& _amount_expr,
+ bool _calc_running_total = false)
: item_handler<post_t>(handler), last_post(NULL),
amount_expr(_amount_expr), calc_running_total(_calc_running_total) {
TRACE_CTOR(calc_posts, "post_handler_ptr, expr_t&, bool");
@@ -390,16 +403,16 @@ public:
class collapse_posts : public item_handler<post_t>
{
- expr_t& amount_expr;
- predicate_t display_predicate;
- predicate_t only_predicate;
- value_t subtotal;
- std::size_t count;
- xact_t * last_xact;
- post_t * last_post;
+ expr_t& amount_expr;
+ predicate_t display_predicate;
+ predicate_t only_predicate;
+ value_t subtotal;
+ std::size_t count;
+ xact_t * last_xact;
+ post_t * last_post;
temporaries_t temps;
- account_t& totals_account;
- bool only_collapse_if_zero;
+ account_t& totals_account;
+ bool only_collapse_if_zero;
std::list<post_t *> component_posts;
report_t& report;
@@ -407,11 +420,11 @@ class collapse_posts : public item_handler<post_t>
public:
collapse_posts(post_handler_ptr handler,
- report_t& _report,
- expr_t& _amount_expr,
- predicate_t _display_predicate,
- predicate_t _only_predicate,
- bool _only_collapse_if_zero = false)
+ report_t& _report,
+ expr_t& _amount_expr,
+ predicate_t _display_predicate,
+ predicate_t _only_predicate,
+ bool _only_collapse_if_zero = false)
: item_handler<post_t>(handler), amount_expr(_amount_expr),
display_predicate(_display_predicate),
only_predicate(_only_predicate), count(0),
@@ -453,17 +466,17 @@ public:
class related_posts : public item_handler<post_t>
{
posts_list posts;
- bool also_matching;
+ bool also_matching;
related_posts();
public:
related_posts(post_handler_ptr handler,
- const bool _also_matching = false)
+ const bool _also_matching = false)
: item_handler<post_t>(handler),
also_matching(_also_matching) {
TRACE_CTOR(related_posts,
- "post_handler_ptr, const bool");
+ "post_handler_ptr, const bool");
}
virtual ~related_posts() throw() {
TRACE_DTOR(related_posts);
@@ -481,29 +494,33 @@ public:
}
};
-class rounding_error_posts : public item_handler<post_t>
+class display_filter_posts : public item_handler<post_t>
{
// This filter requires that calc_posts be used at some point
// later in the chain.
- expr_t display_amount_expr;
- expr_t display_total_expr;
+ expr_t display_amount_expr;
+ expr_t display_total_expr;
report_t& report;
- value_t last_display_total;
- temporaries_t temps;
- account_t& rounding_account;
+ bool show_rounding;
+ value_t last_display_total;
+ temporaries_t temps;
+ account_t& rounding_account;
- rounding_error_posts();
+ display_filter_posts();
public:
- rounding_error_posts(post_handler_ptr handler,
- report_t& _report);
+ account_t& revalued_account;
- virtual ~rounding_error_posts() {
- TRACE_DTOR(rounding_error_posts);
+ display_filter_posts(post_handler_ptr handler,
+ report_t& _report,
+ bool _show_rounding);
+
+ virtual ~display_filter_posts() {
+ TRACE_DTOR(display_filter_posts);
}
- void output_rounding(post_t& post);
+ bool output_rounding(post_t& post);
virtual void operator()(post_t& post);
@@ -524,30 +541,30 @@ class changed_value_posts : public item_handler<post_t>
// This filter requires that calc_posts be used at some point
// later in the chain.
- expr_t total_expr;
- expr_t display_total_expr;
- report_t& report;
- bool changed_values_only;
- bool for_accounts_report;
- bool show_unrealized;
- post_t * last_post;
- value_t last_total;
+ expr_t total_expr;
+ expr_t display_total_expr;
+ report_t& report;
+ bool changed_values_only;
+ bool for_accounts_report;
+ bool show_unrealized;
+ post_t * last_post;
+ value_t last_total;
value_t repriced_total;
- temporaries_t temps;
- account_t& revalued_account;
- account_t * gains_equity_account;
- account_t * losses_equity_account;
+ temporaries_t temps;
+ account_t& revalued_account;
+ account_t * gains_equity_account;
+ account_t * losses_equity_account;
- rounding_error_posts * rounding_handler;
+ display_filter_posts * display_filter;
changed_value_posts();
public:
- changed_value_posts(post_handler_ptr handler,
- report_t& _report,
- bool _for_accounts_report,
- bool _show_unrealized,
- rounding_error_posts * _rounding_handler);
+ changed_value_posts(post_handler_ptr handler,
+ report_t& _report,
+ bool _for_accounts_report,
+ bool _show_unrealized,
+ display_filter_posts * _display_filter);
virtual ~changed_value_posts() {
TRACE_DTOR(changed_value_posts);
@@ -583,8 +600,8 @@ protected:
acct_value_t();
public:
- account_t * account;
- value_t value;
+ account_t * account;
+ value_t value;
acct_value_t(account_t * a) : account(a) {
TRACE_CTOR(acct_value_t, "account_t *");
@@ -605,26 +622,26 @@ protected:
typedef std::pair<string, acct_value_t> values_pair;
protected:
- expr_t& amount_expr;
- values_map values;
+ expr_t& amount_expr;
+ values_map values;
optional<string> date_format;
temporaries_t temps;
std::list<post_t *> component_posts;
public:
subtotal_posts(post_handler_ptr handler, expr_t& _amount_expr,
- const optional<string>& _date_format = none)
+ const optional<string>& _date_format = none)
: item_handler<post_t>(handler), amount_expr(_amount_expr),
date_format(_date_format) {
TRACE_CTOR(subtotal_posts,
- "post_handler_ptr, expr_t&, const optional<string>&");
+ "post_handler_ptr, expr_t&, const optional<string>&");
}
virtual ~subtotal_posts() {
TRACE_DTOR(subtotal_posts);
}
void report_subtotal(const char * spec_fmt = NULL,
- const optional<date_interval_t>& interval = none);
+ const optional<date_interval_t>& interval = none);
virtual void flush() {
if (values.size() > 0)
@@ -648,27 +665,27 @@ class interval_posts : public subtotal_posts
date_interval_t start_interval;
date_interval_t interval;
date_interval_t last_interval;
- post_t * last_post;
- account_t& empty_account;
- bool exact_periods;
- bool generate_empty_posts;
+ post_t * last_post;
+ account_t& empty_account;
+ bool exact_periods;
+ bool generate_empty_posts;
interval_posts();
public:
- interval_posts(post_handler_ptr _handler,
- expr_t& amount_expr,
- const date_interval_t& _interval,
- bool _exact_periods = false,
- bool _generate_empty_posts = false)
+ interval_posts(post_handler_ptr _handler,
+ expr_t& amount_expr,
+ const date_interval_t& _interval,
+ bool _exact_periods = false,
+ bool _generate_empty_posts = false)
: subtotal_posts(_handler, amount_expr), start_interval(_interval),
interval(start_interval), last_post(NULL),
empty_account(temps.create_account(_("<None>"))),
exact_periods(_exact_periods),
generate_empty_posts(_generate_empty_posts) {
TRACE_CTOR(interval_posts,
- "post_handler_ptr, expr_t&, date_interval_t, bool, bool");
+ "post_handler_ptr, expr_t&, date_interval_t, bool, bool");
}
virtual ~interval_posts() throw() {
TRACE_DTOR(interval_posts);
@@ -679,7 +696,7 @@ public:
virtual void flush() {
if (last_post && interval.duration) {
if (interval.is_valid())
- report_subtotal(interval);
+ report_subtotal(interval);
subtotal_posts::flush();
}
}
@@ -731,7 +748,7 @@ class by_payee_posts : public item_handler<post_t>
typedef std::map<string, shared_ptr<subtotal_posts> > payee_subtotals_map;
typedef std::pair<string, shared_ptr<subtotal_posts> > payee_subtotals_pair;
- expr_t& amount_expr;
+ expr_t& amount_expr;
payee_subtotals_map payee_subtotals;
by_payee_posts();
@@ -758,9 +775,9 @@ class by_payee_posts : public item_handler<post_t>
class transfer_details : public item_handler<post_t>
{
- account_t * master;
- expr_t expr;
- scope_t& scope;
+ account_t * master;
+ expr_t expr;
+ scope_t& scope;
temporaries_t temps;
transfer_details();
@@ -773,14 +790,14 @@ public:
} which_element;
transfer_details(post_handler_ptr handler,
- element_t _which_element,
- account_t * _master,
- const expr_t& _expr,
- scope_t& _scope)
+ element_t _which_element,
+ account_t * _master,
+ const expr_t& _expr,
+ scope_t& _scope)
: item_handler<post_t>(handler), master(_master),
expr(_expr), scope(_scope), which_element(_which_element) {
TRACE_CTOR(transfer_details,
- "post_handler_ptr, element_t, account_t *, expr_t, scope_t&");
+ "post_handler_ptr, element_t, account_t *, expr_t, scope_t&");
}
virtual ~transfer_details() {
TRACE_DTOR(transfer_details);
@@ -796,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();
@@ -830,7 +847,7 @@ class generate_posts : public item_handler<post_t>
protected:
typedef std::pair<date_interval_t, post_t *> pending_posts_pair;
- typedef std::list<pending_posts_pair> pending_posts_list;
+ typedef std::list<pending_posts_pair> pending_posts_list;
pending_posts_list pending_posts;
temporaries_t temps;
@@ -860,19 +877,21 @@ public:
class budget_posts : public generate_posts
{
#define BUDGET_NO_BUDGET 0x00
-#define BUDGET_BUDGETED 0x01
+#define BUDGET_BUDGETED 0x01
#define BUDGET_UNBUDGETED 0x02
#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);
@@ -880,24 +899,25 @@ public:
void report_budget_items(const date_t& date);
+ virtual void flush();
virtual void operator()(post_t& post);
};
class forecast_posts : public generate_posts
{
- predicate_t pred;
- scope_t& context;
+ predicate_t pred;
+ scope_t& context;
const std::size_t forecast_years;
public:
forecast_posts(post_handler_ptr handler,
- const predicate_t& predicate,
- scope_t& _context,
- const std::size_t _forecast_years)
+ const predicate_t& predicate,
+ scope_t& _context,
+ const std::size_t _forecast_years)
: generate_posts(handler), pred(predicate), context(_context),
forecast_years(_forecast_years) {
TRACE_CTOR(forecast_posts,
- "post_handler_ptr, predicate_t, scope_t&, std::size_t");
+ "post_handler_ptr, predicate_t, scope_t&, std::size_t");
}
virtual ~forecast_posts() throw() {
TRACE_DTOR(forecast_posts);
@@ -912,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
@@ -927,10 +967,10 @@ class pass_down_accounts : public item_handler<account_t>
optional<scope_t&> context;
public:
- pass_down_accounts(acct_handler_ptr handler,
- accounts_iterator& iter,
- const optional<predicate_t>& _pred = none,
- const optional<scope_t&>& _context = none);
+ pass_down_accounts(acct_handler_ptr handler,
+ accounts_iterator& iter,
+ const optional<predicate_t>& _pred = none,
+ const optional<scope_t&>& _context = none);
virtual ~pass_down_accounts() {
TRACE_DTOR(pass_down_accounts);
diff --git a/src/flags.h b/src/flags.h
index 03f47ff9..09b7eec4 100644
--- a/src/flags.h
+++ b/src/flags.h
@@ -112,11 +112,11 @@ public:
}
basic_flags_t(const T& bits) {
TRACE_CTOR(basic_flags_t, "const T&");
- set_flags(bits);
+ supports_flags<T, U>::set_flags(bits);
}
basic_flags_t(const U& bits) {
TRACE_CTOR(basic_flags_t, "const U&");
- set_flags(static_cast<T>(bits));
+ supports_flags<T, U>::set_flags(static_cast<T>(bits));
}
~basic_flags_t() throw() {
TRACE_DTOR(basic_flags_t);
diff --git a/src/format.cc b/src/format.cc
index c546926e..93ce4ed4 100644
--- a/src/format.cc
+++ b/src/format.cc
@@ -37,8 +37,8 @@
namespace ledger {
-format_t::elision_style_t format_t::default_style = TRUNCATE_TRAILING;
-bool format_t::default_style_changed = false;
+format_t::elision_style_t format_t::default_style = TRUNCATE_TRAILING;
+bool format_t::default_style_changed = false;
void format_t::element_t::dump(std::ostream& out) const
{
@@ -88,14 +88,14 @@ namespace {
// Don't gobble up any whitespace
const char * base = p;
while (p >= base && std::isspace(*p))
- p--;
+ p--;
}
return expr;
}
}
format_t::element_t * format_t::parse_elements(const string& fmt,
- const optional<format_t&>& tmpl)
+ const optional<format_t&>& tmpl)
{
std::auto_ptr<element_t> result;
@@ -147,8 +147,8 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
while (*p == '-') {
switch (*p) {
case '-':
- current->add_flags(ELEMENT_ALIGN_LEFT);
- break;
+ current->add_flags(ELEMENT_ALIGN_LEFT);
+ break;
}
++p;
}
@@ -164,12 +164,12 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
++p;
num = 0;
while (*p && std::isdigit(*p)) {
- num *= 10;
- num += *p++ - '0';
+ num *= 10;
+ num += *p++ - '0';
}
current->max_width = num;
if (current->min_width == 0)
- current->min_width = current->max_width;
+ current->min_width = current->max_width;
}
switch (*p) {
@@ -180,25 +180,25 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
case '$': {
if (! tmpl)
- throw_(format_error, _("Prior field reference, but no template"));
+ throw_(format_error, _("Prior field reference, but no template"));
p++;
if (*p == '0' || (! std::isdigit(*p) &&
- *p != 'A' && *p != 'B' && *p != 'C' &&
- *p != 'D' && *p != 'E' && *p != 'F'))
- throw_(format_error, _("%$ field reference must be a digit from 1-9"));
+ *p != 'A' && *p != 'B' && *p != 'C' &&
+ *p != 'D' && *p != 'E' && *p != 'F'))
+ throw_(format_error, _("%$ field reference must be a digit from 1-9"));
unsigned int index = std::isdigit(*p) ? *p - '0' : (*p - 'A' + 10);
element_t * tmpl_elem = tmpl->elements.get();
for (unsigned int i = 1; i < index && tmpl_elem; i++) {
- tmpl_elem = tmpl_elem->next.get();
- while (tmpl_elem && tmpl_elem->type != element_t::EXPR)
- tmpl_elem = tmpl_elem->next.get();
+ tmpl_elem = tmpl_elem->next.get();
+ while (tmpl_elem && tmpl_elem->type != element_t::EXPR)
+ tmpl_elem = tmpl_elem->next.get();
}
if (! tmpl_elem)
- throw_(format_error, _("%$ reference to a non-existent prior field"));
+ throw_(format_error, _("%$ reference to a non-existent prior field"));
*current = *tmpl_elem;
break;
@@ -214,87 +214,87 @@ format_t::element_t * format_t::parse_elements(const string& fmt,
// Wrap the subexpression in calls to justify and scrub
if (format_amount) {
- if (! *p || *(p + 1) != '}')
- throw_(format_error, _("Expected closing brace"));
- else
- p++;
+ if (! *p || *(p + 1) != '}')
+ throw_(format_error, _("Expected closing brace"));
+ else
+ p++;
- expr_t::ptr_op_t op = boost::get<expr_t>(current->data).get_op();
+ expr_t::ptr_op_t op = boost::get<expr_t>(current->data).get_op();
- expr_t::ptr_op_t amount_op;
- expr_t::ptr_op_t colorize_op;
- if (op->kind == expr_t::op_t::O_CONS) {
- amount_op = op->left();
- colorize_op = op->right();
- } else {
- amount_op = op;
- }
+ expr_t::ptr_op_t amount_op;
+ expr_t::ptr_op_t colorize_op;
+ if (op->kind == expr_t::op_t::O_CONS) {
+ amount_op = op->left();
+ colorize_op = op->right();
+ } else {
+ amount_op = op;
+ }
- expr_t::ptr_op_t scrub_node(new expr_t::op_t(expr_t::op_t::IDENT));
- scrub_node->set_ident("scrub");
+ expr_t::ptr_op_t scrub_node(new expr_t::op_t(expr_t::op_t::IDENT));
+ scrub_node->set_ident("scrub");
- expr_t::ptr_op_t call1_node(new expr_t::op_t(expr_t::op_t::O_CALL));
- call1_node->set_left(scrub_node);
- call1_node->set_right(amount_op);
+ expr_t::ptr_op_t call1_node(new expr_t::op_t(expr_t::op_t::O_CALL));
+ call1_node->set_left(scrub_node);
+ call1_node->set_right(amount_op);
- expr_t::ptr_op_t arg1_node(new expr_t::op_t(expr_t::op_t::VALUE));
- expr_t::ptr_op_t arg2_node(new expr_t::op_t(expr_t::op_t::VALUE));
- expr_t::ptr_op_t arg3_node(new expr_t::op_t(expr_t::op_t::VALUE));
+ expr_t::ptr_op_t arg1_node(new expr_t::op_t(expr_t::op_t::VALUE));
+ expr_t::ptr_op_t arg2_node(new expr_t::op_t(expr_t::op_t::VALUE));
+ expr_t::ptr_op_t arg3_node(new expr_t::op_t(expr_t::op_t::VALUE));
- arg1_node->set_value(current->min_width > 0 ?
- long(current->min_width) : -1);
- arg2_node->set_value(current->max_width > 0 ?
- long(current->max_width) : -1);
- arg3_node->set_value(! current->has_flags(ELEMENT_ALIGN_LEFT));
+ arg1_node->set_value(current->min_width > 0 ?
+ long(current->min_width) : -1);
+ arg2_node->set_value(current->max_width > 0 ?
+ long(current->max_width) : -1);
+ arg3_node->set_value(! current->has_flags(ELEMENT_ALIGN_LEFT));
- current->min_width = 0;
- current->max_width = 0;
+ current->min_width = 0;
+ current->max_width = 0;
- expr_t::ptr_op_t args1_node(new expr_t::op_t(expr_t::op_t::O_CONS));
- args1_node->set_left(arg2_node);
- args1_node->set_right(arg3_node);
+ expr_t::ptr_op_t args1_node(new expr_t::op_t(expr_t::op_t::O_CONS));
+ args1_node->set_left(arg2_node);
+ args1_node->set_right(arg3_node);
- expr_t::ptr_op_t args2_node(new expr_t::op_t(expr_t::op_t::O_CONS));
- args2_node->set_left(arg1_node);
- args2_node->set_right(args1_node);
+ expr_t::ptr_op_t args2_node(new expr_t::op_t(expr_t::op_t::O_CONS));
+ args2_node->set_left(arg1_node);
+ args2_node->set_right(args1_node);
- expr_t::ptr_op_t args3_node(new expr_t::op_t(expr_t::op_t::O_CONS));
- args3_node->set_left(call1_node);
- args3_node->set_right(args2_node);
+ expr_t::ptr_op_t args3_node(new expr_t::op_t(expr_t::op_t::O_CONS));
+ args3_node->set_left(call1_node);
+ args3_node->set_right(args2_node);
- expr_t::ptr_op_t seq1_node(new expr_t::op_t(expr_t::op_t::O_SEQ));
- seq1_node->set_left(args3_node);
+ expr_t::ptr_op_t seq1_node(new expr_t::op_t(expr_t::op_t::O_SEQ));
+ seq1_node->set_left(args3_node);
- expr_t::ptr_op_t justify_node(new expr_t::op_t(expr_t::op_t::IDENT));
- justify_node->set_ident("justify");
+ expr_t::ptr_op_t justify_node(new expr_t::op_t(expr_t::op_t::IDENT));
+ justify_node->set_ident("justify");
- expr_t::ptr_op_t call2_node(new expr_t::op_t(expr_t::op_t::O_CALL));
- call2_node->set_left(justify_node);
- call2_node->set_right(seq1_node);
+ expr_t::ptr_op_t call2_node(new expr_t::op_t(expr_t::op_t::O_CALL));
+ call2_node->set_left(justify_node);
+ call2_node->set_right(seq1_node);
- string prev_expr = boost::get<expr_t>(current->data).text();
+ string prev_expr = boost::get<expr_t>(current->data).text();
- if (colorize_op) {
- expr_t::ptr_op_t ansify_if_node(new expr_t::op_t(expr_t::op_t::IDENT));
- ansify_if_node->set_ident("ansify_if");
+ if (colorize_op) {
+ expr_t::ptr_op_t ansify_if_node(new expr_t::op_t(expr_t::op_t::IDENT));
+ ansify_if_node->set_ident("ansify_if");
- expr_t::ptr_op_t args4_node(new expr_t::op_t(expr_t::op_t::O_CONS));
- args4_node->set_left(call2_node);
- args4_node->set_right(colorize_op);
+ expr_t::ptr_op_t args4_node(new expr_t::op_t(expr_t::op_t::O_CONS));
+ args4_node->set_left(call2_node);
+ args4_node->set_right(colorize_op);
- expr_t::ptr_op_t seq2_node(new expr_t::op_t(expr_t::op_t::O_SEQ));
- seq2_node->set_left(args4_node);
+ expr_t::ptr_op_t seq2_node(new expr_t::op_t(expr_t::op_t::O_SEQ));
+ seq2_node->set_left(args4_node);
- expr_t::ptr_op_t call3_node(new expr_t::op_t(expr_t::op_t::O_CALL));
- call3_node->set_left(ansify_if_node);
- call3_node->set_right(seq2_node);
+ expr_t::ptr_op_t call3_node(new expr_t::op_t(expr_t::op_t::O_CALL));
+ call3_node->set_left(ansify_if_node);
+ call3_node->set_right(seq2_node);
- current->data = expr_t(call3_node);
- } else {
- current->data = expr_t(call2_node);
- }
+ current->data = expr_t(call3_node);
+ } else {
+ current->data = expr_t(call2_node);
+ }
- boost::get<expr_t>(current->data).set_text(prev_expr);
+ boost::get<expr_t>(current->data).set_text(prev_expr);
}
break;
}
@@ -335,7 +335,7 @@ string format_t::real_calc(scope_t& scope)
switch (elem->type) {
case element_t::STRING:
if (elem->min_width > 0)
- out.width(elem->min_width);
+ out.width(elem->min_width);
out << boost::get<string>(elem->data);
break;
@@ -343,28 +343,33 @@ string format_t::real_calc(scope_t& scope)
expr_t& expr(boost::get<expr_t>(elem->data));
try {
- expr.compile(scope);
-
- value_t value;
- if (expr.is_function()) {
- call_scope_t args(scope);
- args.push_back(long(elem->max_width));
- value = expr.get_function()(args);
- } else {
- value = expr.calc(scope);
- }
- DEBUG("format.expr", "value = (" << value << ")");
-
- if (elem->min_width > 0)
- value.print(out, static_cast<int>(elem->min_width), -1,
- ! elem->has_flags(ELEMENT_ALIGN_LEFT));
- else
- out << value.to_string();
+ expr.compile(scope);
+
+ value_t value;
+ if (expr.is_function()) {
+ call_scope_t args(scope);
+ args.push_back(long(elem->max_width));
+ value = expr.get_function()(args);
+ } else {
+ value = expr.calc(scope);
+ }
+ DEBUG("format.expr", "value = (" << value << ")");
+
+ if (elem->min_width > 0)
+ value.print(out, static_cast<int>(elem->min_width), -1,
+ ! elem->has_flags(ELEMENT_ALIGN_LEFT));
+ else
+ out << value.to_string();
}
catch (const calc_error&) {
- add_error_context(_("While calculating format expression:"));
- add_error_context(expr.context_to_str());
- throw;
+ string current_context = error_context();
+
+ add_error_context(_("While calculating format expression:"));
+ add_error_context(expr.context_to_str());
+
+ if (! current_context.empty())
+ add_error_context(current_context);
+ throw;
}
break;
}
@@ -376,15 +381,15 @@ string format_t::real_calc(scope_t& scope)
if (elem->max_width > 0 || elem->min_width > 0) {
unistring temp(out.str());
- string result;
+ string result;
if (elem->max_width > 0 && elem->max_width < temp.length()) {
- result = truncate(temp, elem->max_width);
+ result = truncate(temp, elem->max_width);
} else {
- result = temp.extract();
- if (elem->min_width > temp.length())
- for (std::size_t i = 0; i < elem->min_width - temp.length(); i++)
- result += " ";
+ result = temp.extract();
+ if (elem->min_width > temp.length())
+ for (std::size_t i = 0; i < elem->min_width - temp.length(); i++)
+ result += " ";
}
out_str << result;
} else {
@@ -396,8 +401,8 @@ string format_t::real_calc(scope_t& scope)
}
string format_t::truncate(const unistring& ustr,
- const std::size_t width,
- const std::size_t account_abbrev_length)
+ const std::size_t width,
+ const std::size_t account_abbrev_length)
{
assert(width < 4095);
@@ -420,57 +425,180 @@ string format_t::truncate(const unistring& ustr,
case TRUNCATE_MIDDLE:
// This method truncates in the middle.
buf << ustr.extract(0, (width - 2) / 2)
- << ".."
- << ustr.extract(len - ((width - 2) / 2 + (width - 2) % 2),
- (width - 2) / 2 + (width - 2) % 2);
+ << ".."
+ << ustr.extract(len - ((width - 2) / 2 + (width - 2) % 2),
+ (width - 2) / 2 + (width - 2) % 2);
break;
case ABBREVIATE:
if (account_abbrev_length > 0) {
+ // The algorithm here is complex, but aims to preserve the most
+ // information in the most useful places.
+ //
+ // Consider: You have an account name like
+ // 'Assets:Banking:Check:Register'. This account name, which is
+ // 29 characters long, must be shortened to fit in 20. How would
+ // you shorten it?
+ //
+ // The approach taken below is to compute the difference, or 9
+ // characters, and then distribute this difference semi-evenly
+ // among first three segments of the account name, by taking
+ // characters until the difference is gone. Further, earlier
+ // segments will give up more of their share of letters than later
+ // segments, since the later segments usually contain more useful
+ // information.
+
+ // First, chop up the Unicode string into individual segments.
std::list<string> parts;
string::size_type beg = 0;
string strcopy(ustr.extract());
for (string::size_type pos = strcopy.find(':');
- pos != string::npos;
- beg = pos + 1, pos = strcopy.find(':', beg))
- parts.push_back(string(strcopy, beg, pos - beg));
+ pos != string::npos;
+ beg = pos + 1, pos = strcopy.find(':', beg))
+ parts.push_back(string(strcopy, beg, pos - beg));
parts.push_back(string(strcopy, beg));
- std::ostringstream result;
-
- std::size_t newlen = len;
+ DEBUG("format.abbrev", "Account name: " << strcopy);
+ DEBUG("format.abbrev",
+ "Must fit a " << len << " char string in " << width << " chars");
+
+ // Figure out the lengths of all the parts. The last part is
+ // always displayed in full, while the former parts are
+ // distributed, with the latter parts being longer than the
+ // former, but with none shorter than account_abbrev_length.
+ std::list<std::size_t> lens;
+#if defined(DEBUG_ON)
+ int index = 0;
+#endif
for (std::list<string>::iterator i = parts.begin();
- i != parts.end();
- i++) {
- // Don't contract the last element
- std::list<string>::iterator x = i;
- if (++x == parts.end()) {
- result << *i;
- break;
- }
-
- if (newlen > width) {
- unistring temp(*i);
- if (temp.length() > account_abbrev_length) {
- result << temp.extract(0, account_abbrev_length) << ":";
- newlen -= temp.length() - account_abbrev_length;
- } else {
- result << temp.extract() << ":";
- newlen -= temp.length();
- }
- } else {
- result << *i << ":";
- }
+ i != parts.end();
+ i++) {
+ std::size_t l = unistring(*i).length();
+ DEBUG("format.abbrev",
+ "Segment " << ++index << " is " << l << " chars wide");
+ lens.push_back(l);
+ }
+
+ // Determine the "overflow", or how many chars in excess we are.
+
+ std::size_t overflow = len - width;
+ DEBUG("format.abbrev",
+ "There are " << overflow << " chars of overflow");
+
+ // Walk through the first n-1 segments, and start subtracting
+ // letters to decrease the overflow. This is done in multiple
+ // passes until the overflow is gone, or we cannot reduce any
+ // further. The calculation to find the amount to remove is:
+ //
+ // overflow * (((len(segment) + counter) * iteration) /
+ // (len(string) - len(last_segment) - counter))
+ //
+ // Where:
+ // overflow - the amount that needs to be removed
+ // counter - starts at n-1 for the first segment, then
+ // decreases by one until it reaches 0 for the
+ // last segment (which is never shortened).
+ // This value is used to weight the shrinkage
+ // so that earlier segments shrink faster.
+ // iteration - starts at 1, increase by 1 for every
+ // iteration of the loop
+ //
+ // In the example above, we have this account name:
+ //
+ // Assets:Banking:Check:Register
+ //
+ // Therefore, the amount to be removed from Assets is calculated as:
+ //
+ // 9 * (((6 + 3) * 1) / (29 - 8 - 3)) = ceil(4.5) = 5
+ //
+ // However, since removing 5 chars would make the length of the
+ // segment shorter than the default minimum of 2, we can only
+ // remove 4 chars from Assets to reduce the overflow. And on it
+ // goes.
+ //
+ // The final result will be: As:Ban:Chec:Register
+
+ std::size_t iteration = 1;
+ std::size_t len_minus_last = len - lens.back();
+ while (overflow > 0) {
+ std::size_t overflow_at_start = overflow;
+ DEBUG("format.abbrev",
+ "Overflow starting at " << overflow << " chars");
+#if defined(DEBUG_ON)
+ index = 0;
+#endif
+ std::size_t counter = lens.size();
+ for (std::list<std::size_t>::iterator i = lens.begin();
+ i != lens.end();
+ i++) {
+ if (--counter == 0 || overflow == 0)
+ break;
+ DEBUG("format.abbrev", "Overflow is " << overflow << " chars");
+ std::size_t adjust;
+ if (overflow == 1)
+ adjust = 1;
+ else
+ adjust = std::size_t
+ (std::ceil(double(overflow) *
+ ((double(*i + counter*3) * double(iteration)) /
+ (double(len_minus_last) - double(counter)))));
+ DEBUG("format.abbrev", "Weight calc: (" << overflow
+ << " * (((" << *i << " + " << counter << ") * "
+ << iteration << ") / (" << len_minus_last
+ << " - " << counter << ")))");
+ if (adjust == 0)
+ adjust = 1;
+ else if (adjust > overflow)
+ adjust = overflow;
+ DEBUG("format.abbrev", "The weighted part is " << adjust << " chars");
+ std::size_t slack = *i - std::min(*i, account_abbrev_length);
+ if (adjust > slack)
+ adjust = slack;
+ if (adjust > 0) {
+ DEBUG("format.abbrev",
+ "Reducing segment " << ++index << " by " << adjust << " chars");
+ (*i) -= adjust;
+ DEBUG("format.abbrev",
+ "Segment " << index << " is now " << *i << " chars wide");
+ overflow -= adjust;
+ DEBUG("format.abbrev", "Overflow is now " << overflow << " chars");
+ }
+ }
+ DEBUG("format.abbrev",
+ "Overflow ending this time at " << overflow << " chars");
+ if (overflow == overflow_at_start)
+ break;
+ iteration++;
+ }
+
+ assert(parts.size() == lens.size());
+
+ std::list<string>::iterator i = parts.begin();
+ std::list<std::size_t>::iterator l = lens.begin();
+ std::ostringstream result;
+
+ for (; i != parts.end() && l != lens.end(); i++, l++) {
+ std::list<string>::iterator x = i;
+ if (++x == parts.end()) {
+ result << *i;
+ break;
+ }
+
+ unistring temp(*i);
+ if (temp.length() > *l)
+ result << temp.extract(0, *l) << ":";
+ else
+ result << *i << ":";
}
- if (newlen > width) {
- // Even abbreviated its too big to show the last account, so
- // abbreviate all but the last and truncate at the beginning.
- unistring temp(result.str());
- assert(temp.length() > width - 2);
- buf << ".." << temp.extract(temp.length() - (width - 2), width - 2);
+ if (overflow > 0) {
+ // Even abbreviated its too big to show the last account, so
+ // abbreviate all but the last and truncate at the beginning.
+ unistring temp(result.str());
+ assert(temp.length() > width - 2);
+ buf << ".." << temp.extract(temp.length() - (width - 2), width - 2);
} else {
- buf << result.str();
+ buf << result.str();
}
break;
}
diff --git a/src/format.h b/src/format.h
index 72d44ee5..256dd66a 100644
--- a/src/format.h
+++ b/src/format.h
@@ -61,10 +61,10 @@ class format_t : public expr_base_t<string>
enum kind_t { STRING, EXPR };
- kind_t type;
- std::size_t min_width;
- std::size_t max_width;
- variant<string, expr_t> data;
+ kind_t type;
+ std::size_t min_width;
+ std::size_t max_width;
+ variant<string, expr_t> data;
scoped_ptr<struct element_t> next;
element_t() throw()
@@ -80,11 +80,11 @@ class format_t : public expr_base_t<string>
element_t& operator=(const element_t& elem) {
if (this != &elem) {
- supports_flags<>::operator=(elem);
- type = elem.type;
- min_width = elem.min_width;
- max_width = elem.max_width;
- data = elem.data;
+ supports_flags<>::operator=(elem);
+ type = elem.type;
+ min_width = elem.min_width;
+ max_width = elem.max_width;
+ data = elem.data;
}
return *this;
}
@@ -95,12 +95,12 @@ class format_t : public expr_base_t<string>
out << "\033[31m";
if (elem->has_flags(ELEMENT_ALIGN_LEFT))
- out << std::left;
+ out << std::left;
else
- out << std::right;
+ out << std::right;
if (elem->min_width > 0)
- out.width(elem->min_width);
+ out.width(elem->min_width);
}
void dump(std::ostream& out) const;
@@ -120,7 +120,7 @@ public:
private:
static element_t * parse_elements(const string& fmt,
- const optional<format_t&>& tmpl);
+ const optional<format_t&>& tmpl);
public:
format_t() : base_type() {
@@ -137,23 +137,32 @@ public:
}
void parse_format(const string& _format,
- const optional<format_t&>& tmpl = none) {
+ const optional<format_t&>& tmpl = none) {
elements.reset(parse_elements(_format, tmpl));
set_text(_format);
}
+ virtual void mark_uncompiled() {
+ for (element_t * elem = elements.get(); elem; elem = elem->next.get()) {
+ if (elem->type == element_t::EXPR) {
+ expr_t& expr(boost::get<expr_t>(elem->data));
+ expr.mark_uncompiled();
+ }
+ }
+ }
+
virtual result_type real_calc(scope_t& scope);
virtual void dump(std::ostream& out) const {
for (const element_t * elem = elements.get();
- elem;
- elem = elem->next.get())
+ elem;
+ elem = elem->next.get())
elem->dump(out);
}
static string truncate(const unistring& str,
- const std::size_t width,
- const std::size_t account_abbrev_length = 0);
+ const std::size_t width,
+ const std::size_t account_abbrev_length = 0);
};
} // namespace ledger
diff --git a/src/generate.cc b/src/generate.cc
index 8ea1ab45..05f754e6 100644
--- a/src/generate.cc
+++ b/src/generate.cc
@@ -60,8 +60,8 @@ generate_posts_iterator::generate_posts_iterator
two_six_range(2, 6), two_six_gen(rnd_gen, two_six_range),
strlen_range(1, 40), strlen_gen(rnd_gen, strlen_range),
- neg_number_range(-1000000, -1), neg_number_gen(rnd_gen, neg_number_range),
- pos_number_range(1, 1000000), pos_number_gen(rnd_gen, pos_number_range)
+ neg_number_range(-10000, -1), neg_number_gen(rnd_gen, neg_number_range),
+ pos_number_range(1, 10000), pos_number_gen(rnd_gen, pos_number_range)
{
TRACE_CTOR(generate_posts_iterator, "bool");
@@ -76,10 +76,10 @@ generate_posts_iterator::generate_posts_iterator
}
void generate_posts_iterator::generate_string(std::ostream& out, int len,
- bool only_alpha)
+ bool only_alpha)
{
DEBUG("generate.post.string",
- "Generating string of length " << len << ", only alpha " << only_alpha);
+ "Generating string of length " << len << ", only alpha " << only_alpha);
int last = -1;
bool first = true;
@@ -87,38 +87,38 @@ void generate_posts_iterator::generate_string(std::ostream& out, int len,
int next = only_alpha ? 3 : three_gen();
bool output = true;
switch (next) {
- case 1: // colon
+ case 1: // colon
if (! first && last == 3 && strlen_gen() % 10 == 0 && i + 1 != len)
- out << ':';
+ out << ':';
else {
- i--;
- output = false;
+ i--;
+ output = false;
}
break;
- case 2: // space
+ case 2: // space
if (! first && last == 3 && strlen_gen() % 20 == 0 && i + 1 != len)
- out << ' ';
+ out << ' ';
else {
- i--;
- output = false;
+ i--;
+ output = false;
}
break;
- case 3: // character
+ case 3: // character
switch (three_gen()) {
- case 1: // uppercase
- out << char(upchar_gen());
- break;
- case 2: // lowercase
- out << char(downchar_gen());
- break;
- case 3: // number
- if (! only_alpha && ! first)
- out << char(numchar_gen());
- else {
- i--;
- output = false;
- }
- break;
+ case 1: // uppercase
+ out << char(upchar_gen());
+ break;
+ case 2: // lowercase
+ out << char(downchar_gen());
+ break;
+ case 3: // number
+ if (! only_alpha && ! first)
+ out << char(numchar_gen());
+ else {
+ i--;
+ output = false;
+ }
+ break;
}
break;
}
@@ -130,7 +130,7 @@ void generate_posts_iterator::generate_string(std::ostream& out, int len,
}
bool generate_posts_iterator::generate_account(std::ostream& out,
- bool no_virtual)
+ bool no_virtual)
{
bool must_balance = true;
bool is_virtual = false;
@@ -164,7 +164,7 @@ bool generate_posts_iterator::generate_account(std::ostream& out,
}
void generate_posts_iterator::generate_commodity(std::ostream& out,
- const string& exclude)
+ const string& exclude)
{
string comm;
do {
@@ -173,21 +173,21 @@ void generate_posts_iterator::generate_commodity(std::ostream& out,
comm = buf.str();
}
while (comm == exclude || comm == "h" || comm == "m" || comm == "s" ||
- comm == "and" || comm == "any" || comm == "all" || comm == "div" ||
- comm == "false" || comm == "or" || comm == "not" ||
- comm == "true" || comm == "if" || comm == "else");
+ comm == "and" || comm == "any" || comm == "all" || comm == "div" ||
+ comm == "false" || comm == "or" || comm == "not" ||
+ comm == "true" || comm == "if" || comm == "else");
out << comm;
}
string generate_posts_iterator::generate_amount(std::ostream& out,
- value_t not_this_amount,
- bool no_negative,
- const string& exclude)
+ value_t not_this_amount,
+ bool no_negative,
+ const string& exclude)
{
std::ostringstream buf;
- if (truth_gen()) { // commodity goes in front
+ if (truth_gen()) { // commodity goes in front
generate_commodity(buf, exclude);
if (truth_gen())
buf << ' ';
@@ -262,7 +262,7 @@ void generate_posts_iterator::generate_cost(std::ostream& out, value_t amount)
buf << " @@ ";
if (! generate_amount(buf, amount, true,
- amount.as_amount().commodity().symbol()).empty())
+ amount.as_amount().commodity().symbol()).empty())
out << buf.str();
}
@@ -362,20 +362,20 @@ post_t * generate_posts_iterator::operator()()
std::istringstream in(buf.str());
try {
if (session.journal->parse(in, session) != 0) {
- VERIFY(session.journal->xacts.back()->valid());
- posts.reset(*session.journal->xacts.back());
- post = posts();
+ VERIFY(session.journal->xacts.back()->valid());
+ posts.reset(*session.journal->xacts.back());
+ post = posts();
}
}
- catch (std::exception& err) {
+ catch (std::exception&) {
add_error_context(_("While parsing generated transaction (seed %1):")
- << seed);
+ << seed);
add_error_context(buf.str());
throw;
}
- catch (int status) {
+ catch (int) {
add_error_context(_("While parsing generated transaction (seed %1):")
- << seed);
+ << seed);
add_error_context(buf.str());
throw;
}
diff --git a/src/generate.h b/src/generate.h
index f0f58064..25ad41ea 100644
--- a/src/generate.h
+++ b/src/generate.h
@@ -53,7 +53,7 @@ class generate_posts_iterator : public posts_iterator
session_t& session;
unsigned int seed;
std::size_t quantity;
- bool allow_invalid;
+ bool allow_invalid;
date_t next_date;
date_t next_eff_date;
@@ -97,9 +97,9 @@ class generate_posts_iterator : public posts_iterator
public:
generate_posts_iterator(session_t& _session,
- unsigned int _seed = 0,
- std::size_t _quantity = 100,
- bool _allow_invalid = false);
+ unsigned int _seed = 0,
+ std::size_t _quantity = 100,
+ bool _allow_invalid = false);
virtual ~generate_posts_iterator() throw() {
TRACE_DTOR(generate_posts_iterator);
@@ -108,21 +108,21 @@ public:
virtual post_t * operator()();
protected:
- void generate_string(std::ostream& out, int len, bool only_alpha = false);
- bool generate_account(std::ostream& out, bool no_virtual = false);
- void generate_commodity(std::ostream& out, const string& exclude = "");
+ void generate_string(std::ostream& out, int len, bool only_alpha = false);
+ bool generate_account(std::ostream& out, bool no_virtual = false);
+ void generate_commodity(std::ostream& out, const string& exclude = "");
string generate_amount(std::ostream& out,
- value_t not_this_amount = NULL_VALUE,
- bool no_negative = false,
- const string& exclude = "");
- bool generate_post(std::ostream& out, bool no_amount = false);
- void generate_cost(std::ostream& out, value_t amount);
- void generate_date(std::ostream& out);
- void generate_state(std::ostream& out);
- void generate_code(std::ostream& out);
- void generate_payee(std::ostream& out);
- void generate_note(std::ostream& out);
- void generate_xact(std::ostream& out);
+ value_t not_this_amount = NULL_VALUE,
+ bool no_negative = false,
+ const string& exclude = "");
+ bool generate_post(std::ostream& out, bool no_amount = false);
+ void generate_cost(std::ostream& out, value_t amount);
+ void generate_date(std::ostream& out);
+ void generate_state(std::ostream& out);
+ void generate_code(std::ostream& out);
+ void generate_payee(std::ostream& out);
+ void generate_note(std::ostream& out);
+ void generate_xact(std::ostream& out);
};
} // namespace ledger
diff --git a/src/global.cc b/src/global.cc
index 35651ddb..c0698376 100644
--- a/src/global.cc
+++ b/src/global.cc
@@ -49,6 +49,8 @@ global_scope_t::global_scope_t(char ** envp)
{
TRACE_CTOR(global_scope_t, "");
+ epoch = CURRENT_TIME();
+
#if defined(HAVE_BOOST_PYTHON)
if (! python_session.get()) {
python_session.reset(new ledger::python_interpreter_t);
@@ -113,10 +115,10 @@ void global_scope_t::read_init()
ifstream init(init_file);
if (session().journal->read(init_file, NULL, &report()) > 0 ||
- session().journal->auto_xacts.size() > 0 ||
- session().journal->period_xacts.size() > 0) {
- throw_(parse_error, _("Transactions found in initialization file '%1'")
- << init_file);
+ session().journal->auto_xacts.size() > 0 ||
+ session().journal->period_xacts.size() > 0) {
+ throw_(parse_error, _("Transactions found in initialization file '%1'")
+ << init_file);
}
TRACE_FINISH(init, 1);
@@ -137,7 +139,7 @@ char * global_scope_t::prompt_string()
void global_scope_t::report_error(const std::exception& err)
{
- std::cout.flush(); // first display anything that was pending
+ std::cout.flush(); // first display anything that was pending
if (caught_signal == NONE_CAUGHT) {
// Display any pending error context information
@@ -163,7 +165,7 @@ void global_scope_t::execute_command(strings_list args, bool at_repl)
}
strings_list::iterator arg = args.begin();
- string verb = *arg++;
+ string verb = *arg++;
// Look for a precommand first, which is defined as any defined function
// whose name starts with "ledger_precmd_". The difference between a
@@ -180,8 +182,8 @@ void global_scope_t::execute_command(strings_list args, bool at_repl)
// then invoke the command.
expr_t::func_t command;
- bool is_precommand = false;
- bind_scope_t bound_scope(*this, report());
+ bool is_precommand = false;
+ bind_scope_t bound_scope(*this, report());
if (bool(command = look_for_precommand(bound_scope, verb)))
is_precommand = true;
@@ -206,11 +208,11 @@ void global_scope_t::execute_command(strings_list args, bool at_repl)
report().output_stream
.initialize(report().HANDLED(output_) ?
- optional<path>(path(report().HANDLER(output_).str())) :
- optional<path>(),
- report().HANDLED(pager_) ?
- optional<path>(path(report().HANDLER(pager_).str())) :
- optional<path>());
+ optional<path>(path(report().HANDLER(output_).str())) :
+ optional<path>(),
+ report().HANDLED(pager_) ?
+ optional<path>(path(report().HANDLER(pager_).str())) :
+ optional<path>());
// Now that the output stream is initialized, report the options that will
// participate in this report, if the user specified --options
@@ -316,7 +318,7 @@ option_t<global_scope_t> * global_scope_t::lookup_option(const char * p)
}
expr_t::ptr_op_t global_scope_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
switch (kind) {
case symbol_t::FUNCTION:
@@ -334,9 +336,9 @@ expr_t::ptr_op_t global_scope_t::lookup(const symbol_t::kind_t kind,
switch (*p) {
case 'p':
if (is_eq(p, "push"))
- return MAKE_FUNCTOR(global_scope_t::push_command);
+ return MAKE_FUNCTOR(global_scope_t::push_command);
else if (is_eq(p, "pop"))
- return MAKE_FUNCTOR(global_scope_t::pop_command);
+ return MAKE_FUNCTOR(global_scope_t::pop_command);
break;
}
}
@@ -400,8 +402,8 @@ void global_scope_t::normalize_session_options()
#endif // defined(LOGGING_ON)
}
-expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope,
- const string& verb)
+expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope,
+ const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(symbol_t::PRECOMMAND, verb))
return def->as_function();
@@ -410,7 +412,7 @@ expr_t::func_t global_scope_t::look_for_precommand(scope_t& scope,
}
expr_t::func_t global_scope_t::look_for_command(scope_t& scope,
- const string& verb)
+ const string& verb)
{
if (expr_t::ptr_op_t def = scope.lookup(symbol_t::COMMAND, verb))
return def->as_function();
@@ -420,11 +422,12 @@ expr_t::func_t global_scope_t::look_for_command(scope_t& scope,
void global_scope_t::visit_man_page() const
{
+#ifndef WIN32
int pid = fork();
if (pid < 0) {
throw std::logic_error(_("Failed to fork child process"));
}
- else if (pid == 0) { // child
+ else if (pid == 0) { // child
execlp("man", "man", "1", "ledger", NULL);
// We should never, ever reach here
@@ -434,7 +437,8 @@ void global_scope_t::visit_man_page() const
int status = -1;
wait(&status);
- exit(0); // parent
+#endif
+ exit(0); // parent
}
void handle_debug_options(int argc, char * argv[])
@@ -442,37 +446,37 @@ void handle_debug_options(int argc, char * argv[])
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
if (std::strcmp(argv[i], "--args-only") == 0) {
- args_only = true;
+ args_only = true;
}
else if (std::strcmp(argv[i], "--verify") == 0) {
#if defined(VERIFY_ON)
- verify_enabled = true; // global in utils.h
+ verify_enabled = true; // global in utils.h
#endif
}
else if (std::strcmp(argv[i], "--verbose") == 0 ||
- std::strcmp(argv[i], "-v") == 0) {
+ std::strcmp(argv[i], "-v") == 0) {
#if defined(LOGGING_ON)
- _log_level = LOG_INFO; // global in utils.h
+ _log_level = LOG_INFO; // global in utils.h
#endif
}
else if (i + 1 < argc && std::strcmp(argv[i], "--debug") == 0) {
#if defined(DEBUG_ON)
- _log_level = LOG_DEBUG; // global in utils.h
- _log_category = argv[i + 1]; // global in utils.h
- i++;
+ _log_level = LOG_DEBUG; // global in utils.h
+ _log_category = argv[i + 1]; // global in utils.h
+ i++;
#endif
}
else if (i + 1 < argc && std::strcmp(argv[i], "--trace") == 0) {
#if defined(TRACING_ON)
- _log_level = LOG_TRACE; // global in utils.h
- try {
- // global in utils.h
- _trace_level = boost::lexical_cast<uint8_t>(argv[i + 1]);
- }
- catch (const boost::bad_lexical_cast& e) {
- throw std::logic_error(_("Argument to --trace must be an integer"));
- }
- i++;
+ _log_level = LOG_TRACE; // global in utils.h
+ try {
+ // global in utils.h
+ _trace_level = boost::lexical_cast<uint8_t>(argv[i + 1]);
+ }
+ catch (const boost::bad_lexical_cast&) {
+ throw std::logic_error(_("Argument to --trace must be an integer"));
+ }
+ i++;
#endif
}
}
diff --git a/src/global.h b/src/global.h
index 05e3bdb7..6504230d 100644
--- a/src/global.h
+++ b/src/global.h
@@ -38,7 +38,6 @@
#ifndef _GLOBAL_H
#define _GLOBAL_H
-#include "interactive.h"
#include "option.h"
#include "report.h"
@@ -50,16 +49,20 @@ class report_t;
class global_scope_t : public noncopyable, public scope_t
{
shared_ptr<session_t> session_ptr;
- ptr_list<report_t> report_stack;
+ ptr_list<report_t> report_stack;
public:
global_scope_t(char ** envp);
~global_scope_t();
- void read_init();
- void read_environment_settings(char * envp[]);
- strings_list read_command_arguments(scope_t& scope, strings_list args);
- void normalize_session_options();
+ virtual string description() {
+ return _("global scope");
+ }
+
+ void read_init();
+ void read_environment_settings(char * envp[]);
+ strings_list read_command_arguments(scope_t& scope, strings_list args);
+ void normalize_session_options();
expr_t::func_t look_for_precommand(scope_t& scope, const string& verb);
expr_t::func_t look_for_command(scope_t& scope, const string& verb);
@@ -98,7 +101,7 @@ public:
// open output stream at this point. We want it to get popped off as
// soon as this command terminate so that the stream is closed cleanly.
report_stack.insert(++report_stack.begin(),
- new report_t(report_stack.front()));
+ new report_t(report_stack.front()));
return true;
}
value_t pop_command(call_scope_t&) {
@@ -121,7 +124,7 @@ See LICENSE file included with the distribution for details and disclaimer.");
option_t<global_scope_t> * lookup_option(const char * p);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
OPTION(global_scope_t, args_only);
OPTION(global_scope_t, debug_);
@@ -152,7 +155,7 @@ See LICENSE file included with the distribution for details and disclaimer.");
OPTION_(global_scope_t, version, DO() { // -v
parent->show_version_info(std::cout);
- throw int(0); // exit immediately
+ throw int(0); // exit immediately
});
};
diff --git a/src/interactive.cc b/src/interactive.cc
deleted file mode 100644
index 9aeb5307..00000000
--- a/src/interactive.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * 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.
- */
-
-#include <system.hh>
-
-#include "interactive.h"
-
-namespace ledger {
-
-void interactive_t::verify_arguments() const
-{
- value_t::sequence_t::const_iterator i;
-
- const char * p = spec.c_str();
- const char * label = _("unknown");
- bool wrong_arg = false;
- bool dont_skip = false;
- bool optional = *p == '&';
- bool exit_loop = *p == '*';
- std::size_t offset = 1;
- bool is_seq = args.value().is_sequence();
- const value_t * next_arg = NULL;
- string vlabel;
-
- if (is_seq) {
- i = args.begin();
- if (i != args.end())
- next_arg = &(*i);
- }
- else if (! args.value().is_null()) {
- next_arg = &args.value();
- }
-
- for (; ! wrong_arg && ! exit_loop && *p && next_arg; p++) {
- DEBUG("interactive.verify",
- "Want " << *p << " got: " << next_arg->label());
-
- wrong_arg = false;
- switch (*p) {
- case 'a':
- label = _("an amount");
- wrong_arg = (! next_arg->is_long() &&
- ! next_arg->is_amount() &&
- ! next_arg->is_balance());
- break;
- case 'b':
- label = _("a boolean");
- wrong_arg = false; // booleans are converted
- break;
- case 'd':
- label = _("a date");
- wrong_arg = (! next_arg->is_date() &&
- ! next_arg->is_datetime());
- break;
- case 't':
- label = _("a date/time");
- wrong_arg = (! next_arg->is_date() &&
- ! next_arg->is_datetime());
- break;
- case 'i':
- case 'l':
- label = _("an integer");
- if (next_arg->is_long() ||
- (next_arg->is_amount() &&
- ! next_arg->as_amount().has_commodity())) {
- wrong_arg = false;
- }
- else if (next_arg->is_string()) {
- wrong_arg = false;
- for (const char * q = next_arg->as_string().c_str(); *q; q++) {
- if (! std::isdigit(*q) && *q != '-') {
- wrong_arg = true;
- break;
- }
- }
- }
- else {
- wrong_arg = true;
- }
- break;
- case 'm':
- label = _("a regex");
- wrong_arg = ! next_arg->is_mask();
- break;
- case 's':
- label = _("a string");
- wrong_arg = ! next_arg->is_string();
- break;
- case 'v':
- label = _("any value");
- wrong_arg = false;
- break;
- case '^':
- label = _("a scope");
- wrong_arg = ! next_arg->is_scope();
- break;
- case 'X':
- label = _("an expression");
- wrong_arg = ! next_arg->is_expr();
- break;
- case 'S':
- label = _("a sequence");
- wrong_arg = false;
- break;
- case '&':
- optional = true;
- dont_skip = true;
- break;
- case '*':
- optional = true;
- exit_loop = true;
- dont_skip = true;
- break;
- }
- if (wrong_arg && optional && next_arg->is_null())
- wrong_arg = false;
-
- if (wrong_arg)
- vlabel = next_arg->label();
-
- if (! dont_skip) {
- if (is_seq) {
- if (++i != args.end()) {
- next_arg = &(*i);
- offset++;
- } else {
- next_arg = NULL;
- }
- } else {
- next_arg = NULL;
- }
- }
- dont_skip = false;
- }
-
- if (*p == '&' || *p == '*')
- optional = true;
-
- DEBUG("interactive.verify", "Remaining args are optional");
-
- if (wrong_arg) {
- throw_(std::logic_error,
- _("Expected %1 for argument %2, but received %3")
- << label << offset << vlabel);
- }
- else if (*p && ! optional && ! next_arg) {
- throw_(std::logic_error, _("Too few arguments to function"));
- }
- else if (! *p && next_arg) {
- throw_(std::logic_error, _("Too many arguments to function"));
- }
-}
-
-string join_args(call_scope_t& args)
-{
- std::ostringstream buf;
- bool first = true;
-
- for (std::size_t i = 0; i < args.size(); i++) {
- if (first)
- first = false;
- else
- buf << ' ';
- buf << args[i];
- }
-
- return buf.str();
-}
-
-} // namespace ledger
diff --git a/src/interactive.h b/src/interactive.h
deleted file mode 100644
index 04c23ae5..00000000
--- a/src/interactive.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @addtogroup expr
- */
-
-/**
- * @file interactive.h
- * @author John Wiegley
- *
- * @ingroup expr
- */
-#ifndef _INTERACTIVE_H
-#define _INTERACTIVE_H
-
-#include "scope.h"
-
-namespace ledger {
-
-class interactive_t : public noncopyable
-{
- call_scope_t& args;
- string spec;
-
-public:
- explicit interactive_t(call_scope_t& _args, const string& _spec = "")
- : args(_args), spec(_spec) {
- TRACE_CTOR(interactive_t, "call_scope_t&, const string&");
- verify_arguments();
- }
- virtual ~interactive_t() {
- TRACE_DTOR(interactive_t);
- }
-
- void verify_arguments() const;
-
- bool has(std::size_t index) const {
- if (index < args.size() && ! args[index].is_null())
- return true;
- return false;
- }
-
- value_t& value_at(std::size_t index) {
- assert(has(index));
- return args[index];
- }
-
- template <typename T>
- T get(std::size_t index);
-};
-
-template <>
-inline bool interactive_t::get<bool>(std::size_t index) {
- return value_at(index).to_boolean();
-}
-template <>
-inline int interactive_t::get<int>(std::size_t index) {
- return value_at(index).to_int();
-}
-template <>
-inline long interactive_t::get<long>(std::size_t index) {
- return value_at(index).to_long();
-}
-template <>
-inline amount_t interactive_t::get<amount_t>(std::size_t index) {
- return value_at(index).to_amount();
-}
-template <>
-inline string interactive_t::get<string>(std::size_t index) {
- return value_at(index).to_string();
-}
-template <>
-inline mask_t interactive_t::get<mask_t>(std::size_t index) {
- return value_at(index).to_mask();
-}
-template <>
-inline date_t interactive_t::get<date_t>(std::size_t index) {
- return value_at(index).to_date();
-}
-template <>
-inline datetime_t interactive_t::get<datetime_t>(std::size_t index) {
- return value_at(index).to_datetime();
-}
-template <>
-inline value_t::sequence_t&
-interactive_t::get<value_t::sequence_t&>(std::size_t index) {
- return value_at(index).as_sequence_lval();
-}
-template <>
-inline const value_t::sequence_t&
-interactive_t::get<const value_t::sequence_t&>(std::size_t index) {
- return value_at(index).as_sequence();
-}
-template <>
-inline scope_t *
-interactive_t::get<scope_t *>(std::size_t index) {
- return value_at(index).as_scope();
-}
-template <>
-inline expr_t& interactive_t::get<expr_t&>(std::size_t index) {
- return value_at(index).as_expr_lval();
-}
-template <>
-inline const expr_t& interactive_t::get<const expr_t&>(std::size_t index) {
- return value_at(index).as_expr();
-}
-
-template <typename T>
-class in_context_t : public interactive_t
-{
- T& context;
-
-public:
- explicit in_context_t(call_scope_t& args, const string& spec)
- : interactive_t(args, spec), context(find_scope<T>(args)) {
- TRACE_CTOR(in_context_t, "call_scope_t&, const string&");
- }
- virtual ~in_context_t() {
- TRACE_DTOR(in_context_t);
- }
-
- T& operator *() {
- return context;
- }
- T * operator->() {
- return &context;
- }
-};
-
-string join_args(call_scope_t& args);
-
-} // namespace ledger
-
-#endif // _INTERACTIVE_H
-
diff --git a/src/item.cc b/src/item.cc
index fea73066..9290ab2f 100644
--- a/src/item.cc
+++ b/src/item.cc
@@ -32,13 +32,12 @@
#include <system.hh>
#include "item.h"
-#include "interactive.h"
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) {
@@ -58,22 +57,22 @@ 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) {
if (tag_mask.match(data.first)) {
- if (! value_mask)
- return true;
- else if (data.second.first)
- return value_mask->match(*data.second.first);
+ if (! value_mask)
+ return true;
+ else if (data.second.first)
+ return value_mask->match(data.second.first->to_string());
}
}
}
return false;
}
-optional<string> 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,24 +86,27 @@ optional<string> item_t::get_tag(const string& tag) const
return none;
}
-optional<string> item_t::get_tag(const mask_t& tag_mask,
- const optional<mask_t>& value_mask) const
+optional<value_t> item_t::get_tag(const mask_t& tag_mask,
+ const optional<mask_t>& value_mask,
+ bool) const
{
if (metadata) {
foreach (const string_map::value_type& data, *metadata) {
if (tag_mask.match(data.first) &&
- (! value_mask ||
- (data.second.first && value_mask->match(*data.second.first))))
- return data.second.first;
+ (! value_mask ||
+ (data.second.first &&
+ value_mask->match(data.second.first->to_string())))) {
+ return data.second.first;
+ }
}
}
return none;
}
item_t::string_map::iterator
-item_t::set_tag(const string& tag,
- const optional<string>& value,
- const bool overwrite_existing)
+item_t::set_tag(const string& tag,
+ const optional<value_t>& value,
+ const bool overwrite_existing)
{
assert(! tag.empty());
@@ -112,10 +114,12 @@ item_t::set_tag(const string& tag,
metadata = string_map();
DEBUG("item.meta", "Setting tag '" << tag << "' to value '"
- << (value ? *value : string("<none>")) << "'");
+ << (value ? *value : string_value("<none>")) << "'");
- optional<string> data = value;
- if (data && data->empty())
+ optional<value_t> data = value;
+ if (data &&
+ (data->is_null() ||
+ (data->is_string() && data->as_string().empty())))
data = none;
string_map::iterator i = metadata->find(tag);
@@ -131,61 +135,78 @@ item_t::set_tag(const string& tag,
}
}
-void item_t::parse_tags(const char * p, bool overwrite_existing,
- optional<date_t::year_type> current_year)
+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 (char * p = std::strchr(buf, '=')) {
- *p++ = '\0';
- _date_eff = parse_date(p, current_year);
- }
- if (buf[0])
- _date = parse_date(buf, current_year);
+ 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 (buf[0])
+ _date = parse_date(buf);
+ }
}
}
- }
-
- if (! std::strchr(p, ':'))
return;
+ }
scoped_array<char> buf(new char[std::strlen(p) + 1]);
std::strcpy(buf.get(), p);
string tag;
+ bool by_value = false;
+ bool first = true;
for (char * q = std::strtok(buf.get(), " \t");
q;
q = std::strtok(NULL, " \t")) {
const string::size_type len = std::strlen(q);
+ if (len < 2) continue;
if (! tag.empty()) {
- string_map::iterator i = set_tag(tag, string(p + (q - buf.get())),
- overwrite_existing);
+ string_map::iterator i;
+ string field(p + (q - buf.get()));
+ if (by_value) {
+ bind_scope_t bound_scope(scope, *this);
+ i = set_tag(tag, expr_t(field).calc(bound_scope), overwrite_existing);
+ } else {
+ i = set_tag(tag, string_value(field), overwrite_existing);
+ }
(*i).second.second = true;
break;
}
else if (q[0] == ':' && q[len - 1] == ':') { // a series of tags
for (char * r = std::strtok(q + 1, ":");
- r;
- r = std::strtok(NULL, ":")) {
- string_map::iterator i = set_tag(r, none, overwrite_existing);
- (*i).second.second = true;
+ r;
+ r = std::strtok(NULL, ":")) {
+ string_map::iterator i = set_tag(r, none, overwrite_existing);
+ (*i).second.second = true;
}
}
- else if (q[len - 1] == ':') { // a metadata setting
- tag = string(q, len - 1);
+ else if (first && q[len - 1] == ':') { // a metadata setting
+ int index = 1;
+ if (q[len - 2] == ':') {
+ by_value = true;
+ index = 2;
+ }
+ tag = string(q, len - index);
}
+ first = false;
}
}
-void item_t::append_note(const char * p, bool overwrite_existing,
- optional<date_t::year_type> current_year)
+void item_t::append_note(const char * p,
+ scope_t& scope,
+ bool overwrite_existing)
{
if (note) {
*note += '\n';
@@ -194,7 +215,7 @@ void item_t::append_note(const char * p, bool overwrite_existing,
note = p;
}
- parse_tags(p, overwrite_existing, current_year);
+ parse_tags(p, scope, overwrite_existing);
}
namespace {
@@ -235,21 +256,21 @@ namespace {
if (args.size() == 1) {
if (args[0].is_string())
- return item.has_tag(args[0].as_string());
+ return item.has_tag(args.get<string>(0));
else if (args[0].is_mask())
- return item.has_tag(args[0].as_mask());
+ return item.has_tag(args.get<mask_t>(0));
else
- throw_(std::runtime_error,
- _("Expected string or mask for argument 1, but received %1")
- << args[0].label());
+ throw_(std::runtime_error,
+ _("Expected string or mask for argument 1, but received %1")
+ << args[0].label());
}
else if (args.size() == 2) {
if (args[0].is_mask() && args[1].is_mask())
- return item.has_tag(args[0].to_mask(), args[1].to_mask());
+ return item.has_tag(args.get<mask_t>(0), args.get<mask_t>(1));
else
- throw_(std::runtime_error,
- _("Expected masks for arguments 1 and 2, but received %1 and %2")
- << args[0].label() << args[1].label());
+ throw_(std::runtime_error,
+ _("Expected masks for arguments 1 and 2, but received %1 and %2")
+ << args[0].label() << args[1].label());
}
else if (args.size() == 0) {
throw_(std::runtime_error, _("Too few arguments to function"));
@@ -263,25 +284,25 @@ namespace {
value_t get_tag(call_scope_t& args)
{
item_t& item(find_scope<item_t>(args));
- optional<string> str;
+ optional<value_t> val;
if (args.size() == 1) {
if (args[0].is_string())
- str = item.get_tag(args[0].as_string());
+ val = item.get_tag(args.get<string>(0));
else if (args[0].is_mask())
- str = item.get_tag(args[0].as_mask());
+ val = item.get_tag(args.get<mask_t>(0));
else
- throw_(std::runtime_error,
- _("Expected string or mask for argument 1, but received %1")
- << args[0].label());
+ throw_(std::runtime_error,
+ _("Expected string or mask for argument 1, but received %1")
+ << args[0].label());
}
else if (args.size() == 2) {
if (args[0].is_mask() && args[1].is_mask())
- str = item.get_tag(args[0].to_mask(), args[1].to_mask());
+ val = item.get_tag(args.get<mask_t>(0), args.get<mask_t>(1));
else
- throw_(std::runtime_error,
- _("Expected masks for arguments 1 and 2, but received %1 and %2")
- << args[0].label() << args[1].label());
+ throw_(std::runtime_error,
+ _("Expected masks for arguments 1 and 2, but received %1 and %2")
+ << args[0].label() << args[1].label());
}
else if (args.size() == 0) {
throw_(std::runtime_error, _("Too few arguments to function"));
@@ -290,10 +311,7 @@ namespace {
throw_(std::runtime_error, _("Too many arguments to function"));
}
- if (str)
- return string_value(*str);
- else
- return NULL_VALUE;
+ return val ? *val : NULL_VALUE;
}
value_t get_pathname(item_t& item) {
@@ -355,13 +373,13 @@ value_t get_comment(item_t& item)
bool need_separator = false;
for (const char * p = item.note->c_str(); *p; p++) {
if (*p == '\n') {
- need_separator = true;
+ need_separator = true;
} else {
- if (need_separator) {
- buf << "\n ;";
- need_separator = false;
- }
- buf << *p;
+ if (need_separator) {
+ buf << "\n ;";
+ need_separator = false;
+ }
+ buf << *p;
}
}
return string_value(buf.str());
@@ -369,7 +387,7 @@ value_t get_comment(item_t& item)
}
expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return NULL;
@@ -465,6 +483,11 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind,
return WRAP_FUNCTOR(get_wrapper<&get_uncleared>);
break;
+ case 'v':
+ if (name == "value_date")
+ return WRAP_FUNCTOR(get_wrapper<&get_date>);
+ break;
+
case 'L':
if (name[1] == '\0')
return WRAP_FUNCTOR(get_wrapper<&get_actual>);
@@ -497,7 +520,7 @@ bool item_t::valid() const
void print_item(std::ostream& out, const item_t& item, const string& prefix)
{
out << source_context(item.pos->pathname, item.pos->beg_pos,
- item.pos->end_pos, prefix);
+ item.pos->end_pos, prefix);
}
string item_context(const item_t& item, const string& desc)
@@ -523,7 +546,7 @@ string item_context(const item_t& item, const string& desc)
if (item.pos->beg_line != item.pos->end_line)
out << _(", lines ") << item.pos->beg_line << "-"
- << item.pos->end_line << ":\n";
+ << item.pos->end_line << ":\n";
else
out << _(", line ") << item.pos->beg_line << ":\n";
diff --git a/src/item.h b/src/item.h
index 7045c875..79d2f23b 100644
--- a/src/item.h
+++ b/src/item.h
@@ -50,10 +50,10 @@ struct position_t
{
path pathname;
istream_pos_type beg_pos;
- std::size_t beg_line;
+ std::size_t beg_line;
istream_pos_type end_pos;
- std::size_t end_line;
- std::size_t sequence;
+ std::size_t end_line;
+ std::size_t sequence;
position_t()
: beg_pos(0), beg_line(0), end_pos(0), end_line(0), sequence(0) {
@@ -97,19 +97,19 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
-class item_t : public supports_flags<>, public scope_t
+class item_t : public supports_flags<uint_least16_t>, public scope_t
{
public:
-#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
-#define ITEM_GENERATED 0x01 // posting was not found in a journal
-#define ITEM_TEMP 0x02 // posting is a managed temporary
+#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
+#define ITEM_GENERATED 0x01 // posting was not found in a journal
+#define ITEM_TEMP 0x02 // posting is a managed temporary
enum state_t { UNCLEARED = 0, CLEARED, PENDING };
- typedef std::pair<optional<string>, bool> tag_data_t;
- typedef std::map<string, tag_data_t> string_map;
+ typedef std::pair<optional<value_t>, bool> tag_data_t;
+ typedef std::map<string, tag_data_t> string_map;
- state_t _state;
+ state_t _state;
optional<date_t> _date;
optional<date_t> _date_eff;
optional<string> note;
@@ -117,11 +117,11 @@ public:
optional<string_map> metadata;
item_t(flags_t _flags = ITEM_NORMAL, const optional<string>& _note = none)
- : supports_flags<>(_flags), _state(UNCLEARED), note(_note)
+ : supports_flags<uint_least16_t>(_flags), _state(UNCLEARED), note(_note)
{
TRACE_CTOR(item_t, "flags_t, const string&");
}
- item_t(const item_t& item) : supports_flags<>(), scope_t()
+ item_t(const item_t& item) : supports_flags<uint_least16_t>(), scope_t()
{
TRACE_CTOR(item_t, "copy");
copy_details(item);
@@ -149,31 +149,41 @@ 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<string> get_tag(const string& tag) const;
- virtual optional<string> 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,
- const optional<string>& value = none,
- const bool overwrite_existing = true);
+ set_tag(const string& tag,
+ const optional<value_t>& value = none,
+ const bool overwrite_existing = true);
- virtual void parse_tags(const char * p, bool overwrite_existing = true,
- optional<date_t::year_type> current_year = none);
- virtual void append_note(const char * p, bool overwrite_existing = true,
- optional<date_t::year_type> current_year = none);
+ virtual void parse_tags(const char * p,
+ scope_t& scope,
+ bool overwrite_existing = true);
+ virtual void append_note(const char * p,
+ scope_t& scope,
+ bool overwrite_existing = true);
static bool use_effective_date;
+ virtual bool has_date() const {
+ return _date;
+ }
+
virtual date_t date() const {
assert(_date);
if (use_effective_date)
if (optional<date_t> effective = effective_date())
- return *effective;
+ return *effective;
return *_date;
}
virtual date_t actual_date() const {
@@ -192,7 +202,7 @@ public:
}
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
bool valid() const;
@@ -204,7 +214,7 @@ private:
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
- ar & boost::serialization::base_object<supports_flags<> >(*this);
+ ar & boost::serialization::base_object<supports_flags<uint_least16_t> >(*this);
ar & boost::serialization::base_object<scope_t>(*this);
ar & _state;
ar & _date;
@@ -217,9 +227,9 @@ private:
};
value_t get_comment(item_t& item);
-void print_item(std::ostream& out, const item_t& item,
- const string& prefix = "");
-string item_context(const item_t& item, const string& desc);
+void print_item(std::ostream& out, const item_t& item,
+ const string& prefix = "");
+string item_context(const item_t& item, const string& desc);
} // namespace ledger
diff --git a/src/iterators.cc b/src/iterators.cc
index ade1d4b3..b63a10e9 100644
--- a/src/iterators.cc
+++ b/src/iterators.cc
@@ -91,47 +91,47 @@ void posts_commodities_iterator::reset(journal_t& journal)
foreach (commodity_t * comm, commodities) {
if (optional<commodity_t::varied_history_t&> history =
- comm->varied_history()) {
+ comm->varied_history()) {
account_t * account = journal.master->find_account(comm->symbol());
foreach (commodity_t::history_by_commodity_map::value_type& pair,
- history->histories) {
- foreach (commodity_t::history_map::value_type& hpair,
- pair.second.prices) {
- xact_t * xact;
- string symbol = hpair.second.commodity().symbol();
-
- std::map<string, xact_t *>::iterator i =
- xacts_by_commodity.find(symbol);
- if (i != xacts_by_commodity.end()) {
- xact = (*i).second;
- } else {
- xact = &temps.create_xact();
- xact_temps.push_back(xact);
- xact->payee = symbol;
- xact->_date = hpair.first.date();
- xacts_by_commodity.insert
- (std::pair<string, xact_t *>(symbol, xact));
- }
-
- bool post_already_exists = false;
-
- foreach (post_t * post, xact->posts) {
- if (post->_date == hpair.first.date() &&
- post->amount == hpair.second) {
- post_already_exists = true;
- break;
- }
- }
-
- if (! post_already_exists) {
- post_t& temp = temps.create_post(*xact, account);
- temp._date = hpair.first.date();
- temp.amount = hpair.second;
-
- temp.xdata().datetime = hpair.first;
- }
- }
+ history->histories) {
+ foreach (commodity_t::history_map::value_type& hpair,
+ pair.second.prices) {
+ xact_t * xact;
+ string symbol = hpair.second.commodity().symbol();
+
+ std::map<string, xact_t *>::iterator i =
+ xacts_by_commodity.find(symbol);
+ if (i != xacts_by_commodity.end()) {
+ xact = (*i).second;
+ } else {
+ xact = &temps.create_xact();
+ xact_temps.push_back(xact);
+ xact->payee = symbol;
+ xact->_date = hpair.first.date();
+ xacts_by_commodity.insert
+ (std::pair<string, xact_t *>(symbol, xact));
+ }
+
+ bool post_already_exists = false;
+
+ foreach (post_t * post, xact->posts) {
+ if (post->_date == hpair.first.date() &&
+ post->amount == hpair.second) {
+ post_already_exists = true;
+ break;
+ }
+ }
+
+ if (! post_already_exists) {
+ post_t& temp = temps.create_post(*xact, account);
+ temp._date = hpair.first.date();
+ temp.amount = hpair.second;
+
+ temp.xdata().datetime = hpair.first;
+ }
+ }
}
}
}
@@ -162,7 +162,7 @@ post_t * posts_commodities_iterator::operator()()
account_t * basic_accounts_iterator::operator()()
{
while (! accounts_i.empty() &&
- accounts_i.back() == accounts_end.back()) {
+ accounts_i.back() == accounts_end.back()) {
accounts_i.pop_back();
accounts_end.pop_back();
}
@@ -187,14 +187,14 @@ void sorted_accounts_iterator::push_back(account_t& account)
push_all(account, accounts_list.back());
std::stable_sort(accounts_list.back().begin(),
- accounts_list.back().end(),
- compare_items<account_t>(sort_cmp));
+ accounts_list.back().end(),
+ compare_items<account_t>(sort_cmp));
#if defined(DEBUG_ON)
if (SHOW_DEBUG("accounts.sorted")) {
foreach (account_t * account, accounts_list.back())
- DEBUG("accounts.sorted",
- "Account (flat): " << account->fullname());
+ DEBUG("accounts.sorted",
+ "Account (flat): " << account->fullname());
}
#endif
} else {
@@ -206,7 +206,7 @@ void sorted_accounts_iterator::push_back(account_t& account)
}
void sorted_accounts_iterator::push_all(account_t& account,
- accounts_deque_t& deque)
+ accounts_deque_t& deque)
{
foreach (accounts_map::value_type& pair, account.accounts) {
deque.push_back(pair.second);
@@ -215,13 +215,13 @@ void sorted_accounts_iterator::push_all(account_t& account,
}
void sorted_accounts_iterator::sort_accounts(account_t& account,
- accounts_deque_t& deque)
+ accounts_deque_t& deque)
{
foreach (accounts_map::value_type& pair, account.accounts)
deque.push_back(pair.second);
std::stable_sort(deque.begin(), deque.end(),
- compare_items<account_t>(sort_cmp));
+ compare_items<account_t>(sort_cmp));
#if defined(DEBUG_ON)
if (SHOW_DEBUG("accounts.sorted")) {
@@ -234,7 +234,7 @@ void sorted_accounts_iterator::sort_accounts(account_t& account,
account_t * sorted_accounts_iterator::operator()()
{
while (! sorted_accounts_i.empty() &&
- sorted_accounts_i.back() == sorted_accounts_end.back()) {
+ sorted_accounts_i.back() == sorted_accounts_end.back()) {
sorted_accounts_i.pop_back();
sorted_accounts_end.pop_back();
assert(! accounts_list.empty());
diff --git a/src/iterators.h b/src/iterators.h
index 5e9f5fbe..5113d3b2 100644
--- a/src/iterators.h
+++ b/src/iterators.h
@@ -142,8 +142,8 @@ class posts_commodities_iterator : public posts_iterator
{
protected:
journal_posts_iterator journal_posts;
- xacts_iterator xacts;
- xact_posts_iterator posts;
+ xacts_iterator xacts;
+ xact_posts_iterator posts;
temporaries_t temps;
xacts_list xact_temps;
@@ -203,13 +203,13 @@ class sorted_accounts_iterator : public accounts_iterator
typedef std::deque<account_t *> accounts_deque_t;
- std::list<accounts_deque_t> accounts_list;
+ std::list<accounts_deque_t> accounts_list;
std::list<accounts_deque_t::const_iterator> sorted_accounts_i;
std::list<accounts_deque_t::const_iterator> sorted_accounts_end;
public:
sorted_accounts_iterator(account_t& account,
- const expr_t& _sort_cmp, bool _flatten_all)
+ const expr_t& _sort_cmp, bool _flatten_all)
: sort_cmp(_sort_cmp), flatten_all(_flatten_all) {
TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&");
push_back(account);
diff --git a/src/journal.cc b/src/journal.cc
index 158fac42..fd6d3eac 100644
--- a/src/journal.cc
+++ b/src/journal.cc
@@ -145,9 +145,9 @@ bool journal_t::remove_xact(xact_t * xact)
}
std::size_t journal_t::read(std::istream& in,
- const path& pathname,
- account_t * master_alt,
- scope_t * scope)
+ const path& pathname,
+ account_t * master_alt,
+ scope_t * scope)
{
std::size_t count = 0;
try {
@@ -156,13 +156,13 @@ std::size_t journal_t::read(std::istream& in,
if (! scope)
throw_(std::runtime_error,
- _("No default scope in which to read journal file '%1'")
- << pathname);
+ _("No default scope in which to read journal file '%1'")
+ << pathname);
value_t strict = expr_t("strict").calc(*scope);
count = parse(in, *scope, master_alt ? master_alt : master,
- &pathname, strict.to_boolean());
+ &pathname, strict.to_boolean());
}
catch (...) {
clear_xdata();
@@ -178,14 +178,14 @@ std::size_t journal_t::read(std::istream& in,
}
std::size_t journal_t::read(const path& pathname,
- account_t * master,
- scope_t * scope)
+ account_t * master,
+ scope_t * scope)
{
path filename = resolve_path(pathname);
if (! exists(filename))
throw_(std::runtime_error,
- _("Cannot read journal file '%1'") << filename);
+ _("Cannot read journal file '%1'") << filename);
ifstream stream(filename);
std::size_t count = read(stream, filename, master, scope);
diff --git a/src/journal.h b/src/journal.h
index a407c02c..ca6b6e4f 100644
--- a/src/journal.h
+++ b/src/journal.h
@@ -55,7 +55,7 @@ class period_xact_t;
class account_t;
class scope_t;
-typedef std::list<xact_t *> xacts_list;
+typedef std::list<xact_t *> xacts_list;
typedef std::list<auto_xact_t *> auto_xacts_list;
typedef std::list<period_xact_t *> period_xacts_list;
@@ -70,9 +70,9 @@ public:
struct fileinfo_t
{
optional<path> filename;
- uintmax_t size;
- datetime_t modtime;
- bool from_stream;
+ uintmax_t size;
+ datetime_t modtime;
+ bool from_stream;
fileinfo_t() : size(0), from_stream(true) {
TRACE_CTOR(journal_t::fileinfo_t, "");
@@ -85,7 +85,7 @@ public:
}
fileinfo_t(const fileinfo_t& info)
: filename(info.filename), size(info.size),
- modtime(info.modtime), from_stream(info.from_stream)
+ modtime(info.modtime), from_stream(info.from_stream)
{
TRACE_CTOR(journal_t::fileinfo_t, "copy");
}
@@ -109,11 +109,11 @@ public:
#endif // HAVE_BOOST_SERIALIZATION
};
- account_t * master;
- account_t * bucket;
- xacts_list xacts;
- auto_xacts_list auto_xacts;
- period_xacts_list period_xacts;
+ account_t * master;
+ account_t * bucket;
+ xacts_list xacts;
+ auto_xacts_list auto_xacts;
+ period_xacts_list period_xacts;
std::list<fileinfo_t> sources;
payee_mappings_t payee_mappings;
account_mappings_t account_mappings;
@@ -135,8 +135,8 @@ public:
// These four methods are delegated to the current session, since all
// accounts processed are gathered together at the session level.
- void add_account(account_t * acct);
- bool remove_account(account_t * acct);
+ void add_account(account_t * acct);
+ bool remove_account(account_t * acct);
account_t * find_account(const string& name, bool auto_create = true);
account_t * find_account_re(const string& regexp);
@@ -164,18 +164,18 @@ public:
}
std::size_t read(std::istream& in,
- const path& pathname,
- account_t * master = NULL,
- scope_t * scope = NULL);
- std::size_t read(const path& pathname,
- account_t * master = NULL,
- scope_t * scope = NULL);
+ const path& pathname,
+ account_t * master = NULL,
+ scope_t * scope = NULL);
+ std::size_t read(const path& pathname,
+ account_t * master = NULL,
+ scope_t * scope = NULL);
std::size_t parse(std::istream& in,
- scope_t& session_scope,
- account_t * master = NULL,
- const path * original_file = NULL,
- bool strict = false);
+ scope_t& session_scope,
+ account_t * master = NULL,
+ const path * original_file = NULL,
+ bool strict = false);
bool has_xdata();
void clear_xdata();
diff --git a/src/lookup.cc b/src/lookup.cc
index 40b6c185..221397ca 100644
--- a/src/lookup.cc
+++ b/src/lookup.cc
@@ -43,7 +43,7 @@ namespace {
struct score_sorter {
bool operator()(const score_entry_t& left,
- const score_entry_t& right) const {
+ const score_entry_t& right) const {
return left.second > right.second;
}
};
@@ -53,7 +53,7 @@ namespace {
struct usage_sorter {
bool operator()(const account_use_pair& left,
- const account_use_pair& right) const {
+ const account_use_pair& right) const {
return left.second > right.second;
}
};
@@ -61,8 +61,8 @@ namespace {
std::pair<xact_t *, account_t *>
lookup_probable_account(const string& ident,
- xacts_iterator& iter_func,
- account_t * ref_account)
+ xacts_iterator& iter_func,
+ account_t * ref_account)
{
scorecard_t scores;
@@ -76,11 +76,11 @@ lookup_probable_account(const string& ident,
#endif
DEBUG("lookup.account",
- "Looking up identifier '" << lowered_ident.extract() << "'");
+ "Looking up identifier '" << lowered_ident.extract() << "'");
#if defined(DEBUG_ON)
if (ref_account != NULL)
DEBUG("lookup.account",
- " with reference account: " << ref_account->fullname());
+ " with reference account: " << ref_account->fullname());
#endif
while (xact_t * xact = iter_func()) {
@@ -109,17 +109,17 @@ lookup_probable_account(const string& ident,
DEBUG("lookup", "Considering payee: " << value_key.extract());
- std::size_t index = 0;
- std::size_t last_match_pos = unistring::npos;
- int bonus = 0;
- int score = 0;
- std::size_t pos;
+ std::size_t index = 0;
+ std::size_t last_match_pos = unistring::npos;
+ int bonus = 0;
+ int score = 0;
+ std::size_t pos;
char_positions_map positions;
// Walk each letter in the source identifier
foreach (const uint32_t& ch, lowered_ident.utf32chars) {
- int addend = 0;
- bool added_bonus = false;
+ int addend = 0;
+ bool added_bonus = false;
std::size_t value_len = value_key.length();
pos = value_key.find(ch);
@@ -131,76 +131,76 @@ lookup_probable_account(const string& ident,
char_positions_map::iterator pi = positions.find(ch);
while (pi != positions.end() &&
- pos != unistring::npos && pos <= (*pi).second &&
- (*pi).second + 1 < value_len)
- pos = value_key.find(ch, (*pi).second + 1);
+ pos != unistring::npos && pos <= (*pi).second &&
+ (*pi).second + 1 < value_len)
+ pos = value_key.find(ch, (*pi).second + 1);
if (pos != unistring::npos) {
- if (pi != positions.end())
- (*pi).second = pos;
- else
- positions.insert(char_positions_map::value_type(ch, pos));
-
- // If it occurs in the same order as the source identifier -- that is,
- // without intervening letters to break the pattern -- it's worth 10
- // points. Plus, an extra point is added for every letter in chains
- // of 3 or more.
-
- if (last_match_pos == unistring::npos ?
- index == 0 && pos == 0 : pos == last_match_pos + 1) {
- DEBUG("lookup",
- " char " << index << " in-sequence match with bonus " << bonus);
- addend += 10;
- if (bonus > 2)
- addend += bonus - 2;
- bonus++;
- added_bonus = true;
-
- last_match_pos = pos;
- }
-
- // If it occurs in the same general sequence as the source identifier,
- // it's worth 5 points, plus an extra point if it's within the next 3
- // characters, and an extra point if it's preceded by a non-alphabetic
- // character.
- //
- // If the letter occurs at all in the target identifier, it's worth 1
- // point, plus an extra point if it's within 3 characters, and an
- // extra point if it's preceded by a non-alphabetic character.
-
- else {
- bool in_order_match = (last_match_pos != unistring::npos &&
- pos > last_match_pos);
- DEBUG("lookup", " char " << index << " " <<
- (in_order_match ? "in-order" : "out-of-order")
- << " match" << (in_order_match && pos - index < 3 ?
- " with proximity bonus of 1" : ""));
-
- if (pos < index)
- addend += 1;
- else
- addend += 5;
-
- if (in_order_match && pos - index < 3)
- addend++;
+ if (pi != positions.end())
+ (*pi).second = pos;
+ else
+ positions.insert(char_positions_map::value_type(ch, pos));
+
+ // If it occurs in the same order as the source identifier -- that is,
+ // without intervening letters to break the pattern -- it's worth 10
+ // points. Plus, an extra point is added for every letter in chains
+ // of 3 or more.
+
+ if (last_match_pos == unistring::npos ?
+ index == 0 && pos == 0 : pos == last_match_pos + 1) {
+ DEBUG("lookup",
+ " char " << index << " in-sequence match with bonus " << bonus);
+ addend += 10;
+ if (bonus > 2)
+ addend += bonus - 2;
+ bonus++;
+ added_bonus = true;
+
+ last_match_pos = pos;
+ }
+
+ // If it occurs in the same general sequence as the source identifier,
+ // it's worth 5 points, plus an extra point if it's within the next 3
+ // characters, and an extra point if it's preceded by a non-alphabetic
+ // character.
+ //
+ // If the letter occurs at all in the target identifier, it's worth 1
+ // point, plus an extra point if it's within 3 characters, and an
+ // extra point if it's preceded by a non-alphabetic character.
+
+ else {
+ bool in_order_match = (last_match_pos != unistring::npos &&
+ pos > last_match_pos);
+ DEBUG("lookup", " char " << index << " " <<
+ (in_order_match ? "in-order" : "out-of-order")
+ << " match" << (in_order_match && pos - index < 3 ?
+ " with proximity bonus of 1" : ""));
+
+ if (pos < index)
+ addend += 1;
+ else
+ addend += 5;
+
+ if (in_order_match && pos - index < 3)
+ addend++;
#if !defined(HAVE_BOOST_REGEX_UNICODE)
- if (pos == 0 || (pos > 0 && !std::isalnum(value_key[pos - 1])))
- addend++;
+ if (pos == 0 || (pos > 0 && !std::isalnum(value_key[pos - 1])))
+ addend++;
#else
- // jww (2010-03-07): Not yet implemented
+ // jww (2010-03-07): Not yet implemented
#endif
- last_match_pos = pos;
- }
+ last_match_pos = pos;
+ }
// If the letter does not appear at all, decrease the score by 1
} else {
- last_match_pos = unistring::npos;
+ last_match_pos = unistring::npos;
- DEBUG("lookup", " char " << index << " does not match");
- addend--;
+ DEBUG("lookup", " char " << index << " does not match");
+ addend--;
}
// Finally, decay what is to be added to the score based on its position
@@ -211,9 +211,9 @@ lookup_probable_account(const string& ident,
// divisor for the addend.
if ((int(index / 5) + 1) > 1) {
- DEBUG("lookup",
- " discounting the addend by / " << (int(index / 5) + 1));
- addend = int(double(addend) / (int(index / 5) + 1));
+ DEBUG("lookup",
+ " discounting the addend by / " << (int(index / 5) + 1));
+ addend = int(double(addend) / (int(index / 5) + 1));
}
DEBUG("lookup", " final addend is " << addend);
@@ -221,7 +221,7 @@ lookup_probable_account(const string& ident,
DEBUG("lookup", " score is " << score);
if (! added_bonus)
- bonus = 0;
+ bonus = 0;
index++;
}
@@ -238,26 +238,26 @@ lookup_probable_account(const string& ident,
std::stable_sort(scores.begin(), scores.end(), score_sorter());
- scorecard_t::iterator si = scores.begin();
- int decay = 0;
- xact_t * best_xact = si != scores.end() ? (*si).first : NULL;
- account_use_map account_usage;
+ scorecard_t::iterator si = scores.begin();
+ int decay = 0;
+ xact_t * best_xact = si != scores.end() ? (*si).first : NULL;
+ account_use_map account_usage;
for (int i = 0; i < 5 && si != scores.end(); i++, si++) {
DEBUG("lookup.account",
- "Payee: " << std::setw(5) << std::right << (*si).second <<
- " - " << (*si).first->payee);
+ "Payee: " << std::setw(5) << std::right << (*si).second <<
+ " - " << (*si).first->payee);
foreach (post_t * post, (*si).first->posts) {
if (! post->has_flags(ITEM_TEMP | ITEM_GENERATED) &&
- post->account != ref_account &&
- ! post->account->has_flags(ACCOUNT_TEMP | ACCOUNT_GENERATED)) {
- account_use_map::iterator x = account_usage.find(post->account);
- if (x == account_usage.end())
- account_usage.insert(account_use_pair(post->account,
- ((*si).second - decay)));
- else
- (*x).second += ((*si).second - decay);
+ post->account != ref_account &&
+ ! post->account->has_flags(ACCOUNT_TEMP | ACCOUNT_GENERATED)) {
+ account_use_map::iterator x = account_usage.find(post->account);
+ if (x == account_usage.end())
+ account_usage.insert(account_use_pair(post->account,
+ ((*si).second - decay)));
+ else
+ (*x).second += ((*si).second - decay);
}
decay++;
}
@@ -267,14 +267,14 @@ lookup_probable_account(const string& ident,
#if defined(DEBUG_ON)
if (SHOW_DEBUG("lookup.account")) {
foreach (const account_use_pair& value, account_usage) {
- DEBUG("lookup.account",
- "Account: " << value.second << " - " << value.first->fullname());
+ DEBUG("lookup.account",
+ "Account: " << value.second << " - " << value.first->fullname());
}
}
#endif
return std::pair<xact_t *, account_t *>
(best_xact, (*std::max_element(account_usage.begin(), account_usage.end(),
- usage_sorter())).first);
+ usage_sorter())).first);
} else {
return std::pair<xact_t *, account_t *>(best_xact, NULL);
}
diff --git a/src/lookup.h b/src/lookup.h
index 53cb5837..7776be80 100644
--- a/src/lookup.h
+++ b/src/lookup.h
@@ -48,8 +48,8 @@ namespace ledger {
std::pair<xact_t *, account_t *>
lookup_probable_account(const string& ident,
- xacts_iterator& iter_func,
- account_t * ref_account = NULL);
+ xacts_iterator& iter_func,
+ account_t * ref_account = NULL);
} // namespace ledger
diff --git a/src/main.cc b/src/main.cc
index 23593533..ef611f51 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -31,8 +31,8 @@
#include <system.hh>
-#include "global.h" // This is where the meat of main() is, which
- // was moved there for the sake of clarity here
+#include "global.h" // This is where the meat of main() is, which
+ // was moved there for the sake of clarity here
#include "session.h"
using namespace ledger;
@@ -70,7 +70,9 @@ int main(int argc, char * argv[], char * envp[])
filesystem::path::default_name_check(filesystem::portable_posix_name);
std::signal(SIGINT, sigint_handler);
+#ifndef WIN32
std::signal(SIGPIPE, sigpipe_handler);
+#endif
#if defined(HAVE_GETTEXT)
::textdomain("ledger");
@@ -103,13 +105,13 @@ int main(int argc, char * argv[], char * envp[])
ifstream in(global_scope->HANDLER(script_).str());
while (status == 0 && ! in.eof()) {
- char line[1024];
- in.getline(line, 1023);
+ char line[1024];
+ in.getline(line, 1023);
- char * p = skip_ws(line);
- if (*p && *p != '#')
- status = global_scope->execute_command_wrapper(split_arguments(p),
- true);
+ char * p = skip_ws(line);
+ if (*p && *p != '#')
+ status = global_scope->execute_command_wrapper(split_arguments(p),
+ true);
}
}
else if (! args.empty()) {
@@ -133,53 +135,53 @@ int main(int argc, char * argv[], char * envp[])
#endif
while (char * p = readline(global_scope->prompt_string())) {
- char * expansion = NULL;
- int result;
-
- result = history_expand(skip_ws(p), &expansion);
-
- if (result < 0 || result == 2) {
- if (expansion)
- std::free(expansion);
- std::free(p);
- throw_(std::logic_error,
- _("Failed to expand history reference '%1'") << p);
- }
- else if (expansion) {
- add_history(expansion);
- }
+ char * expansion = NULL;
+ int result;
+
+ result = history_expand(skip_ws(p), &expansion);
+
+ if (result < 0 || result == 2) {
+ if (expansion)
+ std::free(expansion);
+ std::free(p);
+ throw_(std::logic_error,
+ _("Failed to expand history reference '%1'") << p);
+ }
+ else if (expansion) {
+ add_history(expansion);
+ }
#else // HAVE_LIBEDIT
while (! std::cin.eof()) {
- std::cout << global_scope->prompt_string();
- char line[1024];
- std::cin.getline(line, 1023);
+ std::cout << global_scope->prompt_string();
+ char line[1024];
+ std::cin.getline(line, 1023);
- char * p = skip_ws(line);
+ char * p = skip_ws(line);
#endif // HAVE_LIBEDIT
- check_for_signal();
+ check_for_signal();
- if (*p && *p != '#') {
- if (std::strncmp(p, "quit", 4) == 0)
- exit_loop = true;
- else
- global_scope->execute_command_wrapper(split_arguments(p), true);
- }
+ if (*p && *p != '#') {
+ if (std::strncmp(p, "quit", 4) == 0)
+ exit_loop = true;
+ else
+ global_scope->execute_command_wrapper(split_arguments(p), true);
+ }
#ifdef HAVE_LIBEDIT
- if (expansion)
- std::free(expansion);
- std::free(p);
+ if (expansion)
+ std::free(expansion);
+ std::free(p);
#endif
- if (exit_loop)
- break;
+ if (exit_loop)
+ break;
}
- status = 0; // report success
+ status = 0; // report success
}
}
catch (const std::exception& err) {
@@ -187,11 +189,11 @@ int main(int argc, char * argv[], char * envp[])
global_scope->report_error(err);
else
std::cerr << "Exception during initialization: " << err.what()
- << std::endl;
+ << std::endl;
}
catch (int _status) {
- status = _status; // used for a "quick" exit, and is used only
- // if help text (such as --help) was displayed
+ status = _status; // used for a "quick" exit, and is used only
+ // if help text (such as --help) was displayed
}
// If memory verification is being performed (which can be very slow), clean
diff --git a/src/mask.cc b/src/mask.cc
index cd516fe2..52907cfe 100644
--- a/src/mask.cc
+++ b/src/mask.cc
@@ -66,17 +66,17 @@ mask_t& mask_t::assign_glob(const string& pat)
break;
case '[':
while (i < len && pat[i] != ']')
- re_pat += pat[i++];
+ re_pat += pat[i++];
if (i < len)
- re_pat += pat[i];
+ re_pat += pat[i];
break;
case '\\':
if (i + 1 < len) {
- re_pat += pat[++i];
- break;
+ re_pat += pat[++i];
+ break;
} else {
- // fallthrough...
+ // fallthrough...
}
default:
re_pat += pat[i];
diff --git a/src/mask.h b/src/mask.h
index ed9e8ac1..e72347ad 100644
--- a/src/mask.h
+++ b/src/mask.h
@@ -85,13 +85,13 @@ public:
bool match(const string& text) const {
#if defined(HAVE_BOOST_REGEX_UNICODE)
DEBUG("mask.match",
- "Matching: \"" << text << "\" =~ /" << str() << "/ = "
- << (boost::u32regex_search(text, expr) ? "true" : "false"));
+ "Matching: \"" << text << "\" =~ /" << str() << "/ = "
+ << (boost::u32regex_search(text, expr) ? "true" : "false"));
return boost::u32regex_search(text, expr);
#else
DEBUG("mask.match",
- "Matching: \"" << text << "\" =~ /" << str() << "/ = "
- << (boost::regex_search(text, expr) ? "true" : "false"));
+ "Matching: \"" << text << "\" =~ /" << str() << "/ = "
+ << (boost::regex_search(text, expr) ? "true" : "false"));
return boost::regex_search(text, expr);
#endif
}
@@ -107,7 +107,7 @@ public:
unistring ustr;
std::basic_string<UChar32> expr_str = expr.str();
std::copy(expr_str.begin(), expr_str.end(),
- std::back_inserter(ustr.utf32chars));
+ std::back_inserter(ustr.utf32chars));
return ustr.extract();
#else
return expr.str();
diff --git a/src/op.cc b/src/op.cc
index ca720535..86057f66 100644
--- a/src/op.cc
+++ b/src/op.cc
@@ -39,33 +39,40 @@
namespace ledger {
namespace {
- value_t split_cons_expr(expr_t::ptr_op_t op, scope_t& scope,
- std::vector<expr_t>& exprs)
+ value_t split_cons_expr(expr_t::ptr_op_t op)
{
- value_t seq;
-
if (op->kind == expr_t::op_t::O_CONS) {
- exprs.push_back(expr_t(op->left(), &scope));
- seq.push_back(value_t(exprs.back()));
+ value_t seq;
+ seq.push_back(expr_value(op->left()));
expr_t::ptr_op_t next = op->right();
while (next) {
- expr_t::ptr_op_t value_op;
- if (next->kind == expr_t::op_t::O_CONS) {
- value_op = next->left();
- next = next->right();
- } else {
- value_op = next;
- next = NULL;
- }
- exprs.push_back(expr_t(value_op, &scope));
- seq.push_back(value_t(exprs.back()));
+ expr_t::ptr_op_t value_op;
+ if (next->kind == expr_t::op_t::O_CONS) {
+ value_op = next->left();
+ next = next->right();
+ } else {
+ value_op = next;
+ next = NULL;
+ }
+ seq.push_back(expr_value(value_op));
}
+ return seq;
} else {
- exprs.push_back(expr_t(op, &scope));
- seq.push_back(value_t(exprs.back()));
+ return expr_value(op);
+ }
+ }
+
+ inline void check_type_context(scope_t& scope, value_t& result)
+ {
+ if (scope.type_required() &&
+ scope.type_context() != value_t::VOID &&
+ result.type() != scope.type_context()) {
+ throw_(calc_error,
+ _("Expected return of %1, but received %2")
+ << result.label(scope.type_context())
+ << result.label());
}
- return seq;
}
}
@@ -80,8 +87,8 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
// not be found there.
#if defined(DEBUG_ON)
if (SHOW_DEBUG("expr.compile")) {
- DEBUG("expr.compile", "Found definition:");
- def->dump(*_log_stream, 0);
+ DEBUG("expr.compile", "Found definition:");
+ def->dump(*_log_stream, 0);
}
#endif // defined(DEBUG_ON)
return copy(def);
@@ -101,10 +108,15 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
scope.define(symbol_t::FUNCTION, left()->as_ident(), right());
break;
case O_CALL:
- if (left()->left()->is_ident())
- scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), this);
- else
- throw_(compile_error, _("Invalid function definition"));
+ if (left()->left()->is_ident()) {
+ ptr_op_t node(new op_t(op_t::O_LAMBDA));
+ node->set_left(left()->right());
+ node->set_right(right());
+
+ scope.define(symbol_t::FUNCTION, left()->left()->as_ident(), node);
+ } else {
+ throw_(compile_error, _("Invalid function definition"));
+ }
break;
default:
throw_(compile_error, _("Invalid function definition"));
@@ -114,8 +126,8 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth)
ptr_op_t lhs(left()->compile(scope, depth));
ptr_op_t rhs(kind > UNARY_OPERATORS && has_right() ?
- (kind == O_LOOKUP ? right() :
- right()->compile(scope, depth)) : NULL);
+ (kind == O_LOOKUP ? right() :
+ right()->compile(scope, depth)) : NULL);
if (lhs == left() && (! rhs || rhs == right()))
return this;
@@ -144,15 +156,22 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
break;
case IDENT: {
- if (! left())
+ ptr_op_t definition = left();
+ if (! definition) {
+ // If no definition was pre-compiled for this identifier, look it
+ // up in the current scope.
+ definition = scope.lookup(symbol_t::FUNCTION, as_ident());
+ }
+ if (! definition)
throw_(calc_error, _("Unknown identifier '%1'") << as_ident());
// Evaluating an identifier is the same as calling its definition
// directly, so we create an empty call_scope_t to reflect the scope for
// this implicit call.
- call_scope_t call_args(scope);
- result = left()->compile(call_args, depth + 1)
- ->calc(call_args, locus, depth + 1);
+ call_scope_t call_args(scope, locus, depth);
+ result = definition->compile(call_args, depth + 1)
+ ->calc(call_args, locus, depth + 1);
+ check_type_context(scope, result);
break;
}
@@ -160,143 +179,129 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
// Evaluating a FUNCTION is the same as calling it directly; this happens
// when certain functions-that-look-like-variables (such as "amount") are
// resolved.
- call_scope_t call_args(scope);
+ call_scope_t call_args(scope, locus, depth);
result = as_function()(call_args);
+ check_type_context(scope, result);
#if defined(DEBUG_ON)
skip_debug = true;
#endif
break;
}
- case O_DEFINE: {
+ case O_LAMBDA: {
call_scope_t& call_args(downcast<call_scope_t>(scope));
- std::size_t args_count = call_args.size();
- std::size_t args_index = 0;
-
- assert(left()->kind == O_CALL);
+ std::size_t args_count(call_args.size());
+ std::size_t args_index(0);
+ symbol_scope_t call_scope(call_args);
+ ptr_op_t sym(left());
- for (ptr_op_t sym = left()->right();
- sym;
- sym = sym->has_right() ? sym->right() : NULL) {
+ for (; sym; sym = sym->has_right() ? sym->right() : NULL) {
ptr_op_t varname = sym;
if (sym->kind == O_CONS)
- varname = sym->left();
+ varname = sym->left();
- if (! varname->is_ident())
- throw_(calc_error, _("Invalid function definition"));
- else if (args_index == args_count)
- scope.define(symbol_t::FUNCTION, varname->as_ident(),
- wrap_value(false));
- else
- scope.define(symbol_t::FUNCTION, varname->as_ident(),
- wrap_value(call_args[args_index++]));
+ if (! varname->is_ident()) {
+ throw_(calc_error, _("Invalid function definition"));
+ }
+ else if (args_index == args_count) {
+ call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
+ wrap_value(NULL_VALUE));
+ }
+ else {
+ DEBUG("expr.compile",
+ "Defining function parameter " << varname->as_ident());
+ call_scope.define(symbol_t::FUNCTION, varname->as_ident(),
+ wrap_value(call_args[args_index++]));
+ }
}
if (args_index < args_count)
throw_(calc_error,
- _("Too many arguments in function call (saw %1)") << args_count);
+ _("Too few arguments in function call (saw %1)") << args_count);
- result = right()->calc(scope, locus, depth + 1);
+ result = right()->calc(call_scope, locus, depth + 1);
break;
}
- case O_LOOKUP:
- if (value_t obj = left()->calc(scope, locus, depth + 1)) {
- if (obj.is_scope()) {
- if (obj.as_scope() == NULL) {
- throw_(calc_error, _("Left operand of . operator is NULL"));
- } else {
- scope_t& objscope(*obj.as_scope());
- if (ptr_op_t member =
- objscope.lookup(symbol_t::FUNCTION, right()->as_ident())) {
- result = member->calc(objscope, NULL, depth + 1);
- break;
- }
- }
+ case O_LOOKUP: {
+ context_scope_t context_scope(scope, value_t::SCOPE);
+ bool scope_error = true;
+ if (value_t obj = left()->calc(context_scope, locus, depth + 1)) {
+ if (obj.is_scope() && obj.as_scope() != NULL) {
+ bind_scope_t bound_scope(scope, *obj.as_scope());
+ result = right()->calc(bound_scope, locus, depth + 1);
+ scope_error = false;
}
}
- if (right()->kind != IDENT)
- throw_(calc_error,
- _("Right operand of . operator must be an identifier"));
- else
- throw_(calc_error,
- _("Failed to lookup member '%1'") << right()->as_ident());
+ if (scope_error)
+ throw_(calc_error, _("Left operand does not evaluate to an object"));
break;
+ }
- case O_CALL:
- case O_EXPAND: {
- call_scope_t call_args(scope);
- // When evaluating a macro call, these expressions have to live beyond the
- // call to calc() below.
- optional<std::vector<expr_t> > args_expr;
-
- if (has_right()) {
- if (kind == O_CALL) {
- call_args.set_args(right()->calc(scope, locus, depth + 1));
- } else {
- // macros defer calculation to the callee
- args_expr = std::vector<expr_t>();
- call_args.set_args(split_cons_expr(right()->kind == O_SEQ ?
- right()->left() : right(),
- scope, *args_expr));
- }
- }
+ case O_CALL: {
+ call_scope_t call_args(scope, locus, depth);
+ if (has_right())
+ call_args.set_args(split_cons_expr(right()));
ptr_op_t func = left();
const string& name(func->as_ident());
func = func->left();
if (! func)
+ func = scope.lookup(symbol_t::FUNCTION, name);
+ if (! func)
throw_(calc_error, _("Calling unknown function '%1'") << name);
if (func->is_function())
result = func->as_function()(call_args);
else
result = func->calc(call_args, locus, depth + 1);
+
+ check_type_context(scope, result);
break;
}
case O_MATCH:
result = (right()->calc(scope, locus, depth + 1).as_mask()
- .match(left()->calc(scope, locus, depth + 1).to_string()));
+ .match(left()->calc(scope, locus, depth + 1).to_string()));
break;
case O_EQ:
result = (left()->calc(scope, locus, depth + 1) ==
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_LT:
result = (left()->calc(scope, locus, depth + 1) <
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_LTE:
result = (left()->calc(scope, locus, depth + 1) <=
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_GT:
result = (left()->calc(scope, locus, depth + 1) >
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_GTE:
result = (left()->calc(scope, locus, depth + 1) >=
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_ADD:
result = (left()->calc(scope, locus, depth + 1) +
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_SUB:
result = (left()->calc(scope, locus, depth + 1) -
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_MUL:
result = (left()->calc(scope, locus, depth + 1) *
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_DIV:
result = (left()->calc(scope, locus, depth + 1) /
- right()->calc(scope, locus, depth + 1));
+ right()->calc(scope, locus, depth + 1));
break;
case O_NEG:
@@ -345,16 +350,16 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
ptr_op_t next = right();
while (next) {
- ptr_op_t value_op;
- if (next->kind == O_CONS) {
- value_op = next->left();
- next = next->right();
- } else {
- value_op = next;
- next = NULL;
- }
- temp.push_back(value_op->calc(scope, locus, depth + 1));
- DEBUG("op.cons", "temp now = " << temp);
+ ptr_op_t value_op;
+ if (next->kind == O_CONS) {
+ value_op = next->left();
+ next = next->right();
+ } else {
+ value_op = next;
+ next = NULL;
+ }
+ temp.push_back(value_op->calc(scope, locus, depth + 1));
+ DEBUG("op.cons", "temp now = " << temp);
}
result = temp;
}
@@ -373,15 +378,15 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
if (has_right()) {
ptr_op_t next = right();
while (next) {
- ptr_op_t value_op;
- if (next->kind == O_SEQ) {
- value_op = next->left();
- next = next->right();
- } else {
- value_op = next;
- next = NULL;
- }
- result = value_op->calc(seq_scope, locus, depth + 1);
+ ptr_op_t value_op;
+ if (next->kind == O_SEQ) {
+ value_op = next->left();
+ next = next->right();
+ } else {
+ value_op = next;
+ next = NULL;
+ }
+ result = value_op->calc(seq_scope, locus, depth + 1);
}
}
break;
@@ -406,7 +411,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
return result;
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (locus && ! *locus)
*locus = this;
throw;
@@ -415,7 +420,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
namespace {
bool print_cons(std::ostream& out, const expr_t::const_ptr_op_t op,
- const expr_t::op_t::context_t& context)
+ const expr_t::op_t::context_t& context)
{
bool found = false;
@@ -426,15 +431,15 @@ namespace {
if (op->has_right()) {
out << ", ";
if (op->right()->kind == expr_t::op_t::O_CONS)
- found = print_cons(out, op->right(), context);
+ found = print_cons(out, op->right(), context);
else if (op->right()->print(out, context))
- found = true;
+ found = true;
}
return found;
}
bool print_seq(std::ostream& out, const expr_t::const_ptr_op_t op,
- const expr_t::op_t::context_t& context)
+ const expr_t::op_t::context_t& context)
{
bool found = false;
@@ -446,9 +451,9 @@ namespace {
out << "; ";
if (op->right()->kind == expr_t::op_t::O_CONS)
- found = print_cons(out, op->right(), context);
+ found = print_cons(out, op->right(), context);
else if (op->right()->print(out, context))
- found = true;
+ found = true;
}
return found;
@@ -467,6 +472,9 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
string symbol;
+ if (kind > TERMINALS && (kind != O_CALL && kind != O_DEFINE))
+ out << '(';
+
switch (kind) {
case VALUE:
as_value().dump(out, context.relaxed);
@@ -481,118 +489,94 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
break;
case O_NOT:
- out << "!(";
+ out << "! ";
if (left() && left()->print(out, context))
found = true;
- out << ")";
break;
case O_NEG:
- out << "-(";
+ out << "- ";
if (left() && left()->print(out, context))
found = true;
- out << ")";
break;
case O_ADD:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " + ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_SUB:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " - ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_MUL:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " * ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_DIV:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " / ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_EQ:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " == ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_LT:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " < ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_LTE:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " <= ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_GT:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " > ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_GTE:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " >= ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_AND:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " & ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_OR:
- out << "(";
if (left() && left()->print(out, context))
found = true;
out << " | ";
if (has_right() && right()->print(out, context))
found = true;
- out << ")";
break;
case O_QUERY:
@@ -616,15 +600,13 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
break;
case O_SEQ:
- out << "(";
found = print_seq(out, this, context);
- out << ")";
break;
case O_DEFINE:
if (left() && left()->print(out, context))
found = true;
- out << " := ";
+ out << " = ";
if (has_right() && right()->print(out, context))
found = true;
break;
@@ -637,19 +619,26 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
found = true;
break;
+ case O_LAMBDA:
+ if (left() && left()->print(out, context))
+ found = true;
+ out << " -> ";
+ if (has_right() && right()->print(out, context))
+ found = true;
+ break;
+
case O_CALL:
- case O_EXPAND:
if (left() && left()->print(out, context))
found = true;
if (has_right()) {
- if (right()->kind == O_SEQ) {
- if (right()->print(out, context))
- found = true;
+ if (right()->kind == O_CONS) {
+ if (right()->print(out, context))
+ found = true;
} else {
- out << "(";
- if (has_right() && right()->print(out, context))
- found = true;
- out << ")";
+ out << "(";
+ if (has_right() && right()->print(out, context))
+ found = true;
+ out << ")";
}
} else {
out << "()";
@@ -670,6 +659,9 @@ bool expr_t::op_t::print(std::ostream& out, const context_t& context) const
break;
}
+ if (kind > TERMINALS && (kind != O_CALL && kind != O_DEFINE))
+ out << ')';
+
if (! symbol.empty()) {
if (commodity_pool_t::current_pool->find(symbol))
out << '@';
@@ -709,32 +701,32 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
case O_DEFINE: out << "O_DEFINE"; break;
case O_LOOKUP: out << "O_LOOKUP"; break;
- case O_CALL: out << "O_CALL"; break;
- case O_EXPAND: out << "O_EXPAND"; break;
- case O_MATCH: out << "O_MATCH"; break;
+ case O_LAMBDA: out << "O_LAMBDA"; break;
+ case O_CALL: out << "O_CALL"; break;
+ case O_MATCH: out << "O_MATCH"; break;
- case O_NOT: out << "O_NOT"; break;
- case O_NEG: out << "O_NEG"; break;
+ case O_NOT: out << "O_NOT"; break;
+ case O_NEG: out << "O_NEG"; break;
- case O_ADD: out << "O_ADD"; break;
- case O_SUB: out << "O_SUB"; break;
- case O_MUL: out << "O_MUL"; break;
- case O_DIV: out << "O_DIV"; break;
+ case O_ADD: out << "O_ADD"; break;
+ case O_SUB: out << "O_SUB"; break;
+ case O_MUL: out << "O_MUL"; break;
+ case O_DIV: out << "O_DIV"; break;
- case O_EQ: out << "O_EQ"; break;
- case O_LT: out << "O_LT"; break;
- case O_LTE: out << "O_LTE"; break;
- case O_GT: out << "O_GT"; break;
- case O_GTE: out << "O_GTE"; break;
+ case O_EQ: out << "O_EQ"; break;
+ case O_LT: out << "O_LT"; break;
+ case O_LTE: out << "O_LTE"; break;
+ case O_GT: out << "O_GT"; break;
+ case O_GTE: out << "O_GTE"; break;
- case O_AND: out << "O_AND"; break;
- case O_OR: out << "O_OR"; break;
+ case O_AND: out << "O_AND"; break;
+ case O_OR: out << "O_OR"; break;
case O_QUERY: out << "O_QUERY"; break;
- case O_COLON: out << "O_COLON"; break;
+ case O_COLON: out << "O_COLON"; break;
- case O_CONS: out << "O_CONS"; break;
- case O_SEQ: out << "O_SEQ"; break;
+ case O_CONS: out << "O_CONS"; break;
+ case O_SEQ: out << "O_SEQ"; break;
case LAST:
default:
@@ -750,7 +742,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
if (left()) {
left()->dump(out, depth + 1);
if (kind > UNARY_OPERATORS && has_right())
- right()->dump(out, depth + 1);
+ right()->dump(out, depth + 1);
}
else if (kind > UNARY_OPERATORS) {
assert(! has_right());
@@ -759,7 +751,7 @@ void expr_t::op_t::dump(std::ostream& out, const int depth) const
}
string op_context(const expr_t::ptr_op_t op,
- const expr_t::ptr_op_t locus)
+ const expr_t::ptr_op_t locus)
{
ostream_pos_type start_pos, end_pos;
expr_t::op_t::context_t context(op, locus, &start_pos, &end_pos);
@@ -769,9 +761,9 @@ string op_context(const expr_t::ptr_op_t op,
buf << "\n";
for (int i = 0; i <= end_pos; i++) {
if (i > start_pos)
- buf << "^";
+ buf << "^";
else
- buf << " ";
+ buf << " ";
}
}
return buf.str();
diff --git a/src/op.h b/src/op.h
index 936c11f4..6f7d7904 100644
--- a/src/op.h
+++ b/src/op.h
@@ -56,13 +56,13 @@ public:
private:
mutable short refc;
- ptr_op_t left_;
+ ptr_op_t left_;
- variant<ptr_op_t, // used by all binary operators
- value_t, // used by constant VALUE
- string, // used by constant IDENT
- expr_t::func_t // used by terminal FUNCTION
- > data;
+ variant<ptr_op_t, // used by all binary operators
+ value_t, // used by constant VALUE
+ string, // used by constant IDENT
+ expr_t::func_t // used by terminal FUNCTION
+ > data;
public:
enum kind_t {
@@ -104,8 +104,8 @@ public:
O_DEFINE,
O_LOOKUP,
+ O_LAMBDA,
O_CALL,
- O_EXPAND,
O_MATCH,
BINARY_OPERATORS,
@@ -225,13 +225,13 @@ public:
private:
void acquire() const {
DEBUG("op.memory",
- "Acquiring " << this << ", refc now " << refc + 1);
+ "Acquiring " << this << ", refc now " << refc + 1);
assert(refc >= 0);
refc++;
}
void release() const {
DEBUG("op.memory",
- "Releasing " << this << ", refc now " << refc - 1);
+ "Releasing " << this << ", refc now " << refc - 1);
assert(refc > 0);
if (--refc == 0)
checked_delete(this);
@@ -253,35 +253,37 @@ private:
public:
static ptr_op_t new_node(kind_t _kind, ptr_op_t _left = NULL,
- ptr_op_t _right = NULL);
+ ptr_op_t _right = NULL);
ptr_op_t compile(scope_t& scope, const int depth = 0);
value_t calc(scope_t& scope, ptr_op_t * locus = NULL,
- const int depth = 0);
+ const int depth = 0);
struct context_t
{
- ptr_op_t expr_op;
- ptr_op_t op_to_find;
+ ptr_op_t expr_op;
+ ptr_op_t op_to_find;
ostream_pos_type * start_pos;
ostream_pos_type * end_pos;
- bool relaxed;
+ bool relaxed;
- context_t(const ptr_op_t& _expr_op = NULL,
- const ptr_op_t& _op_to_find = NULL,
- ostream_pos_type * const _start_pos = NULL,
- ostream_pos_type * const _end_pos = NULL,
- const bool _relaxed = true)
+ context_t() : start_pos(NULL), end_pos(NULL), relaxed(false) {}
+
+ context_t(const ptr_op_t& _expr_op,
+ const ptr_op_t& _op_to_find,
+ ostream_pos_type * const _start_pos = NULL,
+ ostream_pos_type * const _end_pos = NULL,
+ const bool _relaxed = true)
: expr_op(_expr_op), op_to_find(_op_to_find),
- start_pos(_start_pos), end_pos(_end_pos),
- relaxed(_relaxed) {}
+ start_pos(_start_pos), end_pos(_end_pos),
+ relaxed(_relaxed) {}
};
bool print(std::ostream& out, const context_t& context = context_t()) const;
- void dump(std::ostream& out, const int depth) const;
+ void dump(std::ostream& out, const int depth = 0) const;
static ptr_op_t wrap_value(const value_t& val);
- static ptr_op_t wrap_functor(const expr_t::func_t& fobj);
+ static ptr_op_t wrap_functor(expr_t::func_t fobj);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
@@ -300,8 +302,8 @@ private:
ar & temp_op;
}
if (Archive::is_loading::value || kind == VALUE || kind == IDENT ||
- (kind > UNARY_OPERATORS &&
- (! has_right() || ! right()->is_function()))) {
+ (kind > UNARY_OPERATORS &&
+ (! has_right() || ! right()->is_function()))) {
ar & data;
} else {
variant<ptr_op_t, value_t, string, expr_t::func_t> temp_data;
@@ -327,7 +329,7 @@ inline expr_t::ptr_op_t expr_t::op_t::wrap_value(const value_t& val) {
}
inline expr_t::ptr_op_t
-expr_t::op_t::wrap_functor(const expr_t::func_t& fobj) {
+expr_t::op_t::wrap_functor(expr_t::func_t fobj) {
ptr_op_t temp(new op_t(op_t::FUNCTION));
temp->set_function(fobj);
return temp;
@@ -337,7 +339,7 @@ expr_t::op_t::wrap_functor(const expr_t::func_t& fobj) {
#define WRAP_FUNCTOR(x) expr_t::op_t::wrap_functor(x)
string op_context(const expr_t::ptr_op_t op,
- const expr_t::ptr_op_t locus = NULL);
+ const expr_t::ptr_op_t locus = NULL);
} // namespace ledger
diff --git a/src/option.cc b/src/option.cc
index b375dd8d..dae0f0af 100644
--- a/src/option.cc
+++ b/src/option.cc
@@ -44,9 +44,9 @@ namespace {
char * p = buf;
foreach (char ch, name) {
if (ch == '-')
- *p++ = '_';
+ *p++ = '_';
else
- *p++ = ch;
+ *p++ = ch;
}
*p++ = '_';
*p = '\0';
@@ -75,30 +75,30 @@ namespace {
}
void process_option(const string& whence, const expr_t::func_t& opt,
- scope_t& scope, const char * arg, const string& name)
+ scope_t& scope, const char * arg, const string& name)
{
try {
call_scope_t args(scope);
args.push_back(string_value(whence));
if (arg)
- args.push_back(string_value(arg));
+ args.push_back(string_value(arg));
opt(args);
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (name[0] == '-')
- add_error_context(_("While parsing option '%1'") << name);
-
+ add_error_context(_("While parsing option '%1'") << name);
+
else
- add_error_context(_("While parsing environent variable '%1'") << name);
+ add_error_context(_("While parsing environent variable '%1'") << name);
throw;
}
}
}
bool process_option(const string& whence, const string& name, scope_t& scope,
- const char * arg, const string& varname)
+ const char * arg, const string& varname)
{
op_bool_tuple opt(find_option(scope, name));
if (opt.first) {
@@ -109,9 +109,9 @@ bool process_option(const string& whence, const string& name, scope_t& scope,
}
void process_environment(const char ** envp, const string& tag,
- scope_t& scope)
+ scope_t& scope)
{
- const char * tag_p = tag.c_str();
+ const char * tag_p = tag.c_str();
string::size_type tag_len = tag.length();
assert(tag_p);
@@ -123,25 +123,25 @@ void process_environment(const char ** envp, const string& tag,
char * r = buf;
const char * q;
for (q = *p + tag_len;
- *q && *q != '=' && r - buf < 8191;
- q++)
- if (*q == '_')
- *r++ = '-';
- else
- *r++ = static_cast<char>(std::tolower(*q));
+ *q && *q != '=' && r - buf < 8191;
+ q++)
+ if (*q == '_')
+ *r++ = '-';
+ else
+ *r++ = static_cast<char>(std::tolower(*q));
*r = '\0';
if (*q == '=') {
- try {
- string value = string(*p, q - *p);
- if (! value.empty())
- process_option(string("$") + buf, string(buf), scope, q + 1, value);
- }
- catch (const std::exception& err) {
- add_error_context(_("While parsing environment variable option '%1':")
- << *p);
- throw;
- }
+ try {
+ string value = string(*p, q - *p);
+ if (! value.empty())
+ process_option(string("$") + buf, string(buf), scope, q + 1, value);
+ }
+ catch (const std::exception&) {
+ add_error_context(_("While parsing environment variable option '%1':")
+ << *p);
+ throw;
+ }
}
}
}
@@ -178,9 +178,9 @@ strings_list process_arguments(strings_list args, scope_t& scope)
// --long-option or -s
if ((*i)[1] == '-') {
if ((*i)[2] == '\0') {
- DEBUG("option.args", " it's a --, ending options processing");
- anywhere = false;
- continue;
+ DEBUG("option.args", " it's a --, ending options processing");
+ anywhere = false;
+ continue;
}
DEBUG("option.args", " it's an option string");
@@ -190,26 +190,26 @@ strings_list process_arguments(strings_list args, scope_t& scope)
const char * value = NULL;
if (const char * p = std::strchr(name, '=')) {
- opt_name = string(name, p - name);
- value = ++p;
- DEBUG("option.args", " read option value from option: " << value);
+ opt_name = string(name, p - name);
+ value = ++p;
+ DEBUG("option.args", " read option value from option: " << value);
} else {
- opt_name = name;
+ opt_name = name;
}
op_bool_tuple opt(find_option(scope, opt_name));
if (! opt.first)
- throw_(option_error, _("Illegal option --%1") << name);
+ throw_(option_error, _("Illegal option --%1") << name);
if (opt.second && ! value && ++i != args.end() && value == NULL) {
- value = (*i).c_str();
- DEBUG("option.args", " read option value from arg: " << value);
- if (value == NULL)
- throw_(option_error, _("Missing option argument for --%1") << name);
+ value = (*i).c_str();
+ DEBUG("option.args", " read option value from arg: " << value);
+ if (value == NULL)
+ throw_(option_error, _("Missing option argument for --%1") << name);
}
process_option(string("--") + name,
- opt.first->as_function(), scope, value,
- string("--") + name);
+ opt.first->as_function(), scope, value,
+ string("--") + name);
}
else if ((*i)[1] == '\0') {
throw_(option_error, _("illegal option -%1") << (*i)[0]);
@@ -221,24 +221,24 @@ strings_list process_arguments(strings_list args, scope_t& scope)
int x = 1;
for (char c = (*i)[x]; c != '\0'; x++, c = (*i)[x]) {
- op_bool_tuple opt(find_option(scope, c));
- if (! opt.first)
- throw_(option_error, _("Illegal option -%1") << c);
+ op_bool_tuple opt(find_option(scope, c));
+ if (! opt.first)
+ throw_(option_error, _("Illegal option -%1") << c);
- option_queue.push_back(op_bool_char_tuple(opt.first, opt.second, c));
+ option_queue.push_back(op_bool_char_tuple(opt.first, opt.second, c));
}
foreach (op_bool_char_tuple& o, option_queue) {
- const char * value = NULL;
- if (o.truth && ++i != args.end()) {
- value = (*i).c_str();
- DEBUG("option.args", " read option value from arg: " << value);
- if (value == NULL)
- throw_(option_error,
- _("Missing option argument for -%1") << o.ch);
- }
- process_option(string("-") + o.ch, o.op->as_function(), scope, value,
- string("-") + o.ch);
+ const char * value = NULL;
+ if (o.truth && ++i != args.end()) {
+ value = (*i).c_str();
+ DEBUG("option.args", " read option value from arg: " << value);
+ if (value == NULL)
+ throw_(option_error,
+ _("Missing option argument for -%1") << o.ch);
+ }
+ process_option(string("-") + o.ch, o.op->as_function(), scope, value,
+ string("-") + o.ch);
}
}
}
diff --git a/src/option.h b/src/option.h
index f11497a4..e2a4a839 100644
--- a/src/option.h
+++ b/src/option.h
@@ -52,10 +52,10 @@ template <typename T>
class option_t
{
protected:
- const char * name;
+ const char * name;
string::size_type name_len;
- const char ch;
- bool handled;
+ const char ch;
+ bool handled;
optional<string> source;
option_t& operator=(const option_t&);
@@ -63,7 +63,7 @@ protected:
public:
T * parent;
value_t value;
- bool wants_arg;
+ bool wants_arg;
option_t(const char * _name, const char _ch = '\0')
: name(_name), name_len(std::strlen(name)), ch(_ch),
@@ -93,11 +93,11 @@ public:
out.width(24);
out << std::right << desc();
if (wants_arg) {
- out << " = ";
- value.print(out, 42);
+ out << " = ";
+ value.print(out, 42);
} else {
- out.width(45);
- out << ' ';
+ out.width(45);
+ out << ' ';
}
out << std::left << *source << std::endl;
}
@@ -108,10 +108,10 @@ public:
out << "--";
for (const char * p = name; *p; p++) {
if (*p == '_') {
- if (*(p + 1))
- out << '-';
+ if (*(p + 1))
+ out << '-';
} else {
- out << *p;
+ out << *p;
}
}
if (ch)
@@ -145,7 +145,7 @@ public:
on_with(whence, string_value(str));
}
virtual void on_with(const optional<string>& whence,
- const value_t& val) {
+ const value_t& val) {
handled = true;
value = val;
source = whence;
@@ -162,12 +162,12 @@ public:
virtual void handler(call_scope_t& args) {
if (wants_arg) {
if (args.size() < 2)
- throw_(std::runtime_error, _("No argument provided for %1") << desc());
+ throw_(std::runtime_error, _("No argument provided for %1") << desc());
else if (args.size() > 2)
- throw_(std::runtime_error, _("To many arguments provided for %1") << desc());
+ throw_(std::runtime_error, _("To many arguments provided for %1") << desc());
else if (! args[0].is_string())
- throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
- on_with(args[0].as_string(), args[1]);
+ throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
+ on_with(args.get<string>(0), args[1]);
}
else if (args.size() < 1) {
throw_(std::runtime_error, _("No argument provided for %1") << desc());
@@ -176,7 +176,7 @@ public:
throw_(std::runtime_error, _("Context argument for %1 not a string") << desc());
}
else {
- on_only(args[0].as_string());
+ on_only(args.get<string>(0));
}
handler_thunk(args);
@@ -194,9 +194,9 @@ public:
}
else if (wants_arg) {
if (handled)
- return value;
+ return value;
else
- return NULL_VALUE;
+ return NULL_VALUE;
}
else {
return handled;
@@ -204,13 +204,13 @@ public:
}
};
-#define BEGIN(type, name) \
+#define BEGIN(type, name) \
struct name ## option_t : public option_t<type>
-#define CTOR(type, name) \
+#define CTOR(type, name) \
name ## option_t() : option_t<type>(#name)
-#define DECL1(type, name, vartype, var, value) \
- vartype var ; \
+#define DECL1(type, name, vartype, var, value) \
+ vartype var ; \
name ## option_t() : option_t<type>(#name), var(value)
#define DO() virtual void handler_thunk(call_scope_t&)
@@ -220,10 +220,10 @@ public:
#define COPY_OPT(name, other) name ## handler(other.name ## handler)
-#define MAKE_OPT_HANDLER(type, x) \
+#define MAKE_OPT_HANDLER(type, x) \
expr_t::op_t::wrap_functor(bind(&option_t<type>::handler_wrapper, x, _1))
-#define MAKE_OPT_FUNCTOR(type, x) \
+#define MAKE_OPT_FUNCTOR(type, x) \
expr_t::op_t::wrap_functor(bind(&option_t<type>::operator(), x, _1))
inline bool is_eq(const char * p, const char * n) {
@@ -236,57 +236,57 @@ inline bool is_eq(const char * p, const char * n) {
return *p == *n || (! *p && *n == '_' && ! *(n + 1));
}
-#define OPT(name) \
- if (is_eq(p, #name)) \
+#define OPT(name) \
+ if (is_eq(p, #name)) \
return ((name ## handler).parent = this, &(name ## handler))
-#define OPT_ALT(name, alt) \
- if (is_eq(p, #name) || is_eq(p, #alt)) \
+#define OPT_ALT(name, alt) \
+ if (is_eq(p, #name) || is_eq(p, #alt)) \
return ((name ## handler).parent = this, &(name ## handler))
-#define OPT_(name) \
- if (! *(p + 1) || \
- ((name ## handler).wants_arg && \
- *(p + 1) == '_' && ! *(p + 2)) || \
- is_eq(p, #name)) \
+#define OPT_(name) \
+ if (! *(p + 1) || \
+ ((name ## handler).wants_arg && \
+ *(p + 1) == '_' && ! *(p + 2)) || \
+ is_eq(p, #name)) \
return ((name ## handler).parent = this, &(name ## handler))
-#define OPT_CH(name) \
- if (! *(p + 1) || \
- ((name ## handler).wants_arg && \
- *(p + 1) == '_' && ! *(p + 2))) \
+#define OPT_CH(name) \
+ if (! *(p + 1) || \
+ ((name ## handler).wants_arg && \
+ *(p + 1) == '_' && ! *(p + 2))) \
return ((name ## handler).parent = this, &(name ## handler))
#define HANDLER(name) name ## handler
#define HANDLED(name) HANDLER(name)
-#define OPTION(type, name) \
- BEGIN(type, name) \
- { \
- CTOR(type, name) {} \
- } \
+#define OPTION(type, name) \
+ BEGIN(type, name) \
+ { \
+ CTOR(type, name) {} \
+ } \
END(name)
-#define OPTION_(type, name, body) \
- BEGIN(type, name) \
- { \
- CTOR(type, name) {} \
- body \
- } \
+#define OPTION_(type, name, body) \
+ BEGIN(type, name) \
+ { \
+ CTOR(type, name) {} \
+ body \
+ } \
END(name)
-#define OPTION__(type, name, body) \
- BEGIN(type, name) \
- { \
- body \
- } \
+#define OPTION__(type, name, body) \
+ BEGIN(type, name) \
+ { \
+ body \
+ } \
END(name)
bool process_option(const string& whence, const string& name, scope_t& scope,
- const char * arg, const string& varname);
+ const char * arg, const string& varname);
void process_environment(const char ** envp, const string& tag,
- scope_t& scope);
+ scope_t& scope);
strings_list process_arguments(strings_list args, scope_t& scope);
diff --git a/src/org.cc b/src/org.cc
new file mode 100644
index 00000000..7c8e8c0d
--- /dev/null
+++ b/src/org.cc
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+#include <system.hh>
+
+#include "org.h"
+#include "xact.h"
+#include "post.h"
+#include "account.h"
+#include "journal.h"
+#include "pool.h"
+#include "report.h"
+
+namespace ledger {
+
+posts_to_org_table::posts_to_org_table(report_t& _report,
+ const optional<string>& _prepend_format)
+ : report(_report), last_xact(NULL), last_post(NULL)
+{
+ TRACE_CTOR(posts_to_org_table, "report&, optional<string>");
+
+ first_line_format.parse_format
+ ("|%(format_date(date))"
+ "|%(code)"
+ "|%(payee)"
+ "|%(cleared ? \"*\" : (pending ? \"!\" : \"\"))"
+ "|%(display_account)"
+ "|%(scrub(top_amount(display_amount)))"
+ "|%(scrub(top_amount(display_total)))"
+ "|%(join(note | xact.note))\n");
+
+ next_lines_format.parse_format
+ ("|"
+ "|"
+ "|%(has_tag(\"Payee\") ? payee : \"\")"
+ "|%(cleared ? \"*\" : (pending ? \"!\" : \"\"))"
+ "|%(display_account)"
+ "|%(scrub(top_amount(display_amount)))"
+ "|%(scrub(top_amount(display_total)))"
+ "|%(join(note | xact.note))\n");
+
+ amount_lines_format.parse_format
+ ("|"
+ "|"
+ "|"
+ "|"
+ "|"
+ "|%(scrub(next_amount))"
+ "|%(scrub(next_total))"
+ "|\n");
+
+ if (_prepend_format)
+ prepend_format.parse_format(*_prepend_format);
+}
+
+void posts_to_org_table::flush()
+{
+ report.output_stream.flush();
+}
+
+void posts_to_org_table::operator()(post_t& post)
+{
+ if (! post.has_xdata() ||
+ ! post.xdata().has_flags(POST_EXT_DISPLAYED)) {
+ std::ostream& out(report.output_stream);
+
+ bind_scope_t bound_scope(report, post);
+
+ if (! header_printed) {
+ out << "|Date|Code|Payee|X|Account|Amount|Total|Note|\n"
+ << "|-|\n"
+ << "|||<20>|||<r>|<r>|<20>|\n";
+ header_printed = true;
+ }
+
+ if (! report_title.empty()) {
+ if (first_report_title)
+ first_report_title = false;
+ else
+ out << '\n';
+
+ value_scope_t val_scope(bound_scope, string_value(report_title));
+ format_t group_title_format(report.HANDLER(group_title_format_).str());
+
+ out << "|-|\n";
+ out << '|' << group_title_format(val_scope);
+ out << "|-|\n";
+
+ report_title = "";
+ }
+
+ if (prepend_format)
+ out << '|' << prepend_format(bound_scope);
+
+ if (last_xact != post.xact) {
+ out << first_line_format(bound_scope);
+ last_xact = post.xact;
+ }
+ else if (last_post && last_post->date() != post.date()) {
+ out << first_line_format(bound_scope);
+ }
+ else {
+ out << next_lines_format(bound_scope);
+ }
+
+ value_t amt = expr_t("display_amount").calc(bound_scope).simplified();
+ value_t tot = expr_t("display_total").calc(bound_scope).simplified();
+
+ if (amt.type() == value_t::BALANCE || tot.type() == value_t::BALANCE) {
+ balance_t amt_bal(amt.to_balance());
+ balance_t tot_bal(tot.to_balance());
+ balance_t::amounts_map::const_iterator i = amt_bal.amounts.begin();
+ balance_t::amounts_map::const_iterator j = tot_bal.amounts.begin();
+ bool first = true;
+ while (i != amt_bal.amounts.end() || j != tot_bal.amounts.end()) {
+ if (first) {
+ first = false;
+ if (i != amt_bal.amounts.end()) ++i;
+ if (j != tot_bal.amounts.end()) ++j;
+ } else {
+ symbol_scope_t call_scope(bound_scope);
+ bool assigned = false;
+
+ if (i != amt_bal.amounts.end()) {
+ if ((*i).second) {
+ DEBUG("org.next_amount", "next_amount = " << (*i).second);
+ call_scope.define(symbol_t::FUNCTION, "next_amount",
+ expr_t::op_t::wrap_value((*i++).second));
+ assigned = true;
+ } else {
+ call_scope.define(symbol_t::FUNCTION, "next_amount",
+ expr_t::op_t::wrap_value(string_value("")));
+ ++i;
+ }
+ } else {
+ call_scope.define(symbol_t::FUNCTION, "next_amount",
+ expr_t::op_t::wrap_value(string_value("")));
+ }
+
+ if (j != tot_bal.amounts.end()) {
+ if ((*j).second) {
+ DEBUG("org.next_total", "next_total = " << (*j).second);
+ call_scope.define(symbol_t::FUNCTION, "next_total",
+ expr_t::op_t::wrap_value((*j++).second));
+ DEBUG("org.next_total", "2.next_total = " <<
+ call_scope.lookup(symbol_t::FUNCTION,
+ "next_total")->as_value());
+ assigned = true;
+ } else {
+ call_scope.define(symbol_t::FUNCTION, "next_total",
+ expr_t::op_t::wrap_value(string_value("")));
+ ++j;
+ }
+ } else {
+ call_scope.define(symbol_t::FUNCTION, "next_total",
+ expr_t::op_t::wrap_value(string_value("")));
+ }
+
+ if (assigned) {
+ amount_lines_format.mark_uncompiled();
+ out << amount_lines_format(call_scope);
+ }
+ }
+ }
+ }
+
+ post.xdata().add_flags(POST_EXT_DISPLAYED);
+ last_post = &post;
+ }
+}
+
+} // namespace ledger
diff --git a/src/org.h b/src/org.h
new file mode 100644
index 00000000..ed023be2
--- /dev/null
+++ b/src/org.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup data
+ */
+
+/**
+ * @file org.h
+ * @author John Wiegley
+ *
+ * @ingroup data
+ */
+#ifndef _ORG_H
+#define _ORG_H
+
+#include "chain.h"
+#include "format.h"
+
+namespace ledger {
+
+class xact_t;
+class post_t;
+class report_t;
+
+class posts_to_org_table : public item_handler<post_t>
+{
+protected:
+ typedef std::list<xact_t *> xacts_list;
+ typedef std::map<xact_t *, bool> xacts_present_map;
+
+ report_t& report;
+ format_t first_line_format;
+ format_t next_lines_format;
+ format_t amount_lines_format;
+ format_t prepend_format;
+ xact_t * last_xact;
+ post_t * last_post;
+ bool header_printed;
+ bool first_report_title;
+ string report_title;
+
+public:
+ posts_to_org_table(report_t& _report,
+ const optional<string>& _prepend_format = none);
+ virtual ~posts_to_org_table() {
+ TRACE_DTOR(posts_to_org_table);
+ }
+
+ virtual void flush();
+ virtual void operator()(post_t& post);
+
+ virtual void clear() {
+ last_xact = NULL;
+ last_post = NULL;
+ header_printed = false;
+ first_report_title = true;
+ report_title = "";
+
+ item_handler<post_t>::clear();
+ }
+};
+
+} // namespace ledger
+
+#endif // _ORG_H
diff --git a/src/output.cc b/src/output.cc
index f697dee4..9d2e0cb6 100644
--- a/src/output.cc
+++ b/src/output.cc
@@ -40,10 +40,10 @@
namespace ledger {
-format_posts::format_posts(report_t& _report,
- const string& format,
- const optional<string>& _prepend_format,
- std::size_t _prepend_width)
+format_posts::format_posts(report_t& _report,
+ const string& format,
+ const optional<string>& _prepend_format,
+ std::size_t _prepend_width)
: report(_report), prepend_width(_prepend_width),
last_xact(NULL), last_post(NULL), first_report_title(true)
{
@@ -56,9 +56,9 @@ format_posts::format_posts(report_t& _report,
const char * n = p + 2;
if (const char * p = std::strstr(n, "%/")) {
next_lines_format.parse_format(string(n, 0, p - n),
- first_line_format);
+ first_line_format);
between_format.parse_format(string(p + 2),
- first_line_format);
+ first_line_format);
} else {
next_lines_format.parse_format(string(n), first_line_format);
}
@@ -86,18 +86,14 @@ void format_posts::operator()(post_t& post)
if (! report_title.empty()) {
if (first_report_title)
- first_report_title = false;
+ first_report_title = false;
else
- out << '\n';
+ out << '\n';
- value_scope_t val_scope(string_value(report_title));
- bind_scope_t inner_scope(bound_scope, val_scope);
-
- format_t group_title_format;
- group_title_format
- .parse_format(report.HANDLER(group_title_format_).str());
+ value_scope_t val_scope(bound_scope, string_value(report_title));
+ format_t group_title_format(report.HANDLER(group_title_format_).str());
- out << group_title_format(inner_scope);
+ out << group_title_format(val_scope);
report_title = "";
}
@@ -109,8 +105,8 @@ void format_posts::operator()(post_t& post)
if (last_xact != post.xact) {
if (last_xact) {
- bind_scope_t xact_scope(report, *last_xact);
- out << between_format(xact_scope);
+ bind_scope_t xact_scope(report, *last_xact);
+ out << between_format(xact_scope);
}
out << first_line_format(bound_scope);
last_xact = post.xact;
@@ -127,10 +123,10 @@ void format_posts::operator()(post_t& post)
}
}
-format_accounts::format_accounts(report_t& _report,
- const string& format,
- const optional<string>& _prepend_format,
- std::size_t _prepend_width)
+format_accounts::format_accounts(report_t& _report,
+ const string& format,
+ const optional<string>& _prepend_format,
+ std::size_t _prepend_width)
: report(_report), prepend_width(_prepend_width), disp_pred(),
first_report_title(true)
{
@@ -172,18 +168,14 @@ std::size_t format_accounts::post_account(account_t& account, const bool flat)
if (! report_title.empty()) {
if (first_report_title)
- first_report_title = false;
+ first_report_title = false;
else
- out << '\n';
+ out << '\n';
- value_scope_t val_scope(string_value(report_title));
- bind_scope_t inner_scope(bound_scope, val_scope);
-
- format_t group_title_format;
- group_title_format
- .parse_format(report.HANDLER(group_title_format_).str());
+ value_scope_t val_scope(bound_scope, string_value(report_title));
+ format_t group_title_format(report.HANDLER(group_title_format_).str());
- out << group_title_format(inner_scope);
+ out << group_title_format(val_scope);
report_title = "";
}
@@ -203,7 +195,7 @@ std::size_t format_accounts::post_account(account_t& account, const bool flat)
std::pair<std::size_t, std::size_t>
format_accounts::mark_accounts(account_t& account, const bool flat)
{
- std::size_t visited = 0;
+ std::size_t visited = 0;
std::size_t to_display = 0;
foreach (accounts_map::value_type& pair, account.accounts) {
@@ -218,16 +210,19 @@ format_accounts::mark_accounts(account_t& account, const bool flat)
DEBUG("account.display", " it was visited itself");
DEBUG("account.display", " it has " << visited << " visited children");
DEBUG("account.display",
- " it has " << to_display << " children to display");
+ " it has " << to_display << " children to display");
#endif
if (account.parent &&
(account.has_xflags(ACCOUNT_EXT_VISITED) || (! flat && visited > 0))) {
bind_scope_t bound_scope(report, account);
+ call_scope_t call_scope(bound_scope);
if ((! flat && to_display > 1) ||
- ((flat || to_display != 1 ||
- account.has_xflags(ACCOUNT_EXT_VISITED)) &&
- disp_pred(bound_scope))) {
+ ((flat || to_display != 1 ||
+ account.has_xflags(ACCOUNT_EXT_VISITED)) &&
+ (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");
to_display = 1;
@@ -244,7 +239,7 @@ void format_accounts::flush()
if (report.HANDLED(display_)) {
DEBUG("account.display",
- "Account display predicate: " << report.HANDLER(display_).str());
+ "Account display predicate: " << report.HANDLER(display_).str());
disp_pred.parse(report.HANDLER(display_).str());
}
@@ -263,7 +258,7 @@ void format_accounts::flush()
if (prepend_format) {
static_cast<std::ostream&>(report.output_stream).width(prepend_width);
static_cast<std::ostream&>(report.output_stream)
- << prepend_format(bound_scope);
+ << prepend_format(bound_scope);
}
out << total_line_format(bound_scope);
@@ -311,9 +306,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++;
}
@@ -344,12 +339,12 @@ void report_commodities::operator()(post_t& post)
annotated_commodity_t& ann_comm(as_annotated_commodity(comm));
if (ann_comm.details.price) {
std::map<commodity_t *, std::size_t>::iterator i =
- commodities.find(&ann_comm.details.price->commodity());
+ commodities.find(&ann_comm.details.price->commodity());
if (i == commodities.end())
- commodities.insert
- (commodities_pair(&ann_comm.details.price->commodity(), 1));
+ commodities.insert
+ (commodities_pair(&ann_comm.details.price->commodity(), 1));
else
- (*i).second++;
+ (*i).second++;
}
}
diff --git a/src/output.h b/src/output.h
index a19c6235..ac3925c4 100644
--- a/src/output.h
+++ b/src/output.h
@@ -69,8 +69,8 @@ protected:
public:
format_posts(report_t& _report, const string& format,
- const optional<string>& _prepend_format = none,
- std::size_t _prepend_width = 0);
+ const optional<string>& _prepend_format = none,
+ std::size_t _prepend_width = 0);
virtual ~format_posts() {
TRACE_DTOR(format_posts);
}
@@ -83,8 +83,8 @@ public:
virtual void operator()(post_t& post);
virtual void clear() {
- last_xact = NULL;
- last_post = NULL;
+ last_xact = NULL;
+ last_post = NULL;
report_title = "";
@@ -109,8 +109,8 @@ protected:
public:
format_accounts(report_t& _report, const string& _format,
- const optional<string>& _prepend_format = none,
- std::size_t _prepend_width = 0);
+ const optional<string>& _prepend_format = none,
+ std::size_t _prepend_width = 0);
virtual ~format_accounts() {
TRACE_DTOR(format_accounts);
}
@@ -123,7 +123,7 @@ public:
}
virtual std::size_t post_account(account_t& account, const bool flat);
- virtual void flush();
+ virtual void flush();
virtual void operator()(account_t& account);
diff --git a/src/parser.cc b/src/parser.cc
index f52949ce..f0085295 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -37,7 +37,7 @@ namespace ledger {
expr_t::ptr_op_t
expr_t::parser_t::parse_value_term(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node;
@@ -59,17 +59,12 @@ expr_t::parser_t::parse_value_term(std::istream& in,
tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::LPAREN) {
op_t::kind_t kind = op_t::O_CALL;
- if (ident == "any" || ident == "all")
- kind = op_t::O_EXPAND;
ptr_op_t call_node(new op_t(kind));
call_node->set_left(node);
node = call_node;
- push_token(tok); // let the parser see it again
+ push_token(tok); // let the parser see it again
node->set_right(parse_value_expr(in, tflags.plus_flags(PARSE_SINGLE)));
-
- if (node->has_right() && node->right()->kind == op_t::O_CONS)
- node->set_right(node->right()->left());
} else {
push_token(tok);
}
@@ -78,14 +73,8 @@ expr_t::parser_t::parse_value_term(std::istream& in,
case token_t::LPAREN:
node = parse_value_expr(in, tflags.plus_flags(PARSE_PARTIAL)
- .minus_flags(PARSE_SINGLE));
+ .minus_flags(PARSE_SINGLE));
tok = next_token(in, tflags, ')');
-
- if (node->kind == op_t::O_CONS) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_SEQ);
- node->set_left(prev);
- }
break;
default:
@@ -98,7 +87,7 @@ expr_t::parser_t::parse_value_term(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_dot_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_value_term(in, tflags));
@@ -106,16 +95,16 @@ expr_t::parser_t::parse_dot_expr(std::istream& in,
while (true) {
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::DOT) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_LOOKUP);
- node->set_left(prev);
- node->set_right(parse_value_term(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_LOOKUP);
+ node->set_left(prev);
+ node->set_right(parse_value_term(in, tflags));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
} else {
- push_token(tok);
- break;
+ push_token(tok);
+ break;
}
}
}
@@ -125,7 +114,7 @@ expr_t::parser_t::parse_dot_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_unary_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node;
@@ -136,7 +125,7 @@ expr_t::parser_t::parse_unary_expr(std::istream& in,
ptr_op_t term(parse_dot_expr(in, tflags));
if (! term)
throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ _("%1 operator not followed by argument") << tok.symbol);
// A very quick optimization
if (term->kind == op_t::VALUE) {
@@ -153,7 +142,7 @@ expr_t::parser_t::parse_unary_expr(std::istream& in,
ptr_op_t term(parse_dot_expr(in, tflags));
if (! term)
throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ _("%1 operator not followed by argument") << tok.symbol);
// A very quick optimization
if (term->kind == op_t::VALUE) {
@@ -177,7 +166,7 @@ expr_t::parser_t::parse_unary_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_mul_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_unary_expr(in, tflags));
@@ -186,18 +175,18 @@ expr_t::parser_t::parse_mul_expr(std::istream& in,
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::STAR || tok.kind == token_t::SLASH ||
- tok.kind == token_t::KW_DIV) {
- ptr_op_t prev(node);
- node = new op_t(tok.kind == token_t::STAR ?
- op_t::O_MUL : op_t::O_DIV);
- node->set_left(prev);
- node->set_right(parse_unary_expr(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ tok.kind == token_t::KW_DIV) {
+ ptr_op_t prev(node);
+ node = new op_t(tok.kind == token_t::STAR ?
+ op_t::O_MUL : op_t::O_DIV);
+ node->set_left(prev);
+ node->set_right(parse_unary_expr(in, tflags));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
} else {
- push_token(tok);
- break;
+ push_token(tok);
+ break;
}
}
}
@@ -207,7 +196,7 @@ expr_t::parser_t::parse_mul_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_add_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_mul_expr(in, tflags));
@@ -216,18 +205,18 @@ expr_t::parser_t::parse_add_expr(std::istream& in,
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::PLUS ||
- tok.kind == token_t::MINUS) {
- ptr_op_t prev(node);
- node = new op_t(tok.kind == token_t::PLUS ?
- op_t::O_ADD : op_t::O_SUB);
- node->set_left(prev);
- node->set_right(parse_mul_expr(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ tok.kind == token_t::MINUS) {
+ ptr_op_t prev(node);
+ node = new op_t(tok.kind == token_t::PLUS ?
+ op_t::O_ADD : op_t::O_SUB);
+ node->set_left(prev);
+ node->set_right(parse_mul_expr(in, tflags));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
} else {
- push_token(tok);
- break;
+ push_token(tok);
+ break;
}
}
}
@@ -237,70 +226,67 @@ expr_t::parser_t::parse_add_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_logic_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_add_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
while (true) {
- op_t::kind_t kind = op_t::LAST;
+ op_t::kind_t kind = op_t::LAST;
parse_flags_t _flags = tflags;
- token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
- bool negate = false;
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ bool negate = false;
switch (tok.kind) {
- case token_t::DEFINE:
- kind = op_t::O_DEFINE;
- break;
case token_t::EQUAL:
- if (tflags.has_flags(PARSE_NO_ASSIGN))
- tok.rewind(in);
- else
- kind = op_t::O_EQ;
- break;
+ if (tflags.has_flags(PARSE_NO_ASSIGN))
+ tok.rewind(in);
+ else
+ kind = op_t::O_EQ;
+ break;
case token_t::NEQUAL:
- kind = op_t::O_EQ;
- negate = true;
- break;
+ kind = op_t::O_EQ;
+ negate = true;
+ break;
case token_t::MATCH:
- kind = op_t::O_MATCH;
- break;
+ kind = op_t::O_MATCH;
+ break;
case token_t::NMATCH:
- kind = op_t::O_MATCH;
- negate = true;
- break;
+ kind = op_t::O_MATCH;
+ negate = true;
+ break;
case token_t::LESS:
- kind = op_t::O_LT;
- break;
+ kind = op_t::O_LT;
+ break;
case token_t::LESSEQ:
- kind = op_t::O_LTE;
- break;
+ kind = op_t::O_LTE;
+ break;
case token_t::GREATER:
- kind = op_t::O_GT;
- break;
+ kind = op_t::O_GT;
+ break;
case token_t::GREATEREQ:
- kind = op_t::O_GTE;
- break;
+ kind = op_t::O_GTE;
+ break;
default:
- push_token(tok);
- goto exit_loop;
+ push_token(tok);
+ goto exit_loop;
}
if (kind != op_t::LAST) {
- ptr_op_t prev(node);
- node = new op_t(kind);
- node->set_left(prev);
- node->set_right(parse_add_expr(in, _flags));
-
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
-
- if (negate) {
- prev = node;
- node = new op_t(op_t::O_NOT);
- node->set_left(prev);
- }
+ ptr_op_t prev(node);
+ node = new op_t(kind);
+ node->set_left(prev);
+ node->set_right(parse_add_expr(in, _flags));
+
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
+
+ if (negate) {
+ prev = node;
+ node = new op_t(op_t::O_NOT);
+ node->set_left(prev);
+ }
}
}
}
@@ -311,7 +297,7 @@ expr_t::parser_t::parse_logic_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_and_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_logic_expr(in, tflags));
@@ -320,16 +306,16 @@ expr_t::parser_t::parse_and_expr(std::istream& in,
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::KW_AND) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_AND);
- node->set_left(prev);
- node->set_right(parse_logic_expr(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_AND);
+ node->set_left(prev);
+ node->set_right(parse_logic_expr(in, tflags));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
} else {
- push_token(tok);
- break;
+ push_token(tok);
+ break;
}
}
}
@@ -338,7 +324,7 @@ expr_t::parser_t::parse_and_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_or_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_and_expr(in, tflags));
@@ -347,16 +333,16 @@ expr_t::parser_t::parse_or_expr(std::istream& in,
token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::KW_OR) {
- ptr_op_t prev(node);
- node = new op_t(op_t::O_OR);
- node->set_left(prev);
- node->set_right(parse_and_expr(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_OR);
+ node->set_left(prev);
+ node->set_right(parse_and_expr(in, tflags));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
} else {
- push_token(tok);
- break;
+ push_token(tok);
+ break;
}
}
}
@@ -365,7 +351,7 @@ expr_t::parser_t::parse_or_expr(std::istream& in,
expr_t::ptr_op_t
expr_t::parser_t::parse_querycolon_expr(std::istream& in,
- const parse_flags_t& tflags) const
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_or_expr(in, tflags));
@@ -378,8 +364,8 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
node->set_left(prev);
node->set_right(parse_or_expr(in, tflags));
if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT), ':');
prev = node->right();
@@ -387,42 +373,42 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
subnode->set_left(prev);
subnode->set_right(parse_or_expr(in, tflags));
if (! subnode->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol);
node->set_right(subnode);
}
else if (tok.kind == token_t::KW_IF) {
ptr_op_t if_op(parse_or_expr(in, tflags));
if (! if_op)
- throw_(parse_error, _("'if' keyword not followed by argument"));
+ throw_(parse_error, _("'if' keyword not followed by argument"));
tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
if (tok.kind == token_t::KW_ELSE) {
- ptr_op_t else_op(parse_or_expr(in, tflags));
- if (! else_op)
- throw_(parse_error, _("'else' keyword not followed by argument"));
+ ptr_op_t else_op(parse_or_expr(in, tflags));
+ if (! else_op)
+ throw_(parse_error, _("'else' keyword not followed by argument"));
- ptr_op_t subnode = new op_t(op_t::O_COLON);
- subnode->set_left(node);
- subnode->set_right(else_op);
+ ptr_op_t subnode = new op_t(op_t::O_COLON);
+ subnode->set_left(node);
+ subnode->set_right(else_op);
- node = new op_t(op_t::O_QUERY);
- node->set_left(if_op);
- node->set_right(subnode);
+ node = new op_t(op_t::O_QUERY);
+ node->set_left(if_op);
+ node->set_right(subnode);
} else {
- ptr_op_t null_node = new op_t(op_t::VALUE);
- null_node->set_value(NULL_VALUE);
+ ptr_op_t null_node = new op_t(op_t::VALUE);
+ null_node->set_value(NULL_VALUE);
- ptr_op_t subnode = new op_t(op_t::O_COLON);
- subnode->set_left(node);
- subnode->set_right(null_node);
+ ptr_op_t subnode = new op_t(op_t::O_COLON);
+ subnode->set_left(node);
+ subnode->set_right(null_node);
- node = new op_t(op_t::O_QUERY);
- node->set_left(if_op);
- node->set_right(subnode);
+ node = new op_t(op_t::O_QUERY);
+ node->set_left(if_op);
+ node->set_right(subnode);
- push_token(tok);
+ push_token(tok);
}
}
else {
@@ -433,47 +419,128 @@ expr_t::parser_t::parse_querycolon_expr(std::istream& in,
}
expr_t::ptr_op_t
-expr_t::parser_t::parse_value_expr(std::istream& in,
- const parse_flags_t& tflags) const
+expr_t::parser_t::parse_comma_expr(std::istream& in,
+ const parse_flags_t& tflags) const
{
ptr_op_t node(parse_querycolon_expr(in, tflags));
if (node && ! tflags.has_flags(PARSE_SINGLE)) {
- token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ ptr_op_t next;
+ while (true) {
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+
+ if (tok.kind == token_t::COMMA) {
+ if (! next) {
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_CONS);
+ node->set_left(prev);
+
+ next = node;
+ }
+
+ token_t& ntok = next_token(in, tflags);
+ push_token(ntok);
+ if (ntok.kind == token_t::RPAREN)
+ break;
+
+ ptr_op_t chain(new op_t(op_t::O_CONS));
+ chain->set_left(parse_querycolon_expr(in, tflags));
+
+ next->set_right(chain);
+ next = chain;
+ } else {
+ push_token(tok);
+ break;
+ }
+ }
+ }
+
+ return node;
+}
+
+expr_t::ptr_op_t
+expr_t::parser_t::parse_lambda_expr(std::istream& in,
+ const parse_flags_t& tflags) const
+{
+ ptr_op_t node(parse_comma_expr(in, tflags));
- if (tok.kind == token_t::COMMA || tok.kind == token_t::SEMI) {
- bool comma_op = tok.kind == token_t::COMMA;
+ if (node && ! tflags.has_flags(PARSE_SINGLE)) {
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ if (tok.kind == token_t::ARROW) {
ptr_op_t prev(node);
- node = new op_t(comma_op ? op_t::O_CONS : op_t::O_SEQ);
+ node = new op_t(op_t::O_LAMBDA);
node->set_left(prev);
- node->set_right(parse_value_expr(in, tflags));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol);
-
- tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+ node->set_right(parse_querycolon_expr(in, tflags));
+ } else {
+ push_token(tok);
}
+ }
- if (tok.kind != token_t::TOK_EOF) {
- if (tflags.has_flags(PARSE_PARTIAL))
- push_token(tok);
- else
- tok.unexpected();
+ return node;
+}
+
+expr_t::ptr_op_t
+expr_t::parser_t::parse_assign_expr(std::istream& in,
+ const parse_flags_t& tflags) const
+{
+ ptr_op_t node(parse_lambda_expr(in, tflags));
+
+ if (node && ! tflags.has_flags(PARSE_SINGLE)) {
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+
+ if (tok.kind == token_t::ASSIGN) {
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_DEFINE);
+ node->set_left(prev);
+ node->set_right(parse_lambda_expr(in, tflags));
+ } else {
+ push_token(tok);
}
}
- else if (! tflags.has_flags(PARSE_PARTIAL) &&
- ! tflags.has_flags(PARSE_SINGLE)) {
- throw_(parse_error, _("Failed to parse value expression"));
+
+ return node;
+}
+
+expr_t::ptr_op_t
+expr_t::parser_t::parse_value_expr(std::istream& in,
+ const parse_flags_t& tflags) const
+{
+ ptr_op_t node(parse_assign_expr(in, tflags));
+
+ if (node && ! tflags.has_flags(PARSE_SINGLE)) {
+ ptr_op_t next;
+ while (true) {
+ token_t& tok = next_token(in, tflags.plus_flags(PARSE_OP_CONTEXT));
+
+ if (tok.kind == token_t::SEMI) {
+ if (! next) {
+ ptr_op_t prev(node);
+ node = new op_t(op_t::O_SEQ);
+ node->set_left(prev);
+
+ next = node;
+ }
+
+ ptr_op_t chain(new op_t(op_t::O_SEQ));
+ chain->set_left(parse_assign_expr(in, tflags));
+
+ next->set_right(chain);
+ next = chain;
+ } else {
+ push_token(tok);
+ break;
+ }
+ }
}
return node;
}
expr_t::ptr_op_t
-expr_t::parser_t::parse(std::istream& in,
- const parse_flags_t& flags,
- const optional<string>& original_string)
+expr_t::parser_t::parse(std::istream& in,
+ const parse_flags_t& flags,
+ const optional<string>& original_string)
{
try {
ptr_op_t top_node = parse_value_expr(in, flags);
@@ -486,17 +553,17 @@ expr_t::parser_t::parse(std::istream& in,
return top_node;
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (original_string) {
add_error_context(_("While parsing value expression:"));
std::streamoff end_pos = 0;
if (in.good())
- end_pos = in.tellg();
+ end_pos = in.tellg();
std::streamoff pos = end_pos;
if (pos > 0)
- pos -= lookahead.length;
+ pos -= lookahead.length;
DEBUG("parser.error", "original_string = '" << *original_string << "'");
DEBUG("parser.error", " pos = " << pos);
@@ -505,8 +572,8 @@ expr_t::parser_t::parse(std::istream& in,
DEBUG("parser.error", " token length = " << lookahead.length);
add_error_context(line_context(*original_string,
- static_cast<string::size_type>(pos),
- static_cast<string::size_type>(end_pos)));
+ static_cast<string::size_type>(pos),
+ static_cast<string::size_type>(end_pos)));
}
throw;
}
diff --git a/src/parser.h b/src/parser.h
index 2693fc79..9a65765d 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -50,10 +50,10 @@ namespace ledger {
class expr_t::parser_t : public noncopyable
{
mutable token_t lookahead;
- mutable bool use_lookahead;
+ mutable bool use_lookahead;
token_t& next_token(std::istream& in, const parse_flags_t& tflags,
- const char expecting = '\0') const {
+ const char expecting = '\0') const {
if (use_lookahead)
use_lookahead = false;
else
@@ -76,25 +76,31 @@ class expr_t::parser_t : public noncopyable
}
ptr_op_t parse_value_term(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_dot_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_unary_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_mul_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_add_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_logic_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_and_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_or_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
ptr_op_t parse_querycolon_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
+ ptr_op_t parse_comma_expr(std::istream& in,
+ const parse_flags_t& flags) const;
+ ptr_op_t parse_lambda_expr(std::istream& in,
+ const parse_flags_t& flags) const;
+ ptr_op_t parse_assign_expr(std::istream& in,
+ const parse_flags_t& flags) const;
ptr_op_t parse_value_expr(std::istream& in,
- const parse_flags_t& flags) const;
+ const parse_flags_t& flags) const;
public:
parser_t() : use_lookahead(false) {
@@ -104,9 +110,9 @@ public:
TRACE_DTOR(parser_t);
}
- ptr_op_t parse(std::istream& in,
- const parse_flags_t& flags = PARSE_DEFAULT,
- const optional<string>& original_string = NULL);
+ ptr_op_t parse(std::istream& in,
+ const parse_flags_t& flags = PARSE_DEFAULT,
+ const optional<string>& original_string = NULL);
};
} // namespace ledger
diff --git a/src/pool.cc b/src/pool.cc
index ad97a9c6..20b585dd 100644
--- a/src/pool.cc
+++ b/src/pool.cc
@@ -57,7 +57,7 @@ commodity_t * commodity_pool_t::create(const string& symbol)
base_commodity(new commodity_t::base_t(symbol));
std::auto_ptr<commodity_t> commodity(new commodity_t(this, base_commodity));
- DEBUG("amounts.commodities", "Creating base commodity " << symbol);
+ DEBUG("pool.commodities", "Creating base commodity " << symbol);
// Create the "qualified symbol" version of this commodity's symbol
if (commodity_t::symbol_needs_quotes(symbol)) {
@@ -66,12 +66,12 @@ commodity_t * commodity_pool_t::create(const string& symbol)
*commodity->qualified_symbol += "\"";
}
- DEBUG("amounts.commodities",
- "Creating commodity '" << commodity->symbol() << "'");
+ DEBUG("pool.commodities",
+ "Creating commodity '" << commodity->symbol() << "'");
std::pair<commodities_map::iterator, bool> result
= commodities.insert(commodities_map::value_type(commodity->mapping_key(),
- commodity.get()));
+ commodity.get()));
assert(result.second);
return commodity.release();
@@ -79,7 +79,7 @@ commodity_t * commodity_pool_t::create(const string& symbol)
commodity_t * commodity_pool_t::find_or_create(const string& symbol)
{
- DEBUG("amounts.commodities", "Find-or-create commodity " << symbol);
+ DEBUG("pool.commodities", "Find-or-create commodity " << symbol);
commodity_t * commodity = find(symbol);
if (commodity)
@@ -89,7 +89,7 @@ commodity_t * commodity_pool_t::find_or_create(const string& symbol)
commodity_t * commodity_pool_t::find(const string& symbol)
{
- DEBUG("amounts.commodities", "Find commodity " << symbol);
+ DEBUG("pool.commodities", "Find commodity " << symbol);
commodities_map::const_iterator i = commodities.find(symbol);
if (i != commodities.end())
@@ -111,7 +111,7 @@ commodity_pool_t::create(const string& symbol, const annotation_t& details)
}
string commodity_pool_t::make_qualified_name(const commodity_t& comm,
- const annotation_t& details)
+ const annotation_t& details)
{
assert(details);
@@ -124,10 +124,10 @@ string commodity_pool_t::make_qualified_name(const commodity_t& comm,
#if defined(DEBUG_ON)
if (comm.qualified_symbol)
- DEBUG("amounts.commodities", "make_qualified_name for "
- << *comm.qualified_symbol << std::endl << details);
+ DEBUG("pool.commodities", "make_qualified_name for "
+ << *comm.qualified_symbol << std::endl << details);
#endif
- DEBUG("amounts.commodities", "qualified_name is " << name.str());
+ DEBUG("pool.commodities", "qualified_name is " << name.str());
return name.str();
}
@@ -154,9 +154,9 @@ commodity_pool_t::find(const string& symbol, const annotation_t& details)
commodity_t *
commodity_pool_t::find_or_create(const string& symbol,
- const annotation_t& details)
+ const annotation_t& details)
{
- commodity_t * comm = find(symbol);
+ commodity_t * comm = find_or_create(symbol);
if (! comm)
return NULL;
@@ -167,23 +167,32 @@ commodity_pool_t::find_or_create(const string& symbol,
}
commodity_t *
-commodity_pool_t::create(commodity_t& comm,
- const annotation_t& details,
- const string& mapping_key)
+commodity_pool_t::create(commodity_t& comm,
+ const annotation_t& details,
+ 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());
- DEBUG("amounts.commodities", "Creating annotated commodity "
- << "symbol " << commodity->symbol()
- << " key " << mapping_key << std::endl << details);
+ DEBUG("pool.commodities", "Creating annotated commodity "
+ << "symbol " << commodity->symbol()
+ << " key " << mapping_key << std::endl << details);
// Add the fully annotated name to the map, so that this symbol may
// quickly be found again.
@@ -191,14 +200,14 @@ commodity_pool_t::create(commodity_t& comm,
std::pair<commodities_map::iterator, bool> result
= commodities.insert(commodities_map::value_type(mapping_key,
- commodity.get()));
+ commodity.get()));
assert(result.second);
return commodity.release();
}
-commodity_t * commodity_pool_t::find_or_create(commodity_t& comm,
- const annotation_t& details)
+commodity_t * commodity_pool_t::find_or_create(commodity_t& comm,
+ const annotation_t& details)
{
assert(comm);
assert(details);
@@ -213,12 +222,12 @@ commodity_t * commodity_pool_t::find_or_create(commodity_t& comm,
return create(comm, details, name);
}
-void commodity_pool_t::exchange(commodity_t& commodity,
- const amount_t& per_unit_cost,
- const datetime_t& moment)
+void commodity_pool_t::exchange(commodity_t& commodity,
+ const amount_t& per_unit_cost,
+ const datetime_t& moment)
{
DEBUG("commodity.prices.add", "exchanging commodity " << commodity
- << " at per unit cost " << per_unit_cost << " on " << moment);
+ << " at per unit cost " << per_unit_cost << " on " << moment);
commodity_t& base_commodity
(commodity.annotated ?
@@ -228,11 +237,11 @@ void commodity_pool_t::exchange(commodity_t& commodity,
}
cost_breakdown_t
-commodity_pool_t::exchange(const amount_t& amount,
- const amount_t& cost,
- const bool is_per_unit,
- const optional<datetime_t>& moment,
- const optional<string>& tag)
+commodity_pool_t::exchange(const amount_t& amount,
+ const amount_t& cost,
+ const bool is_per_unit,
+ const optional<datetime_t>& moment,
+ const optional<string>& tag)
{
DEBUG("commodity.prices.add", "exchange: " << amount << " for " << cost);
DEBUG("commodity.prices.add", "exchange: is-per-unit = " << is_per_unit);
@@ -254,14 +263,20 @@ 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;
breakdown.final_cost = ! is_per_unit ? cost : cost * amount.abs();
DEBUG("commodity.prices.add",
- "exchange: final-cost = " << breakdown.final_cost);
+ "exchange: final-cost = " << breakdown.final_cost);
if (current_annotation && current_annotation->price)
breakdown.basis_cost
@@ -270,12 +285,15 @@ commodity_pool_t::exchange(const amount_t& amount,
breakdown.basis_cost = breakdown.final_cost;
DEBUG("commodity.prices.add",
- "exchange: basis-cost = " << breakdown.basis_cost);
+ "exchange: basis-cost = " << breakdown.basis_cost);
annotation_t annotation(per_unit_cost, moment ?
- moment->date() : optional<date_t>(), tag);
+ 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)
@@ -284,7 +302,7 @@ commodity_pool_t::exchange(const amount_t& amount,
breakdown.amount = amount_t(amount, annotation);
DEBUG("commodity.prices.add",
- "exchange: amount = " << breakdown.amount);
+ "exchange: amount = " << breakdown.amount);
return breakdown;
}
@@ -328,7 +346,7 @@ commodity_pool_t::parse_price_directive(char * line, bool do_not_add_price)
DEBUG("commodity.download", "Looking up symbol: " << symbol);
if (commodity_t * commodity = find_or_create(symbol)) {
DEBUG("commodity.download", "Adding price for " << symbol << ": "
- << point.when << " " << point.price);
+ << point.when << " " << point.price);
if (! do_not_add_price)
commodity->add_price(point.when, point.price, true);
commodity->add_flags(COMMODITY_KNOWN);
@@ -340,8 +358,8 @@ commodity_pool_t::parse_price_directive(char * line, bool do_not_add_price)
commodity_t *
commodity_pool_t::parse_price_expression(const std::string& str,
- const bool add_prices,
- const optional<datetime_t>& moment)
+ const bool add_prices,
+ const optional<datetime_t>& moment)
{
scoped_array<char> buf(new char[str.length() + 1]);
@@ -354,9 +372,9 @@ commodity_pool_t::parse_price_expression(const std::string& str,
if (commodity_t * commodity = find_or_create(trim_ws(buf.get()))) {
if (price && add_prices) {
for (char * p = std::strtok(price, ";");
- p;
- p = std::strtok(NULL, ";")) {
- commodity->add_price(moment ? *moment : CURRENT_TIME(), amount_t(p));
+ p;
+ p = std::strtok(NULL, ";")) {
+ commodity->add_price(moment ? *moment : CURRENT_TIME(), amount_t(p));
}
}
return commodity;
@@ -364,9 +382,9 @@ commodity_pool_t::parse_price_expression(const std::string& str,
return NULL;
}
-void commodity_pool_t::print_pricemap(std::ostream& out,
- const keep_details_t& keep,
- const optional<datetime_t>& moment)
+void commodity_pool_t::print_pricemap(std::ostream& out,
+ const keep_details_t& keep,
+ const optional<datetime_t>& moment)
{
typedef std::map<commodity_t *, commodity_t *> comm_map_t;
@@ -391,44 +409,44 @@ void commodity_pool_t::print_pricemap(std::ostream& out,
out << "\"" << comm->symbol() << "\";\n";
if (! comm->has_flags(COMMODITY_NOMARKET) &&
- (! commodity_pool_t::current_pool->default_commodity ||
- comm != commodity_pool_t::current_pool->default_commodity)) {
+ (! commodity_pool_t::current_pool->default_commodity ||
+ comm != commodity_pool_t::current_pool->default_commodity)) {
if (optional<commodity_t::varied_history_t&> vhist =
- comm->varied_history()) {
- foreach (const commodity_t::history_by_commodity_map::value_type& pair,
- vhist->histories) {
- datetime_t most_recent;
- amount_t most_recent_amt;
- foreach (const commodity_t::history_map::value_type& inner_pair,
- pair.second.prices) {
- if ((most_recent.is_not_a_date_time() ||
- inner_pair.first > most_recent) &&
- (! moment || inner_pair.first <= moment)) {
- most_recent = inner_pair.first;
- most_recent_amt = inner_pair.second;
- }
- }
-
- if (! most_recent.is_not_a_date_time()) {
- out << " ";
- if (commodity_t::symbol_needs_quotes(comm->symbol()))
- out << comm->symbol();
- else
- out << "\"" << comm->symbol() << "\"";
-
- out << " -> ";
-
- if (commodity_t::symbol_needs_quotes(pair.first->symbol()))
- out << pair.first->symbol();
- else
- out << "\"" << pair.first->symbol() << "\"";
-
- out << " [label=\""
- << most_recent_amt.number() << "\\n"
- << format_date(most_recent.date(), FMT_WRITTEN)
- << "\" fontcolor=\"#008e28\"];\n";
- }
- }
+ comm->varied_history()) {
+ foreach (const commodity_t::history_by_commodity_map::value_type& pair,
+ vhist->histories) {
+ datetime_t most_recent;
+ amount_t most_recent_amt;
+ foreach (const commodity_t::history_map::value_type& inner_pair,
+ pair.second.prices) {
+ if ((most_recent.is_not_a_date_time() ||
+ inner_pair.first > most_recent) &&
+ (! moment || inner_pair.first <= moment)) {
+ most_recent = inner_pair.first;
+ most_recent_amt = inner_pair.second;
+ }
+ }
+
+ if (! most_recent.is_not_a_date_time()) {
+ out << " ";
+ if (commodity_t::symbol_needs_quotes(comm->symbol()))
+ out << comm->symbol();
+ else
+ out << "\"" << comm->symbol() << "\"";
+
+ out << " -> ";
+
+ if (commodity_t::symbol_needs_quotes(pair.first->symbol()))
+ out << pair.first->symbol();
+ else
+ out << "\"" << pair.first->symbol() << "\"";
+
+ out << " [label=\""
+ << most_recent_amt.number() << "\\n"
+ << format_date(most_recent.date(), FMT_WRITTEN)
+ << "\" fontcolor=\"#008e28\"];\n";
+ }
+ }
}
}
}
diff --git a/src/pool.h b/src/pool.h
index ac66d7a6..4b935f69 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -67,19 +67,19 @@ public:
typedef std::map<string, commodity_t *> commodities_map;
commodities_map commodities;
- commodity_t * null_commodity;
- commodity_t * default_commodity;
+ commodity_t * null_commodity;
+ commodity_t * default_commodity;
- bool keep_base; // --base
+ bool keep_base; // --base
optional<path> price_db; // --price-db=
- long quote_leeway; // --leeway=
- bool get_quotes; // --download
+ long quote_leeway; // --leeway=
+ bool get_quotes; // --download
static shared_ptr<commodity_pool_t> current_pool;
function<optional<price_point_t>
- (commodity_t& commodity, const optional<commodity_t&>& in_terms_of)>
+ (commodity_t& commodity, const optional<commodity_t&>& in_terms_of)>
get_commodity_quote;
explicit commodity_pool_t();
@@ -91,7 +91,7 @@ public:
}
string make_qualified_name(const commodity_t& comm,
- const annotation_t& details);
+ const annotation_t& details);
commodity_t * create(const string& symbol);
commodity_t * find(const string& name);
@@ -100,26 +100,26 @@ public:
commodity_t * create(const string& symbol, const annotation_t& details);
commodity_t * find(const string& symbol, const annotation_t& details);
commodity_t * find_or_create(const string& symbol,
- const annotation_t& details);
+ const annotation_t& details);
- commodity_t * create(commodity_t& comm,
- const annotation_t& details,
- const string& mapping_key);
+ commodity_t * create(commodity_t& comm,
+ const annotation_t& details,
+ const string& mapping_key);
- commodity_t * find_or_create(commodity_t& comm,
- const annotation_t& details);
+ commodity_t * find_or_create(commodity_t& comm,
+ const annotation_t& details);
// Exchange one commodity for another, while recording the factored price.
- void exchange(commodity_t& commodity,
- const amount_t& per_unit_cost,
- const datetime_t& moment);
+ void exchange(commodity_t& commodity,
+ const amount_t& per_unit_cost,
+ const datetime_t& moment);
- cost_breakdown_t exchange(const amount_t& amount,
- const amount_t& cost,
- const bool is_per_unit = false,
- const optional<datetime_t>& moment = none,
- const optional<string>& tag = none);
+ cost_breakdown_t exchange(const amount_t& amount,
+ const amount_t& cost,
+ const bool is_per_unit = false,
+ const optional<datetime_t>& moment = none,
+ const optional<string>& tag = none);
// Parse commodity prices from a textual representation
@@ -128,14 +128,14 @@ public:
commodity_t *
parse_price_expression(const std::string& str,
- const bool add_prices = true,
- const optional<datetime_t>& moment = none);
+ const bool add_prices = true,
+ const optional<datetime_t>& moment = none);
// Output the commodity price map for a given date as a DOT file
- void print_pricemap(std::ostream& out,
- const keep_details_t& keep,
- const optional<datetime_t>& moment = none);
+ void print_pricemap(std::ostream& out,
+ const keep_details_t& keep,
+ const optional<datetime_t>& moment = none);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
diff --git a/src/post.cc b/src/post.cc
index 7dc15830..4fc34892 100644
--- a/src/post.cc
+++ b/src/post.cc
@@ -35,49 +35,57 @@
#include "xact.h"
#include "account.h"
#include "journal.h"
-#include "interactive.h"
#include "format.h"
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<string> post_t::get_tag(const string& tag) const
+optional<value_t> post_t::get_tag(const string& tag, bool inherit) const
{
- if (optional<string> value = item_t::get_tag(tag))
+ 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<string> post_t::get_tag(const mask_t& tag_mask,
- const optional<mask_t>& value_mask) const
+optional<value_t> post_t::get_tag(const mask_t& tag_mask,
+ const optional<mask_t>& value_mask,
+ bool inherit) const
{
- if (optional<string> value = item_t::get_tag(tag_mask, value_mask))
+ 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;
}
+date_t post_t::value_date() const
+{
+ if (xdata_ && is_valid(xdata_->value_date))
+ return xdata_->value_date;
+ return date();
+}
+
date_t post_t::date() const
{
if (xdata_ && is_valid(xdata_->date))
@@ -117,9 +125,17 @@ 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 value_t(static_cast<scope_t *>(&post));
+ return scope_value(&post);
}
value_t get_is_calculated(post_t& post) {
@@ -139,7 +155,7 @@ namespace {
}
value_t get_xact(post_t& post) {
- return value_t(static_cast<scope_t *>(post.xact));
+ return scope_value(post.xact);
}
value_t get_xact_id(post_t& post) {
@@ -154,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) {
@@ -190,20 +206,25 @@ namespace {
return post.has_xdata() && post.xdata().has_flags(POST_EXT_DIRECT_AMT);
}
- value_t get_commodity(post_t& post) {
- if (post.has_xdata() &&
- post.xdata().has_flags(POST_EXT_COMPOUND))
- return string_value(post.xdata().compound_value.to_amount()
- .commodity().symbol());
- else
- return string_value(post.amount.commodity().symbol());
+ value_t get_commodity(call_scope_t& args)
+ {
+ if (args.has<amount_t>(0)) {
+ return string_value(args.get<amount_t>(0).commodity().symbol());
+ } else {
+ post_t& post(args.context<post_t>());
+ if (post.has_xdata() && post.xdata().has_flags(POST_EXT_COMPOUND))
+ return string_value(post.xdata().compound_value.to_amount()
+ .commodity().symbol());
+ else
+ return string_value(post.amount.commodity().symbol());
+ }
}
value_t get_commodity_is_primary(post_t& post) {
if (post.has_xdata() &&
- post.xdata().has_flags(POST_EXT_COMPOUND))
+ post.xdata().has_flags(POST_EXT_COMPOUND))
return post.xdata().compound_value.to_amount()
- .commodity().has_flags(COMMODITY_PRIMARY);
+ .commodity().has_flags(COMMODITY_PRIMARY);
else
return post.amount.commodity().has_flags(COMMODITY_PRIMARY);
}
@@ -216,7 +237,7 @@ namespace {
if (post.cost)
return *post.cost;
else if (post.has_xdata() &&
- post.xdata().has_flags(POST_EXT_COMPOUND))
+ post.xdata().has_flags(POST_EXT_COMPOUND))
return post.xdata().compound_value;
else if (post.amount.is_null())
return 0L;
@@ -240,73 +261,71 @@ namespace {
return 1L;
}
- value_t account_name(call_scope_t& scope)
+ value_t get_account(call_scope_t& args)
{
- in_context_t<post_t> env(scope, "&v");
-
- string name;
-
- if (env.has(0)) {
- if (env.value_at(0).is_long()) {
- if (env.get<long>(0) > 2)
- name = format_t::truncate(env->reported_account()->fullname(),
- env.get<long>(0) - 2,
- 2 /* account_abbrev_length */);
- else
- name = env->reported_account()->fullname();
+ post_t& post(args.context<post_t>());
+ account_t& account(*post.reported_account());
+ string name;
+
+ if (args.has(0)) {
+ if (args[0].is_long()) {
+ if (args.get<long>(0) > 2)
+ name = format_t::truncate(account.fullname(),
+ args.get<long>(0) - 2,
+ 2 /* account_abbrev_length */);
+ else
+ name = account.fullname();
} else {
- account_t * account = NULL;
- account_t * master = env->account;
- while (master->parent)
- master = master->parent;
-
- if (env.value_at(0).is_string()) {
- name = env.get<string>(0);
- account = master->find_account(name, false);
- }
- else if (env.value_at(0).is_mask()) {
- name = env.get<mask_t>(0).str();
- account = master->find_account_re(name);
- }
- else {
- throw_(std::runtime_error,
- _("Expected string or mask for argument 1, but received %1")
- << env.value_at(0).label());
- }
-
- if (! account)
- throw_(std::runtime_error,
- _("Could not find an account matching ") << env.value_at(0));
- else
- return value_t(static_cast<scope_t *>(account));
+ account_t * acct = NULL;
+ account_t * master = &account;
+ while (master->parent)
+ master = master->parent;
+
+ if (args[0].is_string()) {
+ name = args.get<string>(0);
+ acct = master->find_account(name, false);
+ }
+ else if (args[0].is_mask()) {
+ name = args.get<mask_t>(0).str();
+ acct = master->find_account_re(name);
+ }
+ else {
+ throw_(std::runtime_error,
+ _("Expected string or mask for argument 1, but received %1")
+ << args[0].label());
+ }
+
+ if (! acct)
+ throw_(std::runtime_error,
+ _("Could not find an account matching ") << args[0]);
+ else
+ return value_t(static_cast<scope_t *>(acct));
}
- } else {
- name = env->reported_account()->fullname();
+ }
+ else if (args.type_context() == value_t::SCOPE) {
+ return scope_value(&account);
+ }
+ else {
+ name = account.fullname();
}
return string_value(name);
}
- value_t get_display_account(call_scope_t& scope)
+ value_t get_display_account(call_scope_t& args)
{
- in_context_t<post_t> env(scope, "&v");
-
- value_t acct = account_name(scope);
+ post_t& post(args.context<post_t>());
+ value_t acct = get_account(args);
if (acct.is_string()) {
- if (env->has_flags(POST_VIRTUAL)) {
- if (env->must_balance())
- acct = string_value(string("[") + acct.as_string() + "]");
- else
- acct = string_value(string("(") + acct.as_string() + ")");
+ if (post.has_flags(POST_VIRTUAL)) {
+ if (post.must_balance())
+ acct = string_value(string("[") + acct.as_string() + "]");
+ else
+ acct = string_value(string("(") + acct.as_string() + ")");
}
}
return acct;
}
- value_t get_account(call_scope_t& scope)
- {
- return account_name(scope);
- }
-
value_t get_account_id(post_t& post) {
return static_cast<long>(post.account_id());
}
@@ -319,6 +338,14 @@ namespace {
return long(post.reported_account()->depth);
}
+ value_t get_value_date(post_t& post) {
+ if (post.has_xdata()) {
+ post_t::xdata_t& xdata(post.xdata());
+ if (! xdata.value_date.is_not_a_date())
+ return xdata.value_date;
+ }
+ return post.date();
+ }
value_t get_datetime(post_t& post) {
return post.xdata().datetime;
}
@@ -328,45 +355,45 @@ namespace {
return (*Func)(find_scope<post_t>(scope));
}
- value_t fn_any(call_scope_t& scope)
+ value_t fn_any(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- post_t& post(find_scope<post_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ post_t& post(args.context<post_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, post.xact->posts) {
- bind_scope_t bound_scope(scope, *p);
- if (p == &post && args.has(1) &&
- ! args.get<expr_t&>(1).calc(bound_scope).to_boolean()) {
- // If the user specifies any(EXPR, false), and the context is a
- // posting, then that posting isn't considered by the test.
- ; // skip it
+ bind_scope_t bound_scope(args, *p);
+ if (p == &post && args.has<expr_t::ptr_op_t>(1) &&
+ ! args.get<expr_t::ptr_op_t>(1)
+ ->calc(bound_scope, args.locus, args.depth).to_boolean()) {
+ // If the user specifies any(EXPR, false), and the context is a
+ // posting, then that posting isn't considered by the test.
+ ; // skip it
}
- else if (expr.calc(bound_scope).to_boolean()) {
- return true;
+ else if (expr->calc(bound_scope, args.locus,
+ args.depth).to_boolean()) {
+ return true;
}
}
return false;
}
- value_t fn_all(call_scope_t& scope)
+ value_t fn_all(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- post_t& post(find_scope<post_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ post_t& post(args.context<post_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, post.xact->posts) {
- bind_scope_t bound_scope(scope, *p);
- if (p == &post && args.has(1) &&
- ! args.get<expr_t&>(1).calc(bound_scope).to_boolean()) {
- // If the user specifies any(EXPR, false), and the context is a
- // posting, then that posting isn't considered by the test.
- ; // skip it
+ bind_scope_t bound_scope(args, *p);
+ if (p == &post && args.has<expr_t::ptr_op_t>(1) &&
+ ! args.get<expr_t::ptr_op_t>(1)
+ ->calc(bound_scope, args.locus, args.depth).to_boolean()) {
+ // If the user specifies any(EXPR, false), and the context is a
+ // posting, then that posting isn't considered by the test.
+ ; // skip it
}
- else if (! expr.calc(bound_scope).to_boolean()) {
- return false;
+ else if (! expr->calc(bound_scope, args.locus,
+ args.depth).to_boolean()) {
+ return false;
}
}
return true;
@@ -374,7 +401,7 @@ namespace {
}
expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return item_t::lookup(kind, name);
@@ -412,7 +439,7 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind,
else if (name == "calculated")
return WRAP_FUNCTOR(get_wrapper<&get_is_calculated>);
else if (name == "commodity")
- return WRAP_FUNCTOR(get_wrapper<&get_commodity>);
+ return WRAP_FUNCTOR(&get_commodity);
break;
case 'd':
@@ -479,6 +506,8 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind,
case 'v':
if (name == "virtual")
return WRAP_FUNCTOR(get_wrapper<&get_virtual>);
+ else if (name == "value_date")
+ return WRAP_FUNCTOR(get_wrapper<&get_value_date>);
break;
case 'x':
@@ -516,7 +545,7 @@ amount_t post_t::resolve_expr(scope_t& scope, expr_t& expr)
} else {
if (! result.is_amount())
throw_(amount_error,
- _("Amount expressions must result in a simple amount"));
+ _("Amount expressions must result in a simple amount"));
return result.as_amount();
}
}
@@ -554,7 +583,7 @@ bool post_t::valid() const
posts_list::const_iterator i =
std::find(xact->posts.begin(),
- xact->posts.end(), this);
+ xact->posts.end(), this);
if (i == xact->posts.end()) {
DEBUG("ledger.validate", "post_t: ! found");
return false;
@@ -591,7 +620,7 @@ void post_t::add_to_value(value_t& value, const optional<expr_t&>& expr) const
}
else if (expr) {
bind_scope_t bound_scope(*expr->get_context(),
- const_cast<post_t&>(*this));
+ const_cast<post_t&>(*this));
#if 1
value_t temp(expr->calc(bound_scope));
add_or_set_value(value, temp);
@@ -604,7 +633,7 @@ void post_t::add_to_value(value_t& value, const optional<expr_t&>& expr) const
#endif
}
else if (xdata_ && xdata_->has_flags(POST_EXT_VISITED) &&
- ! xdata_->visited_value.is_null()) {
+ ! xdata_->visited_value.is_null()) {
add_or_set_value(value, xdata_->visited_value);
}
else {
@@ -691,18 +720,18 @@ void to_xml(std::ostream& out, const post_t& post)
push_xml y(out, "metadata");
foreach (const item_t::string_map::value_type& pair, *post.metadata) {
if (pair.second.first) {
- push_xml z(out, "variable");
- {
- push_xml z(out, "key");
- out << y.guard(pair.first);
- }
- {
- push_xml z(out, "value");
- out << y.guard(*pair.second.first);
- }
+ push_xml z(out, "variable");
+ {
+ push_xml z(out, "key");
+ out << y.guard(pair.first);
+ }
+ {
+ push_xml z(out, "value");
+ to_xml(out, *pair.second.first);
+ }
} else {
- push_xml z(out, "tag");
- out << y.guard(pair.first);
+ push_xml z(out, "tag");
+ out << y.guard(pair.first);
}
}
}
diff --git a/src/post.h b/src/post.h
index ed22634f..7d5abcd8 100644
--- a/src/post.h
+++ b/src/post.h
@@ -52,32 +52,33 @@ class account_t;
class post_t : public item_t
{
public:
-#define POST_VIRTUAL 0x04 // the account was specified with (parens)
-#define POST_MUST_BALANCE 0x08 // posting must balance in the transaction
-#define POST_CALCULATED 0x10 // posting's amount was calculated
-#define POST_COST_CALCULATED 0x20 // posting's cost was calculated
-#define POST_COST_IN_FULL 0x40 // cost specified using @@
-#define POST_ANONYMIZED 0x80 // a temporary, anonymous posting
-
- xact_t * xact; // only set for posts of regular xacts
- account_t * account;
-
- amount_t amount; // can be null until finalization
+#define POST_VIRTUAL 0x0010 // the account was specified with (parens)
+#define POST_MUST_BALANCE 0x0020 // posting must balance in the transaction
+#define POST_CALCULATED 0x0040 // posting's amount was calculated
+#define POST_COST_CALCULATED 0x0080 // posting's cost was calculated
+#define POST_COST_IN_FULL 0x0100 // cost specified using @@
+#define POST_COST_FIXATED 0x0200 // cost is fixed using = indicator
+#define POST_ANONYMIZED 0x0400 // a temporary, anonymous posting
+
+ xact_t * xact; // only set for posts of regular xacts
+ account_t * account;
+
+ amount_t amount; // can be null until finalization
optional<expr_t> amount_expr;
optional<amount_t> cost;
optional<amount_t> assigned_amount;
post_t(account_t * _account = NULL,
- flags_t _flags = ITEM_NORMAL)
+ flags_t _flags = ITEM_NORMAL)
: item_t(_flags),
xact(NULL), account(_account)
{
TRACE_CTOR(post_t, "account_t *, flags_t");
}
- post_t(account_t * _account,
- const amount_t& _amount,
- flags_t _flags = ITEM_NORMAL,
- const optional<string>& _note = none)
+ post_t(account_t * _account,
+ const amount_t& _amount,
+ flags_t _flags = ITEM_NORMAL,
+ const optional<string>& _note = none)
: item_t(_flags, _note),
xact(NULL), account(_account), amount(_amount)
{
@@ -98,24 +99,41 @@ 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 string description() {
+ if (pos) {
+ std::ostringstream buf;
+ buf << _("posting at line %1") << pos->beg_line;
+ return buf.str();
+ } else {
+ return string(_("generated posting"));
+ }
+ }
+
+ 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<string> get_tag(const string& tag) const;
- virtual optional<string> 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);
}
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
amount_t resolve_expr(scope_t& scope, expr_t& expr);
@@ -136,13 +154,14 @@ public:
#define POST_EXT_MATCHES 0x0080
#define POST_EXT_CONSIDERED 0x0100
- value_t visited_value;
- value_t compound_value;
- value_t total;
- std::size_t count;
- date_t date;
- datetime_t datetime;
- account_t * account;
+ value_t visited_value;
+ value_t compound_value;
+ value_t total;
+ std::size_t count;
+ date_t date;
+ date_t value_date;
+ datetime_t datetime;
+ account_t * account;
std::list<sort_value_t> sort_values;
@@ -152,13 +171,13 @@ public:
}
xdata_t(const xdata_t& other)
: supports_flags<uint_least16_t>(other.flags()),
- visited_value(other.visited_value),
- compound_value(other.compound_value),
- total(other.total),
- count(other.count),
- date(other.date),
- account(other.account),
- sort_values(other.sort_values)
+ visited_value(other.visited_value),
+ compound_value(other.compound_value),
+ total(other.total),
+ count(other.count),
+ date(other.date),
+ account(other.account),
+ sort_values(other.sort_values)
{
TRACE_CTOR(post_t::xdata_t, "copy");
}
@@ -189,14 +208,14 @@ public:
}
void add_to_value(value_t& value,
- const optional<expr_t&>& expr = none) const;
+ const optional<expr_t&>& expr = none) const;
void set_reported_account(account_t * account);
account_t * reported_account() {
if (xdata_)
if (account_t * acct = xdata_->account)
- return acct;
+ return acct;
return account;
}
@@ -210,12 +229,12 @@ public:
{
bool operator()(const post_t * left, const post_t * right) const {
gregorian::date_duration duration =
- left->actual_date() - right->actual_date();
+ left->actual_date() - right->actual_date();
if (duration.days() == 0) {
- return ((left->pos ? left->pos->sequence : 0) <
- (right->pos ? right->pos->sequence : 0));
+ return ((left->pos ? left->pos->sequence : 0) <
+ (right->pos ? right->pos->sequence : 0));
} else {
- return duration.days() < 0;
+ return duration.days() < 0;
}
}
};
diff --git a/src/precmd.cc b/src/precmd.cc
index e545a783..8ca27fd8 100644
--- a/src/precmd.cc
+++ b/src/precmd.cc
@@ -43,32 +43,49 @@
namespace ledger {
namespace {
+ string join_args(call_scope_t& args)
+ {
+ std::ostringstream buf;
+ bool first = true;
+
+ for (std::size_t i = 0; i < args.size(); i++) {
+ if (first)
+ first = false;
+ else
+ buf << ' ';
+ buf << args[i];
+ }
+
+ return buf.str();
+ }
+
post_t * get_sample_xact(report_t& report)
{
{
string str;
{
- std::ostringstream buf;
-
- buf << "2004/05/27 Book Store\n"
- << " ; This note applies to all postings. :SecondTag:\n"
- << " Expenses:Books 20 BOOK @ $10\n"
- << " ; Metadata: Some Value\n"
- << " ; :ExampleTag:\n"
- << " ; Here follows a note describing the posting.\n"
- << " Liabilities:MasterCard $-200.00\n";
-
- str = buf.str();
+ std::ostringstream buf;
+
+ buf << "2004/05/27 Book Store\n"
+ << " ; This note applies to all postings. :SecondTag:\n"
+ << " Expenses:Books 20 BOOK @ $10\n"
+ << " ; Metadata: Some Value\n"
+ << " ; Typed:: $100 + $200\n"
+ << " ; :ExampleTag:\n"
+ << " ; Here follows a note describing the posting.\n"
+ << " Liabilities:MasterCard $-200.00\n";
+
+ str = buf.str();
}
std::ostream& out(report.output_stream);
out << _("--- Context is first posting of the following transaction ---")
- << std::endl << str << std::endl;
+ << std::endl << str << std::endl;
{
- std::istringstream in(str);
- report.session.journal->parse(in, report.session);
- report.session.journal->clear_xdata();
+ std::istringstream in(str);
+ report.session.journal->parse(in, report.session);
+ report.session.journal->clear_xdata();
}
}
xact_t * first = report.session.journal->xacts.front();
@@ -169,7 +186,7 @@ value_t period_command(call_scope_t& args)
out << std::endl;
date_interval_t interval(arg);
- interval.dump(out, report.session.current_year);
+ interval.dump(out);
return NULL_VALUE;
}
@@ -183,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;
+ << 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;
diff --git a/src/predicate.cc b/src/predicate.cc
index 369120e6..fd301a7d 100644
--- a/src/predicate.cc
+++ b/src/predicate.cc
@@ -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
diff --git a/src/predicate.h b/src/predicate.h
index c21167d7..673f1d5d 100644
--- a/src/predicate.h
+++ b/src/predicate.h
@@ -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");
}
@@ -81,10 +85,10 @@ public:
virtual value_t real_calc(scope_t& scope) {
return (*this ?
- expr_t::real_calc(scope)
- .strip_annotations(what_to_keep)
- .to_boolean() :
- true);
+ expr_t::real_calc(scope)
+ .strip_annotations(what_to_keep)
+ .to_boolean() :
+ true);
}
#if defined(HAVE_BOOST_SERIALIZATION)
diff --git a/src/print.cc b/src/print.cc
index 703e885c..03c87884 100644
--- a/src/print.cc
+++ b/src/print.cc
@@ -41,10 +41,10 @@
namespace ledger {
namespace {
- void print_note(std::ostream& out,
- const string& note,
- const std::size_t columns,
- const std::size_t prior_width)
+ void print_note(std::ostream& out,
+ const string& note,
+ const std::size_t columns,
+ const std::size_t prior_width)
{
// The 4 is for four leading spaces at the beginning of the posting, and
// the 3 is for two spaces and a semi-colon before the note.
@@ -56,20 +56,20 @@ namespace {
bool need_separator = false;
for (const char * p = note.c_str(); *p; p++) {
if (*p == '\n') {
- need_separator = true;
+ need_separator = true;
} else {
- if (need_separator) {
- out << "\n ;";
- need_separator = false;
- }
- out << *p;
+ if (need_separator) {
+ out << "\n ;";
+ need_separator = false;
+ }
+ out << *p;
}
}
}
void print_xact(report_t& report, std::ostream& out, xact_t& xact)
{
- format_type_t format_type = FMT_WRITTEN;
+ format_type_t format_type = FMT_WRITTEN;
optional<const char *> format;
if (report.HANDLED(date_format_)) {
@@ -80,15 +80,15 @@ namespace {
std::ostringstream buf;
buf << format_date(item_t::use_effective_date ?
- xact.date() : xact.actual_date(),
- format_type, format);
+ xact.date() : xact.actual_date(),
+ format_type, format);
if (! item_t::use_effective_date && xact.effective_date())
buf << '=' << format_date(*xact.effective_date(),
- format_type, format);
+ format_type, format);
buf << ' ';
buf << (xact.state() == item_t::CLEARED ? "* " :
- (xact.state() == item_t::PENDING ? "! " : ""));
+ (xact.state() == item_t::PENDING ? "! " : ""));
if (xact.code)
buf << '(' << *xact.code << ") ";
@@ -99,7 +99,7 @@ namespace {
out << leader;
std::size_t columns = (report.HANDLED(columns_) ?
- report.HANDLER(columns_).value.to_long() : 80);
+ report.HANDLER(columns_).value.to_long() : 80);
if (xact.note)
print_note(out, *xact.note, columns, unistring(leader).length());
@@ -107,109 +107,112 @@ namespace {
if (xact.metadata) {
foreach (const item_t::string_map::value_type& data, *xact.metadata) {
- if (! data.second.second) {
- out << " ; ";
- if (data.second.first)
- out << data.first << ": " << *data.second.first;
- else
- out << ':' << data.first << ":";
- out << '\n';
- }
+ if (! data.second.second) {
+ out << " ; ";
+ if (data.second.first)
+ out << data.first << ": " << *data.second.first;
+ else
+ out << ':' << data.first << ":";
+ out << '\n';
+ }
}
}
foreach (post_t * post, xact.posts) {
- if (post->has_flags(ITEM_TEMP | ITEM_GENERATED) &&
- ! post->has_flags(POST_ANONYMIZED) &&
- ! report.HANDLED(print_virtual))
- continue;
+ if (! report.HANDLED(generated) &&
+ (post->has_flags(ITEM_TEMP | ITEM_GENERATED) &&
+ ! post->has_flags(POST_ANONYMIZED)))
+ continue;
out << " ";
std::ostringstream buf;
if (xact.state() == item_t::UNCLEARED)
- buf << (post->state() == item_t::CLEARED ? "* " :
- (post->state() == item_t::PENDING ? "! " : ""));
+ buf << (post->state() == item_t::CLEARED ? "* " :
+ (post->state() == item_t::PENDING ? "! " : ""));
if (post->has_flags(POST_VIRTUAL)) {
- if (post->has_flags(POST_MUST_BALANCE))
- buf << '[';
- else
- buf << '(';
+ if (post->has_flags(POST_MUST_BALANCE))
+ buf << '[';
+ else
+ buf << '(';
}
buf << post->account->fullname();
if (post->has_flags(POST_VIRTUAL)) {
- if (post->has_flags(POST_MUST_BALANCE))
- buf << ']';
- else
- buf << ')';
+ if (post->has_flags(POST_MUST_BALANCE))
+ buf << ']';
+ else
+ buf << ')';
}
unistring name(buf.str());
std::size_t account_width =
- (report.HANDLER(account_width_).specified ?
- report.HANDLER(account_width_).value.to_long() : 36);
+ (report.HANDLER(account_width_).specified ?
+ report.HANDLER(account_width_).value.to_long() : 36);
if (account_width < name.length())
- account_width = name.length();
-
- if (! post->has_flags(POST_CALCULATED) || report.HANDLED(print_virtual)) {
- out << name.extract();
- int slip = (static_cast<int>(account_width) -
- static_cast<int>(name.length()));
- if (slip > 0) {
- out.width(slip);
- out << ' ';
- }
-
- std::ostringstream amtbuf;
-
- string amt;
- if (post->amount_expr) {
- amt = post->amount_expr->text();
- } else {
- std::size_t amount_width =
- (report.HANDLER(amount_width_).specified ?
- report.HANDLER(amount_width_).value.to_long() : 12);
-
- std::ostringstream amt_str;
- report.scrub(post->amount)
- .print(amt_str, static_cast<int>(amount_width), -1, true);
- amt = amt_str.str();
- }
-
- string trimmed_amt(amt);
- trim_left(trimmed_amt);
- int amt_slip = (static_cast<int>(amt.length()) -
- static_cast<int>(trimmed_amt.length()));
- if (slip + amt_slip < 2)
- amtbuf << string(2 - (slip + amt_slip), ' ');
- amtbuf << amt;
-
- if (post->cost && ! post->has_flags(POST_CALCULATED)) {
- if (post->has_flags(POST_COST_IN_FULL))
- amtbuf << " @@ " << report.scrub(post->cost->abs());
- else
- amtbuf << " @ " << report.scrub((*post->cost / post->amount).abs());
- }
-
- if (post->assigned_amount)
- amtbuf << " = " << report.scrub(*post->assigned_amount);
-
- string trailer = amtbuf.str();
- out << trailer;
-
- account_width += unistring(trailer).length();
+ account_width = name.length();
+
+ if (! post->has_flags(POST_CALCULATED) || report.HANDLED(generated)) {
+ out << name.extract();
+ int slip = (static_cast<int>(account_width) -
+ static_cast<int>(name.length()));
+ if (slip > 0) {
+ out.width(slip);
+ out << ' ';
+ }
+
+ std::ostringstream amtbuf;
+
+ string amt;
+ if (post->amount_expr) {
+ amt = post->amount_expr->text();
+ } else {
+ int amount_width =
+ (report.HANDLER(amount_width_).specified ?
+ report.HANDLER(amount_width_).value.to_int() : 12);
+
+ std::ostringstream amt_str;
+ value_t(post->amount).print(amt_str, amount_width, -1,
+ AMOUNT_PRINT_RIGHT_JUSTIFY |
+ AMOUNT_PRINT_NO_COMPUTED_ANNOTATIONS);
+ amt = amt_str.str();
+ }
+
+ string trimmed_amt(amt);
+ trim_left(trimmed_amt);
+ int amt_slip = (static_cast<int>(amt.length()) -
+ static_cast<int>(trimmed_amt.length()));
+ if (slip + amt_slip < 2)
+ amtbuf << string(2 - (slip + amt_slip), ' ');
+ amtbuf << amt;
+
+ if (post->cost &&
+ ! post->has_flags(POST_CALCULATED | POST_COST_CALCULATED)) {
+ if (post->has_flags(POST_COST_IN_FULL))
+ amtbuf << " @@ " << post->cost->abs();
+ else
+ amtbuf << " @ "
+ << (*post->cost / post->amount).abs();
+ }
+
+ if (post->assigned_amount)
+ amtbuf << " = " << *post->assigned_amount;
+
+ string trailer = amtbuf.str();
+ out << trailer;
+
+ account_width += unistring(trailer).length();
} else {
- out << buf.str();
+ out << buf.str();
}
if (post->note)
- print_note(out, *post->note, columns, 4 + account_width);
+ print_note(out, *post->note, columns, 4 + account_width);
out << '\n';
}
}
diff --git a/src/print.h b/src/print.h
index f6ef0868..527f1912 100644
--- a/src/print.h
+++ b/src/print.h
@@ -55,14 +55,14 @@ class report_t;
class print_xacts : public item_handler<post_t>
{
protected:
- typedef std::list<xact_t *> xacts_list;
+ typedef std::list<xact_t *> xacts_list;
typedef std::map<xact_t *, bool> xacts_present_map;
- report_t& report;
+ report_t& report;
xacts_present_map xacts_present;
- xacts_list xacts;
- bool print_raw;
- bool first_title;
+ xacts_list xacts;
+ bool print_raw;
+ bool first_title;
public:
print_xacts(report_t& _report, bool _print_raw = false)
@@ -86,7 +86,6 @@ public:
}
};
-
} // namespace ledger
#endif // _PRINT_H
diff --git a/src/pstream.h b/src/pstream.h
index bba2845e..5fac20bd 100644
--- a/src/pstream.h
+++ b/src/pstream.h
@@ -53,44 +53,44 @@ class ptristream : public std::istream
ptrinbuf& operator=(const ptrinbuf&);
protected:
- char * ptr;
+ char * ptr;
std::size_t len;
public:
ptrinbuf(char * _ptr, std::size_t _len) : ptr(_ptr), len(_len) {
if (*ptr && len == 0)
- len = std::strlen(ptr);
+ len = std::strlen(ptr);
- setg(ptr, // beginning of putback area
- ptr, // read position
- ptr+len); // end position
+ setg(ptr, // beginning of putback area
+ ptr, // read position
+ ptr+len); // end position
}
protected:
virtual int_type underflow() {
// is read position before end of buffer?
if (gptr() < egptr())
- return traits_type::to_int_type(*gptr());
+ return traits_type::to_int_type(*gptr());
else
- return EOF;
+ return EOF;
}
virtual pos_type seekoff(off_type off, ios_base::seekdir way,
- ios_base::openmode)
+ ios_base::openmode)
{
switch (way) {
case std::ios::cur:
- setg(ptr, gptr()+off, ptr+len);
- break;
+ setg(ptr, gptr()+off, ptr+len);
+ break;
case std::ios::beg:
- setg(ptr, ptr+off, ptr+len);
- break;
+ setg(ptr, ptr+off, ptr+len);
+ break;
case std::ios::end:
- setg(ptr, egptr()+off, ptr+len);
- break;
+ setg(ptr, egptr()+off, ptr+len);
+ break;
default:
- return pos_type(off_type(-1));
+ return pos_type(off_type(-1));
}
return pos_type(gptr() - ptr);
}
diff --git a/src/py_account.cc b/src/py_account.cc
index 2b860a24..af51ffce 100644
--- a/src/py_account.cc
+++ b/src/py_account.cc
@@ -82,7 +82,7 @@ namespace {
}
account_t * py_find_account_2(journal_t& journal, const string& name,
- const bool auto_create)
+ const bool auto_create)
{
return journal.find_account(name, auto_create);
}
@@ -99,14 +99,14 @@ namespace {
void export_account()
{
- scope().attr("ACCOUNT_EXT_SORT_CALC") = ACCOUNT_EXT_SORT_CALC;
+ scope().attr("ACCOUNT_EXT_SORT_CALC") = ACCOUNT_EXT_SORT_CALC;
scope().attr("ACCOUNT_EXT_HAS_NON_VIRTUALS") = ACCOUNT_EXT_HAS_NON_VIRTUALS;
scope().attr("ACCOUNT_EXT_HAS_UNB_VIRTUALS") = ACCOUNT_EXT_HAS_UNB_VIRTUALS;
scope().attr("ACCOUNT_EXT_AUTO_VIRTUALIZE") = ACCOUNT_EXT_AUTO_VIRTUALIZE;
- scope().attr("ACCOUNT_EXT_VISITED") = ACCOUNT_EXT_VISITED;
- scope().attr("ACCOUNT_EXT_MATCHING") = ACCOUNT_EXT_MATCHING;
+ scope().attr("ACCOUNT_EXT_VISITED") = ACCOUNT_EXT_VISITED;
+ scope().attr("ACCOUNT_EXT_MATCHING") = ACCOUNT_EXT_MATCHING;
scope().attr("ACCOUNT_EXT_TO_DISPLAY") = ACCOUNT_EXT_TO_DISPLAY;
- scope().attr("ACCOUNT_EXT_DISPLAYED") = ACCOUNT_EXT_DISPLAYED;
+ scope().attr("ACCOUNT_EXT_DISPLAYED") = ACCOUNT_EXT_DISPLAYED;
class_< account_t::xdata_t::details_t > ("AccountXDataDetails")
.def_readonly("total", &account_t::xdata_t::details_t::total)
@@ -115,30 +115,30 @@ void export_account()
.def_readonly("posts_count", &account_t::xdata_t::details_t::posts_count)
.def_readonly("posts_virtuals_count",
- &account_t::xdata_t::details_t::posts_virtuals_count)
+ &account_t::xdata_t::details_t::posts_virtuals_count)
.def_readonly("posts_cleared_count",
- &account_t::xdata_t::details_t::posts_cleared_count)
+ &account_t::xdata_t::details_t::posts_cleared_count)
.def_readonly("posts_last_7_count",
- &account_t::xdata_t::details_t::posts_last_7_count)
+ &account_t::xdata_t::details_t::posts_last_7_count)
.def_readonly("posts_last_30_count",
- &account_t::xdata_t::details_t::posts_last_30_count)
+ &account_t::xdata_t::details_t::posts_last_30_count)
.def_readonly("posts_this_month_count",
- &account_t::xdata_t::details_t::posts_this_month_count)
+ &account_t::xdata_t::details_t::posts_this_month_count)
.def_readonly("earliest_post",
- &account_t::xdata_t::details_t::earliest_post)
+ &account_t::xdata_t::details_t::earliest_post)
.def_readonly("earliest_cleared_post",
- &account_t::xdata_t::details_t::earliest_cleared_post)
+ &account_t::xdata_t::details_t::earliest_cleared_post)
.def_readonly("latest_post",
- &account_t::xdata_t::details_t::latest_post)
+ &account_t::xdata_t::details_t::latest_post)
.def_readonly("latest_cleared_post",
- &account_t::xdata_t::details_t::latest_cleared_post)
+ &account_t::xdata_t::details_t::latest_cleared_post)
.def_readonly("filenames", &account_t::xdata_t::details_t::filenames)
.def_readonly("accounts_referenced",
- &account_t::xdata_t::details_t::accounts_referenced)
+ &account_t::xdata_t::details_t::accounts_referenced)
.def_readonly("payees_referenced",
- &account_t::xdata_t::details_t::payees_referenced)
+ &account_t::xdata_t::details_t::payees_referenced)
.def(self += self)
@@ -148,8 +148,8 @@ void export_account()
class_< account_t::xdata_t > ("AccountXData")
#if 1
.add_property("flags",
- &supports_flags<uint_least16_t>::flags,
- &supports_flags<uint_least16_t>::set_flags)
+ &supports_flags<uint_least16_t>::flags,
+ &supports_flags<uint_least16_t>::set_flags)
.def("has_flags", &supports_flags<uint_least16_t>::has_flags)
.def("clear_flags", &supports_flags<uint_least16_t>::clear_flags)
.def("add_flags", &supports_flags<uint_least16_t>::add_flags)
@@ -163,14 +163,14 @@ void export_account()
;
scope().attr("ACCOUNT_NORMAL") = ACCOUNT_NORMAL;
- scope().attr("ACCOUNT_KNOWN") = ACCOUNT_KNOWN;
- scope().attr("ACCOUNT_TEMP") = ACCOUNT_TEMP;
+ scope().attr("ACCOUNT_KNOWN") = ACCOUNT_KNOWN;
+ scope().attr("ACCOUNT_TEMP") = ACCOUNT_TEMP;
class_< account_t > ("Account")
#if 1
.add_property("flags",
- &supports_flags<>::flags,
- &supports_flags<>::set_flags)
+ &supports_flags<>::flags,
+ &supports_flags<>::set_flags)
.def("has_flags", &supports_flags<>::has_flags)
.def("clear_flags", &supports_flags<>::clear_flags)
.def("add_flags", &supports_flags<>::add_flags)
@@ -178,8 +178,8 @@ void export_account()
#endif
.add_property("parent",
- make_getter(&account_t::parent,
- return_internal_reference<>()))
+ make_getter(&account_t::parent,
+ return_internal_reference<>()))
.def_readwrite("name", &account_t::name)
.def_readwrite("note", &account_t::note)
@@ -195,9 +195,9 @@ void export_account()
.def("remove_account", &account_t::remove_account)
.def("find_account", &account_t::find_account,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("find_account_re", &account_t::find_account,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("add_post", &account_t::add_post)
.def("remove_post", &account_t::remove_post)
@@ -208,24 +208,24 @@ void export_account()
.def("__getitem__", accounts_getitem, return_internal_reference<>())
.def("__iter__", python::range<return_internal_reference<> >
- (&account_t::accounts_begin, &account_t::accounts_end))
+ (&account_t::accounts_begin, &account_t::accounts_end))
.def("accounts", python::range<return_internal_reference<> >
- (&account_t::accounts_begin, &account_t::accounts_end))
+ (&account_t::accounts_begin, &account_t::accounts_end))
.def("posts", python::range<return_internal_reference<> >
- (&account_t::posts_begin, &account_t::posts_end))
+ (&account_t::posts_begin, &account_t::posts_end))
.def("has_xdata", &account_t::has_xdata)
.def("clear_xdata", &account_t::clear_xdata)
.def("xdata", py_xdata,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("amount", &account_t::amount)
.def("total", &account_t::total)
.def("self_details", &account_t::self_details,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("family_details", &account_t::family_details,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("has_xflags", &account_t::has_xflags)
.def("children_with_flags", &account_t::children_with_flags)
diff --git a/src/py_amount.cc b/src/py_amount.cc
index 5afe8c6b..0b9e0410 100644
--- a/src/py_amount.cc
+++ b/src/py_amount.cc
@@ -45,16 +45,16 @@ using namespace boost::python;
namespace {
boost::optional<amount_t> py_value_0(const amount_t& amount) {
- return amount.value(false, CURRENT_TIME());
+ return amount.value(CURRENT_TIME());
}
boost::optional<amount_t> py_value_1(const amount_t& amount,
- commodity_t& in_terms_of) {
- return amount.value(false, CURRENT_TIME(), in_terms_of);
+ commodity_t& in_terms_of) {
+ return amount.value(CURRENT_TIME(), in_terms_of);
}
boost::optional<amount_t> py_value_2(const amount_t& amount,
- commodity_t& in_terms_of,
- datetime_t& moment) {
- return amount.value(false, moment, in_terms_of);
+ commodity_t& in_terms_of,
+ datetime_t& moment) {
+ return amount.value(moment, in_terms_of);
}
void py_parse_2(amount_t& amount, object in, unsigned char flags) {
@@ -63,7 +63,7 @@ namespace {
amount.parse(instr, flags);
} else {
PyErr_SetString(PyExc_IOError,
- _("Argument to amount.parse(file) is not a file object"));
+ _("Argument to amount.parse(file) is not a file object"));
}
}
void py_parse_1(amount_t& amount, object in) {
@@ -83,7 +83,7 @@ namespace {
amount.print(outstr);
} else {
PyErr_SetString(PyExc_IOError,
- _("Argument to amount.print_(file) is not a file object"));
+ _("Argument to amount.print_(file) is not a file object"));
}
}
@@ -104,9 +104,9 @@ namespace {
} // unnamed namespace
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
EXC_TRANSLATOR(amount_error)
@@ -120,24 +120,24 @@ void export_amount()
.staticmethod("shutdown")
.add_static_property("is_initialized",
- make_getter(&amount_t::is_initialized),
- make_setter(&amount_t::is_initialized))
+ make_getter(&amount_t::is_initialized),
+ make_setter(&amount_t::is_initialized))
.add_static_property("stream_fullstrings",
- make_getter(&amount_t::stream_fullstrings),
- make_setter(&amount_t::stream_fullstrings))
+ make_getter(&amount_t::stream_fullstrings),
+ make_setter(&amount_t::stream_fullstrings))
.def(init<long>())
.def(init<std::string>())
.def("exact", &amount_t::exact, args("value"),
- _("Construct an amount object whose display precision is always equal to its\n\
+ _("Construct an amount object whose display precision is always equal to its\n\
internal precision."))
.staticmethod("exact")
.def(init<amount_t>())
.def("compare", &amount_t::compare, args("amount"),
- _("Compare two amounts for equality, returning <0, 0 or >0."))
+ _("Compare two amounts for equality, returning <0, 0 or >0."))
.def(self == self)
.def(self == long())
@@ -168,40 +168,40 @@ internal precision."))
.def(self += self)
.def(self += long())
- .def(self + self)
- .def(self + long())
- .def(long() + self)
+ .def(self + self)
+ .def(self + long())
+ .def(long() + self)
.def(self -= self)
.def(self -= long())
- .def(self - self)
- .def(self - long())
- .def(long() - self)
+ .def(self - self)
+ .def(self - long())
+ .def(long() - self)
.def(self *= self)
.def(self *= long())
- .def(self * self)
- .def(self * long())
- .def(long() * self)
+ .def(self * self)
+ .def(self * long())
+ .def(long() * self)
.def(self /= self)
.def(self /= long())
- .def(self / self)
- .def(self / long())
- .def(long() / self)
+ .def(self / self)
+ .def(self / long())
+ .def(long() / self)
.add_property("precision", &amount_t::precision)
.add_property("display_precision", &amount_t::display_precision)
.add_property("keep_precision",
- &amount_t::keep_precision,
- &amount_t::set_keep_precision)
+ &amount_t::keep_precision,
+ &amount_t::set_keep_precision)
.def("negated", &amount_t::negated)
.def("in_place_negate", &amount_t::in_place_negate,
- return_internal_reference<>())
+ return_internal_reference<>())
.def(- self)
.def("abs", &amount_t::abs)
@@ -211,27 +211,27 @@ internal precision."))
.def("rounded", &amount_t::rounded)
.def("in_place_round", &amount_t::in_place_round,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("truncated", &amount_t::truncated)
.def("in_place_truncate", &amount_t::in_place_truncate,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("floored", &amount_t::floored)
.def("in_place_floor", &amount_t::in_place_floor,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("unrounded", &amount_t::unrounded)
.def("in_place_unround", &amount_t::in_place_unround,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("reduced", &amount_t::reduced)
.def("in_place_reduce", &amount_t::in_place_reduce,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("unreduced", &amount_t::unreduced)
.def("in_place_unreduce", &amount_t::in_place_unreduce,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("value", py_value_0)
.def("value", py_value_1, args("in_terms_of"))
@@ -260,10 +260,10 @@ internal precision."))
.def("quantity_string", &amount_t::quantity_string)
.add_property("commodity",
- make_function(&amount_t::commodity,
- return_value_policy<reference_existing_object>()),
- make_function(&amount_t::set_commodity,
- with_custodian_and_ward<1, 2>()))
+ make_function(&amount_t::commodity,
+ return_value_policy<reference_existing_object>()),
+ make_function(&amount_t::set_commodity,
+ with_custodian_and_ward<1, 2>()))
.def("has_commodity", &amount_t::has_commodity)
.def("clear_commodity", &amount_t::clear_commodity)
@@ -272,8 +272,8 @@ internal precision."))
.def("annotate", &amount_t::annotate)
.def("has_annotation", &amount_t::has_annotation)
.add_property("annotation",
- make_function(py_amount_annotation,
- return_internal_reference<>()))
+ make_function(py_amount_annotation,
+ return_internal_reference<>()))
.def("strip_annotations", py_strip_annotations_0)
.def("strip_annotations", py_strip_annotations_1)
@@ -295,7 +295,6 @@ internal precision."))
.value("NoMigrate", PARSE_NO_MIGRATE)
.value("NoReduce", PARSE_NO_REDUCE)
.value("NoAssign", PARSE_NO_ASSIGN)
- .value("NoDates", PARSE_NO_DATES)
.value("OpContext", PARSE_OP_CONTEXT)
.value("SoftFail", PARSE_SOFT_FAIL)
;
diff --git a/src/py_balance.cc b/src/py_balance.cc
index 7be75444..eba5761d 100644
--- a/src/py_balance.cc
+++ b/src/py_balance.cc
@@ -45,16 +45,16 @@ using namespace boost::python;
namespace {
boost::optional<balance_t> py_value_0(const balance_t& balance) {
- return balance.value(false, CURRENT_TIME());
+ return balance.value(CURRENT_TIME());
}
boost::optional<balance_t> py_value_1(const balance_t& balance,
- commodity_t& in_terms_of) {
- return balance.value(false, CURRENT_TIME(), in_terms_of);
+ commodity_t& in_terms_of) {
+ return balance.value(CURRENT_TIME(), in_terms_of);
}
boost::optional<balance_t> py_value_2(const balance_t& balance,
- commodity_t& in_terms_of,
- datetime_t& moment) {
- return balance.value(false, moment, in_terms_of);
+ commodity_t& in_terms_of,
+ datetime_t& moment) {
+ return balance.value(moment, in_terms_of);
}
boost::optional<amount_t>
@@ -64,7 +64,7 @@ namespace {
boost::optional<amount_t>
py_commodity_amount_1(const balance_t& balance,
- const boost::optional<const commodity_t&>& commodity) {
+ const boost::optional<const commodity_t&>& commodity) {
return balance.commodity_amount(commodity);
}
@@ -74,7 +74,7 @@ namespace {
balance.print(outstr);
} else {
PyErr_SetString(PyExc_IOError,
- _("Argument to balance.print_(file) is not a file object"));
+ _("Argument to balance.print_(file) is not a file object"));
}
}
@@ -111,9 +111,9 @@ namespace {
} // unnamed namespace
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
EXC_TRANSLATOR(balance_error)
@@ -162,7 +162,7 @@ void export_balance()
.def("negated", &balance_t::negated)
.def("in_place_negate", &balance_t::in_place_negate,
- return_internal_reference<>())
+ return_internal_reference<>())
.def(- self)
.def("abs", &balance_t::abs)
@@ -173,27 +173,27 @@ void export_balance()
.def("rounded", &balance_t::rounded)
.def("in_place_round", &balance_t::in_place_round,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("truncated", &balance_t::truncated)
.def("in_place_truncate", &balance_t::in_place_truncate,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("floored", &balance_t::floored)
.def("in_place_floor", &balance_t::in_place_floor,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("unrounded", &balance_t::unrounded)
.def("in_place_unround", &balance_t::in_place_unround,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("reduced", &balance_t::reduced)
.def("in_place_reduce", &balance_t::in_place_reduce,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("unreduced", &balance_t::unreduced)
.def("in_place_unreduce", &balance_t::in_place_unreduce,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("value", py_value_0)
.def("value", py_value_1, args("in_terms_of"))
diff --git a/src/py_commodity.cc b/src/py_commodity.cc
index fc7e8c3e..783171dd 100644
--- a/src/py_commodity.cc
+++ b/src/py_commodity.cc
@@ -44,38 +44,38 @@ using namespace boost::python;
namespace {
commodity_t * py_create_1(commodity_pool_t& pool,
- const string& symbol)
+ const string& symbol)
{
return pool.create(symbol);
}
- commodity_t * py_create_2(commodity_pool_t& pool,
- const string& symbol,
- const annotation_t& details)
+ commodity_t * py_create_2(commodity_pool_t& pool,
+ const string& symbol,
+ const annotation_t& details)
{
return pool.create(symbol, details);
}
commodity_t * py_find_or_create_1(commodity_pool_t& pool,
- const string& symbol)
+ const string& symbol)
{
return pool.find_or_create(symbol);
}
- commodity_t * py_find_or_create_2(commodity_pool_t& pool,
- const string& symbol,
- const annotation_t& details)
+ commodity_t * py_find_or_create_2(commodity_pool_t& pool,
+ const string& symbol,
+ const annotation_t& details)
{
return pool.find_or_create(symbol, details);
}
commodity_t * py_find_1(commodity_pool_t& pool,
- const string& name)
+ const string& name)
{
return pool.find(name);
}
commodity_t * py_find_2(commodity_pool_t& pool,
- const string& symbol,
- const annotation_t& details)
+ const string& symbol,
+ const annotation_t& details)
{
return pool.find(symbol, details);
}
@@ -83,25 +83,25 @@ namespace {
// Exchange one commodity for another, while recording the factored price.
void py_exchange_2(commodity_pool_t& pool,
- commodity_t& commodity,
- const amount_t& per_unit_cost)
+ commodity_t& commodity,
+ const amount_t& per_unit_cost)
{
pool.exchange(commodity, per_unit_cost, CURRENT_TIME());
}
void py_exchange_3(commodity_pool_t& pool,
- commodity_t& commodity,
- const amount_t& per_unit_cost,
- const datetime_t& moment)
+ commodity_t& commodity,
+ const amount_t& per_unit_cost,
+ const datetime_t& moment)
{
pool.exchange(commodity, per_unit_cost, moment);
}
- cost_breakdown_t py_exchange_5(commodity_pool_t& pool,
- const amount_t& amount,
- const amount_t& cost,
- const bool is_per_unit,
- const boost::optional<datetime_t>& moment,
- const boost::optional<string>& tag)
+ cost_breakdown_t py_exchange_5(commodity_pool_t& pool,
+ const amount_t& amount,
+ const amount_t& cost,
+ const bool is_per_unit,
+ const boost::optional<datetime_t>& moment,
+ const boost::optional<string>& tag)
{
return pool.exchange(amount, cost, is_per_unit, moment, tag);
}
@@ -112,7 +112,7 @@ namespace {
pool.commodities.find(symbol);
if (i == pool.commodities.end()) {
PyErr_SetString(PyExc_ValueError,
- (string("Could not find commodity ") + symbol).c_str());
+ (string("Could not find commodity ") + symbol).c_str());
throw boost::python::error_already_set();
}
return (*i).second;
@@ -178,12 +178,12 @@ namespace {
}
void py_add_price_2(commodity_t& commodity,
- const datetime_t& date, const amount_t& price) {
+ const datetime_t& date, const amount_t& price) {
commodity.add_price(date, price);
}
void py_add_price_3(commodity_t& commodity, const datetime_t& date,
- const amount_t& price, const bool reflexive) {
+ const amount_t& price, const bool reflexive) {
commodity.add_price(date, price, reflexive);
}
@@ -212,7 +212,7 @@ namespace {
return comm.strip_annotations(keep_details_t());
}
commodity_t& py_strip_annotations_1(commodity_t& comm,
- const keep_details_t& keep) {
+ const keep_details_t& keep) {
return comm.strip_annotations(keep);
}
@@ -220,7 +220,7 @@ namespace {
return comm.strip_annotations(keep_details_t());
}
commodity_t& py_strip_ann_annotations_1(annotated_commodity_t& comm,
- const keep_details_t& keep) {
+ const keep_details_t& keep) {
return comm.strip_annotations(keep);
}
@@ -228,7 +228,7 @@ namespace {
return ann.price;
}
boost::optional<amount_t> py_set_price(annotation_t& ann,
- const boost::optional<amount_t>& price) {
+ const boost::optional<amount_t>& price) {
return ann.price = price;
}
@@ -243,41 +243,41 @@ void export_commodity()
class_< commodity_pool_t, shared_ptr<commodity_pool_t>,
boost::noncopyable > ("CommodityPool", no_init)
.add_property("null_commodity",
- make_getter(&commodity_pool_t::null_commodity,
- return_internal_reference<>()))
+ make_getter(&commodity_pool_t::null_commodity,
+ return_internal_reference<>()))
.add_property("default_commodity",
- make_getter(&commodity_pool_t::default_commodity,
- return_internal_reference<>()),
- make_setter(&commodity_pool_t::default_commodity,
- with_custodian_and_ward<1, 2>()))
+ make_getter(&commodity_pool_t::default_commodity,
+ return_internal_reference<>()),
+ make_setter(&commodity_pool_t::default_commodity,
+ with_custodian_and_ward<1, 2>()))
.add_property("keep_base",
- make_getter(&commodity_pool_t::keep_base),
- make_setter(&commodity_pool_t::keep_base))
+ make_getter(&commodity_pool_t::keep_base),
+ make_setter(&commodity_pool_t::keep_base))
.add_property("price_db",
- make_getter(&commodity_pool_t::price_db),
- make_setter(&commodity_pool_t::price_db))
+ make_getter(&commodity_pool_t::price_db),
+ make_setter(&commodity_pool_t::price_db))
.add_property("quote_leeway",
- make_getter(&commodity_pool_t::quote_leeway),
- make_setter(&commodity_pool_t::quote_leeway))
+ make_getter(&commodity_pool_t::quote_leeway),
+ make_setter(&commodity_pool_t::quote_leeway))
.add_property("get_quotes",
- make_getter(&commodity_pool_t::get_quotes),
- make_setter(&commodity_pool_t::get_quotes))
+ make_getter(&commodity_pool_t::get_quotes),
+ make_setter(&commodity_pool_t::get_quotes))
.add_property("get_commodity_quote",
- make_getter(&commodity_pool_t::get_commodity_quote),
- make_setter(&commodity_pool_t::get_commodity_quote))
+ make_getter(&commodity_pool_t::get_commodity_quote),
+ make_setter(&commodity_pool_t::get_commodity_quote))
.def("make_qualified_name", &commodity_pool_t::make_qualified_name)
.def("create", py_create_1,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("create", py_create_2,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("find_or_create", py_find_or_create_1,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("find_or_create", py_find_or_create_2,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("find", py_find_1, return_value_policy<reference_existing_object>())
.def("find", py_find_2, return_value_policy<reference_existing_object>())
@@ -288,46 +288,46 @@ void export_commodity()
.def("parse_price_directive", &commodity_pool_t::parse_price_directive)
.def("parse_price_expression", &commodity_pool_t::parse_price_expression,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("__getitem__", py_pool_getitem,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("keys", py_pool_keys)
.def("has_key", py_pool_contains)
.def("__contains__", py_pool_contains)
.def("__iter__",
- python::range<return_value_policy<reference_existing_object> >
- (py_pool_commodities_begin, py_pool_commodities_end))
+ python::range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
.def("iteritems",
- python::range<return_value_policy<reference_existing_object> >
- (py_pool_commodities_begin, py_pool_commodities_end))
+ python::range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_begin, py_pool_commodities_end))
.def("iterkeys", python::range<>(py_pool_commodities_keys_begin,
- py_pool_commodities_keys_end))
+ py_pool_commodities_keys_end))
.def("itervalues",
- python::range<return_value_policy<reference_existing_object> >
- (py_pool_commodities_values_begin, py_pool_commodities_values_end))
+ python::range<return_value_policy<reference_existing_object> >
+ (py_pool_commodities_values_begin, py_pool_commodities_values_end))
;
map_value_type_converter<commodity_pool_t::commodities_map>();
scope().attr("commodities") = commodity_pool_t::current_pool;
- scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS;
- scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED;
- scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED;
+ scope().attr("COMMODITY_STYLE_DEFAULTS") = COMMODITY_STYLE_DEFAULTS;
+ scope().attr("COMMODITY_STYLE_SUFFIXED") = COMMODITY_STYLE_SUFFIXED;
+ scope().attr("COMMODITY_STYLE_SEPARATED") = COMMODITY_STYLE_SEPARATED;
scope().attr("COMMODITY_STYLE_DECIMAL_COMMA") = COMMODITY_STYLE_DECIMAL_COMMA;
- scope().attr("COMMODITY_STYLE_THOUSANDS") = COMMODITY_STYLE_THOUSANDS;
- scope().attr("COMMODITY_NOMARKET") = COMMODITY_NOMARKET;
- scope().attr("COMMODITY_BUILTIN") = COMMODITY_BUILTIN;
- scope().attr("COMMODITY_WALKED") = COMMODITY_WALKED;
- scope().attr("COMMODITY_KNOWN") = COMMODITY_KNOWN;
- scope().attr("COMMODITY_PRIMARY") = COMMODITY_PRIMARY;
+ scope().attr("COMMODITY_STYLE_THOUSANDS") = COMMODITY_STYLE_THOUSANDS;
+ scope().attr("COMMODITY_NOMARKET") = COMMODITY_NOMARKET;
+ scope().attr("COMMODITY_BUILTIN") = COMMODITY_BUILTIN;
+ scope().attr("COMMODITY_WALKED") = COMMODITY_WALKED;
+ scope().attr("COMMODITY_KNOWN") = COMMODITY_KNOWN;
+ scope().attr("COMMODITY_PRIMARY") = COMMODITY_PRIMARY;
class_< commodity_t, boost::noncopyable > ("Commodity", no_init)
#if 1
.add_property("flags",
- &supports_flags<uint_least16_t>::flags,
- &supports_flags<uint_least16_t>::set_flags)
+ &supports_flags<uint_least16_t>::flags,
+ &supports_flags<uint_least16_t>::set_flags)
.def("has_flags", &delegates_flags<uint_least16_t>::has_flags)
.def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags)
.def("add_flags", &delegates_flags<uint_least16_t>::add_flags)
@@ -335,8 +335,8 @@ void export_commodity()
#endif
.add_static_property("decimal_comma_by_default",
- make_getter(&commodity_t::decimal_comma_by_default),
- make_setter(&commodity_t::decimal_comma_by_default))
+ make_getter(&commodity_t::decimal_comma_by_default),
+ make_setter(&commodity_t::decimal_comma_by_default))
.def("__str__", &commodity_t::symbol)
.def("__unicode__", py_commodity_unicode)
@@ -348,18 +348,18 @@ void export_commodity()
.staticmethod("symbol_needs_quotes")
.add_property("referent",
- make_function(py_commodity_referent,
- return_value_policy<reference_existing_object>()))
+ make_function(py_commodity_referent,
+ return_value_policy<reference_existing_object>()))
.def("has_annotation", &commodity_t::has_annotation)
.def("strip_annotations", py_strip_annotations_0,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("strip_annotations", py_strip_annotations_1,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("write_annotations", &commodity_t::write_annotations)
.def("pool", &commodity_t::pool,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.add_property("base_symbol", &commodity_t::base_symbol)
.add_property("symbol", &commodity_t::symbol)
@@ -368,14 +368,14 @@ void export_commodity()
.add_property("name", &commodity_t::name, &commodity_t::set_name)
.add_property("note", &commodity_t::note, &commodity_t::set_note)
.add_property("precision", &commodity_t::precision,
- &commodity_t::set_precision)
+ &commodity_t::set_precision)
.add_property("smaller", &commodity_t::smaller, &commodity_t::set_smaller)
.add_property("larger", &commodity_t::larger, &commodity_t::set_larger)
.def("add_price", py_add_price_2)
.def("add_price", py_add_price_3)
.def("remove_price", &commodity_t::remove_price,
- with_custodian_and_ward<1, 3>())
+ with_custodian_and_ward<1, 3>())
.def("find_price", &commodity_t::find_price)
.def("check_for_updated_price", &commodity_t::check_for_updated_price)
@@ -385,7 +385,7 @@ void export_commodity()
class_< annotation_t > ("Annotation", no_init)
#if 1
.add_property("flags", &supports_flags<>::flags,
- &supports_flags<>::set_flags)
+ &supports_flags<>::set_flags)
.def("has_flags", &supports_flags<>::has_flags)
.def("clear_flags", &supports_flags<>::clear_flags)
.def("add_flags", &supports_flags<>::add_flags)
@@ -394,11 +394,11 @@ void export_commodity()
.add_property("price", py_price, py_set_price)
.add_property("date",
- make_getter(&annotation_t::date),
- make_setter(&annotation_t::date))
+ make_getter(&annotation_t::date),
+ make_setter(&annotation_t::date))
.add_property("tag",
- make_getter(&annotation_t::tag),
- make_setter(&annotation_t::tag))
+ make_getter(&annotation_t::tag),
+ make_setter(&annotation_t::tag))
.def("__nonzero__", &annotation_t::operator bool)
@@ -411,17 +411,17 @@ void export_commodity()
.def(init<bool, bool, bool, bool>())
.add_property("keep_price",
- make_getter(&keep_details_t::keep_price),
- make_setter(&keep_details_t::keep_price))
+ make_getter(&keep_details_t::keep_price),
+ make_setter(&keep_details_t::keep_price))
.add_property("keep_date",
- make_getter(&keep_details_t::keep_date),
- make_setter(&keep_details_t::keep_date))
+ make_getter(&keep_details_t::keep_date),
+ make_setter(&keep_details_t::keep_date))
.add_property("keep_tag",
- make_getter(&keep_details_t::keep_tag),
- make_setter(&keep_details_t::keep_tag))
+ make_getter(&keep_details_t::keep_tag),
+ make_setter(&keep_details_t::keep_tag))
.add_property("only_actuals",
- make_getter(&keep_details_t::only_actuals),
- make_setter(&keep_details_t::only_actuals))
+ make_getter(&keep_details_t::only_actuals),
+ make_setter(&keep_details_t::only_actuals))
.def("keep_all", py_keep_all_0)
.def("keep_all", py_keep_all_1)
@@ -433,20 +433,20 @@ void export_commodity()
annotated_commodity_t, boost::noncopyable >
("AnnotatedCommodity", no_init)
.add_property("details",
- make_getter(&annotated_commodity_t::details),
- make_setter(&annotated_commodity_t::details))
+ make_getter(&annotated_commodity_t::details),
+ make_setter(&annotated_commodity_t::details))
.def(self == self)
.def(self == other<commodity_t>())
.add_property("referent",
- make_function(py_annotated_commodity_referent,
- return_value_policy<reference_existing_object>()))
+ make_function(py_annotated_commodity_referent,
+ return_value_policy<reference_existing_object>()))
.def("strip_annotations", py_strip_ann_annotations_0,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("strip_annotations", py_strip_ann_annotations_1,
- return_value_policy<reference_existing_object>())
+ return_value_policy<reference_existing_object>())
.def("write_annotations", &annotated_commodity_t::write_annotations)
;
}
diff --git a/src/py_format.cc b/src/py_format.cc
index 36f89ae5..ce7052ac 100644
--- a/src/py_format.cc
+++ b/src/py_format.cc
@@ -37,9 +37,9 @@ namespace ledger {
using namespace boost::python;
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
//EXC_TRANSLATOR(format_error)
diff --git a/src/py_item.cc b/src/py_item.cc
index edebd532..e37228fe 100644
--- a/src/py_item.cc
+++ b/src/py_item.cc
@@ -49,26 +49,26 @@ namespace {
return item.has_tag(tag_mask);
}
bool py_has_tag_2m(item_t& item, const mask_t& tag_mask,
- const boost::optional<mask_t>& value_mask) {
+ const boost::optional<mask_t>& value_mask) {
return item.has_tag(tag_mask, value_mask);
}
- boost::optional<string> py_get_tag_1s(item_t& item, const string& tag) {
+ boost::optional<value_t> py_get_tag_1s(item_t& item, const string& tag) {
return item.get_tag(tag);
}
- boost::optional<string> py_get_tag_1m(item_t& item, const mask_t& tag_mask) {
+ boost::optional<value_t> py_get_tag_1m(item_t& item, const mask_t& tag_mask) {
return item.get_tag(tag_mask);
}
- boost::optional<string> py_get_tag_2m(item_t& item, const mask_t& tag_mask,
- const boost::optional<mask_t>& value_mask) {
+ boost::optional<value_t> py_get_tag_2m(item_t& item, const mask_t& tag_mask,
+ const boost::optional<mask_t>& value_mask) {
return item.get_tag(tag_mask, value_mask);
}
} // unnamed namespace
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
//EXC_TRANSLATOR(item_error)
@@ -77,25 +77,25 @@ void export_item()
{
class_< position_t > ("Position")
.add_property("pathname",
- make_getter(&position_t::pathname),
- make_setter(&position_t::pathname))
+ make_getter(&position_t::pathname),
+ make_setter(&position_t::pathname))
.add_property("beg_pos",
- make_getter(&position_t::beg_pos),
- make_setter(&position_t::beg_pos))
+ make_getter(&position_t::beg_pos),
+ make_setter(&position_t::beg_pos))
.add_property("beg_line",
- make_getter(&position_t::beg_line),
- make_setter(&position_t::beg_line))
+ make_getter(&position_t::beg_line),
+ make_setter(&position_t::beg_line))
.add_property("end_pos",
- make_getter(&position_t::end_pos),
- make_setter(&position_t::end_pos))
+ make_getter(&position_t::end_pos),
+ make_setter(&position_t::end_pos))
.add_property("end_line",
- make_getter(&position_t::end_line),
- make_setter(&position_t::end_line))
+ make_getter(&position_t::end_line),
+ make_setter(&position_t::end_line))
;
- scope().attr("ITEM_NORMAL") = ITEM_NORMAL;
+ scope().attr("ITEM_NORMAL") = ITEM_NORMAL;
scope().attr("ITEM_GENERATED") = ITEM_GENERATED;
- scope().attr("ITEM_TEMP") = ITEM_TEMP;
+ scope().attr("ITEM_TEMP") = ITEM_TEMP;
enum_< item_t::state_t > ("State")
.value("Uncleared", item_t::UNCLEARED)
@@ -106,11 +106,11 @@ void export_item()
#if 0
class_< item_t, bases<scope_t> > ("JournalItem", init<uint_least8_t>())
#else
- class_< item_t > ("JournalItem", init<uint_least8_t>())
+ class_< item_t, noncopyable > ("JournalItem", no_init)
#endif
#if 1
.add_property("flags", &supports_flags<>::flags,
- &supports_flags<>::set_flags)
+ &supports_flags<>::set_flags)
.def("has_flags", &supports_flags<>::has_flags)
.def("clear_flags", &supports_flags<>::clear_flags)
.def("add_flags", &supports_flags<>::add_flags)
@@ -118,14 +118,14 @@ void export_item()
#endif
.add_property("note",
- make_getter(&item_t::note),
- make_setter(&item_t::note))
+ make_getter(&item_t::note),
+ make_setter(&item_t::note))
.add_property("pos",
- make_getter(&item_t::pos),
- make_setter(&item_t::pos))
+ make_getter(&item_t::pos),
+ make_setter(&item_t::pos))
.add_property("metadata",
- make_getter(&item_t::metadata),
- make_setter(&item_t::metadata))
+ make_getter(&item_t::metadata),
+ make_setter(&item_t::metadata))
.def("copy_details", &item_t::copy_details)
@@ -148,12 +148,12 @@ void export_item()
.def("append_note", &item_t::append_note)
.add_static_property("use_effective_date",
- make_getter(&item_t::use_effective_date),
- make_setter(&item_t::use_effective_date))
+ make_getter(&item_t::use_effective_date),
+ make_setter(&item_t::use_effective_date))
.add_property("date", &item_t::date, make_setter(&item_t::_date))
.add_property("effective_date", &item_t::effective_date,
- make_setter(&item_t::_date_eff))
+ make_setter(&item_t::_date_eff))
.add_property("state", &item_t::state, &item_t::set_state)
diff --git a/src/py_journal.cc b/src/py_journal.cc
index cd25d134..fc4f671b 100644
--- a/src/py_journal.cc
+++ b/src/py_journal.cc
@@ -126,7 +126,7 @@ namespace {
}
account_t * py_find_account_2(journal_t& journal, const string& name,
- const bool auto_create)
+ const bool auto_create)
{
return journal.find_account(name, auto_create);
}
@@ -138,14 +138,14 @@ namespace {
struct collector_wrapper
{
- journal_t& journal;
+ journal_t& journal;
report_t report;
collect_posts * posts_collector;
post_handler_ptr chain;
collector_wrapper(journal_t& _journal, report_t& base)
: journal(_journal), report(base),
- posts_collector(new collect_posts) {}
+ posts_collector(new collect_posts) {}
~collector_wrapper() {
journal.clear_xdata();
}
@@ -167,31 +167,31 @@ namespace {
{
if (journal.has_xdata()) {
PyErr_SetString(PyExc_RuntimeError,
- _("Cannot have multiple journal collections open at once"));
+ _("Cannot have multiple journal collections open at once"));
throw_error_already_set();
}
report_t& current_report(downcast<report_t>(*scope_t::default_scope));
shared_ptr<collector_wrapper> coll(new collector_wrapper(journal,
- current_report));
+ current_report));
std::auto_ptr<journal_t> save_journal
(current_report.session.journal.release());
current_report.session.journal.reset(&journal);
try {
strings_list remaining =
- process_arguments(split_arguments(query.c_str()), coll->report);
+ process_arguments(split_arguments(query.c_str()), coll->report);
coll->report.normalize_options("register");
value_t args;
foreach (const string& arg, remaining)
- args.push_back(string_value(arg));
+ args.push_back(string_value(arg));
coll->report.parse_query_args(args, "@Journal.collect");
journal_posts_iterator walker(coll->journal);
coll->chain =
- chain_post_handlers(post_handler_ptr(coll->posts_collector),
- coll->report);
+ chain_post_handlers(post_handler_ptr(coll->posts_collector),
+ coll->report);
pass_down_posts(coll->chain, walker);
}
catch (...) {
@@ -227,36 +227,36 @@ void export_journal()
shared_ptr<collect_posts>, boost::noncopyable >("PostCollector")
.def("__len__", &collect_posts::length)
.def("__iter__", python::range<return_internal_reference<1,
- with_custodian_and_ward_postcall<1, 0> > >
- (&collect_posts::begin, &collect_posts::end))
+ with_custodian_and_ward_postcall<1, 0> > >
+ (&collect_posts::begin, &collect_posts::end))
;
class_< collector_wrapper, shared_ptr<collector_wrapper>,
boost::noncopyable >("PostCollectorWrapper", no_init)
.def("__len__", &collector_wrapper::length)
.def("__getitem__", posts_getitem, return_internal_reference<1,
- with_custodian_and_ward_postcall<0, 1> >())
+ with_custodian_and_ward_postcall<0, 1> >())
.def("__iter__",
- python::range<return_value_policy<reference_existing_object,
- with_custodian_and_ward_postcall<0, 1> > >
- (&collector_wrapper::begin, &collector_wrapper::end))
+ python::range<return_value_policy<reference_existing_object,
+ with_custodian_and_ward_postcall<0, 1> > >
+ (&collector_wrapper::begin, &collector_wrapper::end))
;
class_< journal_t::fileinfo_t > ("FileInfo")
.def(init<path>())
.add_property("filename",
- make_getter(&journal_t::fileinfo_t::filename),
- make_setter(&journal_t::fileinfo_t::filename))
+ make_getter(&journal_t::fileinfo_t::filename),
+ make_setter(&journal_t::fileinfo_t::filename))
.add_property("size",
- make_getter(&journal_t::fileinfo_t::size),
- make_setter(&journal_t::fileinfo_t::size))
+ make_getter(&journal_t::fileinfo_t::size),
+ make_setter(&journal_t::fileinfo_t::size))
.add_property("modtime",
- make_getter(&journal_t::fileinfo_t::modtime),
- make_setter(&journal_t::fileinfo_t::modtime))
+ make_getter(&journal_t::fileinfo_t::modtime),
+ make_setter(&journal_t::fileinfo_t::modtime))
.add_property("from_stream",
- make_getter(&journal_t::fileinfo_t::from_stream),
- make_setter(&journal_t::fileinfo_t::from_stream))
+ make_getter(&journal_t::fileinfo_t::from_stream),
+ make_setter(&journal_t::fileinfo_t::from_stream))
;
class_< journal_t, boost::noncopyable > ("Journal")
@@ -264,28 +264,28 @@ void export_journal()
.def(init<string>())
.add_property("master",
- make_getter(&journal_t::master,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<1, 0> >()))
+ make_getter(&journal_t::master,
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<1, 0> >()))
.add_property("bucket",
- make_getter(&journal_t::bucket,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<1, 0> >()),
- make_setter(&journal_t::bucket))
+ make_getter(&journal_t::bucket,
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<1, 0> >()),
+ make_setter(&journal_t::bucket))
.add_property("was_loaded", make_getter(&journal_t::was_loaded))
.def("add_account", &journal_t::add_account)
.def("remove_account", &journal_t::remove_account)
.def("find_account", py_find_account_1,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<0, 1> >())
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<0, 1> >())
.def("find_account", py_find_account_2,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<0, 1> >())
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<0, 1> >())
.def("find_account_re", &journal_t::find_account_re,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<0, 1> >())
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<0, 1> >())
.def("add_xact", &journal_t::add_xact)
.def("remove_xact", &journal_t::remove_xact)
@@ -293,20 +293,20 @@ void export_journal()
.def("__len__", xacts_len)
#if 0
.def("__getitem__", xacts_getitem,
- return_internal_reference<1,
- with_custodian_and_ward_postcall<0, 1> >())
+ return_internal_reference<1,
+ with_custodian_and_ward_postcall<0, 1> >())
#endif
.def("__iter__", python::range<return_internal_reference<> >
- (&journal_t::xacts_begin, &journal_t::xacts_end))
+ (&journal_t::xacts_begin, &journal_t::xacts_end))
.def("xacts", python::range<return_internal_reference<> >
- (&journal_t::xacts_begin, &journal_t::xacts_end))
+ (&journal_t::xacts_begin, &journal_t::xacts_end))
.def("auto_xacts", python::range<return_internal_reference<> >
- (&journal_t::auto_xacts_begin, &journal_t::auto_xacts_end))
+ (&journal_t::auto_xacts_begin, &journal_t::auto_xacts_end))
.def("period_xacts", python::range<return_internal_reference<> >
- (&journal_t::period_xacts_begin, &journal_t::period_xacts_end))
+ (&journal_t::period_xacts_begin, &journal_t::period_xacts_end))
.def("sources", python::range<return_internal_reference<> >
- (&journal_t::sources_begin, &journal_t::sources_end))
+ (&journal_t::sources_begin, &journal_t::sources_end))
.def("read", py_read)
diff --git a/src/py_post.cc b/src/py_post.cc
index e4a50980..537289b3 100644
--- a/src/py_post.cc
+++ b/src/py_post.cc
@@ -48,18 +48,18 @@ namespace {
return post.has_tag(tag_mask);
}
bool py_has_tag_2m(post_t& post, const mask_t& tag_mask,
- const boost::optional<mask_t>& value_mask) {
+ const boost::optional<mask_t>& value_mask) {
return post.has_tag(tag_mask, value_mask);
}
- boost::optional<string> py_get_tag_1s(post_t& post, const string& tag) {
+ boost::optional<value_t> py_get_tag_1s(post_t& post, const string& tag) {
return post.get_tag(tag);
}
- boost::optional<string> py_get_tag_1m(post_t& post, const mask_t& tag_mask) {
+ boost::optional<value_t> py_get_tag_1m(post_t& post, const mask_t& tag_mask) {
return post.get_tag(tag_mask);
}
- boost::optional<string> py_get_tag_2m(post_t& post, const mask_t& tag_mask,
- const boost::optional<mask_t>& value_mask) {
+ boost::optional<value_t> py_get_tag_2m(post_t& post, const mask_t& tag_mask,
+ const boost::optional<mask_t>& value_mask) {
return post.get_tag(tag_mask, value_mask);
}
@@ -88,8 +88,8 @@ void export_post()
class_< post_t::xdata_t > ("PostingXData")
#if 1
.add_property("flags",
- &supports_flags<uint_least16_t>::flags,
- &supports_flags<uint_least16_t>::set_flags)
+ &supports_flags<uint_least16_t>::flags,
+ &supports_flags<uint_least16_t>::set_flags)
.def("has_flags", &supports_flags<uint_least16_t>::has_flags)
.def("clear_flags", &supports_flags<uint_least16_t>::clear_flags)
.def("add_flags", &supports_flags<uint_least16_t>::add_flags)
@@ -97,34 +97,34 @@ void export_post()
#endif
.add_property("visited_value",
- make_getter(&post_t::xdata_t::visited_value),
- make_setter(&post_t::xdata_t::visited_value))
+ make_getter(&post_t::xdata_t::visited_value),
+ make_setter(&post_t::xdata_t::visited_value))
.add_property("compound_value",
- make_getter(&post_t::xdata_t::compound_value),
- make_setter(&post_t::xdata_t::compound_value))
+ make_getter(&post_t::xdata_t::compound_value),
+ make_setter(&post_t::xdata_t::compound_value))
.add_property("total",
- make_getter(&post_t::xdata_t::total),
- make_setter(&post_t::xdata_t::total))
+ make_getter(&post_t::xdata_t::total),
+ make_setter(&post_t::xdata_t::total))
.add_property("count",
- make_getter(&post_t::xdata_t::count),
- make_setter(&post_t::xdata_t::count))
+ make_getter(&post_t::xdata_t::count),
+ make_setter(&post_t::xdata_t::count))
.add_property("date",
- make_getter(&post_t::xdata_t::date),
- make_setter(&post_t::xdata_t::date))
+ make_getter(&post_t::xdata_t::date),
+ make_setter(&post_t::xdata_t::date))
.add_property("datetime",
- make_getter(&post_t::xdata_t::datetime),
- make_setter(&post_t::xdata_t::datetime))
+ make_getter(&post_t::xdata_t::datetime),
+ make_setter(&post_t::xdata_t::datetime))
.add_property("account",
- make_getter(&post_t::xdata_t::account,
- return_value_policy<reference_existing_object>()),
- make_setter(&post_t::xdata_t::account,
- with_custodian_and_ward<1, 2>()))
+ make_getter(&post_t::xdata_t::account,
+ return_value_policy<reference_existing_object>()),
+ make_setter(&post_t::xdata_t::account,
+ with_custodian_and_ward<1, 2>()))
.add_property("sort_values",
- make_getter(&post_t::xdata_t::sort_values),
- make_setter(&post_t::xdata_t::sort_values))
+ make_getter(&post_t::xdata_t::sort_values),
+ make_setter(&post_t::xdata_t::sort_values))
;
- scope().attr("POST_VIRTUAL") = POST_VIRTUAL;
+ scope().attr("POST_VIRTUAL") = POST_VIRTUAL;
scope().attr("POST_MUST_BALANCE") = POST_MUST_BALANCE;
scope().attr("POST_CALCULATED") = POST_CALCULATED;
scope().attr("POST_COST_CALCULATED") = POST_COST_CALCULATED;
@@ -133,24 +133,24 @@ void export_post()
//.def(init<account_t *>())
.add_property("xact",
- make_getter(&post_t::xact,
- return_internal_reference<>()),
- make_setter(&post_t::xact,
- with_custodian_and_ward<1, 2>()))
+ make_getter(&post_t::xact,
+ return_internal_reference<>()),
+ make_setter(&post_t::xact,
+ with_custodian_and_ward<1, 2>()))
.add_property("account",
- make_getter(&post_t::account,
- return_internal_reference<>()),
- make_setter(&post_t::account,
- with_custodian_and_ward<1, 2>()))
+ make_getter(&post_t::account,
+ return_internal_reference<>()),
+ make_setter(&post_t::account,
+ with_custodian_and_ward<1, 2>()))
.add_property("amount",
- make_getter(&post_t::amount),
- make_setter(&post_t::amount))
+ make_getter(&post_t::amount),
+ make_setter(&post_t::amount))
.add_property("cost",
- make_getter(&post_t::cost),
- make_setter(&post_t::cost))
+ make_getter(&post_t::cost),
+ make_setter(&post_t::cost))
.add_property("assigned_amount",
- make_getter(&post_t::assigned_amount),
- make_setter(&post_t::assigned_amount))
+ make_getter(&post_t::assigned_amount),
+ make_setter(&post_t::assigned_amount))
.def("has_tag", py_has_tag_1s)
.def("has_tag", py_has_tag_1m)
@@ -171,13 +171,13 @@ void export_post()
.def("has_xdata", &post_t::has_xdata)
.def("clear_xdata", &post_t::clear_xdata)
.def("xdata", py_xdata,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("add_to_value", &post_t::add_to_value)
.def("set_reported_account", &post_t::set_reported_account)
.def("reported_account", py_reported_account,
- return_internal_reference<>())
+ return_internal_reference<>())
;
}
diff --git a/src/py_times.cc b/src/py_times.cc
index 39b0df7a..c2e0b8f8 100644
--- a/src/py_times.cc
+++ b/src/py_times.cc
@@ -41,10 +41,10 @@ namespace ledger {
using namespace boost::python;
-#define MY_PyDateTime_IMPORT \
- PyDateTimeAPI = (PyDateTime_CAPI*) \
- PyCObject_Import(const_cast<char *>("datetime"), \
- const_cast<char *>("datetime_CAPI"))
+#define MY_PyDateTime_IMPORT \
+ PyDateTimeAPI = (PyDateTime_CAPI*) \
+ PyCObject_Import(const_cast<char *>("datetime"), \
+ const_cast<char *>("datetime_CAPI"))
struct date_to_python
{
@@ -65,7 +65,7 @@ struct date_from_python
}
static void construct(PyObject * obj_ptr,
- converter::rvalue_from_python_stage1_data * data)
+ converter::rvalue_from_python_stage1_data * data)
{
MY_PyDateTime_IMPORT;
@@ -113,7 +113,7 @@ struct datetime_from_python
}
static void construct(PyObject * obj_ptr,
- converter::rvalue_from_python_stage1_data * data)
+ converter::rvalue_from_python_stage1_data * data)
{
MY_PyDateTime_IMPORT;
@@ -139,14 +139,14 @@ struct datetime_from_python
datetime_t * moment
= new datetime_t(date_t(y, m, d),
- datetime_t::time_duration_type(h, min, s, ms));
+ datetime_t::time_duration_type(h, min, s, ms));
data->convertible = (void *) moment;
}
};
typedef register_python_conversion<datetime_t,
- datetime_to_python, datetime_from_python>
+ datetime_to_python, datetime_from_python>
datetime_python_conversion;
@@ -189,7 +189,7 @@ struct duration_from_python
}
static void construct(PyObject* obj_ptr,
- python::converter::rvalue_from_python_stage1_data * data)
+ python::converter::rvalue_from_python_stage1_data * data)
{
PyDateTime_Delta const* pydelta
= reinterpret_cast<PyDateTime_Delta*>(obj_ptr);
@@ -202,8 +202,8 @@ struct duration_from_python
// Create time duration object
posix_time::time_duration
duration = (posix_time::hours(24) * days +
- posix_time::seconds(pydelta->seconds) +
- posix_time::microseconds(pydelta->microseconds));
+ posix_time::seconds(pydelta->seconds) +
+ posix_time::microseconds(pydelta->microseconds));
if (is_negative)
duration = duration.invert_sign();
@@ -218,7 +218,7 @@ struct duration_from_python
};
typedef register_python_conversion<time_duration_t,
- duration_to_python, duration_from_python>
+ duration_to_python, duration_from_python>
duration_python_conversion;
@@ -240,7 +240,7 @@ void export_times()
register_optional_to_python<date_t>();
scope().attr("parse_datetime") = &py_parse_datetime;
- scope().attr("parse_date") = &py_parse_date;
+ scope().attr("parse_date") = &py_parse_date;
scope().attr("times_initialize") = &times_initialize;
scope().attr("times_shutdown") = &times_shutdown;
diff --git a/src/py_utils.cc b/src/py_utils.cc
index 952416cc..c513def4 100644
--- a/src/py_utils.cc
+++ b/src/py_utils.cc
@@ -59,7 +59,7 @@ struct bool_from_python
}
static void construct(PyObject* obj_ptr,
- converter::rvalue_from_python_stage1_data* data)
+ converter::rvalue_from_python_stage1_data* data)
{
void * storage =
((converter::rvalue_from_python_storage<bool>*) data)->storage.bytes;
@@ -89,19 +89,19 @@ struct string_from_python
static void* convertible(PyObject* obj_ptr)
{
if (!PyUnicode_Check(obj_ptr) &&
- !PyString_Check(obj_ptr)) return 0;
+ !PyString_Check(obj_ptr)) return 0;
return obj_ptr;
}
static void construct(PyObject* obj_ptr,
- converter::rvalue_from_python_stage1_data* data)
+ converter::rvalue_from_python_stage1_data* data)
{
if (PyString_Check(obj_ptr)) {
const char* value = PyString_AsString(obj_ptr);
if (value == 0) throw_error_already_set();
void* storage =
- reinterpret_cast<converter::rvalue_from_python_storage<string> *>
- (data)->storage.bytes;
+ reinterpret_cast<converter::rvalue_from_python_storage<string> *>
+ (data)->storage.bytes;
new (storage) string(value);
data->convertible = storage;
} else {
@@ -112,18 +112,18 @@ struct string_from_python
string str;
if (sizeof(Py_UNICODE) == 2) // UTF-16
- utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str));
+ utf8::unchecked::utf16to8(value, value + size, std::back_inserter(str));
else if (sizeof(Py_UNICODE) == 4) // UTF-32
- utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str));
+ utf8::unchecked::utf32to8(value, value + size, std::back_inserter(str));
#if !defined(NO_ASSERTS)
else
- assert(! "Py_UNICODE has an unexpected size");
+ assert(! "Py_UNICODE has an unexpected size");
#endif
if (value == 0) throw_error_already_set();
void* storage =
- reinterpret_cast<converter::rvalue_from_python_storage<string> *>
- (data)->storage.bytes;
+ reinterpret_cast<converter::rvalue_from_python_storage<string> *>
+ (data)->storage.bytes;
new (storage) string(str);
data->convertible = storage;
}
@@ -151,7 +151,7 @@ struct istream_from_python
}
static void construct(PyObject* obj_ptr,
- converter::rvalue_from_python_stage1_data* data)
+ converter::rvalue_from_python_stage1_data* data)
{
void* storage =
reinterpret_cast<converter::rvalue_from_python_storage<pyifstream> *>
@@ -162,7 +162,7 @@ struct istream_from_python
};
typedef register_python_conversion<std::istream,
- istream_to_python, istream_from_python>
+ istream_to_python, istream_from_python>
istream_python_conversion;
@@ -183,7 +183,7 @@ struct ostream_from_python
}
static void construct(PyObject* obj_ptr,
- converter::rvalue_from_python_stage1_data* data)
+ converter::rvalue_from_python_stage1_data* data)
{
void* storage =
reinterpret_cast<converter::rvalue_from_python_storage<pyofstream> *>
@@ -194,7 +194,7 @@ struct ostream_from_python
};
typedef register_python_conversion<std::ostream,
- ostream_to_python, ostream_from_python>
+ ostream_to_python, ostream_from_python>
ostream_python_conversion;
@@ -205,8 +205,8 @@ void export_utils()
.def(init<uint_least8_t>())
.add_property("flags",
- &supports_flags<uint_least8_t>::flags,
- &supports_flags<uint_least8_t>::set_flags)
+ &supports_flags<uint_least8_t>::flags,
+ &supports_flags<uint_least8_t>::set_flags)
.def("has_flags", &supports_flags<uint_least8_t>::has_flags)
.def("clear_flags", &supports_flags<uint_least8_t>::clear_flags)
.def("add_flags", &supports_flags<uint_least8_t>::add_flags)
@@ -218,8 +218,8 @@ void export_utils()
.def(init<uint_least16_t>())
.add_property("flags",
- &supports_flags<uint_least16_t>::flags,
- &supports_flags<uint_least16_t>::set_flags)
+ &supports_flags<uint_least16_t>::flags,
+ &supports_flags<uint_least16_t>::set_flags)
.def("has_flags", &supports_flags<uint_least16_t>::has_flags)
.def("clear_flags", &supports_flags<uint_least16_t>::clear_flags)
.def("add_flags", &supports_flags<uint_least16_t>::add_flags)
@@ -237,10 +237,10 @@ void export_utils()
#endif
class_< delegates_flags<uint_least16_t>,
- boost::noncopyable > ("DelegatesFlags16", no_init)
+ boost::noncopyable > ("DelegatesFlags16", no_init)
.add_property("flags",
- &delegates_flags<uint_least16_t>::flags,
- &delegates_flags<uint_least16_t>::set_flags)
+ &delegates_flags<uint_least16_t>::flags,
+ &delegates_flags<uint_least16_t>::set_flags)
.def("has_flags", &delegates_flags<uint_least16_t>::has_flags)
.def("clear_flags", &delegates_flags<uint_least16_t>::clear_flags)
.def("add_flags", &delegates_flags<uint_least16_t>::add_flags)
diff --git a/src/py_value.cc b/src/py_value.cc
index 449320ec..f8f36453 100644
--- a/src/py_value.cc
+++ b/src/py_value.cc
@@ -42,22 +42,22 @@ using namespace boost::python;
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(value_overloads, value, 0, 2)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(exchange_commodities_overloads,
- exchange_commodities, 1, 2)
+ exchange_commodities, 1, 2)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_string_overloads, set_string, 0, 2)
namespace {
boost::optional<value_t> py_value_0(const value_t& value) {
- return value.value(false, CURRENT_TIME());
+ return value.value(CURRENT_TIME());
}
boost::optional<value_t> py_value_1(const value_t& value,
- commodity_t& in_terms_of) {
- return value.value(false, CURRENT_TIME(), in_terms_of);
+ commodity_t& in_terms_of) {
+ return value.value(CURRENT_TIME(), in_terms_of);
}
boost::optional<value_t> py_value_2(const value_t& value,
- commodity_t& in_terms_of,
- datetime_t& moment) {
- return value.value(false, moment, in_terms_of);
+ commodity_t& in_terms_of,
+ datetime_t& moment) {
+ return value.value(moment, in_terms_of);
}
PyObject * py_base_type(value_t& value)
@@ -110,9 +110,9 @@ namespace {
} // unnamed namespace
-#define EXC_TRANSLATOR(type) \
- void exc_translate_ ## type(const type& err) { \
- PyErr_SetString(PyExc_ArithmeticError, err.what()); \
+#define EXC_TRANSLATOR(type) \
+ void exc_translate_ ## type(const type& err) { \
+ PyErr_SetString(PyExc_ArithmeticError, err.what()); \
}
EXC_TRANSLATOR(value_error)
@@ -120,16 +120,16 @@ EXC_TRANSLATOR(value_error)
void export_value()
{
enum_< value_t::type_t >("ValueType")
- .value("Void", value_t::VOID)
- .value("Boolean", value_t::BOOLEAN)
- .value("DateTime", value_t::DATETIME)
- .value("Date", value_t::DATE)
- .value("Integer", value_t::INTEGER)
- .value("Amount", value_t::AMOUNT)
- .value("Balance", value_t::BALANCE)
- .value("String", value_t::STRING)
- .value("Sequence", value_t::SEQUENCE)
- .value("Scope", value_t::SCOPE)
+ .value("Void", value_t::VOID)
+ .value("Boolean", value_t::BOOLEAN)
+ .value("DateTime", value_t::DATETIME)
+ .value("Date", value_t::DATE)
+ .value("Integer", value_t::INTEGER)
+ .value("Amount", value_t::AMOUNT)
+ .value("Balance", value_t::BALANCE)
+ .value("String", value_t::STRING)
+ .value("Sequence", value_t::SEQUENCE)
+ .value("Scope", value_t::SCOPE)
;
class_< value_t > ("Value")
@@ -214,9 +214,9 @@ void export_value()
.def(self -= other<amount_t>())
.def(self -= other<balance_t>())
- .def(self - self)
- .def(self - long())
- .def(long() - self)
+ .def(self - self)
+ .def(self - long())
+ .def(long() - self)
.def(self - other<amount_t>())
.def(other<amount_t>() - self)
.def(self - other<balance_t>())
@@ -225,8 +225,8 @@ void export_value()
.def(self *= long())
.def(self *= other<amount_t>())
- .def(self * self)
- .def(self * long())
+ .def(self * self)
+ .def(self * long())
.def(long() * self)
.def(self * other<amount_t>())
.def(other<amount_t>() * self)
@@ -235,9 +235,9 @@ void export_value()
.def(self /= long())
.def(self /= other<amount_t>())
- .def(self / self)
- .def(self / long())
- .def(long() / self)
+ .def(self / self)
+ .def(self / long())
+ .def(long() / self)
.def(self / other<amount_t>())
.def(other<amount_t>() / self)
@@ -269,7 +269,7 @@ void export_value()
.def("value", &value_t::value, value_overloads())
.def("price", &value_t::price)
.def("exchange_commodities", &value_t::exchange_commodities,
- exchange_commodities_overloads())
+ exchange_commodities_overloads())
.def("__nonzero__", &value_t::is_nonzero)
.def("is_nonzero", &value_t::is_nonzero)
@@ -333,8 +333,8 @@ void export_value()
.def("annotate", &value_t::annotate)
.def("has_annotation", &value_t::has_annotation)
.add_property("annotation",
- make_function(py_value_annotation,
- return_internal_reference<>()))
+ make_function(py_value_annotation,
+ return_internal_reference<>()))
.def("strip_annotations", py_strip_annotations_0)
.def("strip_annotations", py_strip_annotations_1)
@@ -352,13 +352,17 @@ void export_value()
.def("basetype", py_base_type)
;
+#if 0
+ // jww (2010-06-10): This is not working since I switched sequence_t to
+ // ptr_deque<value_t>.
class_< value_t::sequence_t > ("ValueSequence")
- .def(vector_indexing_suite< value_t::sequence_t >());
+ .def(vector_indexing_suite< value_t::sequence_t, true >());
;
+#endif
scope().attr("NULL_VALUE") = NULL_VALUE;
scope().attr("string_value") = &string_value;
- scope().attr("mask_value") = &mask_value;
+ scope().attr("mask_value") = &mask_value;
scope().attr("value_context") = &value_context;
register_optional_to_python<value_t>();
diff --git a/src/py_xact.cc b/src/py_xact.cc
index 6553a67f..b7582854 100644
--- a/src/py_xact.cc
+++ b/src/py_xact.cc
@@ -82,16 +82,16 @@ using namespace boost::python;
void export_xact()
{
- class_< xact_base_t, bases<item_t> > ("TransactionBase")
+ class_< xact_base_t, bases<item_t>, noncopyable > ("TransactionBase", no_init)
.add_property("journal",
- make_getter(&xact_base_t::journal,
- return_internal_reference<>()),
- make_setter(&xact_base_t::journal,
- with_custodian_and_ward<1, 2>()))
+ make_getter(&xact_base_t::journal,
+ return_internal_reference<>()),
+ make_setter(&xact_base_t::journal,
+ with_custodian_and_ward<1, 2>()))
.def("__len__", posts_len)
.def("__getitem__", posts_getitem,
- return_internal_reference<>())
+ return_internal_reference<>())
.def("add_post", &xact_base_t::add_post, with_custodian_and_ward<1, 2>())
.def("remove_post", &xact_base_t::add_post)
@@ -99,20 +99,20 @@ void export_xact()
.def("finalize", &xact_base_t::finalize)
.def("__iter__", python::range<return_internal_reference<> >
- (&xact_t::posts_begin, &xact_t::posts_end))
+ (&xact_t::posts_begin, &xact_t::posts_end))
.def("posts", python::range<return_internal_reference<> >
- (&xact_t::posts_begin, &xact_t::posts_end))
+ (&xact_t::posts_begin, &xact_t::posts_end))
.def("valid", &xact_base_t::valid)
;
class_< xact_t, bases<xact_base_t> > ("Transaction")
.add_property("code",
- make_getter(&xact_t::code),
- make_setter(&xact_t::code))
+ make_getter(&xact_t::code),
+ make_setter(&xact_t::code))
.add_property("payee",
- make_getter(&xact_t::payee),
- make_setter(&xact_t::payee))
+ make_getter(&xact_t::payee),
+ make_setter(&xact_t::payee))
.def("add_post", &xact_t::add_post, with_custodian_and_ward<1, 2>())
@@ -132,8 +132,8 @@ void export_xact()
.def(init<predicate_t>())
.add_property("predicate",
- make_getter(&auto_xact_t::predicate),
- make_setter(&auto_xact_t::predicate))
+ make_getter(&auto_xact_t::predicate),
+ make_setter(&auto_xact_t::predicate))
.def("extend_xact", &auto_xact_t::extend_xact)
;
@@ -142,11 +142,11 @@ void export_xact()
.def(init<string>())
.add_property("period",
- make_getter(&period_xact_t::period),
- make_setter(&period_xact_t::period))
+ make_getter(&period_xact_t::period),
+ make_setter(&period_xact_t::period))
.add_property("period_string",
- make_getter(&period_xact_t::period_string),
- make_setter(&period_xact_t::period_string))
+ make_getter(&period_xact_t::period_string),
+ make_setter(&period_xact_t::period_string))
;
}
diff --git a/src/pyfstream.h b/src/pyfstream.h
index 02e4d240..37978ff4 100644
--- a/src/pyfstream.h
+++ b/src/pyfstream.h
@@ -59,7 +59,7 @@ protected:
z[0] = static_cast<char>(c);
z[1] = '\0';
if (PyFile_WriteString(z, reinterpret_cast<PyObject *>(fo)) < 0) {
- return EOF;
+ return EOF;
}
}
return c;
@@ -124,8 +124,8 @@ public:
TRACE_CTOR(pyinbuf, "PyFileObject *");
setg (buffer+pbSize, // beginning of putback area
- buffer+pbSize, // read position
- buffer+pbSize); // end position
+ buffer+pbSize, // read position
+ buffer+pbSize); // end position
}
~pyinbuf() throw() {
TRACE_DTOR(pyinbuf);
@@ -157,7 +157,7 @@ protected:
* the putback area
*/
memmove (buffer+(pbSize-numPutback), gptr()-numPutback,
- numPutback);
+ numPutback);
// read at most bufSize new characters
PyObject *line = PyFile_GetLine(reinterpret_cast<PyObject *>(fo), bufSize);
@@ -174,8 +174,8 @@ protected:
// reset buffer pointers
setg (buffer+(pbSize-numPutback), // beginning of putback area
- buffer+pbSize, // read position
- buffer+pbSize+num); // end of buffer
+ buffer+pbSize, // read position
+ buffer+pbSize+num); // end of buffer
// return next character
return traits_type::to_int_type(*gptr());
diff --git a/src/pyinterp.cc b/src/pyinterp.cc
index 1330fc5c..8052f6a4 100644
--- a/src/pyinterp.cc
+++ b/src/pyinterp.cc
@@ -80,10 +80,10 @@ struct python_run
object result;
python_run(python_interpreter_t * intepreter,
- const string& str, int input_mode)
+ const string& str, int input_mode)
: result(handle<>(borrowed(PyRun_String(str.c_str(), input_mode,
- intepreter->main_nspace.ptr(),
- intepreter->main_nspace.ptr())))) {}
+ intepreter->main_nspace.ptr(),
+ intepreter->main_nspace.ptr())))) {}
operator object() {
return result;
}
@@ -104,12 +104,12 @@ void python_interpreter_t::initialize()
object main_module = python::import("__main__");
if (! main_module)
throw_(std::runtime_error,
- _("Python failed to initialize (couldn't find __main__)"));
+ _("Python failed to initialize (couldn't find __main__)"));
main_nspace = extract<dict>(main_module.attr("__dict__"));
if (! main_nspace)
throw_(std::runtime_error,
- _("Python failed to initialize (couldn't find __dict__)"));
+ _("Python failed to initialize (couldn't find __dict__)"));
python::detail::init_module("ledger", &initialize_for_python);
@@ -142,17 +142,17 @@ void python_interpreter_t::hack_system_paths()
if (exists(pathname / "ledger" / "__init__.py")) {
if (python::object module_ledger = python::import("ledger")) {
- DEBUG("python.interp",
- "Setting ledger.__path__ = " << (pathname / "ledger"));
+ DEBUG("python.interp",
+ "Setting ledger.__path__ = " << (pathname / "ledger"));
- python::object ledger_dict = module_ledger.attr("__dict__");
- python::list temp_list;
- temp_list.append((pathname / "ledger").string());
+ python::object ledger_dict = module_ledger.attr("__dict__");
+ python::list temp_list;
+ temp_list.append((pathname / "ledger").string());
- ledger_dict["__path__"] = temp_list;
+ ledger_dict["__path__"] = temp_list;
} else {
- throw_(std::runtime_error,
- _("Python failed to initialize (couldn't find ledger)"));
+ throw_(std::runtime_error,
+ _("Python failed to initialize (couldn't find ledger)"));
}
#if defined(DEBUG_ON)
path_initialized = true;
@@ -163,7 +163,7 @@ void python_interpreter_t::hack_system_paths()
#if defined(DEBUG_ON)
if (! path_initialized)
DEBUG("python.init",
- "Ledger failed to find 'ledger/__init__.py' on the PYTHONPATH");
+ "Ledger failed to find 'ledger/__init__.py' on the PYTHONPATH");
#endif
}
@@ -176,7 +176,7 @@ object python_interpreter_t::import_into_main(const string& str)
object mod = python::import(str.c_str());
if (! mod)
throw_(std::runtime_error,
- _("Failed to import Python module %1") << str);
+ _("Failed to import Python module %1") << str);
// Import all top-level entries directly into the main namespace
main_nspace.update(mod.attr("__dict__"));
@@ -217,7 +217,7 @@ object python_interpreter_t::import_option(const string& str)
object python_interpreter_t::eval(std::istream& in, py_eval_mode_t mode)
{
- bool first = true;
+ bool first = true;
string buffer;
buffer.reserve(4096);
@@ -286,7 +286,7 @@ value_t python_interpreter_t::python_command(call_scope_t& args)
std::strcpy(argv[0], argv0);
for (std::size_t i = 0; i < args.size(); i++) {
- string arg = args[i].as_string();
+ string arg = args.get<string>(i);
argv[i + 1] = new char[arg.length() + 1];
std::strcpy(argv[i + 1], arg.c_str());
}
@@ -328,12 +328,12 @@ value_t python_interpreter_t::server_command(call_scope_t& args)
server_module = python::import("ledger.server");
if (! server_module)
throw_(std::runtime_error,
- _("Could not import ledger.server; please check your PYTHONPATH"));
+ _("Could not import ledger.server; please check your PYTHONPATH"));
}
catch (const error_already_set&) {
PyErr_Print();
throw_(std::runtime_error,
- _("Could not import ledger.server; please check your PYTHONPATH"));
+ _("Could not import ledger.server; please check your PYTHONPATH"));
}
if (python::object main_function = server_module.attr("main")) {
@@ -344,12 +344,12 @@ value_t python_interpreter_t::server_command(call_scope_t& args)
catch (const error_already_set&) {
PyErr_Print();
throw_(std::runtime_error,
- _("Error while invoking ledger.server's main() function"));
+ _("Error while invoking ledger.server's main() function"));
}
return true;
} else {
throw_(std::runtime_error,
- _("The ledger.server module is missing its main() function!"));
+ _("The ledger.server module is missing its main() function!"));
}
return false;
@@ -367,7 +367,7 @@ python_interpreter_t::lookup_option(const char * p)
}
expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
// Give our superclass first dibs on symbol definitions
if (expr_t::ptr_op_t op = session_t::lookup(kind, name))
@@ -382,7 +382,7 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind,
DEBUG("python.interp", "Python lookup: " << name);
if (python::object obj = main_nspace.get(name.c_str()))
- return WRAP_FUNCTOR(functor_t(obj, name));
+ return WRAP_FUNCTOR(functor_t(obj, name));
}
break;
@@ -396,12 +396,12 @@ expr_t::ptr_op_t python_interpreter_t::lookup(const symbol_t::kind_t kind,
switch (*p) {
case 'p':
if (is_eq(p, "python"))
- return MAKE_FUNCTOR(python_interpreter_t::python_command);
+ return MAKE_FUNCTOR(python_interpreter_t::python_command);
break;
case 's':
if (is_eq(p, "server"))
- return MAKE_FUNCTOR(python_interpreter_t::server_command);
+ return MAKE_FUNCTOR(python_interpreter_t::server_command);
break;
}
}
@@ -419,21 +419,21 @@ namespace {
if (value.is_scope()) {
const scope_t * scope = value.as_scope();
if (const post_t * post = dynamic_cast<const post_t *>(scope))
- lst.append(ptr(post));
+ lst.append(ptr(post));
else if (const xact_t * xact = dynamic_cast<const xact_t *>(scope))
- lst.append(ptr(xact));
+ lst.append(ptr(xact));
else if (const account_t * account =
- dynamic_cast<const account_t *>(scope))
- lst.append(ptr(account));
+ dynamic_cast<const account_t *>(scope))
+ lst.append(ptr(account));
else if (const period_xact_t * period_xact =
- dynamic_cast<const period_xact_t *>(scope))
- lst.append(ptr(period_xact));
+ dynamic_cast<const period_xact_t *>(scope))
+ lst.append(ptr(period_xact));
else if (const auto_xact_t * auto_xact =
- dynamic_cast<const auto_xact_t *>(scope))
- lst.append(ptr(auto_xact));
+ dynamic_cast<const auto_xact_t *>(scope))
+ lst.append(ptr(auto_xact));
else
- throw_(std::logic_error,
- _("Cannot downcast scoped object to specific type"));
+ throw_(std::logic_error,
+ _("Cannot downcast scoped object to specific type"));
} else {
lst.append(value);
}
@@ -449,7 +449,7 @@ value_t python_interpreter_t::functor_t::operator()(call_scope_t& args)
extract<value_t> val(func);
std::signal(SIGINT, sigint_handler);
if (val.check())
- return val();
+ return val();
return NULL_VALUE;
}
else if (args.size() > 0) {
@@ -457,31 +457,31 @@ value_t python_interpreter_t::functor_t::operator()(call_scope_t& args)
// jww (2009-11-05): What about a single argument which is a sequence,
// rather than a sequence of arguments?
if (args.value().is_sequence())
- foreach (const value_t& value, args.value().as_sequence())
- append_value(arglist, value);
+ foreach (const value_t& value, args.value().as_sequence())
+ append_value(arglist, value);
else
- append_value(arglist, args.value());
+ append_value(arglist, args.value());
if (PyObject * val =
- PyObject_CallObject(func.ptr(), python::tuple(arglist).ptr())) {
- extract<value_t> xval(val);
- value_t result;
- if (xval.check()) {
- result = xval();
- Py_DECREF(val);
- } else {
- Py_DECREF(val);
- throw_(calc_error,
- _("Could not evaluate Python variable '%1'") << name);
- }
- std::signal(SIGINT, sigint_handler);
- return result;
+ PyObject_CallObject(func.ptr(), python::tuple(arglist).ptr())) {
+ extract<value_t> xval(val);
+ value_t result;
+ if (xval.check()) {
+ result = xval();
+ Py_DECREF(val);
+ } else {
+ Py_DECREF(val);
+ throw_(calc_error,
+ _("Could not evaluate Python variable '%1'") << name);
+ }
+ std::signal(SIGINT, sigint_handler);
+ return result;
}
else if (PyErr_Occurred()) {
- PyErr_Print();
- throw_(calc_error, _("Failed call to Python function '%1'") << name);
+ PyErr_Print();
+ throw_(calc_error, _("Failed call to Python function '%1'") << name);
} else {
- assert(false);
+ assert(false);
}
}
else {
diff --git a/src/pyinterp.h b/src/pyinterp.h
index e3a091ad..1dfd0747 100644
--- a/src/pyinterp.h
+++ b/src/pyinterp.h
@@ -69,11 +69,11 @@ public:
};
python::object eval(std::istream& in,
- py_eval_mode_t mode = PY_EVAL_EXPR);
+ py_eval_mode_t mode = PY_EVAL_EXPR);
python::object eval(const string& str,
- py_eval_mode_t mode = PY_EVAL_EXPR);
+ py_eval_mode_t mode = PY_EVAL_EXPR);
python::object eval(const char * c_str,
- py_eval_mode_t mode = PY_EVAL_EXPR) {
+ py_eval_mode_t mode = PY_EVAL_EXPR) {
string str(c_str);
return eval(str, mode);
}
@@ -107,10 +107,9 @@ public:
option_t<python_interpreter_t> * lookup_option(const char * p);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
- OPTION_(python_interpreter_t, import_, DO_(scope) {
- interactive_t args(scope, "ss");
+ OPTION_(python_interpreter_t, import_, DO_(args) {
parent->import_option(args.get<string>(1));
});
};
diff --git a/src/pyutils.h b/src/pyutils.h
index e0f77003..efb1b858 100644
--- a/src/pyutils.h
+++ b/src/pyutils.h
@@ -59,8 +59,8 @@ struct register_optional_to_python : public boost::noncopyable
static PyObject * convert(const boost::optional<T>& value)
{
return boost::python::incref
- (value ? boost::python::to_python_value<T>()(*value) :
- boost::python::detail::none());
+ (value ? boost::python::to_python_value<T>()(*value) :
+ boost::python::detail::none());
}
};
@@ -71,30 +71,30 @@ struct register_optional_to_python : public boost::noncopyable
using namespace boost::python::converter;
if (source == Py_None)
- return source;
+ return source;
const registration& converters(registered<T>::converters);
if (implicit_rvalue_convertible_from_python(source, converters)) {
- rvalue_from_python_stage1_data data =
- rvalue_from_python_stage1(source, converters);
- return rvalue_from_python_stage2(source, data, converters);
+ rvalue_from_python_stage1_data data =
+ rvalue_from_python_stage1(source, converters);
+ return rvalue_from_python_stage2(source, data, converters);
}
return NULL;
}
static void construct(PyObject * source,
- boost::python::converter::rvalue_from_python_stage1_data * data)
+ boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage =
- reinterpret_cast<rvalue_from_python_storage<T> *>(data)->storage.bytes;
+ reinterpret_cast<rvalue_from_python_storage<T> *>(data)->storage.bytes;
- if (data->convertible == source) // == None
- new (storage) boost::optional<T>(); // A Boost uninitialized value
+ if (data->convertible == source) // == None
+ new (storage) boost::optional<T>(); // A Boost uninitialized value
else
- new (storage) boost::optional<T>(*reinterpret_cast<T *>(data->convertible));
+ new (storage) boost::optional<T>(*reinterpret_cast<T *>(data->convertible));
data->convertible = storage;
}
diff --git a/src/query.cc b/src/query.cc
index 363c6f73..5480336c 100644
--- a/src/query.cc
+++ b/src/query.cc
@@ -53,22 +53,27 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
}
}
+ resume:
switch (*arg_i) {
+ case '\0':
+ assert(false);
+ break;
+
case '\'':
case '"':
case '/': {
string pat;
- char closing = *arg_i;
+ char closing = *arg_i;
bool found_closing = false;
for (++arg_i; arg_i != arg_end; ++arg_i) {
if (*arg_i == '\\') {
- if (++arg_i == arg_end)
- throw_(parse_error, _("Unexpected '\\' at end of pattern"));
+ if (++arg_i == arg_end)
+ throw_(parse_error, _("Unexpected '\\' at end of pattern"));
}
else if (*arg_i == closing) {
- ++arg_i;
- found_closing = true;
- break;
+ ++arg_i;
+ found_closing = true;
+ break;
}
pat.push_back(*arg_i);
}
@@ -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)
- goto test_ident;
- else
- ident.push_back(*arg_i);
- break;
+ if (! multiple_args && ! consume_whitespace)
+ goto test_ident;
+ else
+ ident.push_back(*arg_i);
+ break;
+
case '(':
case ')':
case '&':
@@ -139,12 +153,12 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token()
case '#':
case '%':
case '=':
- if (! consume_next)
- goto test_ident;
+ if (! consume_next)
+ goto test_ident;
// fall through...
default:
- ident.push_back(*arg_i);
- break;
+ ident.push_back(*arg_i);
+ break;
}
}
consume_whitespace = false;
@@ -170,20 +184,18 @@ 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 == "only")
+ return token_t(token_t::TOK_ONLY);
+ 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 +250,16 @@ 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_ONLY:
+ 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:
@@ -251,47 +269,12 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
node = parse_query_term(tok.kind);
if (! node)
throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol());
+ _("%1 operator not followed by argument") << tok.symbol());
break;
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;
@@ -308,22 +291,22 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
tok = lexer.peek_token();
if (tok.kind == lexer_t::token_t::TOK_EQ) {
- tok = lexer.next_token();
- tok = lexer.next_token();
- if (tok.kind != lexer_t::token_t::TERM)
- throw_(parse_error,
- _("Metadata equality operator not followed by term"));
-
- expr_t::ptr_op_t arg2 = new expr_t::op_t(expr_t::op_t::VALUE);
- assert(tok.value);
- arg2->set_value(mask_t(*tok.value));
-
- node->set_right(expr_t::op_t::new_node
- (expr_t::op_t::O_SEQ,
- expr_t::op_t::new_node
- (expr_t::op_t::O_CONS, arg1, arg2)));
+ tok = lexer.next_token();
+ tok = lexer.next_token();
+ if (tok.kind != lexer_t::token_t::TERM)
+ throw_(parse_error,
+ _("Metadata equality operator not followed by term"));
+
+ expr_t::ptr_op_t arg2 = new expr_t::op_t(expr_t::op_t::VALUE);
+ assert(tok.value);
+ arg2->set_value(mask_t(*tok.value));
+
+ node->set_right(expr_t::op_t::new_node
+ (expr_t::op_t::O_SEQ,
+ expr_t::op_t::new_node
+ (expr_t::op_t::O_CONS, arg1, arg2)));
} else {
- node->set_right(arg1);
+ node->set_right(arg1);
}
break;
}
@@ -334,15 +317,15 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex
expr_t::ptr_op_t ident = new expr_t::op_t(expr_t::op_t::IDENT);
switch (tok_context) {
case lexer_t::token_t::TOK_ACCOUNT:
- ident->set_ident("account"); break;
+ ident->set_ident("account"); break;
case lexer_t::token_t::TOK_PAYEE:
- ident->set_ident("payee"); break;
+ ident->set_ident("payee"); break;
case lexer_t::token_t::TOK_CODE:
- ident->set_ident("code"); break;
+ ident->set_ident("code"); break;
case lexer_t::token_t::TOK_NOTE:
- ident->set_ident("note"); break;
+ ident->set_ident("note"); break;
default:
- assert(false); break;
+ assert(false); break;
}
expr_t::ptr_op_t mask = new expr_t::op_t(expr_t::op_t::VALUE);
@@ -357,7 +340,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(')');
@@ -382,7 +365,7 @@ query_t::parser_t::parse_unary_expr(lexer_t::token_t::kind_t tok_context)
expr_t::ptr_op_t term(parse_query_term(tok_context));
if (! term)
throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol());
+ _("%1 operator not followed by argument") << tok.symbol());
node = new expr_t::op_t(expr_t::op_t::O_NOT);
node->set_left(term);
@@ -405,16 +388,16 @@ query_t::parser_t::parse_and_expr(lexer_t::token_t::kind_t tok_context)
while (true) {
lexer_t::token_t tok = lexer.next_token();
if (tok.kind == lexer_t::token_t::TOK_AND) {
- 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(parse_unary_expr(tok_context));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol());
+ 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(parse_unary_expr(tok_context));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol());
} else {
- lexer.push_token(tok);
- break;
+ lexer.push_token(tok);
+ break;
}
}
return node;
@@ -429,16 +412,16 @@ query_t::parser_t::parse_or_expr(lexer_t::token_t::kind_t tok_context)
while (true) {
lexer_t::token_t tok = lexer.next_token();
if (tok.kind == lexer_t::token_t::TOK_OR) {
- 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(parse_and_expr(tok_context));
- if (! node->right())
- throw_(parse_error,
- _("%1 operator not followed by argument") << tok.symbol());
+ 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(parse_and_expr(tok_context));
+ if (! node->right())
+ throw_(parse_error,
+ _("%1 operator not followed by argument") << tok.symbol());
} else {
- lexer.push_token(tok);
- break;
+ lexer.push_token(tok);
+ break;
}
}
return node;
@@ -447,18 +430,120 @@ 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:
+ case lexer_t::token_t::TOK_ONLY:
+ case lexer_t::token_t::TOK_BOLD: {
+ lexer.next_token();
+
+ kind_t kind;
+ switch (tok.kind) {
+ case lexer_t::token_t::TOK_SHOW:
+ kind = QUERY_SHOW;
+ break;
+ case lexer_t::token_t::TOK_ONLY:
+ kind = QUERY_ONLY;
+ break;
+ case lexer_t::token_t::TOK_BOLD:
+ kind = QUERY_BOLD;
+ break;
+ default:
+ break;
+ }
+
+ 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
+ (kind, 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
diff --git a/src/query.h b/src/query.h
index 59adfd72..b5b3b0fc 100644
--- a/src/query.h
+++ b/src/query.h
@@ -46,8 +46,11 @@
namespace ledger {
-class query_t : public predicate_t
+class query_t
{
+protected:
+ class parser_t;
+
public:
class lexer_t
{
@@ -57,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;
@@ -68,107 +72,123 @@ public:
struct token_t
{
enum kind_t {
- UNKNOWN,
+ UNKNOWN,
+
+ LPAREN,
+ RPAREN,
- LPAREN,
- RPAREN,
+ TOK_NOT,
+ TOK_AND,
+ TOK_OR,
+ TOK_EQ,
- TOK_NOT,
- TOK_AND,
- TOK_OR,
- TOK_EQ,
+ TOK_CODE,
+ TOK_PAYEE,
+ TOK_NOTE,
+ TOK_ACCOUNT,
+ TOK_META,
+ TOK_EXPR,
- TOK_DATE,
- TOK_CODE,
- TOK_PAYEE,
- TOK_NOTE,
- TOK_ACCOUNT,
- TOK_META,
- TOK_EXPR,
+ TOK_SHOW,
+ TOK_ONLY,
+ TOK_BOLD,
+ TOK_FOR,
+ TOK_SINCE,
+ TOK_UNTIL,
- TERM,
+ TERM,
- END_REACHED
+ END_REACHED
} kind;
optional<string> value;
explicit token_t(kind_t _kind = UNKNOWN,
- const optional<string>& _value = none)
- : kind(_kind), value(_value) {
- TRACE_CTOR(query_t::lexer_t::token_t, "");
+ const optional<string>& _value = none)
+ : kind(_kind), value(_value) {
+ TRACE_CTOR(query_t::lexer_t::token_t, "");
}
token_t(const token_t& tok)
- : kind(tok.kind), value(tok.value) {
- TRACE_CTOR(query_t::lexer_t::token_t, "copy");
+ : kind(tok.kind), value(tok.value) {
+ TRACE_CTOR(query_t::lexer_t::token_t, "copy");
}
~token_t() throw() {
- TRACE_DTOR(query_t::lexer_t::token_t);
+ TRACE_DTOR(query_t::lexer_t::token_t);
}
token_t& operator=(const token_t& tok) {
- if (this != &tok) {
- kind = tok.kind;
- value = tok.value;
- }
- return *this;
+ if (this != &tok) {
+ kind = tok.kind;
+ value = tok.value;
+ }
+ return *this;
}
operator bool() const {
- return kind != END_REACHED;
+ return kind != END_REACHED;
}
string to_string() const {
- switch (kind) {
- case UNKNOWN: return "UNKNOWN";
- case LPAREN: return "LPAREN";
- case RPAREN: return "RPAREN";
- case TOK_NOT: return "TOK_NOT";
- 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 TERM: return string("TERM(") + *value + ")";
- case END_REACHED: return "END_REACHED";
- }
- assert(false);
- return empty_string;
+ switch (kind) {
+ case UNKNOWN: return "UNKNOWN";
+ case LPAREN: return "LPAREN";
+ case RPAREN: return "RPAREN";
+ case TOK_NOT: return "TOK_NOT";
+ case TOK_AND: return "TOK_AND";
+ case TOK_OR: return "TOK_OR";
+ case TOK_EQ: return "TOK_EQ";
+ 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_ONLY: return "TOK_ONLY";
+ 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";
+ }
+ assert(false);
+ return empty_string;
}
string symbol() const {
- switch (kind) {
- case LPAREN: return "(";
- case RPAREN: return ")";
- case TOK_NOT: return "not";
- 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 END_REACHED: return "<EOF>";
-
- case TERM:
- assert(false);
- return "<TERM>";
-
- case UNKNOWN:
- default:
- assert(false);
- return "<UNKNOWN>";
- }
+ switch (kind) {
+ case LPAREN: return "(";
+ case RPAREN: return ")";
+ case TOK_NOT: return "not";
+ case TOK_AND: return "and";
+ case TOK_OR: return "or";
+ case TOK_EQ: return "=";
+ 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_ONLY: return "only";
+ 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>";
+
+ case TERM:
+ assert(false);
+ return "<TERM>";
+
+ case UNKNOWN:
+ default:
+ assert(false);
+ return "<UNKNOWN>";
+ }
}
void unexpected();
@@ -178,11 +198,11 @@ public:
token_t token_cache;
lexer_t(value_t::sequence_t::const_iterator _begin,
- value_t::sequence_t::const_iterator _end,
- bool _multiple_args = true)
+ value_t::sequence_t::const_iterator _end,
+ bool _multiple_args = true)
: begin(_begin), end(_end),
- consume_whitespace(false), consume_next_arg(false),
- multiple_args(_multiple_args)
+ consume_whitespace(false), consume_next_arg(false),
+ multiple_args(_multiple_args)
{
TRACE_CTOR(query_t::lexer_t, "");
assert(begin != end);
@@ -191,11 +211,10 @@ public:
}
lexer_t(const lexer_t& lexer)
: begin(lexer.begin), end(lexer.end),
- 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)
+ 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)
{
TRACE_CTOR(query_t::lexer_t, "copy");
}
@@ -210,29 +229,45 @@ public:
}
token_t peek_token() {
if (token_cache.kind == token_t::UNKNOWN)
- token_cache = next_token();
+ token_cache = next_token();
return token_cache;
}
};
+ enum kind_t {
+ QUERY_LIMIT,
+ QUERY_SHOW,
+ QUERY_ONLY,
+ 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) {
@@ -242,8 +277,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() {
@@ -254,55 +289,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
diff --git a/src/quotes.cc b/src/quotes.cc
index 4e3ec33e..0cc8d06b 100644
--- a/src/quotes.cc
+++ b/src/quotes.cc
@@ -40,13 +40,13 @@ namespace ledger {
optional<price_point_t>
commodity_quote_from_script(commodity_t& commodity,
- const optional<commodity_t&>& exchange_commodity)
+ const optional<commodity_t&>& exchange_commodity)
{
DEBUG("commodity.download", "downloading quote for symbol " << commodity.symbol());
#if defined(DEBUG_ON)
if (exchange_commodity)
DEBUG("commodity.download",
- " in terms of commodity " << exchange_commodity->symbol());
+ " in terms of commodity " << exchange_commodity->symbol());
#endif
char buf[256];
@@ -62,6 +62,7 @@ commodity_quote_from_script(commodity_t& commodity,
DEBUG("commodity.download", "invoking command: " << getquote_cmd);
bool success = true;
+#ifndef WIN32
if (FILE * fp = popen(getquote_cmd.c_str(), "r")) {
if (std::feof(fp) || ! std::fgets(buf, 255, fp))
success = false;
@@ -76,33 +77,34 @@ commodity_quote_from_script(commodity_t& commodity,
DEBUG("commodity.download", "downloaded quote: " << buf);
if (optional<std::pair<commodity_t *, price_point_t> > point =
- commodity_pool_t::current_pool->parse_price_directive(buf)) {
+ commodity_pool_t::current_pool->parse_price_directive(buf)) {
if (commodity_pool_t::current_pool->price_db) {
#if defined(__GNUG__) && __GNUG__ < 3
- ofstream database(*commodity_pool_t::current_pool->price_db,
- ios::out | ios::app);
+ ofstream database(*commodity_pool_t::current_pool->price_db,
+ ios::out | ios::app);
#else
- ofstream database(*commodity_pool_t::current_pool->price_db,
- std::ios_base::out | std::ios_base::app);
+ ofstream database(*commodity_pool_t::current_pool->price_db,
+ std::ios_base::out | std::ios_base::app);
#endif
- database << "P "
- << format_datetime(point->second.when, FMT_WRITTEN)
- << " " << commodity.symbol()
- << " " << point->second.price
- << std::endl;
+ database << "P "
+ << format_datetime(point->second.when, FMT_WRITTEN)
+ << " " << commodity.symbol()
+ << " " << point->second.price
+ << std::endl;
}
return point->second;
}
} else {
DEBUG("commodity.download",
- "Failed to download price for '" << commodity.symbol() <<
- "' (command: \"getquote " << commodity.symbol() <<
- " " << (exchange_commodity ?
- exchange_commodity->symbol() : "''") << "\")");
+ "Failed to download price for '" << commodity.symbol() <<
+ "' (command: \"getquote " << commodity.symbol() <<
+ " " << (exchange_commodity ?
+ exchange_commodity->symbol() : "''") << "\")");
// Don't try to download this commodity again.
commodity.add_flags(COMMODITY_NOMARKET);
}
+#endif
return none;
}
diff --git a/src/quotes.h b/src/quotes.h
index e981fdad..376d8918 100644
--- a/src/quotes.h
+++ b/src/quotes.h
@@ -46,7 +46,7 @@ namespace ledger {
optional<price_point_t>
commodity_quote_from_script(commodity_t& commodity,
- const optional<commodity_t&>& exchange_commodity);
+ const optional<commodity_t&>& exchange_commodity);
} // namespace ledger
diff --git a/src/report.cc b/src/report.cc
index 4302187e..e98596a3 100644
--- a/src/report.cc
+++ b/src/report.cc
@@ -47,6 +47,7 @@
#include "convert.h"
#include "xml.h"
#include "emacs.h"
+#include "org.h"
namespace ledger {
@@ -76,7 +77,7 @@ void report_t::normalize_options(const string& verb)
}
item_t::use_effective_date = (HANDLED(effective) &&
- ! HANDLED(actual_dates));
+ ! HANDLED(actual_dates));
commodity_pool_t::current_pool->keep_base = HANDLED(base);
commodity_pool_t::current_pool->get_quotes = session.HANDLED(download);
@@ -96,7 +97,7 @@ void report_t::normalize_options(const string& verb)
set_datetime_format(HANDLER(datetime_format_).str().c_str());
if (HANDLED(start_of_week_)) {
if (optional<date_time::weekdays> weekday =
- string_to_day_of_week(HANDLER(start_of_week_).str()))
+ string_to_day_of_week(HANDLER(start_of_week_).str()))
start_of_week = *weekday;
}
@@ -106,24 +107,24 @@ void report_t::normalize_options(const string& verb)
if (! HANDLED(meta_width_)) {
string::size_type i = HANDLER(meta_).str().find(':');
if (i != string::npos) {
- HANDLED(meta_width_).on_with
- (string("?normalize"),
- lexical_cast<long>(string(HANDLER(meta_).str(), i + 1)));
- HANDLED(meta_).on(string("?normalize"),
- string(HANDLER(meta_).str(), 0, i));
+ HANDLED(meta_width_).on_with
+ (string("?normalize"),
+ lexical_cast<long>(string(HANDLER(meta_).str(), i + 1)));
+ HANDLED(meta_).on(string("?normalize"),
+ string(HANDLER(meta_).str(), 0, i));
}
}
if (HANDLED(meta_width_)) {
HANDLER(prepend_format_).on
- (string("?normalize"),
- string("%(justify(truncated(tag(\"") +
- HANDLER(meta_).str() + "\"), " +
- HANDLED(meta_width_).value.to_string() + " - 1), " +
- HANDLED(meta_width_).value.to_string() + "))");
+ (string("?normalize"),
+ string("%(justify(truncated(tag(\"") +
+ HANDLER(meta_).str() + "\"), " +
+ HANDLED(meta_width_).value.to_string() + " - 1), " +
+ HANDLED(meta_width_).value.to_string() + "))");
meta_width = HANDLED(meta_width_).value.to_long();
} else {
HANDLER(prepend_format_).on(string("?normalize"), string("%(tag(\"") +
- HANDLER(meta_).str() + "\"))");
+ HANDLER(meta_).str() + "\"))");
}
}
if (! HANDLED(prepend_width_))
@@ -137,14 +138,6 @@ void report_t::normalize_options(const string& verb)
HANDLER(equity).on_only(string("?normalize"));
}
- if (verb == "print")
- HANDLER(limit_).on(string("?normalize"), "actual");
-
- if (! HANDLED(empty))
- HANDLER(display_).on(string("?normalize"),
- string("(post?(display_amount|account=\"") +
- _("<Revalued>") + "\"):display_total)");
-
if (verb[0] != 'b' && verb[0] != 'r')
HANDLER(base).on_only(string("?normalize"));
@@ -153,26 +146,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(session.current_year);
- optional<date_t> end = interval.end(session.current_year);
-
- 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
@@ -191,7 +166,7 @@ void report_t::normalize_options(const string& verb)
if (HANDLED(exchange_) &&
HANDLER(exchange_).str().find('=') != string::npos) {
value_t(0L).exchange_commodities(HANDLER(exchange_).str(), true,
- terminus);
+ terminus);
}
long cols = 0;
@@ -210,22 +185,22 @@ void report_t::normalize_options(const string& verb)
if (! HANDLER(date_width_).specified)
HANDLER(date_width_)
- .on_with(none, static_cast<long>(format_date(CURRENT_DATE(),
- FMT_PRINTED).length()));
+ .on_with(none, static_cast<long>(format_date(CURRENT_DATE(),
+ FMT_PRINTED).length()));
long date_width = HANDLER(date_width_).value.to_long();
long payee_width = (HANDLER(payee_width_).specified ?
- HANDLER(payee_width_).value.to_long() :
- int(double(cols) * 0.263157));
+ HANDLER(payee_width_).value.to_long() :
+ int(double(cols) * 0.263157));
long account_width = (HANDLER(account_width_).specified ?
- HANDLER(account_width_).value.to_long() :
- int(double(cols) * 0.302631));
+ HANDLER(account_width_).value.to_long() :
+ int(double(cols) * 0.302631));
long amount_width = (HANDLER(amount_width_).specified ?
- HANDLER(amount_width_).value.to_long() :
- int(double(cols) * 0.157894));
+ HANDLER(amount_width_).value.to_long() :
+ int(double(cols) * 0.157894));
long total_width = (HANDLER(total_width_).specified ?
- HANDLER(total_width_).value.to_long() :
- amount_width);
+ HANDLER(total_width_).value.to_long() :
+ amount_width);
DEBUG("auto.columns", "date_width = " << date_width);
DEBUG("auto.columns", "payee_width = " << payee_width);
@@ -234,16 +209,16 @@ void report_t::normalize_options(const string& verb)
DEBUG("auto.columns", "total_width = " << total_width);
if (! HANDLER(date_width_).specified &&
- ! HANDLER(payee_width_).specified &&
- ! HANDLER(account_width_).specified &&
- ! HANDLER(amount_width_).specified &&
- ! HANDLER(total_width_).specified) {
+ ! HANDLER(payee_width_).specified &&
+ ! HANDLER(account_width_).specified &&
+ ! HANDLER(amount_width_).specified &&
+ ! HANDLER(total_width_).specified) {
long total = (4 /* the spaces between */ + date_width + payee_width +
- account_width + amount_width + total_width);
+ account_width + amount_width + total_width);
if (total > cols) {
- DEBUG("auto.columns", "adjusting account down");
- account_width -= total - cols;
- DEBUG("auto.columns", "account_width now = " << account_width);
+ DEBUG("auto.columns", "adjusting account down");
+ account_width -= total - cols;
+ DEBUG("auto.columns", "account_width now = " << account_width);
}
}
@@ -262,24 +237,57 @@ 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_ONLY)) {
+ HANDLER(only_).on(whence, query.get_query(query_t::QUERY_ONLY));
+ DEBUG("report.predicate", "Only predicate = " << HANDLER(only_).str());
+ }
- DEBUG("report.predicate",
- "Display predicate = " << HANDLER(display_).str());
- }
+ 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());
+ }
+
+ 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
}
}
@@ -287,7 +295,7 @@ namespace {
struct posts_flusher
{
post_handler_ptr handler;
- report_t& report;
+ report_t& report;
posts_flusher(post_handler_ptr _handler, report_t& _report)
: handler(_handler), report(_report) {}
@@ -318,8 +326,6 @@ void report_t::posts_report(post_handler_ptr handler)
void report_t::generate_report(post_handler_ptr handler)
{
- HANDLER(limit_).on(string("#generate"), "actual");
-
handler = chain_handlers(handler, *this);
generate_posts_iterator walker
@@ -345,7 +351,7 @@ namespace {
struct accounts_title_printer
{
acct_handler_ptr handler;
- report_t& report;
+ report_t& report;
accounts_title_printer(acct_handler_ptr _handler, report_t& _report)
: handler(_handler), report(_report) {}
@@ -353,9 +359,9 @@ namespace {
void operator()(const value_t& val)
{
if (! report.HANDLED(no_titles)) {
- std::ostringstream buf;
- val.print(buf);
- handler->title(buf.str());
+ std::ostringstream buf;
+ val.print(buf);
+ handler->title(buf.str());
}
}
};
@@ -363,7 +369,7 @@ namespace {
struct accounts_flusher
{
acct_handler_ptr handler;
- report_t& report;
+ report_t& report;
accounts_flusher(acct_handler_ptr _handler, report_t& _report)
: handler(_handler), report(_report) {}
@@ -378,23 +384,23 @@ namespace {
scoped_ptr<accounts_iterator> iter;
if (! report.HANDLED(sort_)) {
- iter.reset(new basic_accounts_iterator(*report.session.journal->master));
+ iter.reset(new basic_accounts_iterator(*report.session.journal->master));
} else {
- expr_t sort_expr(report.HANDLER(sort_).str());
- sort_expr.set_context(&report);
- iter.reset(new sorted_accounts_iterator(*report.session.journal->master,
- sort_expr, report.HANDLED(flat)));
+ expr_t sort_expr(report.HANDLER(sort_).str());
+ sort_expr.set_context(&report);
+ iter.reset(new sorted_accounts_iterator(*report.session.journal->master,
+ sort_expr, report.HANDLED(flat)));
}
if (report.HANDLED(display_)) {
- DEBUG("report.predicate",
- "Display predicate = " << report.HANDLER(display_).str());
- pass_down_accounts(handler, *iter.get(),
- predicate_t(report.HANDLER(display_).str(),
- report.what_to_keep()),
- report);
+ DEBUG("report.predicate",
+ "Display predicate = " << report.HANDLER(display_).str());
+ pass_down_accounts(handler, *iter.get(),
+ predicate_t(report.HANDLER(display_).str(),
+ report.what_to_keep()),
+ report);
} else {
- pass_down_accounts(handler, *iter.get());
+ pass_down_accounts(handler, *iter.get());
}
report.session.journal->clear_xdata();
@@ -406,7 +412,7 @@ void report_t::accounts_report(acct_handler_ptr handler)
{
post_handler_ptr chain =
chain_post_handlers(post_handler_ptr(new ignore_posts), *this,
- /* for_accounts_report= */ true);
+ /* for_accounts_report= */ true);
if (HANDLED(group_by_)) {
std::auto_ptr<post_splitter>
splitter(new post_splitter(chain, *this, HANDLER(group_by_).expr));
@@ -438,6 +444,37 @@ 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();
+}
+
+namespace {
+ value_t top_amount(const value_t& val)
+ {
+ switch (val.type()) {
+ case value_t::BALANCE:
+ return (*val.as_balance().amounts.begin()).second;
+
+ case value_t::SEQUENCE: {
+ return top_amount(*val.as_sequence().begin());
+ }
+
+ default:
+ return val;
+ }
+ }
+}
+
+value_t report_t::fn_top_amount(call_scope_t& args)
+{
+ return top_amount(args[0]);
+}
+
value_t report_t::fn_amount_expr(call_scope_t& scope)
{
return HANDLER(amount_).expr.calc(scope);
@@ -458,44 +495,45 @@ value_t report_t::fn_display_total(call_scope_t& scope)
return HANDLER(display_total_).expr.calc(scope);
}
-value_t report_t::fn_market(call_scope_t& 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)
{
- interactive_t args(scope, "a&ts");
-
- value_t result;
- optional<datetime_t> moment = (args.has(1) ?
- args.get<datetime_t>(1) :
- optional<datetime_t>());
- if (args.has(2))
- result = args.value_at(0).exchange_commodities(args.get<string>(2),
- /* add_prices= */ false,
- moment);
+ optional<datetime_t> moment = (args.has<datetime_t>(1) ?
+ args.get<datetime_t>(1) :
+ optional<datetime_t>());
+ value_t result;
+ if (args.has<string>(2))
+ result = args[0].exchange_commodities(args.get<string>(2),
+ /* add_prices= */ false, moment);
else
- result = args.value_at(0).value(true, moment);
+ result = args[0].value(moment);
if (! result.is_null())
return result;
- return args.value_at(0);
+ return args[0];
}
-value_t report_t::fn_get_at(call_scope_t& scope)
+value_t report_t::fn_get_at(call_scope_t& args)
{
- interactive_t args(scope, "Sl");
-
- DEBUG("report.get_at", "get_at[0] = " << args.value_at(0));
- DEBUG("report.get_at", "get_at[1] = " << args.value_at(1));
-
- if (args.get<long>(1) == 0) {
- if (! args.value_at(0).is_sequence())
- return args.value_at(0);
+ std::size_t index = static_cast<std::size_t>(args.get<long>(1));
+ if (index == 0) {
+ if (! args[0].is_sequence())
+ return args[0];
} else {
- if (! args.value_at(0).is_sequence())
+ if (! args[0].is_sequence())
throw_(std::runtime_error,
- _("Attempting to get argument at index %1 from %2")
- << args.get<long>(1) << args.value_at(0).label());
+ _("Attempting to get argument at index %1 from %2")
+ << index << args[0].label());
}
- return args.get<const value_t::sequence_t&>(0)[args.get<long>(1)];
+ return args[0].as_sequence()[index];
}
value_t report_t::fn_is_seq(call_scope_t& scope)
@@ -510,7 +548,7 @@ value_t report_t::fn_strip(call_scope_t& args)
value_t report_t::fn_trim(call_scope_t& args)
{
- string temp(args.value().to_string());
+ string temp(args.value().to_string());
scoped_array<char> buf(new char[temp.length() + 1]);
std::strcpy(buf.get(), temp.c_str());
@@ -534,32 +572,25 @@ value_t report_t::fn_trim(call_scope_t& args)
}
}
-value_t report_t::fn_print(call_scope_t& args)
+value_t report_t::fn_format(call_scope_t& args)
{
- std::ostream& out(output_stream);
- bool first = true;
- for (call_scope_t::iterator i = args.begin(); i != args.end(); i++) {
- if (first)
- first = false;
- else
- out << ' ';
- (*i).print(out);
- }
- return true;
+ format_t format(args.get<string>(0));
+ std::ostringstream out;
+ out << format(args);
+ return string_value(out.str());
}
-value_t report_t::scrub(value_t val)
+value_t report_t::fn_print(call_scope_t& args)
{
- value_t temp(val.strip_annotations(what_to_keep()));
- if (HANDLED(base))
- return temp;
- else
- return temp.unreduced();
+ for (std::size_t i = 0; i < args.size(); i++)
+ args[i].print(output_stream);
+ static_cast<std::ostream&>(output_stream) << std::endl;
+ return true;
}
value_t report_t::fn_scrub(call_scope_t& args)
{
- return scrub(args.value());
+ return display_value(args.value());
}
value_t report_t::fn_rounded(call_scope_t& args)
@@ -572,52 +603,52 @@ value_t report_t::fn_unrounded(call_scope_t& args)
return args.value().unrounded();
}
-value_t report_t::fn_quantity(call_scope_t& scope)
+value_t report_t::fn_quantity(call_scope_t& args)
{
- interactive_t args(scope, "a");
return args.get<amount_t>(0).number();
}
-value_t report_t::fn_floor(call_scope_t& scope)
+value_t report_t::fn_floor(call_scope_t& args)
{
- interactive_t args(scope, "v");
- return args.value_at(0).floored();
+ return args[0].floored();
}
-value_t report_t::fn_abs(call_scope_t& scope)
+value_t report_t::fn_abs(call_scope_t& args)
{
- interactive_t args(scope, "v");
- return args.value_at(0).abs();
+ return args[0].abs();
}
-value_t report_t::fn_truncated(call_scope_t& scope)
+value_t report_t::fn_truncated(call_scope_t& args)
{
- interactive_t args(scope, "v&ll");
return string_value(format_t::truncate
- (args.get<string>(0),
- args.has(1) && args.get<int>(1) > 0 ? args.get<int>(1) : 0,
- args.has(2) ? args.get<int>(2) : 0));
+ (args.get<string>(0),
+ args.has<int>(1) &&
+ args.get<int>(1) > 0 ? args.get<int>(1) : 0,
+ args.has<int>(2) ? args.get<int>(2) : 0));
}
-value_t report_t::fn_justify(call_scope_t& scope)
+value_t report_t::fn_justify(call_scope_t& args)
{
- interactive_t args(scope, "vl&lbb");
+ uint_least8_t flags(AMOUNT_PRINT_ELIDE_COMMODITY_QUOTES);
+
+ if (args.has<bool>(3) && args.get<bool>(3))
+ flags |= AMOUNT_PRINT_RIGHT_JUSTIFY;
+ if (args.has<bool>(4) && args.get<bool>(4))
+ flags |= AMOUNT_PRINT_COLORIZE;
+
std::ostringstream out;
- args.value_at(0)
- .print(out, args.get<int>(1),
- args.has(2) ? args.get<int>(2) : -1,
- args.has(3) ? args.get<bool>(3) : false,
- args.has(4) ? args.get<bool>(4) : false);
+ args[0].print(out, args.get<int>(1),
+ args.has<int>(2) ? args.get<int>(2) : -1, flags);
+
return string_value(out.str());
}
-value_t report_t::fn_quoted(call_scope_t& scope)
+value_t report_t::fn_quoted(call_scope_t& args)
{
- interactive_t args(scope, "v");
std::ostringstream out;
out << '"';
- foreach (const char ch, args.value_at(0).to_string()) {
+ foreach (const char ch, args.get<string>(0)) {
if (ch == '"')
out << "\\\"";
else
@@ -628,9 +659,8 @@ value_t report_t::fn_quoted(call_scope_t& scope)
return string_value(out.str());
}
-value_t report_t::fn_join(call_scope_t& scope)
+value_t report_t::fn_join(call_scope_t& args)
{
- interactive_t args(scope, "s");
std::ostringstream out;
foreach (const char ch, args.get<string>(0)) {
@@ -642,149 +672,130 @@ value_t report_t::fn_join(call_scope_t& scope)
return string_value(out.str());
}
-value_t report_t::fn_format_date(call_scope_t& scope)
+value_t report_t::fn_format_date(call_scope_t& args)
{
- interactive_t args(scope, "d&s");
- if (args.has(1))
+ if (args.has<string>(1))
return string_value(format_date(args.get<date_t>(0), FMT_CUSTOM,
- args.get<string>(1).c_str()));
+ args.get<string>(1).c_str()));
else
return string_value(format_date(args.get<date_t>(0), FMT_PRINTED));
}
-value_t report_t::fn_ansify_if(call_scope_t& scope)
+value_t report_t::fn_ansify_if(call_scope_t& args)
{
- interactive_t args(scope, "v&s");
-
- if (args.has(1)) {
+ if (args.has<string>(1)) {
string color = args.get<string>(1);
std::ostringstream buf;
- if (color == "black") buf << "\033[30m";
- else if (color == "red") buf << "\033[31m";
- else if (color == "green") buf << "\033[32m";
- else if (color == "yellow") buf << "\033[33m";
- else if (color == "blue") buf << "\033[34m";
+ if (color == "black") buf << "\033[30m";
+ else if (color == "red") buf << "\033[31m";
+ else if (color == "green") buf << "\033[32m";
+ else if (color == "yellow") buf << "\033[33m";
+ else if (color == "blue") buf << "\033[34m";
else if (color == "magenta") buf << "\033[35m";
- else if (color == "cyan") buf << "\033[36m";
- else if (color == "white") buf << "\033[37m";
- else if (color == "bold") buf << "\033[1m";
+ else if (color == "cyan") buf << "\033[36m";
+ else if (color == "white") buf << "\033[37m";
+ else if (color == "bold") buf << "\033[1m";
else if (color == "underline") buf << "\033[4m";
- else if (color == "blink") buf << "\033[5m";
- buf << args.value_at(0);
+ else if (color == "blink") buf << "\033[5m";
+ buf << args[0];
buf << "\033[0m";
return string_value(buf.str());
- } else {
- return args.value_at(0);
}
+ return args[0];
}
-value_t report_t::fn_percent(call_scope_t& scope)
+value_t report_t::fn_percent(call_scope_t& args)
{
- interactive_t args(scope, "aa");
return (amount_t("100.00%") *
- (args.get<amount_t>(0) / args.get<amount_t>(1)).number());
+ (args.get<amount_t>(0) / args.get<amount_t>(1)).number());
}
-value_t report_t::fn_price(call_scope_t& scope)
+value_t report_t::fn_price(call_scope_t& args)
{
- interactive_t args(scope, "v");
- return args.value_at(0).price();
+ return args[0].price();
}
-value_t report_t::fn_lot_date(call_scope_t& scope)
+value_t report_t::fn_commodity(call_scope_t& args)
{
- interactive_t args(scope, "v");
- if (args.value_at(0).has_annotation()) {
- const annotation_t& details(args.value_at(0).annotation());
+ return string_value(args.get<amount_t>(0).commodity().symbol());
+}
+
+value_t report_t::fn_lot_date(call_scope_t& args)
+{
+ if (args[0].has_annotation()) {
+ const annotation_t& details(args[0].annotation());
if (details.date)
return *details.date;
}
return NULL_VALUE;
}
-value_t report_t::fn_lot_price(call_scope_t& scope)
+value_t report_t::fn_lot_price(call_scope_t& args)
{
- interactive_t args(scope, "v");
- if (args.value_at(0).has_annotation()) {
- const annotation_t& details(args.value_at(0).annotation());
+ if (args[0].has_annotation()) {
+ const annotation_t& details(args[0].annotation());
if (details.price)
return *details.price;
}
return NULL_VALUE;
}
-value_t report_t::fn_lot_tag(call_scope_t& scope)
+value_t report_t::fn_lot_tag(call_scope_t& args)
{
- interactive_t args(scope, "v");
- if (args.value_at(0).has_annotation()) {
- const annotation_t& details(args.value_at(0).annotation());
+ if (args[0].has_annotation()) {
+ const annotation_t& details(args[0].annotation());
if (details.tag)
return string_value(*details.tag);
}
return NULL_VALUE;
}
-value_t report_t::fn_to_boolean(call_scope_t& scope)
+value_t report_t::fn_to_boolean(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::BOOLEAN);
- return args.value_at(0);
+ return args.get<bool>(0);
}
-value_t report_t::fn_to_int(call_scope_t& scope)
+value_t report_t::fn_to_int(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::INTEGER);
- return args.value_at(0);
+ // This method is not called fn_to_long, because that would be
+ // confusing to users who don't care about the distinction between
+ // integer and long.
+ return args.get<long>(0);
}
-value_t report_t::fn_to_datetime(call_scope_t& scope)
+value_t report_t::fn_to_datetime(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::DATETIME);
- return args.value_at(0);
+ return args.get<datetime_t>(0);
}
-value_t report_t::fn_to_date(call_scope_t& scope)
+value_t report_t::fn_to_date(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::DATE);
- return args.value_at(0);
+ return args.get<date_t>(0);
}
-value_t report_t::fn_to_amount(call_scope_t& scope)
+value_t report_t::fn_to_amount(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::AMOUNT);
- return args.value_at(0);
+ return args.get<amount_t>(0);
}
-value_t report_t::fn_to_balance(call_scope_t& scope)
+value_t report_t::fn_to_balance(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::BALANCE);
- return args.value_at(0);
+ return args.get<balance_t>(0);
}
-value_t report_t::fn_to_string(call_scope_t& scope)
+value_t report_t::fn_to_string(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::STRING);
- return args.value_at(0);
+ return string_value(args.get<string>(0));
}
-value_t report_t::fn_to_mask(call_scope_t& scope)
+value_t report_t::fn_to_mask(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::MASK);
- return args.value_at(0);
+ return args.get<mask_t>(0);
}
-value_t report_t::fn_to_sequence(call_scope_t& scope)
+value_t report_t::fn_to_sequence(call_scope_t& args)
{
- interactive_t args(scope, "v");
- args.value_at(0).in_place_cast(value_t::SEQUENCE);
- return args.value_at(0);
+ return args[0].to_sequence();
}
namespace {
@@ -836,21 +847,19 @@ value_t report_t::reload_command(call_scope_t&)
return true;
}
-value_t report_t::echo_command(call_scope_t& scope)
+value_t report_t::echo_command(call_scope_t& args)
{
- interactive_t args(scope, "s");
std::ostream& out(output_stream);
out << args.get<string>(0) << std::endl;
return true;
}
-value_t report_t::pricemap_command(call_scope_t& scope)
+value_t report_t::pricemap_command(call_scope_t& args)
{
- interactive_t args(scope, "&s");
std::ostream& out(output_stream);
commodity_pool_t::current_pool->print_pricemap
- (out, what_to_keep(), args.has(0) ?
+ (out, what_to_keep(), args.has<string>(0) ?
optional<datetime_t>(datetime_t(parse_date(args.get<string>(0)))) : none);
return true;
@@ -944,6 +953,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;
@@ -992,12 +1002,14 @@ option_t<report_t> * report_t::lookup_option(const char * p)
OPT(gain);
else OPT(group_by_);
else OPT(group_title_format_);
+ else OPT(generated);
break;
case 'h':
OPT(head_);
break;
case 'i':
OPT(invert);
+ else OPT(inject_);
break;
case 'j':
OPT_CH(amount_data);
@@ -1045,7 +1057,6 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(payee_width_);
else OPT(prepend_format_);
else OPT(prepend_width_);
- else OPT(print_virtual);
break;
case 'q':
OPT(quantity);
@@ -1084,7 +1095,6 @@ option_t<report_t> * report_t::lookup_option(const char * p)
else OPT(unrealized_gains_);
else OPT(unrealized_losses_);
else OPT(unround);
- else OPT(unsorted);
break;
case 'w':
OPT(weekly);
@@ -1099,13 +1109,13 @@ option_t<report_t> * report_t::lookup_option(const char * p)
}
void report_t::define(const symbol_t::kind_t kind, const string& name,
- expr_t::ptr_op_t def)
+ expr_t::ptr_op_t def)
{
session.define(kind, name, def);
}
expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (expr_t::ptr_op_t def = session.lookup(kind, name))
return def;
@@ -1119,203 +1129,216 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
switch (*p) {
case 'd':
case 'm':
- return MAKE_FUNCTOR(report_t::fn_now);
+ return MAKE_FUNCTOR(report_t::fn_now);
case 'P':
- return MAKE_FUNCTOR(report_t::fn_market);
+ return MAKE_FUNCTOR(report_t::fn_market);
case 't':
- return MAKE_FUNCTOR(report_t::fn_display_amount);
+ return MAKE_FUNCTOR(report_t::fn_display_amount);
case 'T':
- return MAKE_FUNCTOR(report_t::fn_display_total);
+ return MAKE_FUNCTOR(report_t::fn_display_total);
case 'U':
- return MAKE_FUNCTOR(report_t::fn_abs);
+ return MAKE_FUNCTOR(report_t::fn_abs);
case 'S':
- return MAKE_FUNCTOR(report_t::fn_strip);
+ return MAKE_FUNCTOR(report_t::fn_strip);
case 'i':
- throw_(std::runtime_error,
- _("The i value expression variable is no longer supported"));
+ throw_(std::runtime_error,
+ _("The i value expression variable is no longer supported"));
case 'A':
- throw_(std::runtime_error,
- _("The A value expression variable is no longer supported"));
+ throw_(std::runtime_error,
+ _("The A value expression variable is no longer supported"));
case 'v':
case 'V':
- throw_(std::runtime_error,
- _("The V and v value expression variables are no longer supported"));
+ throw_(std::runtime_error,
+ _("The V and v value expression variables are no longer supported"));
case 'I':
case 'B':
- throw_(std::runtime_error,
- _("The I and B value expression variables are no longer supported"));
+ throw_(std::runtime_error,
+ _("The I and B value expression variables are no longer supported"));
case 'g':
case 'G':
- throw_(std::runtime_error,
- _("The G and g value expression variables are no longer supported"));
+ throw_(std::runtime_error,
+ _("The G and g value expression variables are no longer supported"));
default:
- return NULL;
+ return NULL;
}
}
switch (*p) {
case 'a':
if (is_eq(p, "amount_expr"))
- return MAKE_FUNCTOR(report_t::fn_amount_expr);
+ return MAKE_FUNCTOR(report_t::fn_amount_expr);
else if (is_eq(p, "ansify_if"))
- return MAKE_FUNCTOR(report_t::fn_ansify_if);
+ return MAKE_FUNCTOR(report_t::fn_ansify_if);
else if (is_eq(p, "abs"))
- return MAKE_FUNCTOR(report_t::fn_abs);
+ return MAKE_FUNCTOR(report_t::fn_abs);
break;
case 'b':
if (is_eq(p, "black"))
- return WRAP_FUNCTOR(fn_black);
+ return WRAP_FUNCTOR(fn_black);
else if (is_eq(p, "blink"))
- return WRAP_FUNCTOR(fn_blink);
+ return WRAP_FUNCTOR(fn_blink);
else if (is_eq(p, "blue"))
- return WRAP_FUNCTOR(fn_blue);
+ return WRAP_FUNCTOR(fn_blue);
else if (is_eq(p, "bold"))
- return WRAP_FUNCTOR(fn_bold);
+ return WRAP_FUNCTOR(fn_bold);
break;
case 'c':
if (is_eq(p, "cyan"))
- return WRAP_FUNCTOR(fn_cyan);
+ return WRAP_FUNCTOR(fn_cyan);
+ else if (is_eq(p, "commodity"))
+ return MAKE_FUNCTOR(report_t::fn_commodity);
break;
case 'd':
if (is_eq(p, "display_amount"))
- return MAKE_FUNCTOR(report_t::fn_display_amount);
+ return MAKE_FUNCTOR(report_t::fn_display_amount);
else if (is_eq(p, "display_total"))
- return MAKE_FUNCTOR(report_t::fn_display_total);
+ return MAKE_FUNCTOR(report_t::fn_display_total);
else if (is_eq(p, "date"))
- return MAKE_FUNCTOR(report_t::fn_now);
+ return MAKE_FUNCTOR(report_t::fn_now);
break;
case 'f':
if (is_eq(p, "format_date"))
- return MAKE_FUNCTOR(report_t::fn_format_date);
+ return MAKE_FUNCTOR(report_t::fn_format_date);
+ else if (is_eq(p, "format"))
+ return MAKE_FUNCTOR(report_t::fn_format);
else if (is_eq(p, "floor"))
- return MAKE_FUNCTOR(report_t::fn_floor);
+ return MAKE_FUNCTOR(report_t::fn_floor);
break;
case 'g':
if (is_eq(p, "get_at"))
- return MAKE_FUNCTOR(report_t::fn_get_at);
+ return MAKE_FUNCTOR(report_t::fn_get_at);
else if (is_eq(p, "green"))
- return WRAP_FUNCTOR(fn_green);
+ return WRAP_FUNCTOR(fn_green);
break;
case 'i':
if (is_eq(p, "is_seq"))
- return MAKE_FUNCTOR(report_t::fn_is_seq);
+ return MAKE_FUNCTOR(report_t::fn_is_seq);
break;
case 'j':
if (is_eq(p, "justify"))
- return MAKE_FUNCTOR(report_t::fn_justify);
+ return MAKE_FUNCTOR(report_t::fn_justify);
else if (is_eq(p, "join"))
- return MAKE_FUNCTOR(report_t::fn_join);
+ return MAKE_FUNCTOR(report_t::fn_join);
break;
case 'm':
if (is_eq(p, "market"))
- return MAKE_FUNCTOR(report_t::fn_market);
+ return MAKE_FUNCTOR(report_t::fn_market);
else if (is_eq(p, "magenta"))
- return WRAP_FUNCTOR(fn_magenta);
+ return WRAP_FUNCTOR(fn_magenta);
break;
case 'n':
if (is_eq(p, "null"))
- return WRAP_FUNCTOR(fn_null);
+ return WRAP_FUNCTOR(fn_null);
else if (is_eq(p, "now"))
- return MAKE_FUNCTOR(report_t::fn_now);
+ return MAKE_FUNCTOR(report_t::fn_now);
break;
case 'o':
if (is_eq(p, "options"))
- return MAKE_FUNCTOR(report_t::fn_options);
+ return MAKE_FUNCTOR(report_t::fn_options);
break;
case 'p':
if (is_eq(p, "post"))
- return WRAP_FUNCTOR(fn_false);
+ return WRAP_FUNCTOR(fn_false);
else if (is_eq(p, "percent"))
- return MAKE_FUNCTOR(report_t::fn_percent);
+ return MAKE_FUNCTOR(report_t::fn_percent);
else if (is_eq(p, "price"))
- return MAKE_FUNCTOR(report_t::fn_price);
+ return MAKE_FUNCTOR(report_t::fn_price);
else if (is_eq(p, "print"))
- return MAKE_FUNCTOR(report_t::fn_print);
+ return MAKE_FUNCTOR(report_t::fn_print);
break;
case 'q':
if (is_eq(p, "quoted"))
- return MAKE_FUNCTOR(report_t::fn_quoted);
+ return MAKE_FUNCTOR(report_t::fn_quoted);
else if (is_eq(p, "quantity"))
- return MAKE_FUNCTOR(report_t::fn_quantity);
+ return MAKE_FUNCTOR(report_t::fn_quantity);
break;
case 'r':
if (is_eq(p, "rounded"))
- return MAKE_FUNCTOR(report_t::fn_rounded);
+ return MAKE_FUNCTOR(report_t::fn_rounded);
else if (is_eq(p, "red"))
- return WRAP_FUNCTOR(fn_red);
+ return WRAP_FUNCTOR(fn_red);
break;
case 's':
if (is_eq(p, "scrub"))
- return MAKE_FUNCTOR(report_t::fn_scrub);
+ return MAKE_FUNCTOR(report_t::fn_scrub);
else if (is_eq(p, "strip"))
- return MAKE_FUNCTOR(report_t::fn_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':
if (is_eq(p, "truncated"))
- return MAKE_FUNCTOR(report_t::fn_truncated);
+ return MAKE_FUNCTOR(report_t::fn_truncated);
else if (is_eq(p, "total_expr"))
- return MAKE_FUNCTOR(report_t::fn_total_expr);
+ return MAKE_FUNCTOR(report_t::fn_total_expr);
else if (is_eq(p, "today"))
- return MAKE_FUNCTOR(report_t::fn_today);
+ return MAKE_FUNCTOR(report_t::fn_today);
else if (is_eq(p, "t"))
- return MAKE_FUNCTOR(report_t::fn_display_amount);
+ return MAKE_FUNCTOR(report_t::fn_display_amount);
else if (is_eq(p, "trim"))
- return MAKE_FUNCTOR(report_t::fn_trim);
+ return MAKE_FUNCTOR(report_t::fn_trim);
+ else if (is_eq(p, "top_amount"))
+ return MAKE_FUNCTOR(report_t::fn_top_amount);
else if (is_eq(p, "to_boolean"))
- return MAKE_FUNCTOR(report_t::fn_to_boolean);
+ return MAKE_FUNCTOR(report_t::fn_to_boolean);
else if (is_eq(p, "to_int"))
- return MAKE_FUNCTOR(report_t::fn_to_int);
+ return MAKE_FUNCTOR(report_t::fn_to_int);
else if (is_eq(p, "to_datetime"))
- return MAKE_FUNCTOR(report_t::fn_to_datetime);
+ return MAKE_FUNCTOR(report_t::fn_to_datetime);
else if (is_eq(p, "to_date"))
- return MAKE_FUNCTOR(report_t::fn_to_date);
+ return MAKE_FUNCTOR(report_t::fn_to_date);
else if (is_eq(p, "to_amount"))
- return MAKE_FUNCTOR(report_t::fn_to_amount);
+ return MAKE_FUNCTOR(report_t::fn_to_amount);
else if (is_eq(p, "to_balance"))
- return MAKE_FUNCTOR(report_t::fn_to_balance);
+ return MAKE_FUNCTOR(report_t::fn_to_balance);
else if (is_eq(p, "to_string"))
- return MAKE_FUNCTOR(report_t::fn_to_string);
+ return MAKE_FUNCTOR(report_t::fn_to_string);
else if (is_eq(p, "to_mask"))
- return MAKE_FUNCTOR(report_t::fn_to_mask);
+ return MAKE_FUNCTOR(report_t::fn_to_mask);
else if (is_eq(p, "to_sequence"))
- return MAKE_FUNCTOR(report_t::fn_to_sequence);
+ return MAKE_FUNCTOR(report_t::fn_to_sequence);
break;
case 'T':
if (is_eq(p, "T"))
- return MAKE_FUNCTOR(report_t::fn_display_total);
+ return MAKE_FUNCTOR(report_t::fn_display_total);
break;
case 'u':
if (is_eq(p, "underline"))
- return WRAP_FUNCTOR(fn_underline);
+ return WRAP_FUNCTOR(fn_underline);
else if (is_eq(p, "unrounded"))
- return MAKE_FUNCTOR(report_t::fn_unrounded);
+ return MAKE_FUNCTOR(report_t::fn_unrounded);
+ break;
+
+ case 'v':
+ if (is_eq(p, "value_date"))
+ return MAKE_FUNCTOR(report_t::fn_now);
break;
case 'w':
if (is_eq(p, "white"))
- return WRAP_FUNCTOR(fn_white);
+ return WRAP_FUNCTOR(fn_white);
break;
case 'y':
if (is_eq(p, "yellow"))
- return WRAP_FUNCTOR(fn_yellow);
+ return WRAP_FUNCTOR(fn_yellow);
break;
}
@@ -1333,135 +1356,146 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
switch (*p) {
case 'a':
if (is_eq(p, "accounts")) {
- return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this,
- "#accounts"));
+ return WRAP_FUNCTOR(reporter<>(new report_accounts(*this), *this,
+ "#accounts"));
}
break;
case 'b':
if (*(p + 1) == '\0' || is_eq(p, "bal") || is_eq(p, "balance")) {
- return expr_t::op_t::wrap_functor
- (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
- (new format_accounts(*this, report_format(HANDLER(balance_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#balance"));
+ return expr_t::op_t::wrap_functor
+ (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
+ (new format_accounts(*this, report_format(HANDLER(balance_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#balance"));
}
else if (is_eq(p, "budget")) {
- HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)");
-
- budget_flags |= BUDGET_WRAP_VALUES;
- if (! (budget_flags & ~BUDGET_WRAP_VALUES))
- budget_flags |= BUDGET_BUDGETED;
-
- return expr_t::op_t::wrap_functor
- (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
- (new format_accounts(*this, report_format(HANDLER(budget_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#budget"));
+ HANDLER(amount_).set_expr(string("#budget"), "(amount, 0)");
+
+ budget_flags |= BUDGET_WRAP_VALUES;
+ if (! (budget_flags & ~BUDGET_WRAP_VALUES))
+ budget_flags |= BUDGET_BUDGETED;
+
+ return expr_t::op_t::wrap_functor
+ (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
+ (new format_accounts(*this, report_format(HANDLER(budget_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#budget"));
}
break;
case 'c':
if (is_eq(p, "csv")) {
- return WRAP_FUNCTOR
- (reporter<>
- (new format_posts(*this, report_format(HANDLER(csv_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#csv"));
+ return WRAP_FUNCTOR
+ (reporter<>
+ (new format_posts(*this, report_format(HANDLER(csv_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#csv"));
}
else if (is_eq(p, "cleared")) {
- HANDLER(amount_).set_expr(string("#cleared"),
- "(amount, cleared ? amount : 0)");
- return expr_t::op_t::wrap_functor
- (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
- (new format_accounts(*this, report_format(HANDLER(cleared_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#cleared"));
+ HANDLER(amount_).set_expr(string("#cleared"),
+ "(amount, cleared ? amount : 0)");
+ return expr_t::op_t::wrap_functor
+ (reporter<account_t, acct_handler_ptr, &report_t::accounts_report>
+ (new format_accounts(*this, report_format(HANDLER(cleared_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#cleared"));
}
else if (is_eq(p, "convert")) {
- return WRAP_FUNCTOR(convert_command);
+ return WRAP_FUNCTOR(convert_command);
}
else if (is_eq(p, "commodities")) {
- return WRAP_FUNCTOR(reporter<>(new report_commodities(*this), *this,
- "#commodities"));
+ return WRAP_FUNCTOR(reporter<>(new report_commodities(*this), *this,
+ "#commodities"));
}
break;
case 'e':
if (is_eq(p, "equity")) {
- HANDLER(print_virtual).on_only(string("#equity"));
- return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity"));
+ HANDLER(generated).on_only(string("#equity"));
+ return WRAP_FUNCTOR(reporter<>(new print_xacts(*this), *this, "#equity"));
}
else if (is_eq(p, "entry")) {
- return WRAP_FUNCTOR(xact_command);
+ return WRAP_FUNCTOR(xact_command);
}
else if (is_eq(p, "emacs")) {
- return WRAP_FUNCTOR
- (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs"));
+ return WRAP_FUNCTOR
+ (reporter<>(new format_emacs_posts(output_stream), *this, "#emacs"));
}
else if (is_eq(p, "echo")) {
- return MAKE_FUNCTOR(report_t::echo_command);
+ return MAKE_FUNCTOR(report_t::echo_command);
+ }
+ break;
+
+ case 'o':
+ if (is_eq(p, "org")) {
+ return WRAP_FUNCTOR
+ (reporter<>
+ (new posts_to_org_table(*this, maybe_format(HANDLER(prepend_format_))),
+ *this, "#org"));
}
break;
case 'p':
if (*(p + 1) == '\0' || is_eq(p, "print")) {
- return WRAP_FUNCTOR
- (reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print"));
+ return WRAP_FUNCTOR
+ (reporter<>(new print_xacts(*this, HANDLED(raw)), *this, "#print"));
}
else if (is_eq(p, "prices")) {
- return expr_t::op_t::wrap_functor
- (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
- (new format_posts(*this, report_format(HANDLER(prices_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#prices"));
+ return expr_t::op_t::wrap_functor
+ (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
+ (new format_posts(*this, report_format(HANDLER(prices_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#prices"));
}
else if (is_eq(p, "pricedb")) {
- return expr_t::op_t::wrap_functor
- (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
- (new format_posts(*this, report_format(HANDLER(pricedb_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#pricedb"));
+ return expr_t::op_t::wrap_functor
+ (reporter<post_t, post_handler_ptr, &report_t::commodities_report>
+ (new format_posts(*this, report_format(HANDLER(pricedb_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#pricedb"));
}
else if (is_eq(p, "pricemap")) {
- return MAKE_FUNCTOR(report_t::pricemap_command);
+ return MAKE_FUNCTOR(report_t::pricemap_command);
}
else if (is_eq(p, "payees")) {
- return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this,
- "#payees"));
+ return WRAP_FUNCTOR(reporter<>(new report_payees(*this), *this,
+ "#payees"));
}
break;
case 'r':
if (*(p + 1) == '\0' || is_eq(p, "reg") || is_eq(p, "register")) {
- return WRAP_FUNCTOR
- (reporter<>
- (new format_posts(*this, report_format(HANDLER(register_format_)),
- maybe_format(HANDLER(prepend_format_)),
- HANDLER(prepend_width_).value.to_long()),
- *this, "#register"));
+ return WRAP_FUNCTOR
+ (reporter<>
+ (new format_posts(*this, report_format(HANDLER(register_format_)),
+ maybe_format(HANDLER(prepend_format_)),
+ HANDLER(prepend_width_).value.to_long()),
+ *this, "#register"));
}
else if (is_eq(p, "reload")) {
- return MAKE_FUNCTOR(report_t::reload_command);
+ return MAKE_FUNCTOR(report_t::reload_command);
}
break;
case 's':
if (is_eq(p, "stats") || is_eq(p, "stat"))
- return WRAP_FUNCTOR(report_statistics);
+ return WRAP_FUNCTOR(report_statistics);
+ else if (is_eq(p, "source"))
+ return WRAP_FUNCTOR(source_command);
break;
case 'x':
if (is_eq(p, "xact"))
- return WRAP_FUNCTOR(xact_command);
+ return WRAP_FUNCTOR(xact_command);
else if (is_eq(p, "xml"))
- return WRAP_FUNCTOR(reporter<>(new format_xml(*this), *this, "#xml"));
+ return WRAP_FUNCTOR(reporter<>(new format_xml(*this), *this, "#xml"));
break;
}
break;
@@ -1470,39 +1504,38 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind,
switch (*p) {
case 'a':
if (is_eq(p, "args"))
- return WRAP_FUNCTOR(query_command);
+ return WRAP_FUNCTOR(query_command);
break;
case 'e':
if (is_eq(p, "eval"))
- return WRAP_FUNCTOR(eval_command);
+ return WRAP_FUNCTOR(eval_command);
else if (is_eq(p, "expr"))
- return WRAP_FUNCTOR(parse_command);
+ return WRAP_FUNCTOR(parse_command);
break;
case 'f':
if (is_eq(p, "format"))
- return WRAP_FUNCTOR(format_command);
+ return WRAP_FUNCTOR(format_command);
break;
case 'g':
if (is_eq(p, "generate")) {
- HANDLER(print_virtual).on_only(string("#generate"));
- return expr_t::op_t::wrap_functor
- (reporter<post_t, post_handler_ptr, &report_t::generate_report>
- (new print_xacts(*this), *this, "#generate"));
+ return expr_t::op_t::wrap_functor
+ (reporter<post_t, post_handler_ptr, &report_t::generate_report>
+ (new print_xacts(*this), *this, "#generate"));
}
break;
case 'p':
if (is_eq(p, "parse"))
- return WRAP_FUNCTOR(parse_command);
+ return WRAP_FUNCTOR(parse_command);
else if (is_eq(p, "period"))
- return WRAP_FUNCTOR(period_command);
+ return WRAP_FUNCTOR(period_command);
break;
case 'q':
if (is_eq(p, "query"))
- return WRAP_FUNCTOR(query_command);
+ return WRAP_FUNCTOR(query_command);
break;
case 't':
if (is_eq(p, "template"))
- return WRAP_FUNCTOR(template_command);
+ return WRAP_FUNCTOR(template_command);
break;
}
break;
diff --git a/src/report.h b/src/report.h
index e4eaeaaa..d0a49476 100644
--- a/src/report.h
+++ b/src/report.h
@@ -42,7 +42,6 @@
#ifndef _REPORT_H
#define _REPORT_H
-#include "interactive.h"
#include "expr.h"
#include "query.h"
#include "chain.h"
@@ -107,11 +106,11 @@ class report_t : public scope_t
report_t();
public:
- session_t& session;
+ session_t& session;
output_stream_t output_stream;
#define BUDGET_NO_BUDGET 0x00
-#define BUDGET_BUDGETED 0x01
+#define BUDGET_BUDGETED 0x01
#define BUDGET_UNBUDGETED 0x02
#define BUDGET_WRAP_VALUES 0x04
@@ -126,7 +125,12 @@ public:
output_stream.close();
}
+ virtual string description() {
+ return _("current report");
+ }
+
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);
@@ -135,17 +139,21 @@ 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_top_amount(call_scope_t& val);
+ 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);
value_t fn_strip(call_scope_t& scope);
value_t fn_trim(call_scope_t& scope);
+ value_t fn_format(call_scope_t& scope);
value_t fn_print(call_scope_t& scope);
- value_t scrub(value_t val);
value_t fn_scrub(call_scope_t& scope);
value_t fn_quantity(call_scope_t& scope);
value_t fn_rounded(call_scope_t& scope);
@@ -160,6 +168,7 @@ public:
value_t fn_ansify_if(call_scope_t& scope);
value_t fn_percent(call_scope_t& scope);
value_t fn_price(call_scope_t& scope);
+ value_t fn_commodity(call_scope_t& scope);
value_t fn_lot_date(call_scope_t& scope);
value_t fn_lot_price(call_scope_t& scope);
value_t fn_lot_tag(call_scope_t& scope);
@@ -181,7 +190,7 @@ public:
}
value_t fn_options(call_scope_t&) {
- return value_t(static_cast<scope_t *>(this));
+ return scope_value(this);
}
string report_format(option_t<report_t>& option) {
@@ -203,9 +212,9 @@ public:
keep_details_t what_to_keep() {
bool lots = HANDLED(lots) || HANDLED(lots_actual);
return keep_details_t(lots || HANDLED(lot_prices),
- lots || HANDLED(lot_dates),
- lots || HANDLED(lot_tags),
- HANDLED(lots_actual));
+ lots || HANDLED(lot_dates),
+ lots || HANDLED(lot_tags),
+ HANDLED(lots_actual));
}
void report_options(std::ostream& out)
@@ -257,9 +266,11 @@ public:
HANDLER(forecast_years_).report(out);
HANDLER(format_).report(out);
HANDLER(gain).report(out);
+ HANDLER(generated).report(out);
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);
@@ -289,7 +300,6 @@ public:
HANDLER(price).report(out);
HANDLER(prices_format_).report(out);
HANDLER(pricedb_format_).report(out);
- HANDLER(print_virtual).report(out);
HANDLER(quantity).report(out);
HANDLER(quarterly).report(out);
HANDLER(raw).report(out);
@@ -316,7 +326,6 @@ public:
HANDLER(unrealized_gains_).report(out);
HANDLER(unrealized_losses_).report(out);
HANDLER(unround).report(out);
- HANDLER(unsorted).report(out);
HANDLER(weekly).report(out);
HANDLER(wide).report(out);
HANDLER(yearly).report(out);
@@ -331,17 +340,17 @@ public:
option_t<report_t> * lookup_option(const char * p);
virtual void define(const symbol_t::kind_t kind, const string& name,
- expr_t::ptr_op_t def);
+ expr_t::ptr_op_t def);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
/**
* Option handlers
*/
OPTION__(report_t, abbrev_len_,
- CTOR(report_t, abbrev_len_) { on_with(none, 2L); });
+ CTOR(report_t, abbrev_len_) { on_with(none, 2L); });
OPTION(report_t, account_);
OPTION_(report_t, actual, DO() { // -L
@@ -365,7 +374,7 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION(report_t, amount_data); // -j
@@ -373,16 +382,21 @@ public:
OPTION_(report_t, average, DO() { // -A
parent->HANDLER(display_total_)
- .set_expr(string("--average"), "count>0?(total_expr/count):0");
+ .set_expr(string("--average"), "count>0?(total_expr/count):0");
});
OPTION__(report_t, balance_format_, CTOR(report_t, balance_format_) {
on(none,
- "%(justify(scrub(display_total), 20, 20 + prepend_width, true, color))"
- " %(!options.flat ? depth_spacer : \"\")"
- "%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
- "%$1\n%/"
- "--------------------\n");
+ "%(ansify_if("
+ " justify(scrub(display_total), 20, 20 + prepend_width, true, color),"
+ " bold if should_bold))"
+ " %(!options.flat ? depth_spacer : \"\")"
+ "%-(ansify_if("
+ " ansify_if(partial_account(options.flat), blue if color),"
+ " bold if should_bold))\n%/"
+ "%$1\n%/"
+ "%(prepend_width ? \" \" * prepend_width : \"\")"
+ "--------------------\n");
});
OPTION(report_t, base);
@@ -393,41 +407,54 @@ public:
});
OPTION_(report_t, begin_, DO_(args) { // -b
- date_interval_t interval(args[1].to_string());
- optional<date_t> begin = interval.begin(parent->session.current_year);
+ date_interval_t interval(args.get<string>(1));
+ optional<date_t> begin = interval.begin();
if (! begin)
- throw_(std::invalid_argument,
- _("Could not determine beginning of period '%1'")
- << args[1].to_string());
+ throw_(std::invalid_argument,
+ _("Could not determine beginning of period '%1'")
+ << args.get<string>(1));
string predicate = "date>=[" + to_iso_extended_string(*begin) + "]";
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;
});
OPTION__(report_t, budget_format_, CTOR(report_t, budget_format_) {
on(none,
- "%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))"
- " %(justify(scrub(- get_at(total_expr, 1)), 12, "
- " 12 + 1 + 12, true, color))"
- " %(justify(scrub(get_at(total_expr, 1) + "
- " get_at(total_expr, 0)), 12, "
- " 12 + 1 + 12 + 1 + 12, true, color))"
- " %(ansify_if("
- " justify((get_at(total_expr, 1) ? "
- " scrub((100% * get_at(total_expr, 0)) / "
- " - get_at(total_expr, 1)) : 0), "
- " 5, -1, true, false),"
- " magenta if (color and get_at(total_expr, 1) and "
- " (abs(quantity(get_at(total_expr, 0)) / "
- " quantity(get_at(total_expr, 1))) >= 1))))"
- " %(!options.flat ? depth_spacer : \"\")"
- "%-(ansify_if(partial_account(options.flat), blue if color))\n"
- "%/%$1 %$2 %$3 %$4\n%/"
- "------------ ------------ ------------ -----\n");
+ "%(justify(scrub(get_at(total_expr, 0)), 12, -1, true, color))"
+ " %(justify(-scrub(get_at(total_expr, 1)), 12, "
+ " 12 + 1 + 12, true, color))"
+ " %(justify(scrub(get_at(total_expr, 1) + "
+ " get_at(total_expr, 0)), 12, "
+ " 12 + 1 + 12 + 1 + 12, true, color))"
+ " %(ansify_if("
+ " justify((get_at(total_expr, 1) ? "
+ " (100% * scrub(get_at(total_expr, 0))) / "
+ " -scrub(get_at(total_expr, 1)) : 0), "
+ " 5, -1, true, false),"
+ " magenta if (color and get_at(total_expr, 1) and "
+ " (abs(quantity(scrub(get_at(total_expr, 0))) / "
+ " quantity(scrub(get_at(total_expr, 1)))) >= 1))))"
+ " %(!options.flat ? depth_spacer : \"\")"
+ "%-(ansify_if(partial_account(options.flat), blue if color))\n"
+ "%/%$1 %$2 %$3 %$4\n%/"
+ "%(prepend_width ? \" \" * prepend_width : \"\")"
+ "------------ ------------ ------------ -----\n");
});
OPTION(report_t, by_payee); // -P
@@ -438,14 +465,15 @@ public:
OPTION__(report_t, cleared_format_, CTOR(report_t, cleared_format_) {
on(none,
- "%(justify(scrub(get_at(total_expr, 0)), 16, 16 + prepend_width, "
- " true, color)) %(justify(scrub(get_at(total_expr, 1)), 18, "
- " 36 + prepend_width, true, color))"
- " %(latest_cleared ? format_date(latest_cleared) : \" \")"
- " %(!options.flat ? depth_spacer : \"\")"
- "%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
- "%$1 %$2 %$3\n%/"
- "---------------- ---------------- ---------\n");
+ "%(justify(scrub(get_at(total_expr, 0)), 16, 16 + prepend_width, "
+ " true, color)) %(justify(scrub(get_at(total_expr, 1)), 18, "
+ " 36 + prepend_width, true, color))"
+ " %(latest_cleared ? format_date(latest_cleared) : \" \")"
+ " %(!options.flat ? depth_spacer : \"\")"
+ "%-(ansify_if(partial_account(options.flat), blue if color))\n%/"
+ "%$1 %$2 %$3\n%/"
+ "%(prepend_width ? \" \" * prepend_width : \"\")"
+ "---------------- ---------------- ---------\n");
});
OPTION(report_t, color);
@@ -465,14 +493,14 @@ public:
OPTION__(report_t, csv_format_, CTOR(report_t, csv_format_) {
on(none,
- "%(quoted(date)),"
- "%(quoted(code)),"
- "%(quoted(payee)),"
- "%(quoted(display_account)),"
- "%(quoted(commodity)),"
- "%(quoted(quantity(scrub(display_amount)))),"
- "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),"
- "%(quoted(join(note | xact.note)))\n");
+ "%(quoted(date)),"
+ "%(quoted(code)),"
+ "%(quoted(payee)),"
+ "%(quoted(display_account)),"
+ "%(quoted(commodity)),"
+ "%(quoted(quantity(scrub(display_amount)))),"
+ "%(quoted(cleared ? \"*\" : (pending ? \"!\" : \"\"))),"
+ "%(quoted(join(note | xact.note)))\n");
});
OPTION_(report_t, current, DO() { // -c
@@ -487,15 +515,14 @@ public:
OPTION(report_t, date_format_);
OPTION(report_t, datetime_format_);
- OPTION_(report_t, depth_, DO_(scope) {
- interactive_t args(scope, "sl");
- parent->HANDLER(display_).on(string("--depth"),
- string("depth<=") + args.get<string>(1));
+ OPTION_(report_t, depth_, DO_(args) {
+ parent->HANDLER(display_)
+ .on(string("--depth"), string("depth<=") + args.get<string>(1));
});
OPTION_(report_t, deviation, DO() {
parent->HANDLER(display_total_)
- .set_expr(string("--deviation"), "amount_expr-total_expr/count");
+ .set_expr(string("--deviation"), "amount_expr-total_expr/count");
});
OPTION__
@@ -506,8 +533,8 @@ public:
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
- string_value(string("(") + str() + ")&(" +
- text.as_string() + ")"));
+ string_value(string("(") + str() + ")&(" +
+ text.as_string() + ")"));
});
OPTION__
@@ -521,7 +548,7 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION__
@@ -535,7 +562,7 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION(report_t, dow);
@@ -543,14 +570,15 @@ public:
OPTION(report_t, empty); // -E
OPTION_(report_t, end_, DO_(args) { // -e
- date_interval_t interval(args[1].to_string());
+ date_interval_t interval(args.get<string>(1));
// Use begin() here so that if the user says --end=2008, we end on
- // 2008/01/01 instead of 2009/01/01 (which is what end() would return).
- optional<date_t> end = interval.begin(parent->session.current_year);
+ // 2008/01/01 instead of 2009/01/01 (which is what end() would
+ // return).
+ optional<date_t> end = interval.begin();
if (! end)
- throw_(std::invalid_argument,
- _("Could not determine end of period '%1'")
- << args[1].to_string());
+ throw_(std::invalid_argument,
+ _("Could not determine end of period '%1'")
+ << args.get<string>(1));
string predicate = "date<[" + to_iso_extended_string(*end) + "]";
parent->HANDLER(limit_).on(string("--end"), predicate);
@@ -562,7 +590,7 @@ public:
OPTION(report_t, exact);
OPTION_(report_t, exchange_, DO_(args) { // -X
- on_with(args[0].as_string(), args[1]);
+ on_with(args.get<string>(0), args[1]);
call_scope_t no_args(*parent);
no_args.push_back(args[0]);
parent->HANDLER(market).parent = parent;
@@ -582,23 +610,25 @@ public:
// Since we are displaying the amounts of revalued postings, they
// will end up being composite totals, and hence a pair of pairs.
parent->HANDLER(display_amount_)
- .set_expr(string("--gain"),
- "use_direct_amount ? amount :"
- " (is_seq(get_at(amount_expr, 0)) ?"
- " get_at(get_at(amount_expr, 0), 0) :"
- " market(get_at(amount_expr, 0), date, exchange)"
- " - get_at(amount_expr, 1))");
+ .set_expr(string("--gain"),
+ "use_direct_amount ? amount :"
+ " (is_seq(get_at(amount_expr, 0)) ?"
+ " get_at(get_at(amount_expr, 0), 0) :"
+ " market(get_at(amount_expr, 0), value_date, exchange)"
+ " - get_at(amount_expr, 1))");
parent->HANDLER(revalued_total_)
- .set_expr(string("--gain"),
- "(market(get_at(total_expr, 0), date, exchange), "
- "get_at(total_expr, 1))");
+ .set_expr(string("--gain"),
+ "(market(get_at(total_expr, 0), value_date, exchange), "
+ "get_at(total_expr, 1))");
parent->HANDLER(display_total_)
- .set_expr(string("--gain"),
- "use_direct_amount ? total_expr :"
- " market(get_at(total_expr, 0), date, exchange)"
- " - get_at(total_expr, 1)");
+ .set_expr(string("--gain"),
+ "use_direct_amount ? total_expr :"
+ " market(get_at(total_expr, 0), value_date, exchange)"
+ " - get_at(total_expr, 1)");
});
+ OPTION(report_t, generated);
+
OPTION__
(report_t, group_by_,
expr_t expr;
@@ -608,7 +638,7 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION__(report_t, group_title_format_, CTOR(report_t, group_title_format_) {
@@ -616,6 +646,7 @@ public:
});
OPTION(report_t, head_);
+ OPTION(report_t, inject_);
OPTION_(report_t, invert, DO() {
parent->HANDLER(amount_).set_expr(string("--invert"), "-amount");
@@ -629,8 +660,8 @@ public:
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
- string_value(string("(") + str() + ")&(" +
- text.as_string() + ")"));
+ string_value(string("(") + str() + ")&(" +
+ text.as_string() + ")"));
});
OPTION(report_t, lot_dates);
@@ -642,9 +673,11 @@ public:
OPTION_(report_t, market, DO() { // -V
parent->HANDLER(revalued).on_only(string("--market"));
parent->HANDLER(display_amount_)
- .set_expr(string("--market"), "market(amount_expr, date, exchange)");
+ .set_expr(string("--market"),
+ "market(amount_expr, value_date, exchange)");
parent->HANDLER(display_total_)
- .set_expr(string("--market"), "market(total_expr, date, exchange)");
+ .set_expr(string("--market"),
+ "market(total_expr, value_date, exchange)");
});
OPTION(report_t, meta_);
@@ -662,14 +695,13 @@ public:
OPTION(report_t, no_total);
OPTION_(report_t, now_, DO_(args) {
- date_interval_t interval(args[1].to_string());
- optional<date_t> begin = interval.begin(parent->session.current_year);
+ date_interval_t interval(args.get<string>(1));
+ optional<date_t> begin = interval.begin();
if (! begin)
- throw_(std::invalid_argument,
- _("Could not determine beginning of period '%1'")
- << args[1].to_string());
+ throw_(std::invalid_argument,
+ _("Could not determine beginning of period '%1'")
+ << args.get<string>(1));
ledger::epoch = parent->terminus = datetime_t(*begin);
- parent->session.current_year = ledger::epoch->date().year();
});
OPTION__
@@ -680,8 +712,8 @@ public:
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
- string_value(string("(") + str() + ")&(" +
- text.as_string() + ")"));
+ string_value(string("(") + str() + ")&(" +
+ text.as_string() + ")"));
});
OPTION(report_t, output_); // -o
@@ -693,20 +725,20 @@ public:
if (! std::getenv("PAGER") && isatty(STDOUT_FILENO)) {
bool have_less = false;
if (exists(path("/opt/local/bin/less")) ||
- exists(path("/usr/local/bin/less")) ||
- exists(path("/usr/bin/less")))
- have_less = true;
+ exists(path("/usr/local/bin/less")) ||
+ exists(path("/usr/bin/less")))
+ have_less = true;
if (have_less) {
- on(none, "less");
- setenv("LESS", "-FRSX", 0); // don't overwrite
+ on(none, "less");
+ setenv("LESS", "-FRSX", 0); // don't overwrite
}
}
}
virtual void on_with(const optional<string>& whence, const value_t& text) {
string cmd(text.to_string());
if (cmd == "" || cmd == "false" || cmd == "off" ||
- cmd == "none" || cmd == "no" || cmd == "disable")
+ cmd == "none" || cmd == "no" || cmd == "disable")
option_t<report_t>::off();
else
option_t<report_t>::on_with(whence, text);
@@ -719,7 +751,7 @@ public:
virtual void on_with(const optional<string>& whence, const value_t& text) {
string cmd(text.to_string());
if (cmd == "" || cmd == "false" || cmd == "off" ||
- cmd == "none" || cmd == "no" || cmd == "disable")
+ cmd == "none" || cmd == "no" || cmd == "disable")
option_t<report_t>::off();
else
option_t<report_t>::on_with(whence, text);
@@ -734,8 +766,9 @@ public:
OPTION_(report_t, percent, DO() { // -%
parent->HANDLER(total_)
- .set_expr(string("--percent"),
- "((is_account&parent&parent.total)?percent(total, parent.total):0");
+ .set_expr(string("--percent"),
+ "((is_account&parent&parent.total)?"
+ " percent(scrub(total), scrub(parent.total)):0");
});
OPTION__
@@ -746,46 +779,44 @@ public:
option_t<report_t>::on_with(whence, text);
else
option_t<report_t>::on_with(whence,
- string_value(text.as_string() + " " + str()));
+ string_value(text.as_string() + " " + str()));
});
OPTION(report_t, pivot_);
OPTION__(report_t, plot_amount_format_, CTOR(report_t, plot_amount_format_) {
on(none,
- "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n");
+ "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_amount)))\n");
});
OPTION__(report_t, plot_total_format_, CTOR(report_t, plot_total_format_) {
on(none,
- "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n");
+ "%(format_date(date, \"%Y-%m-%d\")) %(quantity(scrub(display_total)))\n");
});
OPTION(report_t, prepend_format_);
OPTION_(report_t, prepend_width_, DO_(args) {
- value = args[1].to_long();
+ value = args.get<long>(1);
});
OPTION_(report_t, price, DO() { // -I
parent->HANDLER(display_amount_)
- .set_expr(string("--price"), "price(amount_expr)");
+ .set_expr(string("--price"), "price(amount_expr)");
parent->HANDLER(display_total_)
- .set_expr(string("--price"), "price(total_expr)");
+ .set_expr(string("--price"), "price(total_expr)");
});
OPTION__(report_t, prices_format_, CTOR(report_t, prices_format_) {
on(none,
- "%(date) %-8(display_account) %(justify(scrub(display_amount), 12, "
- " 2 + 9 + 8 + 12, true, color))\n");
+ "%(date) %-8(display_account) %(justify(scrub(display_amount), 12, "
+ " 2 + 9 + 8 + 12, true, color))\n");
});
OPTION__(report_t, pricedb_format_, CTOR(report_t, pricedb_format_) {
on(none,
- "P %(datetime) %(display_account) %(scrub(display_amount))\n");
+ "P %(datetime) %(display_account) %(scrub(display_amount))\n");
});
- OPTION(report_t, print_virtual);
-
OPTION_(report_t, quantity, DO() { // -O
parent->HANDLER(revalued).off();
parent->HANDLER(amount_).set_expr(string("--quantity"), "amount");
@@ -804,20 +835,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
@@ -838,13 +886,13 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION(report_t, seed_);
OPTION_(report_t, sort_, DO_(args) { // -S
- on_with(args[0].as_string(), args[1]);
+ on_with(args.get<string>(0), args[1]);
parent->HANDLER(sort_xacts_).off();
parent->HANDLER(sort_all_).off();
});
@@ -874,22 +922,22 @@ public:
on(whence, str);
}
DO_(args) {
- set_expr(args[0].to_string(), args[1].to_string());
+ set_expr(args.get<string>(0), args.get<string>(1));
});
OPTION(report_t, total_data); // -J
OPTION_(report_t, truncate_, DO_(args) {
- string style(args[1].to_string());
+ string style(args.get<string>(1));
if (style == "leading")
- format_t::default_style = format_t::TRUNCATE_LEADING;
+ format_t::default_style = format_t::TRUNCATE_LEADING;
else if (style == "middle")
- format_t::default_style = format_t::TRUNCATE_MIDDLE;
+ format_t::default_style = format_t::TRUNCATE_MIDDLE;
else if (style == "trailing")
- format_t::default_style = format_t::TRUNCATE_TRAILING;
+ format_t::default_style = format_t::TRUNCATE_TRAILING;
else
- throw_(std::invalid_argument,
- _("Unrecognized truncation style: '%1'") << style);
+ throw_(std::invalid_argument,
+ _("Unrecognized truncation style: '%1'") << style);
format_t::default_style_changed = true;
});
@@ -908,13 +956,11 @@ public:
OPTION_(report_t, unround, DO() {
parent->HANDLER(display_amount_)
- .set_expr(string("--unround"), "unrounded(amount_expr)");
+ .set_expr(string("--unround"), "unrounded(amount_expr)");
parent->HANDLER(display_total_)
- .set_expr(string("--unround"), "unrounded(total_expr)");
+ .set_expr(string("--unround"), "unrounded(total_expr)");
});
- OPTION(report_t, unsorted);
-
OPTION_(report_t, weekly, DO() { // -W
parent->HANDLER(period_).on(string("--weekly"), "weekly");
});
@@ -928,36 +974,36 @@ public:
});
OPTION__(report_t, meta_width_,
- bool specified;
- CTOR(report_t, meta_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, meta_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, date_width_,
- bool specified;
- CTOR(report_t, date_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, date_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, payee_width_,
- bool specified;
- CTOR(report_t, payee_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, payee_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, account_width_,
- bool specified;
- CTOR(report_t, account_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, account_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, amount_width_,
- bool specified;
- CTOR(report_t, amount_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, amount_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
OPTION__(report_t, total_width_,
- bool specified;
- CTOR(report_t, total_width_) { specified = false; }
- DO_(args) { value = args[1].to_long(); specified = true; });
+ bool specified;
+ CTOR(report_t, total_width_) { specified = false; }
+ DO_(args) { value = args.get<long>(1); specified = true; });
};
template <class Type = post_t,
- class handler_ptr = post_handler_ptr,
- void (report_t::*report_method)(handler_ptr) =
- &report_t::posts_report>
+ class handler_ptr = post_handler_ptr,
+ void (report_t::*report_method)(handler_ptr) =
+ &report_t::posts_report>
class reporter
{
shared_ptr<item_handler<Type> > handler;
@@ -967,7 +1013,7 @@ class reporter
public:
reporter(item_handler<Type> * _handler,
- report_t& _report, const string& _whence)
+ report_t& _report, const string& _whence)
: handler(_handler), report(_report), whence(_whence) {}
value_t operator()(call_scope_t& args)
diff --git a/src/scope.cc b/src/scope.cc
index 72cf4ad3..e18b5a0a 100644
--- a/src/scope.cc
+++ b/src/scope.cc
@@ -38,7 +38,7 @@ namespace ledger {
scope_t * scope_t::default_scope = NULL;
void symbol_scope_t::define(const symbol_t::kind_t kind,
- const string& name, expr_t::ptr_op_t def)
+ const string& name, expr_t::ptr_op_t def)
{
DEBUG("scope.symbols", "Defining '" << name << "' = " << def);
@@ -53,15 +53,15 @@ void symbol_scope_t::define(const symbol_t::kind_t kind,
symbols->erase(i);
result = symbols->insert(symbol_map::value_type(symbol_t(kind, name, def),
- def));
+ def));
if (! result.second)
throw_(compile_error,
- _("Redefinition of '%1' in the same scope") << name);
+ _("Redefinition of '%1' in the same scope") << name);
}
}
expr_t::ptr_op_t symbol_scope_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (symbols) {
symbol_map::const_iterator i = symbols->find(symbol_t(kind, name));
@@ -71,4 +71,23 @@ expr_t::ptr_op_t symbol_scope_t::lookup(const symbol_t::kind_t kind,
return child_scope_t::lookup(kind, name);
}
+value_t& call_scope_t::resolve(const std::size_t index,
+ value_t::type_t context,
+ const bool required)
+{
+ if (index >= args.size())
+ throw_(calc_error, _("Too few arguments to function"));
+
+ value_t& value(args[index]);
+ if (value.is_any()) {
+ context_scope_t scope(*this, context, required);
+ value = as_expr(value)->calc(scope, locus, depth);
+ if (required && ! value.is_type(context))
+ throw_(calc_error, _("Expected %1 for argument %2, but received %3")
+ << value.label(context) << index
+ << value.label());
+ }
+ return value;
+}
+
} // namespace ledger
diff --git a/src/scope.h b/src/scope.h
index 1e6f24a1..31b10f6b 100644
--- a/src/scope.h
+++ b/src/scope.h
@@ -58,8 +58,8 @@ struct symbol_t
FORMAT
};
- kind_t kind;
- string name;
+ kind_t kind;
+ string name;
expr_t::ptr_op_t definition;
symbol_t() : kind(UNKNOWN), name(""), definition(NULL) {
@@ -109,10 +109,19 @@ public:
TRACE_DTOR(scope_t);
}
+ virtual string description() = 0;
+
virtual void define(const symbol_t::kind_t, const string&,
- expr_t::ptr_op_t) {}
+ expr_t::ptr_op_t) {}
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name) = 0;
+ const string& name) = 0;
+
+ virtual value_t::type_t type_context() const {
+ return value_t::VOID;
+ }
+ virtual bool type_required() const {
+ return false;
+ }
#if defined(HAVE_BOOST_SERIALIZATION)
private:
@@ -142,13 +151,13 @@ public:
}
virtual void define(const symbol_t::kind_t kind,
- const string& name, expr_t::ptr_op_t def) {
+ const string& name, expr_t::ptr_op_t def) {
if (parent)
parent->define(kind, name, def);
}
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name) {
+ const string& name) {
if (parent)
return parent->lookup(kind, name);
return NULL;
@@ -168,6 +177,80 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
+class bind_scope_t : public child_scope_t
+{
+ bind_scope_t();
+
+public:
+ scope_t& grandchild;
+
+ explicit bind_scope_t(scope_t& _parent,
+ scope_t& _grandchild)
+ : child_scope_t(_parent), grandchild(_grandchild) {
+ TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&");
+ }
+ virtual ~bind_scope_t() {
+ TRACE_DTOR(bind_scope_t);
+ }
+
+ virtual string description() {
+ return grandchild.description();
+ }
+
+ virtual void define(const symbol_t::kind_t kind, const string& name,
+ expr_t::ptr_op_t def) {
+ parent->define(kind, name, def);
+ grandchild.define(kind, name, def);
+ }
+
+ virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
+ const string& name) {
+ if (expr_t::ptr_op_t def = grandchild.lookup(kind, name))
+ return def;
+ return child_scope_t::lookup(kind, name);
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+private:
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & grandchild;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+};
+
+template <typename T>
+T * search_scope(scope_t * ptr)
+{
+ if (T * sought = dynamic_cast<T *>(ptr))
+ return sought;
+
+ if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) {
+ if (T * sought = search_scope<T>(&scope->grandchild))
+ return sought;
+ return search_scope<T>(scope->parent);
+ }
+ else if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr)) {
+ return search_scope<T>(scope->parent);
+ }
+ return NULL;
+}
+
+template <typename T>
+inline T& find_scope(child_scope_t& scope, bool skip_this = true)
+{
+ if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope))
+ return *sought;
+
+ throw_(std::runtime_error, _("Could not find scope"));
+ return reinterpret_cast<T&>(scope); // never executed
+}
+
class symbol_scope_t : public child_scope_t
{
typedef std::map<symbol_t, expr_t::ptr_op_t> symbol_map;
@@ -185,11 +268,21 @@ public:
TRACE_DTOR(symbol_scope_t);
}
+ virtual string description() {
+ if (parent)
+ return parent->description();
+#if !defined(NO_ASSERTS)
+ else
+ assert(false);
+#endif
+ return empty_string;
+ }
+
virtual void define(const symbol_t::kind_t kind, const string& name,
- expr_t::ptr_op_t def);
+ expr_t::ptr_op_t def);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
@@ -205,31 +298,117 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
-class call_scope_t : public child_scope_t
+class context_scope_t : public child_scope_t
{
- value_t args;
+ value_t::type_t value_type_context;
+ bool required;
public:
- explicit call_scope_t(scope_t& _parent) : child_scope_t(_parent) {
- TRACE_CTOR(call_scope_t, "scope_t&");
+ explicit context_scope_t(scope_t& _parent,
+ value_t::type_t _type_context = value_t::VOID,
+ const bool _required = true)
+ : child_scope_t(_parent), value_type_context(_type_context),
+ required(_required) {
+ TRACE_CTOR(context_scope_t, "scope_t&, value_t::type_t, bool");
+ }
+ virtual ~context_scope_t() {
+ TRACE_DTOR(context_scope_t);
+ }
+
+ virtual string description() {
+ return parent->description();
+ }
+
+ virtual value_t::type_t type_context() const {
+ return value_type_context;
+ }
+ virtual bool type_required() const {
+ return required;
+ }
+
+#if defined(HAVE_BOOST_SERIALIZATION)
+protected:
+ explicit context_scope_t() {
+ TRACE_CTOR(context_scope_t, "");
+ }
+
+ /** Serialization. */
+
+ friend class boost::serialization::access;
+
+ template<class Archive>
+ void serialize(Archive& ar, const unsigned int /* version */) {
+ ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & value_type_context;
+ ar & required;
+ }
+#endif // HAVE_BOOST_SERIALIZATION
+};
+
+class call_scope_t : public context_scope_t
+{
+ value_t args;
+ mutable void * ptr;
+
+ value_t& resolve(const std::size_t index,
+ value_t::type_t context = value_t::VOID,
+ const bool required = false);
+
+public:
+ expr_t::ptr_op_t * locus;
+ const int depth;
+
+ explicit call_scope_t(scope_t& _parent,
+ expr_t::ptr_op_t * _locus = NULL,
+ const int _depth = 0)
+ : context_scope_t(_parent, _parent.type_context(),
+ _parent.type_required()),
+ ptr(NULL), locus(_locus), depth(_depth) {
+ TRACE_CTOR(call_scope_t,
+ "scope_t&, value_t::type_t, bool, expr_t::ptr_op_t *, int");
}
virtual ~call_scope_t() {
TRACE_DTOR(call_scope_t);
}
+ virtual string description() {
+ return context_scope_t::description();
+ }
+
void set_args(const value_t& _args) {
args = _args;
}
value_t& value() {
+ // Make sure that all of the arguments have been resolved.
+ for (std::size_t index = 0; index < args.size(); index++)
+ resolve(index);
return args;
}
value_t& operator[](const std::size_t index) {
- return args[index];
+ return resolve(index);
}
+#if 0
const value_t& operator[](const std::size_t index) const {
return args[index];
}
+#endif
+
+ bool has(std::size_t index) {
+ return index < args.size() && ! (*this)[index].is_null();
+ }
+ template <typename T>
+ bool has(std::size_t index);
+ template <typename T>
+ T get(std::size_t index, bool convert = true);
+
+ template <typename T>
+ T& context() {
+ if (ptr == NULL)
+ ptr = &find_scope<T>(*this);
+ assert(ptr != NULL);
+ return *static_cast<T *>(ptr);
+ }
void push_front(const value_t& val) {
args.push_front(val);
@@ -267,7 +446,7 @@ public:
}
#if defined(HAVE_BOOST_SERIALIZATION)
-private:
+protected:
explicit call_scope_t() {
TRACE_CTOR(call_scope_t, "");
}
@@ -278,83 +457,179 @@ private:
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */) {
- ar & boost::serialization::base_object<child_scope_t>(*this);
+ ar & boost::serialization::base_object<context_scope_t>(*this);
ar & args;
+ //ar & ptr;
}
#endif // HAVE_BOOST_SERIALIZATION
};
-class bind_scope_t : public child_scope_t
-{
- bind_scope_t();
-
-public:
- scope_t& grandchild;
-
- explicit bind_scope_t(scope_t& _parent,
- scope_t& _grandchild)
- : child_scope_t(_parent), grandchild(_grandchild) {
- TRACE_CTOR(bind_scope_t, "scope_t&, scope_t&");
+template <>
+inline bool call_scope_t::has<bool>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::BOOLEAN, false);
+ return ! args[index].is_null();
}
- virtual ~bind_scope_t() {
- TRACE_DTOR(bind_scope_t);
+ return false;
+}
+template <>
+inline bool call_scope_t::has<int>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::INTEGER, false);
+ return ! args[index].is_null();
}
-
- virtual void define(const symbol_t::kind_t kind, const string& name,
- expr_t::ptr_op_t def) {
- parent->define(kind, name, def);
- grandchild.define(kind, name, def);
+ return false;
+}
+template <>
+inline bool call_scope_t::has<long>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::INTEGER, false);
+ return ! args[index].is_null();
}
-
- virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name) {
- if (expr_t::ptr_op_t def = grandchild.lookup(kind, name))
- return def;
- return child_scope_t::lookup(kind, name);
+ return false;
+}
+template <>
+inline bool call_scope_t::has<amount_t>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::AMOUNT, false);
+ return ! args[index].is_null();
}
-
-#if defined(HAVE_BOOST_SERIALIZATION)
-private:
- /** Serialization. */
-
- friend class boost::serialization::access;
-
- template<class Archive>
- void serialize(Archive& ar, const unsigned int /* version */) {
- ar & boost::serialization::base_object<child_scope_t>(*this);
- ar & grandchild;
+ return false;
+}
+template <>
+inline bool call_scope_t::has<balance_t>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::BALANCE, false);
+ return ! args[index].is_null();
}
-#endif // HAVE_BOOST_SERIALIZATION
-};
-
-template <typename T>
-T * search_scope(scope_t * ptr)
-{
- if (T * sought = dynamic_cast<T *>(ptr))
- return sought;
-
- if (bind_scope_t * scope = dynamic_cast<bind_scope_t *>(ptr)) {
- if (T * sought = search_scope<T>(&scope->grandchild))
- return sought;
- return search_scope<T>(scope->parent);
+ return false;
+}
+template <>
+inline bool call_scope_t::has<string>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::STRING, false);
+ return ! args[index].is_null();
}
- else if (child_scope_t * scope = dynamic_cast<child_scope_t *>(ptr)) {
- return search_scope<T>(scope->parent);
+ return false;
+}
+template <>
+inline bool call_scope_t::has<date_t>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::DATE, false);
+ return ! args[index].is_null();
}
- return NULL;
+ return false;
+}
+template <>
+inline bool call_scope_t::has<datetime_t>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::DATETIME, false);
+ return ! args[index].is_null();
+ }
+ return false;
+}
+template <>
+inline bool call_scope_t::has<scope_t *>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::SCOPE, false);
+ return ! args[index].is_null();
+ }
+ return false;
+}
+template <>
+inline bool call_scope_t::has<expr_t::ptr_op_t>(std::size_t index) {
+ if (index < args.size()) {
+ resolve(index, value_t::ANY, false);
+ return ! args[index].is_null();
+ }
+ return false;
}
-template <typename T>
-inline T& find_scope(child_scope_t& scope, bool skip_this = true)
-{
- if (T * sought = search_scope<T>(skip_this ? scope.parent : &scope))
- return *sought;
+template <>
+inline bool call_scope_t::get<bool>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::BOOLEAN, false).to_boolean();
+ else
+ return resolve(index, value_t::BOOLEAN).as_boolean();
+}
+template <>
+inline int call_scope_t::get<int>(std::size_t index, bool) {
+ return resolve(index, value_t::INTEGER, false).to_int();
+}
+template <>
+inline long call_scope_t::get<long>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::INTEGER, false).to_long();
+ else
+ return resolve(index, value_t::INTEGER).as_long();
+}
+template <>
+inline amount_t call_scope_t::get<amount_t>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::AMOUNT, false).to_amount();
+ else
+ return resolve(index, value_t::AMOUNT).as_amount();
+}
+template <>
+inline balance_t call_scope_t::get<balance_t>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::BALANCE, false).to_balance();
+ else
+ return resolve(index, value_t::BALANCE).as_balance();
+}
+template <>
+inline string call_scope_t::get<string>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::STRING, false).to_string();
+ else
+ return resolve(index, value_t::STRING).as_string();
+}
+template <>
+inline mask_t call_scope_t::get<mask_t>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::MASK, false).to_mask();
+ else
+ return resolve(index, value_t::MASK).as_mask();
+}
+template <>
+inline date_t call_scope_t::get<date_t>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::DATE, false).to_date();
+ else
+ return resolve(index, value_t::DATE).as_date();
+}
+template <>
+inline datetime_t call_scope_t::get<datetime_t>(std::size_t index, bool convert) {
+ if (convert)
+ return resolve(index, value_t::DATETIME, false).to_datetime();
+ else
+ return resolve(index, value_t::DATETIME).as_datetime();
+}
- throw_(std::runtime_error, _("Could not find scope"));
- return reinterpret_cast<T&>(scope); // never executed
+#if 0
+template <>
+inline value_t::sequence_t&
+call_scope_t::get<value_t::sequence_t&>(std::size_t index, bool) {
+ return resolve(index, value_t::SEQUENCE).as_sequence_lval();
+}
+template <>
+inline const value_t::sequence_t&
+call_scope_t::get<const value_t::sequence_t&>(std::size_t index, bool) {
+ return resolve(index, value_t::SEQUENCE).as_sequence();
+}
+#endif
+
+template <>
+inline scope_t * call_scope_t::get<scope_t *>(std::size_t index, bool) {
+ return resolve(index, value_t::SCOPE).as_scope();
+}
+template <>
+inline expr_t::ptr_op_t
+call_scope_t::get<expr_t::ptr_op_t>(std::size_t index, bool) {
+ return args[index].as_any<expr_t::ptr_op_t>();
}
-class value_scope_t : public scope_t
+class value_scope_t : public child_scope_t
{
value_t value;
@@ -363,10 +638,15 @@ class value_scope_t : public scope_t
}
public:
- value_scope_t(const value_t& _value) : value(_value) {}
+ value_scope_t(scope_t& _parent, const value_t& _value)
+ : child_scope_t(_parent), value(_value) {}
+ virtual string description() {
+ return parent->description();
+ }
+
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return NULL;
diff --git a/src/session.cc b/src/session.cc
index f8befde4..96aa98d4 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -48,7 +48,7 @@ void set_session_context(session_t * session)
amount_t::initialize();
amount_t::parse_conversion("1.0m", "60s");
- amount_t::parse_conversion("1.0h", "60m");
+ amount_t::parse_conversion("1.00h", "60m");
value_t::initialize();
}
@@ -60,9 +60,7 @@ void set_session_context(session_t * session)
}
session_t::session_t()
- : flush_on_next_data_file(false),
- current_year(CURRENT_DATE().year()),
- journal(new journal_t)
+ : flush_on_next_data_file(false), journal(new journal_t)
{
TRACE_CTOR(session_t, "");
@@ -105,37 +103,37 @@ std::size_t session_t::read_data(const string& master_account)
cache = archive_t(HANDLED(cache_).str());
if (! (cache &&
- cache->should_load(HANDLER(file_).data_files) &&
- cache->load(*journal.get()))) {
+ cache->should_load(HANDLER(file_).data_files) &&
+ cache->load(*journal.get()))) {
#endif // HAVE_BOOST_SERIALIZATION
if (price_db_path) {
if (exists(*price_db_path)) {
- if (journal->read(*price_db_path) > 0)
- throw_(parse_error, _("Transactions not allowed in price history file"));
+ if (journal->read(*price_db_path) > 0)
+ throw_(parse_error, _("Transactions not allowed in price history file"));
}
}
foreach (const path& pathname, HANDLER(file_).data_files) {
if (pathname == "-") {
- // To avoid problems with stdin and pipes, etc., we read the entire
- // file in beforehand into a memory buffer, and then parcel it out
- // from there.
- std::ostringstream buffer;
-
- while (std::cin.good() && ! std::cin.eof()) {
- char line[8192];
- std::cin.read(line, 8192);
- std::streamsize count = std::cin.gcount();
- buffer.write(line, count);
- }
- buffer.flush();
-
- std::istringstream buf_in(buffer.str());
-
- xact_count += journal->read(buf_in, "/dev/stdin", acct);
- journal->sources.push_back(journal_t::fileinfo_t());
+ // To avoid problems with stdin and pipes, etc., we read the entire
+ // file in beforehand into a memory buffer, and then parcel it out
+ // from there.
+ std::ostringstream buffer;
+
+ while (std::cin.good() && ! std::cin.eof()) {
+ char line[8192];
+ std::cin.read(line, 8192);
+ std::streamsize count = std::cin.gcount();
+ buffer.write(line, count);
+ }
+ buffer.flush();
+
+ std::istringstream buf_in(buffer.str());
+
+ xact_count += journal->read(buf_in, "/dev/stdin", acct);
+ journal->sources.push_back(journal_t::fileinfo_t());
} else {
- xact_count += journal->read(pathname, acct);
+ xact_count += journal->read(pathname, acct);
}
}
@@ -163,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()
@@ -182,6 +182,50 @@ void session_t::close_journal_files()
amount_t::initialize();
}
+value_t session_t::fn_account(call_scope_t& args)
+{
+ if (args[0].is_string())
+ return scope_value(journal->find_account(args.get<string>(0), false));
+ else if (args[0].is_mask())
+ return scope_value(journal->find_account_re(args.get<mask_t>(0).str()));
+ else
+ return NULL_VALUE;
+}
+
+value_t session_t::fn_min(call_scope_t& args)
+{
+ return args[1] < args[0] ? args[1] : args[0];
+}
+value_t session_t::fn_max(call_scope_t& args)
+{
+ return args[1] > args[0] ? args[1] : args[0];
+}
+
+value_t session_t::fn_lot_price(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().price)
+ return *amt.annotation().price;
+ else
+ return NULL_VALUE;
+}
+value_t session_t::fn_lot_date(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().date)
+ return *amt.annotation().date;
+ else
+ return NULL_VALUE;
+}
+value_t session_t::fn_lot_tag(call_scope_t& args)
+{
+ amount_t amt(args.get<amount_t>(1, false));
+ if (amt.has_annotation() && amt.annotation().tag)
+ return string_value(*amt.annotation().tag);
+ else
+ return NULL_VALUE;
+}
+
option_t<session_t> * session_t::lookup_option(const char * p)
{
switch (*p) {
@@ -222,17 +266,44 @@ option_t<session_t> * session_t::lookup_option(const char * p)
}
expr_t::ptr_op_t session_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
+ const char * p = name.c_str();
+
switch (kind) {
case symbol_t::FUNCTION:
+ switch (*p) {
+ case 'a':
+ if (is_eq(p, "account"))
+ return MAKE_FUNCTOR(session_t::fn_account);
+ break;
+
+ case 'l':
+ if (is_eq(p, "lot_price"))
+ return MAKE_FUNCTOR(session_t::fn_lot_price);
+ else if (is_eq(p, "lot_date"))
+ return MAKE_FUNCTOR(session_t::fn_lot_date);
+ else if (is_eq(p, "lot_tag"))
+ return MAKE_FUNCTOR(session_t::fn_lot_tag);
+ break;
+
+ case 'm':
+ if (is_eq(p, "min"))
+ return MAKE_FUNCTOR(session_t::fn_min);
+ else if (is_eq(p, "max"))
+ return MAKE_FUNCTOR(session_t::fn_max);
+ break;
+
+ default:
+ break;
+ }
// Check if they are trying to access an option's setting or value.
- if (option_t<session_t> * handler = lookup_option(name.c_str()))
+ if (option_t<session_t> * handler = lookup_option(p))
return MAKE_OPT_FUNCTOR(session_t, handler);
break;
case symbol_t::OPTION:
- if (option_t<session_t> * handler = lookup_option(name.c_str()))
+ if (option_t<session_t> * handler = lookup_option(p))
return MAKE_OPT_HANDLER(session_t, handler);
break;
diff --git a/src/session.h b/src/session.h
index 3916b964..b8fd52f2 100644
--- a/src/session.h
+++ b/src/session.h
@@ -42,7 +42,6 @@
#ifndef _SESSION_H
#define _SESSION_H
-#include "interactive.h"
#include "account.h"
#include "journal.h"
#include "option.h"
@@ -57,8 +56,7 @@ class session_t : public symbol_scope_t
friend void set_session_context(session_t * session);
public:
- bool flush_on_next_data_file;
- date_t::year_type current_year;
+ bool flush_on_next_data_file;
std::auto_ptr<journal_t> journal;
explicit session_t();
@@ -66,6 +64,10 @@ public:
TRACE_DTOR(session_t);
}
+ virtual string description() {
+ return _("current session");
+ }
+
void set_flush_on_next_data_file(const bool truth) {
flush_on_next_data_file = truth;
}
@@ -75,6 +77,13 @@ public:
void read_journal_files();
void close_journal_files();
+ value_t fn_account(call_scope_t& scope);
+ value_t fn_min(call_scope_t& scope);
+ value_t fn_max(call_scope_t& scope);
+ value_t fn_lot_price(call_scope_t& scope);
+ value_t fn_lot_date(call_scope_t& scope);
+ value_t fn_lot_tag(call_scope_t& scope);
+
void report_options(std::ostream& out)
{
HANDLER(cache_).report(out);
@@ -91,7 +100,7 @@ public:
option_t<session_t> * lookup_option(const char * p);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
/**
* Option handlers
@@ -108,7 +117,7 @@ public:
(session_t, price_exp_, // -Z
CTOR(session_t, price_exp_) { value = 24L * 3600L; }
DO_(args) {
- value = args[1].to_long() * 60L;
+ value = args.get<long>(1) * 60L;
});
OPTION__
@@ -121,13 +130,13 @@ public:
data_files.clear();
parent->flush_on_next_data_file = false;
}
- data_files.push_back(args[1].as_string());
+ data_files.push_back(args.get<string>(1));
});
OPTION_(session_t, input_date_format_, DO_(args) {
// This changes static variables inside times.h, which affects the basic
// date parser.
- set_input_date_format(args[1].as_string().c_str());
+ set_input_date_format(args.get<string>(1).c_str());
});
OPTION(session_t, master_account_);
diff --git a/src/stats.cc b/src/stats.cc
index 86a8338d..172971aa 100644
--- a/src/stats.cc
+++ b/src/stats.cc
@@ -58,11 +58,11 @@ value_t report_statistics(call_scope_t& args)
{
straccstream accum;
out << ACCUM(accum << _("Time period: %1 to %2 (%3 days)")
- << format_date(statistics.earliest_post)
- << format_date(statistics.latest_post)
- << (statistics.latest_post -
- statistics.earliest_post).days())
- << std::endl << std::endl;
+ << format_date(statistics.earliest_post)
+ << format_date(statistics.latest_post)
+ << (statistics.latest_post -
+ statistics.earliest_post).days())
+ << std::endl << std::endl;
}
out << _(" Files these postings came from:") << std::endl;
@@ -89,12 +89,12 @@ value_t report_statistics(call_scope_t& args)
out << " (";
out.precision(2);
out << (double((statistics.latest_post - statistics.earliest_post).days()) /
- double(statistics.posts_count)) << _(" per day)") << std::endl;
+ double(statistics.posts_count)) << _(" per day)") << std::endl;
out << _(" Uncleared postings: ");
out.width(6);
out << (statistics.posts_count -
- statistics.posts_cleared_count) << std::endl;
+ statistics.posts_cleared_count) << std::endl;
out << std::endl;
diff --git a/src/stream.cc b/src/stream.cc
index 272d4f1c..5d4cf5e0 100644
--- a/src/stream.cc
+++ b/src/stream.cc
@@ -63,6 +63,7 @@ namespace {
*/
int do_fork(std::ostream ** os, const path& pager_path)
{
+#ifndef WIN32
int pfd[2];
int status = pipe(pfd);
@@ -73,11 +74,11 @@ namespace {
if (status < 0) {
throw std::logic_error(_("Failed to fork child process"));
}
- else if (status == 0) { // child
+ else if (status == 0) { // child
// Duplicate pipe's reading end into stdin
status = dup2(pfd[0], STDIN_FILENO);
if (status == -1)
- perror("dup2");
+ perror("dup2");
// Close unuseful file descriptors: the pipe's writing and reading
// ends (the latter is not needed anymore, after the duplication).
@@ -98,17 +99,24 @@ namespace {
perror((std::string("execlp: ") + pager_path.string()).c_str());
exit(1);
}
- else { // parent
+ else { // parent
close(pfd[0]);
typedef iostreams::stream<iostreams::file_descriptor_sink> fdstream;
+#if BOOST_VERSION >= 104400
+ *os = new fdstream(pfd[1], iostreams::never_close_handle);
+#else // BOOST_VERSION >= 104400
*os = new fdstream(pfd[1]);
+#endif // BOOST_VERSION >= 104400
}
return pfd[1];
+#else
+ return 0;
+#endif
}
}
void output_stream_t::initialize(const optional<path>& output_file,
- const optional<path>& pager_path)
+ const optional<path>& pager_path)
{
if (output_file && *output_file != "-")
os = new ofstream(*output_file);
@@ -120,6 +128,7 @@ void output_stream_t::initialize(const optional<path>& output_file,
void output_stream_t::close()
{
+#ifndef WIN32
if (os != &std::cout) {
checked_delete(os);
os = &std::cout;
@@ -134,6 +143,7 @@ void output_stream_t::close()
if (! WIFEXITED(status) || WEXITSTATUS(status) != 0)
throw std::logic_error(_("Error in the pager"));
}
+#endif
}
} // namespace ledger
diff --git a/src/stream.h b/src/stream.h
index 356df08c..42c85534 100644
--- a/src/stream.h
+++ b/src/stream.h
@@ -114,7 +114,7 @@ public:
* empty.
*/
void initialize(const optional<path>& output_file = none,
- const optional<path>& pager_path = none);
+ const optional<path>& pager_path = none);
/**
* Convertor to a standard ostream. This is used so that we can
diff --git a/src/system.hh.in b/src/system.hh.in
index 5de7150e..6f709684 100644
--- a/src/system.hh.in
+++ b/src/system.hh.in
@@ -137,6 +137,7 @@ typedef std::ostream::pos_type ostream_pos_type;
#endif
#include <boost/algorithm/string.hpp>
+#include <boost/any.hpp>
#include <boost/bind.hpp>
#include <boost/cast.hpp>
#include <boost/current_function.hpp>
@@ -192,6 +193,7 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/date_time/posix_time/time_serialize.hpp>
#include <boost/date_time/gregorian/greg_serialize.hpp>
+#include <boost/ptr_container/serialize_ptr_deque.hpp>
namespace boost {
namespace serialization {
@@ -237,6 +239,10 @@ void serialize(Archive& ar, istream_pos_type& pos, const unsigned int)
} // namespace serialization
} // namespace boost
+#else // HAVE_BOOST_SERIALIZATION
+
+#include <boost/ptr_container/ptr_deque.hpp>
+
#endif // HAVE_BOOST_SERIALIZATION
#if defined(HAVE_BOOST_PYTHON)
diff --git a/src/temps.cc b/src/temps.cc
index 7a630176..365c33c5 100644
--- a/src/temps.cc
+++ b/src/temps.cc
@@ -63,7 +63,7 @@ xact_t& temporaries_t::create_xact()
}
post_t& temporaries_t::copy_post(post_t& origin, xact_t& xact,
- account_t * account)
+ account_t * account)
{
if (! post_temps)
post_temps = std::list<post_t>();
@@ -99,7 +99,7 @@ post_t& temporaries_t::create_post(xact_t& xact, account_t * account)
}
account_t& temporaries_t::create_account(const string& name,
- account_t * parent)
+ account_t * parent)
{
if (! acct_temps)
acct_temps = std::list<account_t>();
@@ -119,10 +119,10 @@ void temporaries_t::clear()
if (post_temps) {
foreach (post_t& post, *post_temps) {
if (! post.xact->has_flags(ITEM_TEMP))
- post.xact->remove_post(&post);
+ post.xact->remove_post(&post);
if (post.account && ! post.account->has_flags(ACCOUNT_TEMP))
- post.account->remove_post(&post);
+ post.account->remove_post(&post);
}
post_temps->clear();
}
@@ -133,7 +133,7 @@ void temporaries_t::clear()
if (acct_temps) {
foreach (account_t& acct, *acct_temps) {
if (acct.parent && ! acct.parent->has_flags(ACCOUNT_TEMP))
- acct.parent->remove_account(&acct);
+ acct.parent->remove_account(&acct);
}
acct_temps->clear();
}
diff --git a/src/temps.h b/src/temps.h
index 210bbf63..1e7eb69f 100644
--- a/src/temps.h
+++ b/src/temps.h
@@ -61,13 +61,13 @@ public:
return xact_temps->back();
}
post_t& copy_post(post_t& origin, xact_t& xact,
- account_t * account = NULL);
+ account_t * account = NULL);
post_t& create_post(xact_t& xact, account_t * account);
post_t& last_post() {
return post_temps->back();
}
account_t& create_account(const string& name = "",
- account_t * parent = NULL);
+ account_t * parent = NULL);
account_t& last_account() {
return acct_temps->back();
}
diff --git a/src/textual.cc b/src/textual.cc
index 85b1a14b..3dbae9a1 100644
--- a/src/textual.cc
+++ b/src/textual.cc
@@ -49,26 +49,26 @@
namespace ledger {
namespace {
- typedef std::pair<commodity_t *, amount_t> fixed_rate_t;
+ typedef std::pair<commodity_t *, amount_t> fixed_rate_t;
typedef variant<account_t *, string, fixed_rate_t> state_t;
class parse_context_t : public noncopyable
{
public:
- journal_t& journal;
- scope_t& scope;
+ journal_t& journal;
+ scope_t& scope;
std::list<state_t> state_stack;
#if defined(TIMELOG_SUPPORT)
- time_log_t timelog;
+ time_log_t timelog;
#endif
- bool strict;
- std::size_t count;
- std::size_t errors;
- std::size_t sequence;
+ bool strict;
+ std::size_t count;
+ std::size_t errors;
+ std::size_t sequence;
parse_context_t(journal_t& _journal, scope_t& _scope)
- : journal(_journal), scope(_scope), timelog(journal),
- strict(false), count(0), errors(0), sequence(1) {}
+ : journal(_journal), scope(_scope), timelog(journal, scope),
+ strict(false), count(0), errors(0), sequence(1) {}
bool front_is_account() {
return state_stack.front().type() == typeid(account_t *);
@@ -82,8 +82,8 @@ namespace {
account_t * top_account() {
foreach (state_t& state, state_stack)
- if (state.type() == typeid(account_t *))
- return boost::get<account_t *>(state);
+ if (state.type() == typeid(account_t *))
+ return boost::get<account_t *>(state);
return NULL;
}
};
@@ -93,31 +93,34 @@ namespace {
static const std::size_t MAX_LINE = 1024;
public:
- parse_context_t& context;
- instance_t * parent;
- accounts_map account_aliases;
- const path * original_file;
- path pathname;
- std::istream& in;
- char linebuf[MAX_LINE + 1];
- std::size_t linenum;
- istream_pos_type line_beg_pos;
- istream_pos_type curr_pos;
-
- optional<date_t::year_type> current_year;
+ parse_context_t& context;
+ instance_t * parent;
+ accounts_map account_aliases;
+ const path * original_file;
+ path pathname;
+ std::istream& in;
+ char linebuf[MAX_LINE + 1];
+ std::size_t linenum;
+ istream_pos_type line_beg_pos;
+ istream_pos_type curr_pos;
+ optional<datetime_t> prev_epoch;
instance_t(parse_context_t& _context,
- std::istream& _in,
- const path * _original_file = NULL,
- instance_t * _parent = NULL);
+ std::istream& _in,
+ const path * _original_file = NULL,
+ instance_t * _parent = NULL);
~instance_t();
+ virtual string description() {
+ return _("textual parser");
+ }
+
void parse();
std::streamsize read_line(char *& line);
bool peek_whitespace_line() {
return (in.good() && ! in.eof() &&
- (in.peek() == ' ' || in.peek() == '\t'));
+ (in.peek() == ' ' || in.peek() == '\t'));
}
void read_next_directive();
@@ -146,33 +149,36 @@ namespace {
void account_mapping_directive(char * line);
void tag_directive(char * line);
void define_directive(char * line);
+ void assert_directive(char * line);
+ void check_directive(char * line);
+ void expr_directive(char * line);
bool general_directive(char * line);
- post_t * parse_post(char * line,
- std::streamsize len,
- account_t * account,
- xact_t * xact,
- bool defer_expr = false);
+ post_t * parse_post(char * line,
+ std::streamsize len,
+ account_t * account,
+ xact_t * xact,
+ bool defer_expr = false);
bool parse_posts(account_t * account,
- xact_base_t& xact,
- const bool defer_expr = false);
+ xact_base_t& xact,
+ const bool defer_expr = false);
- xact_t * parse_xact(char * line,
- std::streamsize len,
- account_t * account);
+ xact_t * parse_xact(char * line,
+ std::streamsize len,
+ account_t * account);
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
};
- void parse_amount_expr(std::istream& in,
- scope_t& scope,
- post_t& post,
- amount_t& amount,
- const parse_flags_t& flags = PARSE_DEFAULT,
- const bool defer_expr = false,
- optional<expr_t> * amount_expr = NULL)
+ void parse_amount_expr(std::istream& in,
+ scope_t& scope,
+ post_t& post,
+ amount_t& amount,
+ const parse_flags_t& flags = PARSE_DEFAULT,
+ const bool defer_expr = false,
+ optional<expr_t> * amount_expr = NULL)
{
expr_t expr(in, flags.plus_flags(PARSE_PARTIAL));
@@ -181,34 +187,38 @@ namespace {
#if defined(DEBUG_ENABLED)
DEBUG_IF("textual.parse") {
if (_debug_stream) {
- ledger::dump_value_expr(*_debug_stream, expr);
- *_debug_stream << std::endl;
+ ledger::dump_value_expr(*_debug_stream, expr);
+ *_debug_stream << std::endl;
}
}
#endif
if (expr) {
if (amount_expr)
- *amount_expr = expr;
+ *amount_expr = expr;
if (! defer_expr)
- amount = post.resolve_expr(scope, expr);
+ amount = post.resolve_expr(scope, expr);
}
}
}
instance_t::instance_t(parse_context_t& _context,
- std::istream& _in,
- const path * _original_file,
- instance_t * _parent)
+ std::istream& _in,
+ const path * _original_file,
+ instance_t * _parent)
: context(_context), parent(_parent), original_file(_original_file),
pathname(original_file ? *original_file : "/dev/stdin"), in(_in)
{
TRACE_CTOR(instance_t, "...");
+ DEBUG("times.epoch", "Saving epoch " << epoch);
+ prev_epoch = epoch; // declared in times.h
}
instance_t::~instance_t()
{
TRACE_DTOR(instance_t);
+ epoch = prev_epoch;
+ DEBUG("times.epoch", "Restored epoch to " << epoch);
}
void instance_t::parse()
@@ -216,7 +226,7 @@ void instance_t::parse()
INFO("Parsing file '" << pathname.string() << "'");
TRACE_START(instance_parse, 1,
- "Done parsing file '" << pathname.string() << "'");
+ "Done parsing file '" << pathname.string() << "'");
if (! in.good() || in.eof())
return;
@@ -232,30 +242,30 @@ void instance_t::parse()
string current_context = error_context();
if (parent) {
- std::list<instance_t *> instances;
+ std::list<instance_t *> instances;
- for (instance_t * instance = parent;
- instance;
- instance = instance->parent)
- instances.push_front(instance);
+ for (instance_t * instance = parent;
+ instance;
+ instance = instance->parent)
+ instances.push_front(instance);
- foreach (instance_t * instance, instances)
- add_error_context(_("In file included from %1")
- << file_context(instance->pathname,
- instance->linenum));
+ foreach (instance_t * instance, instances)
+ add_error_context(_("In file included from %1")
+ << file_context(instance->pathname,
+ instance->linenum));
}
add_error_context(_("While parsing file %1")
- << file_context(pathname, linenum));
+ << file_context(pathname, linenum));
if (caught_signal != NONE_CAUGHT)
- throw;
+ throw;
string err_context = error_context();
if (! err_context.empty())
- std::cerr << err_context << std::endl;
+ std::cerr << err_context << std::endl;
if (! current_context.empty())
- std::cerr << current_context << std::endl;
+ std::cerr << current_context << std::endl;
std::cerr << _("Error: ") << err.what() << std::endl;
context.errors++;
@@ -268,7 +278,7 @@ void instance_t::parse()
std::streamsize instance_t::read_line(char *& line)
{
assert(in.good());
- assert(! in.eof()); // no one should call us in that case
+ assert(! in.eof()); // no one should call us in that case
line_beg_pos = curr_pos;
@@ -283,7 +293,7 @@ std::streamsize instance_t::read_line(char *& line)
else
line = linebuf;
- if (line[len - 1] == '\r') // strip Windows CRLF down to LF
+ if (line[len - 1] == '\r') // strip Windows CRLF down to LF
line[--len] = '\0';
linenum++;
@@ -291,7 +301,7 @@ std::streamsize instance_t::read_line(char *& line)
curr_pos = line_beg_pos;
curr_pos += len;
- return len - 1; // LF is being silently dropped
+ return len - 1; // LF is being silently dropped
}
return 0;
}
@@ -306,7 +316,7 @@ void instance_t::read_next_directive()
switch (line[0]) {
case '\0':
- assert(false); // shouldn't ever reach here
+ assert(false); // shouldn't ever reach here
break;
case ' ':
@@ -314,13 +324,13 @@ void instance_t::read_next_directive()
break;
}
- case ';': // comments
+ case ';': // comments
case '#':
case '*':
case '|':
break;
- case '-': // option setting
+ case '-': // option setting
option_directive(line);
break;
@@ -336,10 +346,10 @@ void instance_t::read_next_directive()
case '9':
xact_directive(line, len);
break;
- case '=': // automated xact
+ case '=': // automated xact
automated_xact_directive(line);
break;
- case '~': // period xact
+ case '~': // period xact
period_xact_directive(line);
break;
@@ -347,47 +357,47 @@ void instance_t::read_next_directive()
case '!':
line++;
// fall through...
- default: // some other directive
+ default: // some other directive
if (! general_directive(line)) {
switch (line[0]) {
#if defined(TIMELOG_SUPPORT)
case 'i':
- clock_in_directive(line, false);
- break;
+ clock_in_directive(line, false);
+ break;
case 'I':
- clock_in_directive(line, true);
- break;
+ clock_in_directive(line, true);
+ break;
case 'o':
- clock_out_directive(line, false);
- break;
+ clock_out_directive(line, false);
+ break;
case 'O':
- clock_out_directive(line, true);
- break;
+ clock_out_directive(line, true);
+ break;
case 'h':
case 'b':
- break;
+ break;
#endif // TIMELOG_SUPPORT
- case 'A': // a default account for unbalanced posts
- default_account_directive(line);
- break;
- case 'C': // a set of conversions
- price_conversion_directive(line);
- break;
- case 'D': // a default commodity for "xact"
- default_commodity_directive(line);
- break;
- case 'N': // don't download prices
- nomarket_directive(line);
- break;
- case 'P': // a pricing xact
- price_xact_directive(line);
- break;
- case 'Y': // set the current year
- year_directive(line);
- break;
+ case 'A': // a default account for unbalanced posts
+ default_account_directive(line);
+ break;
+ case 'C': // a set of conversions
+ price_conversion_directive(line);
+ break;
+ case 'D': // a default commodity for "xact"
+ default_commodity_directive(line);
+ break;
+ case 'N': // don't download prices
+ nomarket_directive(line);
+ break;
+ case 'P': // a pricing xact
+ price_xact_directive(line);
+ break;
+ case 'Y': // set the current year
+ year_directive(line);
+ break;
}
}
break;
@@ -417,10 +427,10 @@ void instance_t::clock_in_directive(char * line, bool /*capitalized*/)
position.end_line = linenum;
position.sequence = context.sequence++;
- time_xact_t event(position, parse_datetime(datetime, current_year),
- p ? context.top_account()->find_account(p) : NULL,
- n ? n : "",
- end ? end : "");
+ time_xact_t event(position, parse_datetime(datetime),
+ p ? context.top_account()->find_account(p) : NULL,
+ n ? n : "",
+ end ? end : "");
context.timelog.clock_in(event);
}
@@ -446,10 +456,10 @@ void instance_t::clock_out_directive(char * line, bool /*capitalized*/)
position.end_line = linenum;
position.sequence = context.sequence++;
- time_xact_t event(position, parse_datetime(datetime, current_year),
- p ? context.top_account()->find_account(p) : NULL,
- n ? n : "",
- end ? end : "");
+ time_xact_t event(position, parse_datetime(datetime),
+ p ? context.top_account()->find_account(p) : NULL,
+ n ? n : "",
+ end ? end : "");
context.timelog.clock_out(event);
context.count++;
@@ -500,7 +510,12 @@ void instance_t::nomarket_directive(char * line)
void instance_t::year_directive(char * line)
{
- current_year = lexical_cast<unsigned short>(skip_ws(line + 1));
+ unsigned short year(lexical_cast<unsigned short>(skip_ws(line + 1)));
+ DEBUG("times.epoch", "Setting current year to " << year);
+ // This must be set to the last day of the year, otherwise partial
+ // dates like "11/01" will refer to last year's november, not the
+ // current year.
+ epoch = datetime_t(date_t(year, 12, 31));
}
void instance_t::option_directive(char * line)
@@ -523,34 +538,90 @@ 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)));
- ae->pos = position_t();
- ae->pos->pathname = pathname;
- ae->pos->beg_pos = line_beg_pos;
- ae->pos->beg_line = linenum;
- ae->pos->sequence = context.sequence++;
-
- reveal_context = false;
-
- if (parse_posts(context.top_account(), *ae.get(), true)) {
- reveal_context = true;
+ 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;
+ ae->pos->beg_line = linenum;
+ ae->pos->sequence = context.sequence++;
+
+ post_t * last_post = NULL;
+
+ while (peek_whitespace_line()) {
+ std::streamsize len = read_line(line);
+
+ char * p = skip_ws(line);
+ if (! *p)
+ break;
+
+ const std::size_t remlen = std::strlen(p);
+
+ if (*p == ';') {
+ item_t * item;
+ if (last_post)
+ item = last_post;
+ else
+ item = ae.get();
+
+ // This is a trailing note, and possibly a metadata info tag
+ item->append_note(p + 1, context.scope, true);
+ item->pos->end_pos = curr_pos;
+ item->pos->end_line++;
+
+ // If there was no last_post yet, then deferred notes get applied to
+ // the matched posting. Other notes get applied to the auto-generated
+ // posting.
+ ae->deferred_notes->back().apply_to_post = last_post;
+ }
+ else if ((remlen > 7 && *p == 'a' &&
+ std::strncmp(p, "assert", 6) == 0 && std::isspace(p[6])) ||
+ (remlen > 6 && *p == 'c' &&
+ std::strncmp(p, "check", 5) == 0 && std::isspace(p[5])) ||
+ (remlen > 5 && *p == 'e' &&
+ std::strncmp(p, "expr", 4) == 0 && std::isspace(p[4]))) {
+ const char c = *p;
+ p = skip_ws(&p[*p == 'a' ? 6 : (*p == 'c' ? 5 : 4)]);
+ if (! ae->check_exprs)
+ ae->check_exprs = auto_xact_t::check_expr_list();
+ ae->check_exprs->push_back
+ (auto_xact_t::check_expr_pair(expr_t(p),
+ c == 'a' ?
+ auto_xact_t::EXPR_ASSERTION :
+ (c == 'c' ?
+ auto_xact_t::EXPR_CHECK :
+ auto_xact_t::EXPR_GENERAL)));
+ }
+ else {
+ reveal_context = false;
+
+ if (post_t * post =
+ parse_post(p, len - (p - line), context.top_account(),
+ NULL, true)) {
+ reveal_context = true;
+ ae->add_post(post);
+ last_post = post;
+ }
+ reveal_context = true;
+ }
+ }
context.journal.auto_xacts.push_back(ae.get());
- ae->journal = &context.journal;
+ ae->journal = &context.journal;
ae->pos->end_pos = curr_pos;
ae->pos->end_line = linenum;
ae.release();
}
-
- }
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (reveal_context) {
- add_error_context(_("While parsing periodic transaction:"));
+ add_error_context(_("While parsing automated transaction:"));
add_error_context(source_context(pathname, pos, curr_pos, "> "));
}
throw;
@@ -587,13 +658,14 @@ void instance_t::period_xact_directive(char * line)
pe.release();
} else {
+ reveal_context = true;
pe->journal = NULL;
throw parse_error(_("Period transaction failed to balance"));
}
}
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (reveal_context) {
add_error_context(_("While parsing periodic transaction:"));
add_error_context(source_context(pathname, pos, curr_pos, "> "));
@@ -610,12 +682,12 @@ void instance_t::xact_directive(char * line, std::streamsize len)
std::auto_ptr<xact_t> manager(xact);
if (context.journal.add_xact(xact)) {
- manager.release(); // it's owned by the journal now
+ manager.release(); // it's owned by the journal now
context.count++;
}
- // It's perfectly valid for the journal to reject the xact, which it will
- // do if the xact has no substantive effect (for example, a checking
- // xact, all of whose postings have null amounts).
+ // It's perfectly valid for the journal to reject the xact, which it
+ // will do if the xact has no substantive effect (for example, a
+ // checking xact, all of whose postings have null amounts).
} else {
throw parse_error(_("Failed to parse transaction"));
}
@@ -650,44 +722,44 @@ 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());
+ path parent_path = filename.parent_path();
+ glob.assign_glob('^' + filename.filename() + '$');
#else // BOOST_VERSION >= 103700
- path parent_path = filename.branch_path();
- glob.assign_glob(filename.leaf());
+ path parent_path = filename.branch_path();
+ glob.assign_glob('^' + filename.leaf() + '$');
#endif // BOOST_VERSION >= 103700
bool files_found = false;
if (exists(parent_path)) {
filesystem::directory_iterator end;
for (filesystem::directory_iterator iter(parent_path);
- iter != end;
- ++iter) {
+ iter != end;
+ ++iter) {
#if BOOST_VERSION <= 103500
if (is_regular(*iter))
#else
if (is_regular_file(*iter))
#endif
- {
+ {
#if BOOST_VERSION >= 103700
- string base = (*iter).filename();
+ string base = (*iter).filename();
#else // BOOST_VERSION >= 103700
- string base = (*iter).leaf();
+ string base = (*iter).leaf();
#endif // BOOST_VERSION >= 103700
- if (glob.match(base)) {
- path inner_file(*iter);
- ifstream stream(inner_file);
- instance_t instance(context, stream, &inner_file, this);
- instance.parse();
- files_found = true;
- }
+ if (glob.match(base)) {
+ path inner_file(*iter);
+ ifstream stream(inner_file);
+ instance_t instance(context, stream, &inner_file, this);
+ instance.parse();
+ files_found = true;
+ }
}
}
}
if (! files_found)
throw_(std::runtime_error,
- _("File to include was not found: '%1'") << filename);
+ _("File to include was not found: '%1'") << filename);
}
@@ -707,17 +779,17 @@ void instance_t::end_directive(char * kind)
if ((name.empty() || name == "account") && ! context.front_is_account())
throw_(std::runtime_error,
- _("'end account' directive does not match open directive"));
+ _("'end account' directive does not match open directive"));
else if (name == "tag" && ! context.front_is_string())
throw_(std::runtime_error,
- _("'end tag' directive does not match open directive"));
+ _("'end tag' directive does not match open directive"));
else if (name == "fixed" && ! context.front_is_fixed_rate())
throw_(std::runtime_error,
- _("'end fixed' directive does not match open directive"));
+ _("'end fixed' directive does not match open directive"));
if (context.state_stack.size() <= 1)
throw_(std::runtime_error,
- _("'end' found, but no enclosing tag or account directive"));
+ _("'end' found, but no enclosing tag or account directive"));
else
context.state_stack.pop_front();
}
@@ -747,9 +819,9 @@ void instance_t::fixed_directive(char * line)
{
if (optional<std::pair<commodity_t *, price_point_t> > price_point =
commodity_pool_t::current_pool->parse_price_directive(trim_ws(line),
- true)) {
+ true)) {
context.state_stack.push_front(fixed_rate_t(price_point->first,
- price_point->second.price));
+ price_point->second.price));
} else {
throw_(std::runtime_error, _("Error in fixed directive"));
}
@@ -789,7 +861,7 @@ void instance_t::account_mapping_directive(char * line)
if (payee_regex)
context.journal.account_mappings.push_back
(account_mapping_t(mask_t(payee_regex),
- context.top_account()->find_account(account_name)));
+ context.top_account()->find_account(account_name)));
while (peek_whitespace_line()) {
#if defined(NO_ASSERTS)
@@ -805,7 +877,7 @@ void instance_t::account_mapping_directive(char * line)
context.journal.account_mappings.push_back
(account_mapping_t(mask_t(payee_regex),
- context.top_account()->find_account(account_name)));
+ context.top_account()->find_account(account_name)));
}
}
@@ -822,7 +894,27 @@ void instance_t::tag_directive(char * line)
void instance_t::define_directive(char * line)
{
expr_t def(skip_ws(line));
- def.compile(context.scope); // causes definitions to be established
+ def.compile(context.scope); // causes definitions to be established
+}
+
+void instance_t::assert_directive(char * line)
+{
+ expr_t expr(line);
+ if (! expr.calc(context.scope).to_boolean())
+ throw_(parse_error, _("Assertion failed: %1") << line);
+}
+
+void instance_t::check_directive(char * line)
+{
+ expr_t expr(line);
+ if (! expr.calc(context.scope).to_boolean())
+ warning_(_("Check failed: %1") << line);
+}
+
+void instance_t::expr_directive(char * line)
+{
+ expr_t expr(line);
+ expr.calc(context.scope);
}
bool instance_t::general_directive(char * line)
@@ -847,6 +939,10 @@ bool instance_t::general_directive(char * line)
alias_directive(arg);
return true;
}
+ else if (std::strcmp(p, "assert") == 0) {
+ assert_directive(arg);
+ return true;
+ }
break;
case 'b':
@@ -861,6 +957,10 @@ bool instance_t::general_directive(char * line)
account_mapping_directive(arg);
return true;
}
+ else if (std::strcmp(p, "check") == 0) {
+ check_directive(arg);
+ return true;
+ }
break;
case 'd':
@@ -875,6 +975,10 @@ bool instance_t::general_directive(char * line)
end_directive(arg);
return true;
}
+ else if (std::strcmp(p, "expr") == 0) {
+ expr_directive(arg);
+ return true;
+ }
break;
case 'f':
@@ -923,18 +1027,18 @@ bool instance_t::general_directive(char * line)
return false;
}
-post_t * instance_t::parse_post(char * line,
- std::streamsize len,
- account_t * account,
- xact_t * xact,
- bool defer_expr)
+post_t * instance_t::parse_post(char * line,
+ std::streamsize len,
+ account_t * account,
+ xact_t * xact,
+ bool defer_expr)
{
TRACE_START(post_details, 1, "Time spent parsing postings:");
std::auto_ptr<post_t> post(new post_t);
- post->xact = xact; // this could be NULL
- post->pos = position_t();
+ post->xact = xact; // this could be NULL
+ post->pos = position_t();
post->pos->pathname = pathname;
post->pos->beg_pos = line_beg_pos;
post->pos->beg_line = linenum;
@@ -958,14 +1062,14 @@ post_t * instance_t::parse_post(char * line,
post->set_state(item_t::CLEARED);
p = skip_ws(p + 1);
DEBUG("textual.parse", "line " << linenum << ": "
- << "Parsed the CLEARED flag");
+ << "Parsed the CLEARED flag");
break;
case '!':
post->set_state(item_t::PENDING);
p = skip_ws(p + 1);
DEBUG("textual.parse", "line " << linenum << ": "
- << "Parsed the PENDING flag");
+ << "Parsed the PENDING flag");
break;
}
@@ -988,19 +1092,19 @@ post_t * instance_t::parse_post(char * line,
if ((*p == '[' && *(e - 1) == ']') || (*p == '(' && *(e - 1) == ')')) {
post->add_flags(POST_VIRTUAL);
DEBUG("textual.parse", "line " << linenum << ": "
- << "Parsed a virtual account name");
+ << "Parsed a virtual account name");
if (*p == '[') {
post->add_flags(POST_MUST_BALANCE);
DEBUG("textual.parse", "line " << linenum << ": "
- << "Posting must balance");
+ << "Posting must balance");
}
p++; e--;
}
string name(p, e - p);
DEBUG("textual.parse", "line " << linenum << ": "
- << "Parsed account name " << name);
+ << "Parsed account name " << name);
if (account_aliases.size() > 0) {
accounts_map::const_iterator i = account_aliases.find(name);
@@ -1013,15 +1117,15 @@ post_t * instance_t::parse_post(char * line,
if (context.strict && ! post->account->has_flags(ACCOUNT_KNOWN)) {
if (post->_state == item_t::UNCLEARED)
warning_(_("\"%1\", line %2: Unknown account '%3'")
- << pathname << linenum << post->account->fullname());
+ << pathname << linenum << post->account->fullname());
post->account->add_flags(ACCOUNT_KNOWN);
}
if (post->account->name == _("Unknown")) {
foreach (account_mapping_t& value, context.journal.account_mappings) {
if (value.first.match(xact->payee)) {
- post->account = value.second;
- break;
+ post->account = value.second;
+ break;
}
}
}
@@ -1036,39 +1140,39 @@ post_t * instance_t::parse_post(char * line,
beg = next - line;
ptristream stream(next, len - beg);
- if (*next != '(') // indicates a value expression
+ if (*next != '(') // indicates a value expression
post->amount.parse(stream, PARSE_NO_REDUCE);
else
parse_amount_expr(stream, context.scope, *post.get(), post->amount,
- PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN,
- defer_expr, &post->amount_expr);
+ PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN,
+ defer_expr, &post->amount_expr);
if (! post->amount.is_null() && post->amount.has_commodity()) {
if (context.strict &&
- ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) {
- if (post->_state == item_t::UNCLEARED)
- warning_(_("\"%1\", line %2: Unknown commodity '%3'")
- << pathname << linenum << post->amount.commodity());
- post->amount.commodity().add_flags(COMMODITY_KNOWN);
+ ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) {
+ if (post->_state == item_t::UNCLEARED)
+ warning_(_("\"%1\", line %2: Unknown commodity '%3'")
+ << pathname << linenum << post->amount.commodity());
+ post->amount.commodity().add_flags(COMMODITY_KNOWN);
}
if (! post->amount.has_annotation()) {
- foreach (state_t& state, context.state_stack) {
- if (state.type() == typeid(fixed_rate_t)) {
- fixed_rate_t& rate(boost::get<fixed_rate_t>(state));
- if (*rate.first == post->amount.commodity()) {
- annotation_t details(rate.second);
- details.add_flags(ANNOTATION_PRICE_FIXATED);
- post->amount.annotate(details);
- break;
- }
- }
- }
+ foreach (state_t& state, context.state_stack) {
+ if (state.type() == typeid(fixed_rate_t)) {
+ fixed_rate_t& rate(boost::get<fixed_rate_t>(state));
+ if (*rate.first == post->amount.commodity()) {
+ annotation_t details(rate.second);
+ details.add_flags(ANNOTATION_PRICE_FIXATED);
+ post->amount.annotate(details);
+ break;
+ }
+ }
+ }
}
}
DEBUG("textual.parse", "line " << linenum << ": "
- << "post amount = " << post->amount);
+ << "post amount = " << post->amount);
if (stream.eof()) {
next = NULL;
@@ -1078,62 +1182,73 @@ post_t * instance_t::parse_post(char * line,
// Parse the optional cost (@ PER-UNIT-COST, @@ TOTAL-COST)
if (*next == '@') {
- DEBUG("textual.parse", "line " << linenum << ": "
- << "Found a price indicator");
-
- bool per_unit = true;
-
- if (*++next == '@') {
- per_unit = false;
- post->add_flags(POST_COST_IN_FULL);
- DEBUG("textual.parse", "line " << linenum << ": "
- << "And it's for a total price");
- }
-
- beg = ++next - line;
-
- p = skip_ws(next);
- if (*p) {
- post->cost = amount_t();
-
- beg = p - line;
- ptristream cstream(p, len - beg);
-
- if (*p != '(') // indicates a value expression
- post->cost->parse(cstream, PARSE_NO_MIGRATE);
- else
- parse_amount_expr(cstream, context.scope, *post.get(), *post->cost,
- PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN);
-
- if (post->cost->sign() < 0)
- throw parse_error(_("A posting's cost may not be negative"));
-
- post->cost->in_place_unround();
-
- if (per_unit) {
- // For the sole case where the cost might be uncommoditized,
- // guarantee that the commodity of the cost after multiplication
- // is the same as it was before.
- commodity_t& cost_commodity(post->cost->commodity());
- *post->cost *= post->amount;
- post->cost->set_commodity(cost_commodity);
- }
- else if (post->amount.sign() < 0) {
- post->cost->in_place_negate();
- }
-
- DEBUG("textual.parse", "line " << linenum << ": "
- << "Total cost is " << *post->cost);
- DEBUG("textual.parse", "line " << linenum << ": "
- << "Annotated amount is " << post->amount);
-
- if (cstream.eof())
- next = NULL;
- else
- next = skip_ws(p + static_cast<std::ptrdiff_t>(cstream.tellg()));
- } else {
- throw parse_error(_("Expected a cost amount"));
- }
+ DEBUG("textual.parse", "line " << linenum << ": "
+ << "Found a price indicator");
+
+ bool per_unit = true;
+
+ if (*++next == '@') {
+ per_unit = false;
+ post->add_flags(POST_COST_IN_FULL);
+ DEBUG("textual.parse", "line " << linenum << ": "
+ << "And it's for a total price");
+ }
+
+ beg = ++next - line;
+
+ p = skip_ws(next);
+ if (*p) {
+ post->cost = amount_t();
+
+ bool fixed_cost = false;
+ if (*p == '=') {
+ p++;
+ fixed_cost = true;
+ if (*p == '\0')
+ throw parse_error(_("Posting is missing a cost amount"));
+ }
+
+ beg = p - line;
+ ptristream cstream(p, len - beg);
+
+ if (*p != '(') // indicates a value expression
+ post->cost->parse(cstream, PARSE_NO_MIGRATE);
+ else
+ parse_amount_expr(cstream, context.scope, *post.get(), *post->cost,
+ PARSE_NO_MIGRATE | PARSE_SINGLE | PARSE_NO_ASSIGN);
+
+ if (post->cost->sign() < 0)
+ throw parse_error(_("A posting's cost may not be negative"));
+
+ post->cost->in_place_unround();
+
+ if (per_unit) {
+ // For the sole case where the cost might be uncommoditized,
+ // guarantee that the commodity of the cost after multiplication
+ // is the same as it was before.
+ commodity_t& cost_commodity(post->cost->commodity());
+ *post->cost *= post->amount;
+ post->cost->set_commodity(cost_commodity);
+ }
+ else if (post->amount.sign() < 0) {
+ post->cost->in_place_negate();
+ }
+
+ if (fixed_cost)
+ post->add_flags(POST_COST_FIXATED);
+
+ DEBUG("textual.parse", "line " << linenum << ": "
+ << "Total cost is " << *post->cost);
+ DEBUG("textual.parse", "line " << linenum << ": "
+ << "Annotated amount is " << post->amount);
+
+ if (cstream.eof())
+ next = NULL;
+ else
+ next = skip_ws(p + static_cast<std::ptrdiff_t>(cstream.tellg()));
+ } else {
+ throw parse_error(_("Expected a cost amount"));
+ }
}
}
}
@@ -1142,7 +1257,7 @@ post_t * instance_t::parse_post(char * line,
if (xact && next && *next == '=') {
DEBUG("textual.parse", "line " << linenum << ": "
- << "Found a balance assignment indicator");
+ << "Found a balance assignment indicator");
beg = ++next - line;
@@ -1153,70 +1268,70 @@ post_t * instance_t::parse_post(char * line,
beg = p - line;
ptristream stream(p, len - beg);
- if (*p != '(') // indicates a value expression
- post->assigned_amount->parse(stream, PARSE_NO_MIGRATE);
+ if (*p != '(') // indicates a value expression
+ post->assigned_amount->parse(stream, PARSE_NO_MIGRATE);
else
- parse_amount_expr(stream, context.scope, *post.get(),
- *post->assigned_amount,
- PARSE_SINGLE | PARSE_NO_MIGRATE);
+ parse_amount_expr(stream, context.scope, *post.get(),
+ *post->assigned_amount,
+ PARSE_SINGLE | PARSE_NO_MIGRATE);
if (post->assigned_amount->is_null()) {
- if (post->amount.is_null())
- throw parse_error(_("Balance assignment must evaluate to a constant"));
- else
- throw parse_error(_("Balance assertion must evaluate to a constant"));
+ if (post->amount.is_null())
+ throw parse_error(_("Balance assignment must evaluate to a constant"));
+ else
+ throw parse_error(_("Balance assertion must evaluate to a constant"));
}
DEBUG("textual.parse", "line " << linenum << ": "
- << "POST assign: parsed amt = " << *post->assigned_amount);
+ << "POST assign: parsed amt = " << *post->assigned_amount);
- amount_t& amt(*post->assigned_amount);
+ amount_t& amt(*post->assigned_amount);
value_t account_total
- (post->account->amount(false).strip_annotations(keep_details_t()));
+ (post->account->amount(false).strip_annotations(keep_details_t()));
DEBUG("post.assign",
- "line " << linenum << ": " "account balance = " << account_total);
+ "line " << linenum << ": " "account balance = " << account_total);
DEBUG("post.assign",
- "line " << linenum << ": " "post amount = " << amt);
+ "line " << linenum << ": " "post amount = " << amt);
amount_t diff = amt;
switch (account_total.type()) {
case value_t::AMOUNT:
- diff -= account_total.as_amount();
- break;
+ diff -= account_total.as_amount();
+ break;
case value_t::BALANCE:
- if (optional<amount_t> comm_bal =
- account_total.as_balance().commodity_amount(amt.commodity()))
- diff -= *comm_bal;
- break;
+ if (optional<amount_t> comm_bal =
+ account_total.as_balance().commodity_amount(amt.commodity()))
+ diff -= *comm_bal;
+ break;
default:
- break;
+ break;
}
DEBUG("post.assign",
- "line " << linenum << ": " << "diff = " << diff);
+ "line " << linenum << ": " << "diff = " << diff);
DEBUG("textual.parse",
- "line " << linenum << ": " << "POST assign: diff = " << diff);
+ "line " << linenum << ": " << "POST assign: diff = " << diff);
if (! diff.is_zero()) {
- if (! post->amount.is_null()) {
- diff -= post->amount;
- if (! diff.is_zero())
- throw_(parse_error, _("Balance assertion off by %1") << diff);
- } else {
- post->amount = diff;
- DEBUG("textual.parse", "line " << linenum << ": "
- << "Overwrite null posting");
- }
+ if (! post->amount.is_null()) {
+ diff -= post->amount;
+ if (! diff.is_zero())
+ throw_(parse_error, _("Balance assertion off by %1") << diff);
+ } else {
+ post->amount = diff;
+ DEBUG("textual.parse", "line " << linenum << ": "
+ << "Overwrite null posting");
+ }
}
if (stream.eof())
- next = NULL;
+ next = NULL;
else
- next = skip_ws(p + static_cast<std::ptrdiff_t>(stream.tellg()));
+ next = skip_ws(p + static_cast<std::ptrdiff_t>(stream.tellg()));
} else {
throw parse_error(_("Expected an balance assignment/assertion amount"));
}
@@ -1225,18 +1340,18 @@ post_t * instance_t::parse_post(char * line,
// Parse the optional note
if (next && *next == ';') {
- post->append_note(++next, true, current_year);
+ post->append_note(++next, context.scope, true);
next = line + len;
DEBUG("textual.parse", "line " << linenum << ": "
- << "Parsed a posting note");
+ << "Parsed a posting note");
}
// There should be nothing more to read
if (next && *next)
throw_(parse_error,
- _("Unexpected char '%1' (Note: inline math requires parentheses)")
- << *next);
+ _("Unexpected char '%1' (Note: inline math requires parentheses)")
+ << *next);
post->pos->end_pos = curr_pos;
post->pos->end_line = linenum;
@@ -1244,7 +1359,7 @@ post_t * instance_t::parse_post(char * line,
if (! context.state_stack.empty()) {
foreach (const state_t& state, context.state_stack)
if (state.type() == typeid(string))
- post->parse_tags(boost::get<string>(state).c_str(), true);
+ post->parse_tags(boost::get<string>(state).c_str(), context.scope, true);
}
TRACE_STOP(post_details, 1);
@@ -1252,7 +1367,7 @@ post_t * instance_t::parse_post(char * line,
return post.release();
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
add_error_context(_("While parsing posting:"));
add_error_context(line_context(buf, beg, len));
throw;
@@ -1260,8 +1375,8 @@ post_t * instance_t::parse_post(char * line,
}
bool instance_t::parse_posts(account_t * account,
- xact_base_t& xact,
- const bool defer_expr)
+ xact_base_t& xact,
+ const bool defer_expr)
{
TRACE_START(xact_posts, 1, "Time spent parsing postings:");
@@ -1283,15 +1398,15 @@ bool instance_t::parse_posts(account_t * account,
return added;
}
-xact_t * instance_t::parse_xact(char * line,
- std::streamsize len,
- account_t * account)
+xact_t * instance_t::parse_xact(char * line,
+ std::streamsize len,
+ account_t * account)
{
TRACE_START(xact_text, 1, "Time spent parsing transaction text:");
std::auto_ptr<xact_t> xact(new xact_t);
- xact->pos = position_t();
+ xact->pos = position_t();
xact->pos->pathname = pathname;
xact->pos->beg_pos = line_beg_pos;
xact->pos->beg_line = linenum;
@@ -1307,9 +1422,9 @@ xact_t * instance_t::parse_xact(char * line,
if (char * p = std::strchr(line, '=')) {
*p++ = '\0';
- xact->_date_eff = parse_date(p, current_year);
+ xact->_date_eff = parse_date(p);
}
- xact->_date = parse_date(line, current_year);
+ xact->_date = parse_date(line);
// Parse the optional cleared flag: *
@@ -1342,8 +1457,8 @@ xact_t * instance_t::parse_xact(char * line,
char * p = next_element(next, true);
foreach (payee_mapping_t& value, context.journal.payee_mappings) {
if (value.first.match(next)) {
- xact->payee = value.second;
- break;
+ xact->payee = value.second;
+ break;
}
}
if (xact->payee.empty())
@@ -1356,7 +1471,7 @@ xact_t * instance_t::parse_xact(char * line,
// Parse the xact note
if (next && *next == ';')
- xact->append_note(++next, current_year);
+ xact->append_note(++next, context.scope, false);
TRACE_STOP(xact_text, 1);
@@ -1373,25 +1488,51 @@ xact_t * instance_t::parse_xact(char * line,
if (! *p)
break;
- if (*p == ';') {
- item_t * item;
- if (last_post)
- item = last_post;
- else
- item = xact.get();
+ const std::size_t remlen = std::strlen(p);
+
+ item_t * item;
+ if (last_post)
+ item = last_post;
+ else
+ item = xact.get();
+ if (*p == ';') {
// This is a trailing note, and possibly a metadata info tag
- item->append_note(p + 1, true, current_year);
+ item->append_note(p + 1, context.scope, true);
item->pos->end_pos = curr_pos;
item->pos->end_line++;
- } else {
+ }
+ else if ((remlen > 7 && *p == 'a' &&
+ std::strncmp(p, "assert", 6) == 0 && std::isspace(p[6])) ||
+ (remlen > 6 && *p == 'c' &&
+ std::strncmp(p, "check", 5) == 0 && std::isspace(p[5])) ||
+ (remlen > 5 && *p == 'e' &&
+ std::strncmp(p, "expr", 4) == 0 && std::isspace(p[4]))) {
+ const char c = *p;
+ p = skip_ws(&p[*p == 'a' ? 6 : (*p == 'c' ? 5 : 4)]);
+ expr_t expr(p);
+ bind_scope_t bound_scope(context.scope, *item);
+ if (c == 'e') {
+ expr.calc(bound_scope);
+ }
+ else if (! expr.calc(bound_scope).to_boolean()) {
+ if (c == 'a') {
+ throw_(parse_error, _("Transaction assertion failed: %1") << p);
+ } else {
+ warning_(_("Transaction check failed: %1") << p);
+ }
+ }
+ }
+ else {
reveal_context = false;
if (post_t * post =
- parse_post(p, len - (p - line), account, xact.get())) {
- xact->add_post(post);
- last_post = post;
+ parse_post(p, len - (p - line), account, xact.get())) {
+ reveal_context = true;
+ xact->add_post(post);
+ last_post = post;
}
+ reveal_context = true;
}
}
@@ -1400,11 +1541,11 @@ xact_t * instance_t::parse_xact(char * line,
foreach (post_t * post, xact->posts) {
if (post->_state == item_t::UNCLEARED) {
- result = item_t::UNCLEARED;
- break;
+ result = item_t::UNCLEARED;
+ break;
}
else if (post->_state == item_t::PENDING) {
- result = item_t::PENDING;
+ result = item_t::PENDING;
}
}
}
@@ -1415,7 +1556,8 @@ xact_t * instance_t::parse_xact(char * line,
if (! context.state_stack.empty()) {
foreach (const state_t& state, context.state_stack)
if (state.type() == typeid(string))
- xact->parse_tags(boost::get<string>(state).c_str(), false);
+ xact->parse_tags(boost::get<string>(state).c_str(), context.scope,
+ false);
}
TRACE_STOP(xact_details, 1);
@@ -1423,27 +1565,27 @@ xact_t * instance_t::parse_xact(char * line,
return xact.release();
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
if (reveal_context) {
add_error_context(_("While parsing transaction:"));
add_error_context(source_context(xact->pos->pathname,
- xact->pos->beg_pos, curr_pos, "> "));
+ xact->pos->beg_pos, curr_pos, "> "));
}
throw;
}
}
expr_t::ptr_op_t instance_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
return context.scope.lookup(kind, name);
}
std::size_t journal_t::parse(std::istream& in,
- scope_t& scope,
- account_t * master,
- const path * original_file,
- bool strict)
+ scope_t& scope,
+ account_t * master,
+ const path * original_file,
+ bool strict)
{
TRACE_START(parsing_total, 1, "Total time spent parsing text:");
diff --git a/src/timelog.cc b/src/timelog.cc
index 217aa581..698e2420 100644
--- a/src/timelog.cc
+++ b/src/timelog.cc
@@ -41,8 +41,9 @@ namespace ledger {
namespace {
void clock_out_from_timelog(std::list<time_xact_t>& time_xacts,
- time_xact_t out_event,
- journal_t& journal)
+ time_xact_t out_event,
+ journal_t& journal,
+ scope_t& scope)
{
time_xact_t event;
@@ -55,29 +56,29 @@ namespace {
}
else if (! out_event.account) {
throw parse_error
- (_("When multiple check-ins are active, checking out requires an account"));
+ (_("When multiple check-ins are active, checking out requires an account"));
}
else {
bool found = false;
for (std::list<time_xact_t>::iterator i = time_xacts.begin();
- i != time_xacts.end();
- i++)
- if (out_event.account == (*i).account) {
- event = *i;
- found = true;
- time_xacts.erase(i);
- break;
- }
+ i != time_xacts.end();
+ i++)
+ if (out_event.account == (*i).account) {
+ event = *i;
+ found = true;
+ time_xacts.erase(i);
+ break;
+ }
if (! found)
- throw parse_error
- (_("Timelog check-out event does not match any current check-ins"));
+ throw parse_error
+ (_("Timelog check-out event does not match any current check-ins"));
}
if (out_event.checkin < event.checkin)
throw parse_error
- (_("Timelog check-out date less than corresponding check-in"));
+ (_("Timelog check-out date less than corresponding check-in"));
if (! out_event.desc.empty() && event.desc.empty()) {
event.desc = out_event.desc;
@@ -94,11 +95,11 @@ namespace {
curr->pos = event.position;
if (! event.note.empty())
- curr->append_note(event.note.c_str());
+ curr->append_note(event.note.c_str(), scope);
char buf[32];
std::sprintf(buf, "%lds", long((out_event.checkin - event.checkin)
- .total_seconds()));
+ .total_seconds()));
amount_t amt;
amt.parse(buf);
VERIFY(amt.valid());
@@ -128,8 +129,8 @@ time_log_t::~time_log_t()
foreach (account_t * account, accounts)
clock_out_from_timelog(time_xacts,
- time_xact_t(none, CURRENT_TIME(), account),
- journal);
+ time_xact_t(none, CURRENT_TIME(), account),
+ journal, scope);
assert(time_xacts.empty());
}
@@ -140,7 +141,7 @@ void time_log_t::clock_in(time_xact_t event)
if (! time_xacts.empty()) {
foreach (time_xact_t& time_xact, time_xacts) {
if (event.account == time_xact.account)
- throw parse_error(_("Cannot double check-in to the same account"));
+ throw parse_error(_("Cannot double check-in to the same account"));
}
}
@@ -152,7 +153,7 @@ void time_log_t::clock_out(time_xact_t event)
if (time_xacts.empty())
throw std::logic_error(_("Timelog check-out event without a check-in"));
- clock_out_from_timelog(time_xacts, event, journal);
+ clock_out_from_timelog(time_xacts, event, journal, scope);
}
} // namespace ledger
diff --git a/src/timelog.h b/src/timelog.h
index caa23ec0..92b80edc 100644
--- a/src/timelog.h
+++ b/src/timelog.h
@@ -64,14 +64,14 @@ public:
TRACE_CTOR(time_xact_t, "");
}
time_xact_t(const optional<position_t>& _position,
- const datetime_t& _checkin,
- account_t * _account = NULL,
- const string& _desc = "",
- const string& _note = "")
+ const datetime_t& _checkin,
+ account_t * _account = NULL,
+ const string& _desc = "",
+ const string& _note = "")
: checkin(_checkin), account(_account), desc(_desc), note(_note),
position(_position ? *_position : position_t()) {
TRACE_CTOR(time_xact_t,
- "position_t, datetime_t, account_t *, string, string");
+ "position_t, datetime_t, account_t *, string, string");
}
time_xact_t(const time_xact_t& xact)
: checkin(xact.checkin), account(xact.account),
@@ -86,11 +86,13 @@ public:
class time_log_t
{
std::list<time_xact_t> time_xacts;
- journal_t& journal;
+ journal_t& journal;
+ scope_t& scope;
public:
- time_log_t(journal_t& _journal) : journal(_journal) {
- TRACE_CTOR(time_log_t, "journal_t&");
+ time_log_t(journal_t& _journal, scope_t& _scope)
+ : journal(_journal), scope(_scope) {
+ TRACE_CTOR(time_log_t, "journal_t&, scope_t&");
}
~time_log_t();
diff --git a/src/times.cc b/src/times.cc
index 60e8e7cc..02e99e53 100644
--- a/src/times.cc
+++ b/src/times.cc
@@ -60,17 +60,17 @@ namespace {
temporal_io_t(const char * _fmt_str, bool _input)
: fmt_str(_fmt_str),
- traits(icontains(fmt_str, "%y"),
- icontains(fmt_str, "%m") || icontains(fmt_str, "%b"),
- icontains(fmt_str, "%d")),
- input(_input) {
+ traits(icontains(fmt_str, "%y"),
+ icontains(fmt_str, "%m") || icontains(fmt_str, "%b"),
+ icontains(fmt_str, "%d")),
+ input(_input) {
#if defined(USE_BOOST_FACETS)
if (input) {
- input_facet = new InputFacetType(fmt_str);
- input_stream.imbue(std::locale(std::locale::classic(), input_facet));
+ input_facet = new InputFacetType(fmt_str);
+ input_stream.imbue(std::locale(std::locale::classic(), input_facet));
} else {
- output_facet = new OutputFacetType(fmt_str);
- output_stream.imbue(std::locale(std::locale::classic(), output_facet));
+ output_facet = new OutputFacetType(fmt_str);
+ output_stream.imbue(std::locale(std::locale::classic(), output_facet));
}
#endif // USE_BOOST_FACETS
}
@@ -78,14 +78,14 @@ namespace {
void set_format(const char * fmt) {
fmt_str = fmt;
traits = date_traits_t(icontains(fmt_str, "%y"),
- icontains(fmt_str, "%m") ||
- icontains(fmt_str, "%b"),
- icontains(fmt_str, "%d"));
+ icontains(fmt_str, "%m") ||
+ icontains(fmt_str, "%b"),
+ icontains(fmt_str, "%d"));
#if defined(USE_BOOST_FACETS)
if (input)
- input_facet->format(fmt_str);
+ input_facet->format(fmt_str);
else
- output_facet->format(fmt_str);
+ output_facet->format(fmt_str);
#endif // USE_BOOST_FACETS
}
@@ -110,7 +110,7 @@ namespace {
template <>
datetime_t temporal_io_t<datetime_t, posix_time::time_input_facet,
- posix_time::time_facet>
+ posix_time::time_facet>
::parse(const char * str)
{
#if defined(USE_BOOST_FACETS)
@@ -122,15 +122,15 @@ namespace {
input_stream >> when;
#if defined(DEBUG_ON)
if (when.is_not_a_date_time())
- DEBUG("times.parse", "Failed to parse date/time '" << str
- << "' using pattern '" << fmt_str << "'");
+ DEBUG("times.parse", "Failed to parse date/time '" << str
+ << "' using pattern '" << fmt_str << "'");
#endif
if (! when.is_not_a_date_time() &&
- input_stream.good() && ! input_stream.eof() &&
- input_stream.peek() != EOF) {
- DEBUG("times.parse", "This string has leftovers: '" << str << "'");
- return datetime_t();
+ input_stream.good() && ! input_stream.eof() &&
+ input_stream.peek() != EOF) {
+ DEBUG("times.parse", "This string has leftovers: '" << str << "'");
+ return datetime_t();
}
return when;
#else // USE_BOOST_FACETS
@@ -145,7 +145,7 @@ namespace {
template <>
date_t temporal_io_t<date_t, gregorian::date_input_facet,
- gregorian::date_facet>
+ gregorian::date_facet>
::parse(const char * str)
{
#if defined(USE_BOOST_FACETS)
@@ -157,21 +157,21 @@ namespace {
input_stream >> when;
#if defined(DEBUG_ON)
if (when.is_not_a_date())
- DEBUG("times.parse", "Failed to parse date '" << str
- << "' using pattern '" << fmt_str << "'");
+ DEBUG("times.parse", "Failed to parse date '" << str
+ << "' using pattern '" << fmt_str << "'");
#endif
if (! when.is_not_a_date() &&
- input_stream.good() && ! input_stream.eof() &&
- input_stream.peek() != EOF) {
- DEBUG("times.parse", "This string has leftovers: '" << str << "'");
- return date_t();
+ input_stream.good() && ! input_stream.eof() &&
+ input_stream.peek() != EOF) {
+ DEBUG("times.parse", "This string has leftovers: '" << str << "'");
+ return date_t();
}
return when;
#else // USE_BOOST_FACETS
std::tm data;
std::memset(&data, 0, sizeof(std::tm));
- data.tm_mday = 1; // some formats have no day
+ data.tm_mday = 1; // some formats have no day
if (strptime(str, fmt_str, &data))
return gregorian::date_from_tm(data);
else
@@ -180,22 +180,22 @@ namespace {
}
typedef temporal_io_t<datetime_t, posix_time::time_input_facet,
- posix_time::time_facet> datetime_io_t;
+ posix_time::time_facet> datetime_io_t;
typedef temporal_io_t<date_t, gregorian::date_input_facet,
- gregorian::date_facet> date_io_t;
+ gregorian::date_facet> date_io_t;
shared_ptr<datetime_io_t> input_datetime_io;
+ shared_ptr<datetime_io_t> timelog_datetime_io;
shared_ptr<date_io_t> input_date_io;
shared_ptr<datetime_io_t> written_datetime_io;
shared_ptr<date_io_t> written_date_io;
shared_ptr<datetime_io_t> printed_datetime_io;
shared_ptr<date_io_t> printed_date_io;
- std::vector<shared_ptr<date_io_t> > readers;
+ std::deque<shared_ptr<date_io_t> > readers;
date_t parse_date_mask_routine(const char * date_str, date_io_t& io,
- optional_year year,
- date_traits_t * traits = NULL)
+ date_traits_t * traits = NULL)
{
VERIFY(std::strlen(date_str) < 127);
@@ -204,7 +204,7 @@ namespace {
for (char * p = buf; *p; p++)
if (*p == '.' || *p == '-')
- *p = '/';
+ *p = '/';
date_t when = io.parse(buf);
@@ -219,41 +219,38 @@ namespace {
const char * p = when_str.c_str();
const char * q = buf;
for (; *p && *q; p++, q++) {
- if (*p != *q && *p == '0') p++;
- if (! *p || *p != *q) break;
+ if (*p != *q && *p == '0') p++;
+ if (! *p || *p != *q) break;
}
if (*p != '\0' || *q != '\0')
- throw_(date_error, _("Invalid date: %1") << date_str);
+ throw_(date_error, _("Invalid date: %1") << date_str);
if (traits)
- *traits = io.traits;
+ *traits = io.traits;
if (! io.traits.has_year) {
- when = date_t(year ? *year : CURRENT_DATE().year(),
- when.month(), when.day());
+ when = date_t(CURRENT_DATE().year(), when.month(), when.day());
- if (! year && when.month() > CURRENT_DATE().month())
- when -= gregorian::years(1);
+ if (when.month() > CURRENT_DATE().month())
+ when -= gregorian::years(1);
}
}
return when;
}
- date_t parse_date_mask(const char * date_str, optional_year year,
- date_traits_t * traits = NULL)
+ date_t parse_date_mask(const char * date_str, date_traits_t * traits = NULL)
{
if (input_date_io.get()) {
date_t when = parse_date_mask_routine(date_str, *input_date_io.get(),
- year, traits);
+ traits);
if (! when.is_not_a_date())
- return when;
+ return when;
}
foreach (shared_ptr<date_io_t>& reader, readers) {
- date_t when = parse_date_mask_routine(date_str, *reader.get(),
- year, traits);
+ date_t when = parse_date_mask_routine(date_str, *reader.get(), traits);
if (! when.is_not_a_date())
- return when;
+ return when;
}
throw_(date_error, _("Invalid date: %1") << date_str);
@@ -312,26 +309,35 @@ string_to_month_of_year(const std::string& str)
return none;
}
-datetime_t parse_datetime(const char * str, optional_year)
+datetime_t parse_datetime(const char * str)
{
- datetime_t when = input_datetime_io->parse(str);
- if (when.is_not_a_date_time())
- throw_(date_error, _("Invalid date/time: %1") << 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()) {
+ when = timelog_datetime_io->parse(buf);
+ if (when.is_not_a_date_time()) {
+ throw_(date_error, _("Invalid date/time: %1") << str);
+ }
+ }
return when;
}
-date_t parse_date(const char * str, optional_year current_year)
+date_t parse_date(const char * str)
{
- return parse_date_mask(str, current_year);
+ return parse_date_mask(str);
}
-date_t date_specifier_t::begin(const optional_year& current_year) const
+date_t date_specifier_t::begin() const
{
- assert(year || current_year);
-
- year_type the_year = year ? *year : static_cast<year_type>(*current_year);
+ year_type the_year = year ? *year : year_type(CURRENT_DATE().year());
month_type the_month = month ? *month : date_t::month_type(1);
- day_type the_day = day ? *day : date_t::day_type(1);
+ day_type the_day = day ? *day : date_t::day_type(1);
#if !defined(NO_ASSERTS)
if (day)
@@ -344,18 +350,18 @@ date_t date_specifier_t::begin(const optional_year& current_year) const
// wday in that month; if the year is set, then in that year.
return gregorian::date(static_cast<date_t::year_type>(the_year),
- static_cast<date_t::month_type>(the_month),
- static_cast<date_t::day_type>(the_day));
+ static_cast<date_t::month_type>(the_month),
+ static_cast<date_t::day_type>(the_day));
}
-date_t date_specifier_t::end(const optional_year& current_year) const
+date_t date_specifier_t::end() const
{
if (day || wday)
- return begin(current_year) + gregorian::days(1);
+ return begin() + gregorian::days(1);
else if (month)
- return begin(current_year) + gregorian::months(1);
+ return begin() + gregorian::months(1);
else if (year)
- return begin(current_year) + gregorian::years(1);
+ return begin() + gregorian::years(1);
else {
assert(false);
return date_t();
@@ -363,7 +369,7 @@ date_t date_specifier_t::end(const optional_year& current_year) const
}
std::ostream& operator<<(std::ostream& out,
- const date_duration_t& duration)
+ const date_duration_t& duration)
{
if (duration.quantum == date_duration_t::DAYS)
out << duration.length << " day(s)";
@@ -395,194 +401,200 @@ class date_parser_t
struct token_t
{
enum kind_t {
- UNKNOWN,
-
- TOK_DATE,
- TOK_INT,
- TOK_SLASH,
- TOK_DASH,
- TOK_DOT,
-
- TOK_A_YEAR,
- TOK_A_MONTH,
- TOK_A_WDAY,
-
- TOK_SINCE,
- TOK_UNTIL,
- TOK_IN,
- TOK_THIS,
- TOK_NEXT,
- TOK_LAST,
- TOK_EVERY,
-
- TOK_TODAY,
- TOK_TOMORROW,
- TOK_YESTERDAY,
-
- TOK_YEAR,
- TOK_QUARTER,
- TOK_MONTH,
- TOK_WEEK,
- TOK_DAY,
-
- TOK_YEARLY,
- TOK_QUARTERLY,
- TOK_BIMONTHLY,
- TOK_MONTHLY,
- TOK_BIWEEKLY,
- TOK_WEEKLY,
- TOK_DAILY,
-
- TOK_YEARS,
- TOK_QUARTERS,
- TOK_MONTHS,
- TOK_WEEKS,
- TOK_DAYS,
-
- END_REACHED
+ UNKNOWN,
+
+ TOK_DATE,
+ TOK_INT,
+ TOK_SLASH,
+ TOK_DASH,
+ TOK_DOT,
+
+ TOK_A_YEAR,
+ TOK_A_MONTH,
+ TOK_A_WDAY,
+
+ TOK_AGO,
+ TOK_HENCE,
+ TOK_SINCE,
+ TOK_UNTIL,
+ TOK_IN,
+ TOK_THIS,
+ TOK_NEXT,
+ TOK_LAST,
+ TOK_EVERY,
+
+ TOK_TODAY,
+ TOK_TOMORROW,
+ TOK_YESTERDAY,
+
+ TOK_YEAR,
+ TOK_QUARTER,
+ TOK_MONTH,
+ TOK_WEEK,
+ TOK_DAY,
+
+ TOK_YEARLY,
+ TOK_QUARTERLY,
+ TOK_BIMONTHLY,
+ TOK_MONTHLY,
+ TOK_BIWEEKLY,
+ TOK_WEEKLY,
+ TOK_DAILY,
+
+ TOK_YEARS,
+ TOK_QUARTERS,
+ TOK_MONTHS,
+ TOK_WEEKS,
+ TOK_DAYS,
+
+ END_REACHED
} kind;
typedef variant<unsigned short,
- string,
- date_specifier_t::year_type,
- date_time::months_of_year,
- date_time::weekdays,
- date_specifier_t> content_t;
+ string,
+ date_specifier_t::year_type,
+ date_time::months_of_year,
+ date_time::weekdays,
+ date_specifier_t> content_t;
optional<content_t> value;
explicit token_t(kind_t _kind = UNKNOWN,
- const optional<content_t>& _value =
- content_t(empty_string))
- : kind(_kind), value(_value) {
- TRACE_CTOR(date_parser_t::lexer_t::token_t, "");
+ const optional<content_t>& _value =
+ content_t(empty_string))
+ : kind(_kind), value(_value) {
+ TRACE_CTOR(date_parser_t::lexer_t::token_t, "");
}
token_t(const token_t& tok)
- : kind(tok.kind), value(tok.value) {
- TRACE_CTOR(date_parser_t::lexer_t::token_t, "copy");
+ : kind(tok.kind), value(tok.value) {
+ TRACE_CTOR(date_parser_t::lexer_t::token_t, "copy");
}
~token_t() throw() {
- TRACE_DTOR(date_parser_t::lexer_t::token_t);
+ TRACE_DTOR(date_parser_t::lexer_t::token_t);
}
token_t& operator=(const token_t& tok) {
- if (this != &tok) {
- kind = tok.kind;
- value = tok.value;
- }
- return *this;
+ if (this != &tok) {
+ kind = tok.kind;
+ value = tok.value;
+ }
+ return *this;
}
operator bool() const {
- return kind != END_REACHED;
+ return kind != END_REACHED;
}
string to_string() const {
- std::ostringstream out;
-
- switch (kind) {
- case UNKNOWN:
- out << boost::get<string>(*value);
- break;
- case TOK_DATE:
- return boost::get<date_specifier_t>(*value).to_string();
- case TOK_INT:
- out << boost::get<unsigned short>(*value);
- break;
- case TOK_SLASH: return "/";
- case TOK_DASH: return "-";
- case TOK_DOT: return ".";
- case TOK_A_YEAR:
- out << boost::get<date_specifier_t::year_type>(*value);
- break;
- case TOK_A_MONTH:
- out << date_specifier_t::month_type
- (boost::get<date_time::months_of_year>(*value));
- break;
- case TOK_A_WDAY:
- out << date_specifier_t::day_of_week_type
- (boost::get<date_time::weekdays>(*value));
- break;
- case TOK_SINCE: return "since";
- case TOK_UNTIL: return "until";
- case TOK_IN: return "in";
- case TOK_THIS: return "this";
- case TOK_NEXT: return "next";
- case TOK_LAST: return "last";
- case TOK_EVERY: return "every";
- case TOK_TODAY: return "today";
- case TOK_TOMORROW: return "tomorrow";
- case TOK_YESTERDAY: return "yesterday";
- case TOK_YEAR: return "year";
- case TOK_QUARTER: return "quarter";
- case TOK_MONTH: return "month";
- case TOK_WEEK: return "week";
- case TOK_DAY: return "day";
- case TOK_YEARLY: return "yearly";
- case TOK_QUARTERLY: return "quarterly";
- case TOK_BIMONTHLY: return "bimonthly";
- case TOK_MONTHLY: return "monthly";
- case TOK_BIWEEKLY: return "biweekly";
- case TOK_WEEKLY: return "weekly";
- case TOK_DAILY: return "daily";
- case TOK_YEARS: return "years";
- case TOK_QUARTERS: return "quarters";
- case TOK_MONTHS: return "months";
- case TOK_WEEKS: return "weeks";
- case TOK_DAYS: return "days";
- case END_REACHED: return "<EOF>";
- default:
- assert(false);
- return empty_string;
- }
-
- return out.str();
+ std::ostringstream out;
+
+ switch (kind) {
+ case UNKNOWN:
+ out << boost::get<string>(*value);
+ break;
+ case TOK_DATE:
+ return boost::get<date_specifier_t>(*value).to_string();
+ case TOK_INT:
+ out << boost::get<unsigned short>(*value);
+ break;
+ case TOK_SLASH: return "/";
+ case TOK_DASH: return "-";
+ case TOK_DOT: return ".";
+ case TOK_A_YEAR:
+ out << boost::get<date_specifier_t::year_type>(*value);
+ break;
+ case TOK_A_MONTH:
+ out << date_specifier_t::month_type
+ (boost::get<date_time::months_of_year>(*value));
+ break;
+ case TOK_A_WDAY:
+ 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";
+ case TOK_THIS: return "this";
+ case TOK_NEXT: return "next";
+ case TOK_LAST: return "last";
+ case TOK_EVERY: return "every";
+ case TOK_TODAY: return "today";
+ case TOK_TOMORROW: return "tomorrow";
+ case TOK_YESTERDAY: return "yesterday";
+ case TOK_YEAR: return "year";
+ case TOK_QUARTER: return "quarter";
+ case TOK_MONTH: return "month";
+ case TOK_WEEK: return "week";
+ case TOK_DAY: return "day";
+ case TOK_YEARLY: return "yearly";
+ case TOK_QUARTERLY: return "quarterly";
+ case TOK_BIMONTHLY: return "bimonthly";
+ case TOK_MONTHLY: return "monthly";
+ case TOK_BIWEEKLY: return "biweekly";
+ case TOK_WEEKLY: return "weekly";
+ case TOK_DAILY: return "daily";
+ case TOK_YEARS: return "years";
+ case TOK_QUARTERS: return "quarters";
+ case TOK_MONTHS: return "months";
+ case TOK_WEEKS: return "weeks";
+ case TOK_DAYS: return "days";
+ case END_REACHED: return "<EOF>";
+ default:
+ assert(false);
+ return empty_string;
+ }
+
+ return out.str();
}
void dump(std::ostream& out) const {
- switch (kind) {
- case UNKNOWN: out << "UNKNOWN"; break;
- case TOK_DATE: out << "TOK_DATE"; break;
- case TOK_INT: out << "TOK_INT"; break;
- case TOK_SLASH: out << "TOK_SLASH"; break;
- case TOK_DASH: out << "TOK_DASH"; break;
- case TOK_DOT: out << "TOK_DOT"; break;
- 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_SINCE: out << "TOK_SINCE"; break;
- case TOK_UNTIL: out << "TOK_UNTIL"; break;
- case TOK_IN: out << "TOK_IN"; break;
- case TOK_THIS: out << "TOK_THIS"; break;
- case TOK_NEXT: out << "TOK_NEXT"; break;
- case TOK_LAST: out << "TOK_LAST"; break;
- case TOK_EVERY: out << "TOK_EVERY"; break;
- case TOK_TODAY: out << "TOK_TODAY"; break;
- case TOK_TOMORROW: out << "TOK_TOMORROW"; break;
- case TOK_YESTERDAY: out << "TOK_YESTERDAY"; break;
- case TOK_YEAR: out << "TOK_YEAR"; break;
- case TOK_QUARTER: out << "TOK_QUARTER"; break;
- case TOK_MONTH: out << "TOK_MONTH"; break;
- case TOK_WEEK: out << "TOK_WEEK"; break;
- case TOK_DAY: out << "TOK_DAY"; break;
- case TOK_YEARLY: out << "TOK_YEARLY"; break;
- case TOK_QUARTERLY: out << "TOK_QUARTERLY"; break;
- case TOK_BIMONTHLY: out << "TOK_BIMONTHLY"; break;
- case TOK_MONTHLY: out << "TOK_MONTHLY"; break;
- case TOK_BIWEEKLY: out << "TOK_BIWEEKLY"; break;
- case TOK_WEEKLY: out << "TOK_WEEKLY"; break;
- case TOK_DAILY: out << "TOK_DAILY"; break;
- case TOK_YEARS: out << "TOK_YEARS"; break;
- case TOK_QUARTERS: out << "TOK_QUARTERS"; break;
- case TOK_MONTHS: out << "TOK_MONTHS"; break;
- case TOK_WEEKS: out << "TOK_WEEKS"; break;
- case TOK_DAYS: out << "TOK_DAYS"; break;
- case END_REACHED: out << "END_REACHED"; break;
- default:
- assert(false);
- break;
- }
+ switch (kind) {
+ case UNKNOWN: out << "UNKNOWN"; break;
+ case TOK_DATE: out << "TOK_DATE"; break;
+ case TOK_INT: out << "TOK_INT"; break;
+ case TOK_SLASH: out << "TOK_SLASH"; break;
+ case TOK_DASH: out << "TOK_DASH"; break;
+ case TOK_DOT: out << "TOK_DOT"; break;
+ 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;
+ case TOK_THIS: out << "TOK_THIS"; break;
+ case TOK_NEXT: out << "TOK_NEXT"; break;
+ case TOK_LAST: out << "TOK_LAST"; break;
+ case TOK_EVERY: out << "TOK_EVERY"; break;
+ case TOK_TODAY: out << "TOK_TODAY"; break;
+ case TOK_TOMORROW: out << "TOK_TOMORROW"; break;
+ case TOK_YESTERDAY: out << "TOK_YESTERDAY"; break;
+ case TOK_YEAR: out << "TOK_YEAR"; break;
+ case TOK_QUARTER: out << "TOK_QUARTER"; break;
+ case TOK_MONTH: out << "TOK_MONTH"; break;
+ case TOK_WEEK: out << "TOK_WEEK"; break;
+ case TOK_DAY: out << "TOK_DAY"; break;
+ case TOK_YEARLY: out << "TOK_YEARLY"; break;
+ case TOK_QUARTERLY: out << "TOK_QUARTERLY"; break;
+ case TOK_BIMONTHLY: out << "TOK_BIMONTHLY"; break;
+ case TOK_MONTHLY: out << "TOK_MONTHLY"; break;
+ case TOK_BIWEEKLY: out << "TOK_BIWEEKLY"; break;
+ case TOK_WEEKLY: out << "TOK_WEEKLY"; break;
+ case TOK_DAILY: out << "TOK_DAILY"; break;
+ case TOK_YEARS: out << "TOK_YEARS"; break;
+ case TOK_QUARTERS: out << "TOK_QUARTERS"; break;
+ case TOK_MONTHS: out << "TOK_MONTHS"; break;
+ case TOK_WEEKS: out << "TOK_WEEKS"; break;
+ case TOK_DAYS: out << "TOK_DAYS"; break;
+ case END_REACHED: out << "END_REACHED"; break;
+ default:
+ assert(false);
+ break;
+ }
}
void unexpected();
@@ -592,14 +604,14 @@ class date_parser_t
token_t token_cache;
lexer_t(string::const_iterator _begin,
- string::const_iterator _end)
+ string::const_iterator _end)
: begin(_begin), end(_end)
{
TRACE_CTOR(date_parser_t::lexer_t, "");
}
lexer_t(const lexer_t& lexer)
: begin(lexer.begin), end(lexer.end),
- token_cache(lexer.token_cache)
+ token_cache(lexer.token_cache)
{
TRACE_CTOR(date_parser_t::lexer_t, "copy");
}
@@ -614,7 +626,7 @@ class date_parser_t
}
token_t peek_token() {
if (token_cache.kind == token_t::UNKNOWN)
- token_cache = next_token();
+ token_cache = next_token();
return token_cache;
}
};
@@ -642,19 +654,184 @@ private:
};
void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok,
- date_specifier_t& specifier)
+ 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 =
@@ -667,6 +844,16 @@ void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok,
(boost::get<date_time::weekdays>(*tok.value));
break;
+ case lexer_t::token_t::TOK_TODAY:
+ specifier = date_specifier_t(today);
+ break;
+ case lexer_t::token_t::TOK_TOMORROW:
+ specifier = date_specifier_t(today + gregorian::days(1));
+ break;
+ case lexer_t::token_t::TOK_YESTERDAY:
+ specifier = date_specifier_t(today - gregorian::days(1));
+ break;
+
default:
tok.unexpected();
break;
@@ -680,94 +867,86 @@ date_interval_t date_parser_t::parse()
optional<date_specifier_t> inclusion_specifier;
date_interval_t period;
- date_t today = CURRENT_DATE();
- bool end_inclusive = false;
+ date_t today = CURRENT_DATE();
+ bool end_inclusive = false;
for (lexer_t::token_t tok = lexer.next_token();
tok.kind != lexer_t::token_t::END_REACHED;
tok = lexer.next_token()) {
switch (tok.kind) {
-#if 0
- case lexer_t::token_t::TOK_INT:
- // jww (2009-11-18): NYI
- assert(! "Need to allow for expressions like \"4 months ago\"");
- tok.unexpected();
- break;
-#endif
-
case lexer_t::token_t::TOK_DATE:
if (! inclusion_specifier)
- inclusion_specifier = date_specifier_t();
+ inclusion_specifier = date_specifier_t();
determine_when(tok, *inclusion_specifier);
break;
case lexer_t::token_t::TOK_INT:
if (! inclusion_specifier)
- inclusion_specifier = date_specifier_t();
+ inclusion_specifier = date_specifier_t();
determine_when(tok, *inclusion_specifier);
break;
case lexer_t::token_t::TOK_A_YEAR:
if (! inclusion_specifier)
- inclusion_specifier = date_specifier_t();
+ inclusion_specifier = date_specifier_t();
determine_when(tok, *inclusion_specifier);
break;
case lexer_t::token_t::TOK_A_MONTH:
if (! inclusion_specifier)
- inclusion_specifier = date_specifier_t();
+ inclusion_specifier = date_specifier_t();
determine_when(tok, *inclusion_specifier);
break;
case lexer_t::token_t::TOK_A_WDAY:
if (! inclusion_specifier)
- inclusion_specifier = date_specifier_t();
+ inclusion_specifier = date_specifier_t();
determine_when(tok, *inclusion_specifier);
break;
case lexer_t::token_t::TOK_DASH:
if (inclusion_specifier) {
- since_specifier = inclusion_specifier;
- until_specifier = date_specifier_t();
- inclusion_specifier = none;
+ since_specifier = inclusion_specifier;
+ until_specifier = date_specifier_t();
+ inclusion_specifier = none;
- tok = lexer.next_token();
- determine_when(tok, *until_specifier);
+ tok = lexer.next_token();
+ determine_when(tok, *until_specifier);
- // The dash operator is special: it has an _inclusive_ end.
- end_inclusive = true;
+ // The dash operator is special: it has an _inclusive_ end.
+ end_inclusive = true;
} else {
- tok.unexpected();
+ tok.unexpected();
}
break;
case lexer_t::token_t::TOK_SINCE:
if (since_specifier) {
- tok.unexpected();
+ tok.unexpected();
} else {
- since_specifier = date_specifier_t();
- tok = lexer.next_token();
- determine_when(tok, *since_specifier);
+ since_specifier = date_specifier_t();
+ tok = lexer.next_token();
+ determine_when(tok, *since_specifier);
}
break;
case lexer_t::token_t::TOK_UNTIL:
if (until_specifier) {
- tok.unexpected();
+ tok.unexpected();
} else {
- until_specifier = date_specifier_t();
- tok = lexer.next_token();
- determine_when(tok, *until_specifier);
+ until_specifier = date_specifier_t();
+ tok = lexer.next_token();
+ determine_when(tok, *until_specifier);
}
break;
case lexer_t::token_t::TOK_IN:
if (inclusion_specifier) {
- tok.unexpected();
+ tok.unexpected();
} else {
- inclusion_specifier = date_specifier_t();
- tok = lexer.next_token();
- determine_when(tok, *inclusion_specifier);
+ inclusion_specifier = date_specifier_t();
+ tok = lexer.next_token();
+ determine_when(tok, *inclusion_specifier);
}
break;
@@ -776,92 +955,143 @@ date_interval_t date_parser_t::parse()
case lexer_t::token_t::TOK_LAST: {
int8_t adjust = 0;
if (tok.kind == lexer_t::token_t::TOK_NEXT)
- adjust = 1;
+ adjust = 1;
else if (tok.kind == lexer_t::token_t::TOK_LAST)
- adjust = -1;
+ adjust = -1;
tok = lexer.next_token();
switch (tok.kind) {
- case lexer_t::token_t::TOK_INT:
- // jww (2009-11-18): Allow things like "last 5 weeks"
- assert(! "Need to allow for expressions like \"last 5 weeks\"");
- tok.unexpected();
- break;
+ case lexer_t::token_t::TOK_INT: {
+ unsigned short amount = boost::get<unsigned short>(*tok.value);
+
+ 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:
+ base += gregorian::years(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_QUARTERS:
+ base += gregorian::months(amount * adjust * 3);
+ break;
+ case lexer_t::token_t::TOK_MONTHS:
+ base += gregorian::months(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_WEEKS:
+ base += gregorian::weeks(amount * adjust);
+ break;
+ case lexer_t::token_t::TOK_DAYS:
+ base += gregorian::days(amount * adjust);
+ break;
+ default:
+ tok.unexpected();
+ break;
+ }
+
+ if (adjust >= 0) {
+ date_t temp = base;
+ base = end;
+ end = temp;
+ }
+
+ since_specifier = date_specifier_t(base);
+ until_specifier = date_specifier_t(end);
+ break;
+ }
case lexer_t::token_t::TOK_A_MONTH: {
- inclusion_specifier = date_specifier_t();
- determine_when(tok, *inclusion_specifier);
-
- date_t temp(today.year(), *inclusion_specifier->month, 1);
- temp += gregorian::years(adjust);
- inclusion_specifier =
- date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
- temp.month());
- break;
+ inclusion_specifier = date_specifier_t();
+ determine_when(tok, *inclusion_specifier);
+
+ date_t temp(today.year(), *inclusion_specifier->month, 1);
+ temp += gregorian::years(adjust);
+ inclusion_specifier =
+ date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
+ temp.month());
+ break;
}
case lexer_t::token_t::TOK_A_WDAY: {
- inclusion_specifier = date_specifier_t();
- determine_when(tok, *inclusion_specifier);
-
- date_t temp =
- date_duration_t::find_nearest(today, date_duration_t::WEEKS);
- while (temp.day_of_week() != inclusion_specifier->wday)
- temp += gregorian::days(1);
- temp += gregorian::days(7 * adjust);
- inclusion_specifier = date_specifier_t(temp);
- break;
+ inclusion_specifier = date_specifier_t();
+ determine_when(tok, *inclusion_specifier);
+
+ date_t temp =
+ date_duration_t::find_nearest(today, date_duration_t::WEEKS);
+ while (temp.day_of_week() != inclusion_specifier->wday)
+ temp += gregorian::days(1);
+ temp += gregorian::days(7 * adjust);
+ inclusion_specifier = date_specifier_t(temp);
+ break;
}
case lexer_t::token_t::TOK_YEAR: {
- date_t temp(today);
- temp += gregorian::years(adjust);
- inclusion_specifier =
- date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()));
- break;
+ date_t temp(today);
+ temp += gregorian::years(adjust);
+ inclusion_specifier =
+ date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()));
+ break;
}
case lexer_t::token_t::TOK_QUARTER: {
- date_t temp =
- date_duration_t::find_nearest(today, date_duration_t::QUARTERS);
- temp += gregorian::months(3 * adjust);
- inclusion_specifier =
- date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
- temp.month());
-#if 0
- period.duration = date_duration_t(date_duration_t::QUARTERS, 1);
-#endif
- break;
+ 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);
+ }
+ since_specifier = date_specifier_t(adjust < 0 ? temp : base);
+ until_specifier = date_specifier_t(adjust < 0 ? base : temp);
+ break;
}
case lexer_t::token_t::TOK_WEEK: {
- date_t temp =
- date_duration_t::find_nearest(today, date_duration_t::WEEKS);
- temp += gregorian::days(7 * adjust);
- inclusion_specifier = date_specifier_t(today);
-#if 0
- period.duration = date_duration_t(date_duration_t::WEEKS, 1);
-#endif
- break;
+ 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);
+ }
+ since_specifier = date_specifier_t(adjust < 0 ? temp : base);
+ until_specifier = date_specifier_t(adjust < 0 ? base : temp);
+ break;
}
case lexer_t::token_t::TOK_DAY: {
- date_t temp(today);
- temp += gregorian::days(adjust);
- inclusion_specifier = date_specifier_t(temp);
- break;
+ date_t temp(today);
+ temp += gregorian::days(adjust);
+ inclusion_specifier = date_specifier_t(temp);
+ break;
}
default:
case lexer_t::token_t::TOK_MONTH: {
- date_t temp(today);
- temp += gregorian::months(adjust);
- inclusion_specifier =
- date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
- temp.month());
- break;
+ date_t temp(today);
+ temp += gregorian::months(adjust);
+ inclusion_specifier =
+ date_specifier_t(static_cast<date_specifier_t::year_type>(temp.year()),
+ temp.month());
+ break;
}
}
+ break;
}
case lexer_t::token_t::TOK_TODAY:
@@ -876,50 +1106,50 @@ date_interval_t date_parser_t::parse()
case lexer_t::token_t::TOK_EVERY:
tok = lexer.next_token();
- if (tok == lexer_t::token_t::TOK_INT) {
- int quantity = boost::get<unsigned short>(*tok.value);
- tok = lexer.next_token();
- switch (tok.kind) {
- case lexer_t::token_t::TOK_YEARS:
- period.duration = date_duration_t(date_duration_t::YEARS, quantity);
- break;
- case lexer_t::token_t::TOK_QUARTERS:
- period.duration = date_duration_t(date_duration_t::QUARTERS, quantity);
- break;
- case lexer_t::token_t::TOK_MONTHS:
- period.duration = date_duration_t(date_duration_t::MONTHS, quantity);
- break;
- case lexer_t::token_t::TOK_WEEKS:
- period.duration = date_duration_t(date_duration_t::WEEKS, quantity);
- break;
- case lexer_t::token_t::TOK_DAYS:
- period.duration = date_duration_t(date_duration_t::DAYS, quantity);
- break;
- default:
- tok.unexpected();
- break;
- }
+ if (tok.kind == lexer_t::token_t::TOK_INT) {
+ int quantity = boost::get<unsigned short>(*tok.value);
+ tok = lexer.next_token();
+ switch (tok.kind) {
+ case lexer_t::token_t::TOK_YEARS:
+ period.duration = date_duration_t(date_duration_t::YEARS, quantity);
+ break;
+ case lexer_t::token_t::TOK_QUARTERS:
+ period.duration = date_duration_t(date_duration_t::QUARTERS, quantity);
+ break;
+ case lexer_t::token_t::TOK_MONTHS:
+ period.duration = date_duration_t(date_duration_t::MONTHS, quantity);
+ break;
+ case lexer_t::token_t::TOK_WEEKS:
+ period.duration = date_duration_t(date_duration_t::WEEKS, quantity);
+ break;
+ case lexer_t::token_t::TOK_DAYS:
+ period.duration = date_duration_t(date_duration_t::DAYS, quantity);
+ break;
+ default:
+ tok.unexpected();
+ break;
+ }
} else {
- switch (tok.kind) {
- case lexer_t::token_t::TOK_YEAR:
- period.duration = date_duration_t(date_duration_t::YEARS, 1);
- break;
- case lexer_t::token_t::TOK_QUARTER:
- period.duration = date_duration_t(date_duration_t::QUARTERS, 1);
- break;
- case lexer_t::token_t::TOK_MONTH:
- period.duration = date_duration_t(date_duration_t::MONTHS, 1);
- break;
- case lexer_t::token_t::TOK_WEEK:
- period.duration = date_duration_t(date_duration_t::WEEKS, 1);
- break;
- case lexer_t::token_t::TOK_DAY:
- period.duration = date_duration_t(date_duration_t::DAYS, 1);
- break;
- default:
- tok.unexpected();
- break;
- }
+ switch (tok.kind) {
+ case lexer_t::token_t::TOK_YEAR:
+ period.duration = date_duration_t(date_duration_t::YEARS, 1);
+ break;
+ case lexer_t::token_t::TOK_QUARTER:
+ period.duration = date_duration_t(date_duration_t::QUARTERS, 1);
+ break;
+ case lexer_t::token_t::TOK_MONTH:
+ period.duration = date_duration_t(date_duration_t::MONTHS, 1);
+ break;
+ case lexer_t::token_t::TOK_WEEK:
+ period.duration = date_duration_t(date_duration_t::WEEKS, 1);
+ break;
+ case lexer_t::token_t::TOK_DAY:
+ period.duration = date_duration_t(date_duration_t::DAYS, 1);
+ break;
+ default:
+ tok.unexpected();
+ break;
+ }
}
break;
@@ -983,13 +1213,13 @@ void date_interval_t::resolve_end()
if (start && ! end_of_duration) {
end_of_duration = duration->add(*start);
DEBUG("times.interval",
- "stabilize: end_of_duration = " << *end_of_duration);
+ "stabilize: end_of_duration = " << *end_of_duration);
}
if (finish && *end_of_duration > *finish) {
end_of_duration = finish;
DEBUG("times.interval",
- "stabilize: end_of_duration reset to end: " << *end_of_duration);
+ "stabilize: end_of_duration reset to end: " << *end_of_duration);
}
if (start && ! next) {
@@ -1009,9 +1239,9 @@ date_t date_duration_t::find_nearest(const date_t& date, skip_quantum_t skip)
case date_duration_t::QUARTERS:
result = date_t(date.year(), date.month(), 1);
while (result.month() != gregorian::Jan &&
- result.month() != gregorian::Apr &&
- result.month() != gregorian::Jul &&
- result.month() != gregorian::Oct)
+ result.month() != gregorian::Apr &&
+ result.month() != gregorian::Jul &&
+ result.month() != gregorian::Oct)
result -= gregorian::months(1);
break;
case date_duration_t::MONTHS:
@@ -1043,7 +1273,7 @@ void date_interval_t::stabilize(const optional<date_t>& date)
DEBUG("times.interval", "stabilize: date passed, but not aligned");
if (duration) {
DEBUG("times.interval",
- "stabilize: aligning with a duration: " << *duration);
+ "stabilize: aligning with a duration: " << *duration);
// The interval object has not been seeded with a start date yet, so
// find the nearest period before on on date which fits, if possible.
@@ -1052,77 +1282,72 @@ void date_interval_t::stabilize(const optional<date_t>& date)
// want a date early enough that the range will be correct, but late
// enough that we don't spend hundreds of thousands of loops skipping
// through time.
- optional<date_t> initial_start = start ? start : begin(date->year());
- optional<date_t> initial_finish = finish ? finish : end(date->year());
+ optional<date_t> initial_start = start ? start : begin();
+ optional<date_t> initial_finish = finish ? finish : end();
#if defined(DEBUG_ON)
if (initial_start)
- DEBUG("times.interval",
- "stabilize: initial_start = " << *initial_start);
+ DEBUG("times.interval",
+ "stabilize: initial_start = " << *initial_start);
if (initial_finish)
- DEBUG("times.interval",
- "stabilize: initial_finish = " << *initial_finish);
+ DEBUG("times.interval",
+ "stabilize: initial_finish = " << *initial_finish);
#endif
date_t when = start ? *start : *date;
if (duration->quantum == date_duration_t::MONTHS ||
- duration->quantum == date_duration_t::QUARTERS ||
- duration->quantum == date_duration_t::YEARS) {
- DEBUG("times.interval",
- "stabilize: monthly, quarterly or yearly duration");
- start = date_duration_t::find_nearest(when, duration->quantum);
+ duration->quantum == date_duration_t::QUARTERS ||
+ duration->quantum == date_duration_t::YEARS) {
+ DEBUG("times.interval",
+ "stabilize: monthly, quarterly or yearly duration");
+ start = date_duration_t::find_nearest(when, duration->quantum);
} else {
- DEBUG("times.interval", "stabilize: daily or weekly duration");
- start = date_duration_t::find_nearest(when - gregorian::days(400),
- duration->quantum);
+ DEBUG("times.interval", "stabilize: daily or weekly duration");
+ start = date_duration_t::find_nearest(when - gregorian::days(400),
+ duration->quantum);
}
DEBUG("times.interval",
- "stabilize: beginning start date = " << *start);
+ "stabilize: beginning start date = " << *start);
while (*start < *date) {
- date_interval_t next_interval(*this);
- ++next_interval;
-
- if (next_interval.start && *next_interval.start < *date) {
- *this = next_interval;
- } else {
- end_of_duration = none;
- next = none;
- break;
- }
+ date_interval_t next_interval(*this);
+ ++next_interval;
+
+ if (next_interval.start && *next_interval.start < *date) {
+ *this = next_interval;
+ } else {
+ end_of_duration = none;
+ next = none;
+ break;
+ }
}
DEBUG("times.interval", "stabilize: proposed start date = " << *start);
if (initial_start && (! start || *start < *initial_start)) {
- // Using the discovered start, find the end of the period
- resolve_end();
+ // Using the discovered start, find the end of the period
+ resolve_end();
- start = initial_start;
- DEBUG("times.interval", "stabilize: start reset to initial start");
+ start = initial_start;
+ DEBUG("times.interval", "stabilize: start reset to initial start");
}
if (initial_finish && (! finish || *finish > *initial_finish)) {
- finish = initial_finish;
- DEBUG("times.interval", "stabilize: finish reset to initial finish");
+ finish = initial_finish;
+ DEBUG("times.interval", "stabilize: finish reset to initial finish");
}
#if defined(DEBUG_ON)
if (start)
- DEBUG("times.interval", "stabilize: final start = " << *start);
+ DEBUG("times.interval", "stabilize: final start = " << *start);
if (finish)
- DEBUG("times.interval", "stabilize: final finish = " << *finish);
+ DEBUG("times.interval", "stabilize: final finish = " << *finish);
#endif
}
else if (range) {
- if (date) {
- start = range->begin(date->year());
- finish = range->end(date->year());
- } else {
- start = range->begin();
- finish = range->end();
- }
+ start = range->begin();
+ finish = range->end();
}
aligned = true;
}
@@ -1134,7 +1359,7 @@ void date_interval_t::stabilize(const optional<date_t>& date)
if (! start && ! finish)
throw_(date_error,
- _("Invalid date interval: neither start, nor finish, nor duration"));
+ _("Invalid date interval: neither start, nor finish, nor duration"));
} else {
resolve_end();
}
@@ -1146,7 +1371,7 @@ bool date_interval_t::find_period(const date_t& date)
if (finish && date > *finish) {
DEBUG("times.interval",
- "false: date [" << date << "] > finish [" << *finish << "]");
+ "false: date [" << date << "] > finish [" << *finish << "]");
return false;
}
@@ -1155,15 +1380,15 @@ bool date_interval_t::find_period(const date_t& date)
}
else if (date < *start) {
DEBUG("times.interval",
- "false: date [" << date << "] < start [" << *start << "]");
+ "false: date [" << date << "] < start [" << *start << "]");
return false;
}
if (end_of_duration) {
if (date < *end_of_duration) {
DEBUG("times.interval",
- "true: date [" << date << "] < end_of_duration ["
- << *end_of_duration << "]");
+ "true: date [" << date << "] < end_of_duration ["
+ << *end_of_duration << "]");
return true;
}
} else {
@@ -1185,17 +1410,19 @@ bool date_interval_t::find_period(const date_t& date)
while (date >= scan && (! finish || scan < *finish)) {
if (date < end_of_scan) {
- start = scan;
+ start = scan;
end_of_duration = end_of_scan;
- next = none;
+ next = none;
- DEBUG("times.interval", "true: start = " << *start);
+ DEBUG("times.interval", "true: start = " << *start);
DEBUG("times.interval", "true: end_of_duration = " << *end_of_duration);
+ resolve_end();
+
return true;
}
- scan = duration->add(scan);
+ scan = duration->add(scan);
end_of_scan = duration->add(scan);
}
@@ -1211,7 +1438,7 @@ date_interval_t& date_interval_t::operator++()
if (! duration)
throw_(date_error,
- _("Cannot increment a date interval without a duration"));
+ _("Cannot increment a date interval without a duration"));
assert(next);
@@ -1228,7 +1455,7 @@ date_interval_t& date_interval_t::operator++()
return *this;
}
-void date_interval_t::dump(std::ostream& out, optional_year current_year)
+void date_interval_t::dump(std::ostream& out)
{
out << _("--- Before stabilization ---") << std::endl;
@@ -1242,7 +1469,11 @@ void date_interval_t::dump(std::ostream& out, optional_year current_year)
if (duration)
out << _("duration: ") << duration->to_string() << std::endl;
- stabilize(begin(current_year));
+ optional<date_t> when(begin());
+ if (! when)
+ when = CURRENT_DATE();
+
+ stabilize(when);
out << std::endl
<< _("--- After stabilization ---") << std::endl;
@@ -1317,18 +1548,18 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
try {
date_traits_t traits;
- date_t when = parse_date_mask(possible_date.c_str(), none, &traits);
+ date_t when = parse_date_mask(possible_date.c_str(), &traits);
if (! when.is_not_a_date()) {
- begin = i;
- return token_t(token_t::TOK_DATE,
- token_t::content_t(date_specifier_t(when, traits)));
+ begin = i;
+ return token_t(token_t::TOK_DATE,
+ token_t::content_t(date_specifier_t(when, traits)));
}
}
catch (date_error&) {
if (contains(possible_date, "/") ||
- contains(possible_date, "-") ||
- contains(possible_date, "."))
- throw;
+ contains(possible_date, "-") ||
+ contains(possible_date, "."))
+ throw;
}
}
@@ -1337,85 +1568,89 @@ date_parser_t::lexer_t::token_t date_parser_t::lexer_t::next_token()
string term;
bool alnum = std::isalnum(*begin);
for (; (begin != end && ! std::isspace(*begin) &&
- ((alnum && static_cast<bool>(std::isalnum(*begin))) ||
- (! alnum && ! static_cast<bool>(std::isalnum(*begin))))); begin++)
+ ((alnum && static_cast<bool>(std::isalnum(*begin))) ||
+ (! alnum && ! static_cast<bool>(std::isalnum(*begin))))); begin++)
term.push_back(*begin);
if (! term.empty()) {
if (std::isdigit(term[0])) {
if (term.length() == 4)
- return token_t(token_t::TOK_A_YEAR,
- token_t::content_t
- (lexical_cast<date_specifier_t::year_type>(term)));
+ return token_t(token_t::TOK_A_YEAR,
+ token_t::content_t
+ (lexical_cast<date_specifier_t::year_type>(term)));
else
- return token_t(token_t::TOK_INT,
- token_t::content_t(lexical_cast<unsigned short>(term)));
+ return token_t(token_t::TOK_INT,
+ token_t::content_t(lexical_cast<unsigned short>(term)));
}
else if (std::isalpha(term[0])) {
to_lower(term);
if (optional<date_time::months_of_year> month =
- string_to_month_of_year(term)) {
- return token_t(token_t::TOK_A_MONTH, token_t::content_t(*month));
+ string_to_month_of_year(term)) {
+ return token_t(token_t::TOK_A_MONTH, token_t::content_t(*month));
}
else if (optional<date_time::weekdays> wday =
- string_to_day_of_week(term)) {
- return token_t(token_t::TOK_A_WDAY, token_t::content_t(*wday));
+ 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);
+ return token_t(token_t::TOK_SINCE);
else if (term == _("to") || term == _("until"))
- return token_t(token_t::TOK_UNTIL);
+ return token_t(token_t::TOK_UNTIL);
else if (term == _("in"))
- return token_t(token_t::TOK_IN);
+ return token_t(token_t::TOK_IN);
else if (term == _("this"))
- return token_t(token_t::TOK_THIS);
+ return token_t(token_t::TOK_THIS);
else if (term == _("next"))
- return token_t(token_t::TOK_NEXT);
+ return token_t(token_t::TOK_NEXT);
else if (term == _("last"))
- return token_t(token_t::TOK_LAST);
+ return token_t(token_t::TOK_LAST);
else if (term == _("every"))
- return token_t(token_t::TOK_EVERY);
+ return token_t(token_t::TOK_EVERY);
else if (term == _("today"))
- return token_t(token_t::TOK_TODAY);
+ return token_t(token_t::TOK_TODAY);
else if (term == _("tomorrow"))
- return token_t(token_t::TOK_TOMORROW);
+ return token_t(token_t::TOK_TOMORROW);
else if (term == _("yesterday"))
- return token_t(token_t::TOK_YESTERDAY);
+ return token_t(token_t::TOK_YESTERDAY);
else if (term == _("year"))
- return token_t(token_t::TOK_YEAR);
+ return token_t(token_t::TOK_YEAR);
else if (term == _("quarter"))
- return token_t(token_t::TOK_QUARTER);
+ return token_t(token_t::TOK_QUARTER);
else if (term == _("month"))
- return token_t(token_t::TOK_MONTH);
+ return token_t(token_t::TOK_MONTH);
else if (term == _("week"))
- return token_t(token_t::TOK_WEEK);
+ return token_t(token_t::TOK_WEEK);
else if (term == _("day"))
- return token_t(token_t::TOK_DAY);
+ return token_t(token_t::TOK_DAY);
else if (term == _("yearly"))
- return token_t(token_t::TOK_YEARLY);
+ return token_t(token_t::TOK_YEARLY);
else if (term == _("quarterly"))
- return token_t(token_t::TOK_QUARTERLY);
+ return token_t(token_t::TOK_QUARTERLY);
else if (term == _("bimonthly"))
- return token_t(token_t::TOK_BIMONTHLY);
+ return token_t(token_t::TOK_BIMONTHLY);
else if (term == _("monthly"))
- return token_t(token_t::TOK_MONTHLY);
+ return token_t(token_t::TOK_MONTHLY);
else if (term == _("biweekly"))
- return token_t(token_t::TOK_BIWEEKLY);
+ return token_t(token_t::TOK_BIWEEKLY);
else if (term == _("weekly"))
- return token_t(token_t::TOK_WEEKLY);
+ return token_t(token_t::TOK_WEEKLY);
else if (term == _("daily"))
- return token_t(token_t::TOK_DAILY);
+ return token_t(token_t::TOK_DAILY);
else if (term == _("years"))
- return token_t(token_t::TOK_YEARS);
+ return token_t(token_t::TOK_YEARS);
else if (term == _("quarters"))
- return token_t(token_t::TOK_QUARTERS);
+ return token_t(token_t::TOK_QUARTERS);
else if (term == _("months"))
- return token_t(token_t::TOK_MONTHS);
+ return token_t(token_t::TOK_MONTHS);
else if (term == _("weeks"))
- return token_t(token_t::TOK_WEEKS);
+ return token_t(token_t::TOK_WEEKS);
else if (term == _("days"))
- return token_t(token_t::TOK_DAYS);
+ return token_t(token_t::TOK_DAYS);
}
else {
token_t::expected('\0', term[0]);
@@ -1462,12 +1697,12 @@ namespace {
typedef std::map<std::string, date_io_t *> date_io_map;
datetime_io_map temp_datetime_io;
- date_io_map temp_date_io;
+ date_io_map temp_date_io;
}
-std::string format_datetime(const datetime_t& when,
- const format_type_t format_type,
- const optional<const char *>& format)
+std::string format_datetime(const datetime_t& when,
+ const format_type_t format_type,
+ const optional<const char *>& format)
{
if (format_type == FMT_WRITTEN) {
return written_datetime_io->format(when);
@@ -1491,9 +1726,9 @@ std::string format_datetime(const datetime_t& when,
}
}
-std::string format_date(const date_t& when,
- const format_type_t format_type,
- const optional<const char *>& format)
+std::string format_date(const date_t& when,
+ const format_type_t format_type,
+ const optional<const char *>& format)
{
if (format_type == FMT_WRITTEN) {
return written_date_io->format(when);
@@ -1533,13 +1768,14 @@ void set_date_format(const char * format)
void set_input_date_format(const char * format)
{
- input_date_io.reset(new date_io_t(format, true));
+ readers.push_front(shared_ptr<date_io_t>(new date_io_t(format, true)));
}
void times_initialize()
{
if (! is_initialized) {
input_datetime_io.reset(new datetime_io_t("%Y/%m/%d %H:%M:%S", true));
+ timelog_datetime_io.reset(new datetime_io_t("%m/%d/%Y %H:%M:%S", true));
written_datetime_io.reset(new datetime_io_t("%Y/%m/%d %H:%M:%S", false));
written_date_io.reset(new date_io_t("%Y/%m/%d", false));
@@ -1560,6 +1796,7 @@ void times_shutdown()
{
if (is_initialized) {
input_datetime_io.reset();
+ timelog_datetime_io.reset();
input_date_io.reset();
written_datetime_io.reset();
written_date_io.reset();
diff --git a/src/times.h b/src/times.h
index 51cc8491..1ff08739 100644
--- a/src/times.h
+++ b/src/times.h
@@ -51,8 +51,8 @@ namespace ledger {
DECLARE_EXCEPTION(datetime_error, std::runtime_error);
DECLARE_EXCEPTION(date_error, std::runtime_error);
-typedef boost::posix_time::ptime datetime_t;
-typedef datetime_t::time_duration_type time_duration_t;
+typedef boost::posix_time::ptime datetime_t;
+typedef datetime_t::time_duration_type time_duration_t;
inline bool is_valid(const datetime_t& moment) {
return ! moment.is_not_a_date_time();
@@ -68,36 +68,32 @@ 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;
+extern date_time::weekdays start_of_week;
optional<date_time::weekdays>
string_to_day_of_week(const std::string& str);
optional<date_time::months_of_year>
string_to_month_of_year(const std::string& str);
-typedef optional<date_t::year_type> optional_year;
+datetime_t parse_datetime(const char * str);
-datetime_t parse_datetime(const char * str, optional_year current_year = none);
-
-inline datetime_t parse_datetime(const std::string& str,
- optional_year current_year = none) {
- return parse_datetime(str.c_str(), current_year);
+inline datetime_t parse_datetime(const std::string& str) {
+ return parse_datetime(str.c_str());
}
-date_t parse_date(const char * str, optional_year current_year = none);
+date_t parse_date(const char * str);
-inline date_t parse_date(const std::string& str,
- optional_year current_year = none) {
- return parse_date(str.c_str(), current_year);
+inline date_t parse_date(const std::string& str) {
+ return parse_date(str.c_str());
}
enum format_type_t {
@@ -105,18 +101,18 @@ enum format_type_t {
};
std::string format_datetime(const datetime_t& when,
- const format_type_t format_type = FMT_PRINTED,
- const optional<const char *>& format = none);
+ const format_type_t format_type = FMT_PRINTED,
+ const optional<const char *>& format = none);
void set_datetime_format(const char * format);
std::string format_date(const date_t& when,
- const format_type_t format_type = FMT_PRINTED,
- const optional<const char *>& format = none);
+ const format_type_t format_type = FMT_PRINTED,
+ const optional<const char *>& format = none);
void set_date_format(const char * format);
void set_input_date_format(const char * format);
inline void to_xml(std::ostream& out, const datetime_t& when,
- bool wrap = true)
+ bool wrap = true)
{
if (wrap) {
push_xml x(out, "datetime");
@@ -127,7 +123,7 @@ inline void to_xml(std::ostream& out, const datetime_t& when,
}
inline void to_xml(std::ostream& out, const date_t& when,
- bool wrap = true)
+ bool wrap = true)
{
if (wrap) {
push_xml x(out, "date");
@@ -144,8 +140,8 @@ struct date_traits_t
bool has_day;
date_traits_t(bool _has_year = false,
- bool _has_month = false,
- bool _has_day = false)
+ bool _has_month = false,
+ bool _has_day = false)
: has_year(_has_year), has_month(_has_month), has_day(_has_day) {
TRACE_CTOR(date_traits_t, "bool, bool, bool");
}
@@ -160,16 +156,16 @@ struct date_traits_t
}
date_traits_t& operator=(const date_traits_t& traits) {
- has_year = traits.has_year;
+ has_year = traits.has_year;
has_month = traits.has_month;
- has_day = traits.has_day;
+ has_day = traits.has_day;
return *this;
}
bool operator==(const date_traits_t& traits) const {
- return (has_year == traits.has_year &&
- has_month == traits.has_month &&
- has_day == traits.has_day);
+ return (has_year == traits.has_year &&
+ has_month == traits.has_month &&
+ has_day == traits.has_day);
}
#if defined(HAVE_BOOST_SERIALIZATION)
@@ -249,11 +245,11 @@ struct date_duration_t
out << length << ' ';
switch (quantum) {
- case DAYS: out << "day"; break;
- case WEEKS: out << "week"; break;
+ case DAYS: out << "day"; break;
+ case WEEKS: out << "week"; break;
case MONTHS: out << "month"; break;
case QUARTERS: out << "quarter"; break;
- case YEARS: out << "year"; break;
+ case YEARS: out << "year"; break;
default:
assert(false);
break;
@@ -287,31 +283,31 @@ class date_specifier_t
public:
#if 0
- typedef date_t::year_type year_type;
+ typedef date_t::year_type year_type;
#else
- typedef unsigned short year_type;
+ typedef unsigned short year_type;
#endif
- typedef date_t::month_type month_type;
- typedef date_t::day_type day_type;
+ typedef date_t::month_type month_type;
+ typedef date_t::day_type day_type;
typedef date_t::day_of_week_type day_of_week_type;
protected:
- optional<year_type> year;
- optional<month_type> month;
- optional<day_type> day;
+ optional<year_type> year;
+ optional<month_type> month;
+ optional<day_type> day;
optional<day_of_week_type> wday;
public:
date_specifier_t(const optional<year_type>& _year = none,
- const optional<month_type>& _month = none,
- const optional<day_type>& _day = none,
- const optional<day_of_week_type>& _wday = none)
+ const optional<month_type>& _month = none,
+ const optional<day_type>& _day = none,
+ const optional<day_of_week_type>& _wday = none)
: year(_year), month(_month), day(_day), wday(_wday) {
TRACE_CTOR(date_specifier_t,
- "year_type, month_type, day_type, day_of_week_type");
+ "year_type, month_type, day_type, day_of_week_type");
}
date_specifier_t(const date_t& date,
- const optional<date_traits_t>& traits = none) {
+ const optional<date_traits_t>& traits = none) {
TRACE_CTOR(date_specifier_t, "date_t, date_traits_t");
if (! traits || traits->has_year)
year = date.year();
@@ -329,12 +325,11 @@ public:
TRACE_DTOR(date_specifier_t);
}
- date_t begin(const optional_year& current_year = none) const;
- date_t end(const optional_year& current_year = none) const;
+ date_t begin() const;
+ date_t end() const;
- bool is_within(const date_t& date,
- const optional_year& current_year = none) const {
- return date >= begin(current_year) && date < end(current_year);
+ bool is_within(const date_t& date) const {
+ return date >= begin() && date < end();
}
optional<date_duration_t> implied_duration() const {
@@ -390,7 +385,7 @@ class date_range_t
public:
date_range_t(const optional<date_specifier_t>& _range_begin = none,
- const optional<date_specifier_t>& _range_end = none)
+ const optional<date_specifier_t>& _range_end = none)
: range_begin(_range_begin), range_end(_range_end),
end_inclusive(false) {
TRACE_CTOR(date_range_t, "date_specifier_t, date_specifier_t");
@@ -404,27 +399,26 @@ public:
TRACE_DTOR(date_range_t);
}
- optional<date_t> begin(const optional_year& current_year = none) const {
+ optional<date_t> begin() const {
if (range_begin)
- return range_begin->begin(current_year);
+ return range_begin->begin();
else
return none;
}
- optional<date_t> end(const optional_year& current_year = none) const {
+ optional<date_t> end() const {
if (range_end) {
if (end_inclusive)
- return range_end->end(current_year);
+ return range_end->end();
else
- return range_end->begin(current_year);
+ return range_end->begin();
} else {
return none;
}
}
- bool is_within(const date_t& date,
- const optional_year& current_year = none) const {
- optional<date_t> b = begin(current_year);
- optional<date_t> e = end(current_year);
+ bool is_within(const date_t& date) const {
+ optional<date_t> b = begin();
+ optional<date_t> e = end();
bool after_begin = b ? date >= *b : true;
bool before_end = e ? date < *e : true;
return after_begin && before_end;
@@ -482,19 +476,19 @@ public:
TRACE_DTOR(date_specifier_or_range_t);
}
- optional<date_t> begin(const optional_year& current_year = none) const {
+ optional<date_t> begin() const {
if (specifier_or_range.type() == typeid(date_specifier_t))
- return boost::get<date_specifier_t>(specifier_or_range).begin(current_year);
+ return boost::get<date_specifier_t>(specifier_or_range).begin();
else if (specifier_or_range.type() == typeid(date_range_t))
- return boost::get<date_range_t>(specifier_or_range).begin(current_year);
+ return boost::get<date_range_t>(specifier_or_range).begin();
else
return none;
}
- optional<date_t> end(const optional_year& current_year = none) const {
+ optional<date_t> end() const {
if (specifier_or_range.type() == typeid(date_specifier_t))
- return boost::get<date_specifier_t>(specifier_or_range).end(current_year);
+ return boost::get<date_specifier_t>(specifier_or_range).end();
else if (specifier_or_range.type() == typeid(date_range_t))
- return boost::get<date_range_t>(specifier_or_range).end(current_year);
+ return boost::get<date_range_t>(specifier_or_range).end();
else
return none;
}
@@ -527,19 +521,19 @@ private:
class date_interval_t : public equality_comparable<date_interval_t>
{
public:
- static date_t add_duration(const date_t& date,
- const date_duration_t& duration);
- static date_t subtract_duration(const date_t& date,
- const date_duration_t& duration);
+ static date_t add_duration(const date_t& date,
+ const date_duration_t& duration);
+ static date_t subtract_duration(const date_t& date,
+ const date_duration_t& duration);
optional<date_specifier_or_range_t> range;
- optional<date_t> start; // the real start, after adjustment
- optional<date_t> finish; // the real end, likewise
- bool aligned;
- optional<date_t> next;
+ optional<date_t> start; // the real start, after adjustment
+ optional<date_t> finish; // the real end, likewise
+ bool aligned;
+ optional<date_t> next;
optional<date_duration_t> duration;
- optional<date_t> end_of_duration;
+ optional<date_t> end_of_duration;
explicit date_interval_t() : aligned(false) {
TRACE_CTOR(date_interval_t, "");
@@ -564,24 +558,24 @@ public:
bool operator==(const date_interval_t& other) const {
return (start == other.start &&
- (! start || *start == *other.start));
+ (! start || *start == *other.start));
}
operator bool() const {
return is_valid();
}
- optional<date_t> begin(const optional_year& current_year = none) const {
- return start ? start : (range ? range->begin(current_year) : none);
+ optional<date_t> begin() const {
+ return start ? start : (range ? range->begin() : none);
}
- optional<date_t> end(const optional_year& current_year = none) const {
- return finish ? finish : (range ? range->end(current_year) : none);
+ optional<date_t> end() const {
+ return finish ? finish : (range ? range->end() : none);
}
void parse(const string& str);
- void resolve_end();
- void stabilize(const optional<date_t>& date = none);
+ void resolve_end();
+ void stabilize(const optional<date_t>& date = none);
bool is_valid() const {
return start;
@@ -590,7 +584,7 @@ public:
/** Find the current or next period containing date. Returns true if the
date_interval_t object has been altered to reflect the interval
containing date, or false if no such period can be found. */
- bool find_period(const date_t& date);
+ bool find_period(const date_t& date = CURRENT_DATE());
optional<date_t> inclusive_end() const {
if (end_of_duration)
@@ -601,7 +595,7 @@ public:
date_interval_t& operator++();
- void dump(std::ostream& out, optional_year current_year = none);
+ void dump(std::ostream& out);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
diff --git a/src/token.cc b/src/token.cc
index 905e13fe..199c3b3c 100644
--- a/src/token.cc
+++ b/src/token.cc
@@ -50,74 +50,73 @@ int expr_t::token_t::parse_reserved_word(std::istream& in)
switch (buf[0]) {
case 'a':
if (std::strcmp(buf, "and") == 0) {
- symbol[0] = '&';
- symbol[1] = '\0';
- kind = KW_AND;
- return 1;
+ symbol[0] = '&';
+ symbol[1] = '\0';
+ kind = KW_AND;
+ return 1;
}
break;
case 'd':
if (std::strcmp(buf, "div") == 0) {
- symbol[0] = '/';
- symbol[1] = '/';
- symbol[2] = '\0';
- kind = KW_DIV;
- return 1;
+ symbol[0] = '/';
+ symbol[1] = '\0';
+ kind = KW_DIV;
+ return 1;
}
break;
case 'e':
if (std::strcmp(buf, "else") == 0) {
- symbol[0] = 'L';
- symbol[1] = 'S';
- symbol[2] = '\0';
- kind = KW_ELSE;
- return 1;
+ std::strcpy(symbol, "else");
+ kind = KW_ELSE;
+ return 1;
}
break;
case 'f':
if (std::strcmp(buf, "false") == 0) {
- kind = VALUE;
- value = false;
- return 1;
+ std::strcpy(symbol, "false");
+ kind = VALUE;
+ value = false;
+ return 1;
}
break;
case 'i':
if (std::strcmp(buf, "if") == 0) {
- symbol[0] = 'i';
- symbol[1] = 'f';
- symbol[2] = '\0';
- kind = KW_IF;
- return 1;
+ symbol[0] = 'i';
+ symbol[1] = 'f';
+ symbol[2] = '\0';
+ kind = KW_IF;
+ return 1;
}
break;
case 'o':
if (std::strcmp(buf, "or") == 0) {
- symbol[0] = '|';
- symbol[1] = '\0';
- kind = KW_OR;
- return 1;
+ symbol[0] = '|';
+ symbol[1] = '\0';
+ kind = KW_OR;
+ return 1;
}
break;
case 'n':
if (std::strcmp(buf, "not") == 0) {
- symbol[0] = '!';
- symbol[1] = '\0';
- kind = EXCLAM;
- return 1;
+ symbol[0] = '!';
+ symbol[1] = '\0';
+ kind = EXCLAM;
+ return 1;
}
break;
case 't':
if (std::strcmp(buf, "true") == 0) {
- kind = VALUE;
- value = true;
- return 1;
+ std::strcpy(symbol, "true");
+ kind = VALUE;
+ value = true;
+ return 1;
}
break;
}
@@ -129,7 +128,7 @@ int expr_t::token_t::parse_reserved_word(std::istream& in)
void expr_t::token_t::parse_ident(std::istream& in)
{
- kind = IDENT;
+ kind = IDENT;
length = 0;
char c, buf[256];
@@ -139,7 +138,7 @@ void expr_t::token_t::parse_ident(std::istream& in)
}
void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
- const char expecting)
+ const char expecting)
{
if (in.eof()) {
kind = TOK_EOF;
@@ -210,7 +209,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
optional<date_t> begin = timespan.begin();
if (! begin)
throw_(parse_error,
- _("Date specifier does not refer to a starting date"));
+ _("Date specifier does not refer to a starting date"));
kind = VALUE;
value = *begin;
break;
@@ -231,6 +230,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
break;
}
+#if 0
case '{': {
in.get(c);
amount_t temp;
@@ -243,6 +243,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
value = temp;
break;
}
+#endif
case '!':
in.get(c);
@@ -268,6 +269,15 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
case '-':
in.get(c);
+ c = static_cast<char>(in.peek());
+ if (c == '>') {
+ in.get(c);
+ symbol[1] = c;
+ symbol[2] = '\0';
+ kind = ARROW;
+ length = 2;
+ break;
+ }
kind = MINUS;
break;
case '+':
@@ -287,14 +297,6 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
case ':':
in.get(c);
c = static_cast<char>(in.peek());
- if (c == '=') {
- in.get(c);
- symbol[1] = c;
- symbol[2] = '\0';
- kind = DEFINE;
- length = 2;
- break;
- }
kind = COLON;
break;
@@ -302,12 +304,12 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
in.get(c);
if (pflags.has_flags(PARSE_OP_CONTEXT)) { // operator context
kind = SLASH;
- } else { // terminal context
+ } else { // terminal context
// Read in the regexp
char buf[256];
READ_INTO_(in, buf, 255, c, length, c != '/');
if (c != '/')
- expected('/', c);
+ expected('/', c);
in.get(c);
length++;
@@ -336,7 +338,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
length = 2;
break;
}
- kind = EQUAL;
+ kind = ASSIGN;
break;
case '<':
@@ -395,7 +397,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
in.clear();
in.seekg(pos, std::ios::beg);
if (in.fail())
- throw_(parse_error, _("Failed to reset input stream"));
+ throw_(parse_error, _("Failed to reset input stream"));
}
// When in relaxed parsing mode, we want to migrate commodity flags
@@ -403,6 +405,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
// maximum displayed precision.
parse_flags_t parse_flags;
+ parse_flags.add_flags(PARSE_NO_ANNOT);
if (pflags.has_flags(PARSE_NO_MIGRATE))
parse_flags.add_flags(PARSE_NO_MIGRATE);
if (pflags.has_flags(PARSE_NO_REDUCE))
@@ -411,33 +414,33 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
try {
amount_t temp;
if (! temp.parse(in, parse_flags.plus_flags(PARSE_SOFT_FAIL))) {
- // If the amount had no commodity, it must be an unambiguous
- // variable reference
-
- in.clear();
- in.seekg(pos, std::ios::beg);
- if (in.fail())
- throw_(parse_error, _("Failed to reset input stream"));
-
- c = static_cast<char>(in.peek());
- if (std::isdigit(c) || c == '.')
- expected('\0', c);
-
- parse_ident(in);
-
- if (value.as_string().length() == 0) {
- kind = ERROR;
- symbol[0] = c;
- symbol[1] = '\0';
- unexpected(expecting);
- }
+ // If the amount had no commodity, it must be an unambiguous
+ // variable reference
+
+ in.clear();
+ in.seekg(pos, std::ios::beg);
+ if (in.fail())
+ throw_(parse_error, _("Failed to reset input stream"));
+
+ c = static_cast<char>(in.peek());
+ if (std::isdigit(c) || c == '.')
+ expected('\0', c);
+
+ parse_ident(in);
+
+ if (value.as_string().length() == 0) {
+ kind = ERROR;
+ symbol[0] = c;
+ symbol[1] = '\0';
+ unexpected(expecting);
+ }
} else {
- kind = VALUE;
- value = temp;
- length = static_cast<std::size_t>(in.tellg() - pos);
+ kind = VALUE;
+ value = temp;
+ length = static_cast<std::size_t>(in.tellg() - pos);
}
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
kind = ERROR;
length = static_cast<std::size_t>(in.tellg() - pos);
throw;
@@ -449,7 +452,7 @@ void expr_t::token_t::next(std::istream& in, const parse_flags_t& pflags,
void expr_t::token_t::rewind(std::istream& in)
{
- in.seekg(- length, std::ios::cur);
+ in.seekg(- int(length), std::ios::cur);
if (in.fail())
throw_(parse_error, _("Failed to rewind input stream"));
}
@@ -476,16 +479,16 @@ void expr_t::token_t::unexpected(const char wanted)
switch (prev_kind) {
case TOK_EOF:
throw_(parse_error,
- _("Unexpected end of expression (wanted '%1')") << wanted);
+ _("Unexpected end of expression (wanted '%1')") << wanted);
case IDENT:
throw_(parse_error,
- _("Unexpected symbol '%1' (wanted '%2')") << value << wanted);
+ _("Unexpected symbol '%1' (wanted '%2')") << value << wanted);
case VALUE:
throw_(parse_error,
- _("Unexpected value '%1' (wanted '%2')") << value << wanted);
+ _("Unexpected value '%1' (wanted '%2')") << value << wanted);
default:
throw_(parse_error, _("Unexpected expression token '%1' (wanted '%2')")
- << symbol << wanted);
+ << symbol << wanted);
}
}
}
diff --git a/src/token.h b/src/token.h
index 582373cb..13a799cb 100644
--- a/src/token.h
+++ b/src/token.h
@@ -49,52 +49,54 @@ namespace ledger {
struct expr_t::token_t : public noncopyable
{
enum kind_t {
- ERROR, // an error occurred while tokenizing
- VALUE, // any kind of literal value
- IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
- MASK, // /regexp/
-
- LPAREN, // (
- RPAREN, // )
-
- EQUAL, // ==
- NEQUAL, // !=
- LESS, // <
- LESSEQ, // <=
- GREATER, // >
- GREATEREQ, // >=
-
- DEFINE, // :=
- ASSIGN, // =
- MATCH, // =~
- NMATCH, // !~
- MINUS, // -
- PLUS, // +
- STAR, // *
- SLASH, // /
- KW_DIV, // div
-
- EXCLAM, // !, not
- KW_AND, // &, &&, and
- KW_OR, // |, ||, or
- KW_MOD, // %
-
- KW_IF, // if
- KW_ELSE, // else
-
- QUERY, // ?
- COLON, // :
-
- DOT, // .
- COMMA, // ,
- SEMI, // ;
+ ERROR, // an error occurred while tokenizing
+ VALUE, // any kind of literal value
+ IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
+ MASK, // /regexp/
+
+ LPAREN, // (
+ RPAREN, // )
+ LBRACE, // {
+ RBRACE, // }
+
+ EQUAL, // ==
+ NEQUAL, // !=
+ LESS, // <
+ LESSEQ, // <=
+ GREATER, // >
+ GREATEREQ, // >=
+
+ ASSIGN, // =
+ MATCH, // =~
+ NMATCH, // !~
+ MINUS, // -
+ PLUS, // +
+ STAR, // *
+ SLASH, // /
+ ARROW, // ->
+ KW_DIV, // div
+
+ EXCLAM, // !, not
+ KW_AND, // &, &&, and
+ KW_OR, // |, ||, or
+ KW_MOD, // %
+
+ KW_IF, // if
+ KW_ELSE, // else
+
+ QUERY, // ?
+ COLON, // :
+
+ DOT, // .
+ COMMA, // ,
+ SEMI, // ;
TOK_EOF,
UNKNOWN
} kind;
- char symbol[3];
+ char symbol[6];
value_t value;
std::size_t length;
@@ -108,24 +110,21 @@ struct expr_t::token_t : public noncopyable
token_t& operator=(const token_t& other) {
if (&other == this)
return *this;
- assert(false); // only one token object is used at a time
+ assert(false); // only one token object is used at a time
return *this;
}
void clear() {
- kind = UNKNOWN;
- length = 0;
- value = NULL_VALUE;
-
+ kind = UNKNOWN;
+ length = 0;
+ value = NULL_VALUE;
symbol[0] = '\0';
- symbol[1] = '\0';
- symbol[2] = '\0';
}
int parse_reserved_word(std::istream& in);
void parse_ident(std::istream& in);
void next(std::istream& in, const parse_flags_t& flags,
- const char expecting = '\0');
+ const char expecting = '\0');
void rewind(std::istream& in);
void unexpected(const char wanted = '\0');
void expected(const char wanted, char c = '\0');
diff --git a/src/unistring.h b/src/unistring.h
index d42f2b28..979ce08b 100644
--- a/src/unistring.h
+++ b/src/unistring.h
@@ -67,7 +67,7 @@ public:
TRACE_CTOR(unistring, "std::string");
const char * p = input.c_str();
- std::size_t len = input.length();
+ std::size_t len = input.length();
VERIFY(utf8::is_valid(p, p + len));
utf8::unchecked::utf8to32(p, p + len, std::back_inserter(utf32chars));
@@ -81,9 +81,9 @@ public:
}
std::string extract(const std::string::size_type begin = 0,
- const std::string::size_type len = 0) const
+ const std::string::size_type len = 0) const
{
- std::string utf8result;
+ std::string utf8result;
std::string::size_type this_len = length();
assert(begin <= this_len);
@@ -91,10 +91,10 @@ public:
if (this_len)
utf8::unchecked::utf32to8
- (utf32chars.begin() + begin,
- utf32chars.begin() + begin +
- (len ? (len > this_len ? this_len : len) : this_len),
- std::back_inserter(utf8result));
+ (utf32chars.begin() + begin,
+ utf32chars.begin() + begin +
+ (len ? (len > this_len ? this_len : len) : this_len),
+ std::back_inserter(utf8result));
return utf8result;
}
@@ -103,7 +103,7 @@ public:
std::size_t idx = 0;
foreach (const boost::uint32_t& ch, utf32chars) {
if (idx >= __pos && ch == __s)
- return idx;
+ return idx;
idx++;
}
return npos;
@@ -118,10 +118,10 @@ public:
};
inline void justify(std::ostream& out,
- const std::string& str,
- int width,
- bool right = false,
- bool redden = false)
+ const std::string& str,
+ int width,
+ bool right = false,
+ bool redden = false)
{
if (! right) {
if (redden) out << "\033[31m";
diff --git a/src/utils.cc b/src/utils.cc
index c3fecca0..dce804ff 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -45,9 +45,9 @@ namespace ledger {
DECLARE_EXCEPTION(assertion_failed, std::logic_error);
void debug_assert(const string& reason,
- const string& func,
- const string& file,
- std::size_t line)
+ const string& func,
+ const string& file,
+ std::size_t line)
{
std::ostringstream buf;
buf << "Assertion failed in \"" << file << "\", line " << line
@@ -80,11 +80,11 @@ typedef std::map<std::string, count_size_pair> object_count_map;
namespace {
bool memory_tracing_active = false;
- memory_map * live_memory = NULL;
- memory_map * freed_memory = NULL;
+ memory_map * live_memory = NULL;
+ memory_map * freed_memory = NULL;
object_count_map * live_memory_count = NULL;
object_count_map * total_memory_count = NULL;
- objects_map * live_objects = NULL;
+ objects_map * live_objects = NULL;
object_count_map * live_object_count = NULL;
object_count_map * total_object_count = NULL;
object_count_map * total_ctor_count = NULL;
@@ -94,11 +94,11 @@ void initialize_memory_tracing()
{
memory_tracing_active = false;
- live_memory = new memory_map;
- freed_memory = new memory_map;
+ live_memory = new memory_map;
+ freed_memory = new memory_map;
live_memory_count = new object_count_map;
total_memory_count = new object_count_map;
- live_objects = new objects_map;
+ live_objects = new objects_map;
live_object_count = new object_count_map;
total_object_count = new object_count_map;
total_ctor_count = new object_count_map;
@@ -119,18 +119,18 @@ void shutdown_memory_tracing()
report_memory(std::cerr);
}
- checked_delete(live_memory); live_memory = NULL;
- checked_delete(freed_memory); freed_memory = NULL;
- checked_delete(live_memory_count); live_memory_count = NULL;
+ checked_delete(live_memory); live_memory = NULL;
+ checked_delete(freed_memory); freed_memory = NULL;
+ checked_delete(live_memory_count); live_memory_count = NULL;
checked_delete(total_memory_count); total_memory_count = NULL;
- checked_delete(live_objects); live_objects = NULL;
- checked_delete(live_object_count); live_object_count = NULL;
+ checked_delete(live_objects); live_objects = NULL;
+ checked_delete(live_object_count); live_object_count = NULL;
checked_delete(total_object_count); total_object_count = NULL;
- checked_delete(total_ctor_count); total_ctor_count = NULL;
+ checked_delete(total_ctor_count); total_ctor_count = NULL;
}
inline void add_to_count_map(object_count_map& the_map,
- const char * name, std::size_t size)
+ const char * name, std::size_t size)
{
object_count_map::iterator k = the_map.find(name);
if (k != the_map.end()) {
@@ -274,9 +274,9 @@ inline void report_count_map(std::ostream& out, object_count_map& the_map)
{
foreach (object_count_map::value_type& pair, the_map)
out << " " << std::right << std::setw(12) << pair.second.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.first
- << std::endl;
+ << " " << std::right << std::setw(7) << pair.second.second
+ << " " << std::left << pair.first
+ << std::endl;
}
std::size_t current_objects_size()
@@ -290,7 +290,7 @@ std::size_t current_objects_size()
}
void trace_ctor_func(void * ptr, const char * cls_name, const char * args,
- std::size_t cls_size)
+ std::size_t cls_size)
{
if (! live_objects || ! memory_tracing_active) return;
@@ -358,7 +358,7 @@ void report_memory(std::ostream& out, bool report_all)
if (live_memory_count->size() > 0) {
out << "NOTE: There may be memory held by Boost "
- << "and libstdc++ after ledger::shutdown()" << std::endl;
+ << "and libstdc++ after ledger::shutdown()" << std::endl;
out << "Live memory count:" << std::endl;
report_count_map(out, *live_memory_count);
}
@@ -368,9 +368,9 @@ void report_memory(std::ostream& out, bool report_all)
foreach (const memory_map::value_type& pair, *live_memory)
out << " " << std::right << std::setw(12) << pair.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.second.first
- << std::endl;
+ << " " << std::right << std::setw(7) << pair.second.second
+ << " " << std::left << pair.second.first
+ << std::endl;
}
if (report_all && total_memory_count->size() > 0) {
@@ -388,9 +388,9 @@ void report_memory(std::ostream& out, bool report_all)
foreach (const objects_map::value_type& pair, *live_objects)
out << " " << std::right << std::setw(12) << pair.first
- << " " << std::right << std::setw(7) << pair.second.second
- << " " << std::left << pair.second.first
- << std::endl;
+ << " " << std::right << std::setw(7) << pair.second.second
+ << " " << std::left << pair.second.first
+ << std::endl;
}
if (report_all) {
@@ -470,28 +470,28 @@ strings_list split_arguments(const char * line)
for (const char * p = line; *p; p++) {
if (! in_quoted_string && std::isspace(*p)) {
if (q != buf) {
- *q = '\0';
- args.push_back(buf);
- q = buf;
+ *q = '\0';
+ args.push_back(buf);
+ q = buf;
}
}
else if (in_quoted_string != '\'' && *p == '\\') {
p++;
if (! *p)
- throw_(std::logic_error, _("Invalid use of backslash"));
+ throw_(std::logic_error, _("Invalid use of backslash"));
*q++ = *p;
}
else if (in_quoted_string != '"' && *p == '\'') {
if (in_quoted_string == '\'')
- in_quoted_string = '\0';
+ in_quoted_string = '\0';
else
- in_quoted_string = '\'';
+ in_quoted_string = '\'';
}
else if (in_quoted_string != '\'' && *p == '"') {
if (in_quoted_string == '"')
- in_quoted_string = '\0';
+ in_quoted_string = '\0';
else
- in_quoted_string = '"';
+ in_quoted_string = '"';
}
else {
*q++ = *p;
@@ -500,7 +500,7 @@ strings_list split_arguments(const char * line)
if (in_quoted_string)
throw_(std::logic_error,
- _("Unterminated string, expected '%1'") << in_quoted_string);
+ _("Unterminated string, expected '%1'") << in_quoted_string);
if (q != buf) {
*q = '\0';
@@ -521,12 +521,12 @@ strings_list split_arguments(const char * line)
namespace ledger {
-log_level_t _log_level = LOG_WARN;
-std::ostream * _log_stream = &std::cerr;
+log_level_t _log_level = LOG_WARN;
+std::ostream * _log_stream = &std::cerr;
std::ostringstream _log_buffer;
#if defined(TRACING_ON)
-uint8_t _trace_level;
+uint8_t _trace_level;
#endif
static inline void stream_memory_size(std::ostream& out, std::size_t size)
@@ -560,8 +560,8 @@ bool logger_func(log_level_t level)
}
*_log_stream << std::right << std::setw(5)
- << (TRUE_CURRENT_TIME() -
- logger_start).total_milliseconds() << "ms";
+ << (TRUE_CURRENT_TIME() -
+ logger_start).total_milliseconds() << "ms";
#if defined(VERIFY_ON)
IF_VERIFY() {
@@ -593,6 +593,7 @@ bool logger_func(log_level_t level)
}
*_log_stream << ' ' << _log_buffer.str() << std::endl;
+ _log_buffer.clear();
_log_buffer.str("");
return true;
@@ -632,11 +633,11 @@ namespace ledger {
struct timer_t
{
- log_level_t level;
- ptime begin;
- time_duration spent;
- std::string description;
- bool active;
+ log_level_t level;
+ ptime begin;
+ time_duration spent;
+ std::string description;
+ bool active;
timer_t(log_level_t _level, std::string _description)
: level(_level), begin(TRUE_CURRENT_TIME()),
@@ -663,6 +664,7 @@ void start_timer(const char * name, log_level_t lvl)
(*i).second.begin = TRUE_CURRENT_TIME();
(*i).second.active = true;
}
+ _log_buffer.clear();
_log_buffer.str("");
#if defined(VERIFY_ON)
@@ -767,7 +769,7 @@ path expand_path(const path& pathname)
return pathname;
std::string path_string = pathname.string();
- const char * pfx = NULL;
+ const char * pfx = NULL;
string::size_type pos = path_string.find_first_of('/');
if (path_string.length() == 1 || pos == 1) {
@@ -777,14 +779,14 @@ path expand_path(const path& pathname)
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd * pw = getpwuid(getuid());
if (pw)
- pfx = pw->pw_dir;
+ pfx = pw->pw_dir;
}
#endif
}
#ifdef HAVE_GETPWNAM
else {
string user(path_string, 1, pos == string::npos ?
- string::npos : pos - 1);
+ string::npos : pos - 1);
struct passwd * pw = getpwnam(user.c_str());
if (pw)
pfx = pw->pw_dir;
diff --git a/src/utils.h b/src/utils.h
index 9135abde..a228d166 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -59,7 +59,7 @@
#define NO_ASSERTS 1
//#define NO_LOGGING 1
#else
-#define TRACING_ON 1 // use --trace X to enable
+#define TRACING_ON 1 // use --trace X to enable
#endif
/*@}*/
@@ -80,15 +80,15 @@ namespace ledger {
typedef std::list<string> strings_list;
- typedef posix_time::ptime ptime;
+ typedef posix_time::ptime ptime;
typedef ptime::time_duration_type time_duration;
- typedef gregorian::date date;
+ typedef gregorian::date date;
typedef gregorian::date_duration date_duration;
- typedef posix_time::seconds seconds;
+ typedef posix_time::seconds seconds;
- typedef boost::filesystem::path path;
- typedef boost::filesystem::ifstream ifstream;
- typedef boost::filesystem::ofstream ofstream;
+ typedef boost::filesystem::path path;
+ typedef boost::filesystem::ifstream ifstream;
+ typedef boost::filesystem::ofstream ofstream;
typedef boost::filesystem::filesystem_error filesystem_error;
}
@@ -110,12 +110,12 @@ namespace ledger {
namespace ledger {
void debug_assert(const string& reason, const string& func,
- const string& file, std::size_t line);
+ const string& file, std::size_t line);
}
-#define assert(x) \
- ((x) ? ((void)0) : debug_assert(#x, BOOST_CURRENT_FUNCTION, \
- __FILE__, __LINE__))
+#define assert(x) \
+ ((x) ? ((void)0) : debug_assert(#x, BOOST_CURRENT_FUNCTION, \
+ __FILE__, __LINE__))
#else // ! ASSERTS_ON
@@ -146,7 +146,7 @@ std::size_t current_memory_size();
std::size_t current_objects_size();
void trace_ctor_func(void * ptr, const char * cls_name, const char * args,
- std::size_t cls_size);
+ std::size_t cls_size);
void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size);
#define TRACE_CTOR(cls, args) \
@@ -239,8 +239,8 @@ inline string operator+(const string& __lhs, const char* __rhs)
inline string operator+(const string& __lhs, char __rhs)
{
- typedef string __string_type;
- typedef string::size_type __size_type;
+ typedef string __string_type;
+ typedef string::size_type __size_type;
__string_type __str(__lhs);
__str.append(__size_type(1), __rhs);
return __str;
@@ -301,8 +301,8 @@ enum log_level_t {
LOG_ALL
};
-extern log_level_t _log_level;
-extern std::ostream * _log_stream;
+extern log_level_t _log_level;
+extern std::ostream * _log_stream;
extern std::ostringstream _log_buffer;
bool logger_func(log_level_t level);
@@ -539,7 +539,7 @@ extern "C" char * realpath(const char *, char resolved_path[]);
#endif
inline const string& either_or(const string& first,
- const string& second) {
+ const string& second) {
return first.empty() ? second : first;
}
@@ -587,65 +587,65 @@ inline char peek_next_nonws(std::istream& in) {
return c;
}
-#define READ_INTO(str, targ, size, var, cond) { \
- char * _p = targ; \
- var = static_cast<char>(str.peek()); \
- while (str.good() && ! str.eof() && var != '\n' && \
- (cond) && _p - targ < size) { \
- str.get(var); \
- if (str.eof()) \
- break; \
- if (var == '\\') { \
- str.get(var); \
- if (in.eof()) \
- break; \
- switch (var) { \
- case 'b': var = '\b'; break; \
- case 'f': var = '\f'; break; \
- case 'n': var = '\n'; break; \
- case 'r': var = '\r'; break; \
- case 't': var = '\t'; break; \
- case 'v': var = '\v'; break; \
- default: break; \
- } \
- } \
- *_p++ = var; \
- var = static_cast<char>(str.peek()); \
- } \
- *_p = '\0'; \
+#define READ_INTO(str, targ, size, var, cond) { \
+ char * _p = targ; \
+ var = static_cast<char>(str.peek()); \
+ while (str.good() && ! str.eof() && var != '\n' && \
+ (cond) && _p - targ < size) { \
+ str.get(var); \
+ if (str.eof()) \
+ break; \
+ if (var == '\\') { \
+ str.get(var); \
+ if (in.eof()) \
+ break; \
+ switch (var) { \
+ case 'b': var = '\b'; break; \
+ case 'f': var = '\f'; break; \
+ case 'n': var = '\n'; break; \
+ case 'r': var = '\r'; break; \
+ case 't': var = '\t'; break; \
+ case 'v': var = '\v'; break; \
+ default: break; \
+ } \
+ } \
+ *_p++ = var; \
+ var = static_cast<char>(str.peek()); \
+ } \
+ *_p = '\0'; \
}
-#define READ_INTO_(str, targ, size, var, idx, cond) { \
- char * _p = targ; \
- var = static_cast<char>(str.peek()); \
- while (str.good() && ! str.eof() && var != '\n' && \
- (cond) && _p - targ < size) { \
- str.get(var); \
- if (str.eof()) \
- break; \
- idx++; \
- if (var == '\\') { \
- str.get(var); \
- if (in.eof()) \
- break; \
- switch (var) { \
- case 'b': var = '\b'; break; \
- case 'f': var = '\f'; break; \
- case 'n': var = '\n'; break; \
- case 'r': var = '\r'; break; \
- case 't': var = '\t'; break; \
- case 'v': var = '\v'; break; \
- default: break; \
- } \
- idx++; \
- } \
- *_p++ = var; \
- var = static_cast<char>(str.peek()); \
- } \
- *_p = '\0'; \
+#define READ_INTO_(str, targ, size, var, idx, cond) { \
+ char * _p = targ; \
+ var = static_cast<char>(str.peek()); \
+ while (str.good() && ! str.eof() && var != '\n' && \
+ (cond) && _p - targ < size) { \
+ str.get(var); \
+ if (str.eof()) \
+ break; \
+ idx++; \
+ if (var == '\\') { \
+ str.get(var); \
+ if (in.eof()) \
+ break; \
+ switch (var) { \
+ case 'b': var = '\b'; break; \
+ case 'f': var = '\f'; break; \
+ case 'n': var = '\n'; break; \
+ case 'r': var = '\r'; break; \
+ case 't': var = '\t'; break; \
+ case 'v': var = '\v'; break; \
+ default: break; \
+ } \
+ idx++; \
+ } \
+ *_p++ = var; \
+ var = static_cast<char>(str.peek()); \
+ } \
+ *_p = '\0'; \
}
-inline string to_hex(uint_least32_t * message_digest, const int len = 1)
+inline string to_hex(unsigned int * message_digest, const int len = 1)
{
std::ostringstream buf;
@@ -654,7 +654,7 @@ inline string to_hex(uint_least32_t * message_digest, const int len = 1)
buf.fill('0');
buf << std::hex << message_digest[i];
if (i + 1 >= len)
- break; // only output the first LEN dwords
+ break; // only output the first LEN dwords
}
return buf.str();
}
@@ -664,7 +664,7 @@ inline string sha1sum(const string& str)
SHA1 sha;
sha.Reset();
sha << str.c_str();
- uint_least32_t message_digest[5];
+ unsigned int message_digest[5];
sha.Result(message_digest);
return to_hex(message_digest, 5);
}
@@ -672,12 +672,12 @@ inline string sha1sum(const string& str)
class push_xml
{
std::ostream& out;
- string tag;
- bool leave_open;
+ string tag;
+ bool leave_open;
public:
push_xml(std::ostream& _out, const string& _tag, bool has_attrs = false,
- bool _leave_open = false)
+ bool _leave_open = false)
: out(_out), tag(_tag), leave_open(_leave_open) {
out << '<' << tag;
if (! has_attrs)
@@ -697,17 +697,17 @@ public:
foreach (const char& ch, str) {
switch (ch) {
case '<':
- buf << "&lt;";
- break;
+ buf << "&lt;";
+ break;
case '>':
- buf << "&gt;";
- break;
+ buf << "&gt;";
+ break;
case '&':
- buf << "&amp;";
- break;
+ buf << "&amp;";
+ break;
default:
- buf << ch;
- break;
+ buf << ch;
+ break;
}
}
return buf.str();
diff --git a/src/value.cc b/src/value.cc
index e9313f0c..c34792b2 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -35,7 +35,7 @@
#include "commodity.h"
#include "annotate.h"
#include "pool.h"
-#include "unistring.h" // for justify()
+#include "unistring.h" // for justify()
#include "op.h"
namespace ledger {
@@ -65,11 +65,11 @@ value_t::storage_t& value_t::storage_t::operator=(const value_t::storage_t& rhs)
void value_t::initialize()
{
- true_value = new storage_t;
+ true_value = new storage_t;
true_value->type = BOOLEAN;
true_value->data = true;
- false_value = new storage_t;
+ false_value = new storage_t;
false_value->type = BOOLEAN;
false_value->data = false;
}
@@ -103,26 +103,28 @@ value_t::operator bool() const
std::ostringstream out;
out << *this;
throw_(value_error,
- _("Cannot determine truth of %1 (did you mean 'account =~ %2'?)")
- << label() << out.str());
+ _("Cannot determine truth of %1 (did you mean 'account =~ %2'?)")
+ << label() << out.str());
}
case SEQUENCE:
if (! as_sequence().empty()) {
foreach (const value_t& value, as_sequence()) {
- if (value)
- return true;
+ if (value)
+ return true;
}
}
return false;
case SCOPE:
return as_scope() != NULL;
- case EXPR:
- return as_expr();
+ case ANY:
+ return ! as_any().empty();
default:
break;
}
+ add_error_context(_("While taking boolean value of %1:") << *this);
throw_(value_error, _("Cannot determine truth of %1") << label());
+
return false;
}
@@ -143,12 +145,6 @@ void value_t::set_type(type_t new_type)
}
}
-void value_t::set_expr(const expr_t& val)
-{
- set_type(EXPR);
- storage->data = new expr_t(val);
-}
-
bool value_t::to_boolean() const
{
if (is_boolean()) {
@@ -279,7 +275,7 @@ void value_t::in_place_simplify()
DEBUG_("as an amount it looks like: " << *this);
}
-#ifdef REDUCE_TO_INTEGER // this is off by default
+#ifdef REDUCE_TO_INTEGER // this is off by default
if (is_amount() && ! as_amount().has_commodity() &&
as_amount().fits_in_long()) {
DEBUG_("Reducing amount to integer");
@@ -305,7 +301,7 @@ value_t value_t::number() const
if (! as_sequence().empty()) {
value_t temp;
foreach (const value_t& value, as_sequence())
- temp += value.number();
+ temp += value.number();
return temp;
}
break;
@@ -313,7 +309,9 @@ value_t value_t::number() const
break;
}
+ add_error_context(_("While calling number() on %1:") << *this);
throw_(value_error, _("Cannot determine numeric value of %1") << label());
+
return false;
}
@@ -329,16 +327,17 @@ value_t& value_t::operator+=(const value_t& val)
else if (is_sequence()) {
if (val.is_sequence()) {
if (size() == val.size()) {
- sequence_t::iterator i = begin();
- sequence_t::const_iterator j = val.begin();
+ sequence_t::iterator i = begin();
+ sequence_t::const_iterator j = val.begin();
- for (; i != end(); i++, j++)
- *i += *j;
+ for (; i != end(); i++, j++)
+ *i += *j;
} else {
- throw_(value_error, _("Cannot add sequences of different lengths"));
+ add_error_context(_("While adding %1 to %2:") << *this << val);
+ throw_(value_error, _("Cannot add sequences of different lengths"));
}
} else {
- as_sequence_lval().push_back(val);
+ as_sequence_lval().push_back(new value_t(val));
}
return *this;
}
@@ -348,12 +347,12 @@ value_t& value_t::operator+=(const value_t& val)
switch (val.type()) {
case INTEGER:
as_datetime_lval() +=
- time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
+ time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
return *this;
case AMOUNT:
as_datetime_lval() +=
- time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
- (val.as_amount().to_long()));
+ time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
+ (val.as_amount().to_long()));
return *this;
default:
break;
@@ -380,8 +379,8 @@ value_t& value_t::operator+=(const value_t& val)
return *this;
case AMOUNT:
if (val.as_amount().has_commodity()) {
- in_place_cast(BALANCE);
- return *this += val;
+ in_place_cast(BALANCE);
+ return *this += val;
}
in_place_cast(AMOUNT);
as_amount_lval() += val.as_amount();
@@ -399,21 +398,21 @@ value_t& value_t::operator+=(const value_t& val)
switch (val.type()) {
case INTEGER:
if (as_amount().has_commodity()) {
- in_place_cast(BALANCE);
- return *this += val;
+ in_place_cast(BALANCE);
+ return *this += val;
} else {
- as_amount_lval() += val.as_long();
- return *this;
+ as_amount_lval() += val.as_long();
+ return *this;
}
break;
case AMOUNT:
if (as_amount().commodity() != val.as_amount().commodity()) {
- in_place_cast(BALANCE);
- return *this += val;
+ in_place_cast(BALANCE);
+ return *this += val;
} else {
- as_amount_lval() += val.as_amount();
- return *this;
+ as_amount_lval() += val.as_amount();
+ return *this;
}
break;
@@ -447,7 +446,9 @@ value_t& value_t::operator+=(const value_t& val)
break;
}
+ add_error_context(_("While adding %1 to %2:") << *this << val);
throw_(value_error, _("Cannot add %1 to %2") << val.label() << label());
+
return *this;
}
@@ -458,18 +459,19 @@ value_t& value_t::operator-=(const value_t& val)
if (val.is_sequence()) {
if (size() == val.size()) {
- sequence_t::iterator i = begin();
- sequence_t::const_iterator j = val.begin();
+ sequence_t::iterator i = begin();
+ sequence_t::const_iterator j = val.begin();
- for (; i != end(); i++, j++)
- *i -= *j;
+ for (; i != end(); i++, j++)
+ *i -= *j;
} else {
- throw_(value_error, _("Cannot subtract sequences of different lengths"));
+ add_error_context(_("While subtracting %1 to %2:") << *this << val);
+ throw_(value_error, _("Cannot subtract sequences of different lengths"));
}
} else {
sequence_t::iterator i = std::find(seq.begin(), seq.end(), val);
if (i != seq.end())
- seq.erase(i);
+ seq.erase(i);
}
return *this;
}
@@ -479,12 +481,12 @@ value_t& value_t::operator-=(const value_t& val)
switch (val.type()) {
case INTEGER:
as_datetime_lval() -=
- time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
+ time_duration_t(0, 0, static_cast<time_duration_t::sec_type>(val.as_long()));
return *this;
case AMOUNT:
as_datetime_lval() -=
- time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
- (val.as_amount().to_long()));
+ time_duration_t(0, 0, static_cast<time_duration_t::sec_type>
+ (val.as_amount().to_long()));
return *this;
default:
break;
@@ -528,27 +530,27 @@ value_t& value_t::operator-=(const value_t& val)
switch (val.type()) {
case INTEGER:
if (as_amount().has_commodity()) {
- in_place_cast(BALANCE);
- *this -= val;
- in_place_simplify();
- return *this;
+ in_place_cast(BALANCE);
+ *this -= val;
+ in_place_simplify();
+ return *this;
} else {
- as_amount_lval() -= val.as_long();
- in_place_simplify();
- return *this;
+ as_amount_lval() -= val.as_long();
+ in_place_simplify();
+ return *this;
}
break;
case AMOUNT:
if (as_amount().commodity() != val.as_amount().commodity()) {
- in_place_cast(BALANCE);
- *this -= val;
- in_place_simplify();
- return *this;
+ in_place_cast(BALANCE);
+ *this -= val;
+ in_place_simplify();
+ return *this;
} else {
- as_amount_lval() -= val.as_amount();
- in_place_simplify();
- return *this;
+ as_amount_lval() -= val.as_amount();
+ in_place_simplify();
+ return *this;
}
break;
@@ -586,6 +588,7 @@ value_t& value_t::operator-=(const value_t& val)
break;
}
+ add_error_context(_("While subtracting %1 from %2:") << *this << val);
throw_(value_error, _("Cannot subtract %1 from %2") << val.label() << label());
return *this;
@@ -633,8 +636,8 @@ value_t& value_t::operator*=(const value_t& val)
return *this;
case BALANCE:
if (val.as_balance().single_amount()) {
- as_amount_lval() *= val.simplified().as_amount();
- return *this;
+ as_amount_lval() *= val.simplified().as_amount();
+ return *this;
}
break;
default:
@@ -649,13 +652,13 @@ value_t& value_t::operator*=(const value_t& val)
return *this;
case AMOUNT:
if (as_balance().single_amount()) {
- in_place_simplify();
- as_amount_lval() *= val.as_amount();
- return *this;
+ in_place_simplify();
+ as_amount_lval() *= val.as_amount();
+ return *this;
}
else if (! val.as_amount().has_commodity()) {
- as_balance_lval() *= val.as_amount();
- return *this;
+ as_balance_lval() *= val.as_amount();
+ return *this;
}
break;
default:
@@ -667,9 +670,7 @@ value_t& value_t::operator*=(const value_t& val)
break;
}
- DEBUG("value.multiply.error", "Left: " << *this);
- DEBUG("value.multiply.error", "Right: " << val);
-
+ add_error_context(_("While multiplying %1 with %2:") << *this << val);
throw_(value_error, _("Cannot multiply %1 with %2") << label() << val.label());
return *this;
@@ -702,19 +703,19 @@ value_t& value_t::operator/=(const value_t& val)
return *this;
case BALANCE:
if (val.as_balance().single_amount()) {
- value_t simpler(val.simplified());
- switch (simpler.type()) {
- case INTEGER:
- as_amount_lval() /= simpler.as_long();
- break;
- case AMOUNT:
- as_amount_lval() /= simpler.as_amount();
- break;
- default:
- assert(false);
- break;
- }
- return *this;
+ value_t simpler(val.simplified());
+ switch (simpler.type()) {
+ case INTEGER:
+ as_amount_lval() /= simpler.as_long();
+ break;
+ case AMOUNT:
+ as_amount_lval() /= simpler.as_amount();
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return *this;
}
break;
default:
@@ -729,13 +730,13 @@ value_t& value_t::operator/=(const value_t& val)
return *this;
case AMOUNT:
if (as_balance().single_amount()) {
- in_place_simplify();
- as_amount_lval() /= val.as_amount();
- return *this;
+ in_place_simplify();
+ as_amount_lval() /= val.as_amount();
+ return *this;
}
else if (! val.as_amount().has_commodity()) {
- as_balance_lval() /= val.as_amount();
- return *this;
+ as_balance_lval() /= val.as_amount();
+ return *this;
}
break;
default:
@@ -747,6 +748,7 @@ value_t& value_t::operator/=(const value_t& val)
break;
}
+ add_error_context(_("While dividing %1 by %2:") << *this << val);
throw_(value_error, _("Cannot divide %1 by %2") << label() << val.label());
return *this;
@@ -832,6 +834,7 @@ bool value_t::is_equal_to(const value_t& val) const
break;
}
+ add_error_context(_("While comparing equality of %1 to %2:") << *this << val);
throw_(value_error, _("Cannot compare %1 to %2") << label() << val.label());
return *this;
@@ -843,16 +846,16 @@ bool value_t::is_less_than(const value_t& val) const
case BOOLEAN:
if (val.is_boolean()) {
if (as_boolean()) {
- if (! val.as_boolean())
- return false;
- else
- return false;
+ if (! val.as_boolean())
+ return false;
+ else
+ return false;
}
else if (! as_boolean()) {
- if (! val.as_boolean())
- return false;
- else
- return true;
+ if (! val.as_boolean())
+ return false;
+ else
+ return true;
}
}
break;
@@ -884,11 +887,11 @@ bool value_t::is_less_than(const value_t& val) const
return as_amount() < val.as_long();
case AMOUNT:
if (as_amount().commodity() == val.as_amount().commodity() ||
- ! as_amount().has_commodity() ||
- ! val.as_amount().has_commodity())
- return as_amount() < val.as_amount();
+ ! as_amount().has_commodity() ||
+ ! val.as_amount().has_commodity())
+ return as_amount() < val.as_amount();
else
- return commodity_t::compare_by_commodity()(&as_amount(), &val.as_amount());
+ return commodity_t::compare_by_commodity()(&as_amount(), &val.as_amount());
default:
break;
}
@@ -898,15 +901,12 @@ 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)
- return false;
- no_amounts = false;
+ as_balance().amounts) {
+ if (pair.second >= val)
+ return false;
+ no_amounts = false;
}
return ! no_amounts;
}
@@ -924,14 +924,11 @@ 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)
- return false;
- no_amounts = false;
+ if (value >= val)
+ return false;
+ no_amounts = false;
}
return ! no_amounts;
}
@@ -939,14 +936,14 @@ bool value_t::is_less_than(const value_t& val) const
sequence_t::const_iterator i = as_sequence().begin();
sequence_t::const_iterator j = val.as_sequence().begin();
for (; (i != as_sequence().end() &&
- j != val.as_sequence().end()); i++, j++) {
- if (! ((*i) < (*j)))
- return false;
+ j != val.as_sequence().end()); i++, j++) {
+ if (! ((*i) < (*j)))
+ return false;
}
if (i == as_sequence().end())
- return true;
+ return true;
else
- return false;
+ return false;
break;
}
default:
@@ -958,6 +955,8 @@ bool value_t::is_less_than(const value_t& val) const
break;
}
+ add_error_context(_("While comparing if %1 is less than %2:")
+ << *this << val);
throw_(value_error, _("Cannot compare %1 to %2") << label() << val.label());
return *this;
@@ -968,16 +967,16 @@ bool value_t::is_greater_than(const value_t& val) const
switch (type()) {
if (val.is_boolean()) {
if (as_boolean()) {
- if (! val.as_boolean())
- return true;
- else
- return false;
+ if (! val.as_boolean())
+ return true;
+ else
+ return false;
}
else if (! as_boolean()) {
- if (! val.as_boolean())
- return false;
- else
- return false;
+ if (! val.as_boolean())
+ return false;
+ else
+ return false;
}
}
break;
@@ -1018,15 +1017,12 @@ 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)
- return false;
- no_amounts = false;
+ as_balance().amounts) {
+ if (pair.second <= val)
+ return false;
+ no_amounts = false;
}
return ! no_amounts;
}
@@ -1044,14 +1040,11 @@ 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)
- return false;
- no_amounts = false;
+ if (value <= val)
+ return false;
+ no_amounts = false;
}
return ! no_amounts;
}
@@ -1059,14 +1052,14 @@ bool value_t::is_greater_than(const value_t& val) const
sequence_t::const_iterator i = as_sequence().begin();
sequence_t::const_iterator j = val.as_sequence().begin();
for (; (i != as_sequence().end() &&
- j != val.as_sequence().end()); i++, j++) {
- if (! ((*i) > (*j)))
- return false;
+ j != val.as_sequence().end()); i++, j++) {
+ if (! ((*i) > (*j)))
+ return false;
}
if (i == as_sequence().end())
- return false;
+ return false;
else
- return true;
+ return true;
break;
}
default:
@@ -1078,6 +1071,8 @@ bool value_t::is_greater_than(const value_t& val) const
break;
}
+ add_error_context(_("While comparing if %1 is greater than %2:")
+ << *this << val);
throw_(value_error, _("Cannot compare %1 to %2") << label() << val.label());
return *this;
@@ -1097,7 +1092,7 @@ void value_t::in_place_cast(type_t cast_type)
else if (cast_type == SEQUENCE) {
sequence_t temp;
if (! is_null())
- temp.push_back(*this);
+ temp.push_back(new value_t(*this));
set_sequence(temp);
return;
}
@@ -1181,21 +1176,21 @@ void value_t::in_place_cast(type_t cast_type)
switch (cast_type) {
case INTEGER:
if (amt.is_null())
- set_long(0L);
+ set_long(0L);
else
- set_long(as_amount().to_long());
+ set_long(as_amount().to_long());
return;
case BALANCE:
if (amt.is_null())
- set_balance(balance_t());
+ set_balance(balance_t());
else
- set_balance(as_amount());
+ set_balance(as_amount());
return;
case STRING:
if (amt.is_null())
- set_string("");
+ set_string("");
else
- set_string(as_amount().to_string());
+ set_string(as_amount().to_string());
return;
default:
break;
@@ -1208,27 +1203,28 @@ void value_t::in_place_cast(type_t cast_type)
switch (cast_type) {
case AMOUNT: {
if (bal.amounts.size() == 1) {
- // Because we are changing the current balance value to an amount
- // value, and because set_amount takes a reference (and that memory is
- // about to be repurposed), we must pass in a copy.
- set_amount(amount_t((*bal.amounts.begin()).second));
- return;
+ // Because we are changing the current balance value to an amount
+ // value, and because set_amount takes a reference (and that memory is
+ // about to be repurposed), we must pass in a copy.
+ set_amount(amount_t((*bal.amounts.begin()).second));
+ return;
}
else if (bal.amounts.size() == 0) {
- set_amount(0L);
- return;
+ set_amount(0L);
+ return;
}
else {
- throw_(value_error, _("Cannot convert %1 with multiple commodities to %2")
- << label() << label(cast_type));
+ add_error_context(_("While converting %1 to an amount:") << *this);
+ throw_(value_error, _("Cannot convert %1 with multiple commodities to %2")
+ << label() << label(cast_type));
}
break;
}
case STRING:
if (bal.is_empty())
- set_string("");
+ set_string("");
else
- set_string(as_balance().to_string());
+ set_string(as_balance().to_string());
return;
default:
break;
@@ -1240,8 +1236,8 @@ void value_t::in_place_cast(type_t cast_type)
switch (cast_type) {
case INTEGER: {
if (all(as_string(), is_digit())) {
- set_long(lexical_cast<long>(as_string()));
- return;
+ set_long(lexical_cast<long>(as_string()));
+ return;
}
break;
}
@@ -1266,8 +1262,9 @@ void value_t::in_place_cast(type_t cast_type)
break;
}
+ add_error_context(_("While converting %1:") << *this);
throw_(value_error,
- _("Cannot convert %1 to %2") << label() << label(cast_type));
+ _("Cannot convert %1 to %2") << label() << label(cast_type));
}
void value_t::in_place_negate()
@@ -1289,17 +1286,15 @@ void value_t::in_place_negate()
case BALANCE:
as_balance_lval().in_place_negate();
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(- value);
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_negate();
return;
- }
default:
break;
}
+ add_error_context(_("While negating %1:") << *this);
throw_(value_error, _("Cannot negate %1") << label());
}
@@ -1325,17 +1320,15 @@ void value_t::in_place_not()
case STRING:
set_boolean(as_string().empty());
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(! value);
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_not();
return;
- }
default:
break;
}
+ add_error_context(_("While applying not to %1:") << *this);
throw_(value_error, _("Cannot 'not' %1") << label());
}
@@ -1361,10 +1354,11 @@ bool value_t::is_realzero() const
case SCOPE:
return as_scope() == NULL;
- case EXPR:
- return ! as_expr();
+ case ANY:
+ return as_any().empty();
default:
+ add_error_context(_("While applying is_realzero to %1:") << *this);
throw_(value_error, _("Cannot determine if %1 is really zero") << label());
}
return false;
@@ -1392,18 +1386,18 @@ bool value_t::is_zero() const
case SCOPE:
return as_scope() == NULL;
- case EXPR:
- return ! as_expr();
+ case ANY:
+ return as_any().empty();
default:
+ add_error_context(_("While applying is_zero to %1:") << *this);
throw_(value_error, _("Cannot determine if %1 is zero") << label());
}
return false;
}
-value_t value_t::value(const bool primary_only,
- const optional<datetime_t>& moment,
- const optional<commodity_t&>& in_terms_of) const
+value_t value_t::value(const optional<datetime_t>& moment,
+ const optional<commodity_t&>& in_terms_of) const
{
switch (type()) {
case INTEGER:
@@ -1411,13 +1405,13 @@ value_t value_t::value(const bool primary_only,
case AMOUNT:
if (optional<amount_t> val =
- as_amount().value(primary_only, moment, in_terms_of))
+ as_amount().value(moment, in_terms_of))
return *val;
return NULL_VALUE;
case BALANCE:
if (optional<balance_t> bal =
- as_balance().value(primary_only, moment, in_terms_of))
+ as_balance().value(moment, in_terms_of))
return *bal;
return NULL_VALUE;
@@ -1425,6 +1419,7 @@ value_t value_t::value(const bool primary_only,
break;
}
+ add_error_context(_("While finding valuation of %1:") << *this);
throw_(value_error, _("Cannot find the value of %1") << label());
return NULL_VALUE;
}
@@ -1441,9 +1436,9 @@ value_t value_t::price() const
}
}
-value_t value_t::exchange_commodities(const std::string& commodities,
- const bool add_prices,
- const optional<datetime_t>& moment)
+value_t value_t::exchange_commodities(const std::string& commodities,
+ const bool add_prices,
+ const optional<datetime_t>& moment)
{
scoped_array<char> buf(new char[commodities.length() + 1]);
@@ -1453,11 +1448,11 @@ value_t value_t::exchange_commodities(const std::string& commodities,
p;
p = std::strtok(NULL, ",")) {
if (commodity_t * commodity =
- commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
- moment)) {
- value_t result = value(false, moment, *commodity);
+ commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
+ moment)) {
+ value_t result = value(moment, *commodity);
if (! result.is_null())
- return result;
+ return result;
}
}
return *this;
@@ -1472,6 +1467,10 @@ void value_t::in_place_reduce()
case BALANCE:
as_balance_lval().in_place_reduce();
return;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_reduce();
+ return;
default:
return;
}
@@ -1488,6 +1487,10 @@ void value_t::in_place_unreduce()
case BALANCE:
as_balance_lval().in_place_unreduce();
return;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_unreduce();
+ return;
default:
return;
}
@@ -1512,6 +1515,7 @@ value_t value_t::abs() const
break;
}
+ add_error_context(_("While taking abs of %1:") << *this);
throw_(value_error, _("Cannot abs %1") << label());
return NULL_VALUE;
}
@@ -1527,17 +1531,15 @@ void value_t::in_place_round()
case BALANCE:
as_balance_lval().in_place_round();
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(value.rounded());
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_round();
return;
- }
default:
break;
}
+ add_error_context(_("While rounding %1:") << *this);
throw_(value_error, _("Cannot set rounding for %1") << label());
}
@@ -1552,17 +1554,15 @@ void value_t::in_place_truncate()
case BALANCE:
as_balance_lval().in_place_truncate();
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(value.truncated());
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_truncate();
return;
- }
default:
break;
}
+ add_error_context(_("While truncating %1:") << *this);
throw_(value_error, _("Cannot truncate %1") << label());
}
@@ -1577,17 +1577,15 @@ void value_t::in_place_floor()
case BALANCE:
as_balance_lval().in_place_floor();
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(value.floored());
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_floor();
return;
- }
default:
break;
}
+ add_error_context(_("While flooring %1:") << *this);
throw_(value_error, _("Cannot floor %1") << label());
}
@@ -1602,43 +1600,46 @@ void value_t::in_place_unround()
case BALANCE:
as_balance_lval().in_place_unround();
return;
- case SEQUENCE: {
- value_t temp;
- foreach (const value_t& value, as_sequence())
- temp.push_back(value.unrounded());
- *this = temp;
+ case SEQUENCE:
+ foreach (value_t& value, as_sequence_lval())
+ value.in_place_unround();
return;
- }
default:
break;
}
+ add_error_context(_("While unrounding %1:") << *this);
throw_(value_error, _("Cannot unround %1") << label());
}
void value_t::annotate(const annotation_t& details)
{
- if (is_amount())
+ if (is_amount()) {
as_amount_lval().annotate(details);
- else
+ } else {
+ add_error_context(_("While attempting to annotate %1:") << *this);
throw_(value_error, _("Cannot annotate %1") << label());
+ }
}
bool value_t::has_annotation() const
{
- if (is_amount())
+ if (is_amount()) {
return as_amount().has_annotation();
- else
+ } else {
+ add_error_context(_("While checking if %1 has annotations:") << *this);
throw_(value_error,
- _("Cannot determine whether %1 is annotated") << label());
+ _("Cannot determine whether %1 is annotated") << label());
+ }
return false;
}
annotation_t& value_t::annotation()
{
- if (is_amount())
+ if (is_amount()) {
return as_amount_lval().annotation();
- else {
+ } else {
+ add_error_context(_("While requesting the annotations of %1:") << *this);
throw_(value_error, _("Cannot request annotation of %1") << label());
return as_amount_lval().annotation(); // quiet g++ warning
}
@@ -1658,13 +1659,13 @@ value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
case STRING:
case MASK:
case SCOPE:
- case EXPR:
+ case ANY:
return *this;
case SEQUENCE: {
sequence_t temp;
foreach (const value_t& value, as_sequence())
- temp.push_back(value.strip_annotations(what_to_keep));
+ temp.push_back(new value_t(value.strip_annotations(what_to_keep)));
return temp;
}
@@ -1681,18 +1682,56 @@ value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
return NULL_VALUE;
}
-void value_t::print(std::ostream& out,
- const int first_width,
- const int latter_width,
- const bool right_justify,
- const bool colorize) const
+string value_t::label(optional<type_t> the_type) const
+{
+ switch (the_type ? *the_type : type()) {
+ case VOID:
+ return _("an uninitialized value");
+ case BOOLEAN:
+ return _("a boolean");
+ case DATETIME:
+ return _("a date/time");
+ case DATE:
+ return _("a date");
+ case INTEGER:
+ return _("an integer");
+ case AMOUNT:
+ return _("an amount");
+ case BALANCE:
+ return _("a balance");
+ case STRING:
+ return _("a string");
+ case MASK:
+ return _("a regexp");
+ case SEQUENCE:
+ return _("a sequence");
+ case SCOPE:
+ return _("a scope");
+ case ANY:
+ if (as_any().type() == typeid(expr_t::ptr_op_t))
+ return _("an expr");
+ else
+ return _("an object");
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ assert(false);
+ return _("<invalid>");
+}
+
+void value_t::print(std::ostream& out,
+ const int first_width,
+ const int latter_width,
+ const uint_least8_t flags) const
{
if (first_width > 0 &&
(! is_amount() || as_amount().is_zero()) &&
! is_balance() && ! is_string()) {
out.width(first_width);
- if (right_justify)
+ if (flags & AMOUNT_PRINT_RIGHT_JUSTIFY)
out << std::right;
else
out << std::left;
@@ -1716,8 +1755,9 @@ void value_t::print(std::ostream& out,
break;
case INTEGER:
- if (colorize && as_long() < 0)
- justify(out, to_string(), first_width, right_justify, true);
+ if (flags & AMOUNT_PRINT_COLORIZE && as_long() < 0)
+ justify(out, to_string(), first_width,
+ flags & AMOUNT_PRINT_RIGHT_JUSTIFY, true);
else
out << as_long();
break;
@@ -1727,21 +1767,20 @@ void value_t::print(std::ostream& out,
out << 0;
} else {
std::ostringstream buf;
- buf << as_amount();
- justify(out, buf.str(), first_width, right_justify,
- colorize && as_amount().sign() < 0);
+ as_amount().print(buf, flags);
+ justify(out, buf.str(), first_width, flags & AMOUNT_PRINT_RIGHT_JUSTIFY,
+ flags & AMOUNT_PRINT_COLORIZE && as_amount().sign() < 0);
}
break;
}
case BALANCE:
- as_balance().print(out, first_width, latter_width, right_justify,
- colorize);
+ as_balance().print(out, first_width, latter_width, flags);
break;
case STRING:
if (first_width > 0)
- justify(out, as_string(), first_width, right_justify);
+ justify(out, as_string(), first_width, flags & AMOUNT_PRINT_RIGHT_JUSTIFY);
else
out << as_string();
break;
@@ -1755,12 +1794,11 @@ void value_t::print(std::ostream& out,
bool first = true;
foreach (const value_t& value, as_sequence()) {
if (first)
- first = false;
+ first = false;
else
- out << ", ";
+ out << ", ";
- value.print(out, first_width, latter_width, right_justify,
- colorize);
+ value.print(out, first_width, latter_width, flags);
}
out << ')';
break;
@@ -1769,16 +1807,18 @@ void value_t::print(std::ostream& out,
case SCOPE:
out << "<#SCOPE>";
break;
- case EXPR:
- out << "<#EXPR ";
- if (as_expr())
- as_expr().print(out);
- else
- out << "null";
- out << ">";
+ case ANY:
+ if (as_any().type() == typeid(expr_t::ptr_op_t)) {
+ out << "<#EXPR ";
+ as_any<expr_t::ptr_op_t>()->print(out);
+ out << ">";
+ } else {
+ out << "<#OBJECT>";
+ }
break;
default:
+ add_error_context(_("While printing %1:") << *this);
throw_(value_error, _("Cannot print %1") << label());
}
}
@@ -1825,14 +1865,14 @@ void value_t::dump(std::ostream& out, const bool relaxed) const
foreach (const char& ch, as_string()) {
switch (ch) {
case '"':
- out << "\\\"";
- break;
+ out << "\\\"";
+ break;
case '\\':
- out << "\\\\";
- break;
+ out << "\\\\";
+ break;
default:
- out << ch;
- break;
+ out << ch;
+ break;
}
}
out << '"';
@@ -1845,11 +1885,11 @@ void value_t::dump(std::ostream& out, const bool relaxed) const
case SCOPE:
out << as_scope();
break;
- case EXPR:
- if (as_expr())
- as_expr().dump(out);
+ case ANY:
+ if (as_any().type() == typeid(expr_t::ptr_op_t))
+ as_any<expr_t::ptr_op_t>()->dump(out);
else
- out << "null";
+ out << boost::unsafe_any_cast<const void *>(&as_any());
break;
case SEQUENCE: {
@@ -1857,9 +1897,9 @@ void value_t::dump(std::ostream& out, const bool relaxed) const
bool first = true;
foreach (const value_t& value, as_sequence()) {
if (first)
- first = false;
+ first = false;
else
- out << ", ";
+ out << ", ";
value.dump(out, relaxed);
}
@@ -1887,7 +1927,7 @@ bool value_t::valid() const
}
bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
- const std::list<sort_value_t>& right_values)
+ const std::list<sort_value_t>& right_values)
{
std::list<sort_value_t>::const_iterator left_iter = left_values.begin();
std::list<sort_value_t>::const_iterator right_iter = right_values.begin();
@@ -1895,16 +1935,16 @@ bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
while (left_iter != left_values.end() && right_iter != right_values.end()) {
// Don't even try to sort balance values
if (! (*left_iter).value.is_balance() &&
- ! (*right_iter).value.is_balance()) {
+ ! (*right_iter).value.is_balance()) {
DEBUG("value.sort",
- " Comparing " << (*left_iter).value << " < " << (*right_iter).value);
+ " Comparing " << (*left_iter).value << " < " << (*right_iter).value);
if ((*left_iter).value < (*right_iter).value) {
- DEBUG("value.sort", " is less");
- return ! (*left_iter).inverted;
+ DEBUG("value.sort", " is less");
+ return ! (*left_iter).inverted;
}
else if ((*left_iter).value > (*right_iter).value) {
- DEBUG("value.sort", " is greater");
- return (*left_iter).inverted;
+ DEBUG("value.sort", " is greater");
+ return (*left_iter).inverted;
}
}
left_iter++; right_iter++;
@@ -1963,7 +2003,7 @@ void to_xml(std::ostream& out, const value_t& value)
}
case value_t::SCOPE:
- case value_t::EXPR:
+ case value_t::ANY:
default:
assert(false);
break;
diff --git a/src/value.h b/src/value.h
index 2e3998f3..6fe24da6 100644
--- a/src/value.h
+++ b/src/value.h
@@ -49,7 +49,7 @@
#ifndef _VALUE_H
#define _VALUE_H
-#include "balance.h" // includes amount.h
+#include "balance.h" // includes amount.h
#include "mask.h"
namespace ledger {
@@ -57,7 +57,6 @@ namespace ledger {
DECLARE_EXCEPTION(value_error, std::runtime_error);
class scope_t;
-class expr_t;
/**
* @class value_t
@@ -75,21 +74,21 @@ class expr_t;
*/
class value_t
: public ordered_field_operators<value_t,
- equality_comparable<value_t, balance_t,
- additive<value_t, balance_t,
- multiplicative<value_t, balance_t,
- ordered_field_operators<value_t, amount_t,
- ordered_field_operators<value_t, double,
- ordered_field_operators<value_t, unsigned long,
- ordered_field_operators<value_t, long> > > > > > > >
+ equality_comparable<value_t, balance_t,
+ additive<value_t, balance_t,
+ multiplicative<value_t, balance_t,
+ ordered_field_operators<value_t, amount_t,
+ ordered_field_operators<value_t, double,
+ ordered_field_operators<value_t, unsigned long,
+ ordered_field_operators<value_t, long> > > > > > > >
{
public:
/**
* The sequence_t member type abstracts the type used to represent a
* resizable "array" of value_t objects.
*/
- typedef std::deque<value_t> sequence_t;
- typedef sequence_t::iterator iterator;
+ typedef ptr_deque<value_t> sequence_t;
+ typedef sequence_t::iterator iterator;
typedef sequence_t::const_iterator const_iterator;
typedef sequence_t::difference_type difference_type;
@@ -99,18 +98,18 @@ public:
* type_t.
*/
enum type_t {
- VOID, // a null value (i.e., uninitialized)
- BOOLEAN, // a boolean
- DATETIME, // a date and time (Boost posix_time)
- DATE, // a date (Boost gregorian::date)
- INTEGER, // a signed integer value
- AMOUNT, // a ledger::amount_t
- BALANCE, // a ledger::balance_t
- STRING, // a string object
- MASK, // a regular expression mask
- SEQUENCE, // a vector of value_t objects
- SCOPE, // a pointer to a scope
- EXPR // a pointer to a value expression
+ VOID, // a null value (i.e., uninitialized)
+ BOOLEAN, // a boolean
+ DATETIME, // a date and time (Boost posix_time)
+ DATE, // a date (Boost gregorian::date)
+ INTEGER, // a signed integer value
+ AMOUNT, // a ledger::amount_t
+ BALANCE, // a ledger::balance_t
+ STRING, // a string object
+ MASK, // a regular expression mask
+ SEQUENCE, // a vector of value_t objects
+ SCOPE, // a pointer to a scope
+ ANY // a pointer to an arbitrary object
};
private:
@@ -128,18 +127,18 @@ private:
* The `type' member holds the value_t::type_t value representing
* the type of the object stored.
*/
- variant<bool, // BOOLEAN
- datetime_t, // DATETIME
- date_t, // DATE
- long, // INTEGER
- amount_t, // AMOUNT
- balance_t *, // BALANCE
- string, // STRING
- mask_t, // MASK
- sequence_t *, // SEQUENCE
- scope_t *, // SCOPE
- expr_t * // EXPR
- > data;
+ variant<bool, // BOOLEAN
+ datetime_t, // DATETIME
+ date_t, // DATE
+ long, // INTEGER
+ amount_t, // AMOUNT
+ balance_t *, // BALANCE
+ string, // STRING
+ mask_t, // MASK
+ sequence_t *, // SEQUENCE
+ scope_t *, // SCOPE
+ boost::any // ANY
+ > data;
type_t type;
@@ -160,7 +159,7 @@ private:
TRACE_CTOR(value_t::storage_t, "");
}
- public: // so `checked_delete' can access it
+ public: // so `checked_delete' can access it
/**
* Destructor. Must only be called when the reference count has
* reached zero. The `destroy' method is used to do the actual
@@ -193,16 +192,16 @@ private:
*/
void acquire() const {
DEBUG("value.storage.refcount",
- "Acquiring " << this << ", refc now " << refc + 1);
+ "Acquiring " << this << ", refc now " << refc + 1);
VERIFY(refc >= 0);
refc++;
}
void release() const {
DEBUG("value.storage.refcount",
- "Releasing " << this << ", refc now " << refc - 1);
+ "Releasing " << this << ", refc now " << refc - 1);
VERIFY(refc > 0);
if (--refc == 0)
- checked_delete(this);
+ checked_delete(this);
}
friend inline void intrusive_ptr_add_ref(value_t::storage_t * storage) {
@@ -216,15 +215,15 @@ private:
DEBUG("value.storage.refcount", "Destroying " << this);
switch (type) {
case VOID:
- return;
+ return;
case BALANCE:
- checked_delete(boost::get<balance_t *>(data));
- break;
+ checked_delete(boost::get<balance_t *>(data));
+ break;
case SEQUENCE:
- checked_delete(boost::get<sequence_t *>(data));
- break;
+ checked_delete(boost::get<sequence_t *>(data));
+ break;
default:
- break;
+ break;
}
data = false;
type = VOID;
@@ -256,8 +255,7 @@ private:
* subsequently be modified.
*/
void _dup() {
- VERIFY(storage);
- if (storage->refc > 1)
+ if (storage && storage->refc > 1)
storage = new storage_t(*storage.get());
}
@@ -354,10 +352,13 @@ public:
TRACE_CTOR(value_t, "scope_t *");
set_scope(item);
}
- explicit value_t(const expr_t& item) {
- TRACE_CTOR(value_t, "const expr_t&");
- set_expr(item);
+#if 0
+ template <typename T>
+ explicit value_t(T& item) {
+ TRACE_CTOR(value_t, "T&");
+ set_any(item);
}
+#endif
/**
* Destructor. This does not do anything, because the intrusive_ptr
@@ -424,8 +425,8 @@ public:
temp.in_place_negate();
return temp;
}
- void in_place_negate(); // exists for efficiency's sake
- void in_place_not(); // exists for efficiency's sake
+ void in_place_negate(); // exists for efficiency's sake
+ void in_place_not(); // exists for efficiency's sake
value_t operator-() const {
return negated();
@@ -466,25 +467,24 @@ public:
temp.in_place_reduce();
return temp;
}
- void in_place_reduce(); // exists for efficiency's sake
+ void in_place_reduce(); // exists for efficiency's sake
value_t unreduced() const {
value_t temp(*this);
temp.in_place_unreduce();
return temp;
}
- void in_place_unreduce(); // exists for efficiency's sake
+ void in_place_unreduce(); // exists for efficiency's sake
// Return the "market value" of a given value at a specific time.
- value_t value(const bool primary_only = false,
- const optional<datetime_t>& moment = none,
- const optional<commodity_t&>& in_terms_of = none) const;
+ value_t value(const optional<datetime_t>& moment = none,
+ const optional<commodity_t&>& in_terms_of = none) const;
value_t price() const;
- value_t exchange_commodities(const std::string& commodities,
- const bool add_prices = false,
- const optional<datetime_t>& moment = none);
+ value_t exchange_commodities(const std::string& commodities,
+ const bool add_prices = false,
+ const optional<datetime_t>& moment = none);
/**
* Truth tests.
@@ -531,7 +531,7 @@ public:
* is_string()
* is_mask()
* is_sequence()
- * is_pointer()
+ * is_any()
*
* There are corresponding as_*() methods that represent a value as a
* reference to its underlying type. For example, as_long() returns a
@@ -730,29 +730,54 @@ public:
}
/**
- * Dealing with expr pointers.
+ * Dealing with any type at all is bit involved because we actually
+ * deal with typed object. For example, if you call as_any it returns
+ * a boost::any object, but if you use as_any<type_t>, then it returns
+ * a type_t by value.
*/
- bool is_expr() const {
- return is_type(EXPR);
+ bool is_any() const {
+ return is_type(ANY);
+ }
+ template <typename T>
+ bool is_any() const {
+ return (is_type(ANY) &&
+ boost::get<boost::any>(storage->data).type() == typeid(T));
+ }
+ boost::any& as_any_lval() {
+ VERIFY(is_any());
+ _dup();
+ return boost::get<boost::any>(storage->data);
}
- expr_t& as_expr_lval() const {
- VERIFY(is_expr());
- return *boost::get<expr_t *>(storage->data);
+ template <typename T>
+ T& as_any_lval() {
+ return any_cast<T&>(as_any_lval());
}
- const expr_t& as_expr() const {
- VERIFY(is_expr());
- return *boost::get<expr_t *>(storage->data);
+ const boost::any& as_any() const {
+ VERIFY(is_any());
+ return boost::get<boost::any>(storage->data);
+ }
+ template <typename T>
+ const T& as_any() const {
+ return any_cast<const T&>(as_any());
+ }
+ void set_any(const boost::any& val) {
+ set_type(ANY);
+ storage->data = val;
+ }
+ template <typename T>
+ void set_any(T& val) {
+ set_type(ANY);
+ storage->data = boost::any(val);
}
- void set_expr(const expr_t& val);
/**
* Data conversion methods. These methods convert a value object to
* its underlying type, where possible. If not possible, an
* exception is thrown.
*/
- bool to_boolean() const;
- int to_int() const;
- long to_long() const;
+ bool to_boolean() const;
+ int to_int() const;
+ long to_long() const;
datetime_t to_datetime() const;
date_t to_date() const;
amount_t to_amount() const;
@@ -837,7 +862,7 @@ public:
*this = sequence_t();
if (! is_sequence())
in_place_cast(SEQUENCE);
- as_sequence_lval().push_front(val);
+ as_sequence_lval().push_front(new value_t(val));
}
void push_back(const value_t& val) {
@@ -845,7 +870,7 @@ public:
*this = sequence_t();
if (! is_sequence())
in_place_cast(SEQUENCE);
- as_sequence_lval().push_back(val);
+ as_sequence_lval().push_back(new value_t(val));
}
void pop_back() {
@@ -864,13 +889,13 @@ public:
std::size_t new_size = seq.size();
if (new_size == 0) {
#if BOOST_VERSION >= 103700
- storage.reset();
+ storage.reset();
#else
- storage = intrusive_ptr<storage_t>();
+ storage = intrusive_ptr<storage_t>();
#endif
}
else if (new_size == 1) {
- *this = seq.front();
+ *this = seq.front();
}
}
}
@@ -905,48 +930,16 @@ public:
/**
* Informational methods.
*/
- string label(optional<type_t> the_type = none) const {
- switch (the_type ? *the_type : type()) {
- case VOID:
- return _("an uninitialized value");
- case BOOLEAN:
- return _("a boolean");
- case DATETIME:
- return _("a date/time");
- case DATE:
- return _("a date");
- case INTEGER:
- return _("an integer");
- case AMOUNT:
- return _("an amount");
- case BALANCE:
- return _("a balance");
- case STRING:
- return _("a string");
- case MASK:
- return _("a regexp");
- case SEQUENCE:
- return _("a sequence");
- case SCOPE:
- return _("a scope");
- case EXPR:
- return _("a expr");
- default:
- assert(false);
- break;
- }
- assert(false);
- return _("<invalid>");
- }
+ string label(optional<type_t> the_type = none) const;
/**
* Printing methods.
*/
- void print(std::ostream& out,
- const int first_width = -1,
- const int latter_width = -1,
- const bool right_justify = false,
- const bool colorize = false) const;
+ void print(std::ostream& out,
+ const int first_width = -1,
+ const int latter_width = -1,
+ const uint_least8_t flags = AMOUNT_PRINT_NO_FLAGS) const;
+
void dump(std::ostream& out, const bool relaxed = true) const;
/**
@@ -994,6 +987,10 @@ inline string value_context(const value_t& val) {
return buf.str();
}
+inline value_t scope_value(scope_t * val) {
+ return value_t(val);
+}
+
template <typename T>
inline value_t& add_or_set_value(value_t& lhs, const T& rhs) {
if (lhs.is_null())
@@ -1012,7 +1009,7 @@ struct sort_value_t
};
bool sort_value_is_less_than(const std::list<sort_value_t>& left_values,
- const std::list<sort_value_t>& right_values);
+ const std::list<sort_value_t>& right_values);
void to_xml(std::ostream& out, const value_t& value);
diff --git a/src/xact.cc b/src/xact.cc
index 495e6410..35d61edd 100644
--- a/src/xact.cc
+++ b/src/xact.cc
@@ -36,7 +36,6 @@
#include "account.h"
#include "journal.h"
#include "pool.h"
-#include "interactive.h"
namespace ledger {
@@ -101,9 +100,9 @@ value_t xact_base_t::magnitude() const
foreach (const post_t * post, posts) {
if (post->amount.sign() > 0) {
if (post->cost)
- halfbal += *post->cost;
+ halfbal += *post->cost;
else
- halfbal += post->amount;
+ halfbal += post->amount;
}
}
return halfbal;
@@ -125,31 +124,17 @@ 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,
- _("Only one posting with null amount allowed per transaction"));
+ _("Only one posting with null amount allowed per transaction"));
}
else {
null_post = post;
@@ -162,7 +147,7 @@ bool xact_base_t::finalize()
DEBUG("xact.finalize", "balance is " << balance.label());
if (balance.is_balance())
DEBUG("xact.finalize", "balance commodity count = "
- << balance.as_balance().amounts.size());
+ << balance.as_balance().amounts.size());
#endif
// If there is only one post, balance against the default account if one has
@@ -174,29 +159,30 @@ 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;
foreach (post_t * post, posts) {
- if (! post->amount.is_null()) {
- if (post->amount.has_annotation())
- top_post = post;
- else if (! top_post)
- top_post = post;
+ if (! post->amount.is_null() && post->must_balance()) {
+ if (post->amount.has_annotation())
+ top_post = post;
+ else if (! top_post)
+ top_post = post;
}
if (post->cost && ! post->has_flags(POST_COST_CALCULATED)) {
- saw_cost = true;
- break;
+ saw_cost = true;
+ break;
}
}
@@ -211,92 +197,123 @@ bool xact_base_t::finalize()
const amount_t * y = &(*a++).second;
if (x->commodity() != top_post->amount.commodity()) {
- const amount_t * t = x;
- x = y;
- y = t;
+ const amount_t * t = x;
+ x = y;
+ y = t;
}
if (*x && *y) {
- DEBUG("xact.finalize", "primary amount = " << *x);
- DEBUG("xact.finalize", "secondary amount = " << *y);
-
- commodity_t& comm(x->commodity());
- amount_t per_unit_cost;
- amount_t total_cost;
-
- foreach (post_t * post, posts) {
- if (post != top_post && post->must_balance() &&
- ! post->amount.is_null() &&
- post->amount.has_annotation() &&
- post->amount.annotation().price) {
- amount_t temp = *post->amount.annotation().price * post->amount;
- if (total_cost.is_null()) {
- total_cost = temp;
- y = &total_cost;
- } else {
- total_cost += temp;
- }
- DEBUG("xact.finalize", "total_cost = " << total_cost);
- }
- }
- per_unit_cost = (*y / *x).abs().unrounded();
-
- DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
-
- foreach (post_t * post, posts) {
- const amount_t& amt(post->amount);
-
- if (post->must_balance() && amt.commodity() == comm) {
- balance -= amt;
- post->cost = per_unit_cost * amt;
- post->add_flags(POST_COST_CALCULATED);
- balance += *post->cost;
-
- DEBUG("xact.finalize", "set post->cost to = " << *post->cost);
- }
- }
+ DEBUG("xact.finalize", "primary amount = " << *x);
+ DEBUG("xact.finalize", "secondary amount = " << *y);
+
+ commodity_t& comm(x->commodity());
+ amount_t per_unit_cost;
+ amount_t total_cost;
+ const amount_t * prev_y = y;
+
+ foreach (post_t * post, posts) {
+ if (post != top_post && post->must_balance() &&
+ ! post->amount.is_null() &&
+ post->amount.has_annotation() &&
+ post->amount.annotation().price) {
+ amount_t temp = *post->amount.annotation().price * post->amount;
+ if (total_cost.is_null()) {
+ total_cost = temp;
+ y = &total_cost;
+ }
+ else if (total_cost.commodity() == temp.commodity()) {
+ total_cost += temp;
+ }
+ else {
+ DEBUG("xact.finalize",
+ "multiple price commodities, aborting price calc");
+ y = prev_y;
+ break;
+ }
+ DEBUG("xact.finalize", "total_cost = " << total_cost);
+ }
+ }
+ per_unit_cost = (*y / *x).abs().unrounded();
+
+ DEBUG("xact.finalize", "per_unit_cost = " << per_unit_cost);
+
+ foreach (post_t * post, posts) {
+ const amount_t& amt(post->amount);
+
+ if (post->must_balance() && amt.commodity() == comm) {
+ balance -= amt;
+ post->cost = per_unit_cost * amt;
+ post->add_flags(POST_COST_CALCULATED);
+ balance += *post->cost;
+
+ DEBUG("xact.finalize", "set post->cost to = " << *post->cost);
+ }
+ }
}
}
}
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).rounded()) {
- DEBUG("xact.finalize", "gain_loss = " << gain_loss);
-
- 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"));
-
- post_t * p = new post_t(account, gain_loss, ITEM_GENERATED);
- p->set_state(post->state());
- add_post(p);
- DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
+ datetime_t(date(), time_duration(0, 0, 0, 0)));
+
+ 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());
+
+ 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));
+ }
+ add_post(p);
+ DEBUG("xact.finalize", "added gain_loss, balance = " << balance);
+ } else {
+ DEBUG("xact.finalize", "gain_loss would have displayed as zero");
+ }
+ }
+ } else {
+ 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);
+ }
+
+ 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);
}
- } else {
- post->amount = breakdown.amount;
- DEBUG("xact.finalize", "added breakdown, balance = " << balance);
}
}
@@ -311,16 +328,16 @@ bool xact_base_t::finalize()
bool first = true;
const balance_t& bal(balance.as_balance());
foreach (const balance_t::amounts_map::value_type& pair, bal.amounts) {
- if (first) {
- null_post->amount = pair.second.negated();
- null_post->add_flags(POST_CALCULATED);
- first = false;
- } else {
- post_t * p = new post_t(null_post->account, pair.second.negated(),
- ITEM_GENERATED | POST_CALCULATED);
- p->set_state(null_post->state());
- add_post(p);
- }
+ if (first) {
+ null_post->amount = pair.second.negated();
+ null_post->add_flags(POST_CALCULATED);
+ first = false;
+ } else {
+ post_t * p = new post_t(null_post->account, pair.second.negated(),
+ ITEM_GENERATED | POST_CALCULATED);
+ p->set_state(null_post->state());
+ add_post(p);
+ }
}
}
else if (balance.is_amount()) {
@@ -356,10 +373,10 @@ bool xact_base_t::finalize()
foreach (post_t * post, posts) {
if (! post->amount.is_null()) {
- all_null = false;
- post->amount.in_place_reduce();
+ all_null = false;
+ post->amount.in_place_reduce();
} else {
- some_null = true;
+ some_null = true;
}
post->account->add_post(post);
@@ -369,10 +386,10 @@ bool xact_base_t::finalize()
}
if (all_null)
- return false; // ignore this xact completely
+ return false; // ignore this xact completely
else if (some_null)
throw_(balance_error,
- _("There cannot be null amounts after balancing a transaction"));
+ _("There cannot be null amounts after balancing a transaction"));
}
VERIFY(valid());
@@ -398,7 +415,7 @@ bool xact_base_t::verify()
// 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());
+ p.rounded().reduced() : p.reduced());
}
VERIFY(balance.valid());
@@ -412,7 +429,7 @@ bool xact_base_t::verify()
if (post->amount.commodity() == post->cost->commodity())
throw_(amount_error,
- _("A posting's cost must be of a different commodity than its amount"));
+ _("A posting's cost must be of a different commodity than its amount"));
}
if (! balance.is_null() && ! balance.is_zero()) {
@@ -482,39 +499,35 @@ namespace {
return (*Func)(find_scope<xact_t>(scope));
}
- value_t fn_any(call_scope_t& scope)
+ value_t fn_any(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- post_t& post(find_scope<post_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ post_t& post(args.context<post_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, post.xact->posts) {
- bind_scope_t bound_scope(scope, *p);
- if (expr.calc(bound_scope).to_boolean())
- return true;
+ bind_scope_t bound_scope(args, *p);
+ if (expr->calc(bound_scope, args.locus, args.depth).to_boolean())
+ return true;
}
return false;
}
- value_t fn_all(call_scope_t& scope)
+ value_t fn_all(call_scope_t& args)
{
- interactive_t args(scope, "X&X");
-
- post_t& post(find_scope<post_t>(scope));
- expr_t& expr(args.get<expr_t&>(0));
+ post_t& post(args.context<post_t>());
+ expr_t::ptr_op_t expr(args.get<expr_t::ptr_op_t>(0));
foreach (post_t * p, post.xact->posts) {
- bind_scope_t bound_scope(scope, *p);
- if (! expr.calc(bound_scope).to_boolean())
- return false;
+ bind_scope_t bound_scope(args, *p);
+ if (! expr->calc(bound_scope, args.locus, args.depth).to_boolean())
+ return false;
}
return true;
}
}
expr_t::ptr_op_t xact_t::lookup(const symbol_t::kind_t kind,
- const string& name)
+ const string& name)
{
if (kind != symbol_t::FUNCTION)
return item_t::lookup(kind, name);
@@ -580,13 +593,13 @@ namespace {
case expr_t::op_t::O_MATCH:
if (op->left()->kind == expr_t::op_t::IDENT &&
- op->left()->as_ident() == "account" &&
- op->right()->kind == expr_t::op_t::VALUE &&
- op->right()->as_value().is_mask())
- return op->right()->as_value().as_mask()
- .match(post.reported_account()->fullname());
+ op->left()->as_ident() == "account" &&
+ op->right()->kind == expr_t::op_t::VALUE &&
+ op->right()->as_value().is_mask())
+ return op->right()->as_value().as_mask()
+ .match(post.reported_account()->fullname());
else
- break;
+ break;
case expr_t::op_t::O_NOT:
return ! post_pred(op->left(), post);
@@ -599,9 +612,9 @@ namespace {
case expr_t::op_t::O_QUERY:
if (post_pred(op->left(), post))
- return post_pred(op->right()->left(), post);
+ return post_pred(op->right()->left(), post);
else
- return post_pred(op->right()->right(), post);
+ return post_pred(op->right()->right(), post);
default:
break;
@@ -628,109 +641,141 @@ void auto_xact_t::extend_xact(xact_base_t& xact)
bool matches_predicate = false;
if (try_quick_match) {
try {
- bool found_memoized_result = false;
- if (! memoized_results.empty()) {
- std::map<string, bool>::iterator i =
- memoized_results.find(initial_post->account->fullname());
- if (i != memoized_results.end()) {
- found_memoized_result = true;
- matches_predicate = (*i).second;
- }
- }
-
- // Since the majority of people who use automated transactions simply
- // match against account names, try using a *much* faster version of
- // the predicate evaluator.
- if (! found_memoized_result) {
- matches_predicate = post_pred(predicate.get_op(), *initial_post);
- memoized_results.insert
- (std::pair<string, bool>(initial_post->account->fullname(),
- matches_predicate));
- }
+ bool found_memoized_result = false;
+ if (! memoized_results.empty()) {
+ std::map<string, bool>::iterator i =
+ memoized_results.find(initial_post->account->fullname());
+ if (i != memoized_results.end()) {
+ found_memoized_result = true;
+ matches_predicate = (*i).second;
+ }
+ }
+
+ // Since the majority of people who use automated transactions simply
+ // match against account names, try using a *much* faster version of
+ // the predicate evaluator.
+ if (! found_memoized_result) {
+ matches_predicate = post_pred(predicate.get_op(), *initial_post);
+ memoized_results.insert
+ (std::pair<string, bool>(initial_post->account->fullname(),
+ matches_predicate));
+ }
}
catch (...) {
- DEBUG("xact.extend.fail",
- "The quick matcher failed, going back to regular eval");
- try_quick_match = false;
- matches_predicate = predicate(*initial_post);
+ DEBUG("xact.extend.fail",
+ "The quick matcher failed, going back to regular eval");
+ try_quick_match = false;
+ matches_predicate = predicate(*initial_post);
}
} else {
matches_predicate = predicate(*initial_post);
}
if (matches_predicate) {
+ bind_scope_t bound_scope(*scope_t::default_scope, *initial_post);
+
+ if (deferred_notes) {
+ foreach (deferred_tag_data_t& data, *deferred_notes) {
+ if (data.apply_to_post == NULL)
+ initial_post->parse_tags(data.tag_data.c_str(), bound_scope,
+ data.overwrite_existing);
+ }
+ }
+ if (check_exprs) {
+ foreach (check_expr_pair& pair, *check_exprs) {
+ if (pair.second == auto_xact_t::EXPR_GENERAL) {
+ pair.first.calc(bound_scope);
+ }
+ else if (! pair.first.calc(bound_scope).to_boolean()) {
+ if (pair.second == auto_xact_t::EXPR_ASSERTION) {
+ throw_(parse_error,
+ _("Transaction assertion failed: %1") << pair.first);
+ } else {
+ warning_(_("Transaction check failed: %1") << pair.first);
+ }
+ }
+ }
+ }
+
foreach (post_t * post, posts) {
- amount_t post_amount;
- if (post->amount.is_null()) {
- if (! post->amount_expr)
- throw_(amount_error,
- _("Automated transaction's posting has no amount"));
-
- bind_scope_t bound_scope(*scope_t::default_scope, *initial_post);
- value_t result(post->amount_expr->calc(bound_scope));
- if (result.is_long()) {
- post_amount = result.to_amount();
- } else {
- if (! result.is_amount())
- throw_(amount_error,
- _("Amount expressions must result in a simple amount"));
- post_amount = result.as_amount();
- }
- } else {
- post_amount = post->amount;
- }
-
- amount_t amt;
- if (! post_amount.commodity())
- amt = initial_post->amount * post_amount;
- else
- amt = post_amount;
+ amount_t post_amount;
+ if (post->amount.is_null()) {
+ if (! post->amount_expr)
+ throw_(amount_error,
+ _("Automated transaction's posting has no amount"));
+
+ value_t result(post->amount_expr->calc(bound_scope));
+ if (result.is_long()) {
+ post_amount = result.to_amount();
+ } else {
+ if (! result.is_amount())
+ throw_(amount_error,
+ _("Amount expressions must result in a simple amount"));
+ post_amount = result.as_amount();
+ }
+ } else {
+ post_amount = post->amount;
+ }
+
+ amount_t amt;
+ if (! post_amount.commodity())
+ amt = initial_post->amount * post_amount;
+ else
+ amt = post_amount;
#if defined(DEBUG_ON)
- IF_DEBUG("xact.extend") {
- DEBUG("xact.extend",
- "Initial post on line " << initial_post->pos->beg_line << ": "
- << "amount " << initial_post->amount << " (precision "
- << initial_post->amount.precision() << ")");
-
- if (initial_post->amount.keep_precision())
- DEBUG("xact.extend", " precision is kept");
-
- DEBUG("xact.extend",
- "Posting on line " << post->pos->beg_line << ": "
- << "amount " << post_amount << ", amt " << amt
- << " (precision " << post_amount.precision()
- << " != " << amt.precision() << ")");
-
- if (post_amount.keep_precision())
- DEBUG("xact.extend", " precision is kept");
- if (amt.keep_precision())
- DEBUG("xact.extend", " amt precision is kept");
- }
+ IF_DEBUG("xact.extend") {
+ DEBUG("xact.extend",
+ "Initial post on line " << initial_post->pos->beg_line << ": "
+ << "amount " << initial_post->amount << " (precision "
+ << initial_post->amount.precision() << ")");
+
+ if (initial_post->amount.keep_precision())
+ DEBUG("xact.extend", " precision is kept");
+
+ DEBUG("xact.extend",
+ "Posting on line " << post->pos->beg_line << ": "
+ << "amount " << post_amount << ", amt " << amt
+ << " (precision " << post_amount.precision()
+ << " != " << amt.precision() << ")");
+
+ if (post_amount.keep_precision())
+ DEBUG("xact.extend", " precision is kept");
+ if (amt.keep_precision())
+ DEBUG("xact.extend", " amt precision is kept");
+ }
#endif // defined(DEBUG_ON)
- account_t * account = post->account;
- string fullname = account->fullname();
- assert(! fullname.empty());
-
- if (contains(fullname, "$account")) {
- fullname = regex_replace(fullname, regex("\\$account\\>"),
- initial_post->account->fullname());
- while (account->parent)
- account = account->parent;
- account = account->find_account(fullname);
- }
-
- // Copy over details so that the resulting post is a mirror of
- // the automated xact's one.
- post_t * new_post = new post_t(account, amt);
- new_post->copy_details(*post);
- new_post->add_flags(ITEM_GENERATED);
-
- xact.add_post(new_post);
- new_post->account->add_post(new_post);
-
- if (new_post->must_balance())
- needs_further_verification = true;
+ account_t * account = post->account;
+ string fullname = account->fullname();
+ assert(! fullname.empty());
+
+ if (contains(fullname, "$account")) {
+ fullname = regex_replace(fullname, regex("\\$account\\>"),
+ initial_post->account->fullname());
+ while (account->parent)
+ account = account->parent;
+ account = account->find_account(fullname);
+ }
+
+ // Copy over details so that the resulting post is a mirror of
+ // the automated xact's one.
+ post_t * new_post = new post_t(account, amt);
+ new_post->copy_details(*post);
+ new_post->add_flags(ITEM_GENERATED);
+
+ xact.add_post(new_post);
+ new_post->account->add_post(new_post);
+
+ if (new_post->must_balance())
+ needs_further_verification = true;
+
+ if (deferred_notes) {
+ foreach (deferred_tag_data_t& data, *deferred_notes) {
+ if (data.apply_to_post == post)
+ new_post->parse_tags(data.tag_data.c_str(), bound_scope,
+ data.overwrite_existing);
+ }
+ }
}
}
}
@@ -739,20 +784,13 @@ void auto_xact_t::extend_xact(xact_base_t& xact)
xact.verify();
}
- catch (const std::exception& err) {
+ catch (const std::exception&) {
add_error_context(item_context(*this, _("While applying automated transaction")));
add_error_context(item_context(xact, _("While extending transaction")));
throw;
}
}
-void extend_xact_base(journal_t * journal,
- xact_base_t& base)
-{
- foreach (auto_xact_t * xact, journal->auto_xacts)
- xact->extend_xact(base);
-}
-
void to_xml(std::ostream& out, const xact_t& xact)
{
push_xml x(out, "transaction", true, true);
@@ -795,18 +833,18 @@ void to_xml(std::ostream& out, const xact_t& xact)
push_xml y(out, "metadata");
foreach (const item_t::string_map::value_type& pair, *xact.metadata) {
if (pair.second.first) {
- push_xml z(out, "variable");
- {
- push_xml w(out, "key");
- out << y.guard(pair.first);
- }
- {
- push_xml w(out, "value");
- out << y.guard(*pair.second.first);
- }
+ push_xml z(out, "variable");
+ {
+ push_xml w(out, "key");
+ out << y.guard(pair.first);
+ }
+ {
+ push_xml w(out, "value");
+ to_xml(out, *pair.second.first);
+ }
} else {
- push_xml z(out, "tag");
- out << y.guard(pair.first);
+ push_xml z(out, "tag");
+ out << y.guard(pair.first);
}
}
}
diff --git a/src/xact.h b/src/xact.h
index c6c61f95..4879967f 100644
--- a/src/xact.h
+++ b/src/xact.h
@@ -106,7 +106,7 @@ class xact_t : public xact_base_t
{
public:
optional<string> code;
- string payee;
+ string payee;
xact_t() {
TRACE_CTOR(xact_t, "");
@@ -117,13 +117,23 @@ public:
TRACE_DTOR(xact_t);
}
+ virtual string description() {
+ if (pos) {
+ std::ostringstream buf;
+ buf << _("transaction at line %1") << pos->beg_line;
+ return buf.str();
+ } else {
+ return string(_("generated transaction"));
+ }
+ }
+
virtual void add_post(post_t * post);
string idstring() const;
string id() const;
virtual expr_t::ptr_op_t lookup(const symbol_t::kind_t kind,
- const string& name);
+ const string& name);
virtual bool valid() const;
@@ -150,6 +160,32 @@ public:
std::map<string, bool> memoized_results;
+ enum xact_expr_kind_t {
+ EXPR_GENERAL,
+ EXPR_ASSERTION,
+ EXPR_CHECK
+ };
+
+ typedef std::pair<expr_t, xact_expr_kind_t> check_expr_pair;
+ typedef std::list<check_expr_pair> check_expr_list;
+
+ optional<check_expr_list> check_exprs;
+
+ struct deferred_tag_data_t {
+ string tag_data;
+ bool overwrite_existing;
+ post_t * apply_to_post;
+
+ deferred_tag_data_t(string _tag_data,
+ bool _overwrite_existing)
+ : tag_data(_tag_data), overwrite_existing(_overwrite_existing),
+ apply_to_post(NULL) {}
+ };
+
+ typedef std::list<deferred_tag_data_t> deferred_notes_list;
+
+ optional<deferred_notes_list> deferred_notes;
+
auto_xact_t() : try_quick_match(true) {
TRACE_CTOR(auto_xact_t, "");
}
@@ -168,6 +204,24 @@ public:
TRACE_DTOR(auto_xact_t);
}
+ virtual string description() {
+ if (pos) {
+ std::ostringstream buf;
+ buf << _("automated transaction at line %1") << pos->beg_line;
+ return buf.str();
+ } else {
+ return string(_("generated automated transaction"));
+ }
+ }
+
+ virtual void parse_tags(const char * p,
+ scope_t&,
+ bool overwrite_existing = true) {
+ if (! deferred_notes)
+ deferred_notes = deferred_notes_list();
+ deferred_notes->push_back(deferred_tag_data_t(p, overwrite_existing));
+ }
+
virtual void extend_xact(xact_base_t& xact);
#if defined(HAVE_BOOST_SERIALIZATION)
@@ -180,6 +234,8 @@ private:
void serialize(Archive& ar, const unsigned int /* version */) {
ar & boost::serialization::base_object<xact_base_t>(*this);
ar & predicate;
+ ar & check_exprs;
+ ar & deferred_notes;
}
#endif // HAVE_BOOST_SERIALIZATION
};
@@ -188,7 +244,7 @@ class period_xact_t : public xact_base_t
{
public:
date_interval_t period;
- string period_string;
+ string period_string;
period_xact_t() {
TRACE_CTOR(period_xact_t, "");
@@ -206,6 +262,16 @@ class period_xact_t : public xact_base_t
TRACE_DTOR(period_xact_t);
}
+ virtual string description() {
+ if (pos) {
+ std::ostringstream buf;
+ buf << _("periodic transaction at line %1") << pos->beg_line;
+ return buf.str();
+ } else {
+ return string(_("generated periodic transaction"));
+ }
+ }
+
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
@@ -221,7 +287,7 @@ private:
#endif // HAVE_BOOST_SERIALIZATION
};
-typedef std::list<xact_t *> xacts_list;
+typedef std::list<xact_t *> xacts_list;
typedef std::list<auto_xact_t *> auto_xacts_list;
typedef std::list<period_xact_t *> period_xacts_list;
diff --git a/src/xml.cc b/src/xml.cc
index 5dd10012..15710d44 100644
--- a/src/xml.cc
+++ b/src/xml.cc
@@ -43,8 +43,8 @@ namespace ledger {
namespace {
void xml_account(std::ostream& out, const account_t * acct) {
if ((acct->has_xdata() &&
- acct->xdata().has_flags(ACCOUNT_EXT_VISITED)) ||
- acct->children_with_flags(ACCOUNT_EXT_VISITED)) {
+ acct->xdata().has_flags(ACCOUNT_EXT_VISITED)) ||
+ acct->children_with_flags(ACCOUNT_EXT_VISITED)) {
out << "<account id=\"";
out.width(sizeof(unsigned long) * 2);
out.fill('0');
@@ -54,15 +54,15 @@ namespace {
out << "<name>" << acct->name << "</name>\n";
value_t total = acct->amount();
if (! total.is_null()) {
- out << "<amount>\n";
- to_xml(out, total);
- out << "</amount>\n";
+ out << "<amount>\n";
+ to_xml(out, total);
+ out << "</amount>\n";
}
total = acct->total();
if (! total.is_null()) {
- out << "<total>\n";
- to_xml(out, total);
- out << "</total>\n";
+ out << "<total>\n";
+ to_xml(out, total);
+ out << "</total>\n";
}
out << "</account>\n";
}
@@ -76,8 +76,8 @@ namespace {
foreach (const post_t * post, xact->posts)
if (post->has_xdata() &&
- post->xdata().has_flags(POST_EXT_VISITED))
- to_xml(out, *post);
+ post->xdata().has_flags(POST_EXT_VISITED))
+ to_xml(out, *post);
out << "</transaction>\n";
}
@@ -115,7 +115,7 @@ void format_xml::operator()(post_t& post)
assert(post.xdata().has_flags(POST_EXT_VISITED));
commodities.insert(commodities_pair(post.amount.commodity().symbol(),
- &post.amount.commodity()));
+ &post.amount.commodity()));
if (transactions_set.find(post.xact) == transactions_set.end())
transactions.push_back(post.xact);
diff --git a/test/CheckComments.py b/test/CheckComments.py
new file mode 100644
index 00000000..446137b0
--- /dev/null
+++ b/test/CheckComments.py
@@ -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)
diff --git a/test/CheckTests.py b/test/CheckTests.py
new file mode 100755
index 00000000..1a364ff4
--- /dev/null
+++ b/test/CheckTests.py
@@ -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)
diff --git a/test/GenerateTests.py b/test/GenerateTests.py
index d60e0581..79c7ae04 100755
--- a/test/GenerateTests.py
+++ b/test/GenerateTests.py
@@ -4,13 +4,30 @@
# final balance is the same as what the balance report shows.
import sys
-#import re
+import re
from difflib import ndiff
+multiproc = False
+try:
+ from multiprocessing import Pool
+ multiproc = True
+except:
+ pass
+
+args = sys.argv
+jobs = 1
+match = re.match('-j([0-9]+)?', args[1])
+if match:
+ args = [args[0]] + args[2:]
+ if match.group(1):
+ jobs = int(match.group(1))
+if jobs == 1:
+ multiproc = False
+
from LedgerHarness import LedgerHarness
-harness = LedgerHarness(sys.argv)
+harness = LedgerHarness(args)
#def normalize(line):
# match = re.match("((\s*)([A-Za-z]+)?(\s*)([-0-9.]+)(\s*)([A-Za-z]+)?)( (.+))?$", line)
@@ -104,14 +121,30 @@ def generation_test(seed):
beg_range = 1
end_range = 20
-if len(sys.argv) > 4:
- beg_range = int(sys.argv[3])
- end_range = int(sys.argv[4])
+if len(args) > 4:
+ beg_range = int(args[3])
+ end_range = int(args[4])
-for i in range(beg_range, end_range):
+def run_gen_test(i):
if generation_test(i):
harness.success()
else:
harness.failure()
+ return harness.failed
+
+if multiproc:
+ pool = Pool(jobs*2)
+else:
+ pool = None
+
+if pool:
+ 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)
+
+if pool:
+ pool.close()
+ pool.join()
harness.exit()
diff --git a/test/LedgerHarness.py b/test/LedgerHarness.py
index ea8290d4..44e4e61c 100755
--- a/test/LedgerHarness.py
+++ b/test/LedgerHarness.py
@@ -6,6 +6,27 @@ import re
from subprocess import Popen, PIPE
+import copy_reg
+import types
+
+def _pickle_method(method):
+ func_name = method.im_func.__name__
+ obj = method.im_self
+ cls = method.im_class
+ return _unpickle_method, (func_name, obj, cls)
+
+def _unpickle_method(func_name, obj, cls):
+ for cls in cls.mro():
+ try:
+ func = cls.__dict__[func_name]
+ except KeyError:
+ pass
+ else:
+ break
+ return func.__get__(obj, cls)
+
+copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
+
class LedgerHarness:
ledger = None
sourcepath = None
diff --git a/test/RegressTests.py b/test/RegressTests.py
index 13a0a113..2d8ef8e8 100755
--- a/test/RegressTests.py
+++ b/test/RegressTests.py
@@ -5,24 +5,42 @@ import os
import re
import tempfile
+multiproc = False
+try:
+ from multiprocessing import Pool
+ multiproc = True
+except:
+ pass
+
from string import join
from difflib import unified_diff
from LedgerHarness import LedgerHarness
-harness = LedgerHarness(sys.argv)
-tests = sys.argv[3]
+args = sys.argv
+jobs = 1
+match = re.match('-j([0-9]+)?', args[1])
+if match:
+ args = [args[0]] + args[2:]
+ if match.group(1):
+ jobs = int(match.group(1))
+if jobs == 1:
+ multiproc = False
+
+harness = LedgerHarness(args)
+tests = args[3]
if not os.path.isdir(tests) and not os.path.isfile(tests):
sys.exit(1)
-class RegressFile:
+class RegressFile(object):
def __init__(self, filename):
self.filename = filename
self.fd = open(self.filename)
def is_directive(self, line):
return line == "<<<\n" or \
+ line == ">>>\n" or \
line == ">>>1\n" or \
line == ">>>2\n" or \
line.startswith("===")
@@ -34,7 +52,7 @@ class RegressFile:
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)
@@ -42,10 +60,10 @@ class RegressFile:
def read_test(self, last_test = None):
test = {
'command': None,
- 'input': None,
- 'output': None,
- 'error': None,
- 'exitcode': None
+ 'input': "",
+ 'output': "",
+ 'error': "",
+ 'exitcode': 0
}
if last_test:
test['input'] = last_test['input']
@@ -54,7 +72,7 @@ class RegressFile:
while line:
if line == "<<<\n":
(test['input'], line) = self.read_section()
- elif line == ">>>1\n":
+ elif line == ">>>\n" or line == ">>>1\n":
(test['output'], line) = self.read_section()
elif line == ">>>2\n":
(test['error'], line) = self.read_section()
@@ -141,19 +159,37 @@ class RegressFile:
while test:
self.run_test(test)
test = self.read_test(test)
+ return harness.failed
def close(self):
self.fd.close()
-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()
- entry.close()
-else:
- entry = RegressFile(tests)
- entry.run_tests()
+def do_test(path):
+ entry = RegressFile(path)
+ failed = entry.run_tests()
entry.close()
+ return failed
+
+if __name__ == '__main__':
+ if multiproc:
+ pool = Pool(jobs*2)
+ else:
+ pool = None
+
+ if os.path.isdir(tests):
+ 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()
+ entry.close()
+
+ if pool:
+ pool.close()
+ pool.join()
-harness.exit()
+ harness.exit()
diff --git a/test/UnitTests.cc b/test/UnitTests.cc
index 2c5c0406..af3f6311 100644
--- a/test/UnitTests.cc
+++ b/test/UnitTests.cc
@@ -35,7 +35,7 @@ public:
void testInitialization() {
assertEqual(std::string("Hello, world!"),
- std::string("Hello, world!"));
+ std::string("Hello, world!"));
}
private:
@@ -61,7 +61,7 @@ int main(int argc, char* argv[])
// Retreive test path from command line first argument. Default to
// "" which resolves to the top level suite.
std::string testPath = ((argc > index) ? std::string(argv[index]) :
- std::string(""));
+ std::string(""));
// Create the event manager and test controller
CPPUNIT_NS::TestResult controller;
diff --git a/test/UnitTests.h b/test/UnitTests.h
index d9314ddf..a7bfcf9e 100644
--- a/test/UnitTests.h
+++ b/test/UnitTests.h
@@ -6,14 +6,14 @@
#include <cppunit/Portability.h>
#define assertDoublesEqual(x,y,z,w) CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE(x,y,z,w)
-#define assertEqual(x,y) CPPUNIT_ASSERT_EQUAL(x,y)
-#define assertNotEqual(x,y) CPPUNIT_ASSERT((x) != (y))
-#define assertTrue(x) CPPUNIT_ASSERT(x)
-#define assertFalse(x) CPPUNIT_ASSERT(! (x))
-#define assertValid(x) CPPUNIT_ASSERT((x).valid())
+#define assertEqual(x,y) CPPUNIT_ASSERT_EQUAL(x,y)
+#define assertNotEqual(x,y) CPPUNIT_ASSERT((x) != (y))
+#define assertTrue(x) CPPUNIT_ASSERT(x)
+#define assertFalse(x) CPPUNIT_ASSERT(! (x))
+#define assertValid(x) CPPUNIT_ASSERT((x).valid())
#define assertEqualMessage(x,y,z) CPPUNIT_ASSERT_EQUAL_MESSAGE(x,y,z)
-#define assertMessage(x,y) CPPUNIT_ASSERT_MESSAGE(x,y)
-#define assertThrow(x,y) CPPUNIT_ASSERT_THROW(x,y)
+#define assertMessage(x,y) CPPUNIT_ASSERT_MESSAGE(x,y)
+#define assertThrow(x,y) CPPUNIT_ASSERT_THROW(x,y)
#define internalAmount(x) amount_t::exact(x)
diff --git a/test/baseline/feat-check.test b/test/baseline/feat-check.test
new file mode 100644
index 00000000..4029dfcd
--- /dev/null
+++ b/test/baseline/feat-check.test
@@ -0,0 +1,18 @@
+bal
+<<<
+= /Checking/
+ check account =~ /Foo/
+
+2010-06-24 Sample
+ Expenses:Food $100
+ Assets:Checking
+
+check account("Assets:Checking").all(account =~ /Expense/)
+>>>
+ $-100 Assets:Checking
+ $100 Expenses:Food
+--------------------
+ 0
+>>>2
+Warning: Transaction check failed: account =~ /Foo/
+Warning: Check failed: account("Assets:Checking").all(account =~ /Expense/)
diff --git a/test/baseline/feat-fixated-prices.test b/test/baseline/feat-fixated-prices.test
index 11330dea..83c4bcce 100644
--- a/test/baseline/feat-fixated-prices.test
+++ b/test/baseline/feat-fixated-prices.test
@@ -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
diff --git a/test/baseline/opt-abbrev-len.test b/test/baseline/opt-abbrev-len.test
index 40313b22..59164163 100644
--- a/test/baseline/opt-abbrev-len.test
+++ b/test/baseline/opt-abbrev-len.test
@@ -4,8 +4,8 @@ reg --abbrev-len=4
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX Asse:Inve:Vang:VMMXX 0.350 VMMXX 0.350 VMMXX
- Inco:Divi:Vang:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX Asse:Inve:Vangua:VMMXX 0.350 VMMXX 0.350 VMMXX
+ Inco:Divi:Vangua:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-account.test b/test/baseline/opt-account.test
index 10176fde..e577d72b 100644
--- a/test/baseline/opt-account.test
+++ b/test/baseline/opt-account.test
@@ -4,8 +4,8 @@ reg --account='payee + ":" + commodity'
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX RD:VM:As:In:Va:VMMXX 0.350 VMMXX 0.350 VMMXX
-07-Feb-02 RD VMMXX RD:$:In:Di:Va:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX RD:VM:As:In:Vang:VMMXX 0.350 VMMXX 0.350 VMMXX
+07-Feb-02 RD VMMXX RD:$:In:Di:Vangu:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-actual-dates.test b/test/baseline/opt-actual-dates.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-actual-dates.test
diff --git a/test/baseline/opt-add-budget.test b/test/baseline/opt-add-budget.test
index 535335d3..d2cd6945 100644
--- a/test/baseline/opt-add-budget.test
+++ b/test/baseline/opt-add-budget.test
@@ -1,4 +1,4 @@
-reg --add-budget books cards
+reg --add-budget books cards --now=2009/12/31
<<<
~ monthly
Expenses:Books $10.00
diff --git a/test/baseline/opt-amount-width.test b/test/baseline/opt-amount-width.test
index 32282214..c79229dc 100644
--- a/test/baseline/opt-amount-width.test
+++ b/test/baseline/opt-amount-width.test
@@ -4,8 +4,8 @@ reg --amount-width=18
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Investm:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Dividen:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-amount.test b/test/baseline/opt-amount.test
index 2ebbf055..36107fa8 100644
--- a/test/baseline/opt-amount.test
+++ b/test/baseline/opt-amount.test
@@ -4,7 +4,7 @@ reg --amount=10
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 10 10
- In:Di:Vanguard:VMMXX 10 20
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 10 10
+ In:Divid:Vanguar:VMMXX 10 20
>>>2
=== 0
diff --git a/test/baseline/opt-anon.test b/test/baseline/opt-anon.test
deleted file mode 100644
index 6fe6b75f..00000000
--- a/test/baseline/opt-anon.test
+++ /dev/null
@@ -1,11 +0,0 @@
-reg --anon
-<<<
-2007/02/02 RD VMMXX
- Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
- Income:Dividends:Vanguard:VMMXX $-0.35
->>>1
-07-Feb-02 6a93dcb3 da:20:5d:27:988a9c3a 0.350 VMMXX 0.350 VMMXX
- da:1c:b6:27:988a9c3a $-0.35 $-0.35
- 0.350 VMMXX
->>>2
-=== 0
diff --git a/test/baseline/opt-bold-if.test b/test/baseline/opt-bold-if.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-bold-if.test
diff --git a/test/baseline/opt-budget-format.test b/test/baseline/opt-budget-format.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-budget-format.test
diff --git a/test/baseline/opt-budget.test b/test/baseline/opt-budget.test
index eb2ade9d..67b4e85e 100644
--- a/test/baseline/opt-budget.test
+++ b/test/baseline/opt-budget.test
@@ -1,4 +1,4 @@
-reg --budget books
+reg --budget books --now=2009/12/31
<<<
~ monthly
Expenses:Books $10.00
diff --git a/test/baseline/opt-budget_only.test b/test/baseline/opt-budget_only.test
new file mode 100644
index 00000000..b052ed36
--- /dev/null
+++ b/test/baseline/opt-budget_only.test
@@ -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
diff --git a/test/baseline/opt-budget_range.test b/test/baseline/opt-budget_range.test
new file mode 100644
index 00000000..7c8ee2d2
--- /dev/null
+++ b/test/baseline/opt-budget_range.test
@@ -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
diff --git a/test/baseline/opt-cleared-format.test b/test/baseline/opt-cleared-format.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-cleared-format.test
diff --git a/test/baseline/opt-collapse-if-zero.test b/test/baseline/opt-collapse-if-zero.test
index fb4d33fd..ec3aa6d3 100644
--- a/test/baseline/opt-collapse-if-zero.test
+++ b/test/baseline/opt-collapse-if-zero.test
@@ -8,8 +8,8 @@ reg --collapse-if-zero
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-columns.test b/test/baseline/opt-columns.test
index 4dc28d9b..ae8145b9 100644
--- a/test/baseline/opt-columns.test
+++ b/test/baseline/opt-columns.test
@@ -4,8 +4,8 @@ reg --columns=100
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:Investments:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Dividends:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX Asse:Investment:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
+ Incom:Dividends:Vanguard:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-commodity-as-account.test b/test/baseline/opt-commodity-as-account.test
index 2e723347..20756688 100644
--- a/test/baseline/opt-commodity-as-account.test
+++ b/test/baseline/opt-commodity-as-account.test
@@ -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:In:Va:VMMXX 0.350 VMMXX 0.350 VMMXX
-07-Feb-02 RD VMMXX $:In:Di:Vanguard: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
diff --git a/test/baseline/opt-commodity-as-payee.test b/test/baseline/opt-commodity-as-payee.test
index 2f829b4a..dbc91b72 100644
--- a/test/baseline/opt-commodity-as-payee.test
+++ b/test/baseline/opt-commodity-as-payee.test
@@ -4,8 +4,8 @@ reg --payee=commodity
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
-07-Feb-02 $ In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+07-Feb-02 $ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-count.test b/test/baseline/opt-count.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-count.test
diff --git a/test/baseline/opt-date-format.test b/test/baseline/opt-date-format.test
index b4e1a332..0d3ee6fa 100644
--- a/test/baseline/opt-date-format.test
+++ b/test/baseline/opt-date-format.test
@@ -4,8 +4,8 @@ reg --date-format='%Y'
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-2007 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+2007 RD VMMXX As:Investm:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Dividen:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-date-width.test b/test/baseline/opt-date-width.test
index 47652099..c7aa7731 100644
--- a/test/baseline/opt-date-width.test
+++ b/test/baseline/opt-date-width.test
@@ -4,8 +4,8 @@ reg --date-width=20
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Investm:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Dividen:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-date.test b/test/baseline/opt-date.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-date.test
diff --git a/test/baseline/opt-datetime-format.test b/test/baseline/opt-datetime-format.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-datetime-format.test
diff --git a/test/baseline/opt-decimal-comma.test b/test/baseline/opt-decimal-comma.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-decimal-comma.test
diff --git a/test/baseline/opt-forecast-while.test b/test/baseline/opt-forecast-while.test
index c2563a75..e3f1c57a 100644
--- a/test/baseline/opt-forecast-while.test
+++ b/test/baseline/opt-forecast-while.test
@@ -244,42 +244,42 @@ reg --now=2009/03/21 --forecast-while='total < $3500' books
09-Nov-30 End of November Expenses:Books $110.00 $2880.00
09-Dec-01 December Expenses:Books $120.00 $3000.00
09-Dec-31 End of December Expenses:Books $120.00 $3120.00
-09-May-01 Forecast transaction Expenses:Books $10.00 $3130.00
-09-Jun-01 Forecast transaction Expenses:Books $10.00 $3140.00
-09-Jul-01 Forecast transaction Expenses:Books $10.00 $3150.00
-09-Aug-01 Forecast transaction Expenses:Books $10.00 $3160.00
-09-Sep-01 Forecast transaction Expenses:Books $10.00 $3170.00
-09-Oct-01 Forecast transaction Expenses:Books $10.00 $3180.00
-09-Nov-01 Forecast transaction Expenses:Books $10.00 $3190.00
-09-Dec-01 Forecast transaction Expenses:Books $10.00 $3200.00
-10-Jan-01 Forecast transaction Expenses:Books $10.00 $3210.00
-10-Feb-01 Forecast transaction Expenses:Books $10.00 $3220.00
-10-Mar-01 Forecast transaction Expenses:Books $10.00 $3230.00
-10-Apr-01 Forecast transaction Expenses:Books $10.00 $3240.00
-10-May-01 Forecast transaction Expenses:Books $10.00 $3250.00
-10-Jun-01 Forecast transaction Expenses:Books $10.00 $3260.00
-10-Jul-01 Forecast transaction Expenses:Books $10.00 $3270.00
-10-Aug-01 Forecast transaction Expenses:Books $10.00 $3280.00
-10-Sep-01 Forecast transaction Expenses:Books $10.00 $3290.00
-10-Oct-01 Forecast transaction Expenses:Books $10.00 $3300.00
-10-Nov-01 Forecast transaction Expenses:Books $10.00 $3310.00
-10-Dec-01 Forecast transaction Expenses:Books $10.00 $3320.00
-11-Jan-01 Forecast transaction Expenses:Books $10.00 $3330.00
-11-Feb-01 Forecast transaction Expenses:Books $10.00 $3340.00
-11-Mar-01 Forecast transaction Expenses:Books $10.00 $3350.00
-11-Apr-01 Forecast transaction Expenses:Books $10.00 $3360.00
-11-May-01 Forecast transaction Expenses:Books $10.00 $3370.00
-11-Jun-01 Forecast transaction Expenses:Books $10.00 $3380.00
-11-Jul-01 Forecast transaction Expenses:Books $10.00 $3390.00
-11-Aug-01 Forecast transaction Expenses:Books $10.00 $3400.00
-11-Sep-01 Forecast transaction Expenses:Books $10.00 $3410.00
-11-Oct-01 Forecast transaction Expenses:Books $10.00 $3420.00
-11-Nov-01 Forecast transaction Expenses:Books $10.00 $3430.00
-11-Dec-01 Forecast transaction Expenses:Books $10.00 $3440.00
-12-Jan-01 Forecast transaction Expenses:Books $10.00 $3450.00
-12-Feb-01 Forecast transaction Expenses:Books $10.00 $3460.00
-12-Mar-01 Forecast transaction Expenses:Books $10.00 $3470.00
-12-Apr-01 Forecast transaction Expenses:Books $10.00 $3480.00
-12-May-01 Forecast transaction Expenses:Books $10.00 $3490.00
+09-Apr-01 Forecast transaction Expenses:Books $10.00 $3130.00
+09-May-01 Forecast transaction Expenses:Books $10.00 $3140.00
+09-Jun-01 Forecast transaction Expenses:Books $10.00 $3150.00
+09-Jul-01 Forecast transaction Expenses:Books $10.00 $3160.00
+09-Aug-01 Forecast transaction Expenses:Books $10.00 $3170.00
+09-Sep-01 Forecast transaction Expenses:Books $10.00 $3180.00
+09-Oct-01 Forecast transaction Expenses:Books $10.00 $3190.00
+09-Nov-01 Forecast transaction Expenses:Books $10.00 $3200.00
+09-Dec-01 Forecast transaction Expenses:Books $10.00 $3210.00
+10-Jan-01 Forecast transaction Expenses:Books $10.00 $3220.00
+10-Feb-01 Forecast transaction Expenses:Books $10.00 $3230.00
+10-Mar-01 Forecast transaction Expenses:Books $10.00 $3240.00
+10-Apr-01 Forecast transaction Expenses:Books $10.00 $3250.00
+10-May-01 Forecast transaction Expenses:Books $10.00 $3260.00
+10-Jun-01 Forecast transaction Expenses:Books $10.00 $3270.00
+10-Jul-01 Forecast transaction Expenses:Books $10.00 $3280.00
+10-Aug-01 Forecast transaction Expenses:Books $10.00 $3290.00
+10-Sep-01 Forecast transaction Expenses:Books $10.00 $3300.00
+10-Oct-01 Forecast transaction Expenses:Books $10.00 $3310.00
+10-Nov-01 Forecast transaction Expenses:Books $10.00 $3320.00
+10-Dec-01 Forecast transaction Expenses:Books $10.00 $3330.00
+11-Jan-01 Forecast transaction Expenses:Books $10.00 $3340.00
+11-Feb-01 Forecast transaction Expenses:Books $10.00 $3350.00
+11-Mar-01 Forecast transaction Expenses:Books $10.00 $3360.00
+11-Apr-01 Forecast transaction Expenses:Books $10.00 $3370.00
+11-May-01 Forecast transaction Expenses:Books $10.00 $3380.00
+11-Jun-01 Forecast transaction Expenses:Books $10.00 $3390.00
+11-Jul-01 Forecast transaction Expenses:Books $10.00 $3400.00
+11-Aug-01 Forecast transaction Expenses:Books $10.00 $3410.00
+11-Sep-01 Forecast transaction Expenses:Books $10.00 $3420.00
+11-Oct-01 Forecast transaction Expenses:Books $10.00 $3430.00
+11-Nov-01 Forecast transaction Expenses:Books $10.00 $3440.00
+11-Dec-01 Forecast transaction Expenses:Books $10.00 $3450.00
+12-Jan-01 Forecast transaction Expenses:Books $10.00 $3460.00
+12-Feb-01 Forecast transaction Expenses:Books $10.00 $3470.00
+12-Mar-01 Forecast transaction Expenses:Books $10.00 $3480.00
+12-Apr-01 Forecast transaction Expenses:Books $10.00 $3490.00
>>>2
=== 0
diff --git a/test/baseline/opt-forecast-years.test b/test/baseline/opt-forecast-years.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-forecast-years.test
diff --git a/test/baseline/opt-forecast_only.test b/test/baseline/opt-forecast_only.test
new file mode 100644
index 00000000..c63ab2a9
--- /dev/null
+++ b/test/baseline/opt-forecast_only.test
@@ -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
diff --git a/test/baseline/opt-gain.test b/test/baseline/opt-gain.test
index 6d139c79..d2e9abfe 100644
--- a/test/baseline/opt-gain.test
+++ b/test/baseline/opt-gain.test
@@ -51,16 +51,16 @@ P 2010/04/01 00:00:00 S 16 P
>>>1
09-Jan-15 Commodities revalued <Revalued> 100 P 100 P
09-Feb-01 Commodities revalued <Revalued> 200 P 300 P
-09-Feb-01 Sample 2a As:Brokerage:Stocks 300 P 600 P
+09-Feb-01 Sample 2a Asset:Brokerage:Stocks 300 P 600 P
09-Mar-01 Commodities revalued <Revalued> 800 P 1400 P
-09-Mar-01 Sample 3a As:Brokerage:Stocks 700 P 2100 P
+09-Mar-01 Sample 3a Asset:Brokerage:Stocks 700 P 2100 P
09-Apr-01 Commodities revalued <Revalued> 2400 P 4500 P
-09-Apr-01 Sample 4a As:Brokerage:Stocks -1500 P 3000 P
+09-Apr-01 Sample 4a Asset:Brokerage:Stocks -1500 P 3000 P
10-Feb-01 Commodities revalued <Revalued> -2400 P 600 P
-10-Feb-01 Sample 2b As:Brokerage:Stocks 300 P 900 P
+10-Feb-01 Sample 2b Asset:Brokerage:Stocks 300 P 900 P
10-Mar-01 Commodities revalued <Revalued> 1200 P 2100 P
-10-Mar-01 Sample 3b As:Brokerage:Stocks 700 P 2800 P
+10-Mar-01 Sample 3b Asset:Brokerage:Stocks 700 P 2800 P
10-Apr-01 Commodities revalued <Revalued> 3200 P 6000 P
-10-Apr-01 Sample 4b As:Brokerage:Stocks -1500 P 4500 P
+10-Apr-01 Sample 4b Asset:Brokerage:Stocks -1500 P 4500 P
>>>2
=== 0
diff --git a/test/baseline/opt-generated.test b/test/baseline/opt-generated.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-generated.test
diff --git a/test/baseline/opt-group-by.test b/test/baseline/opt-group-by.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-group-by.test
diff --git a/test/baseline/opt-group-title-format.test b/test/baseline/opt-group-title-format.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-group-title-format.test
diff --git a/test/baseline/opt-inject.test b/test/baseline/opt-inject.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-inject.test
diff --git a/test/baseline/opt-input-date-format.test b/test/baseline/opt-input-date-format.test
index 0ab5e5c9..4e77bc28 100644
--- a/test/baseline/opt-input-date-format.test
+++ b/test/baseline/opt-input-date-format.test
@@ -4,8 +4,8 @@ reg --input-date-format='%m%%%d%%%Y'
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-invert.test b/test/baseline/opt-invert.test
index 9a9f6d02..c010c264 100644
--- a/test/baseline/opt-invert.test
+++ b/test/baseline/opt-invert.test
@@ -4,8 +4,8 @@ reg --invert
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX -0.350 VMMXX -0.350 VMMXX
- In:Di:Vanguard:VMMXX $0.35 $0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX -0.350 VMMXX -0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $0.35 $0.35
-0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-lot-dates.test b/test/baseline/opt-lot-dates.test
index 2415fb27..1acc93c8 100644
--- a/test/baseline/opt-lot-dates.test
+++ b/test/baseline/opt-lot-dates.test
@@ -1,4 +1,4 @@
-reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lot-dates --unsorted
+reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lot-dates
<<<
C 1.00s = 100c
C 1.00G = 100s
@@ -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
@@ -625,2650 +625,2573 @@ D 1.00G
-1.25G
"Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
- "Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.05G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.02G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -80.00s
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.03G
- "Plans: Wildthorn Mail" 1
+ -77.41s
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
+ -77.80s
-1.25G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.26G
- "Plans: Wildthorn Mail" 1
+ 42c
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.01G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.08G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.00G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -82.50s
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.49G
- "Plans: Wildthorn Mail" 1
+ -75.00s
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.24G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- 50.00s
- -2.50G
- "Plans: Wildthorn Mail" 1
+ 1.75G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.10G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.10G
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -85.00s
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.42G
- "Plans: Wildthorn Mail" 1
+ -84.70s
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.31G
- "Plans: Wildthorn Mail" 1
+ -1.17G
"Plans: Wildthorn Mail" 1 [2006/03/14]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.06G
+ "Plans: Wildthorn Mail" 1 [2006/03/14]
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -2.50G
- "Plans: Wildthorn Mail" 1
+ -1.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -66.67G
- "Plans: Wildthorn Mail" 1
+ -65.42G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -65.83G
- "Plans: Wildthorn Mail" 1
+ -64.58G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -64.16G
- "Plans: Wildthorn Mail" 1
+ -62.91G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.42G
- "Plans: Wildthorn Mail" 1
+ -66.17G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.37G
- "Plans: Wildthorn Mail" 1
+ -66.12G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.32G
- "Plans: Wildthorn Mail" 1
+ -66.07G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.28G
- "Plans: Wildthorn Mail" 1
+ -66.03G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.26G
- "Plans: Wildthorn Mail" 1
+ -66.01G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.38G
- "Plans: Wildthorn Mail" 1
+ -66.13G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.28G
- "Plans: Wildthorn Mail" 1
+ -66.03G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.50G
- "Plans: Wildthorn Mail" 1
+ -66.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -68.50G
- "Plans: Wildthorn Mail" 1
+ -67.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -68.50G
- "Plans: Wildthorn Mail" 1
+ -67.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -68.50G
- "Plans: Wildthorn Mail" 1
+ -67.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -67.67G
- "Plans: Wildthorn Mail" 1
+ -66.42G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -68.50G
- "Plans: Wildthorn Mail" 1
+ -67.25G
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -68.50G
+ -67.25G
"Plans: Mithril Shield Spike" 1 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -70.61G
+ -69.36G
"Plans: Mithril Shield Spike" 1 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -70.61G
+ -69.36G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -72.90G
+ -71.65G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -72.90G
+ -71.65G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -74.40G
+ -73.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -71.40G
+ -70.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -74.40G
+ -73.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -74.40G
+ -73.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- -74.40G
+ -73.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -9.40G
+ -8.15G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 1
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 45.17G
+ 46.42G
"Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
+ "Plans: Mithril Shield Spike" 1
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 42.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
+ "Recipe: Elixir of Giant Growth" 1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 51.68G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 50.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 59.83G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.28G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.51G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.63G
- "Plans: Mithril Shield Spike" 2
+ 46.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.75G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.76G
- "Plans: Mithril Shield Spike" 2
+ 46.66G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.76G
- "Plans: Mithril Shield Spike" 2
+ 46.78G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.90G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.67G
- "Plans: Mithril Shield Spike" 2
+ 46.91G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 39.07G
- "Plans: Mithril Shield Spike" 2
+ 46.92G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.82G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 43.27G
- "Plans: Mithril Shield Spike" 2
+ 47.22G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 58.27G
- "Plans: Mithril Shield Spike" 2
+ 51.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 38.27G
- "Plans: Mithril Shield Spike" 2
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" 1 [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 2 [2006/03/15]
+ "Beaststalker's Belt" -1
+ "Beaststalker's Belt" 1 [2006/03/15]
+ 66.42G
+ "Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" 1 [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 2 [2006/03/15]
+ "Beaststalker's Belt" -1
+ "Beaststalker's Belt" 1 [2006/03/15]
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" 1 [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 2 [2006/03/15]
+ "Beaststalker's Belt" -1
+ "Beaststalker's Belt" 1 [2006/03/15]
+ 46.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.27G
- "Plans: Mithril Shield Spike" 2
+ 45.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.36G
- "Plans: Mithril Shield Spike" 2
+ 45.52G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.27G
- "Plans: Mithril Shield Spike" 2
+ 45.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.27G
- "Plans: Mithril Shield Spike" 2
+ 45.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 67.27G
- "Plans: Mithril Shield Spike" 2
+ 75.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.27G
- "Plans: Mithril Shield Spike" 2
+ 45.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 37.27G
- "Plans: Mithril Shield Spike" 2
+ 45.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 7.27G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 7.27G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.72G
- "Plans: Mithril Shield Spike" 2
+ 15.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.52G
- "Plans: Mithril Shield Spike" 2
+ 15.63G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -21.98G
- "Plans: Mithril Shield Spike" 2
+ 16.17G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -21.23G
- "Plans: Mithril Shield Spike" 2
+ 16.92G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.43G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -21.73G
- "Plans: Mithril Shield Spike" 2
+ 16.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -22.73G
- "Plans: Mithril Shield Spike" 2
+ 15.42G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -4.67G
- "Plans: Mithril Shield Spike" 2
+ 33.48G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -4.67G
- "Plans: Mithril Shield Spike" 2
+ 33.48G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 1
+ "Recipe: Elixir of Giant Growth" -1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -21.23G
- "Plans: Mithril Shield Spike" 2
+ 16.92G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 1
+ "Recipe: Elixir of Giant Growth" -1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -4.67G
- "Plans: Mithril Shield Spike" 2
+ 33.48G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 1
+ "Recipe: Elixir of Giant Growth" -1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
- "Recipe: Elixir of Giant Growth" 1
+ "Recipe: Elixir of Giant Growth" -1
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -3.67G
- "Plans: Mithril Shield Spike" 2
+ 34.48G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.39G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Ace of Warlords" 2
"Ace of Warlords" 2 [2006/03/16]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.13G
- "Plans: Mithril Shield Spike" 2
+ 52.29G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.41G
- "Plans: Mithril Shield Spike" 2
+ 51.57G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 13.38G
- "Plans: Mithril Shield Spike" 2
+ 51.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
- "Plans: Wildthorn Mail" 1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.63G
- "Plans: Mithril Shield Spike" 2
+ 52.79G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 17.17G
- "Plans: Mithril Shield Spike" 2
+ 55.33G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
+ "Ace of Warlords" -2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 1 [2006/03/17]
+ "Ace of Warlords" -1 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
- "Plans: Mithril Shield Spike" 2
+ 52.54G
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -12.52G
+ 25.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -11.52G
+ 26.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -5.52G
+ 32.64G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -6.95G
+ 31.21G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
- "Plans: Mithril Shield Spike" 1
+ "Plans: Mithril Shield Spike" -1
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -3.79G
+ 34.36G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 12.22G
+ 50.38G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 78.00G
+ 116.16G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.21G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.07G
+ 66.23G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 73.97G
+ 112.12G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 82.07G
+ 120.22G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 94.29G
+ 132.45G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 94.30G
+ 132.45G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -1
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 31.95G
+ 70.10G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
- "Wildheart Belt" 1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 73.05G
+ 111.20G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 91.49G
+ 129.65G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 134.94G
+ 173.10G
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 134.94G
+ 173.10G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 110.44G
+ 148.60G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 134.94G
+ 173.10G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.04G
+ 190.20G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.04G
+ 190.20G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 138.94G
+ 177.10G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.04G
+ 190.20G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 156.70G
+ 194.85G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 156.70G
+ 194.85G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 153.04G
+ 191.20G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 156.70G
+ 194.85G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 156.70G
+ 194.85G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 1 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 156.70G
+ 194.85G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 151.20G
+ 189.35G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 167.54G
+ 205.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 167.54G
+ 205.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 153.20G
+ 191.35G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 167.54G
+ 205.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 172.54G
+ 210.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 172.54G
+ 210.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 170.54G
+ 208.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 172.54G
+ 210.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.54G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.54G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3276,24 +3199,28 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 176.54G
+ 214.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3301,24 +3228,28 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.54G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3326,24 +3257,28 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.55G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3351,24 +3286,28 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.54G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
"Harnessing Shadows" 1 [2006/03/17]
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3376,12 +3315,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 187.54G
+ 225.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3389,12 +3329,15 @@ D 1.00G
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3402,12 +3345,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 17.54G
+ 55.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3415,12 +3359,15 @@ D 1.00G
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3428,12 +3375,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 17.82G
+ 55.97G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3441,12 +3389,15 @@ D 1.00G
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3454,12 +3405,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 18.09G
+ 56.25G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3467,12 +3419,15 @@ D 1.00G
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3480,12 +3435,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 17.54G
+ 55.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3493,12 +3449,15 @@ D 1.00G
"Holy Bologna" -1
"Holy Bologna" 1 [2006/03/17]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3506,12 +3465,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 17.54G
+ 55.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3520,12 +3480,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3533,12 +3496,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -182.46G
+ -144.30G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3547,12 +3511,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3560,12 +3527,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -180.69G
+ -142.53G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3574,12 +3542,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3587,12 +3558,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -178.92G
+ -140.76G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3601,12 +3573,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3614,12 +3589,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -177.15G
+ -138.99G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3628,12 +3604,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3641,12 +3620,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -175.38G
+ -137.22G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3655,12 +3635,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3668,12 +3651,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -174.63G
+ -136.47G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3682,12 +3666,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3695,12 +3682,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -182.46G
+ -144.30G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3709,12 +3697,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3722,12 +3713,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -15.93G
+ 22.22G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3736,12 +3728,15 @@ D 1.00G
"Holy Bologna" 1 [2006/03/17]
Nightblade 1 [2006/03/22]
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3749,12 +3744,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -15.93G
+ 22.22G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3764,12 +3760,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3777,12 +3776,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -12.46G
+ 25.70G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3792,12 +3792,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3805,12 +3808,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -15.93G
+ 22.22G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3820,12 +3824,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3833,12 +3840,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -7.73G
+ 30.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3848,12 +3856,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3861,12 +3872,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -1
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -7.73G
+ 30.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3876,12 +3888,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3889,12 +3904,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -13.43G
+ 24.72G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3904,12 +3920,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3917,12 +3936,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -7.73G
+ 30.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3932,12 +3952,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3945,12 +3968,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -6.23G
+ 31.92G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3960,12 +3984,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -3973,12 +4000,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -6.23G
+ 31.92G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -3988,12 +4016,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4001,12 +4032,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -6.23G
+ 31.93G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4016,12 +4048,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4029,12 +4064,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -7.73G
+ 30.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4044,12 +4080,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4057,12 +4096,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4072,12 +4112,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4085,12 +4128,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4101,12 +4145,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4114,12 +4161,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 192.27G
+ 230.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4130,12 +4178,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4143,12 +4194,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4159,12 +4211,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4172,12 +4227,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4188,12 +4244,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4201,12 +4260,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4217,12 +4277,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4230,12 +4293,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 206.27G
+ 244.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4246,12 +4310,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4259,12 +4326,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 216.27G
+ 254.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4275,12 +4343,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4288,12 +4359,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 226.27G
+ 264.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4304,12 +4376,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4317,12 +4392,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 226.33G
+ 264.48G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4333,12 +4409,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4346,12 +4425,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 226.36G
+ 264.52G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4362,12 +4442,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4375,12 +4458,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 226.37G
+ 264.52G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4391,12 +4475,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4404,12 +4491,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4420,12 +4508,15 @@ D 1.00G
Nightblade 1 [2006/03/22]
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4433,12 +4524,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- 152.27G
+ 190.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4450,12 +4542,15 @@ D 1.00G
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
"Orb of Deception" 1 [2006/04/01]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4463,12 +4558,13 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
"Ace of Warlords" -2
"Ace of Warlords" 2 [2006/03/16]
- "Ace of Warlords" 2 [2006/03/17]
"Beaststalker's Belt" -1
"Beaststalker's Belt" 1 [2006/03/15]
- -2.73G
+ 35.42G
"Garona: Book on Treachery" -1
"Garona: Book on Treachery" 1 [2006/03/17]
"Harnessing Shadows" -1
@@ -4480,12 +4576,15 @@ D 1.00G
"Orb of Deception" -1
"Orb of Deception" 1 [2006/03/21]
"Orb of Deception" 1 [2006/04/01]
+ "Plans: Mithril Shield Spike" -2
"Plans: Mithril Shield Spike" 2 [2006/03/15]
+ "Plans: Wildthorn Mail" -1
"Plans: Wildthorn Mail" 1 [2006/03/14]
"Preserved Holly" -5
"Preserved Holly" 5 [2006/03/17]
"Pulsating Hydra Heart" -1
"Pulsating Hydra Heart" 1 [2006/03/16]
+ "Recipe: Elixir of Giant Growth" -2
"Recipe: Elixir of Giant Growth" 2 [2006/03/15]
"The Arcanist's Cookbook" -1
"The Arcanist's Cookbook" 1 [2006/03/17]
@@ -4493,5 +4592,7 @@ D 1.00G
"The Emerald Dream" 1 [2006/03/17]
"Two of Portals" -2
"Two of Portals" 2 [2006/03/19]
+ "Wildheart Belt" -1
+ "Wildheart Belt" 1 [2006/03/17]
>>>2
=== 0
diff --git a/test/baseline/opt-lot-prices.test b/test/baseline/opt-lot-prices.test
index 22aa5ab5..365d4f8a 100644
--- a/test/baseline/opt-lot-prices.test
+++ b/test/baseline/opt-lot-prices.test
@@ -1,4 +1,4 @@
-reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lot-prices --unsorted
+reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lot-prices
<<<
C 1.00s = 100c
C 1.00G = 100s
@@ -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
@@ -624,2268 +624,1529 @@ D 1.00G
"Plans: Wildthorn Mail" 1 {1.25G}
-1.25G
"Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.05G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.02G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.03G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
-1.25G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.26G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.08G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.00G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.49G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- 50.00s
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.10G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.10G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.42G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.31G
- "Plans: Wildthorn Mail" 2 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -80.00s
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -77.41s
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -77.80s
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ 42c
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.01G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -82.50s
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -75.00s
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.24G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ 1.75G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -85.00s
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -84.70s
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.17G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.06G
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -2.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -1.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -66.67G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -65.42G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -65.83G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -64.58G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -64.16G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -62.91G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.42G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.17G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.37G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.12G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.32G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.07G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.28G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.03G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.26G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.01G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.38G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.13G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.28G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.03G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G}
- -67.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -68.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -67.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -68.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -67.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -68.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -67.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -67.67G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -66.42G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -68.50G
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -67.25G
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -68.50G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -67.25G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -70.61G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ -69.36G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -70.61G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -69.36G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -72.90G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -71.65G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Beaststalker's Belt" 1 {65.00G}
- -72.90G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -71.65G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- -71.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -70.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- -9.40G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ -8.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 2 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 2 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 {2.105G}
"Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 2 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 {2.105G}
"Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 2 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- 45.17G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 42.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 51.68G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.28G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.51G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.63G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.75G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.76G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.76G
- "Plans: Mithril Shield Spike" 2 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 2 {2.105G}
"Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.67G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 39.07G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 43.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 2 {1.00G}
"Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 2 {1.00G}
"Recipe: Elixir of Giant Growth" 2 {1.50G}
- 58.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 2 {1.00G}
"Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 2 {1.50G}
- 38.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 50.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 59.83G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.66G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.78G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.90G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.91G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.82G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 47.22G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 51.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 66.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 37.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 37.36G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 45.52G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 37.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 37.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 67.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 75.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- 37.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G}
- 7.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 7.27G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.72G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.52G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -21.98G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -21.23G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -21.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
- "Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 4 {15.00G}
- -21.23G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 2 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- -3.67G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.39G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.63G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 4 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ "Ace of Warlords" 2 {15.00G}
+ 16.17G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 16.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.13G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 13.41G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 2 {1.25G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.63G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 17.17G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 16.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 1 {3.00G}
- "Ace of Warlords" 1 {3.90G}
"Ace of Warlords" 2 {15.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G}
+ "Ace of Warlords" 2 {15.00G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 16.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Recipe: Elixir of Giant Growth" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 34.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Ace of Warlords" 2 {15.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.29G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 51.57G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Plans: Wildthorn Mail" 1 {1.25G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.79G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 55.33G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ "Ace of Warlords" 1 {3.00G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
+ "Pulsating Hydra Heart" 1 {1.00G}
+ "Wildheart Belt" 1 {30.00G}
+ "Ace of Warlords" 1 {3.00G}
+ "Ace of Warlords" 1 {3.90G}
+ 52.54G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -12.52G
+ 25.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -11.52G
+ 26.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -5.52G
+ 32.64G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -6.95G
+ 31.21G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 2 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.105G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 2 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
+ "Plans: Mithril Shield Spike" 1 {2.30G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- -3.79G
+ 34.36G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 12.22G
+ 50.38G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 78.00G
+ 116.16G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.21G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.07G
+ 66.23G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 73.97G
+ 112.12G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 82.07G
+ 120.22G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 94.29G
+ 132.45G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 94.30G
+ 132.45G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
"Ace of Warlords" 1 {3.90G}
- "Ace of Warlords" 2 {15.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 2 {15.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 2 {15.00G}
- 31.95G
+ 70.10G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 2 {15.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 2 {15.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
"Wildheart Belt" 1 {30.00G}
- "Ace of Warlords" 2 {15.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 73.05G
+ 111.20G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G}
"Harnessing Shadows" 1 {5.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 91.49G
+ 129.65G
"Garona: Book on Treachery" 1 {4.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 134.94G
+ 173.10G
"Garona: Book on Treachery" 1 {4.00G}
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 134.94G
+ 173.10G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 110.44G
+ 148.60G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 134.94G
+ 173.10G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 152.04G
+ 190.20G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 152.04G
+ 190.20G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 138.94G
+ 177.10G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 152.04G
+ 190.20G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 156.70G
+ 194.85G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
"Preserved Holly" 5 {20.00s}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 156.70G
+ 194.85G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 153.04G
+ 191.20G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 156.70G
+ 194.85G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
- "Ace of Warlords" 2 {15.00G}
- 156.70G
+ 194.85G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 156.70G
+ 194.85G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 151.20G
+ 189.35G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 167.54G
+ 205.70G
"Holy Bologna" 1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 167.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 205.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 153.20G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 191.35G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 167.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 205.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 172.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 210.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
"Two of Portals" 1 {3.00G}
- "Ace of Warlords" 2 {15.00G}
- 172.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 210.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 170.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 208.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 172.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 210.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 225.70G
"The Emerald Dream" 1 {4.00G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 225.70G
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 176.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 214.70G
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 225.70G
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.55G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 225.70G
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.54G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
+ 225.70G
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 187.54G
+ 225.70G
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 17.54G
+ 55.70G
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 17.82G
+ 55.97G
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 18.09G
+ 56.25G
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 17.54G
+ 55.70G
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- 17.54G
+ 55.70G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -182.46G
+ -144.30G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -180.69G
+ -142.53G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -178.92G
+ -140.76G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -177.15G
+ -138.99G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -175.38G
+ -137.22G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -174.63G
+ -136.47G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -182.46G
+ -144.30G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -15.93G
+ 22.22G
Nightblade 1 {200.00G}
"Orb of Deception" 1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -15.93G
+ 22.22G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -12.46G
+ 25.70G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -15.93G
+ 22.22G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -7.73G
+ 30.42G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Two of Portals" 1 {2.50G}
- "Ace of Warlords" 2 {15.00G}
- -7.73G
+ 30.42G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -13.43G
+ 24.72G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -7.73G
+ 30.42G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -6.23G
+ 31.92G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -6.23G
+ 31.92G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -6.23G
+ 31.93G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -7.73G
+ 30.42G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
+ 190.42G
Nightblade 1 {200.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 192.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 206.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 216.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 226.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 226.33G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 226.36G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 226.37G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- 152.27G
+ 190.42G
+ 230.42G
+ 190.42G
+ 190.42G
+ 190.42G
+ 244.42G
+ 254.42G
+ 264.42G
+ 264.48G
+ 264.52G
+ 264.52G
+ 190.42G
+ 190.42G
"Orb of Deception" 1 {155.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
- "Ace of Warlords" 2 {15.00G}
- -2.73G
+ 35.42G
"Orb of Deception" 1 {155.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G}
- "Plans: Mithril Shield Spike" 1 {2.30G}
- "Plans: Wildthorn Mail" 1 {1.25G}
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
>>>2
=== 0
diff --git a/test/baseline/opt-lots-actual.test b/test/baseline/opt-lots-actual.test
index 39a27363..c0ff4fc1 100644
--- a/test/baseline/opt-lots-actual.test
+++ b/test/baseline/opt-lots-actual.test
@@ -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.8659s} [2006/03/14]
- 1339829c {1.8659s} [2006/03/14]
- 248720c {10.0515s}
- 1339829c {1.8659s} [2006/03/14]
- 248720c {10.0515s}
- -1388.9h
+ 1339829c {1.86590975416s} [2006/03/14]
+ 1339829c {1.86590975416s} [2006/03/14]
+ 248720c {10.051463493s} [2006/03/14]
+ 1339829c {1.86590975416s} [2006/03/14]
+ 248720c {10.051463493s} [2006/03/14]
+ -1388.89h
>>>2
=== 0
reg --format '%(justify(scrub(total_expr), 40, 40, true))\n' --lots-actual
>>>1
1339829c
- 1339829c
- 248720c {10.0515s}
- 1339829c
- 248720c {10.0515s}
- -1388.9h
+ 1588549c
+ 1588549c
+ -1388.89h
>>>2
=== 0
diff --git a/test/baseline/opt-lots.test b/test/baseline/opt-lots.test
index 916a2b2e..af8a4258 100644
--- a/test/baseline/opt-lots.test
+++ b/test/baseline/opt-lots.test
@@ -1,4 +1,4 @@
-reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lots --unsorted
+reg -F '%(justify(scrub(total_expr), 80, 80, true))\n' --lots
<<<
C 1.00s = 100c
C 1.00G = 100s
@@ -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
@@ -625,3284 +625,3375 @@ D 1.00G
-1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
"Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.05G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.02G
+ -80.00s
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
- "Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.03G
+ -77.41s
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
+ -77.80s
-1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.26G
+ 42c
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.01G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.08G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.00G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -82.50s
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.49G
+ -75.00s
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.24G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- 50.00s
- -2.50G
+ 1.75G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.10G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.10G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -85.00s
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.42G
+ -84.70s
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.31G
+ -1.17G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
- -2.50G
+ -1.06G
+ "Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -2.50G
+ -1.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -66.67G
+ -65.42G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -65.83G
+ -64.58G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -64.16G
+ -62.91G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.42G
+ -66.17G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.37G
+ -66.12G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.32G
+ -66.07G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.28G
+ -66.03G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.26G
+ -66.01G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.38G
+ -66.13G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.28G
+ -66.03G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.50G
+ -66.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -68.50G
+ -67.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -68.50G
+ -67.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -68.50G
+ -67.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -67.67G
+ -66.42G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -68.50G
+ -67.25G
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -68.50G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -67.25G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -70.61G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -69.36G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -70.61G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -69.36G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -72.90G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -71.65G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -72.90G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -71.65G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -71.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -70.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- -74.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -73.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -9.40G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ -8.15G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 45.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 42.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
"Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 51.68G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 50.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 59.83G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.28G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.51G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.63G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.75G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.76G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.66G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.76G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.78G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.90G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.67G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.91G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 39.07G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.82G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 43.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 47.22G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 58.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 38.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Beaststalker's Belt" 1 {65.00G} [2006/03/15]
+ "Beaststalker's Belt" -1 {65.00G}
+ 66.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Beaststalker's Belt" 1 {65.00G} [2006/03/15]
+ "Beaststalker's Belt" -1 {65.00G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Beaststalker's Belt" 1 {65.00G} [2006/03/15]
+ "Beaststalker's Belt" -1 {65.00G}
+ 46.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.36G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.52G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 67.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 75.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 37.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 45.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 7.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
"Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 7.27G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.72G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.52G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.63G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -21.98G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 16.17G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -21.23G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 16.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.43G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -21.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 16.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -22.73G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 15.42G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -21.23G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 16.92G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -4.67G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 33.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
- "Recipe: Elixir of Giant Growth" 1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -3.67G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 34.48G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.39G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
- "Ace of Warlords" 2 {15.00G}
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.13G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.29G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.41G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.57G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 13.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 51.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
- "Plans: Wildthorn Mail" 1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.63G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.79G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 17.17G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 55.33G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ 52.54G
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
- "Wildheart Belt" 1 {30.00G}
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 14.38G
+ 52.54G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -12.52G
+ 25.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -11.52G
+ 26.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.52G
+ 29.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -5.52G
+ 32.64G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -6.95G
+ 31.21G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 6.80G
+ 44.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -8.20G
+ 29.96G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.11G}
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
- "Plans: Mithril Shield Spike" 1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -3.79G
+ 34.36G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 12.22G
+ 50.38G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 78.00G
+ 116.16G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 79.00G
+ 117.16G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.21G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.07G
+ 66.23G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 73.97G
+ 112.12G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 82.07G
+ 120.22G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 94.29G
+ 132.45G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 94.30G
+ 132.45G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.80G
+ 66.95G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 28.05G
+ 66.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 31.95G
+ 70.10G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 43.05G
+ 81.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
- "Wildheart Belt" 1 {30.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 73.05G
+ 111.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 86.49G
+ 124.65G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 91.49G
+ 129.65G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 106.44G
+ 144.60G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 134.94G
+ 173.10G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 134.94G
+ 173.10G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 110.44G
+ 148.60G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 134.94G
+ 173.10G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.04G
+ 190.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.04G
+ 190.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 138.94G
+ 177.10G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.04G
+ 190.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 156.70G
+ 194.85G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 156.70G
+ 194.85G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 153.04G
+ 191.20G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 156.70G
+ 194.85G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 156.70G
+ 194.85G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 156.70G
+ 194.85G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 151.20G
+ 189.35G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 167.54G
+ 205.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 167.54G
+ 205.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 153.20G
+ 191.35G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 167.54G
+ 205.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 172.54G
+ 210.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 172.54G
+ 210.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 170.54G
+ 208.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 172.54G
+ 210.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.54G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.54G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -3910,29 +4001,37 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 176.54G
+ 214.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -3940,29 +4039,37 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.54G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -3970,29 +4077,37 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.55G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4000,29 +4115,37 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.54G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
"Harnessing Shadows" -1 {5.00G}
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4030,14 +4153,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 187.54G
+ 225.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4045,15 +4171,20 @@ D 1.00G
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4061,14 +4192,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 17.54G
+ 55.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4076,15 +4210,20 @@ D 1.00G
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4092,14 +4231,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 17.82G
+ 55.97G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4107,15 +4249,20 @@ D 1.00G
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4123,14 +4270,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 18.09G
+ 56.25G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4138,15 +4288,20 @@ D 1.00G
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4154,14 +4309,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 17.54G
+ 55.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4169,15 +4327,20 @@ D 1.00G
"Holy Bologna" 1 {2.00G} [2006/03/17]
"Holy Bologna" -1 {2.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4185,14 +4348,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 17.54G
+ 55.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4201,15 +4367,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4217,14 +4388,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -182.46G
+ -144.30G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4233,15 +4407,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4249,14 +4428,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -180.69G
+ -142.53G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4265,15 +4447,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4281,14 +4468,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -178.92G
+ -140.76G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4297,15 +4487,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4313,14 +4508,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -177.15G
+ -138.99G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4329,15 +4527,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4345,14 +4548,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -175.38G
+ -137.22G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4361,15 +4567,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4377,14 +4588,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -174.63G
+ -136.47G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4393,15 +4607,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4409,14 +4628,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -182.46G
+ -144.30G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4425,15 +4647,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4441,14 +4668,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -15.93G
+ 22.22G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4457,15 +4687,20 @@ D 1.00G
"Holy Bologna" -1 {2.00G}
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4473,14 +4708,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -15.93G
+ 22.22G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4490,15 +4728,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4506,14 +4749,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -12.46G
+ 25.70G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4523,15 +4769,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4539,14 +4790,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -15.93G
+ 22.22G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4556,15 +4810,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4572,14 +4831,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -7.73G
+ 30.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4589,15 +4851,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4605,14 +4872,17 @@ D 1.00G
"Two of Portals" 1 {2.50G} [2006/03/19]
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -7.73G
+ 30.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4622,15 +4892,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4639,14 +4914,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -13.43G
+ 24.72G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4656,15 +4934,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4673,14 +4956,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -7.73G
+ 30.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4690,15 +4976,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4707,14 +4998,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -6.23G
+ 31.92G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4724,15 +5018,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4741,14 +5040,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -6.23G
+ 31.92G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4758,15 +5060,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4775,14 +5082,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -6.23G
+ 31.93G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4792,15 +5102,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4809,14 +5124,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -7.73G
+ 30.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4826,15 +5144,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4843,14 +5166,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4860,15 +5186,20 @@ D 1.00G
Nightblade 1 {200.00G} [2006/03/22]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4877,14 +5208,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4895,15 +5229,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4912,14 +5251,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 192.27G
+ 230.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4930,15 +5272,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4947,14 +5294,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -4965,15 +5315,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -4982,14 +5337,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5000,15 +5358,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5017,14 +5380,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5035,15 +5401,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5052,14 +5423,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 206.27G
+ 244.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5070,15 +5444,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5087,14 +5466,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 216.27G
+ 254.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5105,15 +5487,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5122,14 +5509,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 226.27G
+ 264.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5140,15 +5530,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5157,14 +5552,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 226.33G
+ 264.48G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5175,15 +5573,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5192,14 +5595,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 226.36G
+ 264.52G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5210,15 +5616,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5227,14 +5638,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 226.37G
+ 264.52G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5245,15 +5659,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5262,14 +5681,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5280,15 +5702,20 @@ D 1.00G
Nightblade -1 {200.00G}
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5297,14 +5724,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- 152.27G
+ 190.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5316,15 +5746,20 @@ D 1.00G
"Orb of Deception" 1 {155.00G} [2006/04/01]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5333,14 +5768,17 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
"Ace of Warlords" 1 {3.00G} [2006/03/17]
"Ace of Warlords" -1 {3.00G}
"Ace of Warlords" 1 {3.90G} [2006/03/17]
"Ace of Warlords" -1 {3.90G}
"Ace of Warlords" 2 {15.00G} [2006/03/16]
+ "Ace of Warlords" -2 {15.00G} [2006/03/17]
"Beaststalker's Belt" 1 {65.00G} [2006/03/15]
"Beaststalker's Belt" -1 {65.00G}
- -2.73G
+ 35.42G
"Garona: Book on Treachery" 1 {4.00G} [2006/03/17]
"Garona: Book on Treachery" -1 {4.00G}
"Harnessing Shadows" 1 {5.00G} [2006/03/17]
@@ -5352,15 +5790,20 @@ D 1.00G
"Orb of Deception" 1 {155.00G} [2006/04/01]
"Orb of Deception" 1 {170.00G} [2006/03/21]
"Orb of Deception" -1 {170.00G}
- "Plans: Mithril Shield Spike" 1 {2.11G} [2006/03/15]
+ "Plans: Mithril Shield Spike" 1 {2.105G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.105G}
"Plans: Mithril Shield Spike" 1 {2.30G} [2006/03/15]
+ "Plans: Mithril Shield Spike" -1 {2.30G}
"Plans: Wildthorn Mail" 1 {1.25G} [2006/03/14]
+ "Plans: Wildthorn Mail" -1 {1.25G}
"Preserved Holly" 5 {20.00s} [2006/03/17]
"Preserved Holly" -5 {20.00s}
"Pulsating Hydra Heart" 1 {1.00G} [2006/03/16]
"Pulsating Hydra Heart" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.00G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.00G}
"Recipe: Elixir of Giant Growth" 1 {1.50G} [2006/03/15]
+ "Recipe: Elixir of Giant Growth" -1 {1.50G}
"The Arcanist's Cookbook" 1 {4.00G} [2006/03/17]
"The Arcanist's Cookbook" -1 {4.00G}
"The Emerald Dream" 1 {4.00G} [2006/03/17]
@@ -5369,5 +5812,7 @@ D 1.00G
"Two of Portals" -1 {2.50G}
"Two of Portals" 1 {3.00G} [2006/03/19]
"Two of Portals" -1 {3.00G}
+ "Wildheart Belt" 1 {30.00G} [2006/03/17]
+ "Wildheart Belt" -1 {30.00G}
>>>2
=== 0
diff --git a/test/baseline/opt-lots_basis.test b/test/baseline/opt-lots_basis.test
index d392fe33..85bed988 100644
--- a/test/baseline/opt-lots_basis.test
+++ b/test/baseline/opt-lots_basis.test
@@ -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
diff --git a/test/baseline/opt-lots_basis_base.test b/test/baseline/opt-lots_basis_base.test
index e3aca02d..c4c3c01a 100644
--- a/test/baseline/opt-lots_basis_base.test
+++ b/test/baseline/opt-lots_basis_base.test
@@ -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
diff --git a/test/baseline/opt-market.test b/test/baseline/opt-market.test
index b6c0ed6d..8c5b168a 100644
--- a/test/baseline/opt-market.test
+++ b/test/baseline/opt-market.test
@@ -49,18 +49,18 @@ P 2010/03/01 00:00:00 S 8 P
P 2010/04/01 00:00:00 S 16 P
>>>1
-09-Jan-01 Sample 1a As:Brokerage:Stocks 200 P 200 P
+09-Jan-01 Sample 1a Asset:Brokerage:Stocks 200 P 200 P
09-Feb-01 Commodities revalued <Revalued> 200 P 400 P
-09-Feb-01 Sample 2a As:Brokerage:Stocks 400 P 800 P
+09-Feb-01 Sample 2a Asset:Brokerage:Stocks 400 P 800 P
09-Mar-01 Commodities revalued <Revalued> 800 P 1600 P
-09-Mar-01 Sample 3a As:Brokerage:Stocks 800 P 2400 P
+09-Mar-01 Sample 3a Asset:Brokerage:Stocks 800 P 2400 P
09-Apr-01 Commodities revalued <Revalued> 2400 P 4800 P
-09-Apr-01 Sample 4a As:Brokerage:Stocks -1600 P 3200 P
+09-Apr-01 Sample 4a Asset:Brokerage:Stocks -1600 P 3200 P
10-Feb-01 Commodities revalued <Revalued> -2400 P 800 P
-10-Feb-01 Sample 2b As:Brokerage:Stocks 400 P 1200 P
+10-Feb-01 Sample 2b Asset:Brokerage:Stocks 400 P 1200 P
10-Mar-01 Commodities revalued <Revalued> 1200 P 2400 P
-10-Mar-01 Sample 3b As:Brokerage:Stocks 800 P 3200 P
+10-Mar-01 Sample 3b Asset:Brokerage:Stocks 800 P 3200 P
10-Apr-01 Commodities revalued <Revalued> 3200 P 6400 P
-10-Apr-01 Sample 4b As:Brokerage:Stocks -1600 P 4800 P
+10-Apr-01 Sample 4b Asset:Brokerage:Stocks -1600 P 4800 P
>>>2
=== 0
diff --git a/test/baseline/opt-meta-width.test b/test/baseline/opt-meta-width.test
new file mode 100644
index 00000000..51fd09cf
--- /dev/null
+++ b/test/baseline/opt-meta-width.test
@@ -0,0 +1,14 @@
+reg --meta Sample --meta-width=15
+<<<
+2004/05/27 (100) Credit card company
+ ; This is an xact note!
+ ; Sample: Value
+ Liabilities:MasterCard $20.00
+ ; This is a posting note!
+ ; Sample: Another Value
+ ; :MyTag:
+ Assets:Bank:Checking
+ ; :AnotherTag:
+>>>
+Another Value 04-May-27 Credit card com.. Liab:MasterCard $20.00 $20.00
+Value As:Ban:Checking $-20.00 0
diff --git a/test/baseline/opt-meta.test b/test/baseline/opt-meta.test
new file mode 100644
index 00000000..85f53003
--- /dev/null
+++ b/test/baseline/opt-meta.test
@@ -0,0 +1,14 @@
+reg --meta Sample
+<<<
+2004/05/27 (100) Credit card company
+ ; This is an xact note!
+ ; Sample: Value
+ Liabilities:MasterCard $20.00
+ ; This is a posting note!
+ ; Sample: Another Value
+ ; :MyTag:
+ Assets:Bank:Checking
+ ; :AnotherTag:
+>>>
+Another Value04-May-27 Credit card company Liabilities:MasterCard $20.00 $20.00
+Value Assets:Bank:Checking $-20.00 0
diff --git a/test/baseline/opt-no-rounding.test b/test/baseline/opt-no-rounding.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-no-rounding.test
diff --git a/test/baseline/opt-no-titles.test b/test/baseline/opt-no-titles.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-no-titles.test
diff --git a/test/baseline/opt-now.test b/test/baseline/opt-now.test
new file mode 100644
index 00000000..c517a24c
--- /dev/null
+++ b/test/baseline/opt-now.test
@@ -0,0 +1,4 @@
+eval today --now=2009/01/01
+<<<
+>>>
+2009/01/01
diff --git a/test/baseline/opt-output.test b/test/baseline/opt-output.test
index 49881fb3..2339a3a1 100644
--- a/test/baseline/opt-output.test
+++ b/test/baseline/opt-output.test
@@ -5,7 +5,7 @@ reg --output=/dev/stderr
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
>>>2
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
=== 0
diff --git a/test/baseline/opt-pager.test b/test/baseline/opt-pager.test
index 2a109ad7..060c4bb8 100644
--- a/test/baseline/opt-pager.test
+++ b/test/baseline/opt-pager.test
@@ -4,8 +4,8 @@ reg --pager=cat
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-payee-as-account.test b/test/baseline/opt-payee-as-account.test
index 6aca0dab..cbce81c3 100644
--- a/test/baseline/opt-payee-as-account.test
+++ b/test/baseline/opt-payee-as-account.test
@@ -22,12 +22,12 @@ 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 En:Expenses:Books $10.00 $10.00
-08-Jan-31 End of January En:Assets:Cash $-10.00 0
-08-Feb-01 February Fe:Expenses:Books $20.00 $20.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 En:Expenses:Books $20.00 $20.00
-08-Feb-28 End of February En:Assets:Cash $-20.00 0
+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
>>>2
diff --git a/test/baseline/opt-payee-width.test b/test/baseline/opt-payee-width.test
index a5f61e87..d92dbe00 100644
--- a/test/baseline/opt-payee-width.test
+++ b/test/baseline/opt-payee-width.test
@@ -4,8 +4,8 @@ reg --payee-width=40
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Investm:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Dividen:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-payee.test b/test/baseline/opt-payee.test
index 56ee0cde..a028bb91 100644
--- a/test/baseline/opt-payee.test
+++ b/test/baseline/opt-payee.test
@@ -4,8 +4,8 @@ reg --payee='account_base + ":" + commodity'
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 VMMXX:VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
-07-Feb-02 VMMXX:$ In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 VMMXX:VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+07-Feb-02 VMMXX:$ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-pivot.test b/test/baseline/opt-pivot.test
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/baseline/opt-pivot.test
diff --git a/test/baseline/opt-prepend-format.test b/test/baseline/opt-prepend-format.test
new file mode 100644
index 00000000..35b6e8d0
--- /dev/null
+++ b/test/baseline/opt-prepend-format.test
@@ -0,0 +1,17 @@
+bal --prepend-format "%(account_base)"
+<<<
+2007/02/02 RD VMMXX
+ Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
+ Income:Dividends:Vanguard:VMMXX $-0.35
+>>>
+VMMXX 0.350 VMMXX Assets:Investments:Vanguard:VMMXX
+VMMXX $-0.35 Income:Dividends:Vanguard:VMMXX
+--------------------
+ $-0.35
+ 0.350 VMMXX
+=== 0
+reg --prepend-format "%(account_base)"
+>>>
+VMMXX07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+VMMXX In:Divid:Vanguar:VMMXX $-0.35 $-0.35
+ 0.350 VMMXX
diff --git a/test/baseline/opt-prepend-width.test b/test/baseline/opt-prepend-width.test
new file mode 100644
index 00000000..488f737b
--- /dev/null
+++ b/test/baseline/opt-prepend-width.test
@@ -0,0 +1,17 @@
+bal --prepend-format "%(account_base) " --prepend-width=10
+<<<
+2007/02/02 RD VMMXX
+ Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
+ Income:Dividends:Vanguard:VMMXX $-0.35
+>>>
+ VMMXX 0.350 VMMXX Assets:Investments:Vanguard:VMMXX
+ VMMXX $-0.35 Income:Dividends:Vanguard:VMMXX
+ --------------------
+ $-0.35
+ 0.350 VMMXX
+=== 0
+reg --prepend-format "%(account_base) " --prepend-width=10
+>>>
+ VMMXX 07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ VMMXX In:Divid:Vanguar:VMMXX $-0.35 $-0.35
+ 0.350 VMMXX
diff --git a/test/baseline/opt-quantity.test b/test/baseline/opt-quantity.test
index 5de92e84..f8cd0e4c 100644
--- a/test/baseline/opt-quantity.test
+++ b/test/baseline/opt-quantity.test
@@ -4,8 +4,8 @@ reg --quantity
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Divid:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-revalued.test b/test/baseline/opt-revalued.test
index b68b256b..541a4e02 100644
--- a/test/baseline/opt-revalued.test
+++ b/test/baseline/opt-revalued.test
@@ -49,18 +49,18 @@ P 2010/03/01 00:00:00 S 8 P
P 2010/04/01 00:00:00 S 16 P
>>>1
-09-Jan-01 Sample 1a As:Brokerage:Stocks 200 P 200 P
+09-Jan-01 Sample 1a Asset:Brokerage:Stocks 200 P 200 P
09-Feb-01 Commodities revalued <Revalued> 200 P 400 P
-09-Feb-01 Sample 2a As:Brokerage:Stocks 400 P 800 P
+09-Feb-01 Sample 2a Asset:Brokerage:Stocks 400 P 800 P
09-Mar-01 Commodities revalued <Revalued> 800 P 1600 P
-09-Mar-01 Sample 3a As:Brokerage:Stocks 800 P 2400 P
+09-Mar-01 Sample 3a Asset:Brokerage:Stocks 800 P 2400 P
09-Apr-01 Commodities revalued <Revalued> 2400 P 4800 P
-09-Apr-01 Sample 4a As:Brokerage:Stocks -1600 P 3200 P
+09-Apr-01 Sample 4a Asset:Brokerage:Stocks -1600 P 3200 P
10-Feb-01 Commodities revalued <Revalued> -2400 P 800 P
-10-Feb-01 Sample 2b As:Brokerage:Stocks 400 P 1200 P
+10-Feb-01 Sample 2b Asset:Brokerage:Stocks 400 P 1200 P
10-Mar-01 Commodities revalued <Revalued> 1200 P 2400 P
-10-Mar-01 Sample 3b As:Brokerage:Stocks 800 P 3200 P
+10-Mar-01 Sample 3b Asset:Brokerage:Stocks 800 P 3200 P
10-Apr-01 Commodities revalued <Revalued> 3200 P 6400 P
-10-Apr-01 Sample 4b As:Brokerage:Stocks -1600 P 4800 P
+10-Apr-01 Sample 4b Asset:Brokerage:Stocks -1600 P 4800 P
>>>2
=== 0
diff --git a/test/baseline/opt-sort-all.test b/test/baseline/opt-sort-all.test
index b289f8e8..974f95c4 100644
--- a/test/baseline/opt-sort-all.test
+++ b/test/baseline/opt-sort-all.test
@@ -84,33 +84,33 @@ reg --monthly --sort=-amount
Expenses:Travel:Passport $127.00
Assets:Checking
>>>1
-08-Jan-01 - 08-Jan-31 Ex:Travel:Airfare $222.19 $222.19
+08-Jan-01 - 08-Jan-31 Expense:Travel:Airfare $222.19 $222.19
Liabilities:MasterCard $-222.19 0
-08-Feb-01 - 08-Feb-29 Ex:Travel:Airfare $477.60 $477.60
+08-Feb-01 - 08-Feb-29 Expense:Travel:Airfare $477.60 $477.60
Expenses:Travel:Auto $280.97 $758.57
Liabilities:MasterCard $-758.57 0
-08-Mar-01 - 08-Mar-31 Ex:Travel:Airfare $2,463.20 $2,463.20
+08-Mar-01 - 08-Mar-31 Expense:Travel:Airfare $2,463.20 $2,463.20
Liabilities:MasterCard $-2,463.20 0
-08-Apr-01 - 08-Apr-30 Ex:Travel:Airfare $1,186.14 $1,186.14
+08-Apr-01 - 08-Apr-30 Expense:Travel:Airfare $1,186.14 $1,186.14
Liabilities:MasterCard $-1,186.14 0
-08-Aug-01 - 08-Aug-31 Ex:Travel:Passport $170.00 $170.00
+08-Aug-01 - 08-Aug-31 Expens:Travel:Passport $170.00 $170.00
Liabilities:MasterCard $-170.00 0
-08-Sep-01 - 08-Sep-30 Ex:Travel:Airfare $3,925.94 $3,925.94
+08-Sep-01 - 08-Sep-30 Expense:Travel:Airfare $3,925.94 $3,925.94
Liabilities:MasterCard $-3,925.94 0
-08-Dec-01 - 08-Dec-31 Ex:Travel:Passport $254.00 $254.00
+08-Dec-01 - 08-Dec-31 Expens:Travel:Passport $254.00 $254.00
Assets:Checking $-254.00 0
>>>2
=== 0
reg --monthly --sort-all=-amount
>>>1
-08-Sep-01 - 08-Sep-30 Ex:Travel:Airfare $3,925.94 $3,925.94
-08-Mar-01 - 08-Mar-31 Ex:Travel:Airfare $2,463.20 $6,389.14
-08-Apr-01 - 08-Apr-30 Ex:Travel:Airfare $1,186.14 $7,575.28
-08-Feb-01 - 08-Feb-29 Ex:Travel:Airfare $477.60 $8,052.88
+08-Sep-01 - 08-Sep-30 Expense:Travel:Airfare $3,925.94 $3,925.94
+08-Mar-01 - 08-Mar-31 Expense:Travel:Airfare $2,463.20 $6,389.14
+08-Apr-01 - 08-Apr-30 Expense:Travel:Airfare $1,186.14 $7,575.28
+08-Feb-01 - 08-Feb-29 Expense:Travel:Airfare $477.60 $8,052.88
Expenses:Travel:Auto $280.97 $8,333.85
-08-Dec-01 - 08-Dec-31 Ex:Travel:Passport $254.00 $8,587.85
-08-Jan-01 - 08-Jan-31 Ex:Travel:Airfare $222.19 $8,810.04
-08-Aug-01 - 08-Aug-31 Ex:Travel:Passport $170.00 $8,980.04
+08-Dec-01 - 08-Dec-31 Expens:Travel:Passport $254.00 $8,587.85
+08-Jan-01 - 08-Jan-31 Expense:Travel:Airfare $222.19 $8,810.04
+08-Aug-01 - 08-Aug-31 Expens:Travel:Passport $170.00 $8,980.04
Liabilities:MasterCard $-170.00 $8,810.04
08-Jan-01 - 08-Jan-31 Liabilities:MasterCard $-222.19 $8,587.85
08-Dec-01 - 08-Dec-31 Assets:Checking $-254.00 $8,333.85
diff --git a/test/baseline/opt-sort-xacts.test b/test/baseline/opt-sort-xacts.test
index 4882e18f..5dee9775 100644
--- a/test/baseline/opt-sort-xacts.test
+++ b/test/baseline/opt-sort-xacts.test
@@ -86,27 +86,27 @@ reg --sort=account
>>>1
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-127.00
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-254.00
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $-214.00
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $-31.81
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $206.99
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $445.79
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,677.39
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $2,908.99
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,064.85
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,220.71
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $3,657.92
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,095.13
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,007.73
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,920.33
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $5,990.33
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $6,796.53
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,602.73
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $8,021.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $-214.00
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $-31.81
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $206.99
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $445.79
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,677.39
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $2,908.99
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,064.85
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,220.71
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $3,657.92
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,095.13
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,007.73
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,920.33
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $5,990.33
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $6,796.53
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,602.73
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $8,021.07
08-Feb-05 CTX Expenses:Travel:Auto $240.38 $8,261.45
08-Feb-22 BUDGET RENT-A-CAR Expenses:Travel:Auto $40.59 $8,302.04
-08-Aug-08 BCIS I-131 FILING F.. Ex:Travel:Passport $170.00 $8,472.04
-08-Dec-26 U.S. Department of .. Ex:Travel:Passport $127.00 $8,599.04
-08-Dec-26 U.S. Department of .. Ex:Travel:Passport $127.00 $8,726.04
+08-Aug-08 BCIS I-131 FILING F.. Expens:Travel:Passport $170.00 $8,472.04
+08-Dec-26 U.S. Department of .. Expens:Travel:Passport $127.00 $8,599.04
+08-Dec-26 U.S. Department of .. Expens:Travel:Passport $127.00 $8,726.04
08-Jan-11 LIAT Liabilities:MasterCard $-40.00 $8,686.04
08-Jan-14 cheaptickets.com Liabilities:MasterCard $-182.19 $8,503.85
08-Feb-05 CTX Liabilities:MasterCard $-240.38 $8,263.47
@@ -130,47 +130,47 @@ reg --sort=account
=== 0
reg --sort-xacts=account
>>>1
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $40.00
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $40.00
Liabilities:MasterCard $-40.00 0
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $182.19
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $182.19
Liabilities:MasterCard $-182.19 0
08-Feb-05 CTX Expenses:Travel:Auto $240.38 $240.38
Liabilities:MasterCard $-240.38 0
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $238.80
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $238.80
Liabilities:MasterCard $-238.80 0
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $238.80
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $238.80
Liabilities:MasterCard $-238.80 0
08-Feb-22 BUDGET RENT-A-CAR Expenses:Travel:Auto $40.59 $40.59
Liabilities:MasterCard $-40.59 0
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,231.60
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,231.60
Liabilities:MasterCard $-1,231.60 0
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,231.60
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,231.60
Liabilities:MasterCard $-1,231.60 0
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $155.86
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $155.86
Liabilities:MasterCard $-155.86 0
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $155.86
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $155.86
Liabilities:MasterCard $-155.86 0
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $437.21
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $437.21
Liabilities:MasterCard $-437.21 0
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $437.21
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $437.21
Liabilities:MasterCard $-437.21 0
-08-Aug-08 BCIS I-131 FILING F.. Ex:Travel:Passport $170.00 $170.00
+08-Aug-08 BCIS I-131 FILING F.. Expens:Travel:Passport $170.00 $170.00
Liabilities:MasterCard $-170.00 0
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $912.60
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $912.60
Liabilities:MasterCard $-912.60 0
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $912.60
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $912.60
Liabilities:MasterCard $-912.60 0
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $70.00
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $70.00
Liabilities:MasterCard $-70.00 0
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $806.20
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $806.20
Liabilities:MasterCard $-806.20 0
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $806.20
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $806.20
Liabilities:MasterCard $-806.20 0
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $418.34
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $418.34
Liabilities:MasterCard $-418.34 0
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-127.00
- Ex:Travel:Passport $127.00 0
+ Expens:Travel:Passport $127.00 0
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-127.00
- Ex:Travel:Passport $127.00 0
+ Expens:Travel:Passport $127.00 0
>>>2
=== 0
diff --git a/test/baseline/opt-sort.test b/test/baseline/opt-sort.test
index 27efe31b..6e9e5ddd 100644
--- a/test/baseline/opt-sort.test
+++ b/test/baseline/opt-sort.test
@@ -84,82 +84,82 @@ reg airfare --sort=date
Expenses:Travel:Passport $127.00
Assets:Checking
>>>1
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $40.00
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $222.19
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $460.99
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $699.79
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,931.39
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $3,162.99
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,318.85
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,474.71
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $3,911.92
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,349.13
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,261.73
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $6,174.33
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $6,244.33
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,050.53
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,856.73
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $8,275.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $40.00
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $222.19
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $460.99
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $699.79
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,931.39
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $3,162.99
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,318.85
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,474.71
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $3,911.92
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,349.13
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,261.73
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $6,174.33
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $6,244.33
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,050.53
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,856.73
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $8,275.07
>>>2
=== 0
reg airfare --sort=date,amount
>>>1
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $40.00
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $222.19
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $460.99
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $699.79
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,931.39
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $3,162.99
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,318.85
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,474.71
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $3,911.92
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,349.13
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,261.73
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $6,174.33
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $6,244.33
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $6,662.67
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,468.87
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $8,275.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $40.00
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $222.19
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $460.99
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $699.79
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,931.39
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $3,162.99
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,318.85
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,474.71
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $3,911.92
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,349.13
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,261.73
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $6,174.33
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $6,244.33
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $6,662.67
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,468.87
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $8,275.07
>>>2
=== 0
reg airfare --sort=date,-amount
>>>1
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $40.00
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $222.19
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $460.99
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $699.79
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,931.39
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $3,162.99
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,318.85
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,474.71
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $3,911.92
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,349.13
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,261.73
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $6,174.33
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $6,980.53
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,786.73
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $8,205.07
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $8,275.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $40.00
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $222.19
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $460.99
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $699.79
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,931.39
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $3,162.99
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,318.85
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,474.71
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $3,911.92
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,349.13
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,261.73
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $6,174.33
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $6,980.53
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,786.73
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $8,205.07
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $8,275.07
>>>2
=== 0
reg airfare --sort=-date,-amount
>>>1
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $806.20
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $1,612.40
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $2,030.74
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $2,100.74
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $3,013.34
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $3,925.94
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,363.15
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,800.36
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $4,956.22
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $5,112.08
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $6,343.68
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $7,575.28
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $7,814.08
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $8,052.88
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $8,235.07
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $8,275.07
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $806.20
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $1,612.40
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $2,030.74
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $2,100.74
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $3,013.34
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $3,925.94
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,363.15
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,800.36
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $4,956.22
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $5,112.08
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $6,343.68
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $7,575.28
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $7,814.08
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $8,052.88
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $8,235.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $8,275.07
>>>2
=== 0
bal --sort=total
@@ -202,27 +202,27 @@ reg --sort=account
>>>1
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-127.00
08-Dec-26 U.S. Department of .. Assets:Checking $-127.00 $-254.00
-08-Jan-11 LIAT Ex:Travel:Airfare $40.00 $-214.00
-08-Jan-14 cheaptickets.com Ex:Travel:Airfare $182.19 $-31.81
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $206.99
-08-Feb-05 UNITED Ex:Travel:Airfare $238.80 $445.79
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $1,677.39
-08-Mar-16 IBERIA Ex:Travel:Airfare $1,231.60 $2,908.99
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,064.85
-08-Apr-03 AMERICAN Ex:Travel:Airfare $155.86 $3,220.71
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $3,657.92
-08-Apr-30 UNITED Ex:Travel:Airfare $437.21 $4,095.13
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,007.73
-08-Sep-06 AMERICAN Ex:Travel:Airfare $912.60 $5,920.33
-08-Sep-22 AGNT FEE Ex:Travel:Airfare $70.00 $5,990.33
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $6,796.53
-08-Sep-22 DELTA Ex:Travel:Airfare $806.20 $7,602.73
-08-Sep-22 LIAT 1974 LIMITED Ex:Travel:Airfare $418.34 $8,021.07
+08-Jan-11 LIAT Expense:Travel:Airfare $40.00 $-214.00
+08-Jan-14 cheaptickets.com Expense:Travel:Airfare $182.19 $-31.81
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $206.99
+08-Feb-05 UNITED Expense:Travel:Airfare $238.80 $445.79
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $1,677.39
+08-Mar-16 IBERIA Expense:Travel:Airfare $1,231.60 $2,908.99
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,064.85
+08-Apr-03 AMERICAN Expense:Travel:Airfare $155.86 $3,220.71
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $3,657.92
+08-Apr-30 UNITED Expense:Travel:Airfare $437.21 $4,095.13
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,007.73
+08-Sep-06 AMERICAN Expense:Travel:Airfare $912.60 $5,920.33
+08-Sep-22 AGNT FEE Expense:Travel:Airfare $70.00 $5,990.33
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $6,796.53
+08-Sep-22 DELTA Expense:Travel:Airfare $806.20 $7,602.73
+08-Sep-22 LIAT 1974 LIMITED Expense:Travel:Airfare $418.34 $8,021.07
08-Feb-05 CTX Expenses:Travel:Auto $240.38 $8,261.45
08-Feb-22 BUDGET RENT-A-CAR Expenses:Travel:Auto $40.59 $8,302.04
-08-Aug-08 BCIS I-131 FILING F.. Ex:Travel:Passport $170.00 $8,472.04
-08-Dec-26 U.S. Department of .. Ex:Travel:Passport $127.00 $8,599.04
-08-Dec-26 U.S. Department of .. Ex:Travel:Passport $127.00 $8,726.04
+08-Aug-08 BCIS I-131 FILING F.. Expens:Travel:Passport $170.00 $8,472.04
+08-Dec-26 U.S. Department of .. Expens:Travel:Passport $127.00 $8,599.04
+08-Dec-26 U.S. Department of .. Expens:Travel:Passport $127.00 $8,726.04
08-Jan-11 LIAT Liabilities:MasterCard $-40.00 $8,686.04
08-Jan-14 cheaptickets.com Liabilities:MasterCard $-182.19 $8,503.85
08-Feb-05 CTX Liabilities:MasterCard $-240.38 $8,263.47
diff --git a/test/baseline/opt-subtotal.test b/test/baseline/opt-subtotal.test
index 41defbc1..f2d9454f 100644
--- a/test/baseline/opt-subtotal.test
+++ b/test/baseline/opt-subtotal.test
@@ -85,9 +85,9 @@ reg --subtotal
Assets:Checking
>>>1
08-Jan-11 - 08-Dec-26 Assets:Checking $-254.00 $-254.00
- Ex:Travel:Airfare $8,275.07 $8,021.07
+ Expense:Travel:Airfare $8,275.07 $8,021.07
Expenses:Travel:Auto $280.97 $8,302.04
- Ex:Travel:Passport $424.00 $8,726.04
+ Expens:Travel:Passport $424.00 $8,726.04
Liabilities:MasterCard $-8,726.04 0
>>>2
=== 0
diff --git a/test/baseline/opt-total-width.test b/test/baseline/opt-total-width.test
index 1d7b8b94..bbcb549e 100644
--- a/test/baseline/opt-total-width.test
+++ b/test/baseline/opt-total-width.test
@@ -4,8 +4,8 @@ reg --total-width=25
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 0.350 VMMXX
- In:Di:Vanguard:VMMXX $-0.35 $-0.35
+07-Feb-02 RD VMMXX As:Investm:Vanguar:VMMXX 0.350 VMMXX 0.350 VMMXX
+ In:Dividen:Vanguar:VMMXX $-0.35 $-0.35
0.350 VMMXX
>>>2
=== 0
diff --git a/test/baseline/opt-total.test b/test/baseline/opt-total.test
index 8f4719d2..c73614c1 100644
--- a/test/baseline/opt-total.test
+++ b/test/baseline/opt-total.test
@@ -4,7 +4,7 @@ reg --total=10
Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00
Income:Dividends:Vanguard:VMMXX $-0.35
>>>1
-07-Feb-02 RD VMMXX As:In:Vanguard:VMMXX 0.350 VMMXX 10
- In:Di:Vanguard:VMMXX $-0.35 10
+07-Feb-02 RD VMMXX As:Inves:Vanguar:VMMXX 0.350 VMMXX 10
+ In:Divid:Vanguar:VMMXX $-0.35 10
>>>2
=== 0
diff --git a/test/regress/04C5E1CA.test b/test/regress/04C5E1CA.test
index 729ae6bf..9aca9b1f 100644
--- a/test/regress/04C5E1CA.test
+++ b/test/regress/04C5E1CA.test
@@ -8,10 +8,10 @@ reg
Expenses:School:CS Club:Home Depot:4" Brush (2 * $3.97)
Liabilities:Mastercard
>>>1
-09-Apr-04 CS Club Sign Ex:Sc:CS:Ho:4" Brush 2 2
+09-Apr-04 CS Club Sign Ex:Sc:CS:Home:4" Brush 2 2
Liabilities:Mastercard $-7.94 2
$-7.94
-09-Apr-04 CS Club Sign Ex:Sc:CS:Ho:4" Brush $7.94 2
+09-Apr-04 CS Club Sign Ex:Sc:CS:Home:4" Brush $7.94 2
Liabilities:Mastercard $-7.94 2
$-7.94
>>>2
diff --git a/test/regress/13965214.test b/test/regress/13965214.test
index 674d4d7d..29a7278e 100644
--- a/test/regress/13965214.test
+++ b/test/regress/13965214.test
@@ -3,20 +3,20 @@ reg
Y2008
01/30 A
- Bank 130
- Income
+ Bank 130
+ Income
02/01 B
- Bank 140
- Income
+ Bank 140
+ Income
02/20 C
- Bank 150
- Income
+ Bank 150
+ Income
03/01 D
- Bank 160
- Income
+ Bank 160
+ Income
>>>1
08-Jan-30 A Bank 130 130
Income -130 0
diff --git a/test/regress/15230B79.test b/test/regress/15230B79.test
new file mode 100644
index 00000000..b20ab89a
--- /dev/null
+++ b/test/regress/15230B79.test
@@ -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
diff --git a/test/regress/1D275740.test b/test/regress/1D275740.test
index 72eb1769..d7536a57 100644
--- a/test/regress/1D275740.test
+++ b/test/regress/1D275740.test
@@ -89,11 +89,11 @@ D 1.200,40 €
Actif:SV 14,89 €
>>>1
1999/11/01 * Achat
- Actif:SSB 125,0000 STK @ 13,37936 $
+ Actif:SSB 125,0000 STK
Actif:SSB -1672,42 $
1999/11/04 * Vente
- Actif:SSB -125,0000 STK @ 15,01288 $
+ Actif:SSB -125,0000 STK
Dépense:SSB:Commissions 55,07 $
Actif:SSB 1821,54 $
diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test
index 251b0f24..b3e23a6c 100644
--- a/test/regress/25A099C9.test
+++ b/test/regress/25A099C9.test
@@ -4,16 +4,16 @@
>>>2
While parsing file "$sourcepath/src/amount.h", line 66:
Error: No quantity specified for amount
-While parsing file "$sourcepath/src/amount.h", line 720:
-Error: Invalid date/time: line amount_t amoun
While parsing file "$sourcepath/src/amount.h", line 726:
-Error: Invalid date/time: line string amount_
+Error: Invalid date/time: line amount_t amoun
While parsing file "$sourcepath/src/amount.h", line 732:
Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 738:
Error: Invalid date/time: line string amount_
While parsing file "$sourcepath/src/amount.h", line 744:
+Error: Invalid date/time: line string amount_
+While parsing file "$sourcepath/src/amount.h", line 750:
Error: Invalid date/time: line std::ostream&
-While parsing file "$sourcepath/src/amount.h", line 751:
+While parsing file "$sourcepath/src/amount.h", line 757:
Error: Invalid date/time: line std::istream&
=== 7
diff --git a/test/regress/3AB70168.test b/test/regress/3AB70168.test
index 6c08b0bf..ffa6a573 100644
--- a/test/regress/3AB70168.test
+++ b/test/regress/3AB70168.test
@@ -5,9 +5,9 @@ o 2007/03/02 01:00:00
i 2007/03/11 23:00:00 B
o 2007/03/12 01:00:00
>>>1
- 2.0h A
- 2.0h B
+ 2.00h A
+ 2.00h B
--------------------
- 4.0h
+ 4.00h
>>>2
=== 0
diff --git a/test/regress/56BBE69B.test b/test/regress/56BBE69B.test
new file mode 100644
index 00000000..508ff8aa
--- /dev/null
+++ b/test/regress/56BBE69B.test
@@ -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
diff --git a/test/regress/5FBF2ED8.test b/test/regress/5FBF2ED8.test
index 78df5a6e..ad8454d1 100644
--- a/test/regress/5FBF2ED8.test
+++ b/test/regress/5FBF2ED8.test
@@ -1,16 +1,16 @@
bal -B
<<<
-2008/01/01 * Checking balance
- Assets:Bank:Checking £0.00
- Equity:Opening Balances
+2008/01/01 * Checking balance
+ Assets:Bank:Checking £0.00
+ Equity:Opening Balances
-2008/02/02 Salary
- Income:Employer £-334.00
- Assets:Bank:Checking $512.85 @@ £334.00
+2008/02/02 Salary
+ Income:Employer £-334.00
+ Assets:Bank:Checking $512.85 @@ £334.00
-2008/03/02 Salary
- Income:Employer £-248.07
- Assets:Bank:Checking $404.82 @@ £248.07
+2008/03/02 Salary
+ Income:Employer £-248.07
+ Assets:Bank:Checking $404.82 @@ £248.07
>>>1
£582.07 Assets:Bank:Checking
£-582.07 Income:Employer
diff --git a/test/regress/620F0674.test b/test/regress/620F0674.test
new file mode 100644
index 00000000..3f81a078
--- /dev/null
+++ b/test/regress/620F0674.test
@@ -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
diff --git a/test/regress/727B2DF8.test b/test/regress/727B2DF8.test
index a13e8292..fbe42e54 100644
--- a/test/regress/727B2DF8.test
+++ b/test/regress/727B2DF8.test
@@ -46,9 +46,9 @@ N $
; :AnotherTag:
>>>1
04-May-01 Checking balance Assets:Bank:Checking  $1,000.00 $1,000.00
- Eq:Opening Balances  $-1,000.00 0
+ Equit:Opening Balances $-1,000.00 0
04-May-03 Investment balance Assets:Brokerage  50 AAPL 50 AAPL
- Eq:Opening Balances  $-1,500.00 $-1,500.00
+ Equit:Opening Balances $-1,500.00 $-1,500.00
50 AAPL
04-May-14 Páy dày Assets:Bank:Checking  500.00€ $-1,500.00
50 AAPL
@@ -59,7 +59,7 @@ N $
50 AAPL
Income:Salary  $-500.00 $-1,500.00
50 AAPL
-04-May-14 Another dày in whic.. Ру:Ру:Ру:Русский язык  $1,000.00 $-500.00
+04-May-14 Another dày in whic.. Ру:Ру:Рус:Русский язык $1,000.00 $-500.00
50 AAPL
Income:Salary  $-1,000.00 $-1,500.00
50 AAPL
diff --git a/test/regress/7C44010B.test b/test/regress/7C44010B.test
new file mode 100644
index 00000000..f0437588
--- /dev/null
+++ b/test/regress/7C44010B.test
@@ -0,0 +1,30 @@
+reg -X F -J Assets
+<<<
+D 1000,00 €
+
+1994/1/1 Company
+ Assets:Checking 10000 F
+ Income:Salary
+
+1998/1/1 Transfer
+ Assets:US account 200 $
+ Assets:Checking -1000 F
+
+P 1998/12/31 $ 6 F
+
+1999/1/1 Books
+ Expenses:Books 200 $
+ Assets:US account
+
+P 2002/1/1 € 6,55957 F
+
+2002/1/1 Company
+ Assets:Checking 2000 €
+ Income:Salary
+>>>
+1994-01-01 10000
+1998-01-01 11000
+1998-01-01 10000
+1998-12-31 10200
+1999-01-01 9000
+2002-01-01 22119.14
diff --git a/test/regress/8254755E.test b/test/regress/8254755E.test
index 26baf52d..98904d6e 100644
--- a/test/regress/8254755E.test
+++ b/test/regress/8254755E.test
@@ -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
diff --git a/test/regress/86D2BDC4.test b/test/regress/86D2BDC4.test
index 8cd51e42..0b463d61 100644
--- a/test/regress/86D2BDC4.test
+++ b/test/regress/86D2BDC4.test
@@ -2,10 +2,10 @@ reg -B
<<<
2009/06/03 Westjet
Expenses:Transportation:Air C$429.80 @ 1.572865
- Expenses:Bank:Fees 2.73
+ Expenses:Bank:Fees 2.73
Liabilities:Mastercard
>>>1
-09-Jun-03 Westjet Ex:Transportation: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
diff --git a/test/regress/9EB10714.test b/test/regress/9EB10714.test
new file mode 100644
index 00000000..9fd49b7a
--- /dev/null
+++ b/test/regress/9EB10714.test
@@ -0,0 +1,43 @@
+reg -J -V ^Actif
+<<<
+1994/01/01 Achat Rialto
+ Actif:Fixe:Rialto 2 Rialto
+ Actif:BNP -120000 €
+ Actif:BNP 120000 €
+ Revenu:Salaire -120000 €
+
+P 1995/01/01 Rialto 70000 €
+P 1996/01/01 Rialto 90000 €
+P 1997/01/01 Rialto 90000 €
+P 1998/01/01 Rialto 105000 €
+P 1999/01/01 Rialto 110000 €
+P 2000/01/01 Rialto 120000 €
+P 2001/01/01 Rialto 130000 €
+P 2002/01/01 Rialto 140000 €
+P 2003/01/01 Rialto 150000 €
+P 2004/01/01 Rialto 160000 €
+P 2005/01/01 Rialto 170000 €
+P 2006/01/01 Rialto 180000 €
+P 2007/01/01 Rialto 190000 €
+P 2008/01/01 Rialto 200000 €
+P 2009/01/01 Rialto 210000 €
+P 2010/01/01 Rialto 211000 €
+>>>
+1994-01-01 120000
+1994-01-01 0
+1994-01-01 120000
+1995-01-01 140000
+1996-01-01 180000
+1998-01-01 210000
+1999-01-01 220000
+2000-01-01 240000
+2001-01-01 260000
+2002-01-01 280000
+2003-01-01 300000
+2004-01-01 320000
+2005-01-01 340000
+2006-01-01 360000
+2007-01-01 380000
+2008-01-01 400000
+2009-01-01 420000
+2010-01-01 422000
diff --git a/test/regress/A28CF697.test b/test/regress/A28CF697.test
new file mode 100644
index 00000000..513dbd97
--- /dev/null
+++ b/test/regress/A28CF697.test
@@ -0,0 +1,9 @@
+print
+<<<
+2010-02-05 * Flight SN2094
+ Assets:Rewards:Airmiles 125 "M&M"
+ Income:Rewards
+>>>
+2010/02/05 * Flight SN2094
+ Assets:Rewards:Airmiles 125 "M&M"
+ Income:Rewards
diff --git a/test/regress/C0212EAC.test b/test/regress/C0212EAC.test
new file mode 100644
index 00000000..da178054
--- /dev/null
+++ b/test/regress/C0212EAC.test
@@ -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}
diff --git a/test/regress/D2829FC4.test b/test/regress/D2829FC4.test
new file mode 100644
index 00000000..83c991fd
--- /dev/null
+++ b/test/regress/D2829FC4.test
@@ -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
diff --git a/test/regress/D943AE0F.test b/test/regress/D943AE0F.test
index 7a2e14d8..8fd5f932 100644
--- a/test/regress/D943AE0F.test
+++ b/test/regress/D943AE0F.test
@@ -8,7 +8,7 @@ D 1000.00 EUR
P 2008/04/20 00:00:00 CAD 1.20 EUR
>>>1
-08-Apr-15 Paid expenses back .. Ex:Cie-Reimbursements 2200.00 EUR 2200.00 EUR
+08-Apr-15 Paid expenses back .. Exp:Cie-Reimbursements 2200.00 EUR 2200.00 EUR
Assets:Checking -2200.00 EUR 0
08-Apr-20 Commodities revalued <Revalued> 200.00 EUR 200.00 EUR
>>>2
diff --git a/test/regress/E4C9A8EA.test b/test/regress/E4C9A8EA.test
index fed47c82..a305a839 100644
--- a/test/regress/E4C9A8EA.test
+++ b/test/regress/E4C9A8EA.test
@@ -10,15 +10,15 @@ reg
Assets:Investments:RBC-Broker:Account-RSP 72.06 CAD
Expenses:Financial:Fees
>>>1
-07-Dec-31 Cost basis for: RED.. As:In:RB:Account-RSP 4.00 RHT 4.00 RHT
- Eq:Op:Cost -689.87 CAD -689.87 CAD
+07-Dec-31 Cost basis for: RED.. As:In:RBC-:Account-RSP 4.00 RHT 4.00 RHT
+ Eq:Opening-Balanc:Cost -689.87 CAD -689.87 CAD
4.00 RHT
-08-Jan-03 Sell -- RHT -- RED .. As:In:RB:Account-RSP -4.00 RHT -689.87 CAD
- Ex:Fi:Commissions 9.95 USD -689.87 CAD
+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
9.95 USD
- As:In:RB:Account-RSP 72.06 CAD -617.81 CAD
+ As:In:RBC-:Account-RSP 72.06 CAD -617.81 CAD
9.95 USD
- Ex:Financial:Fees 2.89 CAD -614.92 CAD
+ Expense:Financial:Fees 2.89 CAD -614.92 CAD
9.95 USD
>>>2
=== 0
diff --git a/test/regress/E627C594.test b/test/regress/E627C594.test
index 0dfbf778..ba48a0c7 100644
--- a/test/regress/E627C594.test
+++ b/test/regress/E627C594.test
@@ -10,6 +10,8 @@ reg --forecast-while="d<[2010/03/01]" --now=2009/11/01
>>>1
09-Nov-01 Sample Expenses:Food:Dining $20.00 $20.00
Assets $-20.00 0
+09-Dec-01 Forecast transaction Expenses:Food $500.00 $500.00
+09-Dec-01 Forecast transaction Assets $-500.00 0
10-Jan-01 Forecast transaction Expenses:Food $500.00 $500.00
10-Jan-01 Forecast transaction Assets $-500.00 0
10-Feb-01 Forecast transaction Expenses:Food $500.00 $500.00
diff --git a/test/regress/F559EC12.test b/test/regress/F559EC12.test
index c8b686db..d6b2521e 100644
--- a/test/regress/F559EC12.test
+++ b/test/regress/F559EC12.test
@@ -6,6 +6,7 @@ format "%-12(scrub(amount))"
; This note applies to all postings. :SecondTag:
Expenses:Books 20 BOOK @ $10
; Metadata: Some Value
+ ; Typed:: $100 + $200
; :ExampleTag:
; Here follows a note describing the posting.
Liabilities:MasterCard $-200.00
@@ -27,6 +28,7 @@ format "%12(scrub(amount))"
; This note applies to all postings. :SecondTag:
Expenses:Books 20 BOOK @ $10
; Metadata: Some Value
+ ; Typed:: $100 + $200
; :ExampleTag:
; Here follows a note describing the posting.
Liabilities:MasterCard $-200.00
diff --git a/test/run b/test/run
new file mode 100755
index 00000000..b0da1b6e
--- /dev/null
+++ b/test/run
@@ -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.$$
diff --git a/test/unit/t_amount.cc b/test/unit/t_amount.cc
index 63d82675..b1c7b837 100644
--- a/test/unit/t_amount.cc
+++ b/test/unit/t_amount.cc
@@ -249,7 +249,7 @@ void AmountTestCase::testAssignment()
assertEqual(x10, x9);
assertFalse(x1.is_null());
- x1 = x0; // sets x1 back to uninitialized state
+ x1 = x0; // sets x1 back to uninitialized state
assertTrue(x0.is_null());
assertTrue(x1.is_null());
@@ -699,11 +699,11 @@ void AmountTestCase::testCommoditySubtraction()
assertEqual(internalAmount("$123454434148472090.138858329277476789"), x7 - x8);
assertEqual(string("$123454434148472090.138858329277476789"), (x7 - x8).to_string());
assertEqual(string("$123454434148472090.14"),
- (amount_t("$1.00") * (x7 - x8)).to_string());
+ (amount_t("$1.00") * (x7 - x8)).to_string());
assertEqual(internalAmount("$-123454434148472090.138858329277476789"), x8 - x7);
assertEqual(string("$-123454434148472090.138858329277476789"), (x8 - x7).to_string());
assertEqual(string("$-123454434148472090.14"),
- (amount_t("$1.00") * (x8 - x7)).to_string());
+ (amount_t("$1.00") * (x8 - x7)).to_string());
assertValid(x1);
assertValid(x2);
@@ -743,7 +743,7 @@ void AmountTestCase::testIntegerMultiplication()
amount_t x4("123456789123456789123456789");
assertEqual(amount_t("15241578780673678546105778281054720515622620750190521"),
- x4 * x4);
+ x4 * x4);
assertValid(x1);
assertValid(y1);
@@ -780,7 +780,7 @@ void AmountTestCase::testFractionalMultiplication()
amount_t x2("123456789123456789.123456789123456789");
assertEqual(amount_t("15241578780673678546105778311537878.046486820281054720515622620750190521"),
- x2 * x2);
+ x2 * x2);
assertValid(x1);
assertValid(y1);
@@ -835,7 +835,7 @@ void AmountTestCase::testCommodityMultiplication()
amount_t x7(internalAmount("$123456789123456789.123456789123456789"));
assertEqual(internalAmount("$15241578780673678546105778311537878.046486820281054720515622620750190521"),
- x7 * x7);
+ x7 * x7);
assertValid(x1);
assertValid(x2);
@@ -877,7 +877,7 @@ void AmountTestCase::testIntegerDivision()
assertEqual(string("2204585520061728377204585.517857"), (x4 / y4).to_string());
assertEqual(amount_t("0.000000000000000000000000000001"),
- amount_t("10") / amount_t("10000000000000000000000000000000"));
+ amount_t("10") / amount_t("10000000000000000000000000000000"));
assertValid(x1);
assertValid(y1);
@@ -973,9 +973,9 @@ void AmountTestCase::testCommodityDivision()
assertEqual(amount_t("$1"), x7 / x7);
assertEqual(string("$0.0019216115121765559608381226612019501"),
- (x6 / x7).to_fullstring());
+ (x6 / x7).to_fullstring());
assertEqual(string("$520.39654928343335571379527154924040947272"),
- (x7 / x6).to_fullstring());
+ (x7 / x6).to_fullstring());
assertValid(x1);
assertValid(x2);
@@ -1110,14 +1110,14 @@ void AmountTestCase::testReduction()
amount_t x2("600s");
amount_t x3("6000s");
amount_t x4("360000s");
- amount_t x5("10m"); // 600s
- amount_t x6("100m"); // 6000s
- amount_t x7("1000m"); // 60000s
- amount_t x8("10000m"); // 600000s
- amount_t x9("10h"); // 36000s
- amount_t x10("100h"); // 360000s
- amount_t x11("1000h"); // 3600000s
- amount_t x12("10000h"); // 36000000s
+ amount_t x5("10m"); // 600s
+ amount_t x6("100m"); // 6000s
+ amount_t x7("1000m"); // 60000s
+ amount_t x8("10000m"); // 600000s
+ amount_t x9("10h"); // 36000s
+ amount_t x10("100h"); // 360000s
+ amount_t x11("1000h"); // 3600000s
+ amount_t x12("10000h"); // 36000000s
assertThrow(x0.reduce(), amount_error);
assertThrow(x0.unreduce(), amount_error);
@@ -1220,7 +1220,7 @@ void AmountTestCase::testCommodityForZero()
{
amount_t x1(internalAmount("$0.000000000000000000001"));
- assertTrue(x1); // an internal amount never betrays its precision
+ assertTrue(x1); // an internal amount never betrays its precision
assertFalse(x1.is_zero());
assertFalse(x1.is_realzero());
@@ -1287,7 +1287,7 @@ void AmountTestCase::testPrinting()
x1.print(bufstr);
assertEqual(std::string("982340823.380238098235098235098235098"),
- bufstr.str());
+ bufstr.str());
}
assertValid(x0);
@@ -1304,7 +1304,7 @@ void AmountTestCase::testCommodityPrinting()
x1.print(bufstr);
assertEqual(std::string("$982340823.386238098235098235098235098"),
- bufstr.str());
+ bufstr.str());
}
{
@@ -1312,7 +1312,7 @@ void AmountTestCase::testCommodityPrinting()
(x1 * x2).print(bufstr);
assertEqual(std::string("$964993493285024293.18099172508158508135413499124"),
- bufstr.str());
+ bufstr.str());
}
{
diff --git a/test/unit/t_commodity.cc b/test/unit/t_commodity.cc
index 3d84ead6..b8555202 100644
--- a/test/unit/t_commodity.cc
+++ b/test/unit/t_commodity.cc
@@ -73,11 +73,11 @@ void CommodityTestCase::testPriceHistory()
cad.add_price(jan17_06, amount_t("$1.11"));
#ifndef NOT_FOR_PYTHON
- optional<amount_t> amt = x1.value(false, feb28_07sbm);
+ optional<amount_t> amt = x1.value(feb28_07sbm);
assertTrue(amt);
assertEqual(amount_t("$1831.83"), *amt);
- amt = x1.value(false, CURRENT_TIME());
+ amt = x1.value(CURRENT_TIME());
assertTrue(amt);
assertEqual(string("$2124.12"), amt->to_string());
#ifdef INTEGER_MATH
@@ -86,18 +86,18 @@ void CommodityTestCase::testPriceHistory()
assertEqual(string("$2124.122"), amt->to_fullstring());
#endif
- amt = x1.value(false, CURRENT_TIME(), euro);
+ amt = x1.value(CURRENT_TIME(), euro);
assertTrue(amt);
assertEqual(string("EUR 1366.87"), amt->rounded().to_string());
// Add a newer Euro pricing
aapl.add_price(jan17_07, amount_t("EUR 23.00"));
- amt = x1.value(false, CURRENT_TIME(), euro);
+ amt = x1.value(CURRENT_TIME(), euro);
assertTrue(amt);
assertEqual(string("EUR 2302.30"), amt->to_string());
- amt = x1.value(false, CURRENT_TIME(), cad);
+ amt = x1.value(CURRENT_TIME(), cad);
assertTrue(amt);
assertEqual(string("CAD 3223.22"), amt->to_string());
#endif // NOT_FOR_PYTHON
diff --git a/test/unit/t_expr.cc b/test/unit/t_expr.cc
index 0d88be9e..d9dc1f1f 100644
--- a/test/unit/t_expr.cc
+++ b/test/unit/t_expr.cc
@@ -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);
diff --git a/test/unit/t_times.cc b/test/unit/t_times.cc
index d8a67b43..aaf31263 100644
--- a/test/unit/t_times.cc
+++ b/test/unit/t_times.cc
@@ -22,8 +22,8 @@ void DateTimeTestCase::tearDown()
void DateTimeTestCase::testConstructors()
{
#ifndef NOT_FOR_PYTHON
- std::time_t now = std::time(NULL);
- struct tm * moment = std::localtime(&now);
+ std::time_t now = std::time(NULL);
+ struct tm * moment = std::localtime(&now);
std::time_t localMoment = std::mktime(moment);
#endif // NOT_FOR_PYTHON
diff --git a/tools/Makefile.am b/tools/Makefile.am
index b08d489d..712b0f30 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,4 @@
-VERSION = 3.0.0
+LIBVERSION = $(shell echo $(PACKAGE_VERSION) | sed 's/[-abgrc].*//')
ACLOCAL_AMFLAGS = -I m4
dist_man_MANS = doc/ledger.1
SUBDIRS = po intl
@@ -25,10 +25,9 @@ libledger_util_la_SOURCES = \
lib/sha1.cpp
libledger_util_la_CPPFLAGS = $(lib_cppflags)
-libledger_util_la_LDFLAGS = -release $(VERSION)
+libledger_util_la_LDFLAGS = -release $(LIBVERSION)
libledger_math_la_SOURCES = \
- src/value.cc \
src/balance.cc \
src/quotes.cc \
src/pool.cc \
@@ -37,7 +36,7 @@ libledger_math_la_SOURCES = \
src/amount.cc
libledger_math_la_CPPFLAGS = $(lib_cppflags)
-libledger_math_la_LDFLAGS = -release $(VERSION)
+libledger_math_la_LDFLAGS = -release $(LIBVERSION)
libledger_expr_la_SOURCES = \
src/option.cc \
@@ -45,14 +44,14 @@ libledger_expr_la_SOURCES = \
src/query.cc \
src/predicate.cc \
src/scope.cc \
- src/interactive.cc \
src/expr.cc \
src/op.cc \
src/parser.cc \
- src/token.cc
+ src/token.cc \
+ src/value.cc
libledger_expr_la_CPPFLAGS = $(lib_cppflags)
-libledger_expr_la_LDFLAGS = -release $(VERSION)
+libledger_expr_la_LDFLAGS = -release $(LIBVERSION)
libledger_data_la_SOURCES = \
src/lookup.cc \
@@ -60,6 +59,7 @@ libledger_data_la_SOURCES = \
src/iterators.cc \
src/timelog.cc \
src/textual.cc \
+ src/temps.cc \
src/journal.cc \
src/archive.cc \
src/account.cc \
@@ -68,7 +68,7 @@ libledger_data_la_SOURCES = \
src/item.cc
libledger_data_la_CPPFLAGS = $(lib_cppflags)
-libledger_data_la_LDFLAGS = -release $(VERSION)
+libledger_data_la_LDFLAGS = -release $(LIBVERSION)
libledger_report_la_SOURCES = \
src/stats.cc \
@@ -77,18 +77,18 @@ libledger_report_la_SOURCES = \
src/convert.cc \
src/draft.cc \
src/emacs.cc \
+ src/org.cc \
src/xml.cc \
src/print.cc \
src/output.cc \
src/precmd.cc \
src/chain.cc \
src/filters.cc \
- src/temps.cc \
src/report.cc \
src/session.cc
libledger_report_la_CPPFLAGS = $(lib_cppflags)
-libledger_report_la_LDFLAGS = -release $(VERSION)
+libledger_report_la_LDFLAGS = -release $(LIBVERSION)
pkginclude_HEADERS = \
src/utils.h \
@@ -107,15 +107,14 @@ pkginclude_HEADERS = \
src/pool.h \
src/quotes.h \
src/balance.h \
- src/value.h \
\
+ src/value.h \
src/token.h \
src/parser.h \
src/op.h \
src/exprbase.h \
src/expr.h \
src/scope.h \
- src/interactive.h \
src/predicate.h \
src/query.h \
src/format.h \
@@ -126,6 +125,7 @@ pkginclude_HEADERS = \
src/xact.h \
src/account.h \
src/journal.h \
+ src/temps.h \
src/archive.h \
src/timelog.h \
src/iterators.h \
@@ -135,7 +135,6 @@ pkginclude_HEADERS = \
src/session.h \
src/report.h \
src/filters.h \
- src/temps.h \
src/chain.h \
src/precmd.h \
src/csv.h \
@@ -147,6 +146,7 @@ pkginclude_HEADERS = \
src/output.h \
src/xml.h \
src/emacs.h \
+ src/org.h \
\
src/global.h \
\
@@ -235,7 +235,7 @@ libledger_python_la_SOURCES = \
libledger_python_la_CPPFLAGS = $(lib_cppflags) -I$(srcdir)/python
-pyexec_LTLIBRARIES = ledger.la
+pyexec_LTLIBRARIES = ledger.la
ledger_la_CPPFLAGS = $(libledger_python_la_CPPFLAGS)
ledger_la_SOURCES = src/pyledger.cc
@@ -243,13 +243,14 @@ ledger_la_DEPENDENCIES = $(lib_LTLIBRARIES)
ledger_la_LDFLAGS = -avoid-version -module
ledger_la_LIBADD = $(LIBOBJS) $(lib_LTLIBRARIES)
-pkgpython_PYTHON = python/__init__.py python/server.py
+pkgpython_PYTHON = python/__init__.py python/server.py
endif
######################################################################
-TESTS = RegressTests BaselineTests ManualTests ConfirmTests GenerateTests
+TESTS = RegressTests BaselineTests ManualTests ConfirmTests \
+ GenerateTests
if HAVE_CPPUNIT
TESTS += \
@@ -260,6 +261,10 @@ TESTS += \
ReportTests
endif
+if DEBUG
+TESTS += CheckTests
+endif
+
if HAVE_BOOST_PYTHON
TESTS += PyUnitTests
endif
@@ -371,7 +376,7 @@ RegressTests_SOURCES = test/RegressTests.py
EXTRA_DIST += test/regress test/convert.py test/LedgerHarness.py
RegressTests: $(srcdir)/test/RegressTests.py
- echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/regress \"\$$@\"" > $@
+ echo "$(PYTHON) $(srcdir)/test/RegressTests.py -j$(JOBS) $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/regress \"\$$@\"" > $@
chmod 755 $@
BaselineTests_SOURCES = test/RegressTests.py
@@ -379,7 +384,7 @@ BaselineTests_SOURCES = test/RegressTests.py
EXTRA_DIST += test/baseline
BaselineTests: $(srcdir)/test/RegressTests.py
- echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/baseline \"\$$@\"" > $@
+ echo "$(PYTHON) $(srcdir)/test/RegressTests.py -j$(JOBS) $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/baseline \"\$$@\"" > $@
chmod 755 $@
ManualTests_SOURCES = test/RegressTests.py
@@ -387,7 +392,7 @@ ManualTests_SOURCES = test/RegressTests.py
EXTRA_DIST += test/manual
ManualTests: $(srcdir)/test/RegressTests.py
- echo "$(PYTHON) $(srcdir)/test/RegressTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/manual \"\$$@\"" > $@
+ echo "$(PYTHON) $(srcdir)/test/RegressTests.py -j$(JOBS) $(top_builddir)/ledger$(EXEEXT) $(srcdir) $(srcdir)/test/manual \"\$$@\"" > $@
chmod 755 $@
ConfirmTests_SOURCES = test/ConfirmTests.py
@@ -408,7 +413,13 @@ ConfirmTests: $(srcdir)/test/ConfirmTests.py
GenerateTests_SOURCES = test/GenerateTests.py
GenerateTests: $(srcdir)/test/GenerateTests.py
- echo "$(PYTHON) $(srcdir)/test/GenerateTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir) 1 20 \"\$$@\"" > $@
+ 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
@@ -433,13 +444,14 @@ endif
fullcheck: cppunittests
@$(top_builddir)/RegressTests --verify
@$(top_builddir)/BaselineTests --verify
- @$(top_builddir)/ManualTests --verify
+ @$(top_builddir)/ManualTests --verify
@$(top_builddir)/ConfirmTests --verify
- @$(top_builddir)/GenerateTests --verify
+ @$(top_builddir)/GenerateTests 20 --verify
@$(top_builddir)/RegressTests --gmalloc
@$(top_builddir)/BaselineTests --gmalloc
- @$(top_builddir)/ManualTests --gmalloc
-# @$(top_builddir)/ConfirmTests --gmalloc
+ @$(top_builddir)/ManualTests --gmalloc
+ @$(top_builddir)/ConfirmTests --gmalloc
+ @$(top_builddir)/GenerateTests 10000
# @$(top_builddir)/GenerateTests --gmalloc
######################################################################
@@ -516,17 +528,26 @@ libs:
(cd lib; make)
report: all
- -rm -fr build
lcov -d $(shell pwd) --zerocounters
+ if [ -d doc/report ]; then rm -fr doc/report; fi
-mkdir doc/report
lcov -c -i -d $(shell pwd) -o doc/report/ledger_base.info
- make fullcheck
+ make check
lcov -c -d $(shell pwd) --checksum -o doc/report/ledger_test.info
lcov -a doc/report/ledger_base.info \
-a doc/report/ledger_test.info -o doc/report/ledger_total.info
- lcov --extract doc/report/ledger_total.info '*src/ledger/*' \
+ lcov --extract doc/report/ledger_total.info '*/src/*' \
-o doc/report/ledger_cov.info
genhtml -o doc/report doc/report/ledger_cov.info
@echo Coverage reported generated\; now open doc/report/index.html
+LEDGER_BINARY = $(top_builddir)/ledger$(EXEEXT)
+SPEEDTEST_DAT = $(srcdir)/test/input/speed-test.dat
+SPEEDTEST_ARGS = -v --decimal-comma -o /dev/null reg 2eb75f84 1eede0cb
+
+speedtest:
+ @$(LEDGER_BINARY) -f $(SPEEDTEST_DAT) $(SPEEDTEST_ARGS)
+ @$(LEDGER_BINARY) -f $(SPEEDTEST_DAT) $(SPEEDTEST_ARGS) -V
+ @$(LEDGER_BINARY) -f $(SPEEDTEST_DAT) $(SPEEDTEST_ARGS) -X €
+
# Makefile.am ends here
diff --git a/tools/configure.ac b/tools/configure.ac
index c0a03249..92a30431 100644
--- a/tools/configure.ac
+++ b/tools/configure.ac
@@ -65,6 +65,16 @@ AC_ARG_ENABLE(doxygen,
AM_CONDITIONAL(USE_DOXYGEN, test x$doxygen = xtrue)
+AC_ARG_ENABLE(cache,
+ [ --enable-cache Enable use of the --cache option],
+ [case "${enableval}" in
+ yes) cache=true ;;
+ no) cache=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-cache) ;;
+ esac],[cache=false])
+
+AM_CONDITIONAL(USE_CACHE_OPTION, test x$cache = xtrue)
+
AC_ARG_ENABLE(python,
[ --enable-python Turn on Python support (experimental)],
[case "${enableval}" in
@@ -299,10 +309,16 @@ AC_CACHE_CHECK(
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <boost/iostreams/device/file_descriptor.hpp>
- #include <boost/iostreams/stream.hpp>]],
+ #include <boost/iostreams/stream.hpp>
+ #include <boost/version.hpp>]],
[[namespace io = boost::iostreams;
typedef io::stream<io::file_descriptor_sink> ofdstream;
- ofdstream outstream(1);]])],
+#if BOOST_VERSION >= 104400
+ ofdstream outstream(1, io::never_close_handle);
+#else // BOOST_VERSION >= 104400
+ ofdstream outstream(1);
+#endif // BOOST_VERSION >= 104400
+ ]])],
[boost_iostreams_cpplib_avail_cv_=true],
[boost_iostreams_cpplib_avail_cv_=false])
AC_LANG_POP
@@ -315,36 +331,37 @@ else
fi
# check for boost_serialization
-AC_CACHE_CHECK(
- [if boost_serialization is available],
- [boost_serialization_cpplib_avail_cv_],
- [boost_serialization_save_libs=$LIBS
- LIBS="-lboost_serialization$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
- AC_LANG_PUSH(C++)
- AC_LINK_IFELSE(
- [AC_LANG_PROGRAM(
- [[#include <boost/archive/binary_oarchive.hpp>
- #include <iostream>
- struct foo {
- int a;
- template<class Archive>
- void serialize(Archive & ar, const unsigned int) {
- ar & a;
- }
- };]],
- [[boost::archive::binary_oarchive oa(std::cout);
- foo x;
- oa << x;]])],
- [boost_serialization_cpplib_avail_cv_=true],
- [boost_serialization_cpplib_avail_cv_=false])
- AC_LANG_POP
- LIBS=$boost_serialization_save_libs])
-
-if [test x$boost_serialization_cpplib_avail_cv_ = xtrue ]; then
- AC_DEFINE([HAVE_BOOST_SERIALIZATION], [1], [Whether Boost.Serialization is available])
- LIBS="-lboost_serialization$BOOST_SUFFIX $LIBS"
-fi
-AM_CONDITIONAL(HAVE_BOOST_SERIALIZATION, test x$boost_serialization_cpplib_avail_cv_ = xtrue)
+#AC_CACHE_CHECK(
+# [if boost_serialization is available],
+# [boost_serialization_cpplib_avail_cv_],
+# [boost_serialization_save_libs=$LIBS
+# LIBS="-lboost_serialization$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
+# AC_LANG_PUSH(C++)
+# AC_LINK_IFELSE(
+# [AC_LANG_PROGRAM(
+# [[#include <boost/archive/binary_oarchive.hpp>
+# #include <iostream>
+# struct foo {
+# int a;
+# template<class Archive>
+# void serialize(Archive & ar, const unsigned int) {
+# ar & a;
+# }
+# };]],
+# [[boost::archive::binary_oarchive oa(std::cout);
+# foo x;
+# oa << x;]])],
+# [boost_serialization_cpplib_avail_cv_=true],
+# [boost_serialization_cpplib_avail_cv_=false])
+# AC_LANG_POP
+# LIBS=$boost_serialization_save_libs])
+#
+#if [test x$boost_serialization_cpplib_avail_cv_ = xtrue -a x$cache = xtrue]; then
+# AC_DEFINE([HAVE_BOOST_SERIALIZATION], [1], [Whether Boost.Serialization is available])
+# LIBS="-lboost_serialization$BOOST_SUFFIX $LIBS"
+#fi
+#AM_CONDITIONAL(HAVE_BOOST_SERIALIZATION, test x$boost_serialization_cpplib_avail_cv_ = xtrue -a x$cache = xtrue)
+AM_CONDITIONAL(HAVE_BOOST_SERIALIZATION, false)
# check for Python
if [ test x$python = xtrue ]; then
diff --git a/tools/excludes b/tools/excludes
index dc56eacc..d914099f 100644
--- a/tools/excludes
+++ b/tools/excludes
@@ -44,4 +44,3 @@ src/system.hh.gch
stamp-h1
texinfo.tex
util_tests
-version.m4
diff --git a/tools/pre-commit b/tools/pre-commit
index 50a32dbd..db47cc45 100755
--- a/tools/pre-commit
+++ b/tools/pre-commit
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# Exit with status 1 if any command below fails
set -e
@@ -12,6 +12,9 @@ fi
# These are the locations I keep my temporary source and build trees in
PRODUCTS=$(./acprep products) # generates a build directory name such as
# ~/Products/ledger
+if echo $PRODUCTS | grep -qv ledger; then
+ PRODUCTS=$PRODUCTS/ledger
+fi
TMPDIR=$PRODUCTS/pre-commit
MIRROR=$PRODUCTS/pre-commit-mirror
@@ -56,6 +59,7 @@ fi
# Finally, (re)build this proposed source tree and see if it passes
# muster.
+
if [ -f acprep ]; then
nice -n 20 ./acprep default --warn make check
else
diff --git a/tools/proof b/tools/proof
index 5a329a50..cd7b6636 100755
--- a/tools/proof
+++ b/tools/proof
@@ -12,22 +12,26 @@ if [[ -f ~/Products/last-proofed && \
exit 0
fi
-rm -fr ~/Products/ledger*
+rm -fr ~/Products/ledger-proof
-time ./acprep --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
if [[ "$1" = "--alert" ]]; then
- notify "Ledger proof build FAILED"
+ notify "Ledger proof build FAILED"
else
- echo "Ledger proof build FAILED"
- exit 1
+ echo "Ledger proof build FAILED"
+ 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
diff --git a/tools/push b/tools/push
index a9c6bc53..0333cf9c 100755
--- a/tools/push
+++ b/tools/push
@@ -2,14 +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 --universal -j16 --warn opt upload
-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
diff --git a/tools/speed-test.sh b/tools/speed-test.sh
new file mode 100755
index 00000000..0b03147c
--- /dev/null
+++ b/tools/speed-test.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+/bin/rm -fr ~/Products/ledger/opt
+
+./acprep -j16 opt update || exit 0
+
+COMMIT=$(git describe --long --all)
+
+SPEEDS=$(./acprep -j16 opt make speedtest 2>&1 \
+ | grep "Finished executing command" \
+ | awk '{print $1}' \
+ | xargs)
+
+echo $COMMIT,$(echo $SPEEDS | sed 's/ /,/g') >> ~/src/ledger/speed.log
+
+exit 0
diff --git a/version.m4 b/version.m4
new file mode 100644
index 00000000..581eae4e
--- /dev/null
+++ b/version.m4
@@ -0,0 +1 @@
+m4_define([VERSION_NUMBER], [3.0.0-20100623])