P4API.cpp #5

  • //
  • guest/
  • robert_cowham/
  • perforce/
  • API/
  • python/
  • official/
  • P4API.cpp
  • View
  • Commits
  • Open Download .zip Download (30 KB)
/*
 * Python wrapper for the Perforce ClientApi object.
 *
 * Copyright (c) 2007-2008, Perforce Software, Inc.  All rights reserved.
 * Portions Copyright (c) 1999, Mike Meyer. All rights reserved.
 * Portions Copyright (c) 2004-2007, Robert Cowham. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTR
 * IBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * $Id: //depot/r10.2/p4-python/P4API.cpp#1 $
 *
 * Build instructions:
 *  Use Distutils - see accompanying setup.py
 *
 *      python setup.py install
 *
 */
 
#include <Python.h>
#include <bytesobject.h>
#include <structmember.h>
#include "undefdups.h"
#include "python2to3.h"
#include <clientapi.h>
#include <strtable.h>
#include <spec.h>
#include <ident.h>
#include <mapapi.h>
#include "P4Result.h"
#include "SpecMgr.h"
#include "PythonClientUser.h"
#include "PythonClientAPI.h"
#include "PythonMergeData.h"
#include "P4MapMaker.h"
#include "PythonMessage.h"
#include "PythonTypes.h"

// #include <alloca.h> 

#include <iostream>
#include <cstring>
#include <sstream>
#include <vector>

using namespace std;

static Ident ident = { 
	IdentMagic "P4Python" "/" ID_OS  "/"  ID_REL "/" ID_PATCH  " (" ID_API " API)",
	ID_Y "/" ID_M "/" ID_D 
};

// ===================
// ==== P4Adapter ====
// ===================

PyObject * P4Error;

/*
 * P4Adapter destructor
 */
static void
P4Adapter_dealloc(P4Adapter *self)
{
    delete self->clientAPI;
    Py_TYPE(self)->tp_free((PyObject*)self);
}

/*
 * P4Adapter constructor.
 */
static PyObject *
P4Adapter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    P4Adapter *self = (P4Adapter *) type->tp_alloc(type, 0);
    if (self != NULL) {	
	self->clientAPI = new PythonClientAPI();
    }
    
    return (PyObject *) self;
}

/*
 * P4Adapter initializer.
 */
static int
P4Adapter_init(P4Adapter *self, PyObject *args, PyObject *kwds)
{

    if (kwds != NULL && PyDict_Check(kwds)) {
    	Py_ssize_t pos = 0;
    	PyObject *key, *value;
	
    	while (PyDict_Next(kwds, &pos, &key, &value)) {
     	    const char * name = GetPythonString(key);
	    
	    if (PyInt_Check(value)) {
	    	PythonClientAPI::intsetter isetter = self->clientAPI->GetIntSetter(name);
	    	if (isetter) {
	    	    int result = (self->clientAPI->*isetter)(PyInt_AS_LONG(value));
		    if (result) 
			return result;
	    	}
	    	else {
	    	    ostringstream os;
	    	    os << "No integer keyword with name " << name;
	    	    
	    	    PyErr_SetString(PyExc_AttributeError, os.str().c_str()); 
	            return -1;	
	    	}
	    }
	    else 
	    if (IsString(value)) {
	    	PythonClientAPI::strsetter ssetter = self->clientAPI->GetStrSetter(name);
	    	if (ssetter) {
	    	    int result = (self->clientAPI->*ssetter)(GetPythonString(value));
		    if (result)
			return result;
	    	}
	    	else {
	    	    ostringstream os;
	    	    os << "No string keyword with name " << name;
	    	    
	    	    PyErr_SetString(PyExc_AttributeError, os.str().c_str()); 
	            return -1;	
	    	}
	    }   	    	
    	} 
    }
    
    return 0;
}

static PyObject *
P4Adapter_repr(P4Adapter *self)
{
	return CreatePythonString("P4Adapter");
}

// **************************************
// P4Adapter directly implemented methods
// **************************************

static PyObject * P4Adapter_connect(P4Adapter * self)
{
    return self->clientAPI->Connect();
}

