diff options
author | John Wiegley <johnw@newartisans.com> | 2009-10-25 21:27:56 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2009-10-25 21:27:56 -0400 |
commit | 9dadaebfeb461ba795124281018d0f7eac200cf4 (patch) | |
tree | 941243868b1dcacd68cbd52a2f96e40bf70a5d3b | |
parent | f35bc939c96c3a3bf09c5881d638b5ba60449c03 (diff) | |
parent | e696bfd913a10edd19f9e35eb1aee2c97b11e7f6 (diff) | |
download | fork-ledger-9dadaebfeb461ba795124281018d0f7eac200cf4.tar.gz fork-ledger-9dadaebfeb461ba795124281018d0f7eac200cf4.tar.bz2 fork-ledger-9dadaebfeb461ba795124281018d0f7eac200cf4.zip |
Merge branch 'next'
57 files changed, 834 insertions, 602 deletions
diff --git a/Makefile.am b/Makefile.am index 8ed18fbb..2556e1df 100644 --- a/Makefile.am +++ b/Makefile.am @@ -136,7 +136,6 @@ pkginclude_HEADERS = \ \ src/pyinterp.h \ \ - lib/fdstream.h \ lib/sha1.h \ lib/gettext.h \ \ @@ -192,7 +192,6 @@ class PrepareBuild(CommandLineApp): self.envvars = { 'PYTHON_HOME': '/usr', 'PYTHON_VERSION': '2.5', - 'BOOST_VERSION': None, 'BOOST_SUFFIX': None, 'BOOST_HOME': '/usr', 'LEDGER_PRODUCTS': None, @@ -520,12 +519,17 @@ class PrepareBuild(CommandLineApp): if exists('/opt/local/bin/port'): self.log.info('Looks like you are using MacPorts on OS X') packages = [ - 'sudo', 'port', 'install', - 'boost', '+python25+debug+st', - 'gmp', 'mpfr', 'gettext', - 'libedit', 'cppunit', - #'texlive', 'doxygen', 'graphviz', 'texinfo', - 'lcov', 'sloccount' + 'sudo', 'port', 'install', '-f', + 'automake', 'autoconf', 'libtool', + 'python26', 'boost-jam', + 'libiconv', '+universal', 'zlib', '+universal', + 'gmp' ,'+universal', 'mpfr', '+universal', + 'ncurses', '+universal', 'ncursesw', '+universal', + 'gettext' ,'+universal', 'libedit' ,'+universal', + 'boost', '+universal+st+debug+python26+doc', + 'cppunit' ,'+universal', + 'texlive', 'doxygen', 'graphviz', 'texinfo', + 'lcov', 'sloccount' ] self.log.info('Executing: ' + string.join(packages, ' ')) self.execute(*packages) @@ -624,7 +628,6 @@ class PrepareBuild(CommandLineApp): self.execute('make', 'BOOST_SOURCE=%s' % boost, - 'BOOST_VERSION=%s' % environ['BOOST_VERSION'], 'CC=%s' % environ['CC'], 'CXX=%s' % environ['CXX'], 'LD=%s' % environ['LD'], @@ -649,14 +652,6 @@ class PrepareBuild(CommandLineApp): suffix = match.group(1) self.log.debug('Found Boost suffix => ' + suffix) self.envvars['BOOST_HOME'] = dirname(path) - - match = re.search('[0-9]+_[0-9]+', suffix) - if match: - version = match.group(0) - self.log.debug('Found Boost version in suffix => ' + - version) - if not self.envvars['BOOST_VERSION']: - self.envvars['BOOST_VERSION'] = version return suffix else: self.log.debug('The directory "%s" is not valid, skipping' % @@ -678,8 +673,6 @@ class PrepareBuild(CommandLineApp): self.log.debug('Boost is located here:') self.log.debug('BOOST_HOME => ' + self.envvars['BOOST_HOME']) - self.log.debug('BOOST_VERSION => ' + - str(self.envvars['BOOST_VERSION'])) self.log.debug('BOOST_SUFFIX => ' + suffix) break if suffix is None: @@ -692,9 +685,8 @@ class PrepareBuild(CommandLineApp): # Each of these becomes '-isystem <name>' for path in ['/usr/local/include', - '%s/include/boost-%s' % - (self.envvars['BOOST_HOME'], - self.envvars['BOOST_VERSION']), + '%s/include/boost' % + self.envvars['BOOST_HOME'], '%s/include' % self.envvars['BOOST_HOME'], '%s/include/python%s' % (self.envvars['PYTHON_HOME'], @@ -737,7 +729,7 @@ class PrepareBuild(CommandLineApp): self.log.debug('System type is => ' + system) # These options are global defaults at the moment - self.option_warn() + #self.option_warn() if not self.no_pch: self.option_pch() @@ -780,8 +772,8 @@ class PrepareBuild(CommandLineApp): self.option_no_pch() if '--enable-pch' not in self.configure_args and \ - exists('/opt/local/bin/ccache') or \ - exists('/usr/local/bin/ccache'): + (exists('/opt/local/bin/ccache') or \ + exists('/usr/local/bin/ccache')): self.envvars['CC'] = 'ccache ' + self.envvars['CC'] self.envvars['CXX'] = 'ccache ' + self.envvars['CXX'] self.envvars['LD'] = 'ccache ' + self.envvars['LD'] @@ -877,6 +869,8 @@ class PrepareBuild(CommandLineApp): def option_warn(self, option=None, opt_str=None, value=None, parser=None): self.log.debug('Saw option --warn') self.CXXFLAGS.append('-ansi') + self.CXXFLAGS.append('-pedantic') + self.CXXFLAGS.append('-pedantic-errors') self.CXXFLAGS.append('-Wall') self.CXXFLAGS.append('-Winvalid-pch') self.CXXFLAGS.append('-Wextra') @@ -892,6 +886,7 @@ class PrepareBuild(CommandLineApp): self.CXXFLAGS.append('-Wwrite-strings') self.CXXFLAGS.append('-Wno-old-style-cast') self.CXXFLAGS.append('-Wno-deprecated') + self.CXXFLAGS.append('-Werror') def option_boost(self, option=None, opt_str=None, value=None, parser=None): self.log.debug('Saw option --boost') @@ -939,60 +934,73 @@ class PrepareBuild(CommandLineApp): self.CXXFLAGS.append('-g') self.LDFLAGS.append('-g') - if not self.options.use_glibcxx_debug: - return + if self.options.use_glibcxx_debug: + self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags') - self.log.debug('We are using GLIBCXX_DEBUG, so setting up flags') + self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1') - self.CPPFLAGS.append('-D_GLIBCXX_DEBUG=1') + if exists('/usr/local/stow/cppunit-debug/include'): + if '/usr/local/stow/cppunit/include' in self.sys_include_dirs: + self.sys_include_dirs.remove('/usr/local/stow/cppunit/include') + self.sys_library_dirs.remove('/usr/local/stow/cppunit/lib') - if exists('/usr/local/stow/cppunit-debug/include'): - if '/usr/local/stow/cppunit/include' in self.sys_include_dirs: - self.sys_include_dirs.remove('/usr/local/stow/cppunit/include') - self.sys_library_dirs.remove('/usr/local/stow/cppunit/lib') + self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit-debug/include') + self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit-debug/lib') - self.sys_include_dirs.insert(0, '/usr/local/stow/cppunit-debug/include') - self.sys_library_dirs.insert(0, '/usr/local/stow/cppunit-debug/lib') + if exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_40.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-sd-1_40' + self.log.debug('Setting BOOST_SUFFIX => %s' % + self.envvars['BOOST_SUFFIX']) - if exists('/usr/local/lib/libboost_regex-xgcc44-sd-1_40.a'): - self.envvars['BOOST_HOME'] = '/usr/local' - self.envvars['BOOST_SUFFIX'] = '-xgcc44-sd-1_40' - self.envvars['BOOST_VERSION'] = '1_40' + self.sys_include_dirs.append('/usr/local/include/boost-1_40') - self.log.debug('Setting BOOST_SUFFIX => %s' % - self.envvars['BOOST_SUFFIX']) - self.log.debug('Setting BOOST_VERSION => %s' % - self.envvars['BOOST_VERSION']) + elif exists('/opt/local/lib/libboost_regex-d.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '-d' - self.sys_include_dirs.append('/usr/local/include/boost-1_40') + self.log.debug('Setting BOOST_SUFFIX => %s' % + self.envvars['BOOST_SUFFIX']) - elif exists('/usr/local/lib/libboost_regex-xgcc43-sd-1_40.a'): - self.envvars['BOOST_HOME'] = '/usr/local' - self.envvars['BOOST_SUFFIX'] = '-xgcc43-sd-1_40' - self.envvars['BOOST_VERSION'] = '1_40' + self.sys_include_dirs.append('/opt/local/include/boost') + else: + if exists('/usr/local/lib/libboost_regex-xgcc44-s-1_40.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40' + self.log.debug('Setting BOOST_SUFFIX => %s' % + self.envvars['BOOST_SUFFIX']) + + self.sys_include_dirs.append('/usr/local/include/boost-1_40') + + elif exists('/opt/local/lib/libboost_regex.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '' + self.log.debug('Setting BOOST_SUFFIX => %s' % + self.envvars['BOOST_SUFFIX']) + + self.sys_include_dirs.append('/opt/local/include/boost') + + def setup_flavor_opt(self): + self.CXXFLAGS.append('-O3') + self.CXXFLAGS.append('-fomit-frame-pointer') + + if exists('/usr/local/lib/libboost_regex-xgcc44-s-1_40.a'): + self.envvars['BOOST_HOME'] = '/usr/local' + self.envvars['BOOST_SUFFIX'] = '-xgcc44-s-1_40' self.log.debug('Setting BOOST_SUFFIX => %s' % self.envvars['BOOST_SUFFIX']) - self.log.debug('Setting BOOST_VERSION => %s' % - self.envvars['BOOST_VERSION']) self.sys_include_dirs.append('/usr/local/include/boost-1_40') - elif exists('/usr/local/lib/libboost_regex-xgcc42-sd-1_40.a'): - self.envvars['BOOST_HOME'] = '/usr/local' - self.envvars['BOOST_SUFFIX'] = '-xgcc42-sd-1_40' - self.envvars['BOOST_VERSION'] = '1_40' + elif exists('/opt/local/lib/libboost_regex.a'): + self.envvars['BOOST_HOME'] = '/opt/local' + self.envvars['BOOST_SUFFIX'] = '' self.log.debug('Setting BOOST_SUFFIX => %s' % self.envvars['BOOST_SUFFIX']) - self.log.debug('Setting BOOST_VERSION => %s' % - self.envvars['BOOST_VERSION']) - self.sys_include_dirs.append('/usr/local/include/boost-1_40') - - def setup_flavor_opt(self): - self.CXXFLAGS.append('-O3') - self.CXXFLAGS.append('-fomit-frame-pointer') + self.sys_include_dirs.append('/opt/local/include/boost') def setup_flavor_gcov(self): self.CXXFLAGS.append('-g') @@ -1122,6 +1130,7 @@ class PrepareBuild(CommandLineApp): def phase_config(self, *args): self.log.debug('Executing phase: config') + self.phase_submodule() self.phase_autoconf() self.phase_configure(*args) if self.should_clean: diff --git a/configure.ac b/configure.ac index c45ff636..ad1c4b37 100644 --- a/configure.ac +++ b/configure.ac @@ -88,7 +88,7 @@ AC_CACHE_CHECK( if (status < 0) { ; } else if (status == 0) { - char *arg0; + char *arg0 = NULL; status = dup2(pfd[0], STDIN_FILENO); @@ -160,8 +160,8 @@ AC_CACHE_CHECK( [[#include <stdlib.h> #include <stdio.h> #include <editline/readline.h>]], - [[rl_readline_name = "foo"; - char * line = readline("foo: "); + [[rl_readline_name = const_cast<char *>("foo"); + char * line = readline(const_cast<char *>("foo: ")); free(line);]])],[libedit_avail_cv_=true],[libedit_avail_cv_=false]) AC_LANG_POP LIBS=$libedit_save_libs]) @@ -255,6 +255,31 @@ else AC_MSG_FAILURE("Could not find boost_filesystem library (set CPPFLAGS and LDFLAGS?)") fi +# check for boost_iostreams +AC_CACHE_CHECK( + [if boost_iostreams is available], + [boost_iostreams_cpplib_avail_cv_], + [boost_iostreams_save_libs=$LIBS + LIBS="-lboost_iostreams$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS" + AC_LANG_PUSH(C++) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[#include <boost/iostreams/device/file_descriptor.hpp> + #include <boost/iostreams/stream.hpp>]], + [[namespace io = boost::iostreams; + typedef io::stream<io::file_descriptor_sink> ofdstream; + ofdstream outstream(1);]])], + [boost_iostreams_cpplib_avail_cv_=true], + [boost_iostreams_cpplib_avail_cv_=false]) + AC_LANG_POP + LIBS=$boost_iostreams_save_libs]) + +if [test x$boost_iostreams_cpplib_avail_cv_ = xtrue ]; then + LIBS="-lboost_iostreams$BOOST_SUFFIX -lboost_system$BOOST_SUFFIX $LIBS" +else + AC_MSG_FAILURE("Could not find boost_iostreams library (set CPPFLAGS and LDFLAGS?)") +fi + # check for Python AM_PATH_PYTHON(2.4,, :) if [test "$PYTHON" != :]; then diff --git a/lib/Makefile b/lib/Makefile index 709358df..6b46b422 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -47,4 +47,4 @@ cppunit-debug: cppunit-build: cppunit-release cppunit-debug -build-all: cppunit-build boost-build +build-all: boost-build cppunit-build diff --git a/lib/fdstream.h b/lib/fdstream.h deleted file mode 100644 index 526c9f53..00000000 --- a/lib/fdstream.h +++ /dev/null @@ -1,184 +0,0 @@ -/* The following code declares classes to read from and write to - * file descriptore or file handles. - * - * See - * http://www.josuttis.com/cppcode - * for details and the latest version. - * - * - open: - * - integrating BUFSIZ on some systems? - * - optimized reading of multiple characters - * - stream for reading AND writing - * - i18n - * - * (C) Copyright Nicolai M. Josuttis 2001. - * Permission to copy, use, modify, sell and distribute this software - * is granted provided this copyright notice appears in all copies. - * This software is provided "as is" without express or implied - * warranty, and with no claim as to its suitability for any purpose. - * - * Version: Jul 28, 2002 - * History: - * Jul 28, 2002: bugfix memcpy() => memmove() - * fdinbuf::underflow(): cast for return statements - * Aug 05, 2001: first public version - */ -#ifndef BOOST_FDSTREAM_HPP -#define BOOST_FDSTREAM_HPP - -#include <istream> -#include <ostream> -#include <streambuf> -// for EOF: -#include <cstdio> -// for memmove(): -#include <cstring> - - -// low-level read and write functions -#ifdef _MSC_VER -# include <io.h> -#else -# include <unistd.h> -//extern "C" { -// int write (int fd, const char* buf, int num); -// int read (int fd, char* buf, int num); -//} -#endif - - -// BEGIN namespace BOOST -namespace boost { - - -/************************************************************ - * fdostream - * - a stream that writes on a file descriptor - ************************************************************/ - - -class fdoutbuf : public std::streambuf { - protected: - int fd; // file descriptor - public: - // constructor - fdoutbuf (int _fd) : fd(_fd) { - } - protected: - // write one character - virtual int_type overflow (int_type c) { - if (c != EOF) { - char z = static_cast<char>(c); - if (write (fd, &z, 1) != 1) { - return EOF; - } - } - return c; - } - // write multiple characters - virtual - std::streamsize xsputn (const char* s, - std::streamsize num) { - return write(fd,s,num); - } -}; - -class fdostream : public std::ostream { - protected: - fdoutbuf buf; - public: - fdostream (int fd) : std::ostream(0), buf(fd) { - rdbuf(&buf); - } -}; - - -/************************************************************ - * fdistream - * - a stream that reads on a file descriptor - ************************************************************/ - -class fdinbuf : public std::streambuf { - protected: - int fd; // file descriptor - protected: - /* data buffer: - * - at most, pbSize characters in putback area plus - * - at most, bufSize characters in ordinary read buffer - */ - static const int pbSize = 4; // size of putback area - static const int bufSize = 1024; // size of the data buffer - char buffer[bufSize+pbSize]; // data buffer - - public: - /* constructor - * - initialize file descriptor - * - initialize empty data buffer - * - no putback area - * => force underflow() - */ - fdinbuf (int _fd) : fd(_fd) { - setg (buffer+pbSize, // beginning of putback area - buffer+pbSize, // read position - buffer+pbSize); // end position - } - - protected: - // insert new characters into the buffer - virtual int_type underflow () { -#ifndef _MSC_VER - using std::memmove; -#endif - - // is read position before end of buffer? - if (gptr() < egptr()) { - return traits_type::to_int_type(*gptr()); - } - - /* process size of putback area - * - use number of characters read - * - but at most size of putback area - */ - std::streamsize numPutback; - numPutback = gptr() - eback(); - if (numPutback > pbSize) { - numPutback = pbSize; - } - - /* copy up to pbSize characters previously read into - * the putback area - */ - memmove (buffer+(pbSize-numPutback), gptr()-numPutback, - numPutback); - - // read at most bufSize new characters - ssize_t num; - num = read (fd, buffer+pbSize, bufSize); - if (num <= 0) { - // ERROR or EOF - return EOF; - } - - // reset buffer pointers - setg (buffer+(pbSize-numPutback), // beginning of putback area - buffer+pbSize, // read position - buffer+pbSize+num); // end of buffer - - // return next character - return traits_type::to_int_type(*gptr()); - } -}; - -class fdistream : public std::istream { - protected: - fdinbuf buf; - public: - fdistream (int fd) : std::istream(0), buf(fd) { - rdbuf(&buf); - } -}; - - -} // END namespace boost - -#endif /*BOOST_FDSTREAM_HPP*/ diff --git a/src/accum.cc b/src/accum.cc index d01d0e52..b918c76a 100644 --- a/src/accum.cc +++ b/src/accum.cc @@ -53,7 +53,7 @@ std::streamsize straccbuf::xsputn(const char * s, std::streamsize num) if (*p == '%') { const char * q = p + 1; if (*q && *q != '%' && std::isdigit(*q) && - std::size_t(*q - '0') == index) { + std::string::size_type(*q - '0') == index) { p++; buf << std::string(s, num); matched = true; diff --git a/src/accum.h b/src/accum.h index caf87d28..c29926d5 100644 --- a/src/accum.h +++ b/src/accum.h @@ -56,8 +56,8 @@ namespace ledger { class straccbuf : public std::streambuf { protected: - std::string str; // accumulator - std::size_t index; + std::string str; // accumulator + std::string::size_type index; public: straccbuf() : index(0) {} diff --git a/src/amount.cc b/src/amount.cc index 2434f110..5aa985c8 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -623,9 +623,9 @@ namespace { "mpfr_print = " << buf << " (precision " << prec << ")"); if (zeros_prec >= 0) { - int index = std::strlen(buf); - int point = 0; - for (int i = 0; i < index; i++) { + string::size_type index = std::strlen(buf); + string::size_type point = 0; + for (string::size_type i = 0; i < index; i++) { if (buf[i] == '.') { point = i; break; @@ -837,7 +837,7 @@ namespace { READ_INTO(in, buf, 255, c, std::isdigit(c) || c == '-' || c == '.' || c == ','); - int len = std::strlen(buf); + string::size_type len = std::strlen(buf); while (len > 0 && ! std::isdigit(buf[len - 1])) { buf[--len] = '\0'; in.unget(); @@ -989,7 +989,7 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) // necessary. if (last_comma != string::npos || last_period != string::npos) { - int len = quant.length(); + string::size_type len = quant.length(); scoped_array<char> buf(new char[len + 1]); const char * p = quant.c_str(); char * t = buf.get(); diff --git a/src/annotate.cc b/src/annotate.cc index 1ea39b5d..c6084f7f 100644 --- a/src/annotate.cc +++ b/src/annotate.cc @@ -127,7 +127,7 @@ void annotation_t::print(std::ostream& out, bool keep_base) const << '}'; if (date) - out << " [" << format_date(*date, string("%Y/%m/%d")) << ']'; + out << " [" << format_date(*date, FMT_WRITTEN) << ']'; if (tag) out << " (" << *tag << ')'; diff --git a/src/chain.cc b/src/chain.cc index 7b9083f0..25f4833c 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -65,10 +65,10 @@ post_handler_ptr chain_post_handlers(report_t& report, if (report.HANDLED(head_) || report.HANDLED(tail_)) handler.reset (new truncate_xacts(handler, - report.HANDLED(head_) ? - report.HANDLER(head_).value.to_long() : 0, - report.HANDLED(tail_) ? - report.HANDLER(tail_).value.to_long() : 0)); + report.HANDLED(head_) ? + report.HANDLER(head_).value.to_int() : 0, + report.HANDLED(tail_) ? + report.HANDLER(tail_).value.to_int() : 0)); // filter_posts will only pass through posts matching the // `display_predicate'. diff --git a/src/commodity.cc b/src/commodity.cc index 37f0b573..4041946b 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -498,10 +498,9 @@ void commodity_t::parse_symbol(std::istream& in, string& symbol) char * _p = buf; c = static_cast<char>(in.peek()); while (_p - buf < 255 && in.good() && ! in.eof() && c != '\n') { - int bytes = 0; - int size = _p - buf; - - unsigned char d = c; + std::size_t bytes = 0; + std::ptrdiff_t size = _p - buf; + unsigned char d = c; // Check for the start of a UTF-8 multi-byte encoded string if (d >= 192 && d <= 223 && size < 254) @@ -518,7 +517,7 @@ void commodity_t::parse_symbol(std::istream& in, string& symbol) break; if (bytes > 0) { // we're looking at a UTF-8 encoding - for (int i = 0; i < bytes; i++) { + for (std::size_t i = 0; i < bytes; i++) { in.get(c); if (in.bad() || in.eof()) break; diff --git a/src/emacs.cc b/src/emacs.cc index 4486b67a..57054690 100644 --- a/src/emacs.cc +++ b/src/emacs.cc @@ -41,7 +41,7 @@ namespace ledger { void format_emacs_posts::write_xact(xact_t& xact) { out << "\"" << xact.pathname << "\" " - << (static_cast<std::size_t>(xact.beg_line) + 1) << " "; + << (xact.beg_line + 1) << " "; tm when = gregorian::to_tm(xact.date()); std::time_t date = std::mktime(&when); // jww (2008-04-20): Is this GMT or local? @@ -77,7 +77,7 @@ void format_emacs_posts::operator()(post_t& post) out << "\n"; } - out << " (" << (static_cast<std::size_t>(post.beg_line) + 1) << " "; + out << " (" << (post.beg_line + 1) << " "; out << "\"" << post.reported_account()->fullname() << "\" \"" << post.amount << "\""; diff --git a/src/error.cc b/src/error.cc index 54d17ad3..70759b08 100644 --- a/src/error.cc +++ b/src/error.cc @@ -47,16 +47,16 @@ string error_context() return context; } -string file_context(const path& file, std::size_t line) +string file_context(const path& file, const std::size_t line) { std::ostringstream buf; buf << "\"" << file << "\", line " << line << ": "; return buf.str(); } -string line_context(const string& line, - std::size_t pos, - std::size_t end_pos) +string line_context(const string& line, + const string::size_type pos, + const string::size_type end_pos) { std::ostringstream buf; buf << " " << line << "\n"; @@ -64,11 +64,11 @@ string line_context(const string& line, if (pos != 0) { buf << " "; if (end_pos == 0) { - for (std::size_t i = 0; i < pos; i += 1) + for (string::size_type i = 0; i < pos; i += 1) buf << " "; buf << "^"; } else { - for (std::size_t i = 0; i < end_pos; i += 1) { + for (string::size_type i = 0; i < end_pos; i += 1) { if (i >= pos) buf << "^"; else @@ -79,12 +79,12 @@ string line_context(const string& line, return buf.str(); } -string source_context(const path& file, - istream_pos_type pos, - istream_pos_type end_pos, - const string& prefix) +string source_context(const path& file, + const istream_pos_type pos, + const istream_pos_type end_pos, + const string& prefix) { - std::streamoff len = end_pos - pos; + const std::streamoff len = end_pos - pos; if (! len || file == path("/dev/stdin")) return _("<no source context>"); @@ -97,10 +97,9 @@ string source_context(const path& file, in.seekg(pos, std::ios::beg); scoped_array<char> buf(new char[len + 1]); - in.read(buf.get(), static_cast<int>(len)); - assert(static_cast<std::size_t>(in.gcount()) == - static_cast<std::size_t>(len)); - buf[static_cast<int>(len)] = '\0'; + in.read(buf.get(), len); + assert(in.gcount() == len); + buf[len] = '\0'; bool first = true; for (char * p = std::strtok(buf.get(), "\n"); diff --git a/src/error.h b/src/error.h index 42eab8d9..21f5bd8f 100644 --- a/src/error.h +++ b/src/error.h @@ -87,14 +87,14 @@ extern std::ostringstream _ctxt_buffer; string error_context(); string file_context(const path& file, std::size_t line); -string line_context(const string& line, - std::size_t pos = 0, - std::size_t end_pos = 0); - -string source_context(const path& file, - istream_pos_type pos, - istream_pos_type end_pos, - const string& prefix = ""); +string line_context(const string& line, + const string::size_type pos = 0, + const string::size_type end_pos = 0); + +string source_context(const path& file, + const istream_pos_type pos, + const istream_pos_type end_pos, + const string& prefix = ""); #define DECLARE_EXCEPTION(name, kind) \ class name : public kind { \ diff --git a/src/filters.cc b/src/filters.cc index 967e0843..08e7a22f 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -133,21 +133,6 @@ void sort_posts::post_accumulated_posts() posts.clear(); } -namespace { - string to_hex(uint_least32_t * message_digest) - { - std::ostringstream buf; - - for(int i = 0; i < 5 ; i++) { - buf.width(8); - buf.fill('0'); - buf << std::hex << message_digest[i]; - break; // only output the first dword - } - return buf.str(); - } -} - void anonymize_posts::operator()(post_t& post) { SHA1 sha; @@ -531,15 +516,14 @@ void subtotal_posts::report_subtotal(const char * spec_fmt, std::ostringstream out_date; if (spec_fmt) { - out_date << format_date(*range_finish, string(spec_fmt)); + out_date << format_date(*range_finish, FMT_CUSTOM, spec_fmt); } else if (date_format) { - string fmt = "- "; - fmt += *date_format; - out_date << format_date(*range_finish, string(fmt)); + out_date << "- " << format_date(*range_finish, FMT_CUSTOM, + date_format->c_str()); } else { - out_date << format_date(*range_finish, std::string("- ") + output_date_format); + out_date << "- " << format_date(*range_finish); } xact_temps.push_back(xact_t()); diff --git a/src/filters.h b/src/filters.h index 050e3dcf..a03d3160 100644 --- a/src/filters.h +++ b/src/filters.h @@ -142,7 +142,8 @@ class truncate_xacts : public item_handler<post_t> truncate_xacts(); public: - truncate_xacts(post_handler_ptr handler, int _head_count, int _tail_count) + truncate_xacts(post_handler_ptr handler, + int _head_count, int _tail_count) : item_handler<post_t>(handler), head_count(_head_count), tail_count(_tail_count), xacts_seen(0), last_xact(NULL) { diff --git a/src/format.cc b/src/format.cc index ecac1133..ea38c861 100644 --- a/src/format.cc +++ b/src/format.cc @@ -345,7 +345,7 @@ void format_t::format(std::ostream& out_str, scope_t& scope) } DEBUG("format.expr", "value = (" << value << ")"); - value.print(out, elem->min_width, -1, + value.print(out, static_cast<int>(elem->min_width), -1, ! elem->has_flags(ELEMENT_ALIGN_LEFT)); } catch (const calc_error&) { @@ -362,15 +362,15 @@ void format_t::format(std::ostream& out_str, scope_t& scope) if (elem->max_width > 0 || elem->min_width > 0) { unistring temp(out.str()); + string result; - string result; if (elem->max_width > 0 && elem->max_width < temp.length()) { result = truncate(temp, elem->max_width); } else { result = temp.extract(); - for (int i = 0; i < (static_cast<int>(elem->min_width) - - static_cast<int>(temp.length())); i++) - result += " "; + if (elem->min_width > temp.length()) + for (std::size_t i = 0; i < elem->min_width - temp.length(); i++) + result += " "; } out_str << result; } else { @@ -379,8 +379,9 @@ void format_t::format(std::ostream& out_str, scope_t& scope) } } -string format_t::truncate(const unistring& ustr, std::size_t width, - const int account_abbrev_length) +string format_t::truncate(const unistring& ustr, + const std::size_t width, + const std::size_t account_abbrev_length) { assert(width < 4095); @@ -434,7 +435,7 @@ string format_t::truncate(const unistring& ustr, std::size_t width, if (newlen > width) { unistring temp(*i); - if (temp.length() > static_cast<std::size_t>(account_abbrev_length)) { + if (temp.length() > account_abbrev_length) { result << temp.extract(0, account_abbrev_length) << ":"; newlen -= temp.length() - account_abbrev_length; } else { diff --git a/src/format.h b/src/format.h index 03ed28c7..bc513f71 100644 --- a/src/format.h +++ b/src/format.h @@ -65,10 +65,7 @@ class format_t : public noncopyable { #define ELEMENT_ALIGN_LEFT 0x01 - enum kind_t { - STRING, - EXPR, - }; + enum kind_t { STRING, EXPR }; kind_t type; std::size_t min_width; @@ -89,7 +86,7 @@ class format_t : public noncopyable friend inline void mark_red(std::ostream& out, const element_t * elem) { out.setf(std::ios::left); out.width(0); - out << "\e[31m"; + out << "\033[31m"; if (elem->has_flags(ELEMENT_ALIGN_LEFT)) out << std::left; @@ -145,8 +142,9 @@ public: elem->dump(out); } - static string truncate(const unistring& str, std::size_t width, - const int account_abbrev_length = -1); + static string truncate(const unistring& str, + const std::size_t width, + const std::size_t account_abbrev_length = 0); }; #define FMT_PREFIX "fmt_" diff --git a/src/generate.cc b/src/generate.cc index 8796f0bf..ebbc3cd7 100644 --- a/src/generate.cc +++ b/src/generate.cc @@ -321,11 +321,11 @@ void generate_posts_iterator::generate_note(std::ostream& out) void generate_posts_iterator::generate_xact(std::ostream& out) { - out << format_date(next_date, string("%Y/%m/%d")); + out << format_date(next_date, FMT_WRITTEN); next_date += gregorian::days(six_gen()); if (truth_gen()) { out << '='; - out << format_date(next_eff_date, string("%Y/%m/%d")); + out << format_date(next_eff_date, FMT_WRITTEN); next_eff_date += gregorian::days(six_gen()); } out << ' '; diff --git a/src/global.cc b/src/global.cc index 24716fae..02c9e79a 100644 --- a/src/global.cc +++ b/src/global.cc @@ -433,8 +433,10 @@ void global_scope_t::normalize_report_options(const string& verb) rep.session.commodity_pool->price_db = none; if (rep.HANDLED(date_format_)) { - output_datetime_format = rep.HANDLER(date_format_).str() + " %H:%M:%S"; - output_date_format = rep.HANDLER(date_format_).str(); + set_date_format(rep.HANDLER(date_format_).str().c_str()); + } + if (rep.HANDLED(datetime_format_)) { + set_datetime_format(rep.HANDLER(datetime_format_).str().c_str()); } if (rep.HANDLED(start_of_week_)) { if (optional<date_time::weekdays> weekday = diff --git a/src/interactive.h b/src/interactive.h index a0388726..0396b1c8 100644 --- a/src/interactive.h +++ b/src/interactive.h @@ -92,6 +92,10 @@ inline bool interactive_t::get<bool>(std::size_t index) { return value_at(index).to_boolean(); } template <> +inline int interactive_t::get<int>(std::size_t index) { + return value_at(index).to_int(); +} +template <> inline long interactive_t::get<long>(std::size_t index) { return value_at(index).to_long(); } diff --git a/src/item.cc b/src/item.cc index 54f36e11..c4db7a51 100644 --- a/src/item.cc +++ b/src/item.cc @@ -142,7 +142,7 @@ void item_t::parse_tags(const char * p, optional<date_t::year_type> current_year for (char * q = std::strtok(buf.get(), " \t"); q; q = std::strtok(NULL, " \t")) { - const std::size_t len = std::strlen(q); + const string::size_type len = std::strlen(q); if (! tag.empty()) { if (! has_tag(tag)) set_tag(tag, string(p + (q - buf.get()))); @@ -38,10 +38,10 @@ namespace ledger { -expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) +expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope, const int depth) { if (is_ident()) { - DEBUG("expr.compile", "Looking up identifier '" << as_ident() << "'"); + DEBUG("expr.compile", "lookup: " << as_ident()); if (ptr_op_t def = scope.lookup(as_ident())) { // Identifier references are first looked up at the point of @@ -79,9 +79,10 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) return wrap_value(value_t()); } - ptr_op_t lhs(left()->compile(scope)); + ptr_op_t lhs(left()->compile(scope, depth)); ptr_op_t rhs(kind > UNARY_OPERATORS && has_right() ? - (kind == O_LOOKUP ? right() : right()->compile(scope)) : NULL); + (kind == O_LOOKUP ? right() : + right()->compile(scope, depth)) : NULL); if (lhs == left() && (! rhs || rhs == right())) return this; @@ -90,19 +91,20 @@ expr_t::ptr_op_t expr_t::op_t::compile(scope_t& scope) // Reduce constants immediately if possible if ((! lhs || lhs->is_value()) && (! rhs || rhs->is_value())) - return wrap_value(intermediate->calc(scope)); + return wrap_value(intermediate->calc(scope, NULL, depth)); return intermediate; } -value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) +value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) { +#if defined(DEBUG_ON) + bool skip_debug = false; +#endif try { value_t result; - DEBUG("expr.calc", "calculating '" << op_context(this) << "'"); - switch (kind) { case VALUE: result = as_value(); @@ -116,7 +118,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) // directly, so we create an empty call_scope_t to reflect the scope for // this implicit call. call_scope_t call_args(scope); - result = left()->calc(call_args, locus); + result = left()->calc(call_args, locus, depth + 1); break; } @@ -126,6 +128,9 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) // resolved. call_scope_t call_args(scope); result = as_function()(call_args); +#if defined(DEBUG_ON) + skip_debug = true; +#endif break; } @@ -157,7 +162,8 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) throw_(calc_error, _("Too many arguments in function call (saw %1)") << args_count); - result = right()->compile(local_scope)->calc(local_scope, locus); + result = right()->compile(local_scope, depth + 1) + ->calc(local_scope, locus, depth + 1); break; } @@ -173,7 +179,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) } else { scope_t& objscope(obj.as_ref_lval<scope_t>()); if (ptr_op_t member = objscope.lookup(right()->as_ident())) { - result = member->calc(objscope); + result = member->calc(objscope, NULL, depth + 1); break; } } @@ -192,7 +198,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) call_scope_t call_args(scope); if (has_right()) - call_args.set_args(right()->calc(scope, locus)); + call_args.set_args(right()->calc(scope, locus, depth + 1)); ptr_op_t func = left(); const string& name(func->as_ident()); @@ -204,74 +210,83 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) if (func->is_function()) result = func->as_function()(call_args); else - result = func->calc(call_args, locus); + result = func->calc(call_args, locus, depth + 1); break; } case O_MATCH: - result = (right()->calc(scope, locus).as_mask() - .match(left()->calc(scope, locus).to_string())); + result = (right()->calc(scope, locus, depth + 1).as_mask() + .match(left()->calc(scope, locus, depth + 1).to_string())); break; case O_EQ: - result = left()->calc(scope, locus) == right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) == + right()->calc(scope, locus, depth + 1)); break; case O_LT: - result = left()->calc(scope, locus) < right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) < + right()->calc(scope, locus, depth + 1)); break; case O_LTE: - result = left()->calc(scope, locus) <= right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) <= + right()->calc(scope, locus, depth + 1)); break; case O_GT: - result = left()->calc(scope, locus) > right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) > + right()->calc(scope, locus, depth + 1)); break; case O_GTE: - result = left()->calc(scope, locus) >= right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) >= + right()->calc(scope, locus, depth + 1)); break; case O_ADD: - result = left()->calc(scope, locus) + right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) + + right()->calc(scope, locus, depth + 1)); break; case O_SUB: - result = left()->calc(scope, locus) - right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) - + right()->calc(scope, locus, depth + 1)); break; case O_MUL: - result = left()->calc(scope, locus) * right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) * + right()->calc(scope, locus, depth + 1)); break; case O_DIV: - result = left()->calc(scope, locus) / right()->calc(scope, locus); + result = (left()->calc(scope, locus, depth + 1) / + right()->calc(scope, locus, depth + 1)); break; case O_NEG: - result = left()->calc(scope, locus).negated(); + result = left()->calc(scope, locus, depth + 1).negated(); break; case O_NOT: - result = ! left()->calc(scope, locus); + result = ! left()->calc(scope, locus, depth + 1); break; case O_AND: - if (left()->calc(scope, locus)) - result = right()->calc(scope, locus); + if (left()->calc(scope, locus, depth + 1)) + result = right()->calc(scope, locus, depth + 1); else result = false; break; case O_OR: - if (value_t temp = left()->calc(scope, locus)) + if (value_t temp = left()->calc(scope, locus, depth + 1)) result = temp; else - result = right()->calc(scope, locus); + result = right()->calc(scope, locus, depth + 1); break; case O_QUERY: assert(right()); assert(right()->kind == O_COLON); - if (value_t temp = left()->calc(scope, locus)) - result = right()->left()->calc(scope, locus); + if (value_t temp = left()->calc(scope, locus, depth + 1)) + result = right()->left()->calc(scope, locus, depth + 1); else - result = right()->right()->calc(scope, locus); + result = right()->right()->calc(scope, locus, depth + 1); break; case O_COLON: @@ -279,7 +294,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) break; case O_CONS: - result = left()->calc(scope, locus); + result = left()->calc(scope, locus, depth + 1); DEBUG("op.cons", "car = " << result); if (has_right()) { @@ -296,7 +311,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) value_op = next; next = NULL; } - temp.push_back(value_op->calc(scope, locus)); + temp.push_back(value_op->calc(scope, locus, depth + 1)); DEBUG("op.cons", "temp now = " << temp); } result = temp; @@ -304,7 +319,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) break; case O_SEQ: { - left()->calc(scope, locus); + left()->calc(scope, locus, depth + 1); assert(has_right()); ptr_op_t next = right(); @@ -317,7 +332,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) value_op = next; next = NULL; } - result = value_op->calc(scope, locus); + result = value_op->calc(scope, locus, depth + 1); } break; } @@ -328,7 +343,15 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus) break; } - DEBUG("expr.calc", "result is '" << result << "'"); +#if defined(DEBUG_ON) + if (! skip_debug && SHOW_DEBUG("expr.calc")) { + for (int i = 0; i < depth; i++) + ledger::_log_buffer << '.'; + ledger::_log_buffer << op_context(this) << " => "; + result.dump(ledger::_log_buffer, true); + DEBUG("expr.calc", ""); + } +#endif return result; @@ -262,8 +262,9 @@ private: } public: - ptr_op_t compile(scope_t& scope); - value_t calc(scope_t& scope, ptr_op_t * locus = NULL); + ptr_op_t compile(scope_t& scope, const int depth = 0); + value_t calc(scope_t& scope, ptr_op_t * locus = NULL, + const int depth = 0); struct context_t { diff --git a/src/option.cc b/src/option.cc index 1275e270..f47410e2 100644 --- a/src/option.cc +++ b/src/option.cc @@ -110,8 +110,8 @@ void process_option(const string& whence, const string& name, scope_t& scope, void process_environment(const char ** envp, const string& tag, scope_t& scope) { - const char * tag_p = tag.c_str(); - std::size_t tag_len = tag.length(); + const char * tag_p = tag.c_str(); + string::size_type tag_len = tag.length(); for (const char ** p = envp; *p; p++) { if (! tag_p || std::strncmp(*p, tag_p, tag_len) == 0) { diff --git a/src/option.h b/src/option.h index 6809a27c..89f1ad08 100644 --- a/src/option.h +++ b/src/option.h @@ -56,11 +56,11 @@ template <typename T> class option_t { protected: - const char * name; - std::size_t name_len; - const char ch; - bool handled; - optional<string> source; + const char * name; + string::size_type name_len; + const char ch; + bool handled; + optional<string> source; option_t& operator=(const option_t&); diff --git a/src/parser.cc b/src/parser.cc index 39004758..a6053d69 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -491,9 +491,10 @@ expr_t::parser_t::parse(std::istream& in, const parse_flags_t& flags, if (original_string) { add_error_context(_("While parsing value expression:")); - std::size_t end_pos = - in.good() ? static_cast<std::size_t>(in.tellg()) : 0; - std::size_t pos = static_cast<std::size_t>(end_pos); + std::streamoff end_pos = 0; + if (in.good()) + end_pos = in.tellg(); + std::streamoff pos = end_pos; if (pos > 0) pos -= lookahead.length; @@ -504,7 +505,9 @@ expr_t::parser_t::parse(std::istream& in, const parse_flags_t& flags, DEBUG("parser.error", " token kind = " << int(lookahead.kind)); DEBUG("parser.error", " token length = " << lookahead.length); - add_error_context(line_context(*original_string, pos, end_pos)); + add_error_context(line_context(*original_string, + static_cast<string::size_type>(pos), + static_cast<string::size_type>(end_pos))); } throw; } diff --git a/src/post.cc b/src/post.cc index 9b416434..90c10a3b 100644 --- a/src/post.cc +++ b/src/post.cc @@ -195,7 +195,8 @@ namespace { string name = env->reported_account()->fullname(); if (env.has(0) && env.get<long>(0) > 2) - name = format_t::truncate(name, env.get<long>(0) - 2, true); + name = format_t::truncate(name, env.get<long>(0) - 2, + 2 /* account_abbrev_length */); if (env->has_flags(POST_VIRTUAL)) { if (env->must_balance()) diff --git a/src/py_times.cc b/src/py_times.cc index 4d6519ed..e140a23c 100644 --- a/src/py_times.cc +++ b/src/py_times.cc @@ -165,8 +165,10 @@ void export_times() register_optional_to_python<datetime_t>(); register_optional_to_python<date_t>(); - scope().attr("parse_datetime") = &py_parse_datetime; - scope().attr("parse_date") = &py_parse_date; + scope().attr("parse_datetime") = &py_parse_datetime; + scope().attr("parse_date") = &py_parse_date; + scope().attr("times_initialize") = ×_initialize; + scope().attr("times_shutdown") = ×_shutdown; #if 0 class_< interval_t > ("Interval") diff --git a/src/pyfstream.h b/src/pyfstream.h index 5e39d38d..3da37523 100644 --- a/src/pyfstream.h +++ b/src/pyfstream.h @@ -109,9 +109,9 @@ protected: * - at most, pbSize characters in putback area plus * - at most, bufSize characters in ordinary read buffer */ - static const int pbSize = 4; // size of putback area - static const int bufSize = 1024; // size of the data buffer - char buffer[bufSize + pbSize]; // data buffer + static const size_t pbSize = 4; // size of putback area + static const size_t bufSize = 1024; // size of the data buffer + char buffer[bufSize + pbSize]; // data buffer public: /* constructor @@ -147,7 +147,7 @@ protected: * - use number of characters read * - but at most size of putback area */ - int numPutback; + size_t numPutback; numPutback = gptr() - eback(); if (numPutback > pbSize) { numPutback = pbSize; @@ -160,14 +160,13 @@ protected: numPutback); // read at most bufSize new characters - int num; PyObject *line = PyFile_GetLine(reinterpret_cast<PyObject *>(fo), bufSize); if (! line || ! PyString_Check(line)) { // ERROR or EOF return EOF; } - num = PyString_Size(line); + Py_ssize_t num = PyString_Size(line); if (num == 0) return EOF; diff --git a/src/pyinterp.cc b/src/pyinterp.cc index a163175f..f5b1a543 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -266,7 +266,7 @@ value_t python_interpreter_t::python_command(call_scope_t& args) std::strcpy(argv[i + 1], arg.c_str()); } - int status = Py_Main(args.size() + 1, argv); + int status = Py_Main(static_cast<int>(args.size()) + 1, argv); for (std::size_t i = 0; i < args.size() + 1; i++) delete[] argv[i]; diff --git a/src/pyinterp.h b/src/pyinterp.h index dd9ca64c..4943eb2f 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -105,6 +105,7 @@ public: virtual expr_t::ptr_op_t lookup(const string& name); +#if BOOST_VERSION >= 103700 OPTION_(python_interpreter_t, import_, DO_(scope) { interactive_t args(scope, "s"); @@ -114,23 +115,31 @@ public: python::object sys_dict = module_sys.attr("__dict__"); python::list paths(sys_dict["path"]); -#if BOOST_VERSION >= 103700 paths.insert(0, file.parent_path().string()); -#else - paths.insert(0, file.branch_path().string()); -#endif sys_dict["path"] = paths; -#if BOOST_VERSION >= 103700 string name = file.filename(); if (contains(name, ".py")) parent->import(file.stem()); else parent->import(name); -#else + }); +#else // BOOST_VERSION >= 103700 + OPTION_(python_interpreter_t, import_, DO_(scope) { + interactive_t args(scope, "s"); + + path file(args.get<string>(0)); + + python::object module_sys = parent->import("sys"); + python::object sys_dict = module_sys.attr("__dict__"); + + python::list paths(sys_dict["path"]); + paths.insert(0, file.branch_path().string()); + sys_dict["path"] = paths; + parent->import(file.leaf()); -#endif }); +#endif // BOOST_VERSION >= 103700 }; extern shared_ptr<python_interpreter_t> python_session; diff --git a/src/quotes.cc b/src/quotes.cc index d4be462e..797e6dd5 100644 --- a/src/quotes.cc +++ b/src/quotes.cc @@ -86,7 +86,7 @@ commodity_quote_from_script(commodity_t& commodity, std::ios_base::out | std::ios_base::app); #endif database << "P " - << format_datetime(point->when, string("%Y/%m/%d %H:%M:%S")) + << format_datetime(point->when, FMT_WRITTEN) << " " << commodity.symbol() << " " << point->price << std::endl; diff --git a/src/report.cc b/src/report.cc index 4c8a40e6..9c8ad8ba 100644 --- a/src/report.cc +++ b/src/report.cc @@ -211,8 +211,8 @@ value_t report_t::fn_truncated(call_scope_t& scope) interactive_t args(scope, "v&ll"); return string_value(format_t::truncate (args.get<string>(0), - args.has(1) && args.get<long>(1) > 0 ? args.get<long>(1) : 0, - args.has(2) ? args.get<long>(2) : -1)); + args.has(1) && args.get<int>(1) > 0 ? args.get<int>(1) : 0, + args.has(2) ? args.get<int>(2) : 0)); } value_t report_t::fn_justify(call_scope_t& scope) @@ -220,8 +220,8 @@ value_t report_t::fn_justify(call_scope_t& scope) interactive_t args(scope, "vl&lbbs"); std::ostringstream out; args.value_at(0) - .print(out, args.get<long>(1), - args.has(2) ? args.get<long>(2) : -1, + .print(out, args.get<int>(1), + args.has(2) ? args.get<int>(2) : -1, args.has(3) ? args.get<bool>(3) : false, args.has(4) ? args.get<bool>(4) : false, args.has(5) ? args.get<string>(5) : @@ -263,9 +263,12 @@ value_t report_t::fn_join(call_scope_t& scope) value_t report_t::fn_format_date(call_scope_t& scope) { - interactive_t args(scope, "ds"); - return string_value(format_date(args.get<date_t>(0), - args.get<string>(1))); + interactive_t args(scope, "d&s"); + if (args.has(1)) + return string_value(format_date(args.get<date_t>(0), FMT_CUSTOM, + args.get<string>(1).c_str())); + else + return string_value(format_date(args.get<date_t>(0), FMT_PRINTED)); } value_t report_t::fn_ansify_if(call_scope_t& scope) @@ -275,19 +278,19 @@ value_t report_t::fn_ansify_if(call_scope_t& scope) if (args.has(1)) { string color = args.get<string>(1); std::ostringstream buf; - if (color == "black") buf << "\e[30m"; - else if (color == "red") buf << "\e[31m"; - else if (color == "green") buf << "\e[32m"; - else if (color == "yellow") buf << "\e[33m"; - else if (color == "blue") buf << "\e[34m"; - else if (color == "magenta") buf << "\e[35m"; - else if (color == "cyan") buf << "\e[36m"; - else if (color == "white") buf << "\e[37m"; - else if (color == "bold") buf << "\e[1m"; - else if (color == "underline") buf << "\e[4m"; - else if (color == "blink") buf << "\e[5m"; + if (color == "black") buf << "\033[30m"; + else if (color == "red") buf << "\033[31m"; + else if (color == "green") buf << "\033[32m"; + else if (color == "yellow") buf << "\033[33m"; + else if (color == "blue") buf << "\033[34m"; + else if (color == "magenta") buf << "\033[35m"; + else if (color == "cyan") buf << "\033[36m"; + else if (color == "white") buf << "\033[37m"; + else if (color == "bold") buf << "\033[1m"; + else if (color == "underline") buf << "\033[4m"; + else if (color == "blink") buf << "\033[5m"; buf << args.value_at(0); - buf << "\e[0m"; + buf << "\033[0m"; return string_value(buf.str()); } else { return args.value_at(0); @@ -521,6 +524,7 @@ option_t<report_t> * report_t::lookup_option(const char * p) case 'd': OPT(daily); else OPT(date_format_); + else OPT(datetime_format_); else OPT(depth_); else OPT(deviation); else OPT_(display_); diff --git a/src/report.h b/src/report.h index 71dc4ca2..5921a154 100644 --- a/src/report.h +++ b/src/report.h @@ -218,6 +218,7 @@ public: HANDLER(current).report(out); HANDLER(daily).report(out); HANDLER(date_format_).report(out); + HANDLER(datetime_format_).report(out); HANDLER(depth_).report(out); HANDLER(deviation).report(out); HANDLER(display_).report(out); @@ -412,10 +413,8 @@ public: parent->HANDLER(period_).on(string("--daily"), "daily"); }); - OPTION__(report_t, date_format_, // -y - CTOR(report_t, date_format_) { - on(none, "%y-%b-%d"); - }); + OPTION(report_t, date_format_); + OPTION(report_t, datetime_format_); OPTION_(report_t, depth_, DO_(scope) { interactive_t args(scope, "sl"); @@ -633,9 +632,9 @@ public: OPTION__(report_t, print_format_, CTOR(report_t, print_format_) { on(none, - "%(format_date(xact.date, \"%Y/%m/%d\"))" + "%(xact.date)" "%(!effective & xact.effective_date ?" - " \"=\" + format_date(xact.effective_date, \"%Y/%m/%d\") : \"\")" + " \"=\" + xact.effective_date : \"\")" "%(xact.cleared ? \" *\" : (xact.pending ? \" !\" : \"\"))" "%(code ? \" (\" + code + \")\" :" " \"\") %(payee)%(xact.comment)\n" @@ -673,7 +672,8 @@ public: OPTION__(report_t, register_format_, CTOR(report_t, register_format_) { on(none, - "%(ansify_if(justify(date, date_width), green if color & date > today))" + "%(ansify_if(justify(format_date(date), date_width), green " + " if color & date > today))" " %(ansify_if(justify(truncated(payee, payee_width), payee_width), " " bold if color & !cleared))" " %(ansify_if(justify(truncated(account, account_width, abbrev_len), " diff --git a/src/session.cc b/src/session.cc index f7a8655b..b46d545e 100644 --- a/src/session.cc +++ b/src/session.cc @@ -45,6 +45,7 @@ namespace ledger { void set_session_context(session_t * session) { if (session) { + times_initialize(); amount_t::initialize(session->commodity_pool); // jww (2009-02-04): Is amount_t the right place for parse_conversion to @@ -57,6 +58,7 @@ void set_session_context(session_t * session) else if (! session) { value_t::shutdown(); amount_t::shutdown(); + times_shutdown(); } } diff --git a/src/session.h b/src/session.h index 894c59fa..a51cdba6 100644 --- a/src/session.h +++ b/src/session.h @@ -144,9 +144,9 @@ public: }); OPTION_(session_t, input_date_format_, DO_(args) { - // This changes the global variable inside times.h, which affects the - // basic date parser - input_date_format = args[1].as_string(); + // This changes static variables inside times.h, which affects the basic + // date parser. + set_input_date_format(args[1].as_string().c_str()); }); OPTION(session_t, price_db_); diff --git a/src/stream.cc b/src/stream.cc index c7fd58fa..e39b74e0 100644 --- a/src/stream.cc +++ b/src/stream.cc @@ -100,7 +100,8 @@ namespace { } else { // parent close(pfd[0]); - *os = new boost::fdostream(pfd[1]); + typedef iostreams::stream<iostreams::file_descriptor_sink> fdstream; + *os = new fdstream(pfd[1]); } return pfd[1]; } diff --git a/src/system.hh.in b/src/system.hh.in index 1f4a7d63..07598173 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -83,8 +83,8 @@ namespace std { } } -typedef std::size_t istream_pos_type; -typedef std::size_t ostream_pos_type; +typedef std::streamoff istream_pos_type; +typedef std::streamoff ostream_pos_type; #else // ! (defined(__GNUG__) && __GNUG__ < 3) @@ -119,7 +119,6 @@ typedef std::ostream::pos_type ostream_pos_type; #if defined(HAVE_UNIX_PIPES) #include <sys/types.h> #include <sys/wait.h> -#include "fdstream.h" #endif #if defined(HAVE_GETTEXT) #include "gettext.h" @@ -154,6 +153,9 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/foreach.hpp> #include <boost/function.hpp> #include <boost/intrusive_ptr.hpp> +#include <boost/iostreams/stream.hpp> +#include <boost/iostreams/write.hpp> +#include <boost/iostreams/device/file_descriptor.hpp> #include <boost/lexical_cast.hpp> #include <boost/operators.hpp> #include <boost/optional.hpp> diff --git a/src/times.cc b/src/times.cc index 45f7ed10..facdc4f6 100644 --- a/src/times.cc +++ b/src/times.cc @@ -35,55 +35,182 @@ namespace ledger { -date_time::weekdays start_of_week = gregorian::Sunday; -optional<std::string> input_date_format; -std::string output_datetime_format = "%Y-%m-%d %H:%M:%S"; -std::string output_date_format = "%Y-%m-%d"; +date_time::weekdays start_of_week = gregorian::Sunday; + +//#define USE_BOOST_FACETS 1 namespace { - struct date_format_t { - const char * format; - bool has_year; - date_format_t(const char * _format, bool _has_year) - : format(_format), has_year(_has_year) {} - }; + template <typename T, typename InputFacetType, typename OutputFacetType> + class temporal_io_t : public noncopyable + { + const char * fmt_str; +#if defined(USE_BOOST_FACETS) + std::istringstream input_stream; + std::ostringstream output_stream; + InputFacetType * input_facet; + OutputFacetType * output_facet; + std::string temp_string; +#endif // USE_BOOST_FACETS + + public: + bool has_year; + bool input; + + temporal_io_t(const char * _fmt_str, bool _input) + : fmt_str(_fmt_str), has_year(icontains(fmt_str, "%y")), + input(_input) { +#if defined(USE_BOOST_FACETS) + if (input) { + input_facet = new InputFacetType(fmt_str); + input_stream.imbue(std::locale(std::locale::classic(), input_facet)); + } else { + output_facet = new OutputFacetType(fmt_str); + output_stream.imbue(std::locale(std::locale::classic(), output_facet)); + } +#endif // USE_BOOST_FACETS + } + + void set_format(const char * fmt) { + fmt_str = fmt; + has_year = icontains(fmt_str, "%y"); + +#if defined(USE_BOOST_FACETS) + if (input) + input_facet->format(fmt_str); + else + output_facet->format(fmt_str); +#endif // USE_BOOST_FACETS + } + + T parse(const char * str) { + } - const date_format_t formats[] = { - date_format_t("%m/%d", false), - date_format_t("%Y/%m/%d", true), - date_format_t("%Y/%m", true), - date_format_t("%y/%m/%d", true), - date_format_t("%m.%d", false), - date_format_t("%Y.%m.%d", true), - date_format_t("%Y.%m", true), - date_format_t("%y.%m.%d", true), - date_format_t("%m-%d", false), - date_format_t("%Y-%m-%d", true), - date_format_t("%Y-%m", true), - date_format_t("%y-%m-%d", true) + std::string format(const T& when) { +#if defined(USE_BOOST_FACETS) + output_stream.str(temp_string); + output_stream.seekp(std::ios_base::beg); + output_stream.clear(); + output_stream << when; + return output_stream.str(); +#else // USE_BOOST_FACETS + std::tm data(to_tm(when)); + char buf[128]; + std::strftime(buf, 127, fmt_str, &data); + return buf; +#endif // USE_BOOST_FACETS + } }; - date_t parse_date_mask_routine(const char * date_str, const date_format_t& df, - optional<date_t::year_type> year, bool& saw_year) + template <> + datetime_t temporal_io_t<datetime_t, posix_time::time_input_facet, + posix_time::time_facet> + ::parse(const char * str) { - std::string str(date_str); +#if defined(USE_BOOST_FACETS) + input_stream.seekg(std::ios_base::beg); + input_stream.clear(); + input_stream.str(str); - gregorian::date_input_facet * facet(new gregorian::date_input_facet(df.format)); - std::istringstream sstr(str); - sstr.imbue(std::locale(sstr.getloc(), facet)); + datetime_t when; + input_stream >> when; +#if defined(DEBUG_ON) + if (when.is_not_a_date_time()) + DEBUG("times.parse", "Failed to parse date/time '" << str + << "' using pattern '" << fmt_str << "'"); +#endif - date_t when; - sstr >> when; + if (! when.is_not_a_date_time() && + input_stream.good() && ! input_stream.eof() && + input_stream.peek() != EOF) { + DEBUG("times.parse", "This string has leftovers: '" << str << "'"); + return datetime_t(); + } + return when; +#else // USE_BOOST_FACETS + std::tm data; + std::memset(&data, 0, sizeof(std::tm)); + if (strptime(str, fmt_str, &data)) + return posix_time::ptime_from_tm(data); + else + return datetime_t(); +#endif // USE_BOOST_FACETS + } - if (! when.is_not_a_date()) { - if (sstr.good() && ! sstr.eof() && sstr.peek() != EOF) + template <> + date_t temporal_io_t<date_t, gregorian::date_input_facet, + gregorian::date_facet> + ::parse(const char * str) + { +#if defined(USE_BOOST_FACETS) + input_stream.seekg(std::ios_base::beg); + input_stream.clear(); + input_stream.str(str); + + date_t when; + input_stream >> when; +#if defined(DEBUG_ON) + if (when.is_not_a_date()) + DEBUG("times.parse", "Failed to parse date '" << str + << "' using pattern '" << fmt_str << "'"); +#endif + + if (! when.is_not_a_date() && + input_stream.good() && ! input_stream.eof() && + input_stream.peek() != EOF) { + DEBUG("times.parse", "This string has leftovers: '" << str << "'"); return date_t(); + } + return when; +#else // USE_BOOST_FACETS + std::tm data; + std::memset(&data, 0, sizeof(std::tm)); + data.tm_mday = 1; // some formats have no day + if (strptime(str, fmt_str, &data)) + return gregorian::date_from_tm(data); + else + return date_t(); +#endif // USE_BOOST_FACETS + } + + typedef temporal_io_t<datetime_t, posix_time::time_input_facet, + posix_time::time_facet> datetime_io_t; + typedef temporal_io_t<date_t, gregorian::date_input_facet, + gregorian::date_facet> date_io_t; + + shared_ptr<datetime_io_t> input_datetime_io; + shared_ptr<date_io_t> input_date_io; + shared_ptr<datetime_io_t> written_datetime_io; + shared_ptr<date_io_t> written_date_io; + shared_ptr<datetime_io_t> printed_datetime_io; + shared_ptr<date_io_t> printed_date_io; + + std::vector<shared_ptr<date_io_t> > readers; + + date_t parse_date_mask_routine(const char * date_str, date_io_t& io, + optional<date_t::year_type> year, + bool& saw_year) + { + date_t when; + + if (std::strchr(date_str, '/')) { + when = io.parse(date_str); + } else { + char buf[128]; + VERIFY(std::strlen(date_str) < 127); + std::strcpy(buf, date_str); + for (char * p = buf; *p; p++) + if (*p == '.' || *p == '-') + *p = '/'; + + when = io.parse(buf); + } + + if (! when.is_not_a_date()) { DEBUG("times.parse", "Parsed date string: " << date_str); - DEBUG("times.parse", "Parsed result is: " << when); - DEBUG("times.parse", "Format used was: " << df.format); + DEBUG("times.parse", "Parsed result is: " << when); - if (! df.has_year) { + if (! io.has_year) { saw_year = false; when = date_t(year ? *year : CURRENT_DATE().year(), @@ -98,25 +225,24 @@ namespace { return when; } - date_t parse_date_mask(const char * date_str, optional<date_t::year_type> year, - bool& saw_year) + date_t parse_date_mask(const char * date_str, + optional<date_t::year_type> year, bool& saw_year) { - if (input_date_format) { - date_format_t df(input_date_format->c_str(), true); - if (! icontains(*input_date_format, "%y")) - df.has_year = false; - date_t when = parse_date_mask_routine(date_str, df, year, saw_year); + if (input_date_io.get()) { + date_t when = parse_date_mask_routine(date_str, *input_date_io.get(), + year, saw_year); if (! when.is_not_a_date()) return when; } - for (uint8_t i = 0; i < (sizeof(formats) / sizeof(date_format_t)); i++) { - date_t when = parse_date_mask_routine(date_str, formats[i], year, - saw_year); + foreach (shared_ptr<date_io_t>& reader, readers) { + date_t when = parse_date_mask_routine(date_str, *reader.get(), + year, saw_year); if (! when.is_not_a_date()) return when; } + throw_(date_error, _("Invalid date: %1") << date_str); return date_t(); } } @@ -174,15 +300,9 @@ string_to_month_of_year(const std::string& str) datetime_t parse_datetime(const char * str, optional<date_t::year_type>) { - posix_time::time_input_facet * facet - (new posix_time::time_input_facet("%Y/%m/%d %H:%M:%S")); - - std::string temp(str); - std::istringstream sstr(temp); - sstr.imbue(std::locale(sstr.getloc(), facet)); - - datetime_t when; - sstr >> when; + datetime_t when = input_datetime_io->parse(str); + if (when.is_not_a_date_time()) + throw_(date_error, _("Invalid date/time: %1") << str); return when; } @@ -481,7 +601,7 @@ namespace { inline void read_lower_word(std::istream& in, string& word) { in >> word; - for (int i = 0, l = word.length(); i < l; i++) + for (string::size_type i = 0, l = word.length(); i < l; i++) word[i] = static_cast<char>(std::tolower(word[i])); } @@ -662,4 +782,126 @@ void date_interval_t::parse(std::istream& in) } } +namespace { + typedef std::map<std::string, datetime_io_t *> datetime_io_map; + typedef std::map<std::string, date_io_t *> date_io_map; + + datetime_io_map temp_datetime_io; + date_io_map temp_date_io; +} + +std::string format_datetime(const datetime_t& when, + const format_type_t format_type, + const optional<const char *>& format) +{ + if (format_type == FMT_WRITTEN) { + return written_datetime_io->format(when); + } + else if (format_type == FMT_CUSTOM || format) { + datetime_io_map::iterator i = temp_datetime_io.find(*format); + if (i != temp_datetime_io.end()) { + return (*i).second->format(when); + } else { + datetime_io_t * formatter = new datetime_io_t(*format, false); + temp_datetime_io.insert(datetime_io_map::value_type(*format, formatter)); + return formatter->format(when); + } + } + else if (format_type == FMT_PRINTED) { + return printed_datetime_io->format(when); + } + else { + assert(0); + return ""; + } +} + +std::string format_date(const date_t& when, + const format_type_t format_type, + const optional<const char *>& format) +{ + if (format_type == FMT_WRITTEN) { + return written_date_io->format(when); + } + else if (format_type == FMT_CUSTOM || format) { + date_io_map::iterator i = temp_date_io.find(*format); + if (i != temp_date_io.end()) { + return (*i).second->format(when); + } else { + date_io_t * formatter = new date_io_t(*format, false); + temp_date_io.insert(date_io_map::value_type(*format, formatter)); + return formatter->format(when); + } + } + else if (format_type == FMT_PRINTED) { + return printed_date_io->format(when); + } + else { + assert(0); + return ""; + } +} + +namespace { + bool is_initialized = false; +} + +void set_datetime_format(const char * format) +{ + printed_datetime_io->set_format(format); +} + +void set_date_format(const char * format) +{ + printed_date_io->set_format(format); +} + +void set_input_date_format(const char * format) +{ + input_date_io.reset(new date_io_t(format, true)); +} + +void times_initialize() +{ + if (! is_initialized) { + input_datetime_io.reset(new datetime_io_t("%Y/%m/%d %H:%M:%S", true)); + + written_datetime_io.reset(new datetime_io_t("%Y/%m/%d %H:%M:%S", false)); + written_date_io.reset(new date_io_t("%Y/%m/%d", false)); + + printed_datetime_io.reset(new datetime_io_t("%y-%b-%d %H:%M:%S", false)); + printed_date_io.reset(new date_io_t("%y-%b-%d", false)); + + readers.push_back(shared_ptr<date_io_t>(new date_io_t("%m/%d", true))); + readers.push_back(shared_ptr<date_io_t>(new date_io_t("%Y/%m/%d", true))); + readers.push_back(shared_ptr<date_io_t>(new date_io_t("%Y/%m", true))); + readers.push_back(shared_ptr<date_io_t>(new date_io_t("%y/%m/%d", true))); + + is_initialized = true; + } +} + +void times_shutdown() +{ + if (is_initialized) { + input_datetime_io.reset(); + input_date_io.reset(); + written_datetime_io.reset(); + written_date_io.reset(); + printed_datetime_io.reset(); + printed_date_io.reset(); + + readers.clear(); + + foreach (datetime_io_map::value_type& pair, temp_datetime_io) + checked_delete(pair.second); + temp_datetime_io.clear(); + + foreach (date_io_map::value_type& pair, temp_date_io) + checked_delete(pair.second); + temp_date_io.clear(); + + is_initialized = false; + } +} } // namespace ledger diff --git a/src/times.h b/src/times.h index 247c9393..c77cde1d 100644 --- a/src/times.h +++ b/src/times.h @@ -74,7 +74,6 @@ inline bool is_valid(const date_t& moment) { #define CURRENT_DATE() boost::gregorian::day_clock::universal_day() extern date_time::weekdays start_of_week; -extern optional<std::string> input_date_format; optional<date_time::weekdays> string_to_day_of_week(const std::string& str); @@ -97,33 +96,20 @@ inline date_t parse_date(const std::string& str, return parse_date(str.c_str(), current_year); } -extern std::string output_datetime_format; +enum format_type_t { + FMT_WRITTEN, FMT_PRINTED, FMT_CUSTOM +}; -inline std::string format_datetime(const datetime_t& when, - const optional<std::string>& format = none) -{ - posix_time::time_facet * facet - (new posix_time::time_facet(format ? format->c_str() : - output_datetime_format.c_str())); - std::ostringstream buf; - buf.imbue(std::locale(std::locale::classic(), facet)); - buf << when; - return buf.str(); -} +std::string format_datetime(const datetime_t& when, + const format_type_t format_type = FMT_PRINTED, + const optional<const char *>& format = none); +void set_datetime_format(const char * format); -extern std::string output_date_format; - -inline std::string format_date(const date_t& when, - const optional<std::string>& format = none) -{ - gregorian::date_facet * facet - (new gregorian::date_facet(format ? format->c_str() : - output_date_format.c_str())); - std::ostringstream buf; - buf.imbue(std::locale(std::locale::classic(), facet)); - buf << when; - return buf.str(); -} +std::string format_date(const date_t& when, + const format_type_t format_type = FMT_PRINTED, + const optional<const char *>& format = none); +void set_date_format(const char * format); +void set_input_date_format(const char * format); class date_interval_t : public equality_comparable<date_interval_t> { @@ -207,6 +193,9 @@ public: date_interval_t& operator++(); }; +void times_initialize(); +void times_shutdown(); + std::ostream& operator<<(std::ostream& out, const date_interval_t::duration_t& duration); diff --git a/src/unistring.h b/src/unistring.h index 5467a151..268f60e3 100644 --- a/src/unistring.h +++ b/src/unistring.h @@ -70,7 +70,7 @@ public: std::size_t len = input.length(); VERIFY(utf8::is_valid(p, p + len)); - utf8::utf8to32(p, p + len, std::back_inserter(utf32chars)); + utf8::unchecked::utf8to32(p, p + len, std::back_inserter(utf32chars)); } ~unistring() { TRACE_DTOR(unistring); @@ -80,18 +80,22 @@ public: return utf32chars.size(); } - std::string extract(const std::size_t begin = 0, - const std::size_t len = 0) const + std::string extract(const std::string::size_type begin = 0, + const std::string::size_type len = 0) const { - std::string utf8result; - std::size_t this_len = length(); + std::string utf8result; + std::string::size_type this_len = length(); + assert(begin <= this_len); assert(begin + len <= this_len); + if (this_len) - utf8::utf32to8(utf32chars.begin() + begin, - utf32chars.begin() + begin + - (len ? (len > this_len ? this_len : len) : this_len), - std::back_inserter(utf8result)); + utf8::unchecked::utf32to8 + (utf32chars.begin() + begin, + utf32chars.begin() + begin + + (len ? (len > this_len ? this_len : len) : this_len), + std::back_inserter(utf8result)); + return utf8result; } }; @@ -103,9 +107,9 @@ inline void justify(std::ostream& out, bool redden = false) { if (! right) { - if (redden) out << "\e[31m"; + if (redden) out << "\033[31m"; out << str; - if (redden) out << "\e[0m"; + if (redden) out << "\033[0m"; } unistring temp(str); @@ -115,9 +119,9 @@ inline void justify(std::ostream& out, out << ' '; if (right) { - if (redden) out << "\e[31m"; + if (redden) out << "\033[31m"; out << str; - if (redden) out << "\e[0m"; + if (redden) out << "\033[0m"; } } diff --git a/src/utils.cc b/src/utils.cc index f2449daf..0afea4c2 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -71,32 +71,34 @@ namespace ledger { bool verify_enabled = false; typedef std::pair<std::string, std::size_t> allocation_pair; -typedef std::map<void *, allocation_pair> live_memory_map; -typedef std::multimap<void *, allocation_pair> live_objects_map; +typedef std::map<void *, allocation_pair> memory_map; +typedef std::multimap<void *, allocation_pair> objects_map; typedef std::pair<std::size_t, std::size_t> count_size_pair; typedef std::map<std::string, count_size_pair> object_count_map; -static live_memory_map * live_memory = NULL; -static object_count_map * live_memory_count = NULL; -static object_count_map * total_memory_count = NULL; +namespace { + bool memory_tracing_active = false; -static bool memory_tracing_active = false; - -static live_objects_map * live_objects = NULL; -static object_count_map * live_object_count = NULL; -static object_count_map * total_object_count = NULL; -static object_count_map * total_ctor_count = NULL; + memory_map * live_memory = NULL; + memory_map * freed_memory = NULL; + object_count_map * live_memory_count = NULL; + object_count_map * total_memory_count = NULL; + objects_map * live_objects = NULL; + object_count_map * live_object_count = NULL; + object_count_map * total_object_count = NULL; + object_count_map * total_ctor_count = NULL; +} void initialize_memory_tracing() { memory_tracing_active = false; - live_memory = new live_memory_map; + live_memory = new memory_map; + freed_memory = new memory_map; live_memory_count = new object_count_map; total_memory_count = new object_count_map; - - live_objects = new live_objects_map; + live_objects = new objects_map; live_object_count = new object_count_map; total_object_count = new object_count_map; total_ctor_count = new object_count_map; @@ -118,9 +120,9 @@ void shutdown_memory_tracing() } checked_delete(live_memory); live_memory = NULL; + checked_delete(freed_memory); freed_memory = NULL; checked_delete(live_memory_count); live_memory_count = NULL; checked_delete(total_memory_count); total_memory_count = NULL; - checked_delete(live_objects); live_objects = NULL; checked_delete(live_object_count); live_object_count = NULL; checked_delete(total_object_count); total_object_count = NULL; @@ -153,12 +155,16 @@ std::size_t current_memory_size() static void trace_new_func(void * ptr, const char * which, std::size_t size) { + if (! live_memory || ! memory_tracing_active) return; + memory_tracing_active = false; - if (! live_memory) return; + memory_map::iterator i = freed_memory->find(ptr); + if (i != freed_memory->end()) + freed_memory->erase(i); live_memory->insert - (live_memory_map::value_type(ptr, allocation_pair(which, size))); + (memory_map::value_type(ptr, allocation_pair(which, size))); add_to_count_map(*live_memory_count, which, size); add_to_count_map(*total_memory_count, which, size); @@ -169,9 +175,9 @@ static void trace_new_func(void * ptr, const char * which, std::size_t size) static void trace_delete_func(void * ptr, const char * which) { - memory_tracing_active = false; + if (! live_memory || ! memory_tracing_active) return; - if (! live_memory) return; + memory_tracing_active = false; // Ignore deletions of memory not tracked, since it's possible that // a user (like boost) allocated a block of memory before memory @@ -179,15 +185,25 @@ static void trace_delete_func(void * ptr, const char * which) // If it really is a double-delete, the malloc library on OS/X will // notify me. - live_memory_map::iterator i = live_memory->find(ptr); - if (i == live_memory->end()) + memory_map::iterator i = live_memory->find(ptr); + if (i == live_memory->end()) { + i = freed_memory->find(ptr); + if (i != freed_memory->end()) + VERIFY(! "Freeing a block of memory twice"); + else + VERIFY(! "Freeing an unknown block of memory"); + memory_tracing_active = true; return; + } std::size_t size = (*i).second.second; VERIFY((*i).second.first == which); live_memory->erase(i); + freed_memory->insert + (memory_map::value_type(ptr, allocation_pair(which, size))); + object_count_map::iterator j = live_memory_count->find(which); VERIFY(j != live_memory_count->end()); @@ -269,9 +285,9 @@ std::size_t current_objects_size() void trace_ctor_func(void * ptr, const char * cls_name, const char * args, std::size_t cls_size) { - memory_tracing_active = false; + if (! live_objects || ! memory_tracing_active) return; - if (! live_objects) return; + memory_tracing_active = false; static char name[1024]; std::strcpy(name, cls_name); @@ -282,7 +298,7 @@ void trace_ctor_func(void * ptr, const char * cls_name, const char * args, DEBUG("memory.debug", "TRACE_CTOR " << ptr << " " << name); live_objects->insert - (live_objects_map::value_type(ptr, allocation_pair(cls_name, cls_size))); + (objects_map::value_type(ptr, allocation_pair(cls_name, cls_size))); add_to_count_map(*live_object_count, cls_name, cls_size); add_to_count_map(*total_object_count, cls_name, cls_size); @@ -294,13 +310,13 @@ void trace_ctor_func(void * ptr, const char * cls_name, const char * args, void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size) { - if (! live_objects) return; + if (! live_objects || ! memory_tracing_active) return; memory_tracing_active = false; DEBUG("memory.debug", "TRACE_DTOR " << ptr << " " << cls_name); - live_objects_map::iterator i = live_objects->find(ptr); + objects_map::iterator i = live_objects->find(ptr); if (i == live_objects->end()) { warning_(_("Attempting to delete %1 a non-living %2") << ptr << cls_name); memory_tracing_active = true; @@ -331,7 +347,7 @@ void trace_dtor_func(void * ptr, const char * cls_name, std::size_t cls_size) void report_memory(std::ostream& out, bool report_all) { - if (! live_memory) return; + if (! live_memory || ! memory_tracing_active) return; if (live_memory_count->size() > 0) { out << "NOTE: There may be memory held by Boost " @@ -343,7 +359,7 @@ void report_memory(std::ostream& out, bool report_all) if (live_memory->size() > 0) { out << "Live memory:" << std::endl; - foreach (const live_memory_map::value_type& pair, *live_memory) + foreach (const memory_map::value_type& pair, *live_memory) out << " " << std::right << std::setw(12) << pair.first << " " << std::right << std::setw(7) << pair.second.second << " " << std::left << pair.second.first @@ -363,7 +379,7 @@ void report_memory(std::ostream& out, bool report_all) if (live_objects->size() > 0) { out << "Live objects:" << std::endl; - foreach (const live_objects_map::value_type& pair, *live_objects) + foreach (const objects_map::value_type& pair, *live_objects) out << " " << std::right << std::setw(12) << pair.first << " " << std::right << std::setw(7) << pair.second.second << " " << std::left << pair.second.first @@ -402,17 +418,19 @@ string::string(const char * str) : std::string(str) { string::string(const char * str, const char * end) : std::string(str, end) { TRACE_CTOR(string, "const char *, const char *"); } -string::string(const string& str, int x) : std::string(str, x) { - TRACE_CTOR(string, "const string&, int"); +string::string(const string& str, size_type x) : std::string(str, x) { + TRACE_CTOR(string, "const string&, size_type"); } -string::string(const string& str, int x, int y) : std::string(str, x, y) { - TRACE_CTOR(string, "const string&, int, int"); +string::string(const string& str, size_type x, size_type y) + : std::string(str, x, y) { + TRACE_CTOR(string, "const string&, size_type, size_type"); } -string::string(const char * str, int x) : std::string(str, x) { - TRACE_CTOR(string, "const char *, int"); +string::string(const char * str, size_type x) : std::string(str, x) { + TRACE_CTOR(string, "const char *, size_type"); } -string::string(const char * str, int x, int y) : std::string(str, x, y) { - TRACE_CTOR(string, "const char *, int, int"); +string::string(const char * str, size_type x, size_type y) + : std::string(str, x, y) { + TRACE_CTOR(string, "const char *, size_type, size_type"); } string::~string() throw() { TRACE_DTOR(string); @@ -557,6 +575,7 @@ static timer_map timers; void start_timer(const char * name, log_level_t lvl) { #if defined(VERIFY_ON) + bool tracing_active = memory_tracing_active; memory_tracing_active = false; #endif @@ -571,13 +590,14 @@ void start_timer(const char * name, log_level_t lvl) _log_buffer.str(""); #if defined(VERIFY_ON) - memory_tracing_active = true; + memory_tracing_active = tracing_active; #endif } void stop_timer(const char * name) { #if defined(VERIFY_ON) + bool tracing_active = memory_tracing_active; memory_tracing_active = false; #endif @@ -588,19 +608,24 @@ void stop_timer(const char * name) (*i).second.active = false; #if defined(VERIFY_ON) - memory_tracing_active = true; + memory_tracing_active = tracing_active; #endif } void finish_timer(const char * name) { #if defined(VERIFY_ON) + bool tracing_active = memory_tracing_active; memory_tracing_active = false; #endif timer_map::iterator i = timers.find(name); - if (i == timers.end()) + if (i == timers.end()) { +#if defined(VERIFY_ON) + memory_tracing_active = tracing_active; +#endif return; + } time_duration spent = (*i).second.spent; if ((*i).second.active) { @@ -626,7 +651,7 @@ void finish_timer(const char * name) timers.erase(i); #if defined(VERIFY_ON) - memory_tracing_active = true; + memory_tracing_active = tracing_active; #endif } diff --git a/src/utils.h b/src/utils.h index 462cef52..7f5ca017 100644 --- a/src/utils.h +++ b/src/utils.h @@ -173,10 +173,10 @@ public: string(size_type len, char x); string(const char * str); string(const char * str, const char * end); - string(const string& str, int x); - string(const string& str, int x, int y); - string(const char * str, int x); - string(const char * str, int x, int y); + string(const string& str, size_type x); + string(const string& str, size_type x, size_type y); + string(const char * str, size_type x); + string(const char * str, size_type x, size_type y); ~string() throw(); }; @@ -594,6 +594,19 @@ inline char peek_next_nonws(std::istream& in) { *_p = '\0'; \ } +inline string to_hex(uint_least32_t * message_digest) +{ + std::ostringstream buf; + + for(int i = 0; i < 5 ; i++) { + buf.width(8); + buf.fill('0'); + buf << std::hex << message_digest[i]; + break; // only output the first dword + } + return buf.str(); +} + extern const string version; } // namespace ledger diff --git a/src/value.cc b/src/value.cc index 702b889e..6ce46f5c 100644 --- a/src/value.cc +++ b/src/value.cc @@ -173,6 +173,17 @@ date_t value_t::to_date() const } } +int value_t::to_int() const +{ + if (is_long()) { + return static_cast<int>(as_long()); + } else { + value_t temp(*this); + temp.in_place_cast(INTEGER); + return static_cast<int>(temp.as_long()); + } +} + long value_t::to_long() const { if (is_long()) { @@ -973,7 +984,7 @@ void value_t::in_place_cast(type_t cast_type) set_datetime(datetime_t(as_date(), time_duration(0, 0, 0, 0))); return; case STRING: - set_string(format_date(as_date(), string("%Y-%m-%d"))); + set_string(format_date(as_date(), FMT_WRITTEN)); return; default: break; @@ -985,7 +996,7 @@ void value_t::in_place_cast(type_t cast_type) set_date(as_datetime().date()); return; case STRING: - set_string(format_datetime(as_datetime(), string("%Y-%m-%d %H:%M:%S"))); + set_string(format_datetime(as_datetime(), FMT_WRITTEN)); return; default: break; @@ -1484,16 +1495,17 @@ void value_t::print(std::ostream& out, case DATETIME: if (date_format) - out << format_datetime(as_datetime(), *date_format); + out << format_datetime(as_datetime(), FMT_CUSTOM, + date_format->c_str()); else - out << format_datetime(as_datetime()); + out << format_datetime(as_datetime(), FMT_WRITTEN); break; case DATE: if (date_format) - out << format_date(as_date(), *date_format); + out << format_date(as_date(), FMT_CUSTOM, date_format->c_str()); else - out << format_date(as_date()); + out << format_date(as_date(), FMT_WRITTEN); break; case INTEGER: @@ -1568,10 +1580,10 @@ void value_t::dump(std::ostream& out, const bool relaxed) const break; case DATETIME: - out << '[' << format_datetime(as_datetime()) << ']'; + out << '[' << format_datetime(as_datetime(), FMT_WRITTEN) << ']'; break; case DATE: - out << '[' << format_date(as_date()) << ']'; + out << '[' << format_date(as_date(), FMT_WRITTEN) << ']'; break; case INTEGER: diff --git a/src/value.h b/src/value.h index 62943e62..23c8c8d5 100644 --- a/src/value.h +++ b/src/value.h @@ -211,6 +211,8 @@ private: void destroy() { DEBUG("value.storage.refcount", "Destroying " << this); switch (type) { + case VOID: + return; case BALANCE: checked_delete(boost::get<balance_t *>(data)); break; @@ -220,6 +222,7 @@ private: default: break; } + data = false; type = VOID; } }; @@ -635,10 +638,12 @@ public: void set_string(const string& val = "") { set_type(STRING); storage->data = val; + VERIFY(boost::get<string>(storage->data) == val); } void set_string(const char * val = "") { set_type(STRING); storage->data = string(val); + VERIFY(boost::get<string>(storage->data) == val); } bool is_mask() const { @@ -733,6 +738,7 @@ public: * exception is thrown. */ bool to_boolean() const; + int to_int() const; long to_long() const; datetime_t to_datetime() const; date_t to_date() const; @@ -788,7 +794,7 @@ public: /** * Collection-style access methods for SEQUENCE values. */ - value_t& operator[](const int index) { + value_t& operator[](const std::size_t index) { VERIFY(! is_null()); if (is_sequence()) return as_sequence_lval()[index]; @@ -799,7 +805,7 @@ public: static value_t null; return null; } - const value_t& operator[](const int index) const { + const value_t& operator[](const std::size_t index) const { VERIFY(! is_null()); if (is_sequence()) return as_sequence()[index]; @@ -933,7 +939,7 @@ public: #define NULL_VALUE (value_t()) -inline value_t string_value(const string& str) { +inline value_t string_value(const string& str = "") { return value_t(str, true); } diff --git a/src/xact.cc b/src/xact.cc index bd8a5955..175a1467 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -352,6 +352,33 @@ void xact_t::add_post(post_t * post) } namespace { + value_t get_magnitude(xact_t& xact) { + balance_t halfbal; + foreach (post_t * post, xact.posts) + if (post->amount.sign() > 0) + halfbal += post->amount.number(); + return halfbal; + } + + value_t get_idstring(xact_t& xact) { + std::ostringstream buf; + buf << *xact._date; + buf << xact.payee; + + get_magnitude(xact).print(buf); + + return string_value(buf.str()); + } + value_t get_id(xact_t& xact) { + SHA1 sha; + sha.Reset(); + sha << get_idstring(xact).as_string().c_str(); + + uint_least32_t message_digest[5]; + sha.Result(message_digest); + return string_value(to_hex(message_digest)); + } + value_t get_code(xact_t& xact) { if (xact.code) return string_value(*xact.code); @@ -377,6 +404,18 @@ expr_t::ptr_op_t xact_t::lookup(const string& name) return WRAP_FUNCTOR(get_wrapper<&get_code>); break; + case 'i': + if (name == "id") + return WRAP_FUNCTOR(get_wrapper<&get_id>); + else if (name == "idstring") + return WRAP_FUNCTOR(get_wrapper<&get_idstring>); + break; + + case 'm': + if (name == "magnitude") + return WRAP_FUNCTOR(get_wrapper<&get_magnitude>); + break; + case 'p': if (name[1] == '\0' || name == "payee") return WRAP_FUNCTOR(get_wrapper<&get_payee>); diff --git a/test/baseline/opt-csv-format.test b/test/baseline/opt-csv-format.test index 7efefc0d..d4975f93 100644 --- a/test/baseline/opt-csv-format.test +++ b/test/baseline/opt-csv-format.test @@ -4,7 +4,7 @@ csv --csv-format='"%(date)"\n' Assets:Investments:Vanguard:VMMXX 0.350 VMMXX @ $1.00 Income:Dividends:Vanguard:VMMXX $-0.35 >>>1 -"07-Feb-02" -"07-Feb-02" +"2007/02/02" +"2007/02/02" >>>2 === 0 diff --git a/test/baseline/opt-prices-format.test b/test/baseline/opt-prices-format.test index ec93d9cd..f8033c59 100644 --- a/test/baseline/opt-prices-format.test +++ b/test/baseline/opt-prices-format.test @@ -10,10 +10,10 @@ P 2009/02/01 17:30:00 AAPL $50.00 Assets:Brokerage 100 AAPL Income >>>1 -09-Jan-01 13:30:00 $10.00 -09-Jan-01 14:30:00 $20.00 -09-Jan-01 15:30:00 $30.00 -09-Jan-01 16:30:00 $40.00 -09-Feb-01 17:30:00 $50.00 +2009/01/01 13:30:00 $10.00 +2009/01/01 14:30:00 $20.00 +2009/01/01 15:30:00 $30.00 +2009/01/01 16:30:00 $40.00 +2009/02/01 17:30:00 $50.00 >>>2 === 0 diff --git a/test/baseline/opt-pricesdb-format.test b/test/baseline/opt-pricesdb-format.test index 28998903..b90371cd 100644 --- a/test/baseline/opt-pricesdb-format.test +++ b/test/baseline/opt-pricesdb-format.test @@ -10,10 +10,10 @@ P 2009/02/01 17:30:00 AAPL $50.00 Assets:Brokerage 100 AAPL Income >>>1 -P 09-Jan-01 $10.00 -P 09-Jan-01 $20.00 -P 09-Jan-01 $30.00 -P 09-Jan-01 $40.00 -P 09-Feb-01 $50.00 +P 2009/01/01 $10.00 +P 2009/01/01 $20.00 +P 2009/01/01 $30.00 +P 2009/01/01 $40.00 +P 2009/02/01 $50.00 >>>2 === 0 diff --git a/test/regress/BBFA1759.test b/test/regress/BBFA1759.test index ca6842dc..26862703 100644 --- a/test/regress/BBFA1759.test +++ b/test/regress/BBFA1759.test @@ -3,8 +3,8 @@ period june 2008 >>>1 global details => - start: 2008-06-01 - end: 2008-07-01 + start: 08-Jun-01 + end: 08-Jul-01 factor: 1 >>>2 === 0 diff --git a/test/unit/t_amount.cc b/test/unit/t_amount.cc index ba863ca7..c2a6b8c9 100644 --- a/test/unit/t_amount.cc +++ b/test/unit/t_amount.cc @@ -11,6 +11,7 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AmountTestCase, "math"); void AmountTestCase::setUp() { + times_initialize(); amount_t::initialize(); // Cause the display precision for dollars to be initialized to 2. @@ -24,6 +25,7 @@ void AmountTestCase::tearDown() { amount_t::stream_fullstrings = false; amount_t::shutdown(); + times_shutdown(); } void AmountTestCase::testParser() diff --git a/test/unit/t_balance.cc b/test/unit/t_balance.cc index 335d1a52..c7d633b8 100644 --- a/test/unit/t_balance.cc +++ b/test/unit/t_balance.cc @@ -11,6 +11,7 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(BalanceTestCase, "math"); void BalanceTestCase::setUp() { + times_initialize(); amount_t::initialize(); // Cause the display precision for dollars to be initialized to 2. @@ -24,4 +25,5 @@ void BalanceTestCase::tearDown() { amount_t::stream_fullstrings = false; amount_t::shutdown(); + times_shutdown(); } diff --git a/test/unit/t_commodity.cc b/test/unit/t_commodity.cc index de46211c..3d84ead6 100644 --- a/test/unit/t_commodity.cc +++ b/test/unit/t_commodity.cc @@ -10,12 +10,14 @@ using namespace ledger; CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(CommodityTestCase, "math"); void CommodityTestCase::setUp() { + times_initialize(); amount_t::initialize(); amount_t::stream_fullstrings = true; } void CommodityTestCase::tearDown() { amount_t::shutdown(); + times_shutdown(); } void CommodityTestCase::testPriceHistory() diff --git a/test/unit/t_expr.cc b/test/unit/t_expr.cc index 49d7dd23..6c88a08a 100644 --- a/test/unit/t_expr.cc +++ b/test/unit/t_expr.cc @@ -10,10 +10,12 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ValueExprTestCase, "expr"); void ValueExprTestCase::setUp() { + times_initialize(); amount_t::initialize(); } void ValueExprTestCase::tearDown() { amount_t::shutdown(); + times_shutdown(); } diff --git a/test/unit/t_times.cc b/test/unit/t_times.cc index 8485a2c9..d8a67b43 100644 --- a/test/unit/t_times.cc +++ b/test/unit/t_times.cc @@ -9,6 +9,16 @@ using namespace ledger; CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(DateTimeTestCase, "util"); +void DateTimeTestCase::setUp() +{ + times_initialize(); +} + +void DateTimeTestCase::tearDown() +{ + times_shutdown(); +} + void DateTimeTestCase::testConstructors() { #ifndef NOT_FOR_PYTHON diff --git a/test/unit/t_times.h b/test/unit/t_times.h index 28784113..5bbadf21 100644 --- a/test/unit/t_times.h +++ b/test/unit/t_times.h @@ -15,8 +15,8 @@ public: DateTimeTestCase() {} virtual ~DateTimeTestCase() {} - //virtual void setUp(); - //virtual void tearDown(); + virtual void setUp(); + virtual void tearDown(); void testConstructors(); |