From 4141afbfae0cfeb55b67efea603962b88b885043 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 25 Nov 2009 02:36:32 -0500 Subject: * and | now comment chars, for the sake of Org-mode --- src/textual.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/textual.cc b/src/textual.cc index 071e111d..0eaa5869 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -345,8 +345,10 @@ void instance_t::read_next_directive() break; } - case '#': // comment line - case ';': // comment line + case ';': // comments + case '#': + case '*': + case '|': break; case '-': // option setting -- cgit v1.2.3 From a7424c1df9b565e77ff25fee46f8a79d2638f42c Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 25 Nov 2009 02:48:58 -0500 Subject: Added a trim() value expression function --- src/report.cc | 28 ++++++++++++++++++++++++++++ src/report.h | 1 + 2 files changed, 29 insertions(+) (limited to 'src') diff --git a/src/report.cc b/src/report.cc index 894e0d89..2d9d7cc6 100644 --- a/src/report.cc +++ b/src/report.cc @@ -380,6 +380,32 @@ value_t report_t::fn_strip(call_scope_t& args) return args.value().strip_annotations(what_to_keep()); } +value_t report_t::fn_trim(call_scope_t& args) +{ + string temp(args.value().to_string()); + scoped_array buf(new char[temp.length() + 1]); + std::strcpy(buf.get(), temp.c_str()); + + const char * p = buf.get(); + while (*p && std::isspace(*p)) + p++; + + const char * e = buf.get() + temp.length(); + while (e > p && std::isspace(*e)) + e--; + + if (e == p) { + return string_value(empty_string); + } + else if (e < p) { + assert(false); + return string_value(empty_string); + } + else { + return string_value(string(p, e - p)); + } +} + value_t report_t::fn_scrub(call_scope_t& args) { value_t temp(args.value().strip_annotations(what_to_keep())); @@ -1078,6 +1104,8 @@ expr_t::ptr_op_t report_t::lookup(const symbol_t::kind_t kind, return MAKE_FUNCTOR(report_t::fn_today); else if (is_eq(p, "t")) return MAKE_FUNCTOR(report_t::fn_display_amount); + else if (is_eq(p, "trim")) + return MAKE_FUNCTOR(report_t::fn_trim); else if (is_eq(p, "to_boolean")) return MAKE_FUNCTOR(report_t::fn_to_boolean); else if (is_eq(p, "to_int")) diff --git a/src/report.h b/src/report.h index d942038b..94d39215 100644 --- a/src/report.h +++ b/src/report.h @@ -143,6 +143,7 @@ public: value_t fn_get_at(call_scope_t& scope); value_t fn_is_seq(call_scope_t& scope); value_t fn_strip(call_scope_t& scope); + value_t fn_trim(call_scope_t& scope); value_t fn_scrub(call_scope_t& scope); value_t fn_quantity(call_scope_t& scope); value_t fn_rounded(call_scope_t& scope); -- cgit v1.2.3 From 2c90c10db17a1e379639f2aa5e7c47fcb351d9f7 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 25 Nov 2009 04:32:30 -0500 Subject: Added support for a "fixed" directive It lets you specify a fixed cost for a duration of a ledger file, for example: fixed ecu $2 2008/01/01 income assets:bank:checking 1 ecu income:salary end fixed This is equivalent to: 2008/01/01 income assets:bank:checking 1 ecu {=$2} income:salary --- src/pool.cc | 16 +++++++++----- src/pool.h | 3 ++- src/quotes.cc | 8 +++---- src/textual.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 75 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/pool.cc b/src/pool.cc index 00f4a3da..70f4eed6 100644 --- a/src/pool.cc +++ b/src/pool.cc @@ -286,7 +286,8 @@ commodity_pool_t::exchange(const amount_t& amount, return breakdown; } -optional commodity_pool_t::parse_price_directive(char * line) +optional > +commodity_pool_t::parse_price_directive(char * line, bool do_not_add_price) { char * date_field_ptr = line; char * time_field_ptr = next_element(date_field_ptr); @@ -295,6 +296,7 @@ optional commodity_pool_t::parse_price_directive(char * line) char * symbol_and_price; datetime_t datetime; + string symbol; if (std::isdigit(time_field_ptr[0])) { symbol_and_price = next_element(time_field_ptr); @@ -307,12 +309,13 @@ optional commodity_pool_t::parse_price_directive(char * line) datetime = datetime_t(parse_date(date_field)); } else { - symbol_and_price = date_field_ptr; + symbol = date_field_ptr; + symbol_and_price = time_field_ptr; datetime = CURRENT_TIME(); } - string symbol; - commodity_t::parse_symbol(symbol_and_price, symbol); + if (symbol.empty()) + commodity_t::parse_symbol(symbol_and_price, symbol); price_point_t point; point.when = datetime; @@ -323,9 +326,10 @@ optional commodity_pool_t::parse_price_directive(char * line) if (commodity_t * commodity = find_or_create(symbol)) { DEBUG("commodity.download", "Adding price for " << symbol << ": " << point.when << " " << point.price); - commodity->add_price(point.when, point.price, true); + if (! do_not_add_price) + commodity->add_price(point.when, point.price, true); commodity->add_flags(COMMODITY_KNOWN); - return point; + return std::pair(commodity, point); } return none; diff --git a/src/pool.h b/src/pool.h index 85de73a9..995ab23c 100644 --- a/src/pool.h +++ b/src/pool.h @@ -123,7 +123,8 @@ public: // Parse commodity prices from a textual representation - optional parse_price_directive(char * line); + optional > + parse_price_directive(char * line, bool do_not_add_price = false); commodity_t * parse_price_expression(const std::string& str, diff --git a/src/quotes.cc b/src/quotes.cc index ffe2142a..f892e93f 100644 --- a/src/quotes.cc +++ b/src/quotes.cc @@ -75,7 +75,7 @@ commodity_quote_from_script(commodity_t& commodity, if (char * p = std::strchr(buf, '\n')) *p = '\0'; DEBUG("commodity.download", "downloaded quote: " << buf); - if (optional point = + if (optional > point = commodity_pool_t::current_pool->parse_price_directive(buf)) { if (commodity_pool_t::current_pool->price_db) { #if defined(__GNUG__) && __GNUG__ < 3 @@ -86,12 +86,12 @@ commodity_quote_from_script(commodity_t& commodity, std::ios_base::out | std::ios_base::app); #endif database << "P " - << format_datetime(point->when, FMT_WRITTEN) + << format_datetime(point->second.when, FMT_WRITTEN) << " " << commodity.symbol() - << " " << point->price + << " " << point->second.price << std::endl; } - return point; + return point->second; } } else { DEBUG("commodity.download", diff --git a/src/textual.cc b/src/textual.cc index 0eaa5869..cf670cae 100644 --- a/src/textual.cc +++ b/src/textual.cc @@ -54,7 +54,8 @@ namespace { static const std::size_t MAX_LINE = 1024; public: - typedef variant state_t; + typedef std::pair fixed_rate_t; + typedef variant state_t; std::list& state_stack; @@ -99,6 +100,9 @@ namespace { bool front_is_string() { return state_stack.front().type() == typeid(string); } + bool front_is_fixed_rate() { + return state_stack.front().type() == typeid(fixed_rate_t); + } account_t * top_account() { foreach (state_t& state, state_stack) @@ -135,6 +139,7 @@ namespace { void master_account_directive(char * line); void end_directive(char * line); void alias_directive(char * line); + void fixed_directive(char * line); void tag_directive(char * line); void define_directive(char * line); bool general_directive(char * line); @@ -512,7 +517,7 @@ void instance_t::price_conversion_directive(char * line) void instance_t::price_xact_directive(char * line) { - optional point = + optional > point = commodity_pool_t::current_pool->parse_price_directive(skip_ws(line + 1)); if (! point) throw parse_error(_("Pricing entry failed to parse")); @@ -705,10 +710,13 @@ void instance_t::end_directive(char * kind) if ((name.empty() || name == "account") && ! front_is_account()) throw_(std::runtime_error, - _("'end account' directive does not match open tag directive")); + _("'end account' directive does not match open directive")); else if (name == "tag" && ! front_is_string()) throw_(std::runtime_error, - _("'end tag' directive does not match open account directive")); + _("'end tag' directive does not match open directive")); + else if (name == "fixed" && ! front_is_fixed_rate()) + throw_(std::runtime_error, + _("'end fixed' directive does not match open directive")); if (state_stack.size() <= 1) throw_(std::runtime_error, @@ -738,6 +746,18 @@ void instance_t::alias_directive(char * line) } } +void instance_t::fixed_directive(char * line) +{ + if (optional > price_point = + commodity_pool_t::current_pool->parse_price_directive(trim_ws(line), + true)) { + state_stack.push_front(fixed_rate_t(price_point->first, + price_point->second.price)); + } else { + throw_(std::runtime_error, _("Error in fixed directive")); + } +} + void instance_t::tag_directive(char * line) { string tag(trim_ws(line)); @@ -799,6 +819,13 @@ bool instance_t::general_directive(char * line) } break; + case 'f': + if (std::strcmp(p, "fixed") == 0) { + fixed_directive(arg); + return true; + } + break; + case 'i': if (std::strcmp(p, "include") == 0) { include_directive(arg); @@ -812,6 +839,13 @@ bool instance_t::general_directive(char * line) return true; } break; + + case 'y': + if (std::strcmp(p, "year") == 0) { + year_directive(arg); + return true; + } + break; } if (expr_t::ptr_op_t op = lookup(symbol_t::DIRECTIVE, p)) { @@ -935,13 +969,28 @@ post_t * instance_t::parse_post(char * line, post.get(), PARSE_NO_REDUCE | PARSE_SINGLE | PARSE_NO_ASSIGN, defer_expr); - if (! post->amount.is_null() && honor_strict && strict && - post->amount.has_commodity() && + if (! post->amount.is_null() && post->amount.has_commodity()) { + if (honor_strict && strict && ! post->amount.commodity().has_flags(COMMODITY_KNOWN)) { - if (post->_state == item_t::UNCLEARED) - warning_(_("\"%1\", line %2: Unknown commodity '%3'") - << pathname << linenum << post->amount.commodity()); - post->amount.commodity().add_flags(COMMODITY_KNOWN); + if (post->_state == item_t::UNCLEARED) + warning_(_("\"%1\", line %2: Unknown commodity '%3'") + << pathname << linenum << post->amount.commodity()); + post->amount.commodity().add_flags(COMMODITY_KNOWN); + } + + if (! post->amount.has_annotation()) { + foreach (state_t& state, state_stack) { + if (state.type() == typeid(fixed_rate_t)) { + fixed_rate_t& rate(boost::get(state)); + if (*rate.first == post->amount.commodity()) { + annotation_t details(rate.second); + details.add_flags(ANNOTATION_PRICE_FIXATED); + post->amount.annotate(details); + break; + } + } + } + } } DEBUG("textual.parse", "line " << linenum << ": " -- cgit v1.2.3 From 72aa0e0e442442b2d08af4e42c281beeeb5ea3af Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Wed, 25 Nov 2009 04:32:39 -0500 Subject: Added some debugging code related to boost::regex --- src/query.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/query.cc b/src/query.cc index 2d6085fa..cfa321b0 100644 --- a/src/query.cc +++ b/src/query.cc @@ -337,7 +337,9 @@ query_t::parser_t::parse_query_term(query_t::lexer_t::token_t::kind_t tok_contex } expr_t::ptr_op_t mask = new expr_t::op_t(expr_t::op_t::VALUE); + DEBUG("query.mask", "Mask from string: " << *tok.value); mask->set_value(mask_t(*tok.value)); + DEBUG("query.mask", "Mask is: " << mask->as_value().as_mask().str()); node->set_left(ident); node->set_right(mask); -- cgit v1.2.3