static PyObject * P4Adapter_connected(P4Adapter * self)
{
    return self->clientAPI->Connected();
}

static PyObject * P4Adapter_disconnect(P4Adapter * self)
{
    return self->clientAPI->Disconnect();
}

//
// Get a value from the environment following the Perforce conventions,
// including honouring P4CONFIG files etc.
//
static PyObject * P4Adapter_env(P4Adapter * self, PyObject * var)
{
    if ( !var ) Py_RETURN_NONE;

    const char *val = self->clientAPI->GetEnv( GetPythonString( var ) );
    if( !val ) Py_RETURN_NONE;

    return CreatePythonString( val );
}

static PyObject * P4Adapter_run(P4Adapter * self, PyObject * args)
{
    PyObject * cmd = PyTuple_GetItem(args, 0);
    if (cmd == NULL) {
    	return NULL;
    }
    
    // assume the args are flattened already
    
    vector<const char *> argv;
    for (Py_ssize_t i = 1; i < PyTuple_Size(args); ++i) {
    	argv.push_back(GetPythonString(PyObject_Str(PyTuple_GET_ITEM(args, i))));
    }
    
    // this is a bit of a hack: it assumes the storage layout of the vector is continuous
    // the other hack is that the API expects (char * const *), but this cannot be stored
    // a std::vector<>, because it cannot exchange pointers
    
    return self->clientAPI->Run(GetPythonString(cmd), argv.size(), 
        (argv.size() > 0) ? (char * const *) &argv[0] : NULL );
}

static PyObject * P4API_identify(PyObject * self)
{
    StrBuf	s;
    ident.GetMessage( &s );
    return CreatePythonString( s.Text() );
}

static PyObject * P4Adapter_formatSpec(P4Adapter * self, PyObject * args)
{
    const char * type;
    PyObject * dict;
    
    if ( PyArg_ParseTuple(args, "sO", &type, &dict) ) {
    	if ( PyDict_Check(dict) ) {
    	    return self->clientAPI->FormatSpec(type, dict);
    	}
    	else {
    	    PyErr_SetString(PyExc_TypeError, "Second argument needs to be a dictionary");
    	    return NULL;
    	}
    }
    
    return NULL;
}

static PyObject * P4Adapter_parseSpec(P4Adapter * self, PyObject * args)
{
    const char * type;
    const char * form;
    
    if ( PyArg_ParseTuple(args, "ss", &type, &form) ) {
    	return self->clientAPI->ParseSpec(type, form);
    }
    
    return NULL;
}

static PyObject * P4Adapter_protocol(P4Adapter * self, PyObject *args)
{
    const char * var;
    const char * val = 0;

    if ( PyArg_ParseTuple(args, "s|s", &var, &val) ) {
	if ( val ) {
	    return self->clientAPI->SetProtocol( var, val );
	}
	else {
	    return self->clientAPI->GetProtocol( var );
	}
    }

    return NULL;
}

static PyMethodDef P4Adapter_methods[] = {
    {"connect", (PyCFunction)P4Adapter_connect, METH_NOARGS,
     "Connects to the Perforce Server"},
    {"connected", (PyCFunction)P4Adapter_connected, METH_NOARGS,
     "Checks whether we are (still) connected"},
    {"disconnect", (PyCFunction)P4Adapter_disconnect, METH_NOARGS,
     "Closes the connection to the Perforce Server"},
    {"env", (PyCFunction)P4Adapter_env, METH_O, 
     "Get values from the Perforce environment"},
    {"run", (PyCFunction)P4Adapter_run, METH_VARARGS,
     "Runs a command"},
    {"format_spec", (PyCFunction)P4Adapter_formatSpec, METH_VARARGS,
     "Converts a dictionary-based form into a string"},
    {"parse_spec", (PyCFunction)P4Adapter_parseSpec, METH_VARARGS,
     "Converts a string form into a dictionary"},
    {"protocol", (PyCFunction)P4Adapter_protocol, METH_VARARGS,
     "Sets a server protocol variable to the given value or gets the protocol level"}, 
     {NULL}  /* Sentinel */
};

static PyMemberDef P4Adapter_members[] = {
//    {"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
//     "first name"},
    {NULL}  /* Sentinel */
};

