diff options
author | John Wiegley <johnw@newartisans.com> | 2009-11-14 20:43:28 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-11-14 20:43:28 -0500 |
commit | badbeb545b9e700e6656dfbc348bfe1387cb2ffa (patch) | |
tree | 26237a150367e13a24917d994602f5f94f979ec8 | |
parent | 73baf9cd727407f6e47b410bbde3b4bcad482ae3 (diff) | |
parent | 8d698e5ccb471d546eee8a5bea6d6c56ec4b08c3 (diff) | |
download | fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.gz fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.tar.bz2 fork-ledger-badbeb545b9e700e6656dfbc348bfe1387cb2ffa.zip |
Merge branch 'next'
-rw-r--r-- | README-1ST | 30 | ||||
-rwxr-xr-x | acprep | 179 | ||||
-rw-r--r-- | doc/ledger.1 | 5 | ||||
-rw-r--r-- | lib/Makefile | 6 | ||||
-rw-r--r-- | src/account.cc | 21 | ||||
-rw-r--r-- | src/amount.cc | 8 | ||||
-rw-r--r-- | src/filters.cc | 21 | ||||
-rw-r--r-- | src/filters.h | 2 | ||||
-rw-r--r-- | src/format.cc | 7 | ||||
-rw-r--r-- | src/item.cc | 5 | ||||
-rw-r--r-- | src/post.cc | 28 | ||||
-rw-r--r-- | src/post.h | 5 | ||||
-rw-r--r-- | src/py_journal.cc | 40 | ||||
-rw-r--r-- | src/py_post.cc | 2 | ||||
-rw-r--r-- | src/pyinterp.cc | 4 | ||||
-rw-r--r-- | src/report.cc | 39 | ||||
-rw-r--r-- | src/report.h | 2 | ||||
-rw-r--r-- | src/value.cc | 5 | ||||
-rw-r--r-- | src/xact.cc | 84 | ||||
-rw-r--r-- | src/xact.h | 10 | ||||
-rw-r--r-- | test/baseline/opt-collapse_reg.test | 46 | ||||
-rw-r--r-- | tools/configure.ac | 140 | ||||
-rwxr-xr-x | tools/push | 1 |
23 files changed, 477 insertions, 213 deletions
@@ -1,15 +1,35 @@ - README FIRST!!! - =============================================================================== + README FIRST!!! + To build this code after doing a Git clone, run: $ ./acprep update -If you try to configure/build on your own, you are almost certainly going to -run into problems. In future, you can run this command again and it will keep -you updated with the very latest version. +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): + + $ mkdir build + $ ./acprep opt make + $ ./acprep debug make + +Now install the optimized version, but know that you have 'build/debug/ledger' +available for testing and more useful bug reports. =============================================================================== @@ -42,6 +42,7 @@ class CommandLineApp(object): force_exit = True # If true, always ends run() with sys.exit() log_handler = None + darwin_gcc = False options = { 'debug': False, @@ -188,10 +189,8 @@ class PrepareBuild(CommandLineApp): self.CPPFLAGS = [] self.CCFLAGS = [] - self.ARCHFLAGS = [] self.CXXFLAGS = [] self.LDFLAGS = [] - self.LDARCHFLAGS = [] self.envvars = { 'PYTHON_HOME': '/usr', @@ -204,10 +203,8 @@ class PrepareBuild(CommandLineApp): 'CCFLAGS': '', 'CXX': 'g++', 'CXXFLAGS': '', - 'ARCHFLAGS': '', 'LD': 'g++', - 'LDFLAGS': '', - 'LDARCHFLAGS': '', + 'LDFLAGS': '' } for varname in self.envvars.keys(): @@ -554,14 +551,12 @@ class PrepareBuild(CommandLineApp): self.log.info('Looks like you are using MacPorts on OS X') packages = [ 'sudo', 'port', 'install', '-f', - 'automake', 'autoconf', 'libtool', - 'python26', 'boost-jam', + 'automake', 'autoconf', 'libtool', 'python26', 'libiconv', '+universal', 'zlib', '+universal', 'gmp' ,'+universal', 'mpfr', '+universal', 'ncurses', '+universal', 'ncursesw', '+universal', 'gettext' ,'+universal', 'libedit' ,'+universal', - 'boost', '+universal+st+debug+python26+doc', - 'cppunit' ,'+universal', + 'boost-jam', 'boost', '+st+python26+icu', 'cppunit', 'texlive', 'doxygen', 'graphviz', 'texinfo', 'lcov', 'sloccount' ] @@ -606,8 +601,7 @@ class PrepareBuild(CommandLineApp): 'python-devel', 'bboost-devel', 'gmp-devel', 'gettext-devel', #'mpfr-devel' - 'libedit-devel', - 'cppunit-devel', + 'libedit-devel', 'cppunit-devel', #'texlive-full', #'doxygen', 'graphviz', 'texinfo', #'lcov', 'sloccount' @@ -696,6 +690,11 @@ class PrepareBuild(CommandLineApp): path) return None + def inform_boost_location(self, text, suffix): + self.log.info('Boost %s here:' % text) + self.log.info('BOOST_HOME => ' + self.envvars['BOOST_HOME']) + self.log.info('BOOST_SUFFIX => ' + suffix) + def locate_boost(self): if self.envvars['BOOST_SUFFIX']: self.log.info(("Not looking for Boost, since " + @@ -708,10 +707,7 @@ class PrepareBuild(CommandLineApp): self.log.info('Looking for Boost in %s...' % path) suffix = self.locate_boost_in_dir(path) if suffix is not None: - self.log.info('Boost is located here:') - self.log.info('BOOST_HOME => ' + - self.envvars['BOOST_HOME']) - self.log.info('BOOST_SUFFIX => ' + suffix) + self.inform_boost_location('was found', suffix) break if suffix is None: self.log.error("Boost could not be found.") @@ -749,29 +745,25 @@ class PrepareBuild(CommandLineApp): self.sys_library_dirs.append(path) def setup_for_johnw(self): - # jww (2009-03-09): Some peculiarities specific to my system - if exists('/Users/johnw/Dropbox/Accounts/ledger.dat'): - if self.current_flavor == 'debug': - 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 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') + if self.current_flavor != 'opt': + 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') - self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1') + 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.options.use_glibcxx_debug = True + self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1') - self.CXXFLAGS.append('-march=nocona') - self.CXXFLAGS.append('-msse3') + self.options.use_glibcxx_debug = True - self.configure_args.append('--disable-shared') - self.configure_args.append('--enable-doxygen') - self.configure_args.append('--enable-python') + self.CXXFLAGS.append('-march=nocona') + self.CXXFLAGS.append('-msse3') - self.locate_my_libraries() + self.configure_args.append('--disable-shared') + self.configure_args.append('--enable-doxygen') + self.configure_args.append('--enable-python') def setup_for_system(self): self.setup_system_directories() @@ -797,17 +789,18 @@ class PrepareBuild(CommandLineApp): self.CXXFLAGS.append('-pthread') elif system == 'Darwin': - #self.ARCHFLAGS += ['-arch', 'i386', '-arch', 'ppc', - # '-isysroot', '/Developer/SDKs/MacOSX10.5.sdk'] - #self.LDARCHFLAGS += self.ARCHFLAGS - #ldflag = '-Wl,-syslibroot,/Developer/SDKs/MacOSX10.5.sdk' - #self.LDARCHFLAGS.append(ldflag) + if exists('/Users/johnw/Dropbox/Accounts/ledger.dat'): + self.setup_for_johnw() - self.setup_for_johnw() + self.locate_darwin_libraries() - # g++ 4.0.1 cannot use PCH headers on OS X 10.5, so we must use a - # newer version. - if exists('/opt/local/bin/g++-mp-4.4'): + if self.current_flavor == 'opt' 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.4'): self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.4' self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.4' self.envvars['LD'] = '/opt/local/bin/g++-mp-4.4' @@ -815,12 +808,13 @@ class PrepareBuild(CommandLineApp): self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.3' self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.3' self.envvars['LD'] = '/opt/local/bin/g++-mp-4.3' - elif not self.options.use_glibcxx_debug and \ - exists('/usr/bin/g++-4.2'): + elif 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 else: + # g++ 4.0.1 cannot use PCH headers on OS X 10.5 self.option_no_pch() if '--enable-pch' not in self.configure_args and \ @@ -859,8 +853,7 @@ class PrepareBuild(CommandLineApp): def finalize_config(self): self.setup_flavor() - for var in ('CPPFLAGS', 'CCFLAGS', 'ARCHFLAGS', - 'CXXFLAGS', 'LDFLAGS', 'LDARCHFLAGS'): + for var in ('CPPFLAGS', 'CCFLAGS', 'CXXFLAGS', 'LDFLAGS'): value = self.__dict__[var] if value: first = not self.envvars[var] @@ -978,69 +971,71 @@ class PrepareBuild(CommandLineApp): # The various build flavors # ######################################################################### - def locate_my_libraries(self): - if self.options.use_glibcxx_debug: + def locate_darwin_libraries(self): + if self.current_flavor != 'opt': self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags') - self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1') + if self.options.use_glibcxx_debug: + self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1') - if exists('/usr/local/stow/cppunit-debug/include'): - if '/usr/local/stow/cppunit/include' in self.sys_include_dirs: - self.sys_include_dirs.remove('/usr/local/stow/cppunit/include') - self.sys_library_dirs.remove('/usr/local/stow/cppunit/lib') + if exists('/usr/local/stow/cppunit-debug/include'): + if '/usr/local/stow/cppunit/include' in self.sys_include_dirs: + self.sys_include_dirs.remove('/usr/local/stow/cppunit/include') + self.sys_library_dirs.remove('/usr/local/stow/cppunit/lib') - self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit-debug/include') - self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit-debug/lib') + self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit-debug/include') + self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit-debug/lib') - if exists('/usr/local/stow/icu-debug/include'): - if '/usr/local/stow/icu/include' in self.sys_include_dirs: - self.sys_include_dirs.remove('/usr/local/stow/icu/include') - self.sys_library_dirs.remove('/usr/local/stow/icu/lib') + if exists('/usr/local/stow/icu-debug/include'): + if '/usr/local/stow/icu/include' in self.sys_include_dirs: + self.sys_include_dirs.remove('/usr/local/stow/icu/include') + self.sys_library_dirs.remove('/usr/local/stow/icu/lib') - self.sys_include_dirs.insert(0, '/usr/local/stow/icu-debug/include') - self.sys_library_dirs.insert(0, '/usr/local/stow/icu-debug/lib') + self.sys_include_dirs.insert(0, '/usr/local/stow/icu-debug/include') + self.sys_library_dirs.insert(0, '/usr/local/stow/icu-debug/lib') - if exists('/opt/local/lib/libboost_regex-d.a'): - self.envvars['BOOST_HOME'] = '/opt/local' - self.envvars['BOOST_SUFFIX'] = '-d' - - self.log.info('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - - self.sys_include_dirs.append('/opt/local/include/boost') - - elif exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_40.a'): + if exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_40.a'): self.envvars['BOOST_HOME'] = '/usr/local' self.envvars['BOOST_SUFFIX'] = '-xgcc44-sd-1_40' - self.log.info('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - self.sys_include_dirs.append('/usr/local/include/boost-1_40') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) elif exists('/usr/local/lib/libboost_regex-xgcc44-d-1_40.a'): self.envvars['BOOST_HOME'] = '/usr/local' self.envvars['BOOST_SUFFIX'] = '-xgcc44-d-1_40' - self.log.info('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - self.sys_include_dirs.append('/usr/local/include/boost-1_40') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/opt/local/lib/libboost_regex-d.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '-d' + self.sys_include_dirs.append('/opt/local/include/boost') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + else: if exists('/opt/local/lib/libboost_regex.a'): self.envvars['BOOST_HOME'] = '/opt/local' self.envvars['BOOST_SUFFIX'] = '' - - self.log.info('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - self.sys_include_dirs.append('/opt/local/include/boost') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) + + elif exists('/usr/local/lib/libboost_regex-xgcc44-s-1_40.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40' + self.sys_include_dirs.append('/usr/local/include/boost-1_40') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) elif exists('/usr/local/lib/libboost_regex-xgcc44-1_40.a'): self.envvars['BOOST_HOME'] = '/usr/local' self.envvars['BOOST_SUFFIX'] = '-xgcc44-1_40' - self.log.info('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - self.sys_include_dirs.append('/usr/local/include/boost-1_40') + self.inform_boost_location('is really located', + self.envvars['BOOST_SUFFIX']) def setup_flavor_default(self): pass @@ -1052,10 +1047,14 @@ class PrepareBuild(CommandLineApp): self.LDFLAGS.append('-g') def setup_flavor_opt(self): - self.CXXFLAGS.append('-O3') - self.LDFLAGS.append('-O3') - self.CXXFLAGS.append('-fomit-frame-pointer') - self.LDFLAGS.append('-fomit-frame-pointer') + if self.darwin_gcc: + self.CXXFLAGS.append('-fast') + self.LDFLAGS.append('-fast') + else: + self.CXXFLAGS.append('-O3') + self.LDFLAGS.append('-O3') + self.CXXFLAGS.append('-fomit-frame-pointer') + self.LDFLAGS.append('-fomit-frame-pointer') def setup_flavor_gcov(self): self.CXXFLAGS.append('-g') @@ -1122,8 +1121,8 @@ class PrepareBuild(CommandLineApp): conf_args = ['sh', join(self.source_dir, 'configure'), '--srcdir', self.source_dir] - for var in ('CC', 'CPPFLAGS', 'CCFLAGS', 'ARCHFLAGS', - 'CXX', 'CXXFLAGS', 'LD', 'LDFLAGS', 'LDARCHFLAGS'): + for var in ('CC', 'CPPFLAGS', 'CCFLAGS', 'CXX', 'CXXFLAGS', + 'LD', 'LDFLAGS'): if self.envvars.has_key(var) and self.envvars[var] and \ (var.endswith('FLAGS') or exists(self.envvars[var])): conf_args.append('%s=%s' % (var, self.envvars[var])) diff --git a/doc/ledger.1 b/doc/ledger.1 index 6007aec3..92457c48 100644 --- a/doc/ledger.1 +++ b/doc/ledger.1 @@ -1,4 +1,4 @@ -.Dd November 12, 2009 +.Dd November 13, 2009 .Dt ledger 1 .Sh NAME .Nm ledger @@ -577,6 +577,7 @@ and displays information about how it was parsed. See the section on .Xr beancount 1, .Xr hledger 1 .Sh AUTHORS -.An "John Wiegley" Aq johnw@newartisans.com +.An "John Wiegley" +.Aq johnw@newartisans.com .\" .Sh BUGS \" Document known, unremedied bugs .\" .Sh HISTORY \" Document history if command behaves in a unique manner diff --git a/lib/Makefile b/lib/Makefile index dee9afda..608be7d5 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -77,7 +77,8 @@ cppunit-release: CFLAGS="$(EXTRA_DEFINES) $(ARCH_CFLAGS)" \ LDFLAGS="$(ARCH_LDFLAGS)" \ CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \ - --prefix=$(STOW_ROOT)/cppunit && \ + --prefix=$(STOW_ROOT)/cppunit \ + --disable-doxygen --disable-dot && \ make install) cppunit-debug: @@ -87,7 +88,8 @@ cppunit-debug: CFLAGS="-g $(EXTRA_DEFINES) $(ARCH_CFLAGS)" \ LDFLAGS="-g $(ARCH_LDFLAGS)" \ CC="$(CC)" CXX="$(CXX)" LD="$(LD)" \ - --prefix=$(STOW_ROOT)/cppunit-debug && \ + --prefix=$(STOW_ROOT)/cppunit-debug \ + --disable-doxygen --disable-dot && \ make install) cppunit-build: cppunit-release cppunit-debug diff --git a/src/account.cc b/src/account.cc index da43745a..e6c7af56 100644 --- a/src/account.cc +++ b/src/account.cc @@ -249,7 +249,7 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, switch (name[0]) { case 'a': - if (name == "amount") + if (name[1] == '\0' || name == "amount") return WRAP_FUNCTOR(get_wrapper<&get_amount>); else if (name == "account") return WRAP_FUNCTOR(get_wrapper<&get_account>); @@ -272,11 +272,20 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, case 'i': if (name == "is_account") return WRAP_FUNCTOR(get_wrapper<&get_true>); + else if (name == "is_index") + return WRAP_FUNCTOR(get_wrapper<&get_subcount>); break; case 'l': if (name == "latest_cleared") return WRAP_FUNCTOR(get_wrapper<&get_latest_cleared>); + else if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_depth>); + break; + + case 'n': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_subcount>); break; case 'p': @@ -300,6 +309,16 @@ expr_t::ptr_op_t account_t::lookup(const symbol_t::kind_t kind, if (name == "use_direct_amount") return WRAP_FUNCTOR(get_wrapper<&ignore>); break; + + case 'N': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_count>); + break; + + case 'O': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_total>); + break; } return NULL; diff --git a/src/amount.cc b/src/amount.cc index f8406505..82b93931 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -56,7 +56,7 @@ struct amount_t::bigint_t : public supports_flags<> mpq_t val; precision_t prec; - uint_least16_t refc; + uint_least32_t refc; #define MP(bigint) ((bigint)->val) @@ -80,11 +80,7 @@ struct amount_t::bigint_t : public supports_flags<> bool valid() const { if (prec > 1024) { - DEBUG("ledger.validate", "amount_t::bigint_t: prec > 128"); - return false; - } - if (refc > 16535) { - DEBUG("ledger.validate", "amount_t::bigint_t: refc > 16535"); + DEBUG("ledger.validate", "amount_t::bigint_t: prec > 1024"); return false; } if (flags() & ~(BIGINT_BULK_ALLOC | BIGINT_KEEP_PREC)) { diff --git a/src/filters.cc b/src/filters.cc index 811067fc..bef4dc24 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -350,9 +350,9 @@ void collapse_posts::report_subtotal() component_posts.clear(); last_xact = NULL; - last_post = NULL; - subtotal = 0L; - count = 0; + last_post = NULL; + subtotal = 0L; + count = 0; } void collapse_posts::operator()(post_t& post) @@ -364,12 +364,12 @@ void collapse_posts::operator()(post_t& post) report_subtotal(); post.add_to_value(subtotal, amount_expr); - count++; component_posts.push_back(&post); last_xact = post.xact; - last_post = &post; + last_post = &post; + count++; } void related_posts::flush() @@ -648,8 +648,15 @@ void posts_as_equity::report_subtotal() value_t total = 0L; foreach (values_map::value_type& pair, values) { - handle_value(pair.second.value, pair.second.account, &xact, temps, - *handler); + if (pair.second.value.is_balance()) { + foreach (balance_t::amounts_map::value_type amount_pair, + pair.second.value.as_balance().amounts) + handle_value(amount_pair.second, pair.second.account, &xact, temps, + *handler); + } else { + handle_value(pair.second.value, pair.second.account, &xact, temps, + *handler); + } total += pair.second.value; } values.clear(); diff --git a/src/filters.h b/src/filters.h index 80bbe5b4..57b3edd2 100644 --- a/src/filters.h +++ b/src/filters.h @@ -466,7 +466,7 @@ public: TRACE_DTOR(subtotal_posts); } - void report_subtotal(const char * spec_fmt = NULL, + void report_subtotal(const char * spec_fmt = NULL, const optional<date_interval_t>& interval = none); virtual void flush() { diff --git a/src/format.cc b/src/format.cc index e910ce3b..f26a86a1 100644 --- a/src/format.cc +++ b/src/format.cc @@ -355,8 +355,11 @@ string format_t::real_calc(scope_t& scope) } DEBUG("format.expr", "value = (" << value << ")"); - value.print(out, static_cast<int>(elem->min_width), -1, - ! elem->has_flags(ELEMENT_ALIGN_LEFT)); + 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:")); diff --git a/src/item.cc b/src/item.cc index f60db226..43274cfd 100644 --- a/src/item.cc +++ b/src/item.cc @@ -395,6 +395,11 @@ expr_t::ptr_op_t item_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(get_wrapper<&get_uncleared>); break; + case 'L': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_actual>); + break; + case 'X': if (name[1] == '\0') return WRAP_FUNCTOR(get_wrapper<&get_cleared>); diff --git a/src/post.cc b/src/post.cc index 7c27b6c4..34284e1b 100644 --- a/src/post.cc +++ b/src/post.cc @@ -297,6 +297,11 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, return WRAP_FUNCTOR(get_wrapper<&get_account_base>); break; + case 'b': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_cost>); + break; + case 'c': if (name == "code") return WRAP_FUNCTOR(get_wrapper<&get_code>); @@ -325,7 +330,9 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, break; case 'i': - if (name == "id") + if (name == "index") + return WRAP_FUNCTOR(get_wrapper<&get_count>); + else if (name == "id") return WRAP_FUNCTOR(get_wrapper<&get_id>); else if (name == "idstring") return WRAP_FUNCTOR(get_wrapper<&get_idstring>); @@ -339,6 +346,8 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, case 'n': if (name == "note") return WRAP_FUNCTOR(get_wrapper<&get_note>); + else if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_count>); break; case 'p': @@ -358,7 +367,7 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, break; case 't': - if (name[1] == '\0' || name == "total") + if (name == "total") return WRAP_FUNCTOR(get_wrapper<&get_total>); break; @@ -376,6 +385,21 @@ expr_t::ptr_op_t post_t::lookup(const symbol_t::kind_t kind, if (name == "xact") return WRAP_FUNCTOR(get_wrapper<&get_xact>); break; + + case 'N': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_count>); + break; + + case 'O': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_total>); + break; + + case 'R': + if (name[1] == '\0') + return WRAP_FUNCTOR(get_wrapper<&get_real>); + break; } return item_t::lookup(kind, name); @@ -135,13 +135,11 @@ public: date_t date; datetime_t datetime; account_t * account; - void * ptr; std::list<sort_value_t> sort_values; xdata_t() - : supports_flags<uint_least16_t>(), count(0), - account(NULL), ptr(NULL) { + : supports_flags<uint_least16_t>(), count(0), account(NULL) { TRACE_CTOR(post_t::xdata_t, ""); } xdata_t(const xdata_t& other) @@ -152,7 +150,6 @@ public: count(other.count), date(other.date), account(other.account), - ptr(NULL), sort_values(other.sort_values) { TRACE_CTOR(post_t::xdata_t, "copy"); diff --git a/src/py_journal.cc b/src/py_journal.cc index bea14d66..7e9f8a1b 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -230,15 +230,18 @@ void export_journal() class_< collect_posts, bases<item_handler<post_t> >, shared_ptr<collect_posts>, boost::noncopyable >("PostCollector") .def("__len__", &collect_posts::length) - .def("__iter__", range<return_internal_reference<> > + .def("__iter__", range<return_internal_reference<1, + 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<>()) - .def("__iter__", range<return_internal_reference<> > + .def("__getitem__", posts_getitem, return_internal_reference<1, + with_custodian_and_ward_postcall<0, 1> >()) + .def("__iter__", range<return_value_policy<reference_existing_object, + with_custodian_and_ward_postcall<0, 1> > > (&collector_wrapper::begin, &collector_wrapper::end)) ; @@ -263,30 +266,43 @@ void export_journal() .def(init<path>()) .def(init<string>()) - .add_property("master", make_getter(&journal_t::master, - return_internal_reference<>())) + .add_property("master", + 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<>()), + 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)) .add_property("commodity_pool", make_getter(&journal_t::commodity_pool, - return_internal_reference<>())) + return_internal_reference<1, + with_custodian_and_ward_postcall<1, 0> >())) .def("add_account", &journal_t::add_account) .def("remove_account", &journal_t::remove_account) - .def("find_account", py_find_account_1, return_internal_reference<>()) - .def("find_account", py_find_account_2, return_internal_reference<>()) + .def("find_account", py_find_account_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> >()) .def("find_account_re", &journal_t::find_account_re, - return_internal_reference<>()) + 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) .def("__len__", xacts_len) - .def("__getitem__", xacts_getitem, return_internal_reference<>()) +#if 0 + .def("__getitem__", xacts_getitem, + return_internal_reference<1, + with_custodian_and_ward_postcall<0, 1> >()) +#endif .def("__iter__", range<return_internal_reference<> > (&journal_t::xacts_begin, &journal_t::xacts_end)) @@ -304,7 +320,7 @@ void export_journal() .def("has_xdata", &journal_t::has_xdata) .def("clear_xdata", &journal_t::clear_xdata) - .def("collect", py_collect) + .def("collect", py_collect, with_custodian_and_ward_postcall<0, 1>()) .def("valid", &journal_t::valid) ; diff --git a/src/py_post.cc b/src/py_post.cc index 8aabea28..20cdba6b 100644 --- a/src/py_post.cc +++ b/src/py_post.cc @@ -116,7 +116,7 @@ void export_post() make_setter(&post_t::xdata_t::datetime)) .add_property("account", make_getter(&post_t::xdata_t::account, - return_internal_reference<>()), + return_value_policy<reference_existing_object>()), make_setter(&post_t::xdata_t::account, with_custodian_and_ward<1, 2>())) .add_property("sort_values", diff --git a/src/pyinterp.cc b/src/pyinterp.cc index 0a56049c..0701176f 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -296,6 +296,10 @@ value_t python_interpreter_t::python_command(call_scope_t& args) try { status = Py_Main(static_cast<int>(args.size()) + 1, argv); } + catch (const error_already_set&) { + PyErr_Print(); + throw_(std::runtime_error, _("Failed to execute Python module")); + } catch (...) { for (std::size_t i = 0; i < args.size() + 1; i++) delete[] argv[i]; diff --git a/src/report.cc b/src/report.cc index 49633350..267a4a3d 100644 --- a/src/report.cc +++ b/src/report.cc @@ -915,6 +915,45 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, switch (kind) { case symbol_t::FUNCTION: + // Support 2.x's single-letter value expression names. + if (*(p + 1) == '\0') { + switch (*p) { + case 'd': + case 'm': + return MAKE_FUNCTOR(report_t::fn_now); + case 'P': + return MAKE_FUNCTOR(report_t::fn_market); + case 't': + return MAKE_FUNCTOR(report_t::fn_display_amount); + case 'T': + return MAKE_FUNCTOR(report_t::fn_display_total); + case 'U': + return MAKE_FUNCTOR(report_t::fn_abs); + case 'S': + return MAKE_FUNCTOR(report_t::fn_strip); + case 'i': + 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")); + case 'v': + case 'V': + 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")); + case 'g': + case 'G': + throw_(std::runtime_error, + _("The G and g value expression variables are no longer supported")); + default: + return NULL; + } + } + switch (*p) { case 'a': if (is_eq(p, "amount_expr")) diff --git a/src/report.h b/src/report.h index c656829b..93f6e9e0 100644 --- a/src/report.h +++ b/src/report.h @@ -775,7 +775,7 @@ public: "%(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))" + " bold if color & !cleared & actual))" " %(ansify_if(justify(truncated(account, account_width, abbrev_len), " " account_width), blue if color))" " %(justify(scrub(display_amount), amount_width, " diff --git a/src/value.cc b/src/value.cc index ce852c2d..3f70ab3d 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1618,7 +1618,10 @@ void value_t::print(std::ostream& out, break; case STRING: - justify(out, as_string(), first_width, right_justify); + if (first_width > 0) + justify(out, as_string(), first_width, right_justify); + else + out << as_string(); break; case MASK: diff --git a/src/xact.cc b/src/xact.cc index 1cece187..f2694976 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -412,7 +412,7 @@ bool xact_base_t::verify() continue; if (post->amount.commodity() == post->cost->commodity()) - throw_(balance_error, + throw_(amount_error, _("A posting's cost must be of a different commodity than its amount")); } @@ -538,6 +538,50 @@ bool xact_t::valid() const return true; } +namespace { + + bool post_pred(expr_t::ptr_op_t op, post_t& post) + { + switch (op->kind) { + case expr_t::op_t::VALUE: + return op->as_value().to_boolean(); + break; + + 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()); + else + break; + + case expr_t::op_t::O_NOT: + return ! post_pred(op->left(), post); + + case expr_t::op_t::O_AND: + return post_pred(op->left(), post) && post_pred(op->right(), post); + + case expr_t::op_t::O_OR: + return post_pred(op->left(), post) || post_pred(op->right(), post); + + case expr_t::op_t::O_QUERY: + if (post_pred(op->left(), post)) + return post_pred(op->right()->left(), post); + else + return post_pred(op->right()->right(), post); + + default: + break; + } + + throw_(calc_error, _("Unhandled operator")); + return false; + } + +} // unnamed namespace + void auto_xact_t::extend_xact(xact_base_t& xact) { posts_list initial_posts(xact.posts.begin(), xact.posts.end()); @@ -547,8 +591,42 @@ void auto_xact_t::extend_xact(xact_base_t& xact) bool needs_further_verification = false; foreach (post_t * initial_post, initial_posts) { - if (! initial_post->has_flags(ITEM_GENERATED) && - predicate(*initial_post)) { + if (initial_post->has_flags(ITEM_GENERATED)) + continue; + + 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)); + } + } + catch (...) { + 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) { foreach (post_t * post, posts) { amount_t post_amount; if (post->amount.is_null()) { @@ -146,16 +146,20 @@ class auto_xact_t : public xact_base_t { public: predicate_t predicate; + bool try_quick_match; - auto_xact_t() { + std::map<string, bool> memoized_results; + + auto_xact_t() : try_quick_match(true) { TRACE_CTOR(auto_xact_t, ""); } auto_xact_t(const auto_xact_t& other) - : xact_base_t(), predicate(other.predicate) { + : xact_base_t(), predicate(other.predicate), + try_quick_match(other.try_quick_match) { TRACE_CTOR(auto_xact_t, "copy"); } auto_xact_t(const predicate_t& _predicate) - : predicate(_predicate) + : predicate(_predicate), try_quick_match(true) { TRACE_CTOR(auto_xact_t, "const predicate_t&"); } diff --git a/test/baseline/opt-collapse_reg.test b/test/baseline/opt-collapse_reg.test new file mode 100644 index 00000000..12d4a2d9 --- /dev/null +++ b/test/baseline/opt-collapse_reg.test @@ -0,0 +1,46 @@ +reg --collapse food +<<< +2009/10/01 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/02 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/03 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/04 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/05 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/06 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash + +2009/10/07 Test + Expenses:Food:Dining $10 + Expenses:Food:Tips $1 + Assets:Cash +>>>1 +09-Oct-01 Test <Total> $11 $11 +09-Oct-02 Test <Total> $11 $22 +09-Oct-03 Test <Total> $11 $33 +09-Oct-04 Test <Total> $11 $44 +09-Oct-05 Test <Total> $11 $55 +09-Oct-06 Test <Total> $11 $66 +09-Oct-07 Test <Total> $11 $77 +>>>2 +=== 0 diff --git a/tools/configure.ac b/tools/configure.ac index f576bd61..b508eb21 100644 --- a/tools/configure.ac +++ b/tools/configure.ac @@ -84,31 +84,31 @@ AC_CACHE_CHECK( [AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <sys/types.h> - #include <sys/wait.h> - #include <unistd.h> - #include <stdlib.h> - #include <string.h> - #include <stdio.h>]], - [[int status, pfd[2]; - status = pipe(pfd); - status = fork(); - if (status < 0) { - ; - } else if (status == 0) { - char *arg0 = NULL; - - status = dup2(pfd[0], STDIN_FILENO); - - close(pfd[1]); - close(pfd[0]); - - execlp("", arg0, (char *)0); - perror("execl"); - exit(1); - } else { - close(pfd[0]); - }]])], + [[#include <sys/types.h> + #include <sys/wait.h> + #include <unistd.h> + #include <stdlib.h> + #include <string.h> + #include <stdio.h>]], + [[int status, pfd[2]; + status = pipe(pfd); + status = fork(); + if (status < 0) { + ; + } else if (status == 0) { + char *arg0 = NULL; + + status = dup2(pfd[0], STDIN_FILENO); + + close(pfd[1]); + close(pfd[0]); + + execlp("", arg0, (char *)0); + perror("execl"); + exit(1); + } else { + close(pfd[0]); + }]])], [pipes_avail_cv_=true], [pipes_avail_cv_=false]) AC_LANG_POP]) @@ -213,7 +213,7 @@ AC_CACHE_CHECK( using namespace boost;]], [[std::string text = "Активы"; u32regex r = make_u32regex("активы", regex::perl | regex::icase); - return u32regex_search(text, r) ? 0 : 1;]])], + return u32regex_search(text, r) ? 0 : 1;]])], [boost_regex_icu_avail_cv_=true], [boost_regex_icu_avail_cv_=false]) AC_LANG_POP @@ -233,26 +233,26 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <boost/date_time/posix_time/posix_time.hpp> - #include <boost/date_time/gregorian/gregorian.hpp> - #include <boost/date_time/local_time_adjustor.hpp> - #include <boost/date_time/time_duration.hpp> + [[#include <boost/date_time/posix_time/posix_time.hpp> + #include <boost/date_time/gregorian/gregorian.hpp> + #include <boost/date_time/local_time_adjustor.hpp> + #include <boost/date_time/time_duration.hpp> - using namespace boost::posix_time; - using namespace boost::date_time; + using namespace boost::posix_time; + using namespace boost::date_time; - #include <ctime> + #include <ctime> - inline ptime time_to_system_local(const ptime& when) { - struct std::tm tm_gmt = to_tm(when); - return from_time_t(mktime(&tm_gmt)); - }]], - [[ptime t10 = ptime(boost::gregorian::from_string("2007-01-15"), - ptime::time_duration_type()); + inline ptime time_to_system_local(const ptime& when) { + struct std::tm tm_gmt = to_tm(when); + return from_time_t(mktime(&tm_gmt)); + }]], + [[ptime t10 = ptime(boost::gregorian::from_string("2007-01-15"), + ptime::time_duration_type()); - ptime t12 = time_to_system_local(t10); + ptime t12 = time_to_system_local(t10); - return t10 != t12;]])], + return t10 != t12;]])], [boost_date_time_cpplib_avail_cv_=true], [boost_date_time_cpplib_avail_cv_=false]) AC_LANG_POP @@ -273,8 +273,8 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <boost/filesystem/path.hpp>]], - [[boost::filesystem::path this_path("Hello");]])], + [[#include <boost/filesystem/path.hpp>]], + [[boost::filesystem::path this_path("Hello");]])], [boost_filesystem_cpplib_avail_cv_=true], [boost_filesystem_cpplib_avail_cv_=false]) AC_LANG_POP @@ -295,11 +295,11 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <boost/iostreams/device/file_descriptor.hpp> - #include <boost/iostreams/stream.hpp>]], - [[namespace io = boost::iostreams; - typedef io::stream<io::file_descriptor_sink> ofdstream; - ofdstream outstream(1);]])], + [[#include <boost/iostreams/device/file_descriptor.hpp> + #include <boost/iostreams/stream.hpp>]], + [[namespace io = boost::iostreams; + typedef io::stream<io::file_descriptor_sink> ofdstream; + ofdstream outstream(1);]])], [boost_iostreams_cpplib_avail_cv_=true], [boost_iostreams_cpplib_avail_cv_=false]) AC_LANG_POP @@ -320,7 +320,7 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <boost/archive/binary_oarchive.hpp> + [[#include <boost/archive/binary_oarchive.hpp> #include <iostream> struct foo { int a; @@ -329,7 +329,7 @@ AC_CACHE_CHECK( ar & a; } };]], - [[boost::archive::binary_oarchive oa(std::cout); + [[boost::archive::binary_oarchive oa(std::cout); foo x; oa << x;]])], [boost_serialization_cpplib_avail_cv_=true], @@ -355,16 +355,16 @@ if [ test x$python = xtrue ]; then LIBS="-lboost_python$BOOST_SUFFIX -lpython$PYTHON_VERSION $LIBS" AC_LANG_PUSH(C++) AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[#include <boost/python.hpp> - using namespace boost::python; - class foo {}; - BOOST_PYTHON_MODULE(samp) { - class_< foo > ("foo") ; - }]], - [[return 0]])], - [boost_python_cpplib_avail_cv_=true], - [boost_python_cpplib_avail_cv_=false]) + [AC_LANG_PROGRAM( + [[#include <boost/python.hpp> + using namespace boost::python; + class foo {}; + BOOST_PYTHON_MODULE(samp) { + class_< foo > ("foo") ; + }]], + [[return 0]])], + [boost_python_cpplib_avail_cv_=true], + [boost_python_cpplib_avail_cv_=false]) AC_LANG_POP LIBS=$boost_python_save_libs]) @@ -390,16 +390,16 @@ AC_CACHE_CHECK( AC_LANG_PUSH(C++) AC_LINK_IFELSE( [AC_LANG_PROGRAM( - [[#include <cppunit/CompilerOutputter.h> - #include <cppunit/TestResult.h> - #include <cppunit/TestResultCollector.h> - #include <cppunit/TestRunner.h> - #include <cppunit/TextTestProgressListener.h> - #include <cppunit/BriefTestProgressListener.h> - #include <cppunit/XmlOutputter.h> - #include <cppunit/extensions/TestFactoryRegistry.h>]], - [[CPPUNIT_NS::TestResult controller; - CPPUNIT_NS::TestResultCollector result;]])], + [[#include <cppunit/CompilerOutputter.h> + #include <cppunit/TestResult.h> + #include <cppunit/TestResultCollector.h> + #include <cppunit/TestRunner.h> + #include <cppunit/TextTestProgressListener.h> + #include <cppunit/BriefTestProgressListener.h> + #include <cppunit/XmlOutputter.h> + #include <cppunit/extensions/TestFactoryRegistry.h>]], + [[CPPUNIT_NS::TestResult controller; + CPPUNIT_NS::TestResultCollector result;]])], [cppunit_avail_cv_=true], [cppunit_avail_cv_=false]) AC_LANG_POP @@ -11,4 +11,5 @@ git rebase master git push git checkout master ./acprep upload +mv *.dmg* build git checkout next |