Merge branch 'next'

This commit is contained in:
John Wiegley 2009-10-31 00:55:56 -04:00
commit a2cb549b1d
53 changed files with 4092 additions and 439 deletions

View file

@ -59,6 +59,7 @@ libledger_data_la_SOURCES = \
src/timelog.cc \
src/textual.cc \
src/journal.cc \
src/archive.cc \
src/account.cc \
src/xact.cc \
src/post.cc \
@ -118,6 +119,7 @@ pkginclude_HEADERS = \
src/xact.h \
src/account.h \
src/journal.h \
src/archive.h \
src/timelog.h \
src/iterators.h \
src/compare.h \

61
README-1ST Normal file
View file

@ -0,0 +1,61 @@
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.
===============================================================================
F.A.Q.
----------------------------------------------------------------------
- Q: The build fails saying it can't find utf8.h
A: You didn't run ./acprep update.
----------------------------------------------------------------------
- Q: Configure fails saying it can't find boost_regex
A: Look in config.log and search for "boost_regex", then scroll down a bit
until you see the exact compile error. Usually it's failing because
your include directory is different from anything acprep is expecting to
see. It could also be failing because your Boost libraries have a
custom "suffix" on them.
Let's say your Boost was installed in ~/boost, and every library has the
suffix '-xgcc42'. This is what you would run:
CPPFLAGS=-I$HOME/boost acprep --boost=xgcc42 update
----------------------------------------------------------------------
- Q: Configure fails saying it can't find MPFR
A: You need MPFR version 2.4.0 or higher. This version does not come with
most Debian distributions, so you will need to build it.
----------------------------------------------------------------------
- Q: Something else fails, or Ledger crashes on startup
A: This, I am most interested in hearing about. Please e-mail me a copy of
config.log and your build log to <johnw@newartisans.com>. Also, if
Ledger is crashing, try running it under gdb like so:
$ gdb ledger
(gdb) run <ARGS TO LEDGER>
... runs till crash ...
(gdb) bt
Send me that backtrace output, and the output from "ledger --version".
----------------------------------------------------------------------

216
acprep
View file

