diff options
-rw-r--r-- | README-1ST | 1 | ||||
-rwxr-xr-x | acprep | 70 | ||||
-rw-r--r-- | contrib/vim/ftplugin/ledger.vim | 85 | ||||
-rw-r--r-- | doc/ledger.texi | 5 | ||||
-rw-r--r-- | doc/ledger3.texi | 21 | ||||
-rw-r--r-- | lib/Makefile | 17 | ||||
-rw-r--r-- | lisp/ldg-mode.el | 4 | ||||
-rw-r--r-- | src/amount.cc | 23 | ||||
-rw-r--r-- | src/report.cc | 14 | ||||
-rw-r--r-- | src/report.h | 2 | ||||
-rw-r--r-- | src/stats.cc | 3 | ||||
-rwxr-xr-x | tools/genuuid | 28 |
12 files changed, 199 insertions, 74 deletions
@@ -101,6 +101,7 @@ it's usually fairly obvious where things have gone astray. exact same Python as the Ledger executable. In particular I see this bug on OS X systems where boost_python is linked against the default Python, while Ledger is linked against the version provided by MacPorts. + Or vice versa. Solution: Use one or the other. If you prefer the system Python, run "port deactivate -f python26", to get MacPorts' version out of the way. @@ -209,7 +209,7 @@ class BoostInfo(object): def dependencies(self, system): if system == 'darwin': - return [ 'boost-jam', 'boost', '+icu+python26+st+universal' ] + return [ 'boost-jam', 'boost', '+icu+python27+st+universal' ] if system == 'centos': return [ 'boost-devel' ] @@ -239,6 +239,15 @@ class BoostInfo(object): 'libboost-filesystem-dev', 'libboost-iostreams-dev' ] + elif system == 'ubuntu-oneiric': + return [ 'libboost-dev', + 'libboost-python-dev', + 'libboost-regex-dev', + 'libboost-date-time-dev', + 'libboost-filesystem-dev', + 'libboost-iostreams-dev' ] + + class CommandLineApp(object): "Base class for building command line applications." @@ -400,8 +409,9 @@ class PrepareBuild(CommandLineApp): self.LDFLAGS = [] self.envvars = { + 'PYTHON': '/usr/bin/python', 'PYTHON_HOME': '/usr', - 'PYTHON_VERSION': '2.6', + 'PYTHON_VERSION': '2.7', 'LEDGER_PRODUCTS': None, 'CC': 'gcc', 'CPPFLAGS': '', @@ -817,7 +827,7 @@ class PrepareBuild(CommandLineApp): packages = [ 'sudo', 'port', 'install', '-f', 'automake', 'autoconf', 'libtool', - 'python26', '+universal', + 'python27', '+universal', 'libiconv', '+universal', 'zlib', '+universal', 'gmp' ,'+universal', 'mpfr', '+universal', @@ -864,7 +874,7 @@ class PrepareBuild(CommandLineApp): 'lcov', 'sloccount' ] + self.boost_info.dependencies('ubuntu-karmic') - else: + elif re.search('hardy', info): self.log.info('Looks like you are using APT on Ubuntu Hardy') packages = [ 'sudo', 'apt-get', 'install', @@ -888,6 +898,30 @@ class PrepareBuild(CommandLineApp): 'lcov', 'sloccount' ] + self.boost_info.dependencies('ubuntu-hardy') + elif re.search('oeneric', info): + self.log.info('Looks like you are using APT on Ubuntu Oeneric') + packages = [ + 'sudo', 'apt-get', 'install', + 'build-essential', + 'libtool', + 'autoconf', + 'automake', + 'autopoint', + 'zlib1g-dev', + 'libbz2-dev', + 'python-dev', + 'cvs', + 'gettext', + 'libgmp3-dev', + 'libmpfr-dev', + 'libedit-dev', + #'texlive-full', + #'doxygen', + #'graphviz', + 'texinfo', + 'lcov', + 'sloccount' + ] + self.boost_info.dependencies('ubuntu-oeneric') self.log.info('Executing: ' + string.join(packages, ' ')) self.execute(*packages) @@ -929,7 +963,7 @@ class PrepareBuild(CommandLineApp): boost_include = self.boost_info.include_directory() boost_library = self.boost_info.library_directory() - if re.match('/opt/local', self.boost_info.home_path): + if re.match('/(usr|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' @@ -946,6 +980,13 @@ class PrepareBuild(CommandLineApp): self.log.info('Noticing include directory => ' + path) self.sys_include_dirs.append(path) + includes = string.split(self.get_stdout('python-config', + '--includes'), '-I') + for include in includes: + include = include.strip() + if include and include not in self.sys_include_dirs: + self.sys_include_dirs.append(include) + # Each of these becomes '-L<name>' for path in ['/usr/local/lib', '%s/lib' % self.envvars['PYTHON_HOME'], @@ -961,12 +1002,14 @@ class PrepareBuild(CommandLineApp): self.sys_library_dirs.append(path) def setup_for_johnw(self): + self.envvars['PYTHON'] = '/opt/local/bin/python' + self.envvars['PYTHON_HOME'] = '/opt/local' + if self.options.use_clang: self.boost_inc_ident = "clang" self.boost_lib_ident = "clang-darwin28" self.log.debug("Setting Python home to /opt/local") - self.envvars['PYTHON_HOME'] = '/opt/local' self.log.debug('Using Clang ident: %s/%s' % (self.boost_inc_ident, self.boost_lib_ident)) @@ -1040,28 +1083,21 @@ class PrepareBuild(CommandLineApp): self.envvars['LD'] = '/usr/bin/g++-4.2' self.darwin_gcc = True elif exists('/opt/local/bin/g++-mp-4.6') and \ - not self.options.gcc45: + self.options.gcc46: self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.6' #if exists('/Users/johnw/bin/gfilt'): # self.envvars['CXX'] = '/Users/johnw/bin/gfilt' #else: self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.6' self.envvars['LD'] = '/opt/local/bin/g++-mp-4.6' - elif exists('/opt/local/bin/g++-mp-4.5'): + elif exists('/opt/local/bin/g++-mp-4.5') and \ + self.options.gcc45: self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.5' if exists('/Users/johnw/bin/gfilt'): self.envvars['CXX'] = '/Users/johnw/bin/gfilt' else: self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.5' self.envvars['LD'] = '/opt/local/bin/g++-mp-4.5' - elif exists('/opt/local/bin/g++-mp-4.4'): - self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.4' - self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.4' - self.envvars['LD'] = '/opt/local/bin/g++-mp-4.4' - elif exists('/opt/local/bin/g++-mp-4.3'): - self.envvars['CC'] = '/opt/local/bin/gcc-mp-4.3' - self.envvars['CXX'] = '/opt/local/bin/g++-mp-4.3' - self.envvars['LD'] = '/opt/local/bin/g++-mp-4.3' elif exists('/usr/bin/g++-4.2'): self.envvars['CC'] = '/usr/bin/gcc-4.2' self.envvars['CXX'] = '/usr/bin/g++-4.2' @@ -1296,7 +1332,9 @@ class PrepareBuild(CommandLineApp): if self.options.gcc45 or self.options.gcc46: self.CXXFLAGS.append('-g2') + self.CXXFLAGS.append('-ggdb') self.LDFLAGS.append('-g2') + self.LDFLAGS.append('-ggdb') else: self.CXXFLAGS.append('-g') self.LDFLAGS.append('-g') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 9cc4ed91..63de88b5 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -69,7 +69,17 @@ endif " A " }}} if !exists('g:ledger_detailed_first') - let g:ledger_detailed_first = 0 + let g:ledger_detailed_first = 1 +endif + +" only display exact matches (no parent accounts etc.) +if !exists('g:ledger_exact_only') + let g:ledger_exact_only = 0 +endif + +" display original text / account name as completion +if !exists('g:ledger_include_original') + let g:ledger_include_original = 0 endif let s:rx_amount = '\('. @@ -141,10 +151,10 @@ function! LedgerComplete(findstart, base) "{{{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) + " (excluding virtual-transaction and 'cleared' marks) " is the beginning of the account name let b:compl_context = 'account' - return matchend(line, '^\s\+[\[(]\?') + return matchend(line, '^\s\+[*!]\?\s*[\[(]\?') endif elseif line =~ '^\d' "{{{2 (description) let pre = matchend(line, '^\d\S\+\%(([^)]*)\|[*?!]\|\s\)\+') @@ -161,31 +171,51 @@ function! LedgerComplete(findstart, base) "{{{1 let b:compl_cache = s:collect_completion_data() let b:compl_cache['#'] = changenr() endif + let update_cache = 0 let results = [] if b:compl_context == 'account' "{{{2 (account) - unlet! b:compl_context let hierarchy = split(a:base, ':') if a:base =~ ':$' call add(hierarchy, '') endif let results = LedgerFindInTree(b:compl_cache.accounts, hierarchy) - " sort by alphabet and reverse because it will get reversed one more time + let exacts = filter(copy(results), 'v:val[1]') + + if len(exacts) < 1 + " update cache if we have no exact matches + let update_cache = 1 + endif + + if g:ledger_exact_only + let results = exacts + endif + + call map(results, 'v:val[0]') + if g:ledger_detailed_first let results = reverse(sort(results, 's:sort_accounts_by_depth')) else let results = sort(results) endif - call insert(results, a:base) elseif b:compl_context == 'description' "{{{2 (description) - let results = [a:base] + s:filter_items(b:compl_cache.descriptions, a:base) + let results = s:filter_items(b:compl_cache.descriptions, a:base) + + if len(results) < 1 + let update_cache = 1 + endif elseif b:compl_context == 'new' "{{{2 (new line) return [strftime('%Y/%m/%d')] endif "}}} + + if g:ledger_include_original + call insert(results, a:base) + endif + " no completion (apart from a:base) found. update cache if file has changed - if len(results) <= 1 && b:compl_cache['#'] != changenr() + if update_cache && b:compl_cache['#'] != changenr() unlet b:compl_cache return LedgerComplete(a:findstart, a:base) else @@ -203,11 +233,12 @@ function! LedgerFindInTree(tree, levels) "{{{1 let currentlvl = a:levels[0] let nextlvls = a:levels[1:] let branches = s:filter_items(keys(a:tree), currentlvl) + let exact = empty(nextlvls) for branch in branches - call add(results, branch) - if !empty(nextlvls) - for result in LedgerFindInTree(a:tree[branch], nextlvls) - call add(results, branch.':'.result) + call add(results, [branch, exact]) + if ! empty(nextlvls) + for [result, exact] in LedgerFindInTree(a:tree[branch], nextlvls) + call add(results, [branch.':'.result, exact]) endfor endif endfor @@ -221,7 +252,7 @@ function! LedgerToggleTransactionState(lnum, ...) let chars = ' *' endif let trans = s:transaction.from_lnum(a:lnum) - if empty(trans) + if empty(trans) || has_key(trans, 'expr') return endif @@ -238,7 +269,7 @@ function! LedgerSetTransactionState(lnum, char) "{{{1 " modifies or sets the state of the transaction at the cursor, " removing the state alltogether if a:char is empty let trans = s:transaction.from_lnum(a:lnum) - if empty(trans) + if empty(trans) || has_key(trans, 'expr') return endif @@ -250,7 +281,7 @@ endf "}}} function! LedgerSetDate(lnum, type, ...) "{{{1 let time = a:0 == 1 ? a:1 : localtime() let trans = s:transaction.from_lnum(a:lnum) - if empty(trans) + if empty(trans) || has_key(trans, 'expr') return endif @@ -288,7 +319,7 @@ function! s:collect_completion_data() "{{{1 let accounts = [] for xact in transactions " collect descriptions - if index(cache.descriptions, xact['description']) < 0 + if has_key(xact, 'description') && index(cache.descriptions, xact['description']) < 0 call add(cache.descriptions, xact['description']) endif let [t, postings] = xact.parse_body() @@ -354,6 +385,9 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 if parts[0] ==# '~' let trans['expr'] = join(parts[1:]) return trans + elseif parts[0] ==# '=' + let trans['auto'] = join(parts[1:]) + return trans elseif parts[0] !~ '^\d' " this case is avoided in s:get_transaction_extents(), " but we'll check anyway. @@ -411,9 +445,14 @@ function! s:transaction.parse_body(...) dict "{{{2 if line[0] =~ '^\s\+[^[:blank:];]' " posting - " FIXME: replaces original spacing in amount with single spaces - let parts = split(line[0], '\%(\t\| \)\s*') - call add(postings, {'account': parts[0], 'amount': join(parts[1:], ' ')}) + let [state, rest] = matchlist(line[0], '^\s\+\([*!]\?\)\s*\(.*\)$')[1:2] + if rest =~ '\t\| ' + let [account, amount] = matchlist(rest, '^\(.\{-}\)\%(\t\| \)\s*\(.\{-}\)\s*$')[1:2] + else + let amount = '' + let account = matchstr(rest, '^\s*\zs.\{-}\ze\s*$') + endif + call add(postings, {'account': account, 'amount': amount, 'state': state}) end " where are tags to be stored? @@ -450,6 +489,8 @@ endf "}}} function! s:transaction.format_head() dict "{{{2 if has_key(self, 'expr') return '~ '.self['expr'] + elseif has_key(self, 'auto') + return '= '.self['auto'] endif let parts = [] @@ -492,7 +533,7 @@ function! s:get_transactions(...) "{{{2 call add(transactions, trans) call cursor(trans['tail'], 0) endif - let lnum = search('^[~[:digit:]]\S\+', 'cW') + let lnum = search('^[~=[:digit:]]', 'cW') endw " restore view / position @@ -503,7 +544,7 @@ function! s:get_transactions(...) "{{{2 endf "}}} function! s:get_transaction_extents(lnum) "{{{2 - if ! (indent(a:lnum) || getline(a:lnum) =~ '^[~[:digit:]]\S\+') + if ! (indent(a:lnum) || getline(a:lnum) =~ '^[~=[:digit:]]') " only do something if lnum is in a transaction return [0, 0] endif @@ -514,7 +555,7 @@ function! s:get_transaction_extents(lnum) "{{{2 set nofoldenable call cursor(a:lnum, 0) - let head = search('^[~[:digit:]]\S\+', 'bcnW') + let head = search('^[~=[:digit:]]', 'bcnW') let tail = search('^[^;[:blank:]]\S\+', 'nW') let tail = tail > head ? tail - 1 : line('$') diff --git a/doc/ledger.texi b/doc/ledger.texi index ac7bfc5f..8389c383 100644 --- a/doc/ledger.texi +++ b/doc/ledger.texi @@ -1305,8 +1305,9 @@ The format of each following posting is: ACCOUNT AMOUNT [; NOTE] @end example -The @samp{ACCOUNT} may be surrounded by parentheses if it is a virtual -postings, or square brackets if it is a virtual postings that +Note that there must be at least two spaces between @samp{ACCOUNT} and +@samp{AMOUNT}. The @samp{ACCOUNT} may be surrounded by parentheses if it +is a virtual posting or square brackets if it is a virtual posting that must balance. The @samp{AMOUNT} can be followed by a per-unit posting cost, by specifying @samp{@@ AMOUNT}, or a complete posting cost with @samp{@@@@ AMOUNT}. Lastly, the @samp{NOTE} may diff --git a/doc/ledger3.texi b/doc/ledger3.texi index 3fce78e2..da63dd98 100644 --- a/doc/ledger3.texi +++ b/doc/ledger3.texi @@ -4223,7 +4223,7 @@ associated commodity. This commodity can appear before or after the amount, and may or may not be separated from it by a space. Most characters are allowed in a commodity name, except for the following: -@itemize +@itemize @bullet @item Any kind of whitespace @item Numerical digits @item Punctuation: @samp{.,;:?!} @@ -4249,18 +4249,17 @@ in the same form as parsed. If you specify dollar amounts using @samp{$100.000}. You may even use decimal commas, such as @samp{$100,00}, or thousand-marks, as in @samp{$10,000.00}. -These display characteristics become associated with the commodity, -with the result being that all amounts of the same commodity are -reported consistently. Where this is most noticeable is the -@dfn{display precision}, which is determined by the most precise value -seen for a given commodity. In most cases. +These display characteristics become associated with the commodity, with +the result being that all amounts of the same commodity are reported +consistently. Where this is most noticeable is the @dfn{display +precision}, which is determined by the most precise value seen for a +given commodity---in most cases. -Ledger makes a distinction by @dfn{observed amounts} and unobserved +Ledger makes a distinction between @dfn{observed amounts} and unobserved amounts. An observed amount is critiqued by Ledger to determine how -amounts using that commodity should be displayed; unobserved amounts -are significant in their value only---no matter how they are -specified, it does not change how other amounts in that commodity will -be displayed. +amounts using that commodity should be displayed; unobserved amounts are +significant in their value only---no matter how they are specified, it +does not change how other amounts in that commodity will be displayed. An example of this is found in cost expressions, covered next. diff --git a/lib/Makefile b/lib/Makefile index 734816af..bc9611f0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ STOW_ROOT = /usr/local/stow PRODUCTS = $(HOME)/Products -GCC_VERSION = 4.5 +GCC_VERSION = 4.6 BOOST_VERSION = 1_47_0 CC = gcc-mp-$(GCC_VERSION) @@ -13,19 +13,19 @@ ifeq ($(CC),clang) CXX = clang++ LD = llvm-ld DIR_SUFFIX = clang -OPTJ = +OPTJ = else CXX = g++-mp-$(GCC_VERSION) LD = gcc-mp-$(GCC_VERSION) DIR_SUFFIX = gcc$(subst .,,$(GCC_VERSION)) -OPTJ = #-j8 +OPTJ = #-j8 endif CPPFLAGS = -D_GLIBCXX_FULLY_DYNAMIC_STRING=1 ifneq ($(CC),clang) CPPFLAGS += -D_GLIBCXX_DEBUG=1 endif -CFLAGS = $(CPPFLAGS) -g -LDFLAGS = -g +CFLAGS = $(CPPFLAGS) -g2 -ggdb +LDFLAGS = -g2 -ggdb BOOST_SOURCE = boost-release BOOST_DEFINES = define=_GLIBCXX_FULLY_DYNAMIC_STRING=1 @@ -36,9 +36,8 @@ BOOST_TOOLSET = darwin BOOST_DEFINES += define=_GLIBCXX_DEBUG=1 endif #BOOST_FLAGS = --architecture=x86 --address_model=32_64 -BOOST_FLAGS = toolset=$(BOOST_TOOLSET) \ - --build-type=complete --layout=versioned \ - $(BOOST_DEFINES) +BOOST_FLAGS = toolset=$(BOOST_TOOLSET) --layout=versioned \ + link=shared threading=single $(BOOST_DEFINES) BOOST_DIR = boost_$(BOOST_VERSION)-$(DIR_SUFFIX) BOOST_STOW = $(STOW_ROOT)/$(BOOST_DIR) BOOST_BUILD = $(PRODUCTS)/$(BOOST_DIR) @@ -56,7 +55,7 @@ prepare-boost: boost-build: prepare-boost (cd $(BOOST_SOURCE) && \ sh bootstrap.sh && \ - ./bjam $(OPTJ) debug --prefix=$(BOOST_STOW) \ + ./b2 $(OPTJ) debug --prefix=$(BOOST_STOW) \ --build-dir=$(BOOST_BUILD) \ $(BOOST_FLAGS) install) diff --git a/lisp/ldg-mode.el b/lisp/ldg-mode.el index 3e9a9106..cc9e8d92 100644 --- a/lisp/ldg-mode.el +++ b/lisp/ldg-mode.el @@ -10,8 +10,8 @@ ;;("^[0-9]+[-/.=][-/.=0-9]+\\s-+\\(([^)]+)\\s-+\\)?\\([*].+?\\)\\(\\( ;\\| ;\\|$\\)\\)" ;; 2 font-lock-type-face) ("^\\s-+\\([*]\\s-*\\)?\\(\\([[(]\\)?[^*: - ]+?:[^]); - ]+?\\([])]\\)?\\)\\( \\| \\|$\\)" + ]+?:\\([^]); + ]\\|\\s-\\)+?\\([])]\\)?\\)\\( \\| \\|$\\)" 2 font-lock-keyword-face) ("^\\([~=].+\\)" 1 font-lock-function-name-face) ("^\\([A-Za-z]+ .+\\)" 1 font-lock-function-name-face)) diff --git a/src/amount.cc b/src/amount.cc index 808f118d..99e346b7 100644 --- a/src/amount.cc +++ b/src/amount.cc @@ -115,6 +115,7 @@ namespace { mpq_t quant, amount_t::precision_t precision, int zeros_prec = -1, + mpfr_rnd_t rnd = MPFR_RNDN, const optional<commodity_t&>& comm = none) { char * buf = NULL; @@ -135,7 +136,7 @@ namespace { DEBUG("amount.convert", "num prec = " << num_prec); mpfr_set_prec(tempfnum, num_prec); - mpfr_set_z(tempfnum, mpq_numref(quant), GMP_RNDN); + mpfr_set_z(tempfnum, mpq_numref(quant), rnd); mp_prec_t den_prec = mpz_sizeinbase(mpq_denref(quant), 2); den_prec += amount_t::extend_by_digits*64; @@ -144,10 +145,10 @@ namespace { DEBUG("amount.convert", "den prec = " << den_prec); mpfr_set_prec(tempfden, den_prec); - mpfr_set_z(tempfden, mpq_denref(quant), GMP_RNDN); + mpfr_set_z(tempfden, mpq_denref(quant), rnd); mpfr_set_prec(tempfb, num_prec + den_prec); - mpfr_div(tempfb, tempfnum, tempfden, GMP_RNDN); + mpfr_div(tempfb, tempfnum, tempfden, rnd); if (mpfr_asprintf(&buf, "%.*RNf", precision, tempfb) < 0) throw_(amount_error, @@ -669,7 +670,7 @@ void amount_t::in_place_floor() _dup(); std::ostringstream out; - stream_out_mpq(out, MP(quantity), precision_t(0)); + stream_out_mpq(out, MP(quantity), precision_t(0), -1, MPFR_RNDZ); mpq_set_str(MP(quantity), out.str().c_str(), 10); } @@ -844,8 +845,8 @@ double amount_t::to_double() const if (! quantity) throw_(amount_error, _("Cannot convert an uninitialized amount to a double")); - mpfr_set_q(tempf, MP(quantity), GMP_RNDN); - return mpfr_get_d(tempf, GMP_RNDN); + mpfr_set_q(tempf, MP(quantity), MPFR_RNDN); + return mpfr_get_d(tempf, MPFR_RNDN); } long amount_t::to_long() const @@ -853,14 +854,14 @@ long amount_t::to_long() const if (! quantity) throw_(amount_error, _("Cannot convert an uninitialized amount to a long")); - mpfr_set_q(tempf, MP(quantity), GMP_RNDN); - return mpfr_get_si(tempf, GMP_RNDN); + mpfr_set_q(tempf, MP(quantity), MPFR_RNDN); + return mpfr_get_si(tempf, MPFR_RNDN); } bool amount_t::fits_in_long() const { - mpfr_set_q(tempf, MP(quantity), GMP_RNDN); - return mpfr_fits_slong_p(tempf, GMP_RNDN); + mpfr_set_q(tempf, MP(quantity), MPFR_RNDN); + return mpfr_fits_slong_p(tempf, MPFR_RNDN); } commodity_t& amount_t::commodity() const @@ -1239,7 +1240,7 @@ void amount_t::print(std::ostream& _out, const uint_least8_t flags) const } stream_out_mpq(out, MP(quantity), display_precision(), - comm ? commodity().precision() : 0, comm); + comm ? commodity().precision() : 0, MPFR_RNDN, comm); if (comm.has_flags(COMMODITY_STYLE_SUFFIXED)) { if (comm.has_flags(COMMODITY_STYLE_SEPARATED)) diff --git a/src/report.cc b/src/report.cc index d3a219a0..548d39df 100644 --- a/src/report.cc +++ b/src/report.cc @@ -622,6 +622,16 @@ value_t report_t::fn_floor(call_scope_t& args) return args[0].floored(); } +value_t report_t::fn_round(call_scope_t& args) +{ + return args[0].rounded(); +} + +value_t report_t::fn_unround(call_scope_t& args) +{ + return args[0].unrounded(); +} + value_t report_t::fn_abs(call_scope_t& args) { return args[0].abs(); @@ -1281,6 +1291,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return MAKE_FUNCTOR(report_t::fn_rounded); else if (is_eq(p, "red")) return WRAP_FUNCTOR(fn_red); + else if (is_eq(p, "round")) + return MAKE_FUNCTOR(report_t::fn_round); break; case 's': @@ -1333,6 +1345,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, case 'u': if (is_eq(p, "underline")) return WRAP_FUNCTOR(fn_underline); + else if (is_eq(p, "unround")) + return MAKE_FUNCTOR(report_t::fn_unround); else if (is_eq(p, "unrounded")) return MAKE_FUNCTOR(report_t::fn_unrounded); break; diff --git a/src/report.h b/src/report.h index e142b0dc..58c12f24 100644 --- a/src/report.h +++ b/src/report.h @@ -160,6 +160,8 @@ public: value_t fn_unrounded(call_scope_t& scope); value_t fn_truncated(call_scope_t& scope); value_t fn_floor(call_scope_t& scope); + value_t fn_round(call_scope_t& scope); + value_t fn_unround(call_scope_t& scope); value_t fn_abs(call_scope_t& scope); value_t fn_justify(call_scope_t& scope); value_t fn_quoted(call_scope_t& scope); diff --git a/src/stats.cc b/src/stats.cc index 8899ddf5..524f5a87 100644 --- a/src/stats.cc +++ b/src/stats.cc @@ -89,7 +89,8 @@ value_t report_statistics(call_scope_t& args) out << " ("; out.precision(2); out << (double(statistics.posts_count)/ - double((statistics.latest_post - statistics.earliest_post).days())) << _(" per day)") << std::endl; + double((statistics.latest_post - statistics.earliest_post).days())) + << _(" per day)") << std::endl; out << _(" Uncleared postings: "); out.width(6); diff --git a/tools/genuuid b/tools/genuuid new file mode 100755 index 00000000..53fb7a0a --- /dev/null +++ b/tools/genuuid @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import re +import sys + +def scan_path(path): + bug = uuid = None + with open(path, 'r') as fd: + for line in fd: + match = re.match('\*', line) + if match: + bug = uuid = None + + match = re.search('\[\[bug:([0-9]+)\]\[#[0-9]+\]\]', line) + if match: + bug = match.group(1) + elif bug: + match = re.search(':ID:\s+(.+?)\s*$', line) + if match: + uuid = match.group(1) + print "UPDATE bugs SET cf_uuid='%s' WHERE bug_id=%s;" % (uuid, bug) + +scan_path('/Users/johnw/src/ledger/plan/TODO') +scan_path('/Users/johnw/src/ledger/plan/TODO-3.0') +scan_path('/Users/johnw/src/ledger/plan/TODO-2.6.2') +scan_path('/Users/johnw/src/ledger/plan/TODO-2.6.1') + +### genuuid ends here |