viewvc-4intranet/misc/tparse/tparsemodule.cpp

297 lines
7.5 KiB
C++

/*
# Copyright (C) 1999-2013 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewVC
# distribution or at http://viewvc.org/license-1.html.
#
# For more information, visit http://viewvc.org/
#
# -----------------------------------------------------------------------
#
# This file has been rewritten in C++ from the rcsparse.py file by
# Lucas Bruand <lucas.bruand@ecl2002.ec-lyon.fr>
#
# This file was originally based on portions of the blame.py script by
# Curt Hagenlocher.
#
# -----------------------------------------------------------------------
*/
/*
This python extension module is a binding to the tparse library.
tparse is a C++ library that offers an API to a performance-oriented
RCSFILE parser. It does little syntax checking.
Version: $Id$
*/
#include <fstream>
#include "tparsemodule.h"
#include "tparse.cpp"
#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
#include <memory> // for auto_ptr
#include <ext/stdio_filebuf.h>
typedef __gnu_cxx::stdio_filebuf<char> stdio_filebuf;
#define GNUC_STDIO_FILEBUF_AVAILABLE
#endif
using namespace std;
class PythonException
{
public:
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 */
};
void inittparse()
{
PyObject *m, *d, *common, *commondict;
pystring ver(__version__),
dat(__date__),
aut(__author__);
m = Py_InitModule3("tparse", tparseMethods, __doc__);
common = PyImport_ImportModule("common");
if (!common)
return ; // Common not imported ?
commondict = PyModule_GetDict(common);
pyRCSStopParser = PyDict_GetItemString(commondict, "RCSStopParser");
Py_INCREF(pyRCSStopParser);
pyRCSParseError = PyDict_GetItemString(commondict, "RCSParseError");
Py_INCREF(pyRCSParseError);
pyRCSIllegalCharacter = PyDict_GetItemString(commondict,
"RCSIllegalCharacter");
Py_INCREF(pyRCSIllegalCharacter);
pyRCSExpected = PyDict_GetItemString(commondict, "RCSExpected");
Py_INCREF(pyRCSExpected);
PySink = PyDict_GetItemString(commondict, "Sink");
Py_INCREF(PySink);
d = PyModule_GetDict(m);
PyDict_SetItemString(d, "__version__", *ver);
PyDict_SetItemString(d, "__date__", *dat);
PyDict_SetItemString(d, "__author__", *aut);
}
class PythonSink : public Sink
{
public:
PyObject *sink;
PythonSink(PyObject *mysink)
{
sink = mysink;
Py_INCREF(sink);
};
virtual ~PythonSink() throw ()
{
Py_DECREF(sink);
};
virtual void set_head_revision(rcstoken &revision)
{
chkpy(PyObject_CallMethod(sink, "set_head_revision", "s",
revision.data));
};
virtual void set_principal_branch(rcstoken &branch_name)
{
chkpy(PyObject_CallMethod(sink, "set_principal_branch",
"s", branch_name.data));
};
virtual void define_tag(rcstoken &name, rcstoken &revision)
{
chkpy(PyObject_CallMethod(sink, "define_tag", "ss",
name.data, revision.data));
};
virtual void set_comment(rcstoken &comment)
{
pystring c(comment);
chkpy(PyObject_CallMethod(sink, "set_comment", "S", *c));
};
virtual void set_description(rcstoken &description)
{
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;
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 = NULL;
PyObject *file = NULL;
PyObject *hsink;
PyObject *rv = Py_None;
#ifdef GNUC_STDIO_FILEBUF_AVAILABLE
auto_ptr<streambuf> rdbuf;
#endif
if (PyArg_ParseTuple(args, "sO!", &filename, &PyInstance_Type, &hsink))
input = new ifstream(filename, ios::in);
else if (PyArg_ParseTuple(args, "O!O!", &PyFile_Type, &file,
&PyInstance_Type, &hsink))
{
PyErr_Clear(); // Reset the exception PyArg_ParseTuple has raised.
#ifdef GNUC_STDIO_FILEBUF_AVAILABLE
rdbuf.reset(new stdio_filebuf(PyFile_AsFile(file), ios::in | ios::binary));
input = new istream(rdbuf.get());
#else
PyErr_SetString(PyExc_NotImplementedError,
"tparse only implements the parsing of filehandles "
"when compiled with GNU C++ version 3.1 or later - "
"please pass a filename instead");
return NULL;
#endif
}
else
return NULL;
if (!PyObject_IsInstance(hsink, PySink))
{
PyErr_SetString(PyExc_TypeError,
"Sink has to be an instance of class Sink.");
return NULL;
}
try
{
tparseParser tp(input, new PythonSink(hsink));
tp.parse();
}
catch (RCSExpected e)
{
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)
{
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)
{
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)
{
if (! PyErr_ExceptionMatches(pyRCSStopParser))
rv = NULL;
else
PyErr_Clear();
}
Py_XINCREF(rv);
return rv;
};