summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--.travis.yml11
-rw-r--r--CMakeLists.txt16
-rwxr-xr-xacprep10
-rw-r--r--cmake/FindUtfcpp.cmake30
-rw-r--r--doc/ledger3.texi9
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.txt8
-rw-r--r--src/emacs.h2
-rw-r--r--src/history.cc2
-rw-r--r--src/pool.h4
-rw-r--r--src/pyinterp.h2
-rw-r--r--src/select.cc2
-rw-r--r--src/strptime.cc2
-rw-r--r--src/value.cc4
-rw-r--r--src/value.h2
-rw-r--r--src/views.h2
-rw-r--r--src/wcwidth.cc2
-rwxr-xr-xtest/CheckBaselineTests.py2
-rw-r--r--test/baseline/cmd-convert.test (renamed from test/baseline/cmd-convert.test.disable)4
-rw-r--r--test/baseline/opt-file.test (renamed from test/baseline/opt-file.test.disable)0
-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.txt2
-rw-r--r--test/unit/t_value.cc714
34 files changed, 1865 insertions, 78 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 06ead752..98b0ab82 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -27,6 +27,8 @@ env:
- 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:
@@ -47,6 +49,13 @@ matrix:
# 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
@@ -84,7 +93,7 @@ before_script:
- make
script:
- - make test
+ - ctest --output-on-failure
- PYTHONPATH=. python python/demo.py
after_script:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3c8c36ef..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)
@@ -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/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/ledger3.texi b/doc/ledger3.texi
index 72c1165d..14a71778 100644
--- a/doc/ledger3.texi
+++ b/doc/ledger3.texi
@@ -7914,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.
@@ -8153,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 8ed6e51a..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)
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/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/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/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/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/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/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/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-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/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 b440d2ed..de7fdd26 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -12,7 +12,7 @@ if (BUILD_LIBRARY)
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})
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()
+