summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Earls <enderw88@gmail.com>2015-08-06 19:38:39 -0700
committerCraig Earls <enderw88@gmail.com>2015-08-06 19:38:39 -0700
commit0e82bd0d63bd0a6e9a9c77f0ef55e332b357368c (patch)
treefea3628fe67824069641f517a659cd88287ffdfc
parent254d82e5eb123feaf87e3f7096a1f8389bac60b3 (diff)
parent3c2d228ddc74b75122b07a87bbd06263092a9661 (diff)
downloadfork-ledger-0e82bd0d63bd0a6e9a9c77f0ef55e332b357368c.tar.gz
fork-ledger-0e82bd0d63bd0a6e9a9c77f0ef55e332b357368c.tar.bz2
fork-ledger-0e82bd0d63bd0a6e9a9c77f0ef55e332b357368c.zip
Merge commit '3c2d228ddc74b75122b07a87bbd06263092a9661' into next
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml104
-rw-r--r--CMakeLists.txt18
-rw-r--r--README.md11
-rwxr-xr-xacprep10
-rw-r--r--cmake/FindUtfcpp.cmake30
-rw-r--r--doc/NEWS24
-rw-r--r--doc/ledger.115
-rw-r--r--doc/ledger3.texi63
m---------lib/utfcpp0
-rw-r--r--lib/utfcpp/v2_0/LICENSE (renamed from doc/LICENSE-utfcpp)2
-rwxr-xr-xlib/utfcpp/v2_0/buildrelease.pl18
-rw-r--r--lib/utfcpp/v2_0/samples/Makefile5
-rw-r--r--lib/utfcpp/v2_0/samples/docsample.cpp52
-rw-r--r--lib/utfcpp/v2_0/source/utf8.h34
-rw-r--r--lib/utfcpp/v2_0/source/utf8/checked.h327
-rw-r--r--lib/utfcpp/v2_0/source/utf8/core.h329
-rw-r--r--lib/utfcpp/v2_0/source/utf8/unchecked.h228
-rw-r--r--src/CMakeLists.txt13
-rw-r--r--src/account.h6
-rw-r--r--src/emacs.h2
-rw-r--r--src/filters.cc2
-rw-r--r--src/history.cc2
-rw-r--r--src/item.h6
-rw-r--r--src/iterators.cc2
-rw-r--r--src/parser.h2
-rw-r--r--src/pool.h4
-rw-r--r--src/post.h6
-rw-r--r--src/pyinterp.h2
-rw-r--r--src/select.cc2
-rw-r--r--src/session.cc83
-rw-r--r--src/strptime.cc2
-rw-r--r--src/times.h6
-rw-r--r--src/value.cc4
-rw-r--r--src/value.h2
-rw-r--r--src/views.h2
-rw-r--r--src/wcwidth.cc2
-rw-r--r--test/CMakeLists.txt4
-rwxr-xr-xtest/CheckBaselineTests.py2
-rwxr-xr-xtest/CheckOptions.py2
-rwxr-xr-xtest/DocTests.py1
-rw-r--r--test/baseline/cmd-convert.test (renamed from test/baseline/cmd-convert.test.disable)4
-rw-r--r--test/baseline/opt-cleared-format.test20
-rw-r--r--test/baseline/opt-explicit.test14
-rw-r--r--test/baseline/opt-file.test (renamed from test/baseline/opt-file.test.disable)0
-rw-r--r--test/baseline/opt-generated.test0
-rw-r--r--test/baseline/opt-no-pager.test0
-rw-r--r--test/baseline/opt-no-revalued.test58
-rw-r--r--test/baseline/opt-no-rounding.test81
-rw-r--r--test/baseline/opt-value-expr.test48
-rw-r--r--test/baseline/opt-verify-memory.test0
-rw-r--r--test/regress/1057.test11
-rw-r--r--test/regress/25A099C9.test61
-rw-r--r--test/regress/25A099C9.test.disable43
-rw-r--r--test/unit/CMakeLists.txt9
-rw-r--r--test/unit/t_value.cc714
-rwxr-xr-xtools/travis-before_install.sh16
-rwxr-xr-xtools/travis-install.sh22
58 files changed, 2355 insertions, 178 deletions
diff --git a/.gitmodules b/.gitmodules
index ff480831..e69de29b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +0,0 @@
-[submodule "lib/utfcpp"]
- path = lib/utfcpp
- url = http://github.com/ledger/utfcpp.git
diff --git a/.travis.yml b/.travis.yml
index 9128c24e..98b0ab82 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,34 +2,106 @@
# provides GNU GCC 4.6, which does not support -std=c++11 GNU GCC 4.8 is installed
# NOTE: Please validate this file after editing it using
-# Travis WebLint http://lint.travis-ci.org/
-# or travis-yaml https://github.com/travis-ci/travis-yaml
+# Travis WebLint https://lint.travis-ci.org/
+# or travis-lint https://github.com/travis-ci/travis-lint
language: cpp
compiler:
- - clang
- gcc
+ - clang
+os:
+ - linux
+ - osx
+sudo: false
+cache:
+ apt: true
+
+env:
+ global:
+ # Boost version to use:
+ # _MIN is used when building the master branch
+ # _MAX is used when building any other branch
+ - BOOST_VERSION_MIN="1.49.0"
+ - BOOST_VERSION_MAX="1.58.0"
+ # List of required boost libraries to build
+ - BOOST_LIBS="date_time,filesystem,iostreams,python,regex,system,test"
+ # List of required Homebrew formulae to install
+ - BREWS="gmp,mpfr"
+ # Encrypted COVERITY_SCAN_TOKEN
+ - secure: "mYNxD1B8WNSvUeKzInehZ7syi2g1jH2ymeSQxoeKKD2duq3pvNWPdZdc4o9MlWQcAqcz58rhFZRIpuEWCnP0LbbJaG+MyuemMn9uAmg9Y4gFpMsBPHuTdf8pO3rDex+tkrr9puEJFgL+QV/TehxO6NDDpx7UdYvJb+4aZD/auYI="
+
+matrix:
+ exclude:
+ - os: linux
+ compiler: clang
+ # Compiling ledger on Linux with clang
+ # either crashes clang or results in a ledger binary that crashes with SIGSEGV.
+ - os: osx
+ compiler: gcc
+ # On Mac OS X building ledger with GNU GCC 4.8 fails due to
+ # undefined symbols, maybe because boost was not being built with g++-4.8.
+ # Undefined symbols for architecture x86_64:
+ # "boost::re_detail::perl_matcher<char const*, std::allocator<boost::sub_match<char const*> >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::construct_init(boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags)", referenced from:
+ # boost::re_detail::perl_matcher<char const*, std::allocator<boost::sub_match<char const*> >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::perl_matcher(char const*, char const*, boost::match_results<char const*, std::allocator<boost::sub_match<char const*> > >&, boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags, char const*) in main.cc.o
+ # boost::re_detail::perl_matcher<char const*, std::allocator<boost::sub_match<char const*> >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::perl_matcher(char const*, char const*, boost::match_results<char const*, std::allocator<boost::sub_match<char const*> > >&, boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags, char const*) in global.cc.o
+ # "boost::re_detail::perl_matcher<char const*, std::allocator<boost::sub_match<char const*> >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::find()", referenced from:
+ # bool boost::regex_search<char const*, char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >(char const*, char const*, boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags) in main.cc.o
+ # bool boost::regex_search<char const*, char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >(char const*, char const*, boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > const&, boost::regex_constants::_match_flags) in global.cc.o
+
+addons:
+ coverity_scan:
+ project:
+ name: "ledger/ledger"
+ description: "Build submitted via Travis CI"
+ build_command_prepend: "cmake . -DUSE_PYTHON=ON -DBUILD_DEBUG=ON -DCLANG_GCOV=ON"
+ build_command: "make"
+ branch_pattern: coverity
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ #- boost-latest
+ packages:
+ - gcc-4.8
+ - g++-4.8
+ - libgmp-dev
+ - libmpfr-dev
+ - libedit-dev
+ #- libboost1.55-dev
+ #- libboost-test1.55-dev
+ #- libboost-regex1.55-dev
+ #- libboost-python1.55-dev
+ #- libboost-system1.55-dev
+ #- libboost-date-time1.55-dev
+ #- libboost-iostreams1.55-dev
+ #- libboost-filesystem1.55-dev
+ #- libboost-serialization1.55-dev
before_install:
- # Add software package repositories with recent versions of gcc and boost
- - sudo add-apt-repository ppa:ubuntu-toolchain-r/test --yes
- - sudo add-apt-repository ppa:boost-latest/ppa --yes
- - sudo apt-get update -qq
-
-install:
- # Install GNU GCC 4.8 required by use of C++11
- - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8 gcc-4.8; fi
- - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
- # Install Ledger dependencies
- - sudo apt-get install -qq libboost1.55 libgmp-dev libmpfr-dev libeditline-dev
+ - if [ "${TRAVIS_BRANCH}" = "master" ]; then export BOOST_VERSION="${BOOST_VERSION_MIN}"; else export BOOST_VERSION="${BOOST_VERSION_MAX}"; fi
+ - if [ -n "${BOOST_VERSION}" ]; then export BOOST_ROOT="${TRAVIS_BUILD_DIR}/../boost-trunk"; export CMAKE_MODULE_PATH="${BOOST_ROOT}"; fi
+ - if [ "${CXX}" = "g++" ]; then export CXX="$(which g++-4.8)"; export CC="$(which gcc-4.8)"; fi
+ - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then export DYLD_LIBRARY_PATH="${BOOST_ROOT}/lib"; fi
+ # c++ is a symlink to clang++, but the compiler behaves differently when invoked as c++
+ - if [ "${TRAVIS_OS_NAME}" = "osx" -a "${CXX}" = "clang++" ]; then export CXX="$(which c++)"; export CC="$(which cc)"; fi
+ - tools/travis-before_install.sh
+
+install:
+ - tools/travis-install.sh
before_script:
- - ./acprep debug make --python
+ - cmake . -DUSE_PYTHON=ON -DBUILD_DEBUG=ON
+ - make
script:
- - ./acprep check --jobs $(nproc) -- --output-on-failure
+ - ctest --output-on-failure
- PYTHONPATH=. python python/demo.py
+after_script:
+ # These scripts are run for informational purposes and
+ # should be reintegrated into CTest once they reliably verify the documentation.
+ - python test/CheckTexinfo.py -l ledger -s .
+ - python test/CheckManpage.py -l ledger -s .
+
notifications:
email:
on_success: change
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6166780c..e455ec02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,9 @@ set(Ledger_VERSION_PATCH 1)
set(Ledger_VERSION_PRERELEASE "-alpha.1")
set(Ledger_VERSION_DATE 20141005)
+# Point CMake at any custom modules we may ship
+list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+
enable_testing()
add_definitions(-std=c++11)
@@ -225,7 +228,7 @@ macro(add_ledger_library_dependencies _target)
target_link_libraries(${_target} ${INTL_LIB})
endif()
if (HAVE_BOOST_PYTHON)
- if(APPLE)
+ if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
# Don't link directly to a Python framework on OS X, to avoid segfaults
# when the module is imported from a different interpreter
target_link_libraries(${_target} ${Boost_LIBRARIES})
@@ -244,13 +247,20 @@ endmacro(add_ledger_library_dependencies _target)
########################################################################
+include(FindUtfcpp)
+if (UTFCPP_FOUND)
+ include_directories("${UTFCPP_INCLUDE_DIR}")
+else()
+ message(FATAL_ERROR "Missing required header file: utf8.h\n"
+ "Define UTFCPP_PATH or install utfcpp locally into the source tree below lib/utfcpp/."
+ )
+endif()
+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
# add the binary tree to the search path for include files so that we will
-# find TutorialConfig.h
-include_directories("${PROJECT_SOURCE_DIR}/lib")
-include_directories("${PROJECT_SOURCE_DIR}/lib/utfcpp/source")
+# find system.hh
include_directories("${PROJECT_BINARY_DIR}")
configure_file(
diff --git a/README.md b/README.md
index 5e2c6a07..759fa26a 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
-[![Build Status](https://img.shields.io/travis/ledger/ledger/master.svg?&style=flat)](https://travis-ci.org/ledger/ledger)
+[![Build Status master](https://img.shields.io/travis/ledger/ledger/master.svg?label=master&style=flat)](https://travis-ci.org/ledger/ledger)
+[![Build Status next](https://img.shields.io/travis/ledger/ledger/next.svg?label=next&style=flat)](https://travis-ci.org/ledger/ledger)
[![Status](https://img.shields.io/badge/status-active-brightgreen.svg?style=flat)](https://github.com/ledger/ledger/pulse/monthly)
[![License](https://img.shields.io/badge/license-BSD-blue.svg?style=flat)](http://opensource.org/licenses/BSD-3-Clause)
-[![GitHub tag](https://img.shields.io/github/tag/ledger/ledger.svg?style=flat)](https://github.com/ledger/ledger/releases)
+[![GitHub release](https://img.shields.io/github/release/ledger/ledger.svg?style=flat)](https://github.com/ledger/ledger/releases)
# Ledger: Command-Line Accounting
@@ -147,9 +148,9 @@ Or, for Ubuntu 12.04:
Debian squeeze (6.0): the version of boost in squeeze is too old
for ledger and unfortunately no backport is available at the moment.
-Debian 7 (wheezy) and Debian 8 (jessie) contain all components needed to
-build ledger. You can install all required build dependencies using the
-following command:
+Debian 7 (wheezy), Debian 8 (jessie), Debian testing (stretch) and Debian
+unstable (sid) contain all components needed to build ledger. You can
+install all required build dependencies using the following command:
$ sudo apt-get install build-essential cmake autopoint texinfo python-dev \
zlib1g-dev libbz2-dev libgmp3-dev gettext libmpfr-dev \
diff --git a/acprep b/acprep
index 275f2c84..17436960 100755
--- a/acprep
+++ b/acprep
@@ -490,17 +490,10 @@ class PrepareBuild(CommandLineApp):
# Update local files with the latest information #
#########################################################################
- def phase_submodule(self, *args):
- self.log.info('Executing phase: submodule')
- if self.git_working_tree():
- self.execute('git', 'submodule', 'init')
- self.execute('git', 'submodule', 'update')
-
def phase_pull(self, *args):
self.log.info('Executing phase: pull')
if self.git_working_tree():
self.execute('git', 'pull')
- self.phase_submodule()
#########################################################################
# Automatic installation of build dependencies #
@@ -569,6 +562,7 @@ class PrepareBuild(CommandLineApp):
'libedit-dev',
'texinfo',
'lcov',
+ 'libutfcpp-dev',
'sloccount'
] + BoostInfo().dependencies('ubuntu-trusty')
elif re.search('saucy', info):
@@ -606,6 +600,7 @@ class PrepareBuild(CommandLineApp):
'libedit-dev',
'texinfo',
'lcov',
+ 'libutfcpp-dev',
'sloccount'
] + BoostInfo().dependencies('ubuntu-precise')
else:
@@ -885,7 +880,6 @@ class PrepareBuild(CommandLineApp):
def phase_config(self, *args):
self.log.info('Executing phase: config')
- self.phase_submodule()
self.phase_configure(*args)
if self.should_clean:
self.phase_clean()
diff --git a/cmake/FindUtfcpp.cmake b/cmake/FindUtfcpp.cmake
new file mode 100644
index 00000000..185a8d88
--- /dev/null
+++ b/cmake/FindUtfcpp.cmake
@@ -0,0 +1,30 @@
+# - Try to find utfcpp
+# Once done, this will define
+#
+# UTFCPP_FOUND - system has utfcpp's utf8.h
+# UTFCPP_PATH - the utfcpp include directories
+
+include(CheckCXXSourceCompiles)
+
+set(UTFCPP_FOUND FALSE)
+
+find_path(UTFCPP_INCLUDE_DIR
+ NAMES utf8.h
+ HINTS "${UTFCPP_PATH}" "${PROJECT_SOURCE_DIR}/lib/utfcpp/v2_0/source"
+)
+
+if (UTFCPP_INCLUDE_DIR)
+ set(CMAKE_REQUIRED_INCLUDES "${UTFCPP_INCLUDE_DIR}")
+ set(UTFCPP_FOUND TRUE)
+endif()
+
+check_cxx_source_compiles("
+#include <string>
+#include \"utf8.h\"
+
+int main(int argc, char** argv) {
+ std::string input = std::string(\"utfcpp\");
+ const char * p = input.c_str();
+ std::size_t len = input.length();
+ utf8::is_valid(p, p + len);
+}" HAVE_WORKING_UTFCPP)
diff --git a/doc/NEWS b/doc/NEWS
index 45596ddc..94c0946a 100644
--- a/doc/NEWS
+++ b/doc/NEWS
@@ -1,5 +1,29 @@
Ledger NEWS
+* 3.x.x
+
+- Added a --no-revalued option
+
+- Improved Embedded Python Support
+
+- Fixed parsing of transactions with single-character payees and comments
+
+- Fixed crash when using -M with empty result
+
+- Fixed sorting for option --auto-match
+
+- Fixed treatment of "year 2015" and "Y2014" directives
+
+- Fixed crash when using --trace 10 or above
+
+- Build fix for boost 1.56
+
+- Build fix for Cygwin
+
+- Fixed Util and Math tests on Mac OS X
+
+- Various documentation improvements
+
* 3.1
- Changed the definition of cost basis to preserve the original cost basis
diff --git a/doc/ledger.1 b/doc/ledger.1
index b674cb6a..0445c237 100644
--- a/doc/ledger.1
+++ b/doc/ledger.1
@@ -574,7 +574,12 @@ posting occurring in that period.
Display values in terms of the given
.Ar COMMODITY .
The latest available price is used.
-.\".It Fl \-explicit
+.It Fl \-explicit
+Direct
+.Nm
+to require pre-declarations for entities (such as accounts,
+commodities and tags) rather than taking entities from cleared
+transactions as defined.
.It Fl \-file Ar FILE
Read journal data from
.Ar FILE .
@@ -716,9 +721,15 @@ Aliases are completely ignored.
Suppress any color TTY output.
.It Fl \-no-pager
Disables the pager on TTY output.
+.It Fl \-no-revalued
+Stop
+.Nm
+from showing
+<Revalued>
+postings.
.It Fl \-no-rounding
Don't output
-.Qq Li <Rounding>
+.Qq Li <Adjustment>
postings. Note that this will cause the
running total to often not add up! Its main use is for
.Fl \-amount-data Pq Fl j
diff --git a/doc/ledger3.texi b/doc/ledger3.texi
index e70210ab..14a71778 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -2105,6 +2105,7 @@ the syntax @code{[ACTUAL_DATE]} or @code{[=EFFECTIVE_DATE]} or
@item P
@findex --download
@findex P
+@cindex historical prices
Specifies a historical price for a commodity. These are usually found
in a pricing history file (see the @option{--download (-Q)} option).
The syntax is:
@@ -2114,6 +2115,9 @@ P DATE SYMBOL PRICE
@end smallexample
@item =
+@findex =
+@cindex automated transaction
+@cindex transaction, automated
An automated transaction. A value expression must appear after the
equal sign.
@@ -2124,17 +2128,23 @@ posting is matched by the value expression (@pxref{Automated
Transactions}).
@item ~
+@findex ~
+@cindex periodic transaction
+@cindex transaction, periodic
A periodic transaction. A period expression must appear after the tilde.
After this initial line there should be a set of one or more
postings, just as if it were a normal transaction.
@item ; # % | *
+@findex comment
+@cindex comments
A line beginning with a semicolon, pound, percent, bar or asterisk
indicates a comment, and is ignored. Comments will not be returned in
a ``print'' response.
@item indented ;
+@cindex tags
If the semicolon is indented and occurs inside a transaction, it is
parsed as a persistent note for its preceding category. These notes or
tags can be used to augment the reporting and filtering capabilities of
@@ -2154,6 +2164,8 @@ Command directives must occur at the beginning of a line. Use of
@samp{!} and @samp{@@} is deprecated.
@item account
+@findex account
+@cindex pre-declare account
Pre-declare valid account names. This only has an effect if
@option{--strict} or @option{--pedantic} is used (see below). The
@code{account} directive supports several optional sub-directives, if
@@ -2203,6 +2215,7 @@ used as the ``balancing account'' for any future transactions that
contain only a single posting.
@item apply account
+@findex apply account
@c instance_t::master_account_directive
Sets the root for all accounts following this directive. Ledger
supports a hierarchical tree of accounts. It may be convenient to
@@ -2225,6 +2238,8 @@ Would result in all postings going into
until an @samp{end apply account} directive was found.
@item alias
+@findex alias
+@cindex account, alias
@c instance_t::alias_directive
Define an alias for an account name. If you have a deeply nested tree
of accounts, it may be convenient to define an alias, for example:
@@ -2276,6 +2291,8 @@ The option @option{--no-aliases} completely disables alias expansion.
All accounts are read verbatim as they are in the ledger file.
@item assert
+@findex assert
+@cindex assertions
@c instance_t::assert_directive
An assertion can throw an error if a condition is not met during
Ledger's run.
@@ -2286,6 +2303,8 @@ assert <VALUE EXPRESSION BOOLEAN RESULT>
@item bucket
@anchor{bucket}
+@findex bucket
+@cindex bucket
@c instance_t::default_account_directive
Defines the default account to use for balancing transactions.
Normally, each transaction has at least two postings, which must
@@ -2311,6 +2330,7 @@ bucket Assets:Checking
@item capture
@c instance_t::account_mapping_directive
+@findex capture
@findex print
@findex register
@@ -2328,6 +2348,8 @@ Ledger will display the mapped payees in @command{print} and
@command{register} reports.
@item check
+@findex check
+@cindex assertions
@c instance_t::check_directive in textual.cc
A check issues a warning if a condition is not met during Ledger's
run.
@@ -2337,10 +2359,14 @@ check <VALUE EXPRESSION BOOLEAN RESULT>
@end smallexample
@item comment
+@findex comment
+@cindex comments
@c instance_t::comment_directive in textual.cc
Start a block comment, closed by @code{end comment}.
@item commodity
+@findex commodity
+@cindex pre-declare commodity
Pre-declare commodity names. This only has an effect if
@option{--strict} or @option{--pedantic} is used (see below).
@@ -2375,6 +2401,7 @@ should never be auto-downloaded.
The @code{default} sub-directive marks this as the ``default'' commodity.
@item define
+@findex define
@c instance_t::define_directive in textual.cc
Allows you to define value expressions for future use. For example:
@@ -2389,13 +2416,17 @@ define var_name=$100
The posting will have a cost of $400.
@item end
+@findex end
@c instance_t::end_directive in textual.cc
Closes block commands like @code{tag} or @code{comment}.
@item expr
+@findex expr
@c instance_t::expr_directive in textual.cc
@item fixed
+@findex fixed
+@cindex fixated prices
@c instance_t::fixed_directive in textual.cc
A fixed block is used to set fixated prices (@pxref{Fixated prices and
@@ -2437,10 +2468,12 @@ For the moment, users may wish to study
before using the @code{fixed} directive in production.
@item include
+@findex include
@c instance_t::include_directive in textual.cc
Include the stated file as if it were part of the current file.
@item payee
+@findex payee
@c instance_t::payee_alias_mapping_directive in textual.cc
@c instance_t::payee_uuid_mapping_directive in textual.cc
@findex print
@@ -2475,6 +2508,7 @@ Ledger will display the mapped payees in @command{print} and
@command{register} reports.
@item apply tag
+@findex apply tag
@c instance_t::tag_directive in textual.cc
Allows you to designate a block of transactions and assign the same
tag to all. Tags can have values and may be nested.
@@ -2532,6 +2566,8 @@ is the equivalent of:
@c track.
@item tag
+@findex tag
+@cindex pre-declare tag
Pre-declares tag names. This only has an effect if @option{--strict} or
@option{--pedantic} is used (see below).
@@ -2558,11 +2594,14 @@ but a string if typed metadata is used!). Such checks or assertions are
not called if no value is given.
@item test
+@findex test
+@cindex comments
@c instance_t::comment_directive in textual.cc
This is a synonym for @code{comment} and must be closed by an
@code{end} tag.
@item year
+@findex year
@anchor{year}
@c instance_t::year_directive in textual.cc
Denotes the year used for all subsequent transactions that give a date
@@ -2580,10 +2619,12 @@ alone, for backwards compatibility with older Ledger versions.
@item A
@findex A
+@findex bucket
@xref{bucket}.
@item Y
@findex Y
+@findex year
@xref{year}.
@item N SYMBOL
@@ -2601,7 +2642,6 @@ N SYMBOL
@item D AMOUNT
@findex xact
@findex D
-
Specifies the default commodity to use, by specifying an amount in the
expected format. The @command{xact} command will use this commodity as
the default when none other can be determined. This command may be used
@@ -5970,8 +6010,10 @@ Direct Ledger to download prices.
@c @option{--getquote @var{FILE}}.
@item --explicit
-@c see test/baseline/opt-explicit.test
-@value{FIXME:UNDOCUMENTED}
+Direct Ledger to require pre-declarations for entities (such as accounts,
+commodities and tags) rather than taking entities from cleared
+transactions as defined. This option is useful in combination with
+@option{--strict} or @option{--pedantic}.
@item --file @var{FILE}
@itemx -f @var{FILE}
@@ -6536,8 +6578,12 @@ Suppress any color TTY output.
@item --no-pager
Direct output to stdout, avoiding pager program.
+@item --no-revalued
+Stop Ledger from showing @code{<Revalued>} postings. This option is useful
+in combination with the @option{--exchange} or @option{--market} option.
+
@item --no-rounding
-Don't output @samp{<Rounding>} postings. Note that this will cause the
+Don't output @samp{<Adjustment>} postings. Note that this will cause the
running total to often not add up! Its main use is for
@option{--amount-data (-j)} and @option{--total-data (-J)} reports.
@@ -7868,6 +7914,13 @@ considering children.
The cost of a posting; the cost of an account, without its
children.
+@item v
+The market value of a posting or an account, without its children.
+
+@item g
+The net gain (market value minus cost basis), for a posting or an
+account, without its children. It is the same as @samp{v-b}.
+
@item l
The depth (``level'') of an account. If an account has one parent,
its depth is one.
@@ -8107,7 +8160,7 @@ Render the given @var{expression} as a string, applying the proper ANSI escape
codes to display it in the given @var{color} if @var{bool} is true. It
typically checks the value of the option @option{--color}. Since ANSI escape
codes include non-printable character sequences, such as escape @kbd{^[}
-the following example may not appear as the final result on the commandline.
+the following example may not appear as the final result on the command-line.
@smallexample @c command:4D836EE,with_input:3406FC1
$ ledger -f expr.dat --format "%(ansify_if(account, blue, options.color))\n" reg
@end smallexample
diff --git a/lib/utfcpp b/lib/utfcpp
deleted file mode 160000
-Subproject 2233ec933f5661c7050b94d3b14f5f9f51ae3d5
diff --git a/doc/LICENSE-utfcpp b/lib/utfcpp/v2_0/LICENSE
index 1751a003..36b7cd93 100644
--- a/doc/LICENSE-utfcpp
+++ b/lib/utfcpp/v2_0/LICENSE
@@ -1,4 +1,4 @@
-Copyright 2006 Nemanja Trifunovic
+Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
diff --git a/lib/utfcpp/v2_0/buildrelease.pl b/lib/utfcpp/v2_0/buildrelease.pl
new file mode 100755
index 00000000..ed3a17bb
--- /dev/null
+++ b/lib/utfcpp/v2_0/buildrelease.pl
@@ -0,0 +1,18 @@
+#! /usr/bin/perl
+
+$release_files = 'source/utf8.h source/utf8/core.h source/utf8/checked.h source/utf8/unchecked.h doc/utf8cpp.html doc/ReleaseNotes';
+
+# First get the latest version
+`svn update`;
+
+# Then construct the name of the zip file
+$argc = @ARGV;
+if ($argc > 0) {
+ $zip_name = $ARGV[0];
+}
+else {
+ $zip_name = "utf8";
+}
+
+# Zip the files to an archive
+`zip $zip_name $release_files`;
diff --git a/lib/utfcpp/v2_0/samples/Makefile b/lib/utfcpp/v2_0/samples/Makefile
new file mode 100644
index 00000000..6cdd3c85
--- /dev/null
+++ b/lib/utfcpp/v2_0/samples/Makefile
@@ -0,0 +1,5 @@
+CC = g++
+CFLAGS = -g -Wall -pedantic
+
+docsample: docsample.cpp ../source/utf8.h
+ $(CC) $(CFLAGS) docsample.cpp -odocsample
diff --git a/lib/utfcpp/v2_0/samples/docsample.cpp b/lib/utfcpp/v2_0/samples/docsample.cpp
new file mode 100644
index 00000000..6f8953b9
--- /dev/null
+++ b/lib/utfcpp/v2_0/samples/docsample.cpp
@@ -0,0 +1,52 @@
+#include "../source/utf8.h"
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if (argc != 2) {
+ cout << "\nUsage: docsample filename\n";
+ return 0;
+ }
+ const char* test_file_path = argv[1];
+ // Open the test file (must be UTF-8 encoded)
+ ifstream fs8(test_file_path);
+ if (!fs8.is_open()) {
+ cout << "Could not open " << test_file_path << endl;
+ return 0;
+ }
+
+ unsigned line_count = 1;
+ string line;
+ // Play with all the lines in the file
+ while (getline(fs8, line)) {
+ // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)
+ string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
+ if (end_it != line.end()) {
+ cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n";
+ cout << "This part is fine: " << string(line.begin(), end_it) << "\n";
+ }
+ // Get the line length (at least for the valid part)
+ int length = utf8::distance(line.begin(), end_it);
+ cout << "Length of line " << line_count << " is " << length << "\n";
+
+ // Convert it to utf-16
+ vector<unsigned short> utf16line;
+ utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));
+ // And back to utf-8;
+ string utf8line;
+ utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));
+ // Confirm that the conversion went OK:
+ if (utf8line != string(line.begin(), end_it))
+ cout << "Error in UTF-16 conversion at line: " << line_count << "\n";
+
+ line_count++;
+ }
+
+ return 0;
+}
diff --git a/lib/utfcpp/v2_0/source/utf8.h b/lib/utfcpp/v2_0/source/utf8.h
new file mode 100644
index 00000000..4e445140
--- /dev/null
+++ b/lib/utfcpp/v2_0/source/utf8.h
@@ -0,0 +1,34 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard
diff --git a/lib/utfcpp/v2_0/source/utf8/checked.h b/lib/utfcpp/v2_0/source/utf8/checked.h
new file mode 100644
index 00000000..13311551
--- /dev/null
+++ b/lib/utfcpp/v2_0/source/utf8/checked.h
@@ -0,0 +1,327 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+#include <stdexcept>
+
+namespace utf8
+{
+ // Base for the exceptions that may be thrown from the library
+ class exception : public ::std::exception {
+ };
+
+ // Exceptions that may be thrown from the library functions.
+ class invalid_code_point : public exception {
+ uint32_t cp;
+ public:
+ invalid_code_point(uint32_t cp) : cp(cp) {}
+ virtual const char* what() const throw() { return "Invalid code point"; }
+ uint32_t code_point() const {return cp;}
+ };
+
+ class invalid_utf8 : public exception {
+ uint8_t u8;
+ public:
+ invalid_utf8 (uint8_t u) : u8(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-8"; }
+ uint8_t utf8_octet() const {return u8;}
+ };
+
+ class invalid_utf16 : public exception {
+ uint16_t u16;
+ public:
+ invalid_utf16 (uint16_t u) : u16(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-16"; }
+ uint16_t utf16_word() const {return u16;}
+ };
+
+ class not_enough_room : public exception {
+ public:
+ virtual const char* what() const throw() { return "Not enough space"; }
+ };
+
+ /// The library API - functions intended to be called by the users
+
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (!utf8::internal::is_code_point_valid(cp))
+ throw invalid_code_point(cp);
+
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
+ {
+ while (start != end) {
+ octet_iterator sequence_start = start;
+ internal::utf_error err_code = utf8::internal::validate_next(start, end);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ for (octet_iterator it = sequence_start; it != start; ++it)
+ *out++ = *it;
+ break;
+ case internal::NOT_ENOUGH_ROOM:
+ throw not_enough_room();
+ case internal::INVALID_LEAD:
+ out = utf8::append (replacement, out);
+ ++start;
+ break;
+ case internal::INCOMPLETE_SEQUENCE:
+ case internal::OVERLONG_SEQUENCE:
+ case internal::INVALID_CODE_POINT:
+ out = utf8::append (replacement, out);
+ ++start;
+ // just one replacement mark for the sequence
+ while (start != end && utf8::internal::is_trail(*start))
+ ++start;
+ break;
+ }
+ }
+ return out;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
+ {
+ static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
+ return utf8::replace_invalid(start, end, out, replacement_marker);
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it, octet_iterator end)
+ {
+ uint32_t cp = 0;
+ internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ break;
+ case internal::NOT_ENOUGH_ROOM :
+ throw not_enough_room();
+ case internal::INVALID_LEAD :
+ case internal::INCOMPLETE_SEQUENCE :
+ case internal::OVERLONG_SEQUENCE :
+ throw invalid_utf8(*it);
+ case internal::INVALID_CODE_POINT :
+ throw invalid_code_point(cp);
+ }
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it, octet_iterator end)
+ {
+ return utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it, octet_iterator start)
+ {
+ // can't do much if it == start
+ if (it == start)
+ throw not_enough_room();
+
+ octet_iterator end = it;
+ // Go back until we hit either a lead octet or start
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ return utf8::peek_next(it, end);
+ }
+
+ /// Deprecated in versions that include "prior"
+ template <typename octet_iterator>
+ uint32_t previous(octet_iterator& it, octet_iterator pass_start)
+ {
+ octet_iterator end = it;
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == pass_start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ octet_iterator temp = it;
+ return utf8::next(temp, end);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n, octet_iterator end)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::next(first, last);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ if (start != end) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ if (utf8::internal::is_trail_surrogate(trail_surrogate))
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ else
+ throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
+ }
+ else
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ }
+ // Lone trail surrogate
+ else if (utf8::internal::is_trail_surrogate(cp))
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ result = utf8::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::next(start, end);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start != end)
+ (*result++) = utf8::next(start, end);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ octet_iterator range_start;
+ octet_iterator range_end;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it,
+ const octet_iterator& range_start,
+ const octet_iterator& range_end) :
+ it(octet_it), range_start(range_start), range_end(range_end)
+ {
+ if (it < range_start || it > range_end)
+ throw std::out_of_range("Invalid utf-8 iterator position");
+ }
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::next(temp, range_end);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ if (range_start != rhs.range_start || range_end != rhs.range_end)
+ throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ utf8::next(it, range_end);
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ utf8::next(it, range_end);
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::prior(it, range_start);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::prior(it, range_start);
+ return temp;
+ }
+ }; // class iterator
+
+} // namespace utf8
+
+#endif //header guard
+
+
diff --git a/lib/utfcpp/v2_0/source/utf8/core.h b/lib/utfcpp/v2_0/source/utf8/core.h
new file mode 100644
index 00000000..693d388c
--- /dev/null
+++ b/lib/utfcpp/v2_0/source/utf8/core.h
@@ -0,0 +1,329 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include <iterator>
+
+namespace utf8
+{
+ // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
+ // You may need to change them to match your system.
+ // These typedefs have the same names as ones from cstdint, or boost/cstdint
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+
+// Helper code - not intended to be directly called by the library users. May be changed at any time
+namespace internal
+{
+ // Unicode constants
+ // Leading (high) surrogates: 0xd800 - 0xdbff
+ // Trailing (low) surrogates: 0xdc00 - 0xdfff
+ const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
+ const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
+ const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
+ const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
+ const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
+ const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
+
+ // Maximum valid value for a Unicode code point
+ const uint32_t CODE_POINT_MAX = 0x0010ffffu;
+
+ template<typename octet_type>
+ inline uint8_t mask8(octet_type oc)
+ {
+ return static_cast<uint8_t>(0xff & oc);
+ }
+ template<typename u16_type>
+ inline uint16_t mask16(u16_type oc)
+ {
+ return static_cast<uint16_t>(0xffff & oc);
+ }
+ template<typename octet_type>
+ inline bool is_trail(octet_type oc)
+ {
+ return ((utf8::internal::mask8(oc) >> 6) == 0x2);
+ }
+
+ template <typename u16>
+ inline bool is_lead_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_trail_surrogate(u16 cp)
+ {
+ return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u32>
+ inline bool is_code_point_valid(u32 cp)
+ {
+ return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
+ }
+
+ template <typename octet_iterator>
+ inline typename std::iterator_traits<octet_iterator>::difference_type
+ sequence_length(octet_iterator lead_it)
+ {
+ uint8_t lead = utf8::internal::mask8(*lead_it);
+ if (lead < 0x80)
+ return 1;
+ else if ((lead >> 5) == 0x6)
+ return 2;
+ else if ((lead >> 4) == 0xe)
+ return 3;
+ else if ((lead >> 3) == 0x1e)
+ return 4;
+ else
+ return 0;
+ }
+
+ template <typename octet_difference_type>
+ inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
+ {
+ if (cp < 0x80) {
+ if (length != 1)
+ return true;
+ }
+ else if (cp < 0x800) {
+ if (length != 2)
+ return true;
+ }
+ else if (cp < 0x10000) {
+ if (length != 3)
+ return true;
+ }
+
+ return false;
+ }
+
+ enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
+
+ /// Helper for get_sequence_x
+ template <typename octet_iterator>
+ utf_error increase_safely(octet_iterator& it, octet_iterator end)
+ {
+ if (++it == end)
+ return NOT_ENOUGH_ROOM;
+
+ if (!utf8::internal::is_trail(*it))
+ return INCOMPLETE_SEQUENCE;
+
+ return UTF8_OK;
+ }
+
+ #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
+
+ /// get_sequence_x functions decode utf-8 sequences of the length x
+ template <typename octet_iterator>
+ utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
+
+ template <typename octet_iterator>
+ utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ // Save the original value of it so we can go back in case of failure
+ // Of course, it does not make much sense with i.e. stream iterators
+ octet_iterator original_it = it;
+
+ uint32_t cp = 0;
+ // Determine the sequence length based on the lead octet
+ typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
+ const octet_difference_type length = utf8::internal::sequence_length(it);
+
+ // Get trail octets and calculate the code point
+ utf_error err = UTF8_OK;
+ switch (length) {
+ case 0:
+ return INVALID_LEAD;
+ case 1:
+ err = utf8::internal::get_sequence_1(it, end, cp);
+ break;
+ case 2:
+ err = utf8::internal::get_sequence_2(it, end, cp);
+ break;
+ case 3:
+ err = utf8::internal::get_sequence_3(it, end, cp);
+ break;
+ case 4:
+ err = utf8::internal::get_sequence_4(it, end, cp);
+ break;
+ }
+
+ if (err == UTF8_OK) {
+ // Decoding succeeded. Now, security checks...
+ if (utf8::internal::is_code_point_valid(cp)) {
+ if (!utf8::internal::is_overlong_sequence(cp, length)){
+ // Passed! Return here.
+ code_point = cp;
+ ++it;
+ return UTF8_OK;
+ }
+ else
+ err = OVERLONG_SEQUENCE;
+ }
+ else
+ err = INVALID_CODE_POINT;
+ }
+
+ // Failure branch - restore the original value of the iterator
+ it = original_it;
+ return err;
+ }
+
+ template <typename octet_iterator>
+ inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
+ uint32_t ignored;
+ return utf8::internal::validate_next(it, end, ignored);
+ }
+
+} // namespace internal
+
+ /// The library API - functions intended to be called by the users
+
+ // Byte order mark
+ const uint8_t bom[] = {0xef, 0xbb, 0xbf};
+
+ template <typename octet_iterator>
+ octet_iterator find_invalid(octet_iterator start, octet_iterator end)
+ {
+ octet_iterator result = start;
+ while (result != end) {
+ utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
+ if (err_code != internal::UTF8_OK)
+ return result;
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ inline bool is_valid(octet_iterator start, octet_iterator end)
+ {
+ return (utf8::find_invalid(start, end) == end);
+ }
+
+ template <typename octet_iterator>
+ inline bool starts_with_bom (octet_iterator it, octet_iterator end)
+ {
+ return (
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
+ ((it != end) && (utf8::internal::mask8(*it)) == bom[2])
+ );
+ }
+
+ //Deprecated in release 2.3
+ template <typename octet_iterator>
+ inline bool is_bom (octet_iterator it)
+ {
+ return (
+ (utf8::internal::mask8(*it++)) == bom[0] &&
+ (utf8::internal::mask8(*it++)) == bom[1] &&
+ (utf8::internal::mask8(*it)) == bom[2]
+ );
+ }
+} // namespace utf8
+
+#endif // header guard
+
+
diff --git a/lib/utfcpp/v2_0/source/utf8/unchecked.h b/lib/utfcpp/v2_0/source/utf8/unchecked.h
new file mode 100644
index 00000000..cb242716
--- /dev/null
+++ b/lib/utfcpp/v2_0/source/utf8/unchecked.h
@@ -0,0 +1,228 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+
+namespace utf8
+{
+ namespace unchecked
+ {
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it)
+ {
+ uint32_t cp = utf8::internal::mask8(*it);
+ typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
+ switch (length) {
+ case 1:
+ break;
+ case 2:
+ it++;
+ cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
+ break;
+ case 3:
+ ++it;
+ cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ case 4:
+ ++it;
+ cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+ ++it;
+ cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ }
+ ++it;
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it)
+ {
+ return utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it)
+ {
+ while (utf8::internal::is_trail(*(--it))) ;
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+
+ // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
+ template <typename octet_iterator>
+ inline uint32_t previous(octet_iterator& it)
+ {
+ return utf8::unchecked::prior(it);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::unchecked::next(first);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ }
+ result = utf8::unchecked::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start < end) {
+ uint32_t cp = utf8::unchecked::next(start);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::unchecked::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start < end)
+ (*result++) = utf8::unchecked::next(start);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::unchecked::prior(it);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::unchecked::prior(it);
+ return temp;
+ }
+ }; // class iterator
+
+ } // namespace utf8::unchecked
+} // namespace utf8
+
+
+#endif // header guard
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a368d378..65e58edb 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -152,7 +152,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
-Wno-unused-parameter
-Wno-c++98-compat
-fno-limit-debug-info)
-
+
macro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
set(_pch_filename "${_header_filename}.pch")
@@ -188,7 +188,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args}
DEPENDS ${_header_filename})
endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
-
+
elseif(CMAKE_CXX_COMPILER MATCHES "g\\+\\+")
set(GXX_WARNING_FLAGS
-pedantic
@@ -210,7 +210,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
-Wno-strict-aliasing)
add_definitions(${GXX_WARNING_FLAGS})
-
+
macro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
set(_gch_filename "${_header_filename}.gch")
@@ -247,7 +247,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args}
DEPENDS ${_header_filename})
endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
-
+
else()
macro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
endmacro(ADD_PCH_RULE _header_filename _src_list _other_srcs)
@@ -273,6 +273,9 @@ if (BUILD_LIBRARY)
add_executable(ledger main.cc global.cc)
target_link_libraries(ledger libledger)
+ if (CMAKE_SYSTEM_NAME STREQUAL Darwin AND HAVE_BOOST_PYTHON)
+ target_link_libraries(ledger ${PYTHON_LIBRARIES})
+ endif()
install(TARGETS libledger DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES ${LEDGER_INCLUDES}
@@ -294,7 +297,7 @@ print(s.get_python_lib(True, prefix=''))"
if (PYTHON_SITE_PACKAGES)
if (WIN32 AND NOT CYGWIN)
set(_ledger_python_module_name "ledger.pyd")
- elseif(CMAKE_HOST_APPLE)
+ elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
set(_ledger_python_module_name "ledger.so")
else()
set(_ledger_python_module_name "ledger${CMAKE_SHARED_LIBRARY_SUFFIX}")
diff --git a/src/account.h b/src/account.h
index 7fae93e1..7de4e560 100644
--- a/src/account.h
+++ b/src/account.h
@@ -261,11 +261,7 @@ public:
mutable optional<xdata_t> xdata_;
bool has_xdata() const {
-#if BOOST_VERSION >= 105600
- return xdata_ != NULL;
-#else
- return xdata_;
-#endif
+ return static_cast<bool>(xdata_);
}
void clear_xdata();
xdata_t& xdata() {
diff --git a/src/emacs.h b/src/emacs.h
index fef7a882..b89ce9f4 100644
--- a/src/emacs.h
+++ b/src/emacs.h
@@ -72,7 +72,7 @@ public:
out.flush();
}
virtual void operator()(post_t& post);
- virtual string escape_string(string raw);
+ virtual string escape_string(string raw);
};
} // namespace ledger
diff --git a/src/filters.cc b/src/filters.cc
index 2f97a0e5..b6530c04 100644
--- a/src/filters.cc
+++ b/src/filters.cc
@@ -707,7 +707,7 @@ namespace {
insert_prices_in_map(price_map_t& _all_prices)
: all_prices(_all_prices) {}
- void operator()(datetime_t& date, const amount_t& price) {
+ void operator()(const datetime_t& date, const amount_t& price) {
all_prices.insert(price_map_t::value_type(date, price));
}
};
diff --git a/src/history.cc b/src/history.cc
index e3c459f3..8772d18c 100644
--- a/src/history.cc
+++ b/src/history.cc
@@ -475,7 +475,7 @@ commodity_history_impl_t::find_price(const commodity_t& source,
#endif
vertex_descriptor v = tv;
- for (vertex_descriptor u = predecessorMap[v];
+ for (vertex_descriptor u = predecessorMap[v];
u != v;
v = u, u = predecessorMap[v])
{
diff --git a/src/item.h b/src/item.h
index ba812175..dbba53a8 100644
--- a/src/item.h
+++ b/src/item.h
@@ -174,11 +174,7 @@ public:
static bool use_aux_date;
virtual bool has_date() const {
-#if BOOST_VERSION >= 105600
- return _date != NULL;
-#else
- return _date;
-#endif
+ return static_cast<bool>(_date);
}
virtual date_t date() const {
diff --git a/src/iterators.cc b/src/iterators.cc
index 21bec5d9..0225e210 100644
--- a/src/iterators.cc
+++ b/src/iterators.cc
@@ -96,7 +96,7 @@ namespace {
TRACE_DTOR(create_price_xact);
}
- void operator()(datetime_t& date, const amount_t& price) {
+ void operator()(const datetime_t& date, const amount_t& price) {
xact_t * xact;
string symbol = price.commodity().symbol();
diff --git a/src/parser.h b/src/parser.h
index e46fc719..25c4a7e3 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -118,7 +118,7 @@ public:
ptr_op_t parse(std::istream& in,
const parse_flags_t& flags = PARSE_DEFAULT,
- const optional<string>& original_string = NULL);
+ const optional<string>& original_string = boost::none);
};
} // namespace ledger
diff --git a/src/pool.h b/src/pool.h
index 2e9d93f1..fcc54b86 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -78,8 +78,8 @@ public:
commodity_t * default_commodity;
bool keep_base; // --base
- optional<path> price_db; // --price-db=
- long quote_leeway; // --leeway=
+ optional<path> price_db; // --price-db=
+ long quote_leeway; // --leeway=
bool get_quotes; // --download
function<optional<price_point_t>
diff --git a/src/post.h b/src/post.h
index 0fb45e90..5f22fa3c 100644
--- a/src/post.h
+++ b/src/post.h
@@ -205,11 +205,7 @@ public:
mutable optional<xdata_t> xdata_;
bool has_xdata() const {
-#if BOOST_VERSION >= 105600
- return xdata_ != NULL;
-#else
- return xdata_;
-#endif
+ return static_cast<bool>(xdata_);
}
void clear_xdata() {
xdata_ = none;
diff --git a/src/pyinterp.h b/src/pyinterp.h
index 32becbf6..fe86573a 100644
--- a/src/pyinterp.h
+++ b/src/pyinterp.h
@@ -77,7 +77,7 @@ public:
if (name != "__main__")
main_module->define_global(name, mod->module_object);
return mod;
- }
+ }
python_interpreter_t() : session_t(), is_initialized(false) {
TRACE_CTOR(python_interpreter_t, "");
diff --git a/src/select.cc b/src/select.cc
index 81800f16..1141df04 100644
--- a/src/select.cc
+++ b/src/select.cc
@@ -396,7 +396,7 @@ value_t select_command(call_scope_t& args)
#if 0
query_t query;
keep_details_t keeper(true, true, true);
- expr_t::ptr_op_t expr =
+ expr_t::ptr_op_t expr =
query.parse_args(string_value(arg).to_sequence(), keeper, false, true);
report.HANDLER(limit_).on("#select", query.get_query(query_t::QUERY_LIMIT));
#else
diff --git a/src/session.cc b/src/session.cc
index 7736023d..b4fb4eb8 100644
--- a/src/session.cc
+++ b/src/session.cc
@@ -127,47 +127,14 @@ std::size_t session_t::read_data(const string& master_account)
if (HANDLED(value_expr_))
journal->value_expr = HANDLER(value_expr_).str();
- if (price_db_path) {
- if (exists(*price_db_path)) {
- parsing_context.push(*price_db_path);
- parsing_context.get_current().journal = journal.get();
- try {
- if (journal->read(parsing_context) > 0)
- throw_(parse_error, _("Transactions not allowed in price history file"));
- }
- catch (...) {
- parsing_context.pop();
- throw;
- }
- parsing_context.pop();
- }
- }
-
- foreach (const path& pathname, HANDLER(file_).data_files) {
- if (pathname == "-" || pathname == "/dev/stdin") {
- // To avoid problems with stdin and pipes, etc., we read the entire
- // file in beforehand into a memory buffer, and then parcel it out
- // from there.
- std::ostringstream buffer;
-
- while (std::cin.good() && ! std::cin.eof()) {
- char line[8192];
- std::cin.read(line, 8192);
- std::streamsize count = std::cin.gcount();
- buffer.write(line, count);
- }
- buffer.flush();
-
- shared_ptr<std::istream> stream(new std::istringstream(buffer.str()));
- parsing_context.push(stream);
- } else {
- parsing_context.push(pathname);
- }
+ if (price_db_path) {
+ if (exists(*price_db_path)) {
+ parsing_context.push(*price_db_path);
parsing_context.get_current().journal = journal.get();
- parsing_context.get_current().master = acct;
try {
- xact_count += journal->read(parsing_context);
+ if (journal->read(parsing_context) > 0)
+ throw_(parse_error, _("Transactions not allowed in price history file"));
}
catch (...) {
parsing_context.pop();
@@ -175,10 +142,44 @@ std::size_t session_t::read_data(const string& master_account)
}
parsing_context.pop();
}
+ }
+
+ foreach (const path& pathname, HANDLER(file_).data_files) {
+ if (pathname == "-" || pathname == "/dev/stdin") {
+ // To avoid problems with stdin and pipes, etc., we read the entire
+ // file in beforehand into a memory buffer, and then parcel it out
+ // from there.
+ std::ostringstream buffer;
+
+ while (std::cin.good() && ! std::cin.eof()) {
+ char line[8192];
+ std::cin.read(line, 8192);
+ std::streamsize count = std::cin.gcount();
+ buffer.write(line, count);
+ }
+ buffer.flush();
+
+ shared_ptr<std::istream> stream(new std::istringstream(buffer.str()));
+ parsing_context.push(stream);
+ } else {
+ parsing_context.push(pathname);
+ }
+
+ parsing_context.get_current().journal = journal.get();
+ parsing_context.get_current().master = acct;
+ try {
+ xact_count += journal->read(parsing_context);
+ }
+ catch (...) {
+ parsing_context.pop();
+ throw;
+ }
+ parsing_context.pop();
+ }
- DEBUG("ledger.read", "xact_count [" << xact_count
- << "] == journal->xacts.size() [" << journal->xacts.size() << "]");
- assert(xact_count == journal->xacts.size());
+ DEBUG("ledger.read", "xact_count [" << xact_count
+ << "] == journal->xacts.size() [" << journal->xacts.size() << "]");
+ assert(xact_count == journal->xacts.size());
if (populated_data_files)
HANDLER(file_).data_files.clear();
diff --git a/src/strptime.cc b/src/strptime.cc
index b64af96b..b31954f4 100644
--- a/src/strptime.cc
+++ b/src/strptime.cc
@@ -85,7 +85,7 @@ static char* _strptime(const char *s, const char *format, struct tm *tm) {
if (tm->tm_wday == -1) return NULL;
s += len;
break;
-
+
// month name.
case 'b':
case 'B':
diff --git a/src/times.h b/src/times.h
index 421d1462..e1a9e847 100644
--- a/src/times.h
+++ b/src/times.h
@@ -500,11 +500,7 @@ public:
void stabilize(const optional<date_t>& date = none);
bool is_valid() const {
-#if BOOST_VERSION >= 105600
- return start != NULL;
-#else
- return start;
-#endif
+ return static_cast<bool>(start);
}
/** Find the current or next period containing date. Returns false if
diff --git a/src/value.cc b/src/value.cc
index 2737add9..4ea7c7a8 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -341,6 +341,10 @@ value_t& value_t::operator+=(const value_t& val)
}
switch (type()) {
+ case VOID:
+ *this = value_t(val);
+ return *this;
+
case DATETIME:
switch (val.type()) {
case INTEGER:
diff --git a/src/value.h b/src/value.h
index 810d34f9..c9084e03 100644
--- a/src/value.h
+++ b/src/value.h
@@ -435,7 +435,7 @@ public:
return temp;
}
void in_place_roundto(int places);
-
+
value_t truncated() const {
value_t temp(*this);
temp.in_place_truncate();
diff --git a/src/views.h b/src/views.h
index 2be3d978..603b28da 100644
--- a/src/views.h
+++ b/src/views.h
@@ -235,7 +235,7 @@ public:
optional<string> note() const {
return ptr()->note;
}
-
+
bool has_tag(const string& tag) const {
return ptr()->has_tag(tag);
}
diff --git a/src/wcwidth.cc b/src/wcwidth.cc
index c23f83d7..75cd76be 100644
--- a/src/wcwidth.cc
+++ b/src/wcwidth.cc
@@ -195,7 +195,7 @@ int mk_wcwidth(boost::uint32_t ucs)
/* if we arrive here, ucs is not a combining or C0/C1 control character */
- return 1 +
+ return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6eb9f956..0e7d5f2c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -47,7 +47,9 @@ if (PYTHONINTERP_FOUND)
set_target_properties(check PROPERTIES DEPENDS ${_class}Test_${TestFile_Name})
endforeach()
- list(APPEND CheckOptions CheckManpage CheckTexinfo CheckBaselineTests)
+ # CheckManpage and CheckTexinfo are disabled, since they do not work
+ # reliably yet, instead they are being run as a Travis CI report.
+ list(APPEND CheckOptions CheckBaselineTests) #CheckManpage CheckTexinfo
foreach(_class ${CheckOptions})
add_test(NAME ${_class}
COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/test/${_class}.py
diff --git a/test/CheckBaselineTests.py b/test/CheckBaselineTests.py
index f0eb2646..8659d1b5 100755
--- a/test/CheckBaselineTests.py
+++ b/test/CheckBaselineTests.py
@@ -23,7 +23,6 @@ class CheckBaselineTests (CheckOptions):
'args-only',
'debug',
'download',
- 'file',
'force-color',
'force-pager',
'generated',
@@ -33,6 +32,7 @@ class CheckBaselineTests (CheckOptions):
'no-pager',
'options',
'price-exp',
+ 'revalued-total',
'seed',
'trace',
'verbose',
diff --git a/test/CheckOptions.py b/test/CheckOptions.py
index 5059a289..e4a1fdc3 100755
--- a/test/CheckOptions.py
+++ b/test/CheckOptions.py
@@ -83,7 +83,7 @@ class CheckOptions (object):
self.missing_functions.add(function)
else:
functions.remove(function)
- known_functions = ['tag', 'has_tag']
+ known_functions = ['tag', 'has_tag', 'meta', 'has_meta']
self.unknown_functions = {function for function in functions if function not in known_functions}
if len(self.missing_options):
diff --git a/test/DocTests.py b/test/DocTests.py
index ac681bc2..7af7abc3 100755
--- a/test/DocTests.py
+++ b/test/DocTests.py
@@ -108,6 +108,7 @@ class DocTests:
validate_command = False
try:
command = example[self.testin_token][self.testin_token]
+ command = re.sub(r'\\\n', '', command)
except KeyError:
if self.validate_dat_token in example:
command = '$ ledger bal'
diff --git a/test/baseline/cmd-convert.test.disable b/test/baseline/cmd-convert.test
index d444da52..8ee5bb2e 100644
--- a/test/baseline/cmd-convert.test.disable
+++ b/test/baseline/cmd-convert.test
@@ -17,7 +17,7 @@ end test
test -f /dev/null --input-date-format "%m/%d/%Y" convert test/baseline/cmd-convert3.dat -> 1
__ERROR__
-While parsing file "$sourcepath/test/baseline/cmd-convert3.dat", line 1:
+While parsing file "$sourcepath/test/baseline/cmd-convert3.dat", line 1:
While parsing CSV line:
01/01/2011,,
@@ -26,7 +26,7 @@ end test
test -f /dev/null convert test/baseline/cmd-convert4.dat -> 1
__ERROR__
-While parsing file "$sourcepath/test/baseline/cmd-convert4.dat", line 1:
+While parsing file "$sourcepath/test/baseline/cmd-convert4.dat", line 1:
While parsing CSV line:
bogus,$10,
diff --git a/test/baseline/opt-cleared-format.test b/test/baseline/opt-cleared-format.test
index e69de29b..4d3ea267 100644
--- a/test/baseline/opt-cleared-format.test
+++ b/test/baseline/opt-cleared-format.test
@@ -0,0 +1,20 @@
+test cleared --file test/input/drewr3.dat --cleared-format "%-30(account) %15(get_at(total_expr, 0)) %15(get_at(total_expr, 1))\n%/"
+Assets $ -3,804.00 $ 775.00
+Assets:Checking $ 1,396.00 $ 775.00
+Assets:Checking:Business $ 30.00 0
+Assets:Savings $ -5,200.00 0
+Equity:Opening Balances $ -1,000.00 $ -1,000.00
+Expenses $ 6,654.00 $ 225.00
+Expenses:Auto $ 5,500.00 0
+Expenses:Books $ 20.00 0
+Expenses:Escrow $ 300.00 0
+Expenses:Food:Groceries $ 334.00 $ 225.00
+Expenses:Interest:Mortgage $ 500.00 0
+Income $ -2,030.00 0
+Income:Salary $ -2,000.00 0
+Income:Sales $ -30.00 0
+Liabilities $ -63.60 0
+Liabilities:MasterCard $ -20.00 0
+Liabilities:Mortgage:Principal $ 200.00 0
+Liabilities:Tithe $ -243.60 0
+end test
diff --git a/test/baseline/opt-explicit.test b/test/baseline/opt-explicit.test
index defae179..20b74913 100644
--- a/test/baseline/opt-explicit.test
+++ b/test/baseline/opt-explicit.test
@@ -2,16 +2,18 @@ account Assets:Cash
account Expenses:Phone
account Expenses:Rent
commodity GBP
+tag bar
-2012-03-20 Phone
+2012-03-20 * Phone
+ ; :bar:
Expenses:Phone 20.00 GBP
Assets:Cash
-2012-03-21 Rent
+2012-03-21 * Rent
Expenses:Rent 550.00 GBP
Assets:Cash
-2012-03-22 Food
+2012-03-22 * Food
; :food:
Expenses:Food 20.00 EUR
Assets:Cash
@@ -27,8 +29,8 @@ test bal --explicit --strict
--------------------
0
__ERROR__
-Warning: "$FILE", line 16: Unknown account 'Expenses:Food'
-Warning: "$FILE", line 16: Unknown commodity 'EUR'
-Warning: "$FILE", line 17: Unknown metadata tag 'food'
+Warning: "$FILE", line 18: Unknown account 'Expenses:Food'
+Warning: "$FILE", line 18: Unknown commodity 'EUR'
+Warning: "$FILE", line 19: Unknown metadata tag 'food'
end test
diff --git a/test/baseline/opt-file.test.disable b/test/baseline/opt-file.test
index 66d0ab1b..66d0ab1b 100644
--- a/test/baseline/opt-file.test.disable
+++ b/test/baseline/opt-file.test
diff --git a/test/baseline/opt-generated.test b/test/baseline/opt-generated.test
deleted file mode 100644
index e69de29b..00000000
--- a/test/baseline/opt-generated.test
+++ /dev/null
diff --git a/test/baseline/opt-no-pager.test b/test/baseline/opt-no-pager.test
deleted file mode 100644
index e69de29b..00000000
--- a/test/baseline/opt-no-pager.test
+++ /dev/null
diff --git a/test/baseline/opt-no-revalued.test b/test/baseline/opt-no-revalued.test
new file mode 100644
index 00000000..487ffa30
--- /dev/null
+++ b/test/baseline/opt-no-revalued.test
@@ -0,0 +1,58 @@
+2009/01/01 Sample 1a
+ Assets:Brokerage:Stocks 100 S
+ Assets:Brokerage:Cash -100 P
+
+P 2009/01/01 00:00:00 S 2 P
+
+2009/02/01 Sample 2a
+ Assets:Brokerage:Stocks 100 S @ 1 P
+ Assets:Brokerage:Cash
+
+P 2009/02/01 00:00:00 S 4 P
+
+2009/03/01 Sample 3a
+ Assets:Brokerage:Stocks 100 S @@ 100 P
+ Assets:Brokerage:Cash
+
+P 2009/03/01 00:00:00 S 8 P
+
+2009/04/01 Sample 4a
+ Assets:Brokerage:Cash 100 P
+ Assets:Brokerage:Stocks -100 S {1 P}
+
+P 2009/04/01 00:00:00 S 16 P
+
+; In this usage case, the top amount is always secondary
+; 2010/01/01 Sample 1b
+; Assets:Brokerage:Cash -100 P
+; Assets:Brokerage:Stocks 100 S
+;
+; P 2010/01/01 00:00:00 S 2 P
+
+2010/02/01 Sample 2b
+ Assets:Brokerage:Cash
+ Assets:Brokerage:Stocks 100 S @ 1 P
+
+P 2010/02/01 00:00:00 S 4 P
+
+2010/03/01 Sample 3b
+ Assets:Brokerage:Cash
+ Assets:Brokerage:Stocks 100 S @@ 100 P
+
+P 2010/03/01 00:00:00 S 8 P
+
+2010/04/01 Sample 4b
+ Assets:Brokerage:Stocks -100 S {1 P}
+ Assets:Brokerage:Cash 100 P
+
+P 2010/04/01 00:00:00 S 16 P
+
+test reg --market --no-revalued stocks
+09-Jan-01 Sample 1a Asset:Brokerage:Stocks 200 P 200 P
+09-Feb-01 Sample 2a Asset:Brokerage:Stocks 400 P 800 P
+09-Mar-01 Sample 3a Asset:Brokerage:Stocks 800 P 2400 P
+09-Apr-01 Sample 4a Asset:Brokerage:Stocks -1600 P 3200 P
+10-Feb-01 Sample 2b Asset:Brokerage:Stocks 400 P 1200 P
+10-Mar-01 Sample 3b Asset:Brokerage:Stocks 800 P 3200 P
+10-Apr-01 Sample 4b Asset:Brokerage:Stocks -1600 P 4800 P
+end test
diff --git a/test/baseline/opt-no-rounding.test b/test/baseline/opt-no-rounding.test
index e69de29b..5d0758c6 100644
--- a/test/baseline/opt-no-rounding.test
+++ b/test/baseline/opt-no-rounding.test
@@ -0,0 +1,81 @@
+2012-01-01 * Opening balance
+ Assets:Current 17.43 EUR
+ Assets:Investments 200 "LU02" @ 24.77 EUR
+ Assets:Investments 58 "LU02" @ 24.79900855 EUR
+ Equity:Opening balance
+
+2012-01-01 * Opening balance
+ Assets:Pension 785.44 GBP
+ Assets:Pension 97.0017 "H2" @ 5.342999720204 GBP
+ Assets:Pension 4.3441 "H1" @ 5.289999915108 GBP
+ Equity:Opening balance
+
+2012-01-01 * Opening balance: misc
+ Assets:Piggy bank 3.51 GBP
+ Equity:Opening balance
+
+2012-01-01 * Opening balance
+ Assets:Rewards 9836 AAdvantage
+ Equity:Opening balance
+
+2012-01-03 * Receivable
+ Assets:Current
+ Assets:Receivable -161.06 EUR
+ Assets:Receivable -9.99 GBP @@ 11.65 EUR
+
+2012-01-27 * Test
+ Income:Test -2759.50 GBP
+ Income:Test -110.76 GBP
+ Assets:Foo 345.57 GBP
+ Expenses:Test 16.47 GBP
+ Expenses:Test 6.33 GBP
+ Expenses:Test 261.39 GBP
+ Assets:Current
+
+test reg -X EUR -H --no-rounding
+12-Jan-01 Opening balance Assets:Current 17.43 EUR 17.43 EUR
+ Assets:Investments 4959.80 EUR 4977.23 EUR
+ Assets:Investments 1438.34 EUR 6415.57 EUR
+ Equity:Opening balance -6409.77 EUR 5.80 EUR
+12-Jan-01 Opening balance Assets:Pension 785.44 GBP 5.80 EUR
+ 785.44 GBP
+ Assets:Pension 97.0017 H2 5.80 EUR
+ 785.44 GBP
+ 97.0017 H2
+ Assets:Pension 4.3441 H1 5.80 EUR
+ 785.44 GBP
+ 4.3441 H1
+ 97.0017 H2
+ Equity:Opening balance -1326.70 GBP 5.80 EUR
+ -541.26 GBP
+ 4.3441 H1
+ 97.0017 H2
+12-Jan-01 Opening balance: misc Assets:Piggy bank 3.51 GBP 5.80 EUR
+ -537.75 GBP
+ 4.3441 H1
+ 97.0017 H2
+ Equity:Opening balance -3.51 GBP 5.80 EUR
+ -541.26 GBP
+ 4.3441 H1
+ 97.0017 H2
+12-Jan-01 Opening balance Assets:Rewards 9836 AAdvantage 9836 AAdvantage
+ 5.80 EUR
+ -541.26 GBP
+ 4.3441 H1
+ 97.0017 H2
+ Equity:Opening balance -9836 AAdvantage 5.80 EUR
+ -541.26 GBP
+ 4.3441 H1
+ 97.0017 H2
+12-Jan-03 Commodities revalued <Revalued> 0 5.80 EUR
+12-Jan-03 Receivable Assets:Current 172.71 EUR 178.51 EUR
+ Assets:Receivable -161.06 EUR 17.45 EUR
+ Assets:Receivable -11.65 EUR 5.80 EUR
+12-Jan-27 Test Income:Test -3218.04 EUR -3212.23 EUR
+ Income:Test -129.16 EUR -3341.40 EUR
+ Assets:Foo 402.99 EUR -2938.41 EUR
+ Expenses:Test 19.21 EUR -2919.20 EUR
+ Expenses:Test 7.38 EUR -2911.82 EUR
+ Expenses:Test 304.82 EUR -2606.99 EUR
+ Assets:Current 2612.80 EUR 5.80 EUR
+end test
diff --git a/test/baseline/opt-value-expr.test b/test/baseline/opt-value-expr.test
index e69de29b..8b68a80e 100644
--- a/test/baseline/opt-value-expr.test
+++ b/test/baseline/opt-value-expr.test
@@ -0,0 +1,48 @@
+
+D 1000.00 EUR
+D 1000.00 USD
+D 1000.00 DM
+
+2015-01-01 * Buy 2 FOO
+ Assets:Investments 2 FOO @@ 20.00 EUR
+ Assets:Cash -20.00 EUR
+
+2015-05-01 * Spend on food
+ Expenses:Food 20.00 USD
+ ; Just to be silly, always valuate *these* $20 as 30 DM, no matter what
+ ; the user asks for with -V or -X
+ ; VALUE:: 30 DM
+ Assets:Cash -20.00 USD
+
+P 2015-05-01 USD 20 DM
+
+P 2015-06-01 USD 22 DM
+
+test bal assets:investments -V --value-expr "25.00 EUR"
+ 50.00 EUR Assets:Investments
+end test
+
+test bal assets:investments -G --value-expr "date < [March 2015] ? 22.00 EUR : 25.00 EUR" --now "2015-02-20"
+ 24.00 EUR Assets:Investments
+end test
+
+test bal assets:investments -G --value-expr "date < [March 2015] ? 22.00 EUR : 25.00 EUR" --now "2015-03-20"
+ 30.00 EUR Assets:Investments
+end test
+
+test bal expenses:food
+ 20.00 USD Expenses:Food
+end test
+
+test bal expenses:food -V
+ 600.00 DM Expenses:Food
+end test
+
+test bal expenses:food -X "DM" --now "2015-05-02"
+ 600.00 DM Expenses:Food
+end test
+
+test bal expenses:food -X "DM" --now "2015-06-02"
+ 600.00 DM Expenses:Food
+end test
+
diff --git a/test/baseline/opt-verify-memory.test b/test/baseline/opt-verify-memory.test
deleted file mode 100644
index e69de29b..00000000
--- a/test/baseline/opt-verify-memory.test
+++ /dev/null
diff --git a/test/regress/1057.test b/test/regress/1057.test
new file mode 100644
index 00000000..94d82767
--- /dev/null
+++ b/test/regress/1057.test
@@ -0,0 +1,11 @@
+2014/04/03 www.amazon.fr
+ Dépense:Loisir:Ordi:Matériel 101,50 € ; disque dur portable 2,5" 2000 Go
+ Dépense:Maison:Service:Poste
+ * Passif:Crédit:BanqueAccord -171,63 €
+
+test -f test/regress/1057.test --now=2014/06/27 emacs
+(("$sourcepath/test/regress/1057.test" 1 (21308 34912 0) nil "www.amazon.fr"
+ (2 "Dépense:Loisir:Ordi:Matériel" "101,50 €" nil " disque dur portable 2,5\" 2000 Go")
+ (3 "Dépense:Maison:Service:Poste" "70,13 €" nil)
+ (4 "Passif:Crédit:BanqueAccord" "-171,63 €" t)))
+end test
diff --git a/test/regress/25A099C9.test b/test/regress/25A099C9.test
new file mode 100644
index 00000000..cfc0eabd
--- /dev/null
+++ b/test/regress/25A099C9.test
@@ -0,0 +1,61 @@
+test -f test/garbage-input.dat reg -> 29
+__ERROR__
+While parsing file "$sourcepath/test/garbage-input.dat", line 1:
+Error: Directive '/*' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 32:
+Error: Directive '/**' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 36:
+Error: Directive '/**' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 66:
+Error: No quantity specified for amount
+While parsing file "$sourcepath/test/garbage-input.dat", line 69:
+Error: Unexpected whitespace at beginning of line
+While parsing file "$sourcepath/test/garbage-input.dat", line 78:
+Error: Directive '};' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 82:
+Error: Directive '/**' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 93:
+Error: Unexpected whitespace at beginning of line
+While parsing file "$sourcepath/test/garbage-input.dat", line 97:
+Error: Directive '{' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 98:
+Error: Directive 'public:' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 120:
+Error: Directive 'protected:' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 131:
+Error: Directive 'public:' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 711:
+Error: Unexpected whitespace at beginning of line
+While parsing file "$sourcepath/test/garbage-input.dat", line 740:
+Error: Directive 'private:' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 749:
+Error: Unexpected whitespace at beginning of line
+While parsing file "$sourcepath/test/garbage-input.dat", line 750:
+Error: Directive '};' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 752:
+Error: Invalid date/time: line amount_t amoun
+While parsing file "$sourcepath/test/garbage-input.dat", line 756:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 758:
+Error: Invalid date/time: line string amount_
+While parsing file "$sourcepath/test/garbage-input.dat", line 762:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 764:
+Error: Invalid date/time: line string amount_
+While parsing file "$sourcepath/test/garbage-input.dat", line 768:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 770:
+Error: Invalid date/time: line string amount_
+While parsing file "$sourcepath/test/garbage-input.dat", line 774:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 776:
+Error: Invalid date/time: line std::ostream&
+While parsing file "$sourcepath/test/garbage-input.dat", line 782:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 783:
+Error: Invalid date/time: line std::istream&
+While parsing file "$sourcepath/test/garbage-input.dat", line 786:
+Error: Directive '}' requires an argument
+While parsing file "$sourcepath/test/garbage-input.dat", line 789:
+Error: Unexpected whitespace at beginning of line
+end test
diff --git a/test/regress/25A099C9.test.disable b/test/regress/25A099C9.test.disable
deleted file mode 100644
index e511c799..00000000
--- a/test/regress/25A099C9.test.disable
+++ /dev/null
@@ -1,43 +0,0 @@
-test -f test/garbage-input.dat reg -> 20
-__ERROR__
-While parsing file "$sourcepath/test/garbage-input.dat", line 2:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 33:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 37:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 66:
-Error: No quantity specified for amount
-While parsing file "$sourcepath/test/garbage-input.dat", line 69:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 83:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 93:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 99:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 121:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 132:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 711:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 741:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 749:
-Error: Unexpected whitespace at beginning of line
-While parsing file "$sourcepath/test/garbage-input.dat", line 752:
-Error: Invalid date/time: line amount_t amoun
-While parsing file "$sourcepath/test/garbage-input.dat", line 758:
-Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/test/garbage-input.dat", line 764:
-Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/test/garbage-input.dat", line 770:
-Error: Invalid date/time: line string amount_
-While parsing file "$sourcepath/test/garbage-input.dat", line 776:
-Error: Invalid date/time: line std::ostream&
-While parsing file "$sourcepath/test/garbage-input.dat", line 783:
-Error: Invalid date/time: line std::istream&
-While parsing file "$sourcepath/test/garbage-input.dat", line 789:
-Error: Unexpected whitespace at beginning of line
-end test
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 23bb0ea4..de7fdd26 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -7,9 +7,16 @@ include_directories(${PROJECT_SOURCE_DIR}/src)
if (BUILD_LIBRARY)
add_executable(UtilTests t_times.cc)
+ if (CMAKE_SYSTEM_NAME STREQUAL Darwin AND HAVE_BOOST_PYTHON)
+ target_link_libraries(UtilTests ${PYTHON_LIBRARIES})
+ endif()
add_ledger_test(UtilTests)
- add_executable(MathTests t_amount.cc t_commodity.cc t_balance.cc t_expr.cc)
+ add_executable(MathTests t_amount.cc t_commodity.cc t_balance.cc t_expr.cc t_value.cc)
+ set_source_files_properties(t_amount.cc PROPERTIES COMPILE_FLAGS "-Wno-unused-comparison")
+ if (CMAKE_SYSTEM_NAME STREQUAL Darwin AND HAVE_BOOST_PYTHON)
+ target_link_libraries(MathTests ${PYTHON_LIBRARIES})
+ endif()
add_ledger_test(MathTests)
set_target_properties(check PROPERTIES DEPENDS LedgerUtilTests)
diff --git a/test/unit/t_value.cc b/test/unit/t_value.cc
new file mode 100644
index 00000000..e8367bbe
--- /dev/null
+++ b/test/unit/t_value.cc
@@ -0,0 +1,714 @@
+#define BOOST_TEST_DYN_LINK
+
+#include <boost/test/unit_test.hpp>
+
+#include <system.hh>
+
+#include "value.h"
+
+using namespace ledger;
+
+struct value_fixture {
+ value_fixture() {
+ times_initialize();
+ amount_t::initialize();
+ value_t::initialize();
+
+
+ // Cause the display precision for dollars to be initialized to 2.
+ amount_t x1("$1.00");
+ BOOST_CHECK(x1);
+
+ amount_t::stream_fullstrings = true; // make reports from UnitTests accurate
+ }
+
+ ~value_fixture()
+ {
+ amount_t::stream_fullstrings = false;
+ amount_t::shutdown();
+ times_shutdown();
+ value_t::shutdown();
+ }
+};
+
+BOOST_FIXTURE_TEST_SUITE(value, value_fixture)
+
+BOOST_AUTO_TEST_CASE(testConstructors)
+{
+ value_t::sequence_t s1;
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_t(NULL)));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(2L);
+ value_t v6(4UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("3 EUR"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("tag"), true);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testAssignment)
+{
+ value_t::sequence_t s1;
+ value_t v1;
+ value_t v2 = true;
+ value_t v3 = boost::posix_time::from_time_t(time_t(NULL));
+ value_t v4 = date_t(parse_date("2014/08/14"));
+ value_t v5 = -2L;
+ value_t v6 = 4UL;
+ value_t v7 = 1.00;
+ value_t v8 = amount_t("4 GBP");
+ value_t v9 = balance_t("3 EUR");
+ value_t v10 = mask_t("regex");
+ value_t v11 = s1;
+ value_t v12 = value_t(string("$1"));
+ value_t v13 = value_t("2 CAD");
+ value_t v14 = value_t("comment", true);
+ value_t v15 = value_t(string("tag"), true);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testEquality)
+{
+ struct tm localtime;
+ strptime("10 February 2010", "%d %b %Y", &localtime);
+ time_t time_var = mktime(&localtime);
+ value_t::sequence_t s1;
+
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_var));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(2L);
+ value_t v6(2UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+ value_t v16;
+
+ BOOST_CHECK_EQUAL(v1, value_t());
+ BOOST_CHECK_EQUAL(v2, value_t(true));
+ BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(time_var)));
+ BOOST_CHECK(!(v4 == value_t(date_t(parse_date("2014/08/15")))));
+
+ value_t v19(amount_t("2"));
+ value_t v20(balance_t("2"));
+ BOOST_CHECK_EQUAL(v5, v6);
+ BOOST_CHECK_EQUAL(v5, v19);
+ BOOST_CHECK_EQUAL(v5, v20);
+ BOOST_CHECK(v19 == v5);
+ BOOST_CHECK(v19 == v20);
+ BOOST_CHECK(v19 == value_t(amount_t("2")));
+ BOOST_CHECK(v20 == v5);
+ BOOST_CHECK(v20 == v19);
+ BOOST_CHECK(v20 == value_t(balance_t(2L)));
+ BOOST_CHECK(v14 == v15);
+ BOOST_CHECK(v10 == value_t(mask_t("regex")));
+ BOOST_CHECK(v11 == value_t(s1));
+
+ BOOST_CHECK_THROW(v8 == v10, value_error);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+ BOOST_CHECK(v19.valid());
+ BOOST_CHECK(v20.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testSequence)
+{
+ value_t::sequence_t s1;
+ value_t v1(s1);
+ BOOST_CHECK(v1.is_sequence());
+ v1.push_back(value_t(2L));
+ v1.push_back(value_t("3 GBP"));
+
+ value_t v2("3 GBP");
+ value_t seq(v1);
+ const value_t v3(seq);
+
+ value_t::sequence_t::iterator i = std::find(seq.begin(), seq.end(), v2);
+ if (i != seq.end())
+ BOOST_CHECK(v2 == *i);
+
+ value_t::sequence_t::const_iterator j = std::find(v3.begin(), v3.end(), v2);
+ if (j != v3.end())
+ BOOST_CHECK(v2 == *j);
+
+ BOOST_CHECK(v2 == seq[1]);
+ BOOST_CHECK(v2 == v3[1]);
+ v1.pop_back();
+ v1.pop_back();
+ v1.push_front(v2);
+ v1.push_front(value_t(2L));
+ BOOST_CHECK(v2 == v1[1]);
+ BOOST_CHECK(seq == v1);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(seq.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testAddition)
+{
+ struct tm localtime;
+ strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime);
+ time_t time_var = mktime(&localtime);
+ value_t::sequence_t s1;
+
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_var));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(2L);
+ value_t v6(2UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+ value_t v16(amount_t("2"));
+
+ v14 += v15;
+ BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment"), true));
+ v14 += v12;
+ BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment$1.00"), true));
+
+ v3 += value_t(2L);
+ strptime("10 February 2010 00:00:02", "%d %b %Y %H:%M:%S", &localtime);
+ BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime))));
+ v3 += value_t(amount_t("2"));
+ strptime("10 February 2010 00:00:04", "%d %b %Y %H:%M:%S", &localtime);
+ BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime))));
+
+ v4 += value_t(2L);
+ BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/16"))));
+ v4 += value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/18"))));
+
+ v5 += value_t(2L);
+ BOOST_CHECK_EQUAL(v5, value_t(4L));
+ v5 += value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v5, value_t(amount_t("6")));
+ v5 += v8;
+
+ v16 += value_t(2L);
+ v16 += value_t(amount_t("2"));
+ v16 += v8;
+ BOOST_CHECK_EQUAL(v5, v16);
+
+ v8 += value_t("6");
+ BOOST_CHECK_EQUAL(v8, v16);
+
+ value_t v17(6L);
+ v17 += value_t(amount_t("4 GBP"));
+ BOOST_CHECK_EQUAL(v8, v17);
+
+ value_t v18(6L);
+ v18 += v9;
+ value_t v19(amount_t("6"));
+ v19 += v9;
+ BOOST_CHECK_EQUAL(v18, v19);
+
+ v9 += value_t(2L);
+ v9 += value_t(amount_t("4"));
+ v9 += v19;
+ v18 += v19;
+ BOOST_CHECK_EQUAL(v9, v18);
+
+ value_t v20(s1);
+ v11 += value_t(2L);
+ v11 += value_t("4 GBP");
+ BOOST_CHECK_THROW(v11 += v20,value_error);
+ BOOST_CHECK_THROW(v10 += v8, value_error);
+
+ v20 += value_t(2L);
+ v20 += value_t("4 GBP");
+ BOOST_CHECK_EQUAL(v11, v20);
+ v11 += v20;
+ v20 += v20;
+ BOOST_CHECK_EQUAL(v11, v20);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+ BOOST_CHECK(v16.valid());
+ BOOST_CHECK(v17.valid());
+ BOOST_CHECK(v18.valid());
+ BOOST_CHECK(v19.valid());
+ BOOST_CHECK(v20.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testSubtraction)
+{
+ struct tm localtime;
+ strptime("10 February 2010 00:00:04", "%d %b %Y %H:%M:%S", &localtime);
+ time_t time_var = mktime(&localtime);
+ value_t::sequence_t s1;
+
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_var));
+ value_t v4(date_t(parse_date("2014/08/18")));
+ value_t v5(6L);
+ value_t v6(6UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+ value_t v16(amount_t("6"));
+
+ v3 -= value_t(2L);
+ strptime("10 February 2010 00:00:02", "%d %b %Y %H:%M:%S", &localtime);
+ BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime))));
+ v3 -= value_t(amount_t("2"));
+ strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime);
+ BOOST_CHECK_EQUAL(v3, value_t(boost::posix_time::from_time_t(mktime(&localtime))));
+
+ v4 -= value_t(2L);
+ BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/16"))));
+ v4 -= value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v4, value_t(date_t(parse_date("2014/08/14"))));
+
+ v5 -= value_t(2L);
+ BOOST_CHECK_EQUAL(v5, value_t(4L));
+ v5 -= value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v5, value_t(amount_t("2")));
+ v5 -= v8;
+
+ v16 -= value_t(2L);
+ v16 -= value_t(amount_t("2"));
+ v16 -= v8;
+ BOOST_CHECK_EQUAL(v5, v16);
+
+ v8 -= value_t("2");
+ BOOST_CHECK_EQUAL(-v8, v16);
+
+ value_t v18(6L);
+ v18 -= v9;
+ value_t v19(amount_t("6"));
+ v19 -= v9;
+ BOOST_CHECK_EQUAL(v18, v19);
+
+ v9 -= value_t(-2L);
+ v9 -= value_t(amount_t("-10"));
+ v9 -= value_t(amount_t("12 GBP"));
+ v9 -= v19;
+ BOOST_CHECK_EQUAL(v9, v18);
+ v18 -=v19;
+ BOOST_CHECK_EQUAL(v18, value_t("0"));
+
+ value_t v20(s1);
+ value_t v21(2L);
+ value_t v22("4 GBP");
+ v11.push_back(v21);
+ v11.push_back(v22);
+ BOOST_CHECK_THROW(v11 -= v20,value_error);
+ BOOST_CHECK_THROW(v10 -= v8, value_error);
+
+ v20.push_back(v21);
+ v20.push_back(v22);
+ v11 -= v20;
+ value_t v23(s1);
+ v23.push_back(value_t(0L));
+ v23.push_back(value_t("0"));
+ BOOST_CHECK_EQUAL(v11, v23);
+ v20 -= v21;
+ v20 -= v22;
+ BOOST_CHECK_EQUAL(v20, value_t(s1));
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+ BOOST_CHECK(v16.valid());
+ BOOST_CHECK(v18.valid());
+ BOOST_CHECK(v19.valid());
+ BOOST_CHECK(v20.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testMultiplication)
+{
+ struct tm localtime;
+ strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime);
+ time_t time_var = mktime(&localtime);
+ value_t::sequence_t s1;
+
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_var));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(2L);
+ value_t v6(2UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+ value_t v16(amount_t("2"));
+
+ v14 *= value_t(2L);
+ BOOST_CHECK_EQUAL(v14, value_t(string("commentcomment"), true));
+
+ v5 *= value_t(2L);
+ BOOST_CHECK_EQUAL(v5, value_t(4L));
+ v5 *= value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v5, value_t(amount_t("8")));
+
+ v16 *= value_t(2L);
+ v16 *= value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v5, v16);
+
+ v8 *= v9;
+ BOOST_CHECK_EQUAL(v8, value_t("16 GBP"));
+
+ value_t v17(v9);
+ v9 *= value_t(2L);
+ BOOST_CHECK_EQUAL(v9, value_t("8 GBP"));
+ v17 += value_t(2L);
+ v17 *= value_t(2L);
+ value_t v18("8 GBP");
+ v18 += value_t(4L);
+ BOOST_CHECK_EQUAL(v17, v18);
+
+ value_t v20(s1);
+ v11.push_back(value_t(2L));
+ v11.push_back(value_t("2 GBP"));
+ v20.push_back(value_t(4L));
+ v20.push_back(value_t("4 GBP"));
+ v11 *= value_t(2L);
+ BOOST_CHECK_EQUAL(v11 ,v20);
+
+ BOOST_CHECK_THROW(v10 *= v8, value_error);
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+ BOOST_CHECK(v16.valid());
+ BOOST_CHECK(v17.valid());
+ BOOST_CHECK(v18.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testDivision)
+{
+ struct tm localtime;
+ strptime("10 February 2010 00:00:00", "%d %b %Y %H:%M:%S", &localtime);
+ time_t time_var = mktime(&localtime);
+ value_t::sequence_t s1;
+
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_var));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(8L);
+ value_t v6(2UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+ value_t v16(amount_t("8"));
+
+ v5 /= value_t(2L);
+ BOOST_CHECK_EQUAL(v5, value_t(4L));
+ v5 /= value_t(amount_t("8"));
+ BOOST_CHECK_EQUAL(v5, value_t(amount_t("2")));
+
+ v16 /= value_t(2L);
+ v16 /= value_t(amount_t("2"));
+ BOOST_CHECK_EQUAL(v5, v16);
+
+ v8 /= v9;
+ v8 /= value_t(balance_t(2L));
+ BOOST_CHECK_EQUAL(v8, value_t("0.5 GBP"));
+
+ value_t v17(v9);
+ v9 /= value_t(2L);
+ BOOST_CHECK_EQUAL(v9, value_t("2 GBP"));
+ v17 /= value_t("2 GBP");
+ v17 /= value_t("2");
+ BOOST_CHECK_EQUAL(v17, value_t(balance_t("1 GBP")));
+
+ BOOST_CHECK_THROW(v10 /= v8, value_error);
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+ BOOST_CHECK(v16.valid());
+ BOOST_CHECK(v17.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testType)
+{
+ value_t::sequence_t s1;
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_t(NULL)));
+ value_t v4(date_t(parse_date("2014/08/14")));
+ value_t v5(2L);
+ value_t v6(4UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("3 EUR"));
+ value_t v10(mask_t("regex"));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string("tag"), true);
+
+ BOOST_CHECK(v1.is_null());
+ BOOST_CHECK(v2.is_boolean());
+ BOOST_CHECK(v3.is_datetime());
+ BOOST_CHECK(v4.is_date());
+ BOOST_CHECK(v5.is_long());
+ BOOST_CHECK(v6.is_amount());
+ BOOST_CHECK(v7.is_amount());
+ BOOST_CHECK(v8.is_amount());
+ BOOST_CHECK(v9.is_balance());
+ BOOST_CHECK(v10.is_mask());
+ BOOST_CHECK(v11.is_sequence());
+ BOOST_CHECK(v12.is_amount());
+ BOOST_CHECK(v13.is_amount());
+ BOOST_CHECK(v14.is_string());
+ BOOST_CHECK(v15.is_string());
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testForZero)
+{
+ value_t::sequence_t s1;
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_t(NULL)));
+ value_t v4(date_t(0));
+ value_t v5(2L);
+ value_t v6(0UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("0"));
+ value_t v10(mask_t(""));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("2 CAD");
+ value_t v14("comment", true);
+ value_t v15(string(""), true);
+
+ BOOST_CHECK(v1.is_null());
+ BOOST_CHECK(v2.is_nonzero());
+ BOOST_CHECK(!v3.is_zero());
+ BOOST_CHECK(v4.is_nonzero());
+ BOOST_CHECK(v5.is_nonzero());
+ BOOST_CHECK(v6.is_realzero());
+ BOOST_CHECK(v7.is_nonzero());
+ BOOST_CHECK(v8.is_nonzero());
+ BOOST_CHECK(v9.is_zero());
+ BOOST_CHECK_THROW(v10.is_zero(), value_error);
+ BOOST_CHECK(v11.is_zero());
+ BOOST_CHECK(v12.is_nonzero());
+ BOOST_CHECK(v13.is_nonzero());
+ BOOST_CHECK(v14.is_nonzero());
+ BOOST_CHECK(v15.is_zero());
+
+ v11.push_back(v6);
+ BOOST_CHECK(v11.is_nonzero());
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+}
+
+BOOST_AUTO_TEST_CASE(testNegation)
+{
+ value_t::sequence_t s1;
+ value_t v1;
+ value_t v2(true);
+ value_t v3(boost::posix_time::from_time_t(time_t(NULL)));
+ value_t v4(date_t(parse_date("2014/08/09")));
+ value_t v5(2L);
+ value_t v6(0UL);
+ value_t v7(1.00);
+ value_t v8(amount_t("4 GBP"));
+ value_t v9(balance_t("4 GBP"));
+ value_t v10(mask_t(""));
+ value_t v11(s1);
+ value_t v12(string("$1"));
+ value_t v13("$-1");
+ value_t v14("comment", true);
+ value_t v15(string("comment"), true);
+
+ BOOST_CHECK_THROW(v1.negated(), value_error);
+ BOOST_CHECK_EQUAL(v2.negated(), value_t(false));
+ v5.in_place_negate();
+ BOOST_CHECK_EQUAL(v5, value_t(-2L));
+ v8.in_place_negate();
+ v9.in_place_negate();
+ BOOST_CHECK_EQUAL(v8, v9);
+ BOOST_CHECK_THROW(v10.negated(), value_error);
+ BOOST_CHECK_EQUAL(-v12, v13);
+ BOOST_CHECK_THROW(-v14, value_error);
+
+ BOOST_CHECK(v1.valid());
+ BOOST_CHECK(v2.valid());
+ BOOST_CHECK(v3.valid());
+ BOOST_CHECK(v4.valid());
+ BOOST_CHECK(v5.valid());
+ BOOST_CHECK(v6.valid());
+ BOOST_CHECK(v7.valid());
+ BOOST_CHECK(v8.valid());
+ BOOST_CHECK(v9.valid());
+ BOOST_CHECK(v10.valid());
+ BOOST_CHECK(v11.valid());
+ BOOST_CHECK(v12.valid());
+ BOOST_CHECK(v13.valid());
+ BOOST_CHECK(v14.valid());
+ BOOST_CHECK(v15.valid());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/tools/travis-before_install.sh b/tools/travis-before_install.sh
new file mode 100755
index 00000000..fe010945
--- /dev/null
+++ b/tools/travis-before_install.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+#set -x
+set -e
+set -o pipefail
+
+if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
+ brew update
+fi
+
+if [ -n "${BOOST_VERSION}" ]; then
+ mkdir -p $BOOST_ROOT
+ wget --no-verbose --output-document=- \
+ http://sourceforge.net/projects/boost/files/boost/${BOOST_VERSION}/boost_${BOOST_VERSION//./_}.tar.bz2/download \
+ | tar jxf - --strip-components=1 -C "${BOOST_ROOT}"
+fi
diff --git a/tools/travis-install.sh b/tools/travis-install.sh
new file mode 100755
index 00000000..4e8bdc48
--- /dev/null
+++ b/tools/travis-install.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+#set -x
+set -e
+set -o pipefail
+
+if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
+ for formula in $(echo "${BREWS//,/ }"); do
+ echo "Checking ${formula} formula"
+ brew outdated "${formula}" \
+ || (brew unlink "${formula}"
+ brew install "${formula}"
+ )
+ done
+fi
+
+if [ -d "${BOOST_ROOT}" ]; then
+ (cd "${BOOST_ROOT}"
+ ./bootstrap.sh --with-libraries="${BOOST_LIBS}"
+ ./b2 threading=multi --prefix="${BOOST_ROOT}" -d0 install
+ )
+fi