From 42f43b7686038e4cbca16d8d2118b139544e6de3 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Sun, 13 Apr 2008 03:35:00 -0400 Subject: Check in all changes made so far toward 3.0. --- xmlparse.cc | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 xmlparse.cc (limited to 'xmlparse.cc') diff --git a/xmlparse.cc b/xmlparse.cc new file mode 100644 index 00000000..c036c007 --- /dev/null +++ b/xmlparse.cc @@ -0,0 +1,473 @@ +#include "xmlparse.h" +#include "journal.h" + +#include + +extern "C" { +#if defined(HAVE_EXPAT) +#include // expat XML parser +#elif defined(HAVE_XMLPARSE) +#include // expat XML parser +#endif +} + +namespace ledger { + +#if defined(HAVE_EXPAT) || defined(HAVE_XMLPARSE) + +static XML_Parser current_parser; +static unsigned int count; + +static journal_t * curr_journal; +static entry_t * curr_entry; +static commodity_t * curr_comm; +static std::string comm_flags; + +static transaction_t::state_t curr_state; + +static std::string data; +static bool ignore; +static std::string have_error; + +static void startElement(void *userData, const char *name, const char **attrs) +{ + if (ignore) + return; + + if (std::strcmp(name, "entry") == 0) { + assert(! curr_entry); + curr_entry = new entry_t; + curr_state = transaction_t::UNCLEARED; + } + else if (std::strcmp(name, "transaction") == 0) { + assert(curr_entry); + curr_entry->add_transaction(new transaction_t); + if (curr_state != transaction_t::UNCLEARED) + curr_entry->transactions.back()->state = curr_state; + } + else if (std::strcmp(name, "commodity") == 0) { + if (std::string(attrs[0]) == "flags") + comm_flags = attrs[1]; + } + else if (std::strcmp(name, "total") == 0) { + ignore = true; + } +} + +static void endElement(void *userData, const char *name) +{ + if (ignore) { + if (std::strcmp(name, "total") == 0) + ignore = false; + return; + } + + if (std::strcmp(name, "entry") == 0) { + assert(curr_entry); + if (curr_journal->add_entry(curr_entry)) { + count++; + } else { + account_t * acct = curr_journal->find_account(""); + curr_entry->add_transaction(new transaction_t(acct)); + if (curr_journal->add_entry(curr_entry)) { + count++; + } else { + delete curr_entry; + have_error = "Entry cannot be balanced"; + } + } + curr_entry = NULL; + } + else if (std::strcmp(name, "en:date") == 0) { + curr_entry->_date = data; + } + else if (std::strcmp(name, "en:date_eff") == 0) { + curr_entry->_date_eff = data; + } + else if (std::strcmp(name, "en:code") == 0) { + curr_entry->code = data; + } + else if (std::strcmp(name, "en:cleared") == 0) { + curr_state = transaction_t::CLEARED; + } + else if (std::strcmp(name, "en:pending") == 0) { + curr_state = transaction_t::PENDING; + } + else if (std::strcmp(name, "en:payee") == 0) { + curr_entry->payee = data; + } + else if (std::strcmp(name, "tr:account") == 0) { + curr_entry->transactions.back()->account = curr_journal->find_account(data); + } + else if (std::strcmp(name, "tr:cleared") == 0) { + curr_entry->transactions.back()->state = transaction_t::CLEARED; + } + else if (std::strcmp(name, "tr:pending") == 0) { + curr_entry->transactions.back()->state = transaction_t::PENDING; + } + else if (std::strcmp(name, "tr:virtual") == 0) { + curr_entry->transactions.back()->flags |= TRANSACTION_VIRTUAL; + } + else if (std::strcmp(name, "tr:generated") == 0) { + curr_entry->transactions.back()->flags |= TRANSACTION_AUTO; + } + else if (std::strcmp(name, "symbol") == 0) { + assert(! curr_comm); + curr_comm = commodity_t::find_or_create(data); + assert(curr_comm); + curr_comm->add_flags(COMMODITY_STYLE_SUFFIXED); + if (! comm_flags.empty()) { + for (std::string::size_type i = 0, l = comm_flags.length(); i < l; i++) { + switch (comm_flags[i]) { + case 'P': curr_comm->drop_flags(COMMODITY_STYLE_SUFFIXED); break; + case 'S': curr_comm->add_flags(COMMODITY_STYLE_SEPARATED); break; + case 'T': curr_comm->add_flags(COMMODITY_STYLE_THOUSANDS); break; + case 'E': curr_comm->add_flags(COMMODITY_STYLE_EUROPEAN); break; + } + } + } + } +#if 0 + // jww (2006-03-02): !!! + else if (std::strcmp(name, "price") == 0) { + assert(curr_comm); + amount_t * price = new amount_t(data); + std::ostringstream symstr; + symstr << curr_comm->symbol << " {" << *price << "}"; + commodity_t * priced_comm = + commodity_t::find_commodity(symstr.str(), true); + priced_comm->price = price; + priced_comm->base = curr_comm; + curr_comm = priced_comm; + } +#endif + else if (std::strcmp(name, "quantity") == 0) { + curr_entry->transactions.back()->amount.parse(data); + if (curr_comm) { + std::string::size_type i = data.find('.'); + if (i != std::string::npos) { + int precision = data.length() - i - 1; + if (precision > curr_comm->precision()) + curr_comm->set_precision(precision); + } + curr_entry->transactions.back()->amount.set_commodity(*curr_comm); + curr_comm = NULL; + } + } + else if (std::strcmp(name, "tr:amount") == 0) { + curr_comm = NULL; + } +} + +static void dataHandler(void *userData, const char *s, int len) +{ + if (! ignore) + data = std::string(s, len); +} + +bool xml_parser_t::test(std::istream& in) const +{ + char buf[80]; + + in.getline(buf, 79); + if (std::strncmp(buf, "\n"; + + commodity_t& c = amount.commodity(); + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "\n"; + for (int i = 0; i < depth + 4; i++) out << ' '; +#if 0 + // jww (2006-03-02): !!! + if (c.price) { + out << "" << c.base->symbol << "\n"; + for (int i = 0; i < depth + 4; i++) out << ' '; + out << "\n"; + xml_write_amount(out, *c.price, depth + 6); + for (int i = 0; i < depth + 4; i++) out << ' '; + out << "\n"; + } else { + out << "" << c.symbol << "\n"; + } +#endif + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "\n"; + + for (int i = 0; i < depth + 2; i++) out << ' '; + out << ""; + out << amount.quantity_string() << "\n"; + + for (int i = 0; i < depth; i++) out << ' '; + out << "\n"; +} + +void xml_write_value(std::ostream& out, const value_t& value, + const int depth = 0) +{ + balance_t * bal = NULL; + + for (int i = 0; i < depth; i++) out << ' '; + out << "\n"; + + switch (value.type) { + case value_t::BOOLEAN: + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "" << *((bool *) value.data) << "\n"; + break; + + case value_t::INTEGER: + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "" << *((long *) value.data) << "\n"; + break; + + case value_t::AMOUNT: + xml_write_amount(out, *((amount_t *) value.data), depth + 2); + break; + + case value_t::BALANCE: + bal = (balance_t *) value.data; + // fall through... + + case value_t::BALANCE_PAIR: + if (! bal) + bal = &((balance_pair_t *) value.data)->quantity; + + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "\n"; + + for (amounts_map::const_iterator i = bal->amounts.begin(); + i != bal->amounts.end(); + i++) + xml_write_amount(out, (*i).second, depth + 4); + + for (int i = 0; i < depth + 2; i++) out << ' '; + out << "\n"; + break; + + default: + assert(0); + break; + } + + for (int i = 0; i < depth; i++) out << ' '; + out << "\n"; +} + +void output_xml_string(std::ostream& out, const std::string& str) +{ + for (const char * s = str.c_str(); *s; s++) { + switch (*s) { + case '<': + out << "<"; + break; + case '>': + out << "&rt;"; + break; + case '&': + out << "&"; + break; + default: + out << *s; + break; + } + } +} + +void format_xml_entries::format_last_entry() +{ + output_stream << " \n" + << " " << last_entry->_date.to_string("%Y/%m/%d") + << "\n"; + + if (last_entry->_date_eff) + output_stream << " " + << last_entry->_date_eff.to_string("%Y/%m/%d") + << "\n"; + + if (! last_entry->code.empty()) { + output_stream << " "; + output_xml_string(output_stream, last_entry->code); + output_stream << "\n"; + } + + if (! last_entry->payee.empty()) { + output_stream << " "; + output_xml_string(output_stream, last_entry->payee); + output_stream << "\n"; + } + + bool first = true; + for (transactions_list::const_iterator i = last_entry->transactions.begin(); + i != last_entry->transactions.end(); + i++) { + if (transaction_has_xdata(**i) && + transaction_xdata_(**i).dflags & TRANSACTION_TO_DISPLAY) { + if (first) { + output_stream << " \n"; + first = false; + } + + output_stream << " \n"; + + if ((*i)->_date) + output_stream << " " + << (*i)->_date.to_string("%Y/%m/%d") + << "\n"; + + if ((*i)->_date_eff) + output_stream << " " + << (*i)->_date_eff.to_string("%Y/%m/%d") + << "\n"; + + if ((*i)->state == transaction_t::CLEARED) + output_stream << " \n"; + else if ((*i)->state == transaction_t::PENDING) + output_stream << " \n"; + + if ((*i)->flags & TRANSACTION_VIRTUAL) + output_stream << " \n"; + if ((*i)->flags & TRANSACTION_AUTO) + output_stream << " \n"; + + if ((*i)->account) { + std::string name = (*i)->account->fullname(); + if (name == "") + name = "[TOTAL]"; + else if (name == "") + name = "[UNKNOWN]"; + + output_stream << " "; + output_xml_string(output_stream, name); + output_stream << "\n"; + } + + output_stream << " \n"; + if (transaction_xdata_(**i).dflags & TRANSACTION_COMPOUND) + xml_write_value(output_stream, + transaction_xdata_(**i).value, 10); + else + xml_write_value(output_stream, value_t((*i)->amount), 10); + output_stream << " \n"; + + if ((*i)->cost) { + output_stream << " \n"; + xml_write_value(output_stream, value_t(*(*i)->cost), 10); + output_stream << " \n"; + } + + if (! (*i)->note.empty()) { + output_stream << " "; + output_xml_string(output_stream, (*i)->note); + output_stream << "\n"; + } + + if (show_totals) { + output_stream << " \n"; + xml_write_value(output_stream, transaction_xdata_(**i).total, 10); + output_stream << " \n"; + } + + output_stream << " \n"; + + transaction_xdata_(**i).dflags |= TRANSACTION_DISPLAYED; + } + } + + if (! first) + output_stream << " \n"; + + output_stream << " \n"; +} +#endif + +} // namespace ledger -- cgit v1.2.3