Exception usage cleanup. Use exceptions to terminate the parser in all cases.

Also protect pointers with auto_ptr to ensure cleanup.

Note: Before this change exceptions *could* occur, but all pointer-referenced
memory would be leaked.

* tparse/tparse.h: Change #include-s to C++ names.
  (RCSParseError):  Change to be a public descendant of exception. Use
  string datatype to ensure automatic cleanup. Implement a destructor
  as required by exception.
  (RCSExpected):  Use string datatype to ensure automatic cleanup. Add
  constructor for expected characters.
  (Branche): Removed.  Replaced with std::list<>.
  (Sink): Change method definition to reflect switch to exceptions.
  (TokenParser::match):  Add method for matching characters.
  (TokenParser::semicol, TokenParser::matchsemicol): Removed.
  Obsolete because we're now able to match single characters.
  (tparseParser):  Change method definition to reflect the switch
  to exceptions.
  (tparseParser::parse):  Adapt to changed method definitions.

* tparse/tparse.cpp: Change #include-s to C++ names.
  (TokenParser::get): Space changes and conversion to auto_ptr.
  (tparseParser::parse_rcs_admin,
   tparseParser::parse_rcs_description,
   tparseParser::parse_rcs_deltatext): Conversion to auto_ptr and exceptions.
  (tparseParser::parse_rcs_tree): Conversion to auto_ptr and exceptions. Also
  adjust for removal of Branche class.

* tparse/tparsemodule.h:  Include Python.h, since
  we,re actually using python types.

* tparse/tparsemodule.cpp (pyobject, pystring):
  New classes.  Used to anchor python objects ensuring their refcounts
  are decremented.
  (chkpy):  New.  Function to check python return value and act appropriately.
  (initparse):  Correctly anchor python strings.
  (rcstoken_to_pystring):  Removed.  Now integrated into the pystring class.
  (PythonSink):  Claim ownership for the duration of the instance lifetime.
  Also adjust all methods for the switch to exceptions.
  (tparse):  Adapt to the switch to exceptions.  Also prevent memory leakage
  when an exception occurs.


git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1060 8cb11bc2-c004-0410-86c3-e597b4017df7
remotes/tags/1.0.0-rc1
dionisos 2005-05-01 13:56:23 +00:00
parent cab7c9ae04
commit 55889fd691
4 changed files with 312 additions and 391 deletions

View File