static PyObject * P4Adapter_getattro(P4Adapter *self, PyObject * nameObject) 
{
    const char * name = GetPythonString(nameObject);
    
    PythonClientAPI::intgetter igetter = self->clientAPI->GetIntGetter(name);
    if (igetter) {
    	return PyInt_FromLong((self->clientAPI->*igetter)());
    }
    
    PythonClientAPI::strgetter sgetter = self->clientAPI->GetStrGetter(name);
    if (sgetter) {
    	return CreatePythonString((self->clientAPI->*sgetter)());
    }
    
    PythonClientAPI::objgetter ogetter = self->clientAPI->GetObjGetter(name);
    if (ogetter) {
    	return (self->clientAPI->*ogetter)();
    }
    
    return PyObject_GenericGetAttr((PyObject *) self, nameObject);
}

static int P4Adapter_setattro(P4Adapter *self, PyObject * nameObject, PyObject * value)
{
    const char * name = GetPythonString(nameObject);

    // Special case first: 
    // If there is a specific ObjectSetter for this name available use this one
    
    PythonClientAPI::objsetter osetter = self->clientAPI->GetObjSetter(name);
    if (osetter) {
        return (self->clientAPI->*osetter)(value);
    }
    else
    if (PyInt_Check(value)) {
    	PythonClientAPI::intsetter isetter = self->clientAPI->GetIntSetter(name);
    	if (isetter) {
    	    return (self->clientAPI->*isetter)(PyInt_AS_LONG(value));
    	}
    	else {
    	    ostringstream os;
    	    os << "No integer attribute with name " << name;
    	    
    	    PyErr_SetString(PyExc_AttributeError, os.str().c_str()); 
            return -1;	
    	}
    }
    else 
    if (IsString(value)) {
    	PythonClientAPI::strsetter ssetter = self->clientAPI->GetStrSetter(name);
    	if (ssetter) {
    	    return (self->clientAPI->*ssetter)(GetPythonString(value));
    	}
    	else {
    	    ostringstream os;
    	    os << "No string attribute with name " << name;
    	    
    	    PyErr_SetString(PyExc_AttributeError, os.str().c_str()); 
            return -1;	
    	}
    }
    
    // can only set int and string or certain object values -> bail out with exception
    ostringstream os;
    os << "Cannot set attribute : " << name << " with value " << GetPythonString(PyObject_Str(value));
    
    PyErr_SetString(PyExc_AttributeError, os.str().c_str()); 
    return -1;	
}

/* PyObject object for the P4Adapter */
static PyTypeObject P4AdapterType = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "P4API.P4Adapter",				/* name */
    sizeof(P4Adapter),				/* basicsize */
    0,           				/* itemsize */
    (destructor) P4Adapter_dealloc,		/* dealloc */
    0,           				/* print */
    0,						/* getattr */
    0,						/* setattr */
    0,           				/* compare */
    (reprfunc) P4Adapter_repr,   		/* repr */
    0,           				/* number methods */
    0,           				/* sequence methods */
    0,           				/* mapping methods */
    0,                         			/* tp_hash */
    0,                         			/* tp_call*/
    0,                         			/* tp_str*/
    (getattrofunc) P4Adapter_getattro, 		/* tp_getattro*/
    (setattrofunc) P4Adapter_setattro,		/* tp_setattro*/
    0,                         			/* tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* tp_flags*/
    "P4Adapter - base class for P4",		/* tp_doc */
    0,		               			/* tp_traverse */
    0,		               			/* tp_clear */
    0,		               			/* tp_richcompare */
    0,		               			/* tp_weaklistoffset */
    0,		               			/* tp_iter */
    0,		               			/* tp_iternext */
    P4Adapter_methods,             		/* tp_methods */
    P4Adapter_members,             		/* tp_members */
    0,                         			/* tp_getset */
    0,                         			/* tp_base */
    0,                         			/* tp_dict */
    0,                         			/* tp_descr_get */
    0,                         			/* tp_descr_set */
    0,                         			/* tp_dictoffset */
    (initproc)P4Adapter_init,      		/* tp_init */
    0,                         			/* tp_alloc */
    P4Adapter_new,                 		/* tp_new */
};

