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

View File

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

View File

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

View File

@ -29,6 +29,8 @@ extern "C"
{
#endif
#include <Python.h>
static char *__doc__ = \
"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" \