@ -31,10 +31,14 @@
*/ */
#include "tparse.h" #include "tparse.h"
#ifndef __USE_XOPEN #ifndef __USE_XOPEN
#define __USE_XOPEN #define __USE_XOPEN
#endif #endif
#include <time.h> #include <ctime> /* for strptime */
using namespace std;
#define Whitespace(c) (c == ' ' || c == '\t' || c == '\014' || c == '\n' || \ #define Whitespace(c) (c == ' ' || c == '\t' || c == '\014' || c == '\n' || \
c == '\r') c == '\r')
@ -90,22 +94,25 @@ rcstoken *rcstoken::copy_begin_len(size_t begin, size_t len)
/*--------- Tokenparser class -----------*/ /*--------- Tokenparser class -----------*/
rcstoken *TokenParser::get() rcstoken *TokenParser::get()
{ {
rcstoken *token; auto_ptr<rcstoken> token;
if (backget) if (backget)
{ {
token = backget; token.reset(backget);
backget = NULL; backget = NULL;
return token;
return token.release();
} }
token.reset(new rcstoken());
while (1) while (1)
{ {
if (idx == buflength) if (idx == buflength)
{ {
input->read(buf, CHUNK_SIZE); input->read(buf, CHUNK_SIZE);
if ( (buflength = input->gcount()) == 0 ) if ( (buflength = input->gcount()) == 0 )
return NULL; return token.release();
idx = 0; idx = 0;
} }
if (!Whitespace(buf[idx])) if (!Whitespace(buf[idx]))
@ -113,17 +120,17 @@ rcstoken *TokenParser::get()
idx++; idx++;
} }
token = new rcstoken();
if (buf[idx] == ';') if (buf[idx] == ';')
{ {
idx++; idx++;
(*token) = ';'; (*token) = ';';
return token; return token.release();
} }
if (buf[idx] != '@') if (buf[idx] != '@')
{ {
int end = idx + 1; int end = idx + 1;
while (1) while (1)
{ {
while ( (end < buflength) && !(Token_term(buf[end])) ) while ( (end < buflength) && !(Token_term(buf[end])) )
@ -132,7 +139,7 @@ rcstoken *TokenParser::get()
if (end < buflength) if (end < buflength)
{ {
idx = end; idx = end;
return token; return token.release();
} }
input->read(buf, CHUNK_SIZE); input->read(buf, CHUNK_SIZE);
buflength = input->gcount(); buflength = input->gcount();
@ -141,9 +148,11 @@ rcstoken *TokenParser::get()
} }
} }
idx++; idx++;
while (1) while (1)
{ {
int i; int i;
if (idx == buflength) if (idx == buflength)
{ {
idx = 0; idx = 0;
@ -181,11 +190,10 @@ rcstoken *TokenParser::get()
if ((i - idx) > 0) if ((i - idx) > 0)
token->append(buf + idx, i - idx); token->append(buf + idx, i - idx);
idx = i + 1; idx = i + 1;
return token; return token.release();
} }
}; };
void TokenParser::unget(rcstoken *token) void TokenParser::unget(rcstoken *token)
{ {
if (backget) if (backget)
@ -197,84 +205,63 @@ void TokenParser::unget(rcstoken *token)
} }
/*--------- tparseParser class -----------*/ /*--------- tparseParser class -----------*/
int tparseParser::parse_rcs_admin() void tparseParser::parse_rcs_admin()
{ {
while (1) while (1)
{ {
rcstoken *token = tokenstream->get(); auto_ptr<rcstoken> token(tokenstream->get());
if (isdigit((*token)[0])) if (isdigit((*token)[0]))
{ {
tokenstream->unget(token); tokenstream->unget(token.release());
return 0; return;
} }
if (*token == "head") if (*token == "head")
{ {
delete token; token.reset(tokenstream->get());
if (sink->set_head_revision(token = tokenstream->get())) sink->set_head_revision(*token);
{
delete token; tokenstream->match(';');
return 1;
}
tokenstream->matchsemicol();
delete token;
continue; continue;
} }
if (*token == "branch") if (*token == "branch")
{ {
rcstoken *branch = tokenstream->get(); token.reset(tokenstream->get());
if (*branch != ';') if (*token != ';')
{ {
if (sink->set_principal_branch(branch)) sink->set_principal_branch(*token);
{
delete branch; tokenstream->match(';');
delete token;
return 1;
}
delete branch;
tokenstream->matchsemicol();
} }
delete token;
continue; continue;
} }
if (*token == "symbols") if (*token == "symbols")
{ {
while (1) while (1)
{ {
rcstoken *tag, *rev; auto_ptr<rcstoken> tag, rev;
char *second; char *second;
delete token; // delete token;
token = tokenstream->get(); token.reset(tokenstream->get());
if (*token == ';') if (*token == ';')
break; break;
/*FIXME: this does not allow "<tag> : <rev>" /*FIXME: this does not allow "<tag> : <rev>"
which the spec does allow */ which the spec does allow */
second = index(token->data, ':'); second = index(token->data, ':');
tag = token->copy_begin_len(0, second - token->data); tag.reset(token->copy_begin_len(0, second - token->data));
second++; second++;
rev = new rcstoken(second); rev.reset(new rcstoken(second));
if (sink->define_tag(tag, rev)) sink->define_tag(*tag, *rev);
{
delete tag;
delete rev;
delete token;
return 1;
}
delete tag;
delete rev;
} }
continue; continue;
} }
if (*token == "comment") if (*token == "comment")
{ {
delete token; token.reset(tokenstream->get());
if (sink->set_comment(token = tokenstream->get())) sink->set_comment((*token));
{
delete token; tokenstream->match(';');
return 1;
}
tokenstream->matchsemicol();
delete token;
continue; continue;
} }
if (*token == "locks" || if (*token == "locks" ||
@ -284,81 +271,79 @@ int tparseParser::parse_rcs_admin()
{ {
while (1) while (1)
{ {
rcstoken *tag = tokenstream->get(); token.reset(tokenstream->get());
if (*tag == ';') if (*token == ';')
{ break;
delete tag;
break;
}
delete tag;
} }
delete token;
continue; continue;
} }
delete token;
} }
}; };
int tparseParser::parse_rcs_tree() void tparseParser::parse_rcs_tree()
{ {
while (1) while (1)
{ {
rcstoken *revision; auto_ptr<rcstoken> revision, date, author, hstate, next;
rcstoken *date;
long timestamp; long timestamp;
rcstoken *author; tokenlist branches;
rcstoken *hstate;
rcstoken *next;
Branche *branches = NULL;
struct tm tm; struct tm tm;
revision = tokenstream->get();
revision.reset(tokenstream->get());
if (*revision == "desc") if (*revision == "desc")
{ {
tokenstream->unget(revision); tokenstream->unget(revision.release());
return 0; return;
} }
// Parse date // Parse date
tokenstream->match("date"); tokenstream->match("date");
date = tokenstream->get(); date.reset(tokenstream->get());
tokenstream->matchsemicol(); tokenstream->match(";");
memset ((void *) &tm, 0, sizeof(struct tm)); memset ((void *) &tm, 0, sizeof(struct tm));
if (strptime(date->data, "%y.%m.%d.%H.%M.%S", &tm) == NULL) if (strptime((*date).data, "%y.%m.%d.%H.%M.%S", &tm) == NULL)
strptime(date->data, "%Y.%m.%d.%H.%M.%S", &tm); strptime((*date).data, "%Y.%m.%d.%H.%M.%S", &tm);
timestamp = mktime(&tm); timestamp = mktime(&tm);
delete date;
tokenstream->match("author"); tokenstream->match("author");
author = tokenstream->get(); author.reset(tokenstream->get());
tokenstream->matchsemicol(); tokenstream->match(';');
tokenstream->match("state"); tokenstream->match("state");
hstate = new rcstoken(); hstate.reset(new rcstoken());
while (1) while (1)
{ {
rcstoken *token = tokenstream->get(); auto_ptr<rcstoken> token;
if (*token == ';') token.reset(tokenstream->get());
{
break;
}
if (hstate->length)
(*hstate) += ' ';
(*hstate) += *token;
delete token;
}
tokenstream->match("branches");
while (1)
{
rcstoken *token = tokenstream->get();
if (*token == ';') if (*token == ';')
break; break;
branches = new Branche(token, branches); if ((*hstate).length)
(*hstate) += ' ';
(*hstate) += *token;
} }
tokenstream->match("branches");
while (1)
{
auto_ptr<rcstoken> token;
token.reset(tokenstream->get());
if (*token == ';')
break;
branches.push_front((*token));
}
tokenstream->match("next"); tokenstream->match("next");
next = tokenstream->get(); next.reset(tokenstream->get());
if (*next == ';') if (*next == ';')
/* generate null token */ /* generate null token */
next = new rcstoken(); next.reset(new rcstoken());
else else
tokenstream->matchsemicol(); tokenstream->match(';');
/* /*
* there are some files with extra tags in them. for example: * there are some files with extra tags in them. for example:
* owner 640; * owner 640;
@ -367,77 +352,53 @@ int tparseParser::parse_rcs_tree()
* hardlinks @configure.in@; * hardlinks @configure.in@;
* this is "newphrase" in RCSFILE(5). we just want to skip over these. * this is "newphrase" in RCSFILE(5). we just want to skip over these.
*/ */
while (1) while (1)
{
rcstoken *token = tokenstream->get();
if (*token == "desc" || isdigit((*token)[0]))
{ {
tokenstream->unget(token); auto_ptr<rcstoken> token;
break; token.reset(tokenstream->get());
};
delete token;
while ( (*(token = tokenstream->get())) == ';')
delete token;
}
if (sink->define_revision(revision, timestamp, author, if ((*token == "desc") || isdigit((*token)[0]) )
hstate, branches, next)) {
{ tokenstream->unget(token.release());
delete revision; break;
delete author; };
delete hstate;
delete branches; while (*token != ";")
delete next; token.reset(tokenstream->get());
return 1;
} }
delete revision;
delete author; sink->define_revision(*revision, timestamp, *author,
delete hstate; *hstate, branches, *next);
delete branches;
delete next;
} }
return 0; return;
} }
int tparseParser::parse_rcs_description() void tparseParser::parse_rcs_description()
{ {
rcstoken *token; auto_ptr<rcstoken> token;
tokenstream->match("desc"); tokenstream->match("desc");
if (sink->set_description(token = tokenstream->get()))
{
delete token;
return 1;
}
delete token;
return 0; token.reset(tokenstream->get());
sink->set_description(*token);
} }
int tparseParser::parse_rcs_deltatext() void tparseParser::parse_rcs_deltatext()
{ {
rcstoken *revision; auto_ptr<rcstoken> revision, log, text;
rcstoken *log;
rcstoken *text;
while (1) while (1)
{ {
revision = tokenstream->get(); revision.reset(tokenstream->get());
if (revision == NULL) if ((*revision).null_token())
break; break;
tokenstream->match("log"); tokenstream->match("log");
log = tokenstream->get(); log.reset(tokenstream->get());
tokenstream->match("text"); tokenstream->match("text");
text = tokenstream->get(); text.reset(tokenstream->get());
if (sink->set_revision_info(revision, log, text))
{ sink->set_revision_info(*revision, *log, *text);
delete revision;
delete log;
delete text;
return 1;
}
delete revision;
delete log;
delete text;
} }
return 0; return;
} }

View File

@ -30,15 +30,18 @@
Version: $Id$ Version: $Id$
*/ */
#define CHUNK_SIZE 30000
#ifndef __PARSE_H #ifndef __PARSE_H
#define __PARSE_H #define __PARSE_H
#include <iostream.h> #include <memory> /* for auto_ptr */
#include <stdio.h> #include <algorithm> /* for iterator */
#include <fstream.h> #include <exception> /* for exception */
#include <string.h> #include <iostream> /* for istream */
#include <stdlib.h> #include <list> /* for list<> */
#include <string> /* for string */
#define CHUNK_SIZE 30000
#define DEFAULT_TOKEN_SIZE 512 #define DEFAULT_TOKEN_SIZE 512
#define DEFAULT_TOKEN_DELTA 10240 #define DEFAULT_TOKEN_DELTA 10240
@ -46,15 +49,17 @@ using namespace std;
/* This class represents a exception that occured during the parsing /* This class represents a exception that occured during the parsing
of a file */ of a file */
class RCSParseError
class RCSParseError : public exception
{ {
public: public:
const char *value; string value;
RCSParseError() {}; RCSParseError() {};
RCSParseError(const char *myvalue) RCSParseError(const char *myvalue)
{ {
value = myvalue; value = myvalue;
}; };
virtual ~RCSParseError() throw() {};
}; };
class RCSIllegalCharacter : public RCSParseError class RCSIllegalCharacter : public RCSParseError
@ -64,21 +69,27 @@ class RCSIllegalCharacter : public RCSParseError
{ {
value = myvalue; value = myvalue;
}; };
virtual ~RCSIllegalCharacter() throw() {};
}; };
class RCSExpected : public RCSParseError class RCSExpected : public RCSParseError
{ {
public: public:
const char *got; string got;
const char *wanted; string wanted;
RCSExpected(const char *mygot, const char *mywanted) RCSExpected(const char *mygot, const char *mywanted)
{ {
got = mygot; got = mygot;
wanted = mywanted; wanted = mywanted;
} };
RCSExpected(const char *mygot, const char c)
{
got = mygot;
wanted = c;
};
virtual ~RCSExpected() throw() {};
}; };
class rcstoken class rcstoken
{ {
public: public:
@ -168,26 +179,10 @@ class rcstoken
rcstoken *copy_begin_len(size_t begin, size_t len); rcstoken *copy_begin_len(size_t begin, size_t len);
}; };
/* This class is used to store a list of the branches of a revision */ typedef list<rcstoken> tokenlist;
class Branche typedef tokenlist::iterator tokenlist_iter;
{
public:
rcstoken *name;
Branche *next;
Branche(rcstoken *myname, Branche *mynext)
{
name = myname;
next = mynext;
};
~Branche()
{
delete name;
name = NULL;
if (next != NULL)
delete next;
next = NULL;
};
};
/* This class is a handler that receive the event generated by the parser /* This class is a handler that receive the event generated by the parser
i.e.: When we reach the head revision tag, etc... */ i.e.: When we reach the head revision tag, etc... */
@ -195,19 +190,19 @@ class Sink
{ {
public: public:
Sink() {}; Sink() {};
virtual int set_head_revision(rcstoken *revision) = 0; virtual ~Sink() throw () {};
virtual int set_principal_branch(rcstoken *branch_name) = 0; virtual void set_head_revision(rcstoken &revision) = 0;
virtual int define_tag(rcstoken *name, rcstoken *revision) = 0; virtual void set_principal_branch(rcstoken &branch_name) = 0;
virtual int set_comment(rcstoken *comment) = 0; virtual void define_tag(rcstoken &name, rcstoken &revision) = 0;
virtual int set_description(rcstoken *description) = 0; virtual void set_comment(rcstoken &comment) = 0;
virtual int define_revision(rcstoken *revision, long timestamp, virtual void set_description(rcstoken &description) = 0;
rcstoken *author, rcstoken *state, virtual void define_revision(rcstoken &revision, long timestamp,
Branche *branches, rcstoken *next) = 0; rcstoken &author, rcstoken &state,
virtual int set_revision_info(rcstoken *revision, tokenlist &branches, rcstoken &next) = 0;
rcstoken *log, virtual void set_revision_info(rcstoken &revision,
rcstoken *text) = 0; rcstoken &log, rcstoken &text) = 0;
virtual int tree_completed() = 0; virtual void tree_completed() = 0;
virtual int parse_completed() = 0; virtual void parse_completed() = 0;
}; };
/* The class is used to get one by one every token in the file. */ /* The class is used to get one by one every token in the file. */
@ -220,33 +215,30 @@ class TokenParser
int idx; int idx;
rcstoken *backget; rcstoken *backget;
public: public:
char *semicol;
rcstoken *get(); rcstoken *get();
void unget(rcstoken *token); void unget(rcstoken *token);
int eof() int eof()
{ {
return (input->gcount() == 0); return (input->gcount() == 0);
}; };
void matchsemicol()
{
rcstoken *ptr = get();
if ((*ptr) != ';')
throw RCSExpected(ptr->data, semicol);
delete ptr;
};
void match(const char *token) void match(const char *token)
{ {
rcstoken *ptr = get(); auto_ptr<rcstoken> ptr(get());
if (*ptr != token) if (*ptr != token)
throw RCSExpected(ptr->data, token); throw RCSExpected(ptr->data, token);
delete ptr; }
void match(const char c)
{
auto_ptr<rcstoken> token(get());
if ((*token) != c)
throw RCSExpected(token->data, c);
}; };
TokenParser(istream *myinput) TokenParser(istream *myinput)
{ {
input = myinput; input = myinput;
backget = NULL; backget = NULL;
idx = 0; idx = 0;
semicol = ";";
input->read(buf, CHUNK_SIZE); input->read(buf, CHUNK_SIZE);
if ( (buflength = input->gcount()) == 0 ) if ( (buflength = input->gcount()) == 0 )
throw RCSParseError("Non-existing file or empty file"); throw RCSParseError("Non-existing file or empty file");
@ -273,10 +265,10 @@ class tparseParser
private: private:
TokenParser *tokenstream; TokenParser *tokenstream;
Sink *sink; Sink *sink;
int parse_rcs_admin(); void parse_rcs_admin();
int parse_rcs_tree(); void parse_rcs_tree();
int parse_rcs_description(); void parse_rcs_description();
int parse_rcs_deltatext(); void parse_rcs_deltatext();
public: public:
tparseParser(istream *myinput, Sink* mysink) tparseParser(istream *myinput, Sink* mysink)
{ {
@ -285,25 +277,18 @@ class tparseParser
} }
void parse() void parse()
{ {
if (parse_rcs_admin()) parse_rcs_admin();
return; parse_rcs_tree();
if (parse_rcs_tree())
return;
// many sinks want to know when the tree has been completed so they can // many sinks want to know when the tree has been completed so they can
// do some work to prepare for the arrival of the deltatext // do some work to prepare for the arrival of the deltatext
if (sink->tree_completed()) sink->tree_completed();
return;
if (parse_rcs_description())
return;
if (parse_rcs_deltatext())
return;
parse_rcs_description();
parse_rcs_deltatext();
// easiest for us to tell the sink it is done, rather than worry about // easiest for us to tell the sink it is done, rather than worry about
// higher level software doing it. // higher level software doing it.
if (sink->parse_completed()) sink->parse_completed();
return;
} }
~tparseParser() ~tparseParser()
{ {

View File

@ -30,7 +30,9 @@
Version: $Id$ Version: $Id$
*/ */
#include <Python.h>
#include <fstream>
#include "tparsemodule.h" #include "tparsemodule.h"
#include "tparse.cpp" #include "tparse.cpp"
@ -49,6 +51,49 @@ class PythonException
PythonException() {}; PythonException() {};
}; };
class pyobject
{
private:
PyObject *obj;
public:
pyobject(PyObject *myobj)
{
obj = myobj;
}
~pyobject()
{
Py_XDECREF(obj);
};
PyObject *operator*()
{
return obj;
};
};
class pystring : public pyobject
{
public:
pystring(const char *s) :
pyobject(PyString_FromString(s))
{};
pystring(rcstoken& t) :
pyobject(PyString_FromStringAndSize(t.data, t.length))
{};
};
static
void chkpy(PyObject *obj)
{
Py_XDECREF(obj);
if (!obj)
throw PythonException();
};
static PyMethodDef tparseMethods[] = { static PyMethodDef tparseMethods[] = {
{"parse", tparse, METH_VARARGS, tparse__doc__}, {"parse", tparse, METH_VARARGS, tparse__doc__},
{NULL, NULL} /* Sentinel */ {NULL, NULL} /* Sentinel */
@ -57,6 +102,9 @@ static PyMethodDef tparseMethods[] = {
void inittparse() void inittparse()
{ {
PyObject *m, *d, *common, *commondict; PyObject *m, *d, *common, *commondict;
pystring ver(__version__),
dat(__date__),
aut(__author__);
m = Py_InitModule3("tparse", tparseMethods, __doc__); m = Py_InitModule3("tparse", tparseMethods, __doc__);
common = PyImport_ImportModule("common"); common = PyImport_ImportModule("common");
@ -82,17 +130,11 @@ void inittparse()
d = PyModule_GetDict(m); d = PyModule_GetDict(m);
PyDict_SetItemString(d, "__version__", PyString_FromString(__version__)); PyDict_SetItemString(d, "__version__", *ver);
PyDict_SetItemString(d, "__date__", PyString_FromString(__date__)); PyDict_SetItemString(d, "__date__", *dat);
PyDict_SetItemString(d, "__author__", PyString_FromString(__author__)); PyDict_SetItemString(d, "__author__", *aut);
} }
static
PyObject *rcstoken_to_pystring(rcstoken *token)
{
return PyString_FromStringAndSize(token->data, token->length);
};
class PythonSink : public Sink class PythonSink : public Sink
{ {
public: public:
@ -100,166 +142,79 @@ class PythonSink : public Sink
PythonSink(PyObject *mysink) PythonSink(PyObject *mysink)
{ {
sink = mysink; sink = mysink;
Py_INCREF(sink);
}; };
int set_head_revision(rcstoken *revision) virtual ~PythonSink() throw ()
{ {
PyObject *rv = PyObject_CallMethod(sink, "set_head_revision", "s", Py_DECREF(sink);
revision->data);
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
}; };
int set_principal_branch(rcstoken *branch_name) virtual void set_head_revision(rcstoken &revision)
{ {
PyObject *rv = PyObject_CallMethod(sink, "set_principal_branch", "s", chkpy(PyObject_CallMethod(sink, "set_head_revision", "s",
branch_name->data); revision.data));
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
}; };
int define_tag(rcstoken *name, rcstoken *revision) virtual void set_principal_branch(rcstoken &branch_name)
{ {
PyObject *rv = PyObject_CallMethod(sink, "define_tag", "ss", chkpy(PyObject_CallMethod(sink, "set_principal_branch",
name->data, revision->data); "s", branch_name.data));
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
}; };
int set_comment(rcstoken *comment) virtual void define_tag(rcstoken &name, rcstoken &revision)
{ {
PyObject *rv = PyObject_CallMethod(sink, "set_comment", "s", chkpy(PyObject_CallMethod(sink, "define_tag", "ss",
comment->data); name.data, revision.data));
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
}; };
int set_description(rcstoken *description) virtual void set_comment(rcstoken &comment)
{ {
PyObject *rv = PyObject_CallMethod(sink, "set_description", "s", pystring c(comment);
description->data); chkpy(PyObject_CallMethod(sink, "set_comment", "S", *c));
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
}; };
int define_revision(rcstoken *revision, long timestamp, rcstoken *author, virtual void set_description(rcstoken &description)
rcstoken *state, Branche *branches, rcstoken *next)
{ {
PyObject *pbranchs = PyList_New(0); pystring d(description);
Branche *move = branches; chkpy(PyObject_CallMethod(sink, "set_description", "S", *d));
while (move != NULL) };
{ virtual void define_revision(rcstoken &revision, long timestamp,
PyObject *str = rcstoken_to_pystring(move->name); rcstoken &author, rcstoken &state,
PyList_Append(pbranchs, str ); tokenlist &branches, rcstoken &next)
Py_DECREF(str); {
move = move->next; pyobject branchlist(PyList_New(0));
} tokenlist_iter branch;
PyObject *rv = PyObject_CallMethod(sink, "define_revision", "slssOs", for (branch = branches.begin(); branch != branches.end(); branch++)
revision->data,timestamp, {
author->data,state->data,pbranchs, pystring str(*branch);
next ? next->data : NULL); PyList_Append(*branchlist, *str);
if (!rv) { }
Py_DECREF(pbranchs);
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
Py_DECREF(pbranchs);
return 0;
};
int set_revision_info(rcstoken *revision, rcstoken *log, rcstoken *text)
{
PyObject *txt = rcstoken_to_pystring(text);
PyObject *rv = PyObject_CallMethod(sink, "set_revision_info", "ssS",
revision->data,log->data,txt);
Py_DECREF(txt);
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
};
int tree_completed()
{
PyObject *rv = PyObject_CallMethod(sink, "tree_completed", NULL);
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
};
int parse_completed()
{
PyObject *rv = PyObject_CallMethod(sink, "parse_completed", NULL);
if (!rv) {
if (PyErr_ExceptionMatches(pyRCSStopParser))
return 1;
else
throw PythonException();
}
else {
Py_DECREF(rv);
}
return 0;
chkpy(PyObject_CallMethod(sink, "define_revision", "slssOs",
revision.data,timestamp,
author.data,state.data,*branchlist,
next.data));
};
virtual void set_revision_info(rcstoken& revision,
rcstoken& log, rcstoken& text)
{
pystring l(log), txt(text);
chkpy(PyObject_CallMethod(sink, "set_revision_info", "sSS",
revision.data, *l, *txt));
};
virtual void tree_completed()
{
chkpy(PyObject_CallMethod(sink, "tree_completed", NULL));
};
virtual void parse_completed()
{
chkpy(PyObject_CallMethod(sink, "parse_completed", NULL));
}; };
}; };
static PyObject * tparse( PyObject *self, PyObject *args) static PyObject * tparse( PyObject *self, PyObject *args)
{ {
char *filename; char *filename;
istream *input; istream *input = NULL;
PyObject *file = NULL; PyObject *file = NULL;
PyObject *hsink; PyObject *hsink;
PyObject *rv = Py_None;
#ifdef GNUC_STDIO_FILEBUF_AVAILABLE #ifdef GNUC_STDIO_FILEBUF_AVAILABLE
auto_ptr<streambuf> rdbuf; auto_ptr<streambuf> rdbuf;
#endif #endif
@ -284,6 +239,8 @@ static PyObject * tparse( PyObject *self, PyObject *args)
else else
return NULL; return NULL;
if (!PyObject_IsInstance(hsink, PySink)) if (!PyObject_IsInstance(hsink, PySink))
{ {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -298,31 +255,47 @@ static PyObject * tparse( PyObject *self, PyObject *args)
} }
catch (RCSExpected e) catch (RCSExpected e)
{ {
PyObject *exp = PyInstance_New(pyRCSExpected, const char *got = e.got.c_str();
Py_BuildValue("(ss)", e.got, e.wanted), const char *wanted = e.wanted.c_str();
NULL);
PyErr_SetObject(pyRCSExpected, exp); pyobject arg(Py_BuildValue("(ss)", got, wanted)),
return NULL; exp(PyInstance_New(pyRCSExpected, *arg, NULL));
PyErr_SetObject(pyRCSExpected, *exp);
delete [] got;
delete [] wanted;
rv = NULL;
} }
catch (RCSIllegalCharacter e) catch (RCSIllegalCharacter e)
{ {
PyObject *exp = PyInstance_New(pyRCSIllegalCharacter, const char *value = e.value.c_str();
Py_BuildValue("(s)", e.value), NULL);
PyErr_SetObject(pyRCSIllegalCharacter, exp); pyobject arg(Py_BuildValue("(s)", value)),
return NULL; exp(PyInstance_New(pyRCSIllegalCharacter,*arg, NULL));
PyErr_SetObject(pyRCSIllegalCharacter, *exp);
delete [] value;
rv = NULL;
} }
catch (RCSParseError e) catch (RCSParseError e)
{ {
PyObject *exp = PyInstance_New(pyRCSParseError, const char *value = e.value.c_str();
Py_BuildValue("(s)", e.value), NULL);
PyErr_SetObject(pyRCSParseError, exp); pyobject arg(Py_BuildValue("(s)", value)),
return NULL; exp(PyInstance_New(pyRCSParseError, *arg, NULL));
PyErr_SetObject(pyRCSParseError, *exp);
delete [] value;
rv = NULL;
} }
catch (PythonException e) catch (PythonException e)
{ {
return NULL; if (! PyErr_ExceptionMatches(pyRCSStopParser))
rv = NULL;
else
PyErr_Clear();
} }
Py_INCREF(Py_None); Py_XINCREF(rv);
return Py_None; return rv;
}; };

View File

@ -29,6 +29,8 @@ extern "C"
{ {
#endif #endif
#include <Python.h>
static char *__doc__ = \ static char *__doc__ = \
"This python extension module is a binding to the tparse library.\n" \ "This python extension module is a binding to the tparse library.\n" \
"tparse is a C++ library that offers an API to a performance-oriented\n" \ "tparse is a C++ library that offers an API to a performance-oriented\n" \