summaryrefslogtreecommitdiff
path: root/parser.cc
blob: cc93b9dcf6d906377551455b16075422972a31bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "parser.h"
#include "journal.h"

#include <fstream>
#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

namespace ledger {

typedef std::list<parser_t *> parsers_list;

static parsers_list parsers;

bool register_parser(parser_t * parser)
{
  parsers_list::iterator i;
  for (i = parsers.begin(); i != parsers.end(); i++)
    if (*i == parser)
      break;
  if (i != parsers.end())
    return false;

  parsers.push_back(parser);

  return true;
}

bool unregister_parser(parser_t * parser)
{
  parsers_list::iterator i;
  for (i = parsers.begin(); i != parsers.end(); i++)
    if (*i == parser)
      break;
  if (i == parsers.end())
    return false;

  parsers.erase(i);

  return true;
}

unsigned int parse_journal(std::istream&       in,
			   journal_t *	       journal,
			   account_t *	       master,
			   const std::string * original_file)
{
  if (! master)
    master = journal->master;

  for (parsers_list::iterator i = parsers.begin();
       i != parsers.end();
       i++)
    if ((*i)->test(in))
      return (*i)->parse(in, journal, master, original_file);

  return 0;
}

unsigned int parse_journal_file(const std::string&  path,
				journal_t *	    journal,
				account_t *	    master,
				const std::string * original_file)
{
  journal->sources.push_back(path);

  if (access(path.c_str(), R_OK) == -1)
    throw error(std::string("Cannot read file '") + path + "'");

  if (! original_file)
    original_file = &path;

  std::ifstream stream(path.c_str());
  return parse_journal(stream, journal, master, original_file);
}

} // namespace ledger

#ifdef USE_BOOST_PYTHON

#include <boost/python.hpp>
#include <Python.h>

using namespace boost::python;
using namespace ledger;

struct parser_wrap : public parser_t
{
  PyObject * self;
  parser_wrap(PyObject * self_) : self(self_) {}

  virtual bool test(std::istream& in) const {
    return call_method<bool>(self, "test", in);
  }

  virtual unsigned int parse(std::istream&	 in,
			     journal_t *	 journal,
			     account_t *	 master        = NULL,
			     const std::string * original_file = NULL) {
    return call_method<unsigned int>(self, "__call__", in, journal, master,
				     original_file);
  }
};

BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_overloads, parse_journal, 2, 4)
BOOST_PYTHON_FUNCTION_OVERLOADS(parse_journal_file_overloads,
				parse_journal_file, 2, 4)

void export_parser() {
  class_< parser_t, parser_wrap, boost::noncopyable > ("Parser")
    ;

  def("register_parser", register_parser);
  def("unregister_parser", unregister_parser);
  def("parse_journal", parse_journal, parse_journal_overloads());
  def("parse_journal_file", parse_journal_file, parse_journal_file_overloads());
}

#endif // USE_BOOST_PYTHON