@ -293,7 +293,7 @@ class PrepareBuild(CommandLineApp):
else:
cmd = 'config'
self.log.debug('Invoking primary phase: ' + cmd)
self.log.info('Invoking primary phase: ' + cmd)
PrepareBuild.__dict__['phase_' + cmd](self, *args)
#########################################################################
@ -364,7 +364,7 @@ class PrepareBuild(CommandLineApp):
def ensure(self, dirname):
if not exists(dirname):
self.log.debug('Making directory: ' + dirname)
self.log.info('Making directory: ' + dirname)
os.makedirs(dirname)
elif not isdir(dirname):
self.log.error('Directory is not a directory: ' + dirname)
@ -396,11 +396,11 @@ class PrepareBuild(CommandLineApp):
return False
def phase_products(self, *args):
self.log.debug('Executing phase: products')
self.log.info('Executing phase: products')
print self.products_directory()
def phase_info(self, *args):
self.log.debug('Executing phase: info')
self.log.info('Executing phase: info')
environ, conf_args = self.configure_environment()
@ -433,7 +433,7 @@ class PrepareBuild(CommandLineApp):
self.log.debug(' %s' % arg)
def phase_sloc(self, *args):
self.log.debug('Executing phase: sloc')
self.log.info('Executing phase: sloc')
self.execute('sloccount', 'src', 'python', 'lisp', 'test')
#########################################################################
@ -441,13 +441,13 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def phase_gettext(self, *args):
self.log.debug('Executing phase: gettext')
self.log.info('Executing phase: gettext')
# configure the template files
assert exists('po') and isdir('po')
if not exists(join('po', 'Makevars')):
assert exists(join('po', 'Makevars.template'))
self.log.debug('Moving po/Makevars.template -> po/Makevars')
self.log.info('Moving po/Makevars.template -> po/Makevars')
os.rename(join('po', 'Makevars.template'),
join('po', 'Makevars'))
@ -460,22 +460,36 @@ class PrepareBuild(CommandLineApp):
POTFILES_in.close()
def phase_version(self, *args):
self.log.debug('Executing phase: version')
self.log.info('Executing phase: version')
version_m4 = open('version.m4', 'w')
version_m4.write("m4_define([VERSION_NUMBER], [%s])" %
self.current_version())
version_m4.close()
def phase_autogen(self, *args):
self.log.debug('Executing phase: autogen')
self.execute('sh', 'autogen.sh')
self.log.info('Executing phase: autogen')
if not exists('autogen.sh') or \
self.isnewer('tools/autogen.sh', 'autogen.sh'):
shutil.copyfile('tools/autogen.sh', 'autogen.sh')
self.execute('sh', 'tools/autogen.sh')
def phase_aclocal(self, *args):
self.log.debug('Executing phase: aclocal')
self.log.info('Executing phase: aclocal')
self.execute('aclocal', '-I', 'm4')
def phase_autoconf(self, *args):
self.log.debug('Executing phase: autoconf')
self.log.info('Executing phase: autoconf')
if not exists('configure.ac') or \
self.isnewer('tools/configure.ac', 'configure.ac'):
shutil.copyfile('tools/configure.ac', 'configure.ac')
if not exists('Makefile.am') or \
self.isnewer('tools/Makefile.am', 'Makefile.am'):
shutil.copyfile('tools/Makefile.am', 'Makefile.am')
reason = self.need_to_prepare_autotools()
if reason:
self.log.info('autogen.sh must be run ' + reason)
@ -491,13 +505,13 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def phase_submodule(self, *args):
self.log.debug('Executing phase: submodule')
self.log.info('Executing phase: submodule')
if exists('.git') and isdir('.git'):
self.execute('git', 'submodule', 'init')
self.execute('git', 'submodule', 'update')
def phase_pull(self, *args):
self.log.debug('Executing phase: pull')
self.log.info('Executing phase: pull')
if not exists('.git') and not isdir('.git'):
self.log.error("This is not a Git clone.")
sys.exit(1)
@ -509,7 +523,7 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def phase_dependencies(self, *args):
self.log.debug('Executing phase: dependencies')
self.log.info('Executing phase: dependencies')
self.log.info("Installing Ledger's build dependencies ...")
@ -581,7 +595,7 @@ class PrepareBuild(CommandLineApp):
self.execute(*packages)
def phase_buildlibs(self, *args):
self.log.debug('Executing phase: buildlibs')
self.log.info('Executing phase: buildlibs')
try:
os.chdir('lib')
@ -645,12 +659,12 @@ class PrepareBuild(CommandLineApp):
entries.sort()
for entry in entries:
if re.search('boost_regex', entry):
self.log.debug('Found a Boost library: ' + entry)
self.log.info('Found a Boost library: ' + entry)
match = re.match('libboost_regex([^.]*)\.(a|so|dylib)', entry)
if match:
suffix = match.group(1)
self.log.debug('Found Boost suffix => ' + suffix)
self.log.info('Found Boost suffix => ' + suffix)
self.envvars['BOOST_HOME'] = dirname(path)
return suffix
else:
@ -660,20 +674,20 @@ class PrepareBuild(CommandLineApp):
def locate_boost(self):
if self.envvars['BOOST_SUFFIX']:
self.log.debug(("Not looking for Boost, since " +
self.log.info(("Not looking for Boost, since " +
"a suffix of '%s' was given") %
self.envvars['BOOST_SUFFIX'])
else:
suffix = None
for path in ['/usr/local/lib', '/opt/local/lib',
'/sw/lib', '/usr/lib']:
self.log.debug('Looking for Boost in %s...' % path)
self.log.info('Looking for Boost in %s...' % path)
suffix = self.locate_boost_in_dir(path)
if suffix is not None:
self.log.debug('Boost is located here:')
self.log.debug('BOOST_HOME => ' +
self.log.info('Boost is located here:')
self.log.info('BOOST_HOME => ' +
self.envvars['BOOST_HOME'])
self.log.debug('BOOST_SUFFIX => ' + suffix)
self.log.info('BOOST_SUFFIX => ' + suffix)
break
if suffix is None:
self.log.error("Boost could not be found.")
@ -695,7 +709,7 @@ class PrepareBuild(CommandLineApp):
'/sw/include']:
if exists(path) and isdir(path) and \
path != '/usr/include':
self.log.debug('Noticing include directory => ' + path)
self.log.info('Noticing include directory => ' + path)
self.sys_include_dirs.append(path)
# Each of these becomes '-L<name>'
@ -707,17 +721,19 @@ class PrepareBuild(CommandLineApp):
'/opt/local/lib',
'/sw/lib']:
if exists(path) and isdir(path):
self.log.debug('Noticing library directory => ' + path)
self.log.info('Noticing library directory => ' + path)
self.sys_library_dirs.append(path)
def setup_for_johnw(self):
# jww (2009-03-09): Some peculiarities specific to my system
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('/Users/johnw/Dropbox/Accounts/ledger.dat'):
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.CXXFLAGS.append('-march=nocona')
self.CXXFLAGS.append('-msse3')
self.CPPFLAGS.append('-D_GLIBCXX_FULLY_DYNAMIC_STRING=1')
self.options.use_glibcxx_debug = True
@ -726,7 +742,7 @@ class PrepareBuild(CommandLineApp):
system = self.get_stdout('uname', '-s')
self.log.debug('System type is => ' + system)
self.log.info('System type is => ' + system)
# These options are global defaults at the moment
#self.option_warn()
@ -796,7 +812,7 @@ class PrepareBuild(CommandLineApp):
self.log.error('Unknown build flavor "%s"' % self.current_flavor)
sys.exit(1)
self.log.debug('Setting up build flavor => ' + self.current_flavor)
self.log.info('Setting up build flavor => ' + self.current_flavor)
PrepareBuild.__dict__['setup_flavor_' + self.current_flavor](self)
self.setup_flags()
@ -927,23 +943,23 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def setup_flavor_default(self):
if 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.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
elif exists('/opt/local/lib/libboost_regex.a'):
if exists('/opt/local/lib/libboost_regex.a'):
self.envvars['BOOST_HOME'] = '/opt/local'
self.envvars['BOOST_SUFFIX'] = ''
self.log.debug('Setting BOOST_SUFFIX => %s' %
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-s-1_40.a'):
self.envvars['BOOST_HOME'] = '/usr/local'
self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40'
self.log.info('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
def setup_flavor_debug(self):
self.configure_args.append('--enable-debug')
@ -960,64 +976,65 @@ class PrepareBuild(CommandLineApp):
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')
if exists('/usr/local/stow/cppunit-debug/include'):
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/lib/libboost_regex-xgcc44-sd-1_40.a'):
self.envvars['BOOST_HOME'] = '/usr/local'
self.envvars['BOOST_SUFFIX'] = '-xgcc44-sd-1_40'
self.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
elif exists('/opt/local/lib/libboost_regex-d.a'):
if exists('/opt/local/lib/libboost_regex-d.a'):
self.envvars['BOOST_HOME'] = '/opt/local'
self.envvars['BOOST_SUFFIX'] = '-d'
self.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.log.info('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/opt/local/include/boost')
else:
if exists('/usr/local/lib/libboost_regex-xgcc44-s-1_40.a'):
elif exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_40.a'):
self.envvars['BOOST_HOME'] = '/usr/local'
self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40'
self.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
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')
elif exists('/opt/local/lib/libboost_regex.a'):
else:
if exists('/opt/local/lib/libboost_regex.a'):
self.envvars['BOOST_HOME'] = '/opt/local'
self.envvars['BOOST_SUFFIX'] = ''
self.log.debug('Setting BOOST_SUFFIX => %s' %
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-s-1_40.a'):
self.envvars['BOOST_HOME'] = '/usr/local'
self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40'
self.log.info('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
def setup_flavor_opt(self):
self.CXXFLAGS.append('-O3')
self.CXXFLAGS.append('-fomit-frame-pointer')
if 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.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
elif exists('/opt/local/lib/libboost_regex.a'):
if exists('/opt/local/lib/libboost_regex.a'):
self.envvars['BOOST_HOME'] = '/opt/local'
self.envvars['BOOST_SUFFIX'] = ''
self.log.debug('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
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-s-1_40.a'):
self.envvars['BOOST_HOME'] = '/usr/local'
self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40'
self.log.info('Setting BOOST_SUFFIX => %s' %
self.envvars['BOOST_SUFFIX'])
self.sys_include_dirs.append('/usr/local/include/boost-1_40')
def setup_flavor_gcov(self):
self.CXXFLAGS.append('-g')
self.CXXFLAGS.append('-fprofile-arcs')
@ -1038,7 +1055,7 @@ class PrepareBuild(CommandLineApp):
"""Alter the Makefile so that it's not nearly so verbose.
This makes errors and warnings much easier to spot."""
self.log.debug('Executing phase: patch')
self.log.info('Executing phase: patch')
if exists('Makefile'):
self.log.debug('Patching generated Makefile')
@ -1108,7 +1125,7 @@ class PrepareBuild(CommandLineApp):
return False
def phase_configure(self, *args):
self.log.debug('Executing phase: configure')
self.log.info('Executing phase: configure')
self.configured = True
@ -1130,7 +1147,10 @@ class PrepareBuild(CommandLineApp):
self.log.debug('configure args => ' + str(conf_args))
configure = Popen(conf_args, shell=False, env=environ)
configure.wait()
retcode = configure.wait()
if retcode < 0:
self.log.error("Child was terminated by signal", -retcode)
sys.exit(1)
if not self.options.no_patch:
self.phase_patch()
@ -1145,7 +1165,7 @@ class PrepareBuild(CommandLineApp):
os.chdir(self.source_dir)
def phase_config(self, *args):
self.log.debug('Executing phase: config')
self.log.info('Executing phase: config')
self.phase_submodule()
self.phase_autoconf()
self.phase_configure(*args)
@ -1157,7 +1177,7 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def phase_make(self, *args):
self.log.debug('Executing phase: make')
self.log.info('Executing phase: make')
config_args = []
make_args = []
@ -1182,15 +1202,12 @@ class PrepareBuild(CommandLineApp):
self.log.debug('Changing directory to ' + build_dir)
os.chdir(build_dir)
self.log.debug('make args => ' + str(make_args))
configure = Popen(['make'] + make_args, shell=False)
configure.wait()
self.execute(*(['make'] + make_args))
finally:
os.chdir(self.source_dir)
def phase_update(self, *args):
self.log.debug('Executing phase: update')
self.log.info('Executing phase: update')
self.phase_pull()
self.phase_make(*args)
@ -1199,15 +1216,15 @@ class PrepareBuild(CommandLineApp):
#########################################################################
def phase_clean(self, *args):
self.log.debug('Executing phase: clean')
self.log.info('Executing phase: clean')
self.phase_make('clean')
def phase_distclean(self, *args):
self.log.debug('Executing phase: distclean')
self.log.info('Executing phase: distclean')
self.phase_make('distclean')
def phase_gitclean(self, *args):
self.log.debug('Executing phase: gitclean')
self.log.info('Executing phase: gitclean')
self.execute('git', 'clean', '-dfx')
#########################################################################
@ -1238,7 +1255,7 @@ class PrepareBuild(CommandLineApp):
'@loader_path/' + base, dest_file)
def phase_bindmg(self, *args):
self.log.debug('Executing phase: bindmg')
self.log.info('Executing phase: bindmg')
self.phase_make()
@ -1263,7 +1280,7 @@ class PrepareBuild(CommandLineApp):
shutil.rmtree(tempdir)
def phase_upload(self, *args):
self.log.debug('Executing phase: upload')
self.log.info('Executing phase: upload')
self.phase_bindmg()
@ -1295,7 +1312,7 @@ class PrepareBuild(CommandLineApp):
shutil.rmtree(self.build_directory())
def phase_distcheck(self, *args):
self.log.debug('Executing phase: distcheck')
self.log.info('Executing phase: distcheck')
self.configure_flavor('default', False)
@ -1320,7 +1337,7 @@ class PrepareBuild(CommandLineApp):
self.phase_make(*make_args)
def phase_rsync(self, *args):
self.log.debug('Executing phase: rsync')
self.log.info('Executing phase: rsync')
source_copy_dir = join(self.ensure(self.products_directory()),
'ledger-proof')
@ -1332,32 +1349,28 @@ class PrepareBuild(CommandLineApp):
self.source_dir = source_copy_dir
def phase_proof(self, *args):
self.log.debug('Executing phase: proof')
self.log.info('Executing phase: proof')
self.phase_makeall(*args)
self.log.info('=== Copying source tree ===')
self.phase_rsync()
self.phase_makeall(*args)
self.configure_flavor('opt')
self.log.info('=== Building opt ===')
self.phase_make(*args)
self.log.info('=== Testing opt ===')
self.phase_make('fullcheck')
self.configure_flavor('gcov')
self.log.info('=== Building gcov ===')
self.phase_make(*args)
self.log.info('=== Testing gcov ===')
self.phase_make('check')
self.configure_flavor('debug')
self.log.info('=== Building debug ===')
self.phase_make(*args)
self.log.info('=== Testing debug ===')
self.phase_make('fullcheck')
self.configure_flavor('default')
self.log.info('=== Building default ===')
self.phase_make(*args)
self.log.info('=== Testing default ===')
self.phase_make('fullcheck')
@ -1365,7 +1378,7 @@ class PrepareBuild(CommandLineApp):
self.phase_distcheck()
def phase_makeall(self, *args):
self.log.debug('Executing phase: makeall')
self.log.info('Executing phase: makeall')
self.configure_flavor('opt', False)
@ -1403,11 +1416,6 @@ class PrepareBuild(CommandLineApp):
self.configure_flavor('default', False)
def phase_do_all(self, *args):
self.log.debug('Executing phase: do_all')
self.phase_makeall(*args)
self.phase_proof(*args)
#########################################################################
# Help #
#########################################################################

0
autogen.sh Executable file → Normal file
View file

View file

@ -280,6 +280,38 @@ else
AC_MSG_FAILURE("Could not find boost_iostreams library (set CPPFLAGS and LDFLAGS?)")
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)
# check for Python
AM_PATH_PYTHON(2.4,, :)
if [test "$PYTHON" != :]; then

View file

@ -4,7 +4,7 @@
;; Emacs Lisp Archive Entry
;; Filename: ledger.el
;; Version: 2.7
;; Version: 3.0
;; Date: Fri 18-Jul-2008
;; Keywords: data
;; Author: John Wiegley (johnw AT gnu DOT org)

View file

@ -458,7 +458,7 @@ void account_t::xdata_t::details_t::update(post_t& post,
posts_virtuals_count++;
if (gather_all)
filenames.insert(post.pathname);
filenames.insert(post.pos->pathname);
date_t date = post.date();

View file

@ -232,6 +232,26 @@ public:
return xdata_ && xdata_->has_flags(flags);
}
std::size_t children_with_flags(xdata_t::flags_t flags) const;
#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<supports_flags<> >(*this);
ar & boost::serialization::base_object<scope_t>(*this);
ar & parent;
ar & name;
ar & note;
ar & depth;
ar & accounts;
ar & posts;
ar & _fullname;
}
#endif // HAVE_BOOST_SERIALIZATION
};
std::ostream& operator<<(std::ostream& out, const account_t& account);

View file

@ -56,25 +56,25 @@ struct amount_t::bigint_t : public supports_flags<>
mpq_t val;
precision_t prec;
uint_least16_t ref;
uint_least16_t refc;
#define MP(bigint) ((bigint)->val)
bigint_t() : prec(0), ref(1) {
bigint_t() : prec(0), refc(1) {
TRACE_CTOR(bigint_t, "");
mpq_init(val);
}
bigint_t(const bigint_t& other)
: supports_flags<>(static_cast<uint_least8_t>
(other.flags() & ~BIGINT_BULK_ALLOC)),
prec(other.prec), ref(1) {
prec(other.prec), refc(1) {
TRACE_CTOR(bigint_t, "copy");
mpq_init(val);
mpq_set(val, other.val);
}
~bigint_t() {
TRACE_DTOR(bigint_t);
assert(ref == 0);
assert(refc == 0);
mpq_clear(val);
}
@ -83,8 +83,8 @@ struct amount_t::bigint_t : public supports_flags<>
DEBUG("ledger.validate", "amount_t::bigint_t: prec > 128");
return false;
}
if (ref > 16535) {
DEBUG("ledger.validate", "amount_t::bigint_t: ref > 16535");
if (refc > 16535) {
DEBUG("ledger.validate", "amount_t::bigint_t: refc > 16535");
return false;
}
if (flags() & ~(BIGINT_BULK_ALLOC | BIGINT_KEEP_PREC)) {
@ -94,6 +94,20 @@ struct amount_t::bigint_t : public supports_flags<>
}
return true;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned int /* version */)
{
ar & boost::serialization::base_object<supports_flags<> >(*this);
ar & val;
ar & prec;
ar & refc;
}
#endif // HAVE_BOOST_SERIALIZATION
};
shared_ptr<commodity_pool_t> amount_t::current_pool;
@ -147,8 +161,8 @@ void amount_t::_copy(const amount_t& amt)
} else {
quantity = amt.quantity;
DEBUG("amounts.refs",
quantity << " ref++, now " << (quantity->ref + 1));
quantity->ref++;
quantity << " refc++, now " << (quantity->refc + 1));
quantity->refc++;
}
}
commodity_ = amt.commodity_;
@ -160,7 +174,7 @@ void amount_t::_dup()
{
VERIFY(valid());
if (quantity->ref > 1) {
if (quantity->refc > 1) {
bigint_t * q = new bigint_t(*quantity);
_release();
quantity = q;
@ -184,9 +198,9 @@ void amount_t::_release()
{
VERIFY(valid());
DEBUG("amounts.refs", quantity << " ref--, now " << (quantity->ref - 1));
DEBUG("amounts.refs", quantity << " refc--, now " << (quantity->refc - 1));
if (--quantity->ref == 0) {
if (--quantity->refc == 0) {
if (quantity->has_flags(BIGINT_BULK_ALLOC))
quantity->~bigint_t();
else
@ -920,7 +934,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags)
quantity = new bigint_t;
safe_holder.reset(quantity);
}
else if (quantity->ref > 1) {
else if (quantity->refc > 1) {
_release();
quantity = new bigint_t;
safe_holder.reset(quantity);
@ -1095,8 +1109,8 @@ bool amount_t::valid() const
return false;
}
if (quantity->ref == 0) {
DEBUG("ledger.validate", "amount_t: quantity->ref == 0");
if (quantity->refc == 0) {
DEBUG("ledger.validate", "amount_t: quantity->refc == 0");
return false;
}
}
@ -1107,4 +1121,63 @@ bool amount_t::valid() const
return true;
}
#if defined(HAVE_BOOST_SERIALIZATION)
template<class Archive>
void amount_t::serialize(Archive& ar, const unsigned int /* version */)
{
ar & current_pool;
ar & is_initialized;
ar & quantity;
ar & commodity_;
}
#endif // HAVE_BOOST_SERIALIZATION
} // namespace ledger
#if defined(HAVE_BOOST_SERIALIZATION)
namespace boost {
namespace serialization {
template <class Archive>
void serialize(Archive& ar, MP_INT& mpz, const unsigned int /* version */)
{
ar & mpz._mp_alloc;
ar & mpz._mp_size;
ar & mpz._mp_d;
}
template <class Archive>
void serialize(Archive& ar, MP_RAT& mpq, const unsigned int /* version */)
{
ar & mpq._mp_num;
ar & mpq._mp_den;
}
template <class Archive>
void serialize(Archive& ar, long unsigned int& integer,
const unsigned int /* version */)
{
ar & make_binary_object(&integer, sizeof(long unsigned int));
}
} // namespace serialization
} // namespace boost
BOOST_CLASS_EXPORT(ledger::annotated_commodity_t)
template void boost::serialization::serialize(boost::archive::binary_oarchive&,
MP_INT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_iarchive&,
MP_RAT&, const unsigned int);
template void boost::serialization::serialize(boost::archive::binary_iarchive&,
long unsigned int&,
const unsigned int);
template void ledger::amount_t::serialize(boost::archive::binary_oarchive&,
const unsigned int);
template void ledger::amount_t::serialize(boost::archive::binary_iarchive&,
const unsigned int);
#endif // HAVE_BOOST_SERIALIZATION

View file

@ -691,6 +691,16 @@ public:
bool valid() const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */);
#endif // HAVE_BOOST_SERIALIZATION
/*@}*/
};

View file

@ -98,6 +98,21 @@ struct annotation_t : public supports_flags<>,
assert(*this);
return true;
}
#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<supports_flags<> >(*this);
ar & price;
ar & date;
ar & tag;
}
#endif // HAVE_BOOST_SERIALIZATION
};
struct keep_details_t
@ -136,6 +151,21 @@ struct keep_details_t
return keep_price || keep_date || keep_tag;
}
bool keep_any(const commodity_t& comm) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & keep_price;
ar & keep_date;
ar & keep_tag;
ar & only_actuals;
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out,
@ -183,6 +213,22 @@ public:
virtual commodity_t& strip_annotations(const keep_details_t& what_to_keep);
virtual void write_annotations(std::ostream& out) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
explicit annotated_commodity_t() : ptr(NULL) {}
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & boost::serialization::base_object<commodity_t>(*this);
ar & ptr;
ar & details;
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline annotated_commodity_t&