// =====================
// ==== P4MergeData ====
// =====================

/*
 * P4MergeData destructor
 */
static void P4MergeData_dealloc(P4MergeData *self)
{
    delete self->mergeData;
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject * P4MergeData_repr(P4MergeData *self)
{
    // TODO: add more output information to give full representation
    return CreatePythonString("P4MergeData");
}

// ****************************************
// P4MergeData directly implemented methods
// ****************************************

static PyObject * P4MergeData_run_merge(P4MergeData * self)
{
    return self->mergeData->RunMergeTool();
}

static PyMethodDef P4MergeData_methods[] = {
    {"run_merge", (PyCFunction)P4MergeData_run_merge, METH_NOARGS,
     "Runs the merge tool with this data"},
    {NULL}  /* Sentinel */
};

static PyObject * P4MergeData_getattro(P4MergeData * self, PyObject * nameObject)
{
    const char * name = GetPythonString(nameObject);
    
    if( !strcmp( name, "your_name" ) ) {
        return self->mergeData->GetYourName();
    } 
    else if( !strcmp( name, "their_name" ) ) {
        return self->mergeData->GetTheirName();
    }
    else if( !strcmp( name, "base_name" ) ) {
        return self->mergeData->GetBaseName();
    }
    else if( !strcmp( name, "your_path" ) ) {
        return self->mergeData->GetYourPath();
    }
    else if( !strcmp( name, "their_path" ) ) {
        return self->mergeData->GetTheirPath();
    }
    else if( !strcmp( name, "base_path" ) ) {
        return self->mergeData->GetBasePath();
    }
    else if( !strcmp( name, "result_path" ) ) {
        return self->mergeData->GetResultPath();
    }
    else if( !strcmp( name, "merge_hint" ) ) {
        return self->mergeData->GetMergeHint();
    }
    
    // no matching name found, falling back to default
    return PyObject_GenericGetAttr((PyObject *) self, nameObject);
}

/* PyObject object for the P4MergeData */
PyTypeObject P4MergeDataType = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "P4API.P4MergeData",                        /* name */
    sizeof(P4MergeData),                        /* basicsize */
    0,                                          /* itemsize */
    (destructor) P4MergeData_dealloc,           /* dealloc */
    0,                                          /* print */
    0,                                          /* getattr */
    0,                                          /* setattr */
    0,                                          /* compare */
    (reprfunc) P4MergeData_repr,                /* repr */
    0,                                          /* number methods */
    0,                                          /* sequence methods */
    0,                                          /* mapping methods */
    0,                                          /* tp_hash */
    0,                                          /* tp_call*/
    0,                                          /* tp_str*/
    (getattrofunc) P4MergeData_getattro,        /* tp_getattro*/
    0,                                          /* tp_setattro*/
    0,                                          /* tp_as_buffer*/
    Py_TPFLAGS_DEFAULT,                         /* tp_flags*/
    "P4MergeData - contains merge information for resolve",            /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    P4MergeData_methods,                          /* tp_methods */
    0,                                          /* tp_members */
    0,                                          /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    0,                                          /* tp_init */
    0,                                          /* tp_alloc */
    0,                                          /* tp_new */
};

// ===============
// ==== P4Map ====
// ===============

extern PyTypeObject P4MapType; // forward


/*
 * P4Map destructor
 */
static void
        P4Map_dealloc(P4Map *self)
{
    delete self->map;
    Py_TYPE(self)->tp_free((PyObject*)self);
}

/*
 * P4Map constructor.
 */
static PyObject *
        P4Map_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    P4Map *self = (P4Map *) type->tp_alloc(type, 0);
    if (self != NULL) { 
        self->map = new P4MapMaker();
    }
    
    return (PyObject *) self;
}

/*
 * P4Map initializer.
 */
static int
        P4Map_init(P4Map *self, PyObject *args, PyObject *kwds)
{
    // nothing to do for now
    return 0;
}

static PyObject *
        P4Map_repr(P4Map *self)
{
    return self->map->Inspect();
}

