297 lines
7.5 KiB
C++
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;
|
|
};
|