247
src/archive.cc Normal file
View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 2003-2009, 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>
#if defined(HAVE_BOOST_SERIALIZATION)
#include "archive.h"
#include "amount.h"
#include "commodity.h"
#include "pool.h"
#include "scope.h"
#include "account.h"
#include "post.h"
#include "xact.h"
#define ARCHIVE_VERSION 0x03000001
//BOOST_IS_ABSTRACT(ledger::scope_t)
BOOST_CLASS_EXPORT(ledger::scope_t)
BOOST_CLASS_EXPORT(ledger::child_scope_t)
BOOST_CLASS_EXPORT(ledger::symbol_scope_t)
BOOST_CLASS_EXPORT(ledger::call_scope_t)
BOOST_CLASS_EXPORT(ledger::account_t)
BOOST_CLASS_EXPORT(ledger::item_t)
BOOST_CLASS_EXPORT(ledger::post_t)
BOOST_CLASS_EXPORT(ledger::xact_base_t)
BOOST_CLASS_EXPORT(ledger::xact_t)
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);
template void ledger::journal_t::serialize(boost::archive::binary_iarchive&,
const unsigned int);
namespace ledger {
void archive_t::read_header()
{
if (exists(file)) {
// Open the stream, read the version number and the list of sources
ifstream stream(file, std::ios::binary);
boost::archive::binary_iarchive iarchive(stream);
DEBUG("archive.journal", "Reading header from archive");
iarchive >> *this;
DEBUG("archive.journal",
"Version number: " << std::hex << version << std::dec);
DEBUG("archive.journal", "Number of sources: " << sources.size());
foreach (const journal_t::fileinfo_t& i, sources)
DEBUG("archive.journal", "Loaded source: " << *i.filename);
}
}
bool archive_t::should_load(const std::list<path>& data_files)
{
std::size_t found = 0;
DEBUG("archive.journal", "Should the archive be loaded?");
if (! exists(file)) {
DEBUG("archive.journal", "No, it does not exist");
return false;
}
if (version != ARCHIVE_VERSION) {
DEBUG("archive.journal", "No, it fails the version check");
return false;
}
if (data_files.empty()) {
DEBUG("archive.journal", "No, there were no data files!");
return false;
}
if (sources.empty()) {
DEBUG("archive.journal", "No, there were no sources!");
return false;
}
if (data_files.size() != sources.size()) {
DEBUG("archive.journal", "No, number of sources doesn't match: "
<< data_files.size() << " != " << sources.size());
return false;
}
foreach (const path& p, data_files) {
DEBUG("archive.journal", "Scanning for data file: " << p);
if (! exists(p)) {
DEBUG("archive.journal", "No, an input source no longer exists: " << p);
return false;
}
foreach (const journal_t::fileinfo_t& i, sources) {
assert(! i.from_stream);
assert(i.filename);
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 (found != data_files.size()) {
DEBUG("archive.journal", "No, not every source's name matched");
return false;
}
DEBUG("archive.journal", "Yes, it should be loaded!");
return true;
}
bool archive_t::should_save(shared_ptr<journal_t> journal)
{
std::list<path> data_files;
DEBUG("archive.journal", "Should the archive be saved?");
if (journal->was_loaded) {
DEBUG("archive.journal", "No, it's one we loaded before");
return false;
}
if (journal->sources.empty()) {
DEBUG("archive.journal", "No, there were no sources!");
return false;
}
foreach (const journal_t::fileinfo_t& i, journal->sources) {
if (i.from_stream) {
DEBUG("archive.journal", "No, one source was from a stream");
return false;
}
if (! exists(*i.filename)) {
DEBUG("archive.journal",
"No, a source no longer exists: " << *i.filename);
return false;
}
data_files.push_back(*i.filename);
}
if (should_load(data_files)) {
DEBUG("archive.journal", "No, because it's still loadable");
return false;
}
DEBUG("archive.journal", "Yes, it should be saved!");
return true;
}
void archive_t::save(shared_ptr<journal_t> journal)
{
INFO_START(archive, "Saved journal file cache");
ofstream archive(file, std::ios::binary);
boost::archive::binary_oarchive oa(archive);
version = ARCHIVE_VERSION;
sources = journal->sources;
foreach (const journal_t::fileinfo_t& i, sources)
DEBUG("archive.journal", "Saving source: " << *i.filename);
DEBUG("archive.journal",
"Creating archive with version " << std::hex << version << std::dec);
oa << *this;
DEBUG("archive.journal",
"Archiving journal with " << sources.size() << " sources");
oa << *journal;
INFO_FINISH(archive);
}
bool archive_t::load(shared_ptr<journal_t> journal)
{
INFO_START(archive, "Read cached journal file");
ifstream stream(file, std::ios::binary);
boost::archive::binary_iarchive iarchive(stream);
// Skip past the archive header, it was already read in before
archive_t temp;
iarchive >> temp;
iarchive >> *journal.get();
journal->was_loaded = true;
INFO_FINISH(archive);
return true;
}
} // namespace ledger
#endif // HAVE_BOOST_SERIALIZATION

105
src/archive.h Normal file
View file

@ -0,0 +1,105 @@
/*
* Copyright (c) 2003-2009, 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.
*/
/**
* @defgroup report Reporting
*/
/**
* @file archive.h
* @author John Wiegley
*
* @ingroup report
*
* @brief Brief
*
* Long.
*/
#ifndef _ARCHIVE_H
#define _ARCHIVE_H
#include "journal.h"
namespace ledger {
/**
* @brief Brief
*
* Long.
*/
class archive_t
{
path file;
uint32_t version;
std::list<journal_t::fileinfo_t> sources;
public:
archive_t() {
TRACE_CTOR(archive_t, "");
}
archive_t(const path& _file)
: file(_file), version(0) {
TRACE_CTOR(archive_t, "const path&");
}
archive_t(const archive_t& ar)
: file(ar.file), version(0) {
TRACE_CTOR(archive_t, "copy");
}
~archive_t() {
TRACE_DTOR(archive_t);
}
void read_header();
bool should_load(const std::list<path>& data_files);
bool should_save(shared_ptr<journal_t> journal);
void save(shared_ptr<journal_t> journal);
bool load(shared_ptr<journal_t> journal);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & version;
ar & sources;
}
#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger
#endif // _ARCHIVE_H

View file

@ -228,12 +228,14 @@ balance_t::commodity_amount(const optional<const commodity_t&>& commodity) const
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);
}
#endif
}
else if (amounts.size() > 0) {
amounts_map::const_iterator i = amounts.find(&*commodity);
amounts_map::const_iterator i =
amounts.find(const_cast<commodity_t *>(&*commodity));
if (i != amounts.end())
return i->second;
}

View file

@ -80,7 +80,7 @@ class balance_t
multiplicative<balance_t, long> > > > > > > > > > > > > >
{
public:
typedef std::map<const commodity_t *, amount_t> amounts_map;
typedef std::map<commodity_t *, amount_t> amounts_map;
amounts_map amounts;
@ -523,6 +523,18 @@ public:
}
return true;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & amounts;
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const balance_t& bal) {

View file

@ -223,33 +223,33 @@ post_handler_ptr chain_post_handlers(report_t& report,
if (report.HANDLED(set_account_))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
report.session.master.get(),
report.session.journal->master,
report.HANDLER(set_account_).str(),
report));
else if (report.HANDLED(set_payee_))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
report.session.master.get(),
report.session.journal->master,
report.HANDLER(set_payee_).str(),
report));
else if (report.HANDLED(comm_as_payee))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
report.session.master.get(),
report.session.journal->master,
expr_t("commodity"), report));
else if (report.HANDLED(code_as_payee))
handler.reset(new transfer_details(handler, transfer_details::SET_PAYEE,
report.session.master.get(),
report.session.journal->master,
expr_t("code"), report));
else if (report.HANDLED(payee_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
report.session.master.get(),
report.session.journal->master,
expr_t("payee"), report));
else if (report.HANDLED(comm_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
report.session.master.get(),
report.session.journal->master,
expr_t("commodity"), report));
else if (report.HANDLED(code_as_account))
handler.reset(new transfer_details(handler, transfer_details::SET_ACCOUNT,
report.session.master.get(),
report.session.journal->master,
expr_t("code"), report));
return handler;

View file

@ -62,6 +62,19 @@ struct price_point_t
{
datetime_t when;
amount_t price;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & when;
ar & price;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -78,7 +91,7 @@ class commodity_t
public:
class base_t : public noncopyable, public supports_flags<uint_least16_t>
{
base_t();
base_t() {}
public:
typedef std::map<const datetime_t, amount_t> history_map;
@ -100,6 +113,18 @@ public:
, const int indent = 0
#endif
) const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & prices;
}
#endif // HAVE_BOOST_SERIALIZATION
};
typedef std::map<commodity_t *, history_t> history_by_commodity_map;
@ -126,6 +151,18 @@ public:
optional<history_t&>
history(const optional<commodity_t&>& commodity = none);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & histories;
}
#endif // HAVE_BOOST_SERIALIZATION
};
#define COMMODITY_STYLE_DEFAULTS 0x000
@ -158,6 +195,25 @@ public:
~base_t() {
TRACE_DTOR(base_t);
}
#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<supports_flags<uint_least16_t> >(*this);
ar & symbol;
ar & precision;
ar & name;
ar & note;
ar & varied_history;
ar & smaller;
ar & larger;
}
#endif // HAVE_BOOST_SERIALIZATION
};
public:
@ -330,6 +386,31 @@ public:
}
bool valid() const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
supports_flags<uint_least16_t> temp_flags;
protected:
explicit commodity_t()
: delegates_flags<uint_least16_t>(temp_flags), parent_(NULL),
annotated(false) {}
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & boost::serialization::base_object<delegates_flags<uint_least16_t> >(*this);
ar & base;
ar & parent_;
ar & qualified_symbol;
ar & mapping_key_;
ar & annotated;
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const commodity_t& comm) {

View file

@ -252,7 +252,7 @@ namespace {
if (tmpl.payee_mask.match((*j)->payee)) {
matching = *j;
DEBUG("derive.xact",
"Found payee match: transaction on line " << (*j)->beg_line);
"Found payee match: transaction on line " << (*j)->pos->beg_line);
break;
}
}
@ -332,7 +332,7 @@ namespace {
if (post.account_mask->match(x->account->fullname())) {
new_post.reset(new post_t(*x));
DEBUG("derive.xact",
"Founding posting from line " << x->beg_line);
"Founding posting from line " << x->pos->beg_line);
break;
}
}

View file

@ -40,8 +40,8 @@ namespace ledger {
void format_emacs_posts::write_xact(xact_t& xact)
{
out << "\"" << xact.pathname << "\" "
<< (xact.beg_line + 1) << " ";
out << "\"" << xact.pos->pathname << "\" "
<< (xact.pos->beg_line + 1) << " ";
tm when = gregorian::to_tm(xact.date());
std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local?
@ -77,7 +77,7 @@ void format_emacs_posts::operator()(post_t& post)
out << "\n";
}
out << " (" << (post.beg_line + 1) << " ";
out << " (" << (post.pos->beg_line + 1) << " ";
out << "\"" << post.reported_account()->fullname() << "\" \""
<< post.amount << "\"";

View file

@ -96,10 +96,10 @@ string source_context(const path& file,
ifstream in(file);
in.seekg(pos, std::ios::beg);
scoped_array<char> buf(new char[len + 1]);
in.read(buf.get(), len);
assert(in.gcount() == len);
buf[len] = '\0';
scoped_array<char> buf(new char[static_cast<std::size_t>(len) + 1]);
in.read(buf.get(), static_cast<std::streamsize>(len));
assert(in.gcount() == static_cast<std::streamsize>(len));
buf[static_cast<std::size_t>(len)] = '\0';
bool first = true;
for (char * p = std::strtok(buf.get(), "\n");

View file

@ -103,7 +103,7 @@ public:
expr_t(const string& _str, const uint_least8_t flags = 0);
expr_t(std::istream& in, const uint_least8_t flags = 0);
virtual ~expr_t() throw();
~expr_t() throw();
expr_t& operator=(const expr_t& _expr);
expr_t& operator=(const string& _expr) {
@ -163,6 +163,22 @@ public:
void dump(std::ostream& out) const;
static value_t eval(const string& _expr, scope_t& scope);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & ptr;
ar & context;
ar & str;
if (Archive::is_loading::value)
compiled = false;
}
#endif // HAVE_BOOST_SERIALIZATION
};
std::ostream& operator<<(std::ostream& out, const expr_t& expr);

View file

@ -99,6 +99,17 @@ public:
void drop_flags(const flags_t arg) {
_flags = static_cast<T>(static_cast<U>(_flags) & static_cast<U>(~arg));
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */)
{
ar & _flags;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -201,6 +212,17 @@ public:
void drop_flags(const flags_t arg) {
_flags.drop_flags(arg);
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */)
{
ar & _flags;
}
#endif // HAVE_BOOST_SERIALIZATION
};
#endif // _FLAGS_H

View file

@ -435,17 +435,18 @@ void global_scope_t::normalize_report_options(const string& verb)
item_t::use_effective_date = (rep.HANDLED(effective) &&
! rep.HANDLED(actual_dates));
rep.session.commodity_pool->keep_base = rep.HANDLED(base);
rep.session.commodity_pool->get_quotes = rep.session.HANDLED(download);
rep.session.journal->commodity_pool->keep_base = rep.HANDLED(base);
rep.session.journal->commodity_pool->get_quotes = rep.session.HANDLED(download);
if (rep.session.HANDLED(price_exp_))
rep.session.commodity_pool->quote_leeway =
rep.session.journal->commodity_pool->quote_leeway =
rep.session.HANDLER(price_exp_).value.as_long();
if (rep.session.HANDLED(price_db_))
rep.session.commodity_pool->price_db = rep.session.HANDLER(price_db_).str();
rep.session.journal->commodity_pool->price_db =
rep.session.HANDLER(price_db_).str();
else
rep.session.commodity_pool->price_db = none;
rep.session.journal->commodity_pool->price_db = none;
if (rep.HANDLED(date_format_))
set_date_format(rep.HANDLER(date_format_).str().c_str());
@ -542,7 +543,8 @@ void global_scope_t::normalize_report_options(const string& verb)
if (! rep.HANDLER(date_width_).specified)
rep.HANDLER(date_width_)
.on_with(none, format_date(CURRENT_DATE(), FMT_PRINTED).length());
.on_with(none, static_cast<long>(format_date(CURRENT_DATE(),
FMT_PRINTED).length()));
long date_width = rep.HANDLER(date_width_).value.to_long();
long payee_width = (rep.HANDLER(payee_width_).specified ?

View file

@ -118,9 +118,9 @@ void interactive_t::verify_arguments() const
label = _("any value");
wrong_arg = false;
break;
case 'P':
label = _("a pointer");
wrong_arg = ! next_arg->is_pointer();
case '^':
label = _("a scope");
wrong_arg = ! next_arg->is_scope();
break;
case 'S':
label = _("a sequence");

View file

@ -187,7 +187,7 @@ namespace {
}
value_t get_actual(item_t& item) {
return ! item.has_flags(ITEM_GENERATED);
return ! item.has_flags(ITEM_GENERATED | ITEM_TEMP);
}
value_t get_date(item_t& item) {
@ -224,23 +224,26 @@ namespace {
}
value_t get_pathname(item_t& item) {
return string_value(item.pathname.string());
if (item.pos)
return string_value(item.pos->pathname.string());
else
return string_value(empty_string);
}
value_t get_beg_pos(item_t& item) {
return long(item.beg_pos);
return item.pos ? long(item.pos->beg_pos) : 0L;
}
value_t get_beg_line(item_t& item) {
return long(item.beg_line);
return item.pos ? long(item.pos->beg_line) : 0L;
}
value_t get_end_pos(item_t& item) {
return long(item.end_pos);
return item.pos ? long(item.pos->end_pos) : 0L;
}
value_t get_end_line(item_t& item) {
return long(item.end_line);
return item.pos ? long(item.pos->end_line) : 0L;
}
value_t get_depth(item_t&) {
@ -397,12 +400,13 @@ bool item_t::valid() const
void print_item(std::ostream& out, const item_t& item, const string& prefix)
{
out << source_context(item.pathname, item.beg_pos, item.end_pos, prefix);
out << source_context(item.pos->pathname, item.pos->beg_pos,
item.pos->end_pos, prefix);
}
string item_context(const item_t& item, const string& desc)
{
std::streamoff len = item.end_pos - item.beg_pos;
std::streamoff len = item.pos->end_pos - item.pos->beg_pos;
if (! len)
return _("<no item context>");
@ -411,18 +415,18 @@ string item_context(const item_t& item, const string& desc)
std::ostringstream out;
if (item.pathname == path("/dev/stdin")) {
if (item.pos->pathname == path("/dev/stdin")) {
out << desc << _(" from standard input:");
return out.str();
}
out << desc << _(" from \"") << item.pathname.string() << "\"";
out << desc << _(" from \"") << item.pos->pathname.string() << "\"";
if (item.beg_line != item.end_line)
out << _(", lines ") << item.beg_line << "-"
<< item.end_line << ":\n";
if (item.pos->beg_line != item.pos->end_line)
out << _(", lines ") << item.pos->beg_line << "-"
<< item.pos->end_line << ":\n";
else
out << _(", line ") << item.beg_line << ":\n";
out << _(", line ") << item.pos->beg_line << ":\n";
print_item(out, item, "> ");

View file

@ -50,6 +50,53 @@
namespace ledger {
struct position_t
{
path pathname;
istream_pos_type beg_pos;
std::size_t beg_line;
istream_pos_type end_pos;
std::size_t end_line;
position_t() : beg_pos(0), beg_line(0), end_pos(0), end_line(0) {
TRACE_CTOR(position_t, "");
}
position_t(const position_t& pos) {
TRACE_CTOR(position_t, "copy");
*this = pos;
}
~position_t() throw() {
TRACE_DTOR(position_t);
}
position_t& operator=(const position_t& pos) {
if (this != &pos) {
pathname = pos.pathname;
beg_pos = pos.beg_pos;
beg_line = pos.beg_line;
end_pos = pos.end_pos;
end_line = pos.end_line;
}
return *this;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & pathname;
ar & beg_pos;
ar & beg_line;
ar & end_pos;
ar & end_line;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
* @brief Brief
*
@ -61,28 +108,21 @@ public:
#define ITEM_NORMAL 0x00 // no flags at all, a basic posting
// jww (2009-10-27): I'm not consistent on the difference between these two.
#define ITEM_GENERATED 0x01 // posting was not found in a journal
#define ITEM_TEMP 0x02 // posting is a temporary object
#define ITEM_TEMP 0x02 // posting is a managed temporary
enum state_t { UNCLEARED = 0, CLEARED, PENDING };
state_t _state;
optional<date_t> _date;
optional<date_t> _date_eff;
optional<string> note;
typedef std::map<string, optional<string> > string_map;
state_t _state;
optional<date_t> _date;
optional<date_t> _date_eff;
optional<string> note;
optional<position_t> pos;
optional<string_map> metadata;
path pathname;
istream_pos_type beg_pos;
std::size_t beg_line;
istream_pos_type end_pos;
std::size_t end_line;
item_t(flags_t _flags = ITEM_NORMAL, const optional<string>& _note = none)
: supports_flags<>(_flags), _state(UNCLEARED), note(_note),
beg_pos(0), beg_line(0), end_pos(0), end_line(0)
: supports_flags<>(_flags), _state(UNCLEARED), note(_note)
{
TRACE_CTOR(item_t, "flags_t, const string&");
}
@ -102,14 +142,8 @@ public:
_date = item._date;
_date_eff = item._date_eff;
note = item.note;
pathname = item.pathname;
beg_pos = item.beg_pos;
beg_line = item.beg_line;
end_pos = item.end_pos;
end_line = item.end_line;
pos = item.pos;
}
virtual bool operator==(const item_t& xact) {
@ -158,6 +192,25 @@ public:
virtual expr_t::ptr_op_t lookup(const string& name);
bool valid() const;
#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<supports_flags<> >(*this);
ar & boost::serialization::base_object<scope_t>(*this);
ar & _state;
ar & _date;
ar & _date_eff;
ar & note;
ar & metadata;
ar & pos;
}
#endif // HAVE_BOOST_SERIALIZATION
};
value_t get_comment(item_t& item);

View file

@ -32,11 +32,34 @@
#include <system.hh>
#include "journal.h"
#include "amount.h"
#include "commodity.h"
#include "pool.h"
#include "xact.h"
#include "account.h"
namespace ledger {
journal_t::journal_t()
: master(new account_t), was_loaded(false),
commodity_pool(new commodity_pool_t)
{
TRACE_CTOR(journal_t, "");
// Add time commodity conversions, so that timelog's may be parsed
// in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool->create("s"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
else
assert(false);
// Add a "percentile" commodity
if (commodity_t * commodity = commodity_pool->create("%"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
else
assert(false);
}
journal_t::~journal_t()
{
TRACE_DTOR(journal_t);
@ -52,6 +75,9 @@ journal_t::~journal_t()
foreach (period_xact_t * xact, period_xacts)
checked_delete(xact);
checked_delete(master);
commodity_pool.reset();
}
void journal_t::add_account(account_t * acct)

View file

@ -48,11 +48,11 @@
#include "utils.h"
#include "hooks.h"
#include "times.h"
namespace ledger {
typedef std::list<path> paths_list;
class commodity_pool_t;
class xact_t;
class auto_xact_t;
class xact_finalizer_t;
@ -72,18 +72,60 @@ typedef std::list<period_xact_t *> period_xacts_list;
class journal_t : public noncopyable
{
public:
account_t * master;
account_t * basket;
xacts_list xacts;
struct fileinfo_t
{
optional<path> filename;
uintmax_t size;
datetime_t modtime;
bool from_stream;
auto_xacts_list auto_xacts;
period_xacts_list period_xacts;
fileinfo_t() : size(0), from_stream(true) {
TRACE_CTOR(journal_t::fileinfo_t, "");
}
fileinfo_t(const path& _filename)
: filename(_filename), from_stream(false) {
TRACE_CTOR(journal_t::fileinfo_t, "const path&");
size = file_size(*filename);
modtime = posix_time::from_time_t(last_write_time(*filename));
}
fileinfo_t(const fileinfo_t& info)
: filename(info.filename), size(info.size),
modtime(info.modtime), from_stream(info.from_stream)
{
TRACE_CTOR(journal_t::fileinfo_t, "copy");
}
~fileinfo_t() throw() {
TRACE_DTOR(journal_t::fileinfo_t);
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & filename;
ar & size;
ar & modtime;
ar & from_stream;
}
#endif // HAVE_BOOST_SERIALIZATION
};
account_t * master;
account_t * basket;
xacts_list xacts;
auto_xacts_list auto_xacts;
period_xacts_list period_xacts;
std::list<fileinfo_t> sources;
bool was_loaded;
shared_ptr<commodity_pool_t> commodity_pool;
hooks_t<xact_finalizer_t, xact_t> xact_finalize_hooks;
journal_t(account_t * _master = NULL) : master(_master) {
TRACE_CTOR(journal_t, "");
}
journal_t();
~journal_t();
// These four methods are delegated to the current session, since all
@ -110,6 +152,23 @@ public:
bool strict = false);
bool valid() const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & master;
ar & basket;
ar & xacts;
ar & auto_xacts;
ar & period_xacts;
ar & sources;
}
#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger

View file

@ -94,6 +94,25 @@ public:
}
return true;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
string temp;
if (Archive::is_loading::value) {
ar & temp;
*this = temp;
} else {
temp = expr.str();
ar & temp;
}
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline std::ostream& operator<<(std::ostream& out, const mask_t& mask) {

View file

@ -172,12 +172,12 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth)
left()->left() && left()->left()->is_function()) {
call_scope_t call_args(scope);
if (value_t obj = left()->left()->as_function()(call_args)) {
if (obj.is_pointer()) {
if (obj.as_pointer_lval<scope_t>() == NULL) {
if (obj.is_scope()) {
if (obj.as_scope() == NULL) {
throw_(calc_error,
_("Left operand of . operator is NULL"));
} else {
scope_t& objscope(obj.as_ref_lval<scope_t>());
scope_t& objscope(*obj.as_scope());
if (ptr_op_t member = objscope.lookup(right()->as_ident())) {
result = member->calc(objscope, NULL, depth + 1);
break;

View file

@ -192,6 +192,7 @@ public:
}
ptr_op_t& left() {
assert(kind > TERMINALS || kind == IDENT);
return left_;
}
const ptr_op_t& left() const {
@ -289,6 +290,33 @@ public:
static ptr_op_t wrap_value(const value_t& val);
static ptr_op_t wrap_functor(const function_t& fobj);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & refc;
ar & kind;
if (Archive::is_loading::value || ! left_ || left_->kind != FUNCTION) {
ar & left_;
} else {
ptr_op_t temp_op;
ar & temp_op;
}
if (Archive::is_loading::value || kind == VALUE || kind == IDENT ||
(kind > UNARY_OPERATORS &&
(! has_right() || ! right()->is_function()))) {
ar & data;
} else {
variant<ptr_op_t, value_t, string, function_t> temp_data;
ar & temp_data;
}
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline expr_t::ptr_op_t

View file

@ -203,7 +203,7 @@ void format_accounts::flush()
disp_pred.predicate.parse(report.HANDLER(display_).str());
}
mark_accounts(*report.session.master, report.HANDLED(flat));
mark_accounts(*report.session.journal->master, report.HANDLED(flat));
std::size_t displayed = 0;
@ -212,7 +212,7 @@ void format_accounts::flush()
if (displayed > 1 &&
! report.HANDLED(no_total) && ! report.HANDLED(percent)) {
bind_scope_t bound_scope(report, *report.session.master);
bind_scope_t bound_scope(report, *report.session.journal->master);
separator_format.format(out, bound_scope);
total_line_format.format(out, bound_scope);
}

View file

@ -134,6 +134,24 @@ public:
parse_price_expression(const std::string& str,
const bool add_prices = true,
const optional<datetime_t>& moment = none);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & commodities;
ar & null_commodity;
ar & default_commodity;
ar & keep_base;
ar & price_db;
ar & quote_leeway;
ar & get_quotes;
}
#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger

View file

@ -205,6 +205,23 @@ public:
}
friend class xact_t;
#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<item_t>(*this);
ar & xact;
ar & account;
ar & amount;
ar & cost;
ar & assigned_amount;
}
#endif // HAVE_BOOST_SERIALIZATION
};
} // namespace ledger

View file

@ -94,6 +94,19 @@ public:
throw;
}
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & predicate;
ar & what_to_keep;
}
#endif // HAVE_BOOST_SERIALIZATION
};
class query_lexer_t

View file

@ -45,8 +45,8 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(value_overloads, value, 0, 2)
namespace {
expr_t py_value_getattr(const value_t& value, const string& name)
{
if (value.is_pointer()) {
if (scope_t * scope = value.as_pointer<scope_t>())
if (value.is_scope()) {
if (scope_t * scope = value.as_scope())
return expr_t(scope->lookup(name), scope);
}
throw_(value_error, _("Cannot lookup attributes in %1") << value.label());
@ -283,7 +283,7 @@ void export_value()
.value("BALANCE", value_t::BALANCE)
.value("STRING", value_t::STRING)
.value("SEQUENCE", value_t::SEQUENCE)
.value("POINTER", value_t::POINTER)
.value("SCOPE", value_t::SCOPE)
;
scope().attr("NULL_VALUE") = NULL_VALUE;

View file

@ -87,11 +87,11 @@ void report_t::accounts_report(acct_handler_ptr handler)
scoped_ptr<accounts_iterator> iter;
if (! HANDLED(sort_)) {
iter.reset(new basic_accounts_iterator(*session.master));
iter.reset(new basic_accounts_iterator(*session.journal->master));
} else {
expr_t sort_expr(HANDLER(sort_).str());
sort_expr.set_context(this);
iter.reset(new sorted_accounts_iterator(*session.master.get(),
iter.reset(new sorted_accounts_iterator(*session.journal->master,
sort_expr, HANDLED(flat)));
}

View file

@ -67,6 +67,16 @@ public:
virtual void define(const string&, expr_t::ptr_op_t) {}
virtual expr_t::ptr_op_t lookup(const string& name) = 0;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &, const unsigned int /* version */) {}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -100,6 +110,19 @@ public:
return parent->lookup(name);
return 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<scope_t>(*this);
ar & parent;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -127,6 +150,19 @@ public:
virtual void define(const string& name, expr_t::ptr_op_t def);
virtual expr_t::ptr_op_t lookup(const string& 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 & symbols;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -138,8 +174,6 @@ class call_scope_t : public child_scope_t
{
value_t args;
call_scope_t();
public:
explicit call_scope_t(scope_t& _parent) : child_scope_t(_parent) {
TRACE_CTOR(call_scope_t, "scope_t&");
@ -182,6 +216,21 @@ public:
bool empty() const {
return args.size() == 0;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
explicit call_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 & args;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -215,6 +264,19 @@ public:
return def;
return child_scope_t::lookup(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
};
/**

View file

@ -32,13 +32,12 @@
#include <system.hh>
#include "session.h"
#include "commodity.h"
#include "pool.h"
#include "xact.h"
#include "account.h"
#include "journal.h"
#include "iterators.h"
#include "filters.h"
#include "archive.h"
namespace ledger {
@ -46,7 +45,7 @@ void set_session_context(session_t * session)
{
if (session) {
times_initialize();
amount_t::initialize(session->commodity_pool);
amount_t::initialize(session->journal->commodity_pool);
// jww (2009-02-04): Is amount_t the right place for parse_conversion to
// happen?
@ -64,12 +63,8 @@ void set_session_context(session_t * session)
session_t::session_t()
: flush_on_next_data_file(false),
current_year(CURRENT_DATE().year()),
commodity_pool(new commodity_pool_t),
master(new account_t),
journal(new journal_t(master.get()))
journal(new journal_t)
{
TRACE_CTOR(session_t, "");
@ -77,19 +72,6 @@ session_t::session_t()
HANDLER(price_db_).on(none, (path(home_var) / ".pricedb").string());
else
HANDLER(price_db_).on(none, path("./.pricedb").string());
// Add time commodity conversions, so that timelog's may be parsed
// in terms of seconds, but reported as minutes or hours.
if (commodity_t * commodity = commodity_pool->create("s"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
else
assert(false);
// Add a "percentile" commodity
if (commodity_t * commodity = commodity_pool->create("%"))
commodity->add_flags(COMMODITY_BUILTIN | COMMODITY_NOMARKET);
else
assert(false);
}
std::size_t session_t::read_journal(std::istream& in,
@ -123,6 +105,9 @@ std::size_t session_t::read_journal(const path& pathname,
std::size_t session_t::read_data(const string& master_account)
{
bool populated_data_files = false;
bool populated_price_db = false;
if (HANDLER(file_).data_files.empty()) {
path file;
if (const char * home_var = std::getenv("HOME"))
@ -132,6 +117,8 @@ std::size_t session_t::read_data(const string& master_account)
HANDLER(file_).data_files.push_back(file);
else
throw_(parse_error, "No journal file was specified (please use -f)");
populated_data_files = true;
}
std::size_t xact_count = 0;
@ -140,43 +127,75 @@ std::size_t session_t::read_data(const string& master_account)
if (! master_account.empty())
acct = journal->find_account(master_account);
if (HANDLED(price_db_)) {
path price_db_path = resolve_path(HANDLER(price_db_).str());
if (exists(price_db_path) && read_journal(price_db_path) > 0)
optional<path> price_db_path;
if (HANDLED(price_db_))
price_db_path = resolve_path(HANDLER(price_db_).str());
optional<archive_t> cache;
if (HANDLED(cache_) && master_account.empty()) {
cache = archive_t(HANDLED(cache_).str());
cache->read_header();
if (price_db_path) {
HANDLER(file_).data_files.push_back(*price_db_path);
populated_price_db = true;
}
}
if (! (cache &&
cache->should_load(HANDLER(file_).data_files) &&
cache->load(journal))) {
if (price_db_path) {
if (exists(*price_db_path) && read_journal(*price_db_path) > 0)
throw_(parse_error, _("Transactions not allowed in price history file"));
}
journal->sources.push_back(journal_t::fileinfo_t(*price_db_path));
HANDLER(file_).data_files.remove(*price_db_path);
}
foreach (const path& pathname, HANDLER(file_).data_files) {
path filename = resolve_path(pathname);
if (filename == "-") {
// 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;
foreach (const path& pathname, HANDLER(file_).data_files) {
path filename = resolve_path(pathname);
if (filename == "-") {
// 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);
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 += read_journal(buf_in, "/dev/stdin", acct);
journal->sources.push_back(journal_t::fileinfo_t());
}
buffer.flush();
else if (exists(filename)) {
xact_count += read_journal(filename, acct);
journal->sources.push_back(journal_t::fileinfo_t(filename));
}
else {
throw_(parse_error, _("Could not read journal file '%1'") << filename);
}
}
std::istringstream buf_in(buffer.str());
assert(xact_count == journal->xacts.size());
xact_count += read_journal(buf_in, "/dev/stdin", acct);
}
else if (exists(filename)) {
xact_count += read_journal(filename, acct);
}
else {
throw_(parse_error, _("Could not read journal file '%1'") << filename);
}
if (cache && cache->should_save(journal))
cache->save(journal);
}
if (populated_data_files)
HANDLER(file_).data_files.clear();
else if (populated_price_db)
HANDLER(file_).data_files.remove(*price_db_path);
VERIFY(journal->valid());
return xact_count;
return journal->xacts.size();
}
void session_t::read_journal_files()
@ -200,14 +219,10 @@ void session_t::read_journal_files()
void session_t::close_journal_files()
{
journal.reset();
master.reset();
commodity_pool.reset();
amount_t::shutdown();
commodity_pool.reset(new commodity_pool_t);
amount_t::initialize(commodity_pool);
master.reset(new account_t);
journal.reset(new journal_t(master.get()));
journal.reset(new journal_t);
amount_t::initialize(journal->commodity_pool);
}
void session_t::clean_posts()
@ -224,9 +239,9 @@ void session_t::clean_posts(xact_t& xact)
void session_t::clean_accounts()
{
basic_accounts_iterator acct_walker(*master);
basic_accounts_iterator acct_walker(*journal->master);
pass_down_accounts(acct_handler_ptr(new clear_account_xdata), acct_walker);
master->clear_xdata();
journal->master->clear_xdata();
}
option_t<session_t> * session_t::lookup_option(const char * p)
@ -241,6 +256,9 @@ option_t<session_t> * session_t::lookup_option(const char * p)
case 'a':
OPT_(account_); // -a
break;
case 'c':
OPT(cache_);
break;
case 'd':
OPT(download); // -Q
break;

View file

@ -66,12 +66,9 @@ 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;
shared_ptr<commodity_pool_t> commodity_pool;
scoped_ptr<account_t> master;
scoped_ptr<journal_t> journal;
bool flush_on_next_data_file;
date_t::year_type current_year;
shared_ptr<journal_t> journal;
explicit session_t();
virtual ~session_t() {
@ -106,6 +103,7 @@ public:
void report_options(std::ostream& out)
{
HANDLER(account_).report(out);
HANDLER(cache_).report(out);
HANDLER(download).report(out);
HANDLER(file_).report(out);
HANDLER(input_date_format_).report(out);
@ -123,6 +121,7 @@ public:
*/
OPTION(session_t, account_); // -a
OPTION(session_t, cache_);
OPTION(session_t, download); // -Q
OPTION__

View file

@ -46,7 +46,7 @@ value_t report_statistics(call_scope_t& args)
std::ostream& out(report.output_stream);
const account_t::xdata_t::details_t&
statistics(report.session.master->family_details(true));
statistics(report.session.journal->master->family_details(true));
if (! is_valid(statistics.earliest_post) &&
! is_valid(statistics.latest_post))

View file

@ -138,7 +138,6 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/any.hpp>
#include <boost/bind.hpp>
#include <boost/cast.hpp>
#include <boost/current_function.hpp>
@ -168,6 +167,74 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/variant.hpp>
#include <boost/version.hpp>
#if defined(HAVE_BOOST_SERIALIZATION)
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/optional.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/level.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/map.hpp>
#include <boost/date_time/posix_time/time_serialize.hpp>
#include <boost/date_time/gregorian/greg_serialize.hpp>
namespace boost {
namespace serialization {
template <class Archive>
void serialize(Archive& ar, boost::filesystem::path& p, const unsigned int)
{
std::string s;
if (Archive::is_saving::value)
s = p.string();
ar & s;
if (Archive::is_loading::value)
p = s;
}
template <class Archive, class T>
void serialize(Archive& ar, boost::intrusive_ptr<T>& ptr, const unsigned int)
{
if (Archive::is_saving::value) {
T * p = ptr.get();
ar & p;
}
else if (Archive::is_loading::value) {
T * p;
ar & p;
ptr.reset(p);
}
}
template <class Archive, class T>
void serialize(Archive&, boost::function<T>&, const unsigned int)
{
}
template <class Archive>
void serialize(Archive& ar, istream_pos_type& pos, const unsigned int)
{
ar & make_binary_object(&pos, sizeof(istream_pos_type));
}
} // namespace serialization
} // namespace boost
#endif // HAVE_BOOST_SERIALIZATION
#if defined(HAVE_BOOST_PYTHON)
#include <boost/python.hpp>

View file

@ -525,11 +525,12 @@ void instance_t::automated_xact_directive(char * line)
journal.auto_xacts.push_back(ae.get());
ae->pathname = pathname;
ae->beg_pos = pos;
ae->beg_line = lnum;
ae->end_pos = curr_pos;
ae->end_line = linenum;
ae->pos = position_t();
ae->pos->pathname = pathname;
ae->pos->beg_pos = pos;
ae->pos->beg_line = lnum;
ae->pos->end_pos = curr_pos;
ae->pos->end_line = linenum;
ae.release();
}
@ -565,11 +566,12 @@ void instance_t::period_xact_directive(char * line)
journal.period_xacts.push_back(pe.get());
pe->pathname = pathname;
pe->beg_pos = pos;
pe->beg_line = lnum;
pe->end_pos = curr_pos;
pe->end_line = linenum;
pe->pos = position_t();
pe->pos->pathname = pathname;
pe->pos->beg_pos = pos;
pe->pos->beg_line = lnum;
pe->pos->end_pos = curr_pos;
pe->pos->end_line = linenum;
pe.release();
} else {
@ -778,10 +780,11 @@ post_t * instance_t::parse_post(char * line,
std::auto_ptr<post_t> post(new post_t);
post->xact = xact; // this could be NULL
post->pathname = pathname;
post->beg_pos = line_beg_pos;
post->beg_line = linenum;
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;
char buf[MAX_LINE + 1];
std::strcpy(buf, line);
@ -1056,8 +1059,8 @@ post_t * instance_t::parse_post(char * line,
_("Unexpected char '%1' (Note: inline math requires parentheses)")
<< *next);
post->end_pos = curr_pos;
post->end_line = linenum;
post->pos->end_pos = curr_pos;
post->pos->end_line = linenum;
if (! tag_stack.empty()) {
foreach (const string& tag, tag_stack)
@ -1107,9 +1110,10 @@ xact_t * instance_t::parse_xact(char * line,
std::auto_ptr<xact_t> xact(new xact_t);
xact->pathname = pathname;
xact->beg_pos = line_beg_pos;
xact->beg_line = linenum;
xact->pos = position_t();
xact->pos->pathname = pathname;
xact->pos->beg_pos = line_beg_pos;
xact->pos->beg_line = linenum;
bool reveal_context = true;
@ -1189,8 +1193,8 @@ xact_t * instance_t::parse_xact(char * line,
// This is a trailing note, and possibly a metadata info tag
item->append_note(p + 1, current_year);
item->end_pos = curr_pos;
item->end_line++;
item->pos->end_pos = curr_pos;
item->pos->end_line++;
} else {
reveal_context = false;
@ -1216,8 +1220,8 @@ xact_t * instance_t::parse_xact(char * line,
}
}
xact->end_pos = curr_pos;
xact->end_line = linenum;
xact->pos->end_pos = curr_pos;
xact->pos->end_line = linenum;
if (! tag_stack.empty()) {
foreach (const string& tag, tag_stack)
@ -1232,8 +1236,8 @@ xact_t * instance_t::parse_xact(char * line,
catch (const std::exception& err) {
if (reveal_context) {
add_error_context(_("While parsing transaction:"));
add_error_context(source_context(xact->pathname,
xact->beg_pos, curr_pos, "> "));
add_error_context(source_context(xact->pos->pathname,
xact->pos->beg_pos, curr_pos, "> "));
}
throw;
}

View file

@ -314,50 +314,18 @@ date_t parse_date(const char * str, optional<date_t::year_type> current_year)
return parse_date_mask(str, current_year, saw_year);
}
date_t date_interval_t::add_duration(const date_t& date,
const duration_t& duration)
{
if (duration.type() == typeid(gregorian::days))
return date + boost::get<gregorian::days>(duration);
else if (duration.type() == typeid(gregorian::weeks))
return date + boost::get<gregorian::weeks>(duration);
else if (duration.type() == typeid(gregorian::months))
return date + boost::get<gregorian::months>(duration);
else
assert(duration.type() == typeid(gregorian::years));
return date + boost::get<gregorian::years>(duration);
}
date_t date_interval_t::subtract_duration(const date_t& date,
const duration_t& duration)
{
if (duration.type() == typeid(gregorian::days))
return date - boost::get<gregorian::days>(duration);
else if (duration.type() == typeid(gregorian::weeks))
return date - boost::get<gregorian::weeks>(duration);
else if (duration.type() == typeid(gregorian::months))
return date - boost::get<gregorian::months>(duration);
else
assert(duration.type() == typeid(gregorian::years));
return date - boost::get<gregorian::years>(duration);
}
std::ostream& operator<<(std::ostream& out,
const date_interval_t::duration_t& duration)
{
if (duration.type() == typeid(gregorian::days))
out << boost::get<gregorian::days>(duration).days()
<< " day(s)";
else if (duration.type() == typeid(gregorian::weeks))
out << (boost::get<gregorian::weeks>(duration).days() / 7)
<< " week(s)";
else if (duration.type() == typeid(gregorian::months))
out << boost::get<gregorian::months>(duration).number_of_months()
<< " month(s)";
if (duration.quantum == date_interval_t::duration_t::DAYS)
out << duration.length << " day(s)";
else if (duration.quantum == date_interval_t::duration_t::WEEKS)
out << duration.length << " week(s)";
else if (duration.quantum == date_interval_t::duration_t::MONTHS)
out << duration.length << " month(s)";
else {
assert(duration.type() == typeid(gregorian::years));
out << boost::get<gregorian::years>(duration).number_of_years()
<< " year(s)";
assert(duration.quantum == date_interval_t::duration_t::YEARS);
out << duration.length << " year(s)";
}
return out;
}
@ -365,7 +333,7 @@ std::ostream& operator<<(std::ostream& out,
void date_interval_t::resolve_end()
{
if (start && ! end_of_duration) {
end_of_duration = add_duration(*start, *duration);
end_of_duration = duration->add(*start);
DEBUG("times.interval",
"stabilize: end_of_duration = " << *end_of_duration);
}
@ -383,7 +351,7 @@ void date_interval_t::resolve_end()
}
if (start && ! next) {
next = add_duration(*start, *skip_duration);
next = skip_duration->add(*start);
DEBUG("times.interval",
"stabilize: next set to: " << *next);
}
@ -423,8 +391,8 @@ void date_interval_t::stabilize(const optional<date_t>& date)
date_t when = start ? *start : *date;
if (duration->type() == typeid(gregorian::months) ||
duration->type() == typeid(gregorian::years)) {
if (duration->quantum == duration_t::MONTHS ||
duration->quantum == duration_t::YEARS) {
DEBUG("times.interval", "stabilize: monthly or yearly duration");
start = date_t(when.year(), gregorian::Jan, 1);
@ -433,7 +401,7 @@ void date_interval_t::stabilize(const optional<date_t>& date)
start = date_t(when - gregorian::days(400));
if (duration->type() == typeid(gregorian::weeks)) {
if (duration->quantum == duration_t::WEEKS) {
// Move it to a Sunday
while (start->day_of_week() != start_of_week)
*start += gregorian::days(1);
@ -540,8 +508,8 @@ bool date_interval_t::find_period(const date_t& date)
return true;
}
scan = add_duration(scan, *skip_duration);
end_of_scan = add_duration(scan, *duration);
scan = skip_duration->add(scan);
end_of_scan = duration->add(scan);
}
return false;
@ -565,7 +533,7 @@ date_interval_t& date_interval_t::operator++()
} else {
start = *next;
end_of_duration = add_duration(*start, *duration);
end_of_duration = duration->add(*start);
}
next = none;
@ -634,15 +602,15 @@ namespace {
assert(look_for_start || look_for_end);
if (word == _("year")) {
duration = gregorian::years(1);
duration = date_interval_t::duration_t(date_interval_t::duration_t::YEARS, 1);
start = gregorian::date(start.year(), 1, 1);
}
else if (word == _("month")) {
duration = gregorian::months(1);
duration = date_interval_t::duration_t(date_interval_t::duration_t::MONTHS, 1);
start = gregorian::date(start.year(), start.month(), 1);
}
else if (word == _("today") || word == _("day")) {
duration = gregorian::days(1);
duration = date_interval_t::duration_t(date_interval_t::duration_t::DAYS, 1);
}
else {
parse_specifier = true;
@ -651,15 +619,15 @@ namespace {
if (parse_specifier)
parse_inclusion_specifier(word, &start, &end);
else
end = date_interval_t::add_duration(start, *duration);
end = duration->add(start);
if (type == _("last") && duration) {
start = date_interval_t::subtract_duration(start, *duration);
end = date_interval_t::subtract_duration(end, *duration);
start = duration->subtract(start);
end = duration->subtract(end);
}
else if (type == _("next") && duration) {
start = date_interval_t::add_duration(start, *duration);
end = date_interval_t::add_duration(end, *duration);
start = duration->add(start);
end = duration->add(end);
}
if (look_for_start && is_valid(start)) interval.start = start;
@ -683,41 +651,41 @@ void date_interval_t::parse(std::istream& in)
int quantity = lexical_cast<int>(word);
read_lower_word(in, word);
if (word == _("days"))
duration = gregorian::days(quantity);
duration = duration_t(duration_t::DAYS, quantity);
else if (word == _("weeks"))
duration = gregorian::weeks(quantity);
duration = duration_t(duration_t::WEEKS, quantity);
else if (word == _("months"))
duration = gregorian::months(quantity);
duration = duration_t(duration_t::MONTHS, quantity);
else if (word == _("quarters"))
duration = gregorian::months(3 * quantity);
duration = duration_t(duration_t::MONTHS, 3 * quantity);
else if (word == _("years"))
duration = gregorian::years(quantity);
duration = duration_t(duration_t::YEARS, quantity);
}
else if (word == _("day"))
duration = gregorian::days(1);
duration = duration_t(duration_t::DAYS, 1);
else if (word == _("week"))
duration = gregorian::weeks(1);
duration = duration_t(duration_t::WEEKS, 1);
else if (word == _("month"))
duration = gregorian::months(1);
duration = duration_t(duration_t::MONTHS, 1);
else if (word == _("quarter"))
duration = gregorian::months(3);
duration = duration_t(duration_t::MONTHS, 3);
else if (word == _("year"))
duration = gregorian::years(1);
duration = duration_t(duration_t::YEARS, 1);
}
else if (word == _("daily"))
duration = gregorian::days(1);
duration = duration_t(duration_t::DAYS, 1);
else if (word == _("weekly"))
duration = gregorian::weeks(1);
duration = duration_t(duration_t::WEEKS, 1);
else if (word == _("biweekly"))
duration = gregorian::weeks(2);
duration = duration_t(duration_t::WEEKS, 2);
else if (word == _("monthly"))
duration = gregorian::months(1);
duration = duration_t(duration_t::MONTHS, 1);
else if (word == _("bimonthly"))
duration = gregorian::months(2);
duration = duration_t(duration_t::MONTHS, 2);
else if (word == _("quarterly"))
duration = gregorian::months(3);
duration = duration_t(duration_t::MONTHS, 3);
else if (word == _("yearly"))
duration = gregorian::years(1);
duration = duration_t(duration_t::YEARS, 1);
else if (word == _("this") || word == _("last") || word == _("next") ||
word == _("today")) {
parse_date_words(in, word, *this);
@ -760,17 +728,17 @@ void date_interval_t::parse(std::istream& in)
if (wday) {
while (start->day_of_week() != *wday)
*start -= gregorian::days(1);
*start = duration_t(duration_t::DAYS, 1).subtract(*start);
if (! end)
end = *start + gregorian::days(1);
end = duration_t(duration_t::DAYS, 1).add(*start);
} else {
bool overwrite_end = false;
if (year) {
start = date_t(*year, 1, 1);
if (! end) {
end = *start + gregorian::years(1);
end = duration_t(duration_t::YEARS, 1).add(*start);
overwrite_end = true;
}
}
@ -778,7 +746,7 @@ void date_interval_t::parse(std::istream& in)
if (mon) {
start = date_t(start->year(), *mon, 1);
if (! end || overwrite_end)
end = *start + gregorian::months(1);
end = duration_t(duration_t::MONTHS, 1).add(*start);
}
}
}

View file

@ -119,10 +119,71 @@ void set_input_date_format(const char * format);
class date_interval_t : public equality_comparable<date_interval_t>
{
public:
typedef variant<gregorian::days,
gregorian::weeks,
gregorian::months,
gregorian::years> duration_t;
struct duration_t
{
enum skip_quantum_t {
DAYS, WEEKS, MONTHS, YEARS
} quantum;
int length;
duration_t() : quantum(DAYS), length(0) {
TRACE_CTOR(date_interval_t::duration_t, "");
}
duration_t(skip_quantum_t _quantum, int _length)
: quantum(_quantum), length(_length) {
TRACE_CTOR(date_interval_t::duration_t, "skip_quantum_t, int");
}
duration_t(const duration_t& dur)
: quantum(dur.quantum), length(dur.length) {
TRACE_CTOR(date_interval_t::duration_t, "copy");
}
~duration_t() throw() {
TRACE_DTOR(date_interval_t::duration_t);
}
date_t add(const date_t& date) const {
switch (quantum) {
case DAYS:
return date + gregorian::days(length);
case WEEKS:
return date + gregorian::weeks(length);
case MONTHS:
return date + gregorian::months(length);
case YEARS:
return date + gregorian::years(length);
default:
assert(0); return date_t();
}
}
date_t subtract(const date_t& date) const {
switch (quantum) {
case DAYS:
return date - gregorian::days(length);
case WEEKS:
return date - gregorian::weeks(length);
case MONTHS:
return date - gregorian::months(length);
case YEARS:
return date - gregorian::years(length);
default:
assert(0); return date_t();
}
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & quantum;
ar & length;
}
#endif // HAVE_BOOST_SERIALIZATION
};
static date_t add_duration(const date_t& date,
const duration_t& duration);
@ -196,6 +257,25 @@ public:
}
date_interval_t& operator++();
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & start;
ar & aligned;
ar & skip_duration;
ar & factor;
ar & next;
ar & duration;
ar & end_of_duration;
ar & end;
}
#endif // HAVE_BOOST_SERIALIZATION
};
void times_initialize();

View file

@ -178,6 +178,18 @@ public:
string(const char * str, size_type x);
string(const char * str, size_type x, size_type y);
~string() throw();
#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<std::string>(*this);
}
#endif // HAVE_BOOST_SERIALIZATION
};
inline string operator+(const string& __lhs, const string& __rhs)

View file

@ -113,8 +113,8 @@ value_t::operator bool() const
}
}
return false;
case POINTER:
return ! as_any_pointer().empty();
case SCOPE:
return as_scope() != NULL;
default:
break;
}
@ -1206,8 +1206,8 @@ bool value_t::is_realzero() const
case SEQUENCE:
return as_sequence().empty();
case POINTER:
return as_any_pointer().empty();
case SCOPE:
return as_scope() == NULL;
default:
throw_(value_error, _("Cannot determine if %1 is really zero") << label());
@ -1235,8 +1235,8 @@ bool value_t::is_zero() const
case SEQUENCE:
return as_sequence().empty();
case POINTER:
return as_any_pointer().empty();
case SCOPE:
return as_scope() == NULL;
default:
throw_(value_error, _("Cannot determine if %1 is zero") << label());
@ -1474,7 +1474,7 @@ value_t value_t::strip_annotations(const keep_details_t& what_to_keep) const
case DATE:
case STRING:
case MASK:
case POINTER:
case SCOPE:
return *this;
case SEQUENCE: {
@ -1579,8 +1579,8 @@ void value_t::print(std::ostream& out,
break;
}
case POINTER:
out << "<POINTER>";
case SCOPE:
out << "<SCOPE>";
break;
default:
@ -1647,8 +1647,8 @@ void value_t::dump(std::ostream& out, const bool relaxed) const
out << '/' << as_mask() << '/';
break;
case POINTER:
out << boost::unsafe_any_cast<const void *>(&as_any_pointer());
case SCOPE:
out << as_scope();
break;
case SEQUENCE: {

View file

@ -56,6 +56,8 @@ namespace ledger {
DECLARE_EXCEPTION(value_error, std::runtime_error);
class scope_t;
/**
* @class value_t
*
@ -107,7 +109,7 @@ public:
STRING, // a string object
MASK, // a regular expression mask
SEQUENCE, // a vector of value_t objects
POINTER // an opaque pointer of any type
SCOPE // a pointer to a scope
};
private:
@ -134,7 +136,7 @@ private:
string, // STRING
mask_t, // MASK
sequence_t *, // SEQUENCE
boost::any // POINTER
scope_t * // SCOPE
> data;
type_t type;
@ -225,6 +227,20 @@ private:
data = false;
type = VOID;
}
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & data;
ar & type;
ar & refc;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -332,10 +348,9 @@ public:
set_sequence(val);
}
template <typename T>
explicit value_t(T * item) {
TRACE_CTOR(value_t, "T *");
set_pointer(item);
explicit value_t(scope_t * item) {
TRACE_CTOR(value_t, "scope_t *");
set_scope(item);
}
/**
@ -687,50 +702,19 @@ public:
}
/**
* Dealing with pointers is bit involved because we actually deal
* with typed pointers. For example, if you call as_pointer it
* returns a boost::any object, but if you use as_pointer<void>,
* then it returns a void *. The latter form only succeeds if the
* stored pointers was assigned to the value as a void*, otherwise
* it throws an exception.
* Dealing with scope pointers.
*/
bool is_pointer() const {
return is_type(POINTER);
bool is_scope() const {
return is_type(SCOPE);
}
boost::any& as_any_pointer_lval() {
VERIFY(is_pointer());
_dup();
return boost::get<boost::any>(storage->data);
scope_t * as_scope() const {
VERIFY(is_scope());
return boost::get<scope_t *>(storage->data);
}
template <typename T>
T * as_pointer_lval() {
return any_cast<T *>(as_any_pointer_lval());
}
template <typename T>
T& as_ref_lval() {
return *as_pointer_lval<T>();
}
const boost::any& as_any_pointer() const {
VERIFY(is_pointer());
return boost::get<boost::any>(storage->data);
}
template <typename T>
T * as_pointer() const {
return any_cast<T *>(as_any_pointer());
}
template <typename T>
T& as_ref() const {
return *as_pointer<T>();
}
void set_any_pointer(const boost::any& val) {
set_type(POINTER);
void set_scope(scope_t * val) {
set_type(SCOPE);
storage->data = val;
}
template <typename T>
void set_pointer(T * val) {
set_type(POINTER);
storage->data = boost::any(val);
}
/**
* Data conversion methods. These methods convert a value object to
@ -902,8 +886,8 @@ public:
return _("a regexp");
case SEQUENCE:
return _("a sequence");
case POINTER:
return _("a pointer");
case SCOPE:
return _("a scope");
default:
assert(false);
break;
@ -926,6 +910,20 @@ public:
* Debugging methods.
*/
bool valid() const;
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & true_value;
ar & false_value;
ar & storage;
}
#endif // HAVE_BOOST_SERIALIZATION
};
#define NULL_VALUE (value_t())

View file

@ -499,7 +499,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler)
IF_DEBUG("xact.extend") {
DEBUG("xact.extend",
"Initial post on line " << initial_post->beg_line << ": "
"Initial post on line " << initial_post->pos->beg_line << ": "
<< "amount " << initial_post->amount << " (precision "
<< initial_post->amount.precision() << ")");
@ -509,7 +509,7 @@ void auto_xact_t::extend_xact(xact_base_t& xact, bool post_handler)
#endif
DEBUG("xact.extend",
"Posting on line " << post->beg_line << ": "
"Posting on line " << post->pos->beg_line << ": "
<< "amount " << post->amount << ", amt " << amt
<< " (precision " << post->amount.precision()
<< " != " << amt.precision() << ")");

View file

@ -80,6 +80,20 @@ public:
virtual bool finalize();
virtual bool valid() const = 0;
#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<item_t>(*this);
ar & journal;
ar & posts;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -111,6 +125,20 @@ public:
virtual expr_t::ptr_op_t lookup(const string& name);
virtual bool valid() const;
#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<xact_base_t>(*this);
ar & code;
ar & payee;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -154,6 +182,19 @@ public:
virtual bool valid() const {
return true;
}
#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<xact_base_t>(*this);
ar & predicate;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -180,6 +221,18 @@ struct auto_xact_finalizer_t : public xact_finalizer_t
}
virtual bool operator()(xact_t& xact, bool post);
#if defined(HAVE_BOOST_SERIALIZATION)
private:
/** Serialization. */
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int /* version */) {
ar & journal;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**
@ -205,7 +258,7 @@ class period_xact_t : public xact_base_t
TRACE_CTOR(period_xact_t, "const string&");
}
virtual ~period_xact_t() throw() {
virtual ~period_xact_t() {
TRACE_DTOR(period_xact_t);
}
@ -218,6 +271,20 @@ class period_xact_t : public xact_base_t
#endif
return true;
}
#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<xact_base_t>(*this);
ar & period;
ar & period_string;
}
#endif // HAVE_BOOST_SERIALIZATION
};
/**

520
tools/Makefile.am Normal file
View file

@ -0,0 +1,520 @@
VERSION = 3.0
ACLOCAL_AMFLAGS = -I m4
dist_man_MANS = doc/ledger.1
SUBDIRS = po intl
EXTRA_DIST = autogen.sh config.rpath contrib src/system.hh.in
DISTCLEANFILES = .timestamp
lib_LTLIBRARIES = \
libledger_report.la \
libledger_data.la \
libledger_expr.la \
libledger_math.la \
libledger_util.la
lib_cppflags = -I$(srcdir)/src -I$(srcdir)/lib \
-I$(srcdir)/lib/utfcpp/source
libledger_util_la_SOURCES = \
src/stream.cc \
src/mask.cc \
src/times.cc \
src/error.cc \
src/utils.cc \
src/accum.cc \
lib/sha1.cpp
libledger_util_la_CPPFLAGS = $(lib_cppflags)
libledger_util_la_LDFLAGS = -release $(VERSION).0
libledger_math_la_SOURCES = \
src/value.cc \
src/balance.cc \
src/quotes.cc \
src/pool.cc \
src/annotate.cc \
src/commodity.cc \
src/amount.cc
libledger_math_la_CPPFLAGS = $(lib_cppflags)
libledger_math_la_LDFLAGS = -release $(VERSION).0
libledger_expr_la_SOURCES = \
src/option.cc \
src/format.cc \
src/predicate.cc \
src/scope.cc \
src/interactive.cc \
src/expr.cc \
src/op.cc \
src/parser.cc \
src/token.cc
libledger_expr_la_CPPFLAGS = $(lib_cppflags)
libledger_expr_la_LDFLAGS = -release $(VERSION).0
libledger_data_la_SOURCES = \
src/compare.cc \
src/iterators.cc \
src/timelog.cc \
src/textual.cc \
src/journal.cc \
src/archive.cc \
src/account.cc \
src/xact.cc \
src/post.cc \
src/item.cc
libledger_data_la_CPPFLAGS = $(lib_cppflags)
libledger_data_la_LDFLAGS = -release $(VERSION).0
libledger_report_la_SOURCES = \
src/stats.cc \
src/generate.cc \
src/derive.cc \
src/emacs.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).0
pkginclude_HEADERS = \
src/utils.h \
src/flags.h \
src/hooks.h \
src/error.h \
src/times.h \
src/mask.h \
src/stream.h \
src/pstream.h \
src/unistring.h \
src/accum.h \
\
src/amount.h \
src/commodity.h \
src/annotate.h \
src/pool.h \
src/quotes.h \
src/balance.h \
src/value.h \
\
src/token.h \
src/parser.h \
src/op.h \
src/expr.h \
src/scope.h \
src/interactive.h \
src/predicate.h \
src/format.h \
src/option.h \
\
src/item.h \
src/post.h \
src/xact.h \
src/account.h \
src/journal.h \
src/archive.h \
src/timelog.h \
src/iterators.h \
src/compare.h \
\
src/session.h \
src/report.h \
src/filters.h \
src/temps.h \
src/chain.h \
src/precmd.h \
src/derive.h \
src/generate.h \
src/stats.h \
src/output.h \
src/emacs.h \
\
src/global.h \
\
src/pyinterp.h \
\
lib/sha1.h \
lib/gettext.h \
\
lib/utfcpp/source/utf8.h \
lib/utfcpp/source/utf8/checked.h \
lib/utfcpp/source/utf8/core.h \
lib/utfcpp/source/utf8/unchecked.h
nodist_libledger_util_la_SOURCES = system.hh
BUILT_SOURCES = system.hh
CLEANFILES = system.hh
system.hh: src/system.hh.in
cp -p $< $@
if USE_PCH
nodist_libledger_util_la_SOURCES += system.hh.gch
BUILT_SOURCES += system.hh.gch
CLEANFILES += system.hh.gch
system.hh.gch: system.hh
$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(lib_cppflags) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) \
-o $@ $<
endif
######################################################################
bin_PROGRAMS = ledger
ledger_CPPFLAGS = $(lib_cppflags)
if HAVE_BOOST_PYTHON
ledger_CPPFLAGS += -I$(srcdir)/python
endif
ledger_SOURCES = src/main.cc src/global.cc
ledger_LDADD = $(LIBOBJS) $(lib_LTLIBRARIES) $(INTLLIBS)
ledger_LDFLAGS = -static
info_TEXINFOS = doc/ledger.texi
dist_lisp_LISP = lisp/ledger.el lisp/timeclock.el
ELCFILES =
DISTCLEANFILES += ledger.elc timeclock.elc
all_sources = $(libledger_util_la_SOURCES) \
$(libledger_math_la_SOURCES) \
$(libledger_expr_la_SOURCES) \
$(libledger_data_la_SOURCES) \
$(libledger_report_la_SOURCES) \
$(libledger_python_la_SOURCES) \
src/pyledger.cc
all_files = $(all_sources) $(pkginclude_HEADERS)
######################################################################
if HAVE_BOOST_PYTHON
lib_LTLIBRARIES += libledger_python.la
libledger_python_la_SOURCES = \
src/pyutils.h \
src/pyfstream.h \
src/py_amount.cc \
src/py_balance.cc \
src/py_chain.cc \
src/py_commodity.cc \
src/py_expr.cc \
src/py_flags.cc \
src/py_format.cc \
src/py_global.cc \
src/py_item.cc \
src/py_journal.cc \
src/py_post.cc \
src/py_report.cc \
src/py_scope.cc \
src/py_session.cc \
src/py_timelog.cc \
src/py_times.cc \
src/py_utils.cc \
src/py_value.cc \
src/py_xact.cc \
src/pyinterp.cc
libledger_python_la_CPPFLAGS = $(lib_cppflags) -I$(srcdir)/python
pyexec_LTLIBRARIES = ledger.la
ledger_la_CPPFLAGS = $(libledger_python_la_CPPFLAGS)
ledger_la_SOURCES = src/pyledger.cc
ledger_la_DEPENDENCIES = $(lib_LTLIBRARIES)
ledger_la_LDFLAGS = -avoid-version -module
ledger_la_LIBADD = $(LIBOBJS) $(lib_LTLIBRARIES) $(INTLLIBS)
pkgpython_PYTHON = python/__init__.py \
python/hello.py \
python/server.py
endif
######################################################################
TESTS =
if HAVE_PYTHON
TESTS += RegressTests BaselineTests ConfirmTests GenerateTests
endif
if HAVE_CPPUNIT
TESTS += \
UtilTests \
MathTests \
ExprTests \
DataTests \
ReportTests
endif
if HAVE_BOOST_PYTHON
TESTS += PyUnitTests
endif
check_PROGRAMS = $(TESTS)
UtilTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/UtilTests.cc \
test/unit/t_utils.cc \
test/unit/t_utils.h \
test/unit/t_times.cc \
test/unit/t_times.h
UtilTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
UtilTests_LDADD = libledger_util.la -lcppunit
MathTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/MathTests.cc \
test/unit/t_commodity.cc \
test/unit/t_commodity.h \
test/unit/t_amount.cc \
test/unit/t_amount.h \
test/unit/t_balance.cc \
test/unit/t_balance.h
MathTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
MathTests_LDADD = libledger_math.la $(UtilTests_LDADD)
ExprTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/ExprTests.cc \
test/unit/t_expr.cc \
test/unit/t_expr.h
ExprTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
ExprTests_LDADD = libledger_expr.la $(MathTests_LDADD)
DataTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/DataTests.cc
DataTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
DataTests_LDADD = libledger_data.la $(ExprTests_LDADD)
ReportTests_SOURCES = \
test/UnitTests.cc \
test/UnitTests.h \
test/ReportTests.cc
ReportTests_CPPFLAGS = -I$(srcdir)/test $(lib_cppflags)
ReportTests_LDADD = libledger_report.la $(DataTests_LDADD)
all_tests_sources = \
$(UtilTests_SOURCES) \
$(MathTests_SOURCES) \
$(ExprTests_SOURCES) \
$(DataTests_SOURCES) \
$(ReportTests_SOURCES)
PyUnitTests_SOURCES = test/PyUnitTests.py
all_py_tests_sources = \
$(patsubst test/unit/%.cc,$(top_builddir)/test/python/%.py, \
$(filter test/unit/t_%.cc,$(all_tests_sources)))
test/python/%.py: test/unit/%.cc test/convert.py
$(PYTHON) $(srcdir)/test/convert.py $< $@
test/python/UnitTests.py: $(all_py_tests_sources)
@echo "from unittest import TextTestRunner, TestSuite" > $@
@for file in $$(ls $(srcdir)/test/unit/*.cc); do \
base=$$(basename $$file); \
base=$$(echo $$base | sed 's/\.cc//'); \
echo "import $$base" >> $@; \
done
@echo "suites = [" >> $@
@for file in $$(ls $(srcdir)/test/unit/*.cc); do \
base=$$(basename $$file); \
base=$$(echo $$base | sed 's/\.cc//'); \
echo " $$base.suite()," >> $@; \
done
@echo "]" >> $@
@echo "TextTestRunner().run(TestSuite(suites))" >> $@
ledger_python = $(top_builddir)/ledger$(EXEEXT) python
ESC_python=`echo "$(ledger_python)" | sed 's/\//\\\\\//g'`
ESC_srcdir=`echo "$(srcdir)" | sed 's/\//\\\\\//g'`
ESC_builddir=`echo "$(top_builddir)" | sed 's/\//\\\\\//g'`
ESC_distdir=`echo "$(distdir)" | sed 's/\//\\\\\//g'`
# jww (2007-05-10): This rule will not be triggered on systems that
# define an EXEEXT.
PyUnitTests: test/PyUnitTests.py test/python/UnitTests.py
@cat $(srcdir)/test/PyUnitTests.py \
| sed "s/%python%/$(ESC_python)/" \
| sed "s/%srcdir%/$(ESC_srcdir)/g" \
| sed "s/%builddir%/$(ESC_builddir)/g" > $@
chmod 755 $@
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)/test/regress \"\$$@\"" > $@
chmod 755 $@
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)/test/baseline \"\$$@\"" > $@
chmod 755 $@
ConfirmTests_SOURCES = test/ConfirmTests.py
EXTRA_DIST += test/input
test/input/mondo.dat: test/input/standard.dat
@for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do \
for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do \
cat $< >> $@; \
done; \
done
ConfirmTests: $(srcdir)/test/ConfirmTests.py
echo "$(PYTHON) $(srcdir)/test/ConfirmTests.py $(top_builddir)/ledger$(EXEEXT) $(srcdir)/test/input \"\$$@\"" > $@
chmod 755 $@
GenerateTests_SOURCES = test/GenerateTests.py
GenerateTests: $(srcdir)/test/GenerateTests.py
echo "$(PYTHON) $(srcdir)/test/GenerateTests.py $(top_builddir)/ledger$(EXEEXT) 1 20 \"\$$@\"" > $@
chmod 755 $@
FULLCHECK=$(srcdir)/test/fullcheck.sh
if HAVE_CPPUNIT
cppunittests: check
@sh $(FULLCHECK) $(top_builddir)/UtilTests$(EXEEXT) --verify \
2>&1 | grep -v '^GuardMalloc:'
@sh $(FULLCHECK) $(top_builddir)/MathTests$(EXEEXT) --verify \
2>&1 | grep -v '^GuardMalloc:'
@sh $(FULLCHECK) $(top_builddir)/ExprTests$(EXEEXT) --verify \
2>&1 | grep -v '^GuardMalloc:'
@sh $(FULLCHECK) $(top_builddir)/DataTests$(EXEEXT) --verify \
2>&1 | grep -v '^GuardMalloc:'
@sh $(FULLCHECK) $(top_builddir)/ReportTests$(EXEEXT) --verify \
2>&1 | grep -v '^GuardMalloc:'
else
cppunittests: check
@test 1 -eq 1
endif
fullcheck: cppunittests
@$(top_builddir)/RegressTests --verify
@$(top_builddir)/BaselineTests --verify
@$(top_builddir)/ConfirmTests --verify
@$(top_builddir)/GenerateTests --verify
@$(top_builddir)/RegressTests --gmalloc
@$(top_builddir)/BaselineTests --gmalloc
# @$(top_builddir)/ConfirmTests --gmalloc
# @$(top_builddir)/GenerateTests --gmalloc
######################################################################
EXTRA_DIST += doc/README doc/LICENSE doc/NEWS doc/ledger.pdf
if USE_DOXYGEN
EXTRA_DIST += doc/Doxyfile doc/refman.pdf
endif
DISTCLEANFILES += doc/ledger.info doc/ledger.pdf
if USE_DOXYGEN
DISTCLEANFILES += Doxyfile.gen doc/Doxyfile.bak doc/refman.pdf
endif
if USE_DOXYGEN
dist-hook-doxygen:
find $(distdir)/doc -name .dirstamp -delete
rm -fr $(distdir)/doc/latex \
$(distdir)/doc/Doxyfile.bak \
$(distdir)/doc/Doxyfile.gen
cp -pR doc/html $(distdir)/doc
else
dist-hook-doxygen:
@test 1 -eq 1
endif
dist-hook: dist-hook-doxygen
find $(distdir) -name .DS_Store -delete
find $(distdir) -name .localized -delete
rm -f $(distdir)/README.textile
cp -p $(srcdir)/doc/README $(distdir)/README
if USE_DOXYGEN
distclean-local-doxygen:
rm -fr doc/html doc/latex
rm -f doc/refman.pdf
else
distclean-local-doxygen:
@test 1 -eq 1
endif
distclean-local: distclean-local-doxygen
rm -fr test/python
if USE_DOXYGEN
ESC_top_builddir=`cd $(top_builddir); pwd | sed 's/\//\\\\\//g'`
Doxyfile.gen: doc/Doxyfile
cat $< | sed "s/%srcdir%/$(ESC_srcdir)/g" \
| sed "s/%builddir%/$(ESC_top_builddir)/g" > $@
doc/html/index.html: Doxyfile.gen $(all_files)
BUILD_DIR=`cd $(top_builddir); pwd`; \
(cd $(srcdir); doxygen $$BUILD_DIR/Doxyfile.gen)
# The intention with the following rules is that all of the Doxygen
# documentation (both HTML and PDF) is built locally before distcheck is
# run, since it's quite possible that the user will not have a complete
# TeX + Doxygen + dot environment on their own system.
doc/refman.pdf: doc/html/index.html
(cd doc/latex && make)
cp doc/latex/refman.pdf $@
docs: pdf doc/refman.pdf
else
docs: pdf
endif
libs:
@echo Building dependency libs and installing in /usr/local/stow ...
git submodule update --init
(cd lib; make)
report: all
-rm -fr build
lcov -d $(shell pwd) --zerocounters
-mkdir doc/report
lcov -c -i -d $(shell pwd) -o doc/report/ledger_base.info
make fullcheck
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/*' \
-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
# Makefile.am ends here

1491
tools/autogen.sh Executable file

File diff suppressed because it is too large Load diff

391
tools/configure.ac Normal file
View file

@ -0,0 +1,391 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.61)
m4_include([version.m4])
AC_INIT([ledger],[VERSION_NUMBER],[johnw@newartisans.com])
AC_CONFIG_AUX_DIR([.])
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/main.cc])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CXX
AC_PROG_MAKE_SET
AC_PROG_LIBTOOL
AM_GNU_GETTEXT
AM_GNU_GETTEXT_VERSION([0.17])
# Checks for emacs lisp path
AM_PATH_LISPDIR
# Check for options
AC_ARG_ENABLE(debug,
[ --enable-debug Turn on debugging],
[case "${enableval}" in
yes) debug=true ;;
no) debug=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-debug) ;;
esac],[debug=false])
if [ test x$debug = xtrue ]; then
AC_DEFINE([DEBUG_MODE], [1], [Whether debugging is enabled])
fi
AM_CONDITIONAL(DEBUG, test x$debug = xtrue)
AC_ARG_ENABLE(pch,
[ --enable-pch Use GCC 4.x pre-compiled headers],
[case "${enableval}" in
yes) pch=true ;;
no) pch=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-pch) ;;
esac],[pch=false])
if [ test x$pch = xtrue ]; then
AC_DEFINE([USE_PCH], [1], [Whether pre-compiled headers are being used])
fi
AM_CONDITIONAL(USE_PCH, test x$pch = xtrue)
AC_ARG_ENABLE(doxygen,
[ --enable-doxygen Turns on generation of code documentation],
[case "${enableval}" in
yes) doxygen=true ;;
no) doxygen=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-doxygen) ;;
esac],[doxygen=false])
AM_CONDITIONAL(USE_DOXYGEN, test x$doxygen = xtrue)
AC_ARG_WITH(boost-suffix,
[ --with-boost-suffix=X Append X to the Boost library names],
[BOOST_SUFFIX="${withval}"],
[BOOST_SUFFIX=""])
AC_SUBST([BOOST_SUFFIX], $BOOST_SUFFIX)
# check if UNIX pipes are available
AC_CACHE_CHECK(
[if pipes can be used],
[pipes_avail_cv_],
[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]);
}]])],
[pipes_avail_cv_=true],
[pipes_avail_cv_=false])
AC_LANG_POP])
if [test x$pipes_avail_cv_ = xtrue ]; then
AC_DEFINE([HAVE_UNIX_PIPES], [1], [Whether UNIX pipes are available])
fi
# check for gmp
AC_CACHE_CHECK(
[if GMP is available],
[libgmp_avail_cv_],
[libgmp_save_libs=$LIBS
LIBS="-lgmp $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <gmp.h>]], [[mpz_t bar;
mpz_init(bar);
mpz_clear(bar);]])],[libgmp_avail_cv_=true],[libgmp_avail_cv_=false])
AC_LANG_POP
LIBS=$libgmp_save_libs])
if [test x$libgmp_avail_cv_ = xtrue ]; then
LIBS="-lgmp $LIBS"
else
AC_MSG_FAILURE("Could not find gmp library (set CPPFLAGS and LDFLAGS?)")
fi
# check for mpfr
AC_CACHE_CHECK(
[if MPFR is available],
[libmpfr_avail_cv_],
[libmpfr_save_libs=$LIBS
LIBS="-lmpfr $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <mpfr.h>]], [[mpfr_t bar;
mpfr_init(bar);
char * buf = NULL;
mpfr_asprintf(&buf, "%Rf", bar);
mpfr_clear(bar);]])],[libmpfr_avail_cv_=true],[libmpfr_avail_cv_=false])
AC_LANG_POP
LIBS=$libmpfr_save_libs])
if [test x$libmpfr_avail_cv_ = xtrue ]; then
LIBS="-lmpfr $LIBS"
else
AC_MSG_FAILURE("Could not find mpfr library 2.4.0 or higher (set CPPFLAGS and LDFLAGS?)")
fi
# check for edit
AC_CACHE_CHECK(
[if libedit is available],
[libedit_avail_cv_],
[libedit_save_libs=$LIBS
LIBS="-ledit $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE([AC_LANG_PROGRAM(
[[#include <stdlib.h>
#include <stdio.h>
#include <editline/readline.h>]],
[[rl_readline_name = const_cast<char *>("foo");
char * line = readline(const_cast<char *>("foo: "));
free(line);]])],[libedit_avail_cv_=true],[libedit_avail_cv_=false])
AC_LANG_POP
LIBS=$libedit_save_libs])
if [test x$libedit_avail_cv_ = xtrue ]; then
LIBS="-ledit $LIBS"
AC_DEFINE([HAVE_LIBEDIT], [1], [If the libedit library is available])
fi
# check for boost_regex
AC_CACHE_CHECK(
[if boost_regex is available],
[boost_regex_avail_cv_],
[boost_regex_save_libs=$LIBS
LIBS="-lboost_regex$BOOST_SUFFIX $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#include <boost/regex.hpp>]],
[[boost::regex foo_regexp("Hello, world!");]])],
[boost_regex_avail_cv_=true],
[boost_regex_avail_cv_=false])
AC_LANG_POP
LIBS=$boost_regex_save_libs])
if [test x$boost_regex_avail_cv_ = xtrue ]; then
LIBS="-lboost_regex$BOOST_SUFFIX $LIBS"
else
AC_MSG_FAILURE("Could not find boost_regex library (set CPPFLAGS and LDFLAGS?)")
fi
# check for boost_date_time
AC_CACHE_CHECK(
[if boost_date_time is available],
[boost_date_time_cpplib_avail_cv_],
[boost_date_time_save_libs=$LIBS
LIBS="-lboost_date_time$BOOST_SUFFIX $LIBS"
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>
using namespace boost::posix_time;
using namespace boost::date_time;
#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());
ptime t12 = time_to_system_local(t10);
return t10 != t12;]])],
[boost_date_time_cpplib_avail_cv_=true],
[boost_date_time_cpplib_avail_cv_=false])
AC_LANG_POP
LIBS=$boost_date_time_save_libs])
if [test x$boost_date_time_cpplib_avail_cv_ = xtrue ]; then
LIBS="-lboost_date_time$BOOST_SUFFIX $LIBS"
else
AC_MSG_FAILURE("Could not find boost_date_time library (set CPPFLAGS and LDFLAGS?)")
fi
# check for boost_filesystem
AC_CACHE_CHECK(
[if boost_filesystem is available],
[boost_filesystem_cpplib_avail_cv_],
[boost_filesystem_save_libs=$LIBS
LIBS="-lboost_filesystem$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
AC_LANG_PUSH(C++)
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[#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
LIBS=$boost_filesystem_save_libs])
if [test x$boost_filesystem_cpplib_avail_cv_ = xtrue ]; then
LIBS="-lboost_filesystem$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
else
AC_MSG_FAILURE("Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)")
fi
# check for boost_iostreams
AC_CACHE_CHECK(
[if boost_iostreams is available],
[boost_iostreams_cpplib_avail_cv_],
[boost_iostreams_save_libs=$LIBS
LIBS="-lboost_iostreams$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
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);]])],
[boost_iostreams_cpplib_avail_cv_=true],
[boost_iostreams_cpplib_avail_cv_=false])
AC_LANG_POP
LIBS=$boost_iostreams_save_libs])
if [test x$boost_iostreams_cpplib_avail_cv_ = xtrue ]; then
LIBS="-lboost_iostreams$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS"
else
AC_MSG_FAILURE("Could not find boost_iostreams library (set CPPFLAGS and LDFLAGS?)")
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)
# check for Python
AM_PATH_PYTHON(2.4,, :)
if [test "$PYTHON" != :]; then
AM_CONDITIONAL(HAVE_PYTHON, true)
AC_CACHE_CHECK(
[if boost_python is available],
[boost_python_cpplib_avail_cv_],
[boost_python_save_libs=$LIBS
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_POP
LIBS=$boost_python_save_libs])
if [ test x$boost_python_cpplib_avail_cv_ = xtrue ]; then
AC_DEFINE([HAVE_BOOST_PYTHON], [1], [Whether Boost.Python is available])
LIBS="-lboost_python$BOOST_SUFFIX -lpython$PYTHON_VERSION $LIBS"
fi
else
AM_CONDITIONAL(HAVE_PYTHON, false)
fi
AM_CONDITIONAL(HAVE_BOOST_PYTHON, test x$boost_python_cpplib_avail_cv_ = xtrue)
# check for CppUnit
AC_CACHE_CHECK(
[if cppunit is available],
[cppunit_avail_cv_],
[cppunit_save_libs=$LIBS
LIBS="-lcppunit $LIBS"
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;]])],
[cppunit_avail_cv_=true],
[cppunit_avail_cv_=false])
AC_LANG_POP
LIBS=$cppunit_save_libs])
AM_CONDITIONAL(HAVE_CPPUNIT, test x$cppunit_avail_cv_ = xtrue)
# Checks for header files.
AC_HEADER_STDC
AC_HEADER_STAT
AC_CHECK_HEADERS([langinfo.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_SIZE_T
AC_STRUCT_TM
# Checks for library functions.
#AC_FUNC_MKTIME
#AC_FUNC_STAT
#AC_FUNC_STRFTIME
AC_CHECK_FUNCS([access realpath getpwuid getpwnam isatty])
# Pepare the Makefiles
AC_CONFIG_FILES([Makefile po/Makefile.in intl/Makefile])
AC_OUTPUT