static PyObject *
        P4Map_insert(P4Map *self, PyObject * args)
{
    // expects one, or two arguments, lhs, and optional rhs. In the
    // absence of rhs, lhs is assumed to contain both halves.
    PyObject *lhs;
    PyObject *rhs = NULL;
    
    // ugly hack for now
#if PY_MAJOR_VERSION >= 3
    const char * format = "U|U";
#else
    const char * format = "S|S";
#endif
    int ok = PyArg_ParseTuple(args, format, &lhs, &rhs );
    if (ok) {
	if( !rhs )
	    self->map->Insert( lhs );
	else
	    self->map->Insert(lhs, rhs );
        Py_RETURN_NONE;
    }
    return NULL;
}

static PyObject *
        P4Map_clear(P4Map *self)
{
    // clears out the map
    
    self->map->Clear();
    
    Py_RETURN_NONE;
}

static PyObject *
        P4Map_translate(P4Map *self, PyObject * args)
{
    // expects two arguments, the string and the direction 
    // True (default) ==> Left to Right
    // False ==> Right to Left
    
    PyObject *str;
    int direction = 1;
    
#if PY_MAJOR_VERSION >= 3
    const char * format = "U|b";
#else
    const char * format = "S|b";
#endif

    int ok = PyArg_ParseTuple(args, format, &str, &direction);
    if (ok) {
        return self->map->Translate(str, direction);
    }
    return NULL;
}

static PyObject *
        P4Map_reverse(P4Map *self)
{
    P4Map *	rmap = (P4Map *) P4MapType.tp_alloc(&P4MapType, 0);

    if (!rmap)
       return (PyObject *) rmap;

    rmap->map = new P4MapMaker( *self->map );
    rmap->map->Reverse();
    
    return (PyObject *) rmap;
}

static PyObject *
        P4Map_count(P4Map *self)
{
    return PyInt_FromLong( self->map->Count() );
}

static PyObject *
        P4Map_lhs(P4Map *self)
{
    return self->map->Lhs();
}

static PyObject *
        P4Map_rhs(P4Map *self)
{
    return self->map->Rhs();
}

static PyObject *
        P4Map_as_array(P4Map *self)
{
    return self->map->ToA();
}

static PyObject *
        P4Map_join(PyTypeObject *type, PyObject * args)
{
    // expects two P4Map objects
    
    P4Map *left;
    P4Map *right;
    P4Map *result;
    
    int ok = PyArg_ParseTuple(args, "O!O!", &P4MapType, (PyObject **) &left, &P4MapType, (PyObject **) &right);
    if (!ok) 
    	return NULL;
    
    PyObject * p4Module = PyImport_ImportModule("P4");
    PyObject * p4Dict = PyModule_GetDict(p4Module);
    PyObject * mapClass = PyDict_GetItemString(p4Dict, "Map");
    if (mapClass == NULL) {
        cout << "Could not find class P4.Map" << endl;
	return NULL;
    }

    result = (P4Map *) PyObject_CallObject(mapClass, NULL);
    delete result->map;
    result->map = P4MapMaker::Join(left->map, right->map);
    return (PyObject *) result;
}

static PyMethodDef P4Map_methods[] = {
    {"insert", (PyCFunction) P4Map_insert, METH_VARARGS,
                "Insert left hand, right hand, and the maptype ('', '+', '-')"},
    {"clear",  (PyCFunction) P4Map_clear, METH_NOARGS,
                "Clears out the map."},
    {"translate", (PyCFunction) P4Map_translate, METH_VARARGS,
                   "Translates the passed arguments using the map and returns a string"},
    {"count", (PyCFunction) P4Map_count, METH_NOARGS,
                   "Returns number of entries in the maps"},
    {"reverse", (PyCFunction) P4Map_reverse, METH_NOARGS,
                   "Swap the left and right sides of the map"},
    {"lhs", (PyCFunction) P4Map_lhs, METH_NOARGS,
                   "Returns a list containing the LHS"},
    {"rhs", (PyCFunction) P4Map_rhs, METH_NOARGS,
                   "Returns a list containing the RHS"},
    {"as_array", (PyCFunction) P4Map_as_array, METH_NOARGS,
                   "Returns the map contents as a list"},
    {"join", (PyCFunction) P4Map_join, METH_VARARGS | METH_CLASS,
                   "Joins two maps together and returns a third"},
    {NULL}  /* Sentinel */
};

