diff options
59 files changed, 675 insertions, 463 deletions
@@ -245,8 +245,8 @@ class CommandLineApp(object): force_exit = True # If true, always ends run() with sys.exit() log_handler = None darwin_gcc = False - boost_version = "1_46_1" - boost_major = "1_46_1" + boost_version = "1_47_0" + boost_major = "1_47" options = { 'debug': False, @@ -338,7 +338,7 @@ class CommandLineApp(object): self.log.setLevel(logging.DEBUG) elif self.options.verbose: self.log.setLevel(logging.INFO) - + exit_code = 0 try: # We could just call main() and catch a TypeError, but that would @@ -928,7 +928,7 @@ class PrepareBuild(CommandLineApp): def setup_system_directories(self): boost_include = self.boost_info.include_directory() boost_library = self.boost_info.library_directory() - + if re.match('/opt/local', self.boost_info.home_path): self.log.debug("Setting Python home to /opt/local based on Boost's location") self.envvars['PYTHON_HOME'] = '/opt/local' @@ -1252,7 +1252,7 @@ class PrepareBuild(CommandLineApp): home_path = '/usr/local/stow/boost_%s-%s' % \ (self.boost_version, self.boost_inc_ident), suffix = '-%s-sd-%s' % \ - (self.boost_lib_ident, self.boost_version), + (self.boost_lib_ident, self.boost_major), file_suffix = '.dylib', include_path = 'include/boost-%s' % self.boost_major): pass @@ -1260,7 +1260,7 @@ class PrepareBuild(CommandLineApp): home_path = '/usr/local/stow/boost_%s-%s' % \ (self.boost_version, self.boost_inc_ident), suffix = '-%s-d-%s' % \ - (self.boost_lib_ident, self.boost_version), + (self.boost_lib_ident, self.boost_major), file_suffix = '.dylib', include_path = 'include/boost-%s' % self.boost_major): pass @@ -1274,7 +1274,7 @@ class PrepareBuild(CommandLineApp): home_path = '/usr/local/stow/boost_%s-%s' % \ (self.boost_version, self.boost_inc_ident), suffix = '-%s-s-%s' % \ - (self.boost_lib_ident, self.boost_version), + (self.boost_lib_ident, self.boost_major), file_suffix = '.dylib', include_path = 'include/boost-%s' % self.boost_major): pass @@ -1282,7 +1282,7 @@ class PrepareBuild(CommandLineApp): home_path = '/usr/local/stow/boost_%s-%s' % \ (self.boost_version, self.boost_inc_ident), suffix = '-%s-%s' % \ - (self.boost_lib_ident, self.boost_version), + (self.boost_lib_ident, self.boost_major), file_suffix = '.dylib', include_path = 'include/boost-%s' % self.boost_major): pass @@ -1518,7 +1518,7 @@ class PrepareBuild(CommandLineApp): match = re.search('/opt/local/lib/(.+?)\.dylib', line) if not match: continue - + lib = match.group(0) base = basename(lib) @@ -1587,7 +1587,7 @@ class PrepareBuild(CommandLineApp): def phase_distcheck(self, *args): self.log.info('Executing phase: distcheck') - + self.configure_flavor('default', False) environ, conf_args = self.configure_environment() @@ -1621,7 +1621,7 @@ class PrepareBuild(CommandLineApp): '%s/' % self.source_dir, '%s/' % source_copy_dir) self.source_dir = source_copy_dir - + def phase_proof(self, *args): self.log.info('Executing phase: proof') @@ -1633,15 +1633,15 @@ class PrepareBuild(CommandLineApp): self.configure_flavor('opt', reset=False) self.log.info('=== Testing opt ===') self.phase_make('fullcheck') - + self.configure_flavor('gcov', reset=False) self.log.info('=== Testing gcov ===') self.phase_make('check') - + self.configure_flavor('debug', reset=False) self.log.info('=== Testing debug ===') self.phase_make('fullcheck') - + self.configure_flavor('default', reset=False) self.log.info('=== Testing default ===') self.phase_make('fullcheck') @@ -1654,14 +1654,14 @@ class PrepareBuild(CommandLineApp): self.log.info('Executing phase: makeall') self.configure_flavor('opt', reset) - + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') if exists(system_hh_gch): os.remove(system_hh_gch) self.log.info('=== Building opt ===') self.phase_make(*args) - + self.configure_flavor('gcov', reset) system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') @@ -1670,7 +1670,7 @@ class PrepareBuild(CommandLineApp): self.log.info('=== Building gcov ===') self.phase_make(*args) - + system_hh_gch = join(self.source_dir, 'src', 'system.hh.gch') if exists(system_hh_gch): os.remove(system_hh_gch) @@ -1686,7 +1686,7 @@ class PrepareBuild(CommandLineApp): self.log.info('=== Building debug ===') self.phase_make(*args) - + self.configure_flavor('default', reset) ######################################################################### @@ -1696,7 +1696,7 @@ class PrepareBuild(CommandLineApp): def phase_help(self, *args): self.option_parser.print_help() - print """ + print """ Of the optional ARGS, the first is an optional build FLAVOR, with the default being 'debug': diff --git a/contrib/vim/README b/contrib/vim/README index 368c9c71..a3f5a877 100644 --- a/contrib/vim/README +++ b/contrib/vim/README @@ -6,6 +6,22 @@ Then include the following line in your .vimrc or in ~/.vim/filetype.vim You can also use a modeline like this in every ledger file vim:filetype=ledger +Tips and useful commands +====================================================================== + • Try account-completion (as explained below) + • :call LedgerSetDate(line('.'), 'effective') + will set today's date as the effective date of the current + transaction. You can use also 'actual' in place of 'effective' + or pass in a different date measured as seconds since 1st Jan 1970. + • :call LedgerSetTransactionState(line('.'), '*') + sets the state of the current transaction to '*'. You can + use this in custom mappings. + • :call LedgerToggleTransactionState(line('.'), ' *?!') + will toggle through the provided transaction states. + You can map this to double-clicking for example: + noremap <silent><buffer> <2-LeftMouse> + \ :call LedgerToggleTransactionState(line('.'), ' *?!')<CR> + Configuration ====================================================================== Include the following let-statements somewhere in your .vimrc @@ -35,7 +51,7 @@ to modify the behaviour of the ledger filetype. Completion ====================================================================== -Omni completion is implemented for account names and tags. +Omni completion is currently implemented for account names only. Accounts ---------------------------------------------------------------------- @@ -52,38 +68,11 @@ When you want to complete on a virtual transaction, it's currently best to keep the cursor in front of the closing bracket. Of course you can insert the closing bracket after calling the completion, too. -Tags ----------------------------------------------------------------------- -The support for completing tags is pretty basic right now -but it's useful to keep the spelling of your tags consistent. -You can call the completion after the ';' to get a list of all tags. -When you have a list of tags (:like: :this:) you can call -the completion too and everything up to the last ':' (excluding whitespace) -will be considered the beginning of the tag to search for. - -Revision history (major changes) -====================================================================== - 2009-06-23 & 2009-06-25 - J. Klähn: Omni-Completion for account names and tags - 2009-06-17 J. Klähn: Highlight account text - Updated documentation and added fillstring option. - 2009-06-15 J. Klähn: Split into multiple files - 2009-06-12 J. Klähn: Use all available columns for foldtext - Also rewrote foldtext generation. - 2009-03-25 J. Klähn: Allow Metadata - in transactions and postings (Ledger 3.0) - Also fixed alignment for multi-byte-characters - 2009-01-28 S.Karrmann: minor fixes - 2009-01-27 third version by S.Karrmann. - better extraction of the amount of the posting - decimal separator can be one of '.' and ','. - 2005-02-05 first version (partly copied from ledger.vim 0.0.1) - License ====================================================================== -Copyright 2009 by Johann Klähn -Copyright 2009 by Stefan Karrmann -Copyright 2005 by Wolfgang Oertl +Copyright 2011-2009 by Johann Klähn +Copyright 2009 by Stefan Karrmann +Copyright 2005 by Wolfgang Oertl This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index d1c8e1a9..9cc4ed91 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -1,6 +1,5 @@ " Vim filetype plugin file " filetype: ledger -" Version: 0.1.0 " by Johann Klähn; Use according to the terms of the GPL>=2. " vim:ts=2:sw=2:sts=2:foldmethod=marker @@ -137,22 +136,33 @@ function! LedgerComplete(findstart, base) "{{{1 if a:findstart let lnum = line('.') let line = getline('.') - let lastcol = col('.') - 2 let b:compl_context = '' if line =~ '^\s\+[^[:blank:];]' "{{{2 (account) - let b:compl_context = 'account' - if matchend(line, '^\s\+\%(\S \S\|\S\)\+') <= lastcol - " only allow completion when in or at end of account name - return -1 + " only allow completion when in or at end of account name + if matchend(line, '^\s\+\%(\S \S\|\S\)\+') >= col('.') - 1 + " the start of the first non-blank character + " (excluding virtual-transaction-marks) + " is the beginning of the account name + let b:compl_context = 'account' + return matchend(line, '^\s\+[\[(]\?') endif - " the start of the first non-blank character - " (excluding virtual-transaction-marks) - " is the beginning of the account name - return matchend(line, '^\s\+[\[(]\?') - else "}}} - return -1 - endif + elseif line =~ '^\d' "{{{2 (description) + let pre = matchend(line, '^\d\S\+\%(([^)]*)\|[*?!]\|\s\)\+') + if pre < col('.') - 1 + let b:compl_context = 'description' + return pre + endif + elseif line =~ '^$' "{{{2 (new line) + let b:compl_context = 'new' + endif "}}} + return -1 else + if ! exists('b:compl_cache') + let b:compl_cache = s:collect_completion_data() + let b:compl_cache['#'] = changenr() + endif + + let results = [] if b:compl_context == 'account' "{{{2 (account) unlet! b:compl_context let hierarchy = split(a:base, ':') @@ -160,7 +170,7 @@ function! LedgerComplete(findstart, base) "{{{1 call add(hierarchy, '') endif - let results = LedgerFindInTree(LedgerGetAccountHierarchy(), hierarchy) + let results = LedgerFindInTree(b:compl_cache.accounts, hierarchy) " sort by alphabet and reverse because it will get reversed one more time if g:ledger_detailed_first let results = reverse(sort(results, 's:sort_accounts_by_depth')) @@ -168,10 +178,19 @@ function! LedgerComplete(findstart, base) "{{{1 let results = sort(results) endif call insert(results, a:base) - return results - else "}}} + elseif b:compl_context == 'description' "{{{2 (description) + let results = [a:base] + s:filter_items(b:compl_cache.descriptions, a:base) + elseif b:compl_context == 'new' "{{{2 (new line) + return [strftime('%Y/%m/%d')] + endif "}}} + + " no completion (apart from a:base) found. update cache if file has changed + if len(results) <= 1 && b:compl_cache['#'] != changenr() + unlet b:compl_cache + return LedgerComplete(a:findstart, a:base) + else unlet! b:compl_context - return [] + return results endif endif endf "}}} @@ -195,21 +214,6 @@ function! LedgerFindInTree(tree, levels) "{{{1 return results endf "}}} -function! LedgerGetAccountHierarchy() "{{{1 - let hierarchy = {} - let accounts = s:grep_buffer('^\s\+\zs[^[:blank:];]\%(\S \S\|\S\)\+\ze') - for name in accounts - " remove virtual-transaction-marks - let name = substitute(name, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') - let last = hierarchy - for part in split(name, ':') - let last[part] = get(last, part, {}) - let last = last[part] - endfor - endfor - return hierarchy -endf "}}} - function! LedgerToggleTransactionState(lnum, ...) if a:0 == 1 let chars = a:1 @@ -278,6 +282,51 @@ function! LedgerSetDate(lnum, type, ...) "{{{1 call setline(trans['head'], trans.format_head()) endf "}}} +function! s:collect_completion_data() "{{{1 + let transactions = s:get_transactions() + let cache = {'descriptions': [], 'tags': {}, 'accounts': {}} + let accounts = [] + for xact in transactions + " collect descriptions + if index(cache.descriptions, xact['description']) < 0 + call add(cache.descriptions, xact['description']) + endif + let [t, postings] = xact.parse_body() + let tagdicts = [t] + + " collect account names + for posting in postings + if has_key(posting, 'tags') + call add(tagdicts, posting.tags) + endif + " remove virtual-transaction-marks + let name = substitute(posting.account, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') + if index(accounts, name) < 0 + call add(accounts, name) + endif + endfor + + " collect tags + for tags in tagdicts | for [tag, val] in items(tags) + let values = get(cache.tags, tag, []) + if index(values, val) < 0 + call add(values, val) + endif + let cache.tags[tag] = values + endfor | endfor + endfor + + for account in accounts + let last = cache.accounts + for part in split(account, ':') + let last[part] = get(last, part, {}) + let last = last[part] + endfor + endfor + + return cache +endf "}}} + let s:transaction = {} "{{{1 function! s:transaction.new() dict return copy(s:transaction) @@ -293,7 +342,15 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 let trans['head'] = head let trans['tail'] = tail - let parts = split(getline(head), '\s\+') + " split off eventual comments at the end of line + let line = split(getline(head), '\ze\s*\%(\t\| \);', 1) + if len(line) > 1 + let trans['appendix'] = join(line[1:], '') + endif + + " parse rest of line + " FIXME (minor): will not preserve spacing (see 'join(parts)') + let parts = split(line[0], '\s\+') if parts[0] ==# '~' let trans['expr'] = join(parts[1:]) return trans @@ -318,8 +375,6 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 call remove(parts, 0) endfor - " FIXME: this will break comments at the end of this 'head' line - " they need 2 spaces in front of the semicolon let trans['description'] = join(parts) return trans endf "}}} @@ -402,7 +457,11 @@ function! s:transaction.format_head() dict "{{{2 if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif if has_key(self, 'state') | call add(parts, self['state']) | endif if has_key(self, 'description') | call add(parts, self['description']) | endif - return join(parts) + + let line = join(parts) + if has_key(self, 'appendix') | let line .= self['appendix'] | endif + + return line endf "}}} "}}} @@ -518,7 +577,7 @@ endf "}}} " return only those items that start with a specified keyword function! s:filter_items(list, keyword) "{{{2 - return filter(a:list, 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') + return filter(copy(a:list), 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') endf "}}} " return all lines matching an expression, returning only the matched part diff --git a/contrib/vim/syntax/ledger.vim b/contrib/vim/syntax/ledger.vim index c6845488..73aaa0c3 100644 --- a/contrib/vim/syntax/ledger.vim +++ b/contrib/vim/syntax/ledger.vim @@ -1,19 +1,8 @@ " Vim syntax file " filetype: ledger -" Version: 0.1.0 " by Johann Klähn; Use according to the terms of the GPL>=2. " by Stefan Karrmann; Use according to the terms of the GPL>=2. " by Wolfgang Oertl; Use according to the terms of the GPL>=2. -" Revision history -" 2009-06-12 J. Klähn: Use all available columns for foldtext -" 2009-03-25 J. Klähn: Allow Metadata -" in transactions and postings (Ledger 3.0) -" Also fixed alignment for multi-byte-characters -" 2009-01-28 S.Karrmann: minor fixes -" 2009-01-27 third version by S.Karrmann. -" better extraction of the amount of the posting -" decimal separator can be one of '.' and ','. -" 2005-02-05 first version (partly copied from ledger.vim 0.0.1) " vim:ts=2:sw=2:sts=2:foldmethod=marker if version < 600 diff --git a/lib/Makefile b/lib/Makefile index e2d5dd2b..734816af 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,8 +5,8 @@ STOW_ROOT = /usr/local/stow PRODUCTS = $(HOME)/Products -GCC_VERSION = 4.6 -BOOST_VERSION = 1_46_1 +GCC_VERSION = 4.5 +BOOST_VERSION = 1_47_0 CC = gcc-mp-$(GCC_VERSION) ifeq ($(CC),clang) @@ -51,7 +51,7 @@ all: boost-build #icu-build boost-icu-build prepare-boost: perl -i -pe 's/local command = \[ common\.get-invocation-command darwin : g\+\+ : .*/local command = [ common.get-invocation-command darwin : g++ : $(CXX) ] ;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam - perl -i -pe 's/flags darwin\.compile OPTIONS : -no-cpp-precomp -gdwarf-2 ;/flags darwin\.compile OPTIONS : -gdwarf-2 ;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam + perl -i -pe 's/flags darwin\.compile OPTIONS : -no-cpp-precomp -gdwarf-2 (-fexceptions )?;/flags darwin\.compile OPTIONS : -gdwarf-2 \1;/;' $(BOOST_SOURCE)/tools/build/v2/tools/darwin.jam boost-build: prepare-boost (cd $(BOOST_SOURCE) && \ diff --git a/lisp/ldg-new.el b/lisp/ldg-new.el index 84863c95..64377bb9 100644 --- a/lisp/ldg-new.el +++ b/lisp/ldg-new.el @@ -53,4 +53,30 @@ (provide 'ledger) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun ledger-create-test () + (interactive) + (save-restriction + (org-narrow-to-subtree) + (save-excursion + (let (text beg) + (goto-char (point-min)) + (forward-line 1) + (setq beg (point)) + (search-forward ":PROPERTIES:") + (goto-char (line-beginning-position)) + (setq text (buffer-substring-no-properties beg (point))) + (goto-char (point-min)) + (re-search-forward ":ID:\\s-+\\([^-]+\\)") + (find-file-other-window + (format "~/src/ledger/test/regress/%s.test" (match-string 1))) + (sit-for 0) + (insert text) + (goto-char (point-min)) + (while (not (eobp)) + (goto-char (line-beginning-position)) + (delete-char 3) + (forward-line 1)))))) + ;;; ledger.el ends here diff --git a/lisp/ledger.el b/lisp/ledger.el index 25bb485b..2d15f090 100644 --- a/lisp/ledger.el +++ b/lisp/ledger.el @@ -433,7 +433,9 @@ dropped." ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files." + "A mode for editing ledger data files. + +\\{ledger-mode-map}" (set (make-local-variable 'comment-start) " ; ") (set (make-local-variable 'comment-end) "") (set (make-local-variable 'indent-tabs-mode) nil) @@ -632,8 +634,7 @@ dropped." (defvar ledger-reconcile-mode-abbrev-table) -(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries." +(defvar ledger-reconcile-mode-map (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) @@ -647,7 +648,12 @@ dropped." (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) - (use-local-map map))) + map)) + +(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" + "A mode for reconciling ledger entries. + +\\{ledger-reconcile-mode-map}") ;; Context sensitivity @@ -807,8 +813,7 @@ specified line, returns nil." (defvar ledger-report-mode-abbrev-table) -(define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports." +(defvar ledger-report-mode-map (let ((map (make-sparse-keymap))) (define-key map [? ] 'scroll-up) (define-key map [backspace] 'scroll-down) @@ -825,7 +830,10 @@ specified line, returns nil." 'ledger-report-kill) (define-key map [(control ?c) (control ?l) (control ?e)] 'ledger-report-edit) - (use-local-map map))) + map)) + +(define-derived-mode ledger-report-mode text-mode "Ledger-Report" + "A mode for viewing ledger reports.") (defun ledger-report-read-name () "Read the name of a ledger report to use, with completion. @@ -1201,7 +1209,7 @@ the default." ;; A sample function for $ users (defun ledger-next-amount (&optional end) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) + (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) diff --git a/src/account.cc b/src/account.cc index 3e0ad086..36070a52 100644 --- a/src/account.cc +++ b/src/account.cc @@ -45,7 +45,7 @@ account_t::~account_t() if (! pair.second->has_flags(ACCOUNT_TEMP) || has_flags(ACCOUNT_TEMP)) { checked_delete(pair.second); - } + } } } diff --git a/src/amount.cc b/src/amount.cc index 1dc160cc..808f118d 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -152,7 +152,7 @@ namespace { if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0) throw_(amount_error, _("Cannot output amount to a floating-point representation")); - + DEBUG("amount.convert", "mpfr_print = " << buf << " (precision " << precision << ", zeros_prec " << zeros_prec << ")"); @@ -1049,16 +1049,12 @@ bool amount_t::parse(std::istream& in, const parse_flags_t& flags) // Create the commodity if has not already been seen, and update the // precision if something greater was used for the quantity. - bool newly_created = false; - if (symbol.empty()) { commodity_ = NULL; } else { commodity_ = commodity_pool_t::current_pool->find(symbol); - if (! commodity_) { + if (! commodity_) commodity_ = commodity_pool_t::current_pool->create(symbol); - newly_created = true; - } assert(commodity_); if (details) diff --git a/src/amount.h b/src/amount.h index 8a2ebf04..f7e877a7 100644 --- a/src/amount.h +++ b/src/amount.h @@ -349,7 +349,7 @@ public: return temp; } void in_place_truncate(); - + /** Yields an amount which has lost all of its extra precision, beyond what the display precision of the commodity would have printed. */ amount_t floored() const { @@ -358,7 +358,7 @@ public: return temp; } void in_place_floor(); - + /** Yields an amount whose display precision is never truncated, even though its commodity normally displays only rounded values. */ amount_t unrounded() const { diff --git a/src/chain.cc b/src/chain.cc index 67f2c8d5..450e3758 100644 --- a/src/chain.cc +++ b/src/chain.cc @@ -138,9 +138,9 @@ post_handler_ptr chain_post_handlers(post_handler_ptr base_handler, report.HANDLED(tail_) ? report.HANDLER(tail_).value.to_int() : 0)); - // changed_value_posts adds virtual posts to the list to account for changes - // in market value of commodities, which otherwise would affect the running - // total unpredictably. + // display_filter_posts adds virtual posts to the list to account + // for changes in value of commodities, which otherwise would affect + // the running total unpredictably. display_filter = new display_filter_posts(handler, report, report.HANDLED(revalued) && ! report.HANDLED(no_rounding)); diff --git a/src/commodity.cc b/src/commodity.cc index f8a4b364..5685059d 100644 --- a/src/commodity.cc +++ b/src/commodity.cc @@ -444,7 +444,7 @@ commodity_t::find_price(const optional<commodity_t&>& commodity, return point; } return none; -} +} optional<price_point_t> commodity_t::check_for_updated_price(const optional<price_point_t>& point, @@ -758,7 +758,7 @@ void to_xml(std::ostream& out, const commodity_t& comm, out << '"'; x.close_attrs(); - + { push_xml y(out, "symbol"); out << y.guard(comm.symbol()); diff --git a/src/commodity.h b/src/commodity.h index fcd26da0..d7747b2a 100644 --- a/src/commodity.h +++ b/src/commodity.h @@ -376,7 +376,7 @@ public: #if defined(DEBUG_ON) , const int indent = 0 #endif - ) const; + ) const; optional<price_point_t> check_for_updated_price(const optional<price_point_t>& point, diff --git a/src/compare.h b/src/compare.h index 0ba9d424..0e7bf5e5 100644 --- a/src/compare.h +++ b/src/compare.h @@ -58,7 +58,7 @@ class compare_items expr_t sort_order; compare_items(); - + public: compare_items(const compare_items& other) : sort_order(other.sort_order) { TRACE_CTOR(compare_items, "copy"); diff --git a/src/convert.cc b/src/convert.cc index 5d3f23fa..493fbb7a 100644 --- a/src/convert.cc +++ b/src/convert.cc @@ -62,10 +62,10 @@ value_t convert_command(call_scope_t& args) post_map_t post_map; xacts_iterator journal_iter(journal); - while (xact_t * xact = journal_iter()) { + while (xact_t * xact = *journal_iter++) { post_t * post = NULL; xact_posts_iterator xact_iter(*xact); - while ((post = xact_iter()) != NULL) { + while ((post = *xact_iter++) != NULL) { if (post->account == bucket) break; } @@ -95,7 +95,7 @@ value_t convert_command(call_scope_t& args) foreach (post_t * post, xact->posts) post->amount.in_place_negate(); } - + bool matched = false; if (! xact->posts.front()->amount.is_null()) { post_map_t::iterator i = post_map.find(- xact->posts.front()->amount); @@ -121,14 +121,10 @@ value_t convert_command(call_scope_t& args) } else { if (xact->posts.front()->account == NULL) { - xacts_iterator xi; - xi.xacts_i = current_xacts.begin(); - xi.xacts_end = current_xacts.end(); - xi.xacts_uninitialized = false; - // jww (2010-03-07): Bind this logic to an option: --auto-match if (account_t * acct = - lookup_probable_account(xact->payee, xi, bucket).second) + lookup_probable_account(xact->payee, current_xacts.rbegin(), + current_xacts.rend(), bucket).second) xact->posts.front()->account = acct; else xact->posts.front()->account = unknown; @@ -141,7 +137,7 @@ value_t convert_command(call_scope_t& args) } else { xact_posts_iterator xact_iter(*xact); - while (post_t * post = xact_iter()) + while (post_t * post = *xact_iter++) formatter(*post); } } @@ -289,7 +289,7 @@ xact_t * csv_reader::read_xact(journal_t& journal, account_t * bucket) amt.set_commodity(*commodity_pool_t::current_pool->default_commodity); post->assigned_amount = amt; } - + xact->add_post(post.release()); return xact.release(); diff --git a/src/draft.cc b/src/draft.cc index ba78fc42..0cce1d5d 100644 --- a/src/draft.cc +++ b/src/draft.cc @@ -66,16 +66,6 @@ void draft_t::xact_template_t::dump(std::ostream& out) const << _("<Posting copied from last related transaction>") << std::endl; } else { - bool has_only_from = true; - bool has_only_to = true; - - foreach (const post_template_t& post, posts) { - if (post.from) - has_only_to = false; - else - has_only_from = false; - } - foreach (const post_template_t& post, posts) { straccstream accum; out << std::endl @@ -245,12 +235,12 @@ xact_t * draft_t::insert(journal_t& journal) if (tmpl->payee_mask.empty()) throw std::runtime_error(_("'xact' command requires at least a payee")); - xact_t * matching = NULL; - + xact_t * matching = NULL; std::auto_ptr<xact_t> added(new xact_t); - xacts_iterator xi(journal); - if (xact_t * xact = lookup_probable_account(tmpl->payee_mask.str(), xi).first) { + if (xact_t * xact = + lookup_probable_account(tmpl->payee_mask.str(), journal.xacts.rbegin(), + journal.xacts.rend()).first) { DEBUG("draft.xact", "Found payee by lookup: transaction on line " << xact->pos->beg_line); matching = xact; diff --git a/src/error.cc b/src/error.cc index 02413ef6..542d12b9 100644 --- a/src/error.cc +++ b/src/error.cc @@ -93,10 +93,10 @@ string source_context(const path& file, assert(len < 8192); std::ostringstream out; - + ifstream in(file); in.seekg(pos, std::ios::beg); - + scoped_array<char> buf(new char[static_cast<std::size_t>(len) + 1]); in.read(buf.get(), static_cast<std::streamsize>(len)); assert(in.gcount() == static_cast<std::streamsize>(len)); diff --git a/src/exprbase.h b/src/exprbase.h index 83ef34ff..d86ee14c 100644 --- a/src/exprbase.h +++ b/src/exprbase.h @@ -130,7 +130,7 @@ public: const optional<string>& original_string = none) { set_text(original_string ? *original_string : "<stream>"); } - + virtual void mark_uncompiled() { compiled = false; } diff --git a/src/filters.cc b/src/filters.cc index a39fc951..5bad0414 100644 --- a/src/filters.cc +++ b/src/filters.cc @@ -53,7 +53,7 @@ void post_splitter::flush() { foreach (value_to_posts_map::value_type& pair, posts_map) { preflush_func(pair.first); - + foreach (post_t * post, pair.second) (*post_chain)(*post); @@ -83,25 +83,6 @@ void post_splitter::operator()(post_t& post) } } -pass_down_posts::pass_down_posts(post_handler_ptr handler, - posts_iterator& iter) - : item_handler<post_t>(handler) -{ - TRACE_CTOR(pass_down_posts, "post_handler_ptr, posts_iterator"); - - for (post_t * post = iter(); post; post = iter()) { - try { - item_handler<post_t>::operator()(*post); - } - catch (const std::exception&) { - add_error_context(item_context(*post, _("While handling posting"))); - throw; - } - } - - item_handler<post_t>::flush(); -} - void truncate_xacts::flush() { if (! posts.size()) @@ -434,7 +415,7 @@ void collapse_posts::report_subtotal() bind_scope_t bound_scope(report, *post); if (only_predicate(bound_scope) && display_predicate(bound_scope)) displayed_count++; - } + } if (displayed_count == 1) { item_handler<post_t>::operator()(*last_post); @@ -460,6 +441,7 @@ void collapse_posts::report_subtotal() xact.payee = last_xact->payee; xact._date = (is_valid(earliest_date) ? earliest_date : last_xact->_date); + DEBUG("filters.collapse", "Pseudo-xact date = " << *xact._date); DEBUG("filters.collapse", "earliest date = " << earliest_date); DEBUG("filters.collapse", "latest date = " << latest_date); @@ -523,14 +505,11 @@ display_filter_posts::display_filter_posts(post_handler_ptr handler, report_t& _report, bool _show_rounding) : item_handler<post_t>(handler), report(_report), + display_amount_expr(report.HANDLER(display_amount_).expr), + display_total_expr(report.HANDLER(display_total_).expr), show_rounding(_show_rounding) { - TRACE_CTOR(display_filter_posts, - "post_handler_ptr, report_t&, account_t&, bool"); - - display_amount_expr = report.HANDLER(display_amount_).expr; - display_total_expr = report.HANDLER(display_total_).expr; - + TRACE_CTOR(display_filter_posts, "post_handler_ptr, report_t&, bool"); create_accounts(); } @@ -606,17 +585,17 @@ changed_value_posts::changed_value_posts bool _show_unrealized, display_filter_posts * _display_filter) : item_handler<post_t>(handler), report(_report), + total_expr(report.HANDLED(revalued_total_) ? + report.HANDLER(revalued_total_).expr : + report.HANDLER(display_total_).expr), + display_total_expr(report.HANDLER(display_total_).expr), + changed_values_only(report.HANDLED(revalued_only)), for_accounts_report(_for_accounts_report), show_unrealized(_show_unrealized), last_post(NULL), display_filter(_display_filter) { - TRACE_CTOR(changed_value_posts, "post_handler_ptr, report_t&, bool"); - - total_expr = (report.HANDLED(revalued_total_) ? - report.HANDLER(revalued_total_).expr : - report.HANDLER(display_total_).expr); - display_total_expr = report.HANDLER(display_total_).expr; - changed_values_only = report.HANDLED(revalued_only); + TRACE_CTOR(changed_value_posts, + "post_handler_ptr, report_t&, bool, bool, display_filter_posts *"); string gains_equity_account_name; if (report.HANDLED(unrealized_gains_)) @@ -755,7 +734,7 @@ void changed_value_posts::output_intermediate_prices(post_t& post, case value_t::DATE: default: assert(false); - break; + break; } bind_scope_t inner_scope(report, temp); @@ -937,8 +916,6 @@ void interval_posts::report_subtotal(const date_interval_t& interval) void interval_posts::operator()(post_t& post) { - date_t date = post.date(); - if (! interval.find_period(post.date())) return; @@ -1373,7 +1350,7 @@ inject_posts::inject_posts(post_handler_ptr handler, account_t * master) : item_handler<post_t>(handler) { - TRACE_CTOR(inject_posts, "post_handler_ptr, string"); + TRACE_CTOR(inject_posts, "post_handler_ptr, string, account_t *"); scoped_array<char> buf(new char[tag_list.length() + 1]); std::strcpy(buf.get(), tag_list.c_str()); @@ -1381,9 +1358,9 @@ inject_posts::inject_posts(post_handler_ptr handler, for (char * q = std::strtok(buf.get(), ","); q; q = std::strtok(NULL, ",")) { - std::list<string> account_names; split_string(q, ':', account_names); + account_t * account = create_temp_account_from_path(account_names, temps, master); account->add_flags(ACCOUNT_GENERATED); @@ -1397,13 +1374,12 @@ void inject_posts::operator()(post_t& post) { foreach (tags_list_pair& pair, tags_list) { optional<value_t> tag_value = post.get_tag(pair.first, false); + // When checking if the transaction has the tag, only inject once + // per transaction. if (! tag_value && - pair.second.second.find(post.xact) == pair.second.second.end()) { - // When checking if the transaction has the tag, only inject once - // per transaction. + pair.second.second.find(post.xact) == pair.second.second.end() && + (tag_value = post.xact->get_tag(pair.first))) pair.second.second.insert(post.xact); - tag_value = post.xact->get_tag(pair.first); - } if (tag_value) { xact_t& xact = temps.copy_xact(*post.xact); @@ -1422,25 +1398,4 @@ void inject_posts::operator()(post_t& post) item_handler<post_t>::operator()(post); } -pass_down_accounts::pass_down_accounts(acct_handler_ptr handler, - accounts_iterator& iter, - const optional<predicate_t>& _pred, - const optional<scope_t&>& _context) - : item_handler<account_t>(handler), pred(_pred), context(_context) -{ - TRACE_CTOR(pass_down_accounts, "acct_handler_ptr, accounts_iterator, ..."); - - for (account_t * account = iter(); account; account = iter()) { - if (! pred) { - item_handler<account_t>::operator()(*account); - } else { - bind_scope_t bound_scope(*context, *account); - if ((*pred)(bound_scope)) - item_handler<account_t>::operator()(*account); - } - } - - item_handler<account_t>::flush(); -} - } // namespace ledger diff --git a/src/filters.h b/src/filters.h index 2916857d..e7a2eefa 100644 --- a/src/filters.h +++ b/src/filters.h @@ -73,10 +73,10 @@ public: post_splitter(post_handler_ptr _post_chain, report_t& _report, expr_t _group_by_expr) - : post_chain(_post_chain), report(_report), + : post_chain(_post_chain), report(_report), group_by_expr(_group_by_expr) { TRACE_CTOR(post_splitter, "scope_t&, post_handler_ptr, expr_t"); - preflush_func = bind(&post_splitter::print_title, this, _1); + preflush_func = bind(&post_splitter::print_title, this, _1); } virtual ~post_splitter() { TRACE_DTOR(post_splitter); @@ -97,6 +97,7 @@ public: virtual void clear() { posts_map.clear(); post_chain->clear(); + item_handler<post_t>::clear(); } }; @@ -145,14 +146,28 @@ public: } }; -class posts_iterator; - +template <typename Iterator> class pass_down_posts : public item_handler<post_t> { pass_down_posts(); public: - pass_down_posts(post_handler_ptr handler, posts_iterator& iter); + pass_down_posts(post_handler_ptr handler, Iterator& iter) + : item_handler<post_t>(handler) { + TRACE_CTOR(pass_down_posts, "post_handler_ptr, posts_iterator"); + + while (post_t * post = *iter++) { + try { + item_handler<post_t>::operator()(*post); + } + catch (const std::exception&) { + add_error_context(item_context(*post, _("While handling posting"))); + throw; + } + } + + item_handler<post_t>::flush(); + } virtual ~pass_down_posts() { TRACE_DTOR(pass_down_posts); @@ -295,7 +310,7 @@ public: virtual void clear() { sorter.clear(); last_xact = NULL; - + item_handler<post_t>::clear(); } }; @@ -365,8 +380,9 @@ public: virtual void clear() { temps.clear(); + comms.clear(); last_xact = NULL; - + item_handler<post_t>::clear(); } }; @@ -442,7 +458,7 @@ public: } virtual void flush() { - report_subtotal(); + report_subtotal(); item_handler<post_t>::flush(); } @@ -463,7 +479,7 @@ public: temps.clear(); create_accounts(); component_posts.clear(); - + item_handler<post_t>::clear(); } }; @@ -504,9 +520,9 @@ class display_filter_posts : public item_handler<post_t> // This filter requires that calc_posts be used at some point // later in the chain. + report_t& report; expr_t display_amount_expr; expr_t display_total_expr; - report_t& report; bool show_rounding; value_t last_display_total; temporaries_t temps; @@ -552,9 +568,9 @@ class changed_value_posts : public item_handler<post_t> // This filter requires that calc_posts be used at some point // later in the chain. + report_t& report; expr_t total_expr; expr_t display_total_expr; - report_t& report; bool changed_values_only; bool for_accounts_report; bool show_unrealized; @@ -984,8 +1000,7 @@ class inject_posts : public item_handler<post_t> // Account filters // -class accounts_iterator; - +template <typename Iterator> class pass_down_accounts : public item_handler<account_t> { pass_down_accounts(); @@ -995,9 +1010,24 @@ class pass_down_accounts : public item_handler<account_t> public: pass_down_accounts(acct_handler_ptr handler, - accounts_iterator& iter, + Iterator& iter, const optional<predicate_t>& _pred = none, - const optional<scope_t&>& _context = none); + const optional<scope_t&>& _context = none) + : item_handler<account_t>(handler), pred(_pred), context(_context) { + TRACE_CTOR(pass_down_accounts, "acct_handler_ptr, accounts_iterator, ..."); + + while (account_t * account = *iter++) { + if (! pred) { + item_handler<account_t>::operator()(*account); + } else { + bind_scope_t bound_scope(*context, *account); + if ((*pred)(bound_scope)) + item_handler<account_t>::operator()(*account); + } + } + + item_handler<account_t>::flush(); + } virtual ~pass_down_accounts() { TRACE_DTOR(pass_down_accounts); diff --git a/src/generate.cc b/src/generate.cc index 05f754e6..185e23e7 100644 --- a/src/generate.cc +++ b/src/generate.cc @@ -271,14 +271,14 @@ void generate_posts_iterator::generate_date(std::ostream& out) out.width(4); out.fill('0'); out << year_gen(); - + out.width(1); out << '/'; out.width(2); out.fill('0'); out << mon_gen(); - + out.width(1); out << '/'; @@ -350,9 +350,10 @@ void generate_posts_iterator::generate_xact(std::ostream& out) out << '\n'; } -post_t * generate_posts_iterator::operator()() +void generate_posts_iterator::increment() { - post_t * post = posts(); + post_t * post = *posts++; + if (post == NULL && quantity > 0) { std::ostringstream buf; generate_xact(buf); @@ -364,7 +365,7 @@ post_t * generate_posts_iterator::operator()() if (session.journal->parse(in, session) != 0) { VERIFY(session.journal->xacts.back()->valid()); posts.reset(*session.journal->xacts.back()); - post = posts(); + post = *posts++; } } catch (std::exception&) { @@ -382,7 +383,8 @@ post_t * generate_posts_iterator::operator()() quantity--; } - return post; + + m_node = post; } } // namespace ledger diff --git a/src/generate.h b/src/generate.h index 25ad41ea..47abcd94 100644 --- a/src/generate.h +++ b/src/generate.h @@ -48,7 +48,9 @@ namespace ledger { class session_t; -class generate_posts_iterator : public posts_iterator +class generate_posts_iterator + : public iterator_facade_base<generate_posts_iterator, post_t *, + boost::forward_traversal_tag> { session_t& session; unsigned int seed; @@ -104,8 +106,8 @@ public: virtual ~generate_posts_iterator() throw() { TRACE_DTOR(generate_posts_iterator); } - - virtual post_t * operator()(); + + virtual void increment(); protected: void generate_string(std::ostream& out, int len, bool only_alpha = false); diff --git a/src/item.cc b/src/item.cc index 9a9ab833..7e7cda0d 100644 --- a/src/item.cc +++ b/src/item.cc @@ -535,7 +535,7 @@ string item_context(const item_t& item, const string& desc) assert(len < 8192); std::ostringstream out; - + if (item.pos->pathname == path("/dev/stdin")) { out << desc << _(" from standard input:"); return out.str(); diff --git a/src/iterators.cc b/src/iterators.cc index b63a10e9..bb7a587c 100644 --- a/src/iterators.cc +++ b/src/iterators.cc @@ -41,37 +41,38 @@ void xacts_iterator::reset(journal_t& journal) { xacts_i = journal.xacts.begin(); xacts_end = journal.xacts.end(); + xacts_uninitialized = false; + + increment(); } -xact_t * xacts_iterator::operator()() +void xacts_iterator::increment() { if (xacts_i != xacts_end) - return *xacts_i++; + m_node = *xacts_i++; else - return NULL; + m_node = NULL; } void journal_posts_iterator::reset(journal_t& journal) { xacts.reset(journal); - - xact_t * xact = xacts(); - if (xact != NULL) - posts.reset(*xact); + increment(); } -post_t * journal_posts_iterator::operator()() +void journal_posts_iterator::increment() { - post_t * post = posts(); - if (post == NULL) { - xact_t * xact = xacts(); - if (xact != NULL) { - posts.reset(*xact); - post = posts(); - } + if (post_t * post = *posts++) { + m_node = post; + } + else if (xact_t * xact = *xacts++) { + posts.reset(*xact); + m_node = *posts++; + } + else { + m_node = NULL; } - return post; } void posts_commodities_iterator::reset(journal_t& journal) @@ -80,7 +81,7 @@ void posts_commodities_iterator::reset(journal_t& journal) std::set<commodity_t *> commodities; - for (post_t * post = journal_posts(); post; post = journal_posts()) { + while (const post_t * post = *journal_posts++) { commodity_t& comm(post->amount.commodity()); if (comm.flags() & COMMODITY_NOMARKET) continue; @@ -136,47 +137,44 @@ void posts_commodities_iterator::reset(journal_t& journal) } } - xacts.xacts_i = xact_temps.begin(); - xacts.xacts_end = xact_temps.end(); + xacts.reset(xact_temps.begin(), xact_temps.end()); - xacts.xacts_uninitialized = false; - - xact_t * xact = xacts(); - if (xact != NULL) - posts.reset(*xact); + increment(); } -post_t * posts_commodities_iterator::operator()() +void posts_commodities_iterator::increment() { - post_t * post = posts(); - if (post == NULL) { - xact_t * xact = xacts(); - if (xact != NULL) { - posts.reset(*xact); - post = posts(); - } + if (post_t * post = *posts++) { + m_node = post; + } + else if (xact_t * xact = *xacts++) { + posts.reset(*xact); + m_node = *posts++; + } + else { + m_node = NULL; } - return post; } -account_t * basic_accounts_iterator::operator()() +void basic_accounts_iterator::increment() { - while (! accounts_i.empty() && - accounts_i.back() == accounts_end.back()) { + while (! accounts_i.empty() && accounts_i.back() == accounts_end.back()) { accounts_i.pop_back(); accounts_end.pop_back(); } - if (accounts_i.empty()) - return NULL; - account_t * account = (*(accounts_i.back()++)).second; - assert(account); + if (accounts_i.empty()) { + m_node = NULL; + } else { + account_t * account = (*(accounts_i.back()++)).second; + assert(account); - // If this account has children, queue them up to be iterated next. - if (! account->accounts.empty()) - push_back(*account); + // If this account has children, queue them up to be iterated next. + if (! account->accounts.empty()) + push_back(*account); - return account; + m_node = account; + } } void sorted_accounts_iterator::push_back(account_t& account) @@ -231,7 +229,7 @@ void sorted_accounts_iterator::sort_accounts(account_t& account, #endif } -account_t * sorted_accounts_iterator::operator()() +void sorted_accounts_iterator::increment() { while (! sorted_accounts_i.empty() && sorted_accounts_i.back() == sorted_accounts_end.back()) { @@ -240,19 +238,22 @@ account_t * sorted_accounts_iterator::operator()() assert(! accounts_list.empty()); accounts_list.pop_back(); } - if (sorted_accounts_i.empty()) - return NULL; - account_t * account = *sorted_accounts_i.back()++; - assert(account); + if (sorted_accounts_i.empty()) { + m_node = NULL; + } else { + account_t * account = *sorted_accounts_i.back()++; + assert(account); + + // If this account has children, queue them up to be iterated next. + if (! flatten_all && ! account->accounts.empty()) + push_back(*account); - // If this account has children, queue them up to be iterated next. - if (! flatten_all && ! account->accounts.empty()) - push_back(*account); + // Make sure the sorting value gets recalculated for this account + account->xdata().drop_flags(ACCOUNT_EXT_SORT_CALC); - // Make sure the sorting value gets recalculated for this account - account->xdata().drop_flags(ACCOUNT_EXT_SORT_CALC); - return account; + m_node = account; + } } } // namespace ledger diff --git a/src/iterators.h b/src/iterators.h index 5113d3b2..93782400 100644 --- a/src/iterators.h +++ b/src/iterators.h @@ -51,14 +51,35 @@ namespace ledger { class journal_t; -class posts_iterator : public noncopyable +template <typename Derived, typename Value, typename CategoryOrTraversal> +class iterator_facade_base + : public boost::iterator_facade<Derived, Value, CategoryOrTraversal> { + typedef Value node_base; + public: - virtual ~posts_iterator() throw() {} - virtual post_t * operator()() = 0; + iterator_facade_base() : m_node(NULL) {} + + explicit iterator_facade_base(node_base p) : m_node(p) {} + + void increment(); + +private: + friend class boost::iterator_core_access; + + bool equal(iterator_facade_base const& other) const { + return this->m_node == other.m_node; + } + + node_base& dereference() const { return const_cast<node_base&>(m_node); } + +protected: + node_base m_node; }; -class xact_posts_iterator : public posts_iterator +class xact_posts_iterator + : public iterator_facade_base<xact_posts_iterator, post_t *, + boost::forward_traversal_tag> { posts_list::iterator posts_i; posts_list::iterator posts_end; @@ -66,33 +87,33 @@ class xact_posts_iterator : public posts_iterator bool posts_uninitialized; public: - xact_posts_iterator() : posts_uninitialized(true) { - TRACE_CTOR(xact_posts_iterator, ""); - } + xact_posts_iterator() : posts_uninitialized(true) {} xact_posts_iterator(xact_t& xact) : posts_uninitialized(true) { - TRACE_CTOR(xact_posts_iterator, "xact_t&"); reset(xact); } - virtual ~xact_posts_iterator() throw() { - TRACE_DTOR(xact_posts_iterator); - } + ~xact_posts_iterator() throw() {} void reset(xact_t& xact) { posts_i = xact.posts.begin(); posts_end = xact.posts.end(); posts_uninitialized = false; + + increment(); } - virtual post_t * operator()() { + void increment() { if (posts_uninitialized || posts_i == posts_end) - return NULL; - return *posts_i++; + m_node = NULL; + else + m_node = *posts_i++; } }; -class xacts_iterator : public noncopyable +class xacts_iterator + : public iterator_facade_base<xacts_iterator, xact_t *, + boost::forward_traversal_tag> { public: xacts_list::iterator xacts_i; @@ -100,45 +121,49 @@ public: bool xacts_uninitialized; - xacts_iterator() : xacts_uninitialized(true) { - TRACE_CTOR(xacts_iterator, ""); - } - xacts_iterator(journal_t& journal) : xacts_uninitialized(true) { - TRACE_CTOR(xacts_iterator, "journal_t&"); + xacts_iterator() : xacts_uninitialized(true) {} + xacts_iterator(journal_t& journal) : xacts_uninitialized(false) { reset(journal); } - virtual ~xacts_iterator() throw() { - TRACE_DTOR(xacts_iterator); + xacts_iterator(xacts_list::iterator beg, + xacts_list::iterator end) : xacts_uninitialized(false) { + reset(beg, end); } + ~xacts_iterator() throw() {} void reset(journal_t& journal); - xact_t * operator()(); + void reset(xacts_list::iterator beg, xacts_list::iterator end) { + xacts_i = beg; + xacts_end = end; + increment(); + } + + void increment(); }; -class journal_posts_iterator : public posts_iterator +class journal_posts_iterator + : public iterator_facade_base<journal_posts_iterator, post_t *, + boost::forward_traversal_tag> { - xacts_iterator xacts; + xacts_iterator xacts; xact_posts_iterator posts; public: - journal_posts_iterator() { - TRACE_CTOR(journal_posts_iterator, ""); - } + journal_posts_iterator() {} journal_posts_iterator(journal_t& journal) { - TRACE_CTOR(journal_posts_iterator, "journal_t&"); reset(journal); } - virtual ~journal_posts_iterator() throw() { - TRACE_DTOR(journal_posts_iterator); - } + ~journal_posts_iterator() throw() {} void reset(journal_t& journal); - virtual post_t * operator()(); + void increment(); }; -class posts_commodities_iterator : public posts_iterator +class posts_commodities_iterator + : public iterator_facade_base<posts_commodities_iterator, post_t *, + boost::forward_traversal_tag> { protected: journal_posts_iterator journal_posts; @@ -148,55 +173,44 @@ protected: xacts_list xact_temps; public: - posts_commodities_iterator() { - TRACE_CTOR(posts_commodities_iterator, ""); - } + posts_commodities_iterator() {} posts_commodities_iterator(journal_t& journal) { - TRACE_CTOR(posts_commodities_iterator, "journal_t&"); reset(journal); } - virtual ~posts_commodities_iterator() throw() { - TRACE_DTOR(posts_commodities_iterator); - } + ~posts_commodities_iterator() throw() {} void reset(journal_t& journal); - virtual post_t * operator()(); -}; - -class accounts_iterator : public noncopyable -{ -public: - virtual ~accounts_iterator() throw() {} - virtual account_t * operator()() = 0; + void increment(); }; -class basic_accounts_iterator : public accounts_iterator +class basic_accounts_iterator + : public iterator_facade_base<basic_accounts_iterator, account_t *, + boost::forward_traversal_tag> { std::list<accounts_map::const_iterator> accounts_i; std::list<accounts_map::const_iterator> accounts_end; public: - basic_accounts_iterator() { - TRACE_CTOR(basic_accounts_iterator, ""); - } + basic_accounts_iterator() {} basic_accounts_iterator(account_t& account) { - TRACE_CTOR(basic_accounts_iterator, "account_t&"); push_back(account); + increment(); } - virtual ~basic_accounts_iterator() throw() { - TRACE_DTOR(basic_accounts_iterator); - } + ~basic_accounts_iterator() throw() {} + void increment(); + +private: void push_back(account_t& account) { accounts_i.push_back(account.accounts.begin()); accounts_end.push_back(account.accounts.end()); } - - virtual account_t * operator()(); }; -class sorted_accounts_iterator : public accounts_iterator +class sorted_accounts_iterator + : public iterator_facade_base<sorted_accounts_iterator, account_t *, + boost::forward_traversal_tag> { expr_t sort_cmp; bool flatten_all; @@ -211,18 +225,17 @@ public: sorted_accounts_iterator(account_t& account, const expr_t& _sort_cmp, bool _flatten_all) : sort_cmp(_sort_cmp), flatten_all(_flatten_all) { - TRACE_CTOR(sorted_accounts_iterator, "const expr_t&, bool, account_t&"); push_back(account); + increment(); } - virtual ~sorted_accounts_iterator() throw() { - TRACE_DTOR(sorted_accounts_iterator); - } + ~sorted_accounts_iterator() throw() {} + + void increment(); +private: void push_back(account_t& account); void push_all(account_t& account, accounts_deque_t& deque); void sort_accounts(account_t& account, accounts_deque_t& deque); - - virtual account_t * operator()(); }; } // namespace ledger diff --git a/src/journal.cc b/src/journal.cc index fd6d3eac..2a9adeeb 100644 --- a/src/journal.cc +++ b/src/journal.cc @@ -74,7 +74,7 @@ journal_t::~journal_t() foreach (period_xact_t * xact, period_xacts) checked_delete(xact); - + checked_delete(master); } diff --git a/src/lookup.cc b/src/lookup.cc index 221397ca..452727d6 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -60,9 +60,10 @@ namespace { } std::pair<xact_t *, account_t *> -lookup_probable_account(const string& ident, - xacts_iterator& iter_func, - account_t * ref_account) +lookup_probable_account(const string& ident, + xacts_list::reverse_iterator iter, + xacts_list::reverse_iterator end, + account_t * ref_account) { scorecard_t scores; @@ -83,14 +84,15 @@ lookup_probable_account(const string& ident, " with reference account: " << ref_account->fullname()); #endif - while (xact_t * xact = iter_func()) { + xact_t * xact; + while (iter != end && (xact = *iter++) != NULL) { #if 0 // Only consider transactions from the last two years (jww (2010-03-07): // make this an option) if ((CURRENT_DATE() - xact->date()).days() > 700) continue; #endif - + // An exact match is worth a score of 100 and terminates the search if (ident == xact->payee) { DEBUG("lookup", " we have an exact match, score = 100"); diff --git a/src/lookup.h b/src/lookup.h index 7776be80..8e83b84e 100644 --- a/src/lookup.h +++ b/src/lookup.h @@ -47,9 +47,10 @@ namespace ledger { std::pair<xact_t *, account_t *> -lookup_probable_account(const string& ident, - xacts_iterator& iter_func, - account_t * ref_account = NULL); +lookup_probable_account(const string& ident, + xacts_list::reverse_iterator iter, + xacts_list::reverse_iterator end, + account_t * ref_account = NULL); } // namespace ledger @@ -164,6 +164,11 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) result = as_value(); break; + case O_DEFINE: + //result = left()->calc(scope, locus, depth + 1); + result = NULL_VALUE; + break; + case IDENT: { ptr_op_t definition = left(); if (! definition) { @@ -416,10 +421,8 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) break; } - case LAST: default: - assert(false); - break; + throw_(calc_error, _("Unexpected expr node '%1'") << op_context(this)); } #if defined(DEBUG_ON) @@ -435,7 +438,7 @@ value_t expr_t::op_t::calc(scope_t& scope, ptr_op_t * locus, const int depth) return result; } - catch (const std::exception&) { + catch (const std::exception&) { if (locus && ! *locus) *locus = this; throw; diff --git a/src/option.cc b/src/option.cc index dae0f0af..f7008b47 100644 --- a/src/option.cc +++ b/src/option.cc @@ -89,7 +89,7 @@ namespace { catch (const std::exception&) { if (name[0] == '-') add_error_context(_("While parsing option '%1'") << name); - + else add_error_context(_("While parsing environent variable '%1'") << name); throw; @@ -156,7 +156,7 @@ namespace { op_bool_char_tuple(expr_t::ptr_op_t _op, bool _truth, char _ch) : op(_op), truth(_truth), ch(_ch) {} }; -} +} strings_list process_arguments(strings_list args, scope_t& scope) { diff --git a/src/option.h b/src/option.h index e2a4a839..8f89d081 100644 --- a/src/option.h +++ b/src/option.h @@ -209,10 +209,12 @@ public: #define CTOR(type, name) \ name ## option_t() : option_t<type>(#name) +#define CTOR_(type, name, base) \ + name ## option_t() : option_t<type>(#name), base #define DECL1(type, name, vartype, var, value) \ vartype var ; \ name ## option_t() : option_t<type>(#name), var(value) - + #define DO() virtual void handler_thunk(call_scope_t&) #define DO_(var) virtual void handler_thunk(call_scope_t& var) diff --git a/src/pool.cc b/src/pool.cc index aa56efff..65edbd6a 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -298,7 +298,7 @@ commodity_pool_t::exchange(const amount_t& amount, annotation.add_flags(ANNOTATION_DATE_CALCULATED); if (tag) annotation.add_flags(ANNOTATION_TAG_CALCULATED); - + breakdown.amount = amount_t(amount, annotation); DEBUG("commodity.prices.add", diff --git a/src/post.cc b/src/post.cc index ca03a675..4178c8bc 100644 --- a/src/post.cc +++ b/src/post.cc @@ -115,7 +115,7 @@ date_t post_t::actual_date() const return xact->date(); } return *_date; -} +} optional<date_t> post_t::effective_date() const { @@ -341,7 +341,7 @@ namespace { value_t get_value_date(post_t& post) { if (post.has_xdata()) { post_t::xdata_t& xdata(post.xdata()); - if (! xdata.value_date.is_not_a_date()) + if (! xdata.value_date.is_not_a_date()) return xdata.value_date; } return post.date(); diff --git a/src/pstream.h b/src/pstream.h index 5fac20bd..8134495d 100644 --- a/src/pstream.h +++ b/src/pstream.h @@ -99,7 +99,7 @@ class ptristream : public std::istream protected: ptrinbuf buf; -public: +public: ptristream(char * ptr, std::size_t len = 0) : std::istream(0), buf(ptr, len) { rdbuf(&buf); diff --git a/src/py_balance.cc b/src/py_balance.cc index eba5761d..540b3221 100644 --- a/src/py_balance.cc +++ b/src/py_balance.cc @@ -56,7 +56,7 @@ namespace { datetime_t& moment) { return balance.value(moment, in_terms_of); } - + boost::optional<amount_t> py_commodity_amount_0(const balance_t& balance) { return balance.commodity_amount(); diff --git a/src/py_commodity.cc b/src/py_commodity.cc index 783171dd..6d8a29b3 100644 --- a/src/py_commodity.cc +++ b/src/py_commodity.cc @@ -181,7 +181,7 @@ namespace { const datetime_t& date, const amount_t& price) { commodity.add_price(date, price); } - + void py_add_price_3(commodity_t& commodity, const datetime_t& date, const amount_t& price, const bool reflexive) { commodity.add_price(date, price, reflexive); diff --git a/src/py_journal.cc b/src/py_journal.cc index a06ef8e2..cb629f62 100644 --- a/src/py_journal.cc +++ b/src/py_journal.cc @@ -191,7 +191,7 @@ namespace { coll->chain = chain_post_handlers(post_handler_ptr(coll->posts_collector), coll->report); - pass_down_posts(coll->chain, walker); + pass_down_posts<journal_posts_iterator>(coll->chain, walker); } catch (...) { current_report.session.journal.release(); diff --git a/src/py_post.cc b/src/py_post.cc index 537289b3..62323eb1 100644 --- a/src/py_post.cc +++ b/src/py_post.cc @@ -173,7 +173,7 @@ void export_post() .def("xdata", py_xdata, return_internal_reference<>()) - .def("add_to_value", &post_t::add_to_value) + //.def("add_to_value", &post_t::add_to_value) .def("set_reported_account", &post_t::set_reported_account) .def("reported_account", py_reported_account, diff --git a/src/py_xact.cc b/src/py_xact.cc index b7582854..adaf81a2 100644 --- a/src/py_xact.cc +++ b/src/py_xact.cc @@ -140,7 +140,7 @@ void export_xact() class_< period_xact_t, bases<xact_base_t> > ("PeriodicTransaction") .def(init<string>()) - + .add_property("period", make_getter(&period_xact_t::period), make_setter(&period_xact_t::period)) diff --git a/src/pyinterp.cc b/src/pyinterp.cc index e0801604..e0fd2d59 100644 --- a/src/pyinterp.cc +++ b/src/pyinterp.cc @@ -126,7 +126,7 @@ void python_interpreter_t::initialize() void python_interpreter_t::hack_system_paths() { // Hack ledger.__path__ so it points to a real location - python::object sys_module = python::import("sys"); + python::object sys_module = python::import("sys"); python::object sys_dict = sys_module.attr("__dict__"); python::list paths(sys_dict["path"]); @@ -177,7 +177,7 @@ object python_interpreter_t::import_into_main(const string& str) if (! mod) throw_(std::runtime_error, _("Failed to import Python module %1") << str); - + // Import all top-level entries directly into the main namespace main_nspace.update(mod.attr("__dict__")); @@ -193,7 +193,7 @@ object python_interpreter_t::import_option(const string& str) { path file(str); - python::object sys_module = python::import("sys"); + python::object sys_module = python::import("sys"); python::object sys_dict = sys_module.attr("__dict__"); python::list paths(sys_dict["path"]); @@ -312,7 +312,7 @@ value_t python_interpreter_t::python_command(call_scope_t& args) delete[] argv; throw; } - + for (std::size_t i = 0; i < args.size() + 1; i++) delete[] argv[i]; delete[] argv; @@ -445,7 +445,7 @@ namespace { } } } - + value_t python_interpreter_t::functor_t::operator()(call_scope_t& args) { try { diff --git a/src/pyinterp.h b/src/pyinterp.h index 1dfd0747..ea947c5a 100644 --- a/src/pyinterp.h +++ b/src/pyinterp.h @@ -48,7 +48,7 @@ public: : session_t(), main_nspace(), is_initialized(false) { TRACE_CTOR(python_interpreter_t, ""); } - + virtual ~python_interpreter_t() { TRACE_DTOR(python_interpreter_t); diff --git a/src/pyutils.h b/src/pyutils.h index efb1b858..7e016502 100644 --- a/src/pyutils.h +++ b/src/pyutils.h @@ -173,7 +173,7 @@ namespace boost { namespace python { arg_to_python(T const& x) \ : python::handle<>(expr) {} \ }; \ - } + } // Specialize argument and return value converters for T using expr # define BOOST_PYTHON_TO_PYTHON_BY_VALUE(T, expr, pytype) \ diff --git a/src/query.cc b/src/query.cc index 5480336c..5c11add5 100644 --- a/src/query.cc +++ b/src/query.cc @@ -127,7 +127,6 @@ query_t::lexer_t::token_t query_t::lexer_t::next_token() // fall through... default: { string ident; - string::const_iterator beg = arg_i; for (; arg_i != arg_end; ++arg_i) { switch (*arg_i) { case '\0': @@ -296,7 +295,7 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex if (tok.kind != lexer_t::token_t::TERM) throw_(parse_error, _("Metadata equality operator not followed by term")); - + expr_t::ptr_op_t arg2 = new expr_t::op_t(expr_t::op_t::VALUE); assert(tok.value); arg2->set_value(mask_t(*tok.value)); @@ -310,7 +309,7 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex } break; } - + default: { node = new expr_t::op_t(expr_t::op_t::O_MATCH); @@ -536,11 +535,13 @@ query_t::parser_t::parse_query_expr(lexer_t::token_t::kind_t tok_context, } default: - break; + goto done; } tok = lexer.peek_token(); } + done: + ; } return limiter; diff --git a/src/report.cc b/src/report.cc index 5fff77c7..d3a219a0 100644 --- a/src/report.cc +++ b/src/report.cc @@ -289,7 +289,7 @@ void report_t::parse_query_args(const value_t& args, const string& whence) normalize_period(); // it needs normalization } -} +} namespace { struct posts_flusher @@ -318,7 +318,7 @@ void report_t::posts_report(post_handler_ptr handler) handler = chain_pre_post_handlers(handler, *this); journal_posts_iterator walker(*session.journal.get()); - pass_down_posts(handler, walker); + pass_down_posts<journal_posts_iterator>(handler, walker); if (! HANDLED(group_by_)) posts_flusher(handler, *this)(value_t()); @@ -334,7 +334,7 @@ void report_t::generate_report(post_handler_ptr handler) HANDLED(head_) ? static_cast<unsigned int>(HANDLER(head_).value.to_long()) : 50); - pass_down_posts(handler, walker); + pass_down_posts<generate_posts_iterator>(handler, walker); } void report_t::xact_report(post_handler_ptr handler, xact_t& xact) @@ -342,7 +342,7 @@ void report_t::xact_report(post_handler_ptr handler, xact_t& xact) handler = chain_handlers(handler, *this); xact_posts_iterator walker(xact); - pass_down_posts(handler, walker); + pass_down_posts<xact_posts_iterator>(handler, walker); xact.clear_xdata(); } @@ -382,25 +382,34 @@ namespace { report.HANDLER(display_total_).expr.mark_uncompiled(); report.HANDLER(revalued_total_).expr.mark_uncompiled(); - scoped_ptr<accounts_iterator> iter; - if (! report.HANDLED(sort_)) { - iter.reset(new basic_accounts_iterator(*report.session.journal->master)); - } else { - expr_t sort_expr(report.HANDLER(sort_).str()); - sort_expr.set_context(&report); - iter.reset(new sorted_accounts_iterator(*report.session.journal->master, - sort_expr, report.HANDLED(flat))); - } - if (report.HANDLED(display_)) { DEBUG("report.predicate", "Display predicate = " << report.HANDLER(display_).str()); - pass_down_accounts(handler, *iter.get(), - predicate_t(report.HANDLER(display_).str(), - report.what_to_keep()), - report); + if (! report.HANDLED(sort_)) { + basic_accounts_iterator iter(*report.session.journal->master); + pass_down_accounts<basic_accounts_iterator> + (handler, iter, predicate_t(report.HANDLER(display_).str(), + report.what_to_keep()), report); + } else { + expr_t sort_expr(report.HANDLER(sort_).str()); + sort_expr.set_context(&report); + sorted_accounts_iterator iter(*report.session.journal->master, + sort_expr, report.HANDLED(flat)); + pass_down_accounts<sorted_accounts_iterator> + (handler, iter, predicate_t(report.HANDLER(display_).str(), + report.what_to_keep()), report); + } } else { - pass_down_accounts(handler, *iter.get()); + if (! report.HANDLED(sort_)) { + basic_accounts_iterator iter(*report.session.journal->master); + pass_down_accounts<basic_accounts_iterator>(handler, iter); + } else { + expr_t sort_expr(report.HANDLER(sort_).str()); + sort_expr.set_context(&report); + sorted_accounts_iterator iter(*report.session.journal->master, + sort_expr, report.HANDLED(flat)); + pass_down_accounts<sorted_accounts_iterator>(handler, iter); + } } report.session.journal->clear_xdata(); @@ -428,7 +437,7 @@ void report_t::accounts_report(acct_handler_ptr handler) // objects created within it during the call to pass_down_posts, which will // be needed later by the pass_down_accounts. journal_posts_iterator walker(*session.journal.get()); - pass_down_posts(chain, walker); + pass_down_posts<journal_posts_iterator>(chain, walker); if (! HANDLED(group_by_)) accounts_flusher(handler, *this)(value_t()); @@ -439,7 +448,7 @@ void report_t::commodities_report(post_handler_ptr handler) handler = chain_handlers(handler, *this); posts_commodities_iterator walker(*session.journal.get()); - pass_down_posts(handler, walker); + pass_down_posts<posts_commodities_iterator>(handler, walker); session.journal->clear_xdata(); } @@ -648,7 +657,8 @@ value_t report_t::fn_quoted(call_scope_t& args) std::ostringstream out; out << '"'; - foreach (const char ch, args.get<string>(0)) { + string arg(args.get<string>(0)); + foreach (const char ch, arg) { if (ch == '"') out << "\\\""; else @@ -663,7 +673,8 @@ value_t report_t::fn_join(call_scope_t& args) { std::ostringstream out; - foreach (const char ch, args.get<string>(0)) { + string arg(args.get<string>(0)); + foreach (const char ch, arg) { if (ch != '\n') out << ch; else diff --git a/src/report.h b/src/report.h index d0a49476..e142b0dc 100644 --- a/src/report.h +++ b/src/report.h @@ -68,7 +68,7 @@ class xact_t; // --- The details of #1 and #2 together represent the ItemHandler. // // 3. Mode of the report. Currently there are four modes: -// +// // a. Posting or commodity iteration. In this mode, all the journal's // xacts, the postings of a specific xact, or all the journal's // commodities are walked. In the first two cases, it's the underlying @@ -86,7 +86,7 @@ class xact_t; // c. Write journal. In this mode, a single function is called that output // the journal object as a textual file. #2 is used to print out each // posting in the journal. -// +// // d. Dump binary file. This is just like 'c', except that it dumps out a // binary file and #2 is completely ignored. // diff --git a/src/scope.h b/src/scope.h index ea030b16..71894d00 100644 --- a/src/scope.h +++ b/src/scope.h @@ -646,7 +646,7 @@ class value_scope_t : public child_scope_t public: value_scope_t(scope_t& _parent, const value_t& _value) : child_scope_t(_parent), value(_value) {} - + virtual string description() { return parent->description(); } diff --git a/src/series.h b/src/series.h new file mode 100644 index 00000000..40f34051 --- /dev/null +++ b/src/series.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2003-2010, John Wiegley. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of New Artisans LLC nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @addtogroup expr + */ + +/** + * @file series.h + * @author John Wiegley + * + * @ingroup expr + */ +#ifndef _SERIES_H +#define _SERIES_H + +#include "scope.h" + +namespace ledger { + +class expr_series_t +{ +protected: + scope_t * context; + +public: + optional<std::list<expr_t> > exprs; + expr_t default_expr; + std::string variable; + + expr_series_t(const std::string& _variable) + : context(NULL), default_expr(_variable), variable(_variable) { + TRACE_CTOR(expr_series_t, "std::string"); + } + expr_series_t(const expr_t& expr, const std::string& _variable) + : context(const_cast<expr_t&>(expr).get_context()), + default_expr(expr), variable(_variable) { + TRACE_CTOR(expr_series_t, "expr_t, std::string"); + } + expr_series_t(const expr_series_t& other) + : context(other.context), exprs(other.exprs), + default_expr(other.default_expr), variable(other.variable) { + TRACE_CTOR(expr_series_t, "copy"); + } + virtual ~expr_series_t() { + TRACE_DTOR(expr_series_t); + } + + scope_t * get_context() { + return context; + } + void set_context(scope_t * scope) { + context = scope; + } + + bool empty() const { + return ! exprs || exprs->empty(); + } + + void push_back(const expr_t& expr) { + if (! exprs) + exprs = std::list<expr_t>(); + exprs->push_back(expr); + } + void pop_back() { + assert(exprs); + exprs->pop_back(); + } + + void mark_uncompiled() { + if (exprs) + foreach (expr_t& expr, *exprs) + expr.mark_uncompiled(); + else + default_expr.mark_uncompiled(); + } + + void compile(scope_t& scope) { + if (exprs) + foreach (expr_t& expr, *exprs) + expr.compile(scope); + else + default_expr.compile(scope); + } + + value_t calc(scope_t& scope) { + if (exprs) { + value_t result; + symbol_scope_t sym_scope(scope); + std::size_t len(exprs->size()); + + foreach (expr_t& expr, *exprs) { + result = expr.calc(sym_scope); + if (--len > 0) + sym_scope.define(symbol_t::FUNCTION, variable, + expr_t::op_t::wrap_value(result)); + } + return result; + } else { + return default_expr.calc(scope); + } + } +}; + +} // namespace ledger + +#endif // _SERIES_H diff --git a/src/session.cc b/src/session.cc index fdb0ad1d..72e29895 100644 --- a/src/session.cc +++ b/src/session.cc @@ -178,7 +178,7 @@ void session_t::close_journal_files() { journal.reset(); amount_t::shutdown(); - + journal.reset(new journal_t); amount_t::initialize(); } diff --git a/src/system.hh.in b/src/system.hh.in index f71dce68..f063a761 100644 --- a/src/system.hh.in +++ b/src/system.hh.in @@ -158,6 +158,7 @@ typedef std::ostream::pos_type ostream_pos_type; #include <boost/iostreams/write.hpp> #define BOOST_IOSTREAMS_USE_DEPRECATED 1 #include <boost/iostreams/device/file_descriptor.hpp> +#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/lexical_cast.hpp> #include <boost/operators.hpp> @@ -204,7 +205,7 @@ namespace serialization { template <class Archive> void serialize(Archive& ar, boost::filesystem::path& p, const unsigned int) { - std::string s; + std::string s; if (Archive::is_saving::value) s = p.string(); diff --git a/src/textual.cc b/src/textual.cc index 0e7f2aec..341271b6 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -129,7 +129,7 @@ namespace { (in.peek() == ' ' || in.peek() == '\t')); } - void read_next_directive(); + void read_next_directive(); #if defined(TIMELOG_SUPPORT) void clock_in_directive(char * line, bool capitalized); @@ -270,7 +270,7 @@ void instance_t::parse() string err_context = error_context(); if (! err_context.empty()) std::cerr << err_context << std::endl; - + if (! current_context.empty()) std::cerr << current_context << std::endl; @@ -442,7 +442,7 @@ void instance_t::clock_in_directive(char * line, bool /*capitalized*/) } void instance_t::clock_out_directive(char * line, bool /*capitalized*/) -{ +{ string datetime(line, 2, 19); char * p = skip_ws(line + 22); @@ -546,7 +546,7 @@ void instance_t::automated_xact_directive(char * line) try { 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(skip_ws(line + 1)).to_sequence(), keeper, false, true); @@ -831,7 +831,7 @@ void instance_t::alias_directive(char * line) void instance_t::fixed_directive(char * line) { - if (optional<std::pair<commodity_t *, price_point_t> > price_point = + if (optional<std::pair<commodity_t *, price_point_t> > price_point = commodity_pool_t::current_pool->parse_price_directive(trim_ws(line), true)) { context.state_stack.push_front(fixed_rate_t(price_point->first, @@ -1165,11 +1165,7 @@ post_t * instance_t::parse_post(char * line, // Parse the optional amount - bool saw_amount = false; - if (next && *next && (*next != ';' && *next != '=')) { - saw_amount = true; - beg = next - line; ptristream stream(next, len - beg); @@ -1320,7 +1316,7 @@ post_t * instance_t::parse_post(char * line, amount_t& amt(*post->assigned_amount); value_t account_total - (post->account->amount(false).strip_annotations(keep_details_t())); + (post->account->amount().strip_annotations(keep_details_t())); DEBUG("post.assign", "line " << linenum << ": " "account balance = " << account_total); @@ -1569,6 +1565,7 @@ xact_t * instance_t::parse_xact(char * line, } } +#if 0 if (xact->_state == item_t::UNCLEARED) { item_t::state_t result = item_t::CLEARED; @@ -1582,6 +1579,7 @@ xact_t * instance_t::parse_xact(char * line, } } } +#endif xact->pos->end_pos = curr_pos; xact->pos->end_line = linenum; diff --git a/src/times.cc b/src/times.cc index 5249c11c..7fc9c21e 100644 --- a/src/times.cc +++ b/src/times.cc @@ -280,7 +280,7 @@ optional<date_time::weekdays> string_to_day_of_week(const std::string& str) else return none; } - + optional<date_time::months_of_year> string_to_month_of_year(const std::string& str) { @@ -709,12 +709,9 @@ void date_parser_t::determine_when(date_parser_t::lexer_t::token_t& tok, when += gregorian::years(amount * adjust); break; case lexer_t::token_t::TOK_QUARTER: - case lexer_t::token_t::TOK_QUARTERS: { - date_t temp = - date_duration_t::find_nearest(today, date_duration_t::QUARTERS); + case lexer_t::token_t::TOK_QUARTERS: when += gregorian::months(amount * 3 * adjust); break; - } case lexer_t::token_t::TOK_MONTH: case lexer_t::token_t::TOK_MONTHS: when += gregorian::months(amount * adjust); diff --git a/src/times.h b/src/times.h index 1ff08739..fed47ae3 100644 --- a/src/times.h +++ b/src/times.h @@ -203,7 +203,7 @@ struct date_duration_t } ~date_duration_t() throw() { TRACE_DTOR(date_duration_t); - } + } date_t add(const date_t& date) const { switch (quantum) { @@ -431,7 +431,7 @@ public: out << "from" << range_begin->to_string(); if (range_end) out << " to" << range_end->to_string(); - + return out.str(); } diff --git a/src/value.cc b/src/value.cc index c34792b2..1ecfffe7 100644 --- a/src/value.cc +++ b/src/value.cc @@ -333,7 +333,7 @@ value_t& value_t::operator+=(const value_t& val) for (; i != end(); i++, j++) *i += *j; } else { - add_error_context(_("While adding %1 to %2:") << *this << val); + add_error_context(_("While adding %1 to %2:") << val << *this); throw_(value_error, _("Cannot add sequences of different lengths")); } } else { @@ -446,7 +446,7 @@ value_t& value_t::operator+=(const value_t& val) break; } - add_error_context(_("While adding %1 to %2:") << *this << val); + add_error_context(_("While adding %1 to %2:") << val << *this); throw_(value_error, _("Cannot add %1 to %2") << val.label() << label()); return *this; @@ -465,7 +465,7 @@ value_t& value_t::operator-=(const value_t& val) for (; i != end(); i++, j++) *i -= *j; } else { - add_error_context(_("While subtracting %1 to %2:") << *this << val); + add_error_context(_("While subtracting %1 from %2:") << val << *this); throw_(value_error, _("Cannot subtract sequences of different lengths")); } } else { @@ -588,7 +588,7 @@ value_t& value_t::operator-=(const value_t& val) break; } - add_error_context(_("While subtracting %1 from %2:") << *this << val); + add_error_context(_("While subtracting %1 from %2:") << val << *this); throw_(value_error, _("Cannot subtract %1 from %2") << val.label() << label()); return *this; @@ -670,7 +670,7 @@ value_t& value_t::operator*=(const value_t& val) break; } - add_error_context(_("While multiplying %1 with %2:") << *this << val); + add_error_context(_("While multiplying %1 with %2:") << val << *this); throw_(value_error, _("Cannot multiply %1 with %2") << label() << val.label()); return *this; @@ -748,7 +748,7 @@ value_t& value_t::operator/=(const value_t& val) break; } - add_error_context(_("While dividing %1 by %2:") << *this << val); + add_error_context(_("While dividing %1 by %2:") << val << *this); throw_(value_error, _("Cannot divide %1 by %2") << label() << val.label()); return *this; @@ -760,7 +760,7 @@ bool value_t::is_equal_to(const value_t& val) const switch (type()) { case VOID: return val.type() == VOID; - + case BOOLEAN: if (val.is_boolean()) return as_boolean() == val.as_boolean(); @@ -834,7 +834,7 @@ bool value_t::is_equal_to(const value_t& val) const break; } - add_error_context(_("While comparing equality of %1 to %2:") << *this << val); + add_error_context(_("While comparing equality of %1 and %2:") << *this << val); throw_(value_error, _("Cannot compare %1 to %2") << label() << val.label()); return *this; @@ -1263,8 +1263,8 @@ void value_t::in_place_cast(type_t cast_type) } add_error_context(_("While converting %1:") << *this); - throw_(value_error, - _("Cannot convert %1 to %2") << label() << label(cast_type)); + throw_(value_error, _("Cannot convert %1 to %2") + << label() << label(cast_type)); } void value_t::in_place_negate() @@ -1721,11 +1721,13 @@ string value_t::label(optional<type_t> the_type) const return _("<invalid>"); } -void value_t::print(std::ostream& out, +void value_t::print(std::ostream& _out, const int first_width, const int latter_width, const uint_least8_t flags) const { + std::ostringstream out; + if (first_width > 0 && (! is_amount() || as_amount().is_zero()) && ! is_balance() && ! is_string()) { @@ -1821,6 +1823,8 @@ void value_t::print(std::ostream& out, add_error_context(_("While printing %1:") << *this); throw_(value_error, _("Cannot print %1") << label()); } + + _out << out.str(); } void value_t::dump(std::ostream& out, const bool relaxed) const diff --git a/src/value.h b/src/value.h index 1176ad09..7c507712 100644 --- a/src/value.h +++ b/src/value.h @@ -139,7 +139,7 @@ private: scope_t *, // SCOPE boost::any // ANY > data; - + type_t type; /** diff --git a/src/xact.cc b/src/xact.cc index 1acbd0a4..7f0b1afe 100644 --- a/src/xact.cc +++ b/src/xact.cc @@ -192,7 +192,7 @@ bool xact_base_t::finalize() DEBUG("xact.finalize", "there were no costs, and a valid top_post"); balance_t::amounts_map::const_iterator a = bal.amounts.begin(); - + const amount_t * x = &(*a++).second; const amount_t * y = &(*a++).second; @@ -418,7 +418,7 @@ bool xact_base_t::verify() amount_t& p(post->cost ? *post->cost : post->amount); assert(! p.is_null()); - + // If the amount was a cost, it very likely has the "keep_precision" flag // set, meaning commodity display precision is ignored when displaying the // amount. We never want this set for the balance, so we must clear the @@ -609,7 +609,7 @@ namespace { .match(post.reported_account()->fullname()); else break; - + case expr_t::op_t::O_NOT: return ! post_pred(op->left(), post); @@ -61,7 +61,7 @@ public: xact_base_t() : item_t(), journal(NULL) { TRACE_CTOR(xact_base_t, ""); } - xact_base_t(const xact_base_t& e); + xact_base_t(const xact_base_t& e); virtual ~xact_base_t(); diff --git a/tools/Makefile.am b/tools/Makefile.am index 4605c4a2..5bb41cc0 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -119,6 +119,7 @@ pkginclude_HEADERS = \ src/query.h \ src/format.h \ src/option.h \ + src/series.h \ \ src/item.h \ src/post.h \ diff --git a/tools/configure.ac b/tools/configure.ac index c3a913e6..e078ebc4 100644 --- a/tools/configure.ac +++ b/tools/configure.ac @@ -66,7 +66,7 @@ AC_ARG_ENABLE(doxygen, AM_CONDITIONAL(USE_DOXYGEN, test x$doxygen = xtrue) AC_ARG_ENABLE(cache, - [ --enable-cache Enable use of the --cache option], + [ --enable-cache Enable use of the --cache option], [case "${enableval}" in yes) cache=true ;; no) cache=false ;; @@ -76,7 +76,7 @@ AC_ARG_ENABLE(cache, AM_CONDITIONAL(USE_CACHE_OPTION, test x$cache = xtrue) AC_ARG_ENABLE(python, - [ --enable-python Turn on Python support (experimental)], + [ --enable-python Turn on Python support (experimental)], [case "${enableval}" in yes) python=true ;; no) python=false ;; |