/* PyObject object for the P4MergeData */
PyTypeObject P4MapType = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
            "P4API.P4Map",                               /* name */
            sizeof(P4Map),                              /* basicsize */
            0,                                          /* itemsize */
            (destructor) P4Map_dealloc,                 /* dealloc */
            0,                                          /* print */
            0,                                          /* getattr */
            0,                                          /* setattr */
            0,                                          /* compare */
            (reprfunc) P4Map_repr,                      /* repr */
            0,                                          /* number methods */
            0,                                          /* sequence methods */
            0,                                          /* mapping methods */
            0,                                          /* tp_hash */
            0,                                          /* tp_call*/
            0,                                          /* tp_str*/
            0,                                          /* tp_getattro*/
            0,                                          /* tp_setattro*/
            0,                                          /* tp_as_buffer*/
            Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags*/
            "P4Map - client mapping interface",         /* tp_doc */
            0,                                          /* tp_traverse */
            0,                                          /* tp_clear */
            0,                                          /* tp_richcompare */
            0,                                          /* tp_weaklistoffset */
            0,                                          /* tp_iter */
            0,                                          /* tp_iternext */
            P4Map_methods,                              /* tp_methods */
            0,                                          /* tp_members */
            0,                                          /* tp_getset */
            0,                                          /* tp_base */
            0,                                          /* tp_dict */
            0,                                          /* tp_descr_get */
            0,                                          /* tp_descr_set */
            0,                                          /* tp_dictoffset */
            (initproc) P4Map_init,                      /* tp_init */
            0,                                          /* tp_alloc */
            P4Map_new,                                  /* tp_new */
};

// ===================
// ==== P4Message ====
// ===================

static void
P4Message_dealloc(P4Message *self)
{
    delete self->msg;
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
P4Message_str(P4Message *self)
{
    return self->msg->getText();
}

static PyObject *
P4Message_repr(P4Message *self)
{
    return self->msg->getRepr();
}

static int
P4Message_init(P4Message *self, PyObject *args, PyObject *kwds)
{
    return 0;
}

static PyMethodDef P4Message_methods[] = {
	{NULL}  /* Sentinel */
};

static PyObject *
P4Message_getattro(P4Message * self, PyObject * nameObject)
{
    const char * name = GetPythonString(nameObject);

    if( strcmp(name, "severity") == 0) {
	return self->msg->getSeverity();
    }
    else if( strcmp(name, "generic") == 0) {
	return self->msg->getGeneric();
    }
    else if( strcmp(name, "msgid") == 0) {
	return self->msg->getMsgid();
    }
    else
	return PyObject_GenericGetAttr((PyObject *) self, nameObject);
}

PyTypeObject P4MessageType =
{
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
	    "P4API.P4Message",                          /* name */
	    sizeof(P4Message),                          /* basicsize */
	    0,                                          /* itemsize */
	    (destructor) P4Message_dealloc,             /* dealloc */
	    0,                                          /* print */
	    0,                                          /* getattr */
	    0,                                          /* setattr */
	    0,                                          /* compare */
	    (reprfunc) P4Message_repr,                  /* repr */
	    0,                                          /* number methods */
	    0,                                          /* sequence methods */
	    0,                                          /* mapping methods */
	    0,                                          /* tp_hash */
	    0,                                          /* tp_call*/
	    (reprfunc) P4Message_str,                   /* tp_str*/
	    (getattrofunc) P4Message_getattro,          /* tp_getattro*/
	    0,                                          /* tp_setattro*/
	    0,                                          /* tp_as_buffer*/
	    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags*/
	    "P4Message - errors and warnings",          /* tp_doc */
	    0,                                          /* tp_traverse */
	    0,                                          /* tp_clear */
	    0,                                          /* tp_richcompare */
	    0,                                          /* tp_weaklistoffset */
	    0,                                          /* tp_iter */
	    0,                                          /* tp_iternext */
	    P4Message_methods,                          /* tp_methods */
	    0,                                          /* tp_members */
	    0,                                          /* tp_getset */
	    0,                                          /* tp_base */
	    0,                                          /* tp_dict */
	    0,                                          /* tp_descr_get */
	    0,                                          /* tp_descr_set */
	    0,                                          /* tp_dictoffset */
	    (initproc) P4Message_init,                  /* tp_init */
	    0,                                          /* tp_alloc */
	    0,                                          /* tp_new */
};


// ===============
// ==== P4API ====
// ===============

struct P4API_state {
        PyObject * error;
};

#if PY_MAJOR_VERSION >= 3
#define GETSTATE(m) ((struct P4API_state*)PyModule_GetState(m))
#else
#define GETSTATE(m) (&_state)
static struct P4API_state _state;
#endif

static struct PyMethodDef P4API_methods[] = {
    {"identify", (PyCFunction)P4API_identify, METH_NOARGS,
     "Identify module version"},
    {NULL} /* Sentinel */
};

// ===================
// ==== initP4API ====
// ===================

#if PY_MAJOR_VERSION >= 3

static int P4API_traverse(PyObject *m, visitproc visit, void *arg) {
    Py_VISIT(GETSTATE(m)->error);
    return 0;
}

static int P4API_clear(PyObject *m) {
    Py_CLEAR(GETSTATE(m)->error);
    return 0;
}

static struct PyModuleDef P4API_moduledef = {
        PyModuleDef_HEAD_INIT,
        "P4API",
        "P4 Python Adapter Module",
        sizeof(struct P4API_state),
        P4API_methods,
        NULL,
        P4API_traverse,
        P4API_clear,
        NULL
};

#define INITERROR return NULL

PyMODINIT_FUNC
PyInit_P4API(void)

#else 

#define INITERROR return

PyMODINIT_FUNC
initP4API(void)
#endif

{
    if (PyType_Ready(&P4AdapterType) < 0) 
	INITERROR;

#if PY_MAJOR_VERSION >= 3
    PyObject * module = PyModule_Create(&P4API_moduledef);
#else
    PyObject * module = Py_InitModule3("P4API", P4API_methods, "P4 Python Adapter Module");
#endif

    if (module == NULL) INITERROR;

    Py_INCREF(&P4AdapterType);
    PyModule_AddObject(module, "P4Adapter", (PyObject*) &P4AdapterType);
    
    Py_INCREF(&P4MergeDataType);
    PyModule_AddObject(module, "P4MergeData", (PyObject*) &P4MergeDataType);

    Py_INCREF(&P4MapType);
    PyModule_AddObject(module, "P4Map", (PyObject*) &P4MapType);
    
    Py_INCREF(&P4MessageType);
    PyModule_AddObject(module, "P4Message", (PyObject*) &P4MessageType);

    struct P4API_state *st = GETSTATE(module);

    st->error = PyErr_NewException("P4API.Error", NULL, NULL);
    if (st->error == NULL) {
        Py_DECREF(module);
        INITERROR;
    }

    // Get a reference to P4.P4Error
    // Not declared as an exception here because of module inconsistencies
    // Better for the user to have an exception of type P4.P4Error than
    // P4API.P4Error
    
    PyObject * p4Module = PyImport_ImportModule("P4");
    PyObject * p4Dict = PyModule_GetDict(p4Module);
    P4Error = PyDict_GetItemString(p4Dict, "P4Exception");
    if (P4Error) 
    	Py_INCREF(P4Error);
    else {
    	PyErr_SetString(st->error, "Could not find P4.P4Exception." );
    	Py_DECREF(module);
        INITERROR;
    }
    
#if PY_MAJOR_VERSION >= 3
    return module;
#endif
}

# Change User Description Committed
#6 8053 Robert Cowham P4Python 2011.1
#5 8052 Robert Cowham P4Python 2010.2
#4 8051 Robert Cowham P4Python 2010.1
#3 8050 Robert Cowham P4Python 2009.1
#2 6514 Robert Cowham 2008.1 release
#1 6286 Robert Cowham Official release of P4Python 2007.3