swigutil_py.c

来自「linux subdivision ying gai ke yi le ba」· C语言 代码 · 共 1,316 行 · 第 1/3 页

C
1,316
字号
/*
 * swigutil_py.c: utility functions for the SWIG Python bindings
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */


#include <Python.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_portable.h>
#include <apr_thread_proc.h>

#include "svn_string.h"
#include "svn_opt.h"
#include "svn_delta.h"

#if SVN_SWIG_VERSION >= 103024
#if SVN_SWIG_VERSION >= 103025
#include <swiglabels.swg>
#endif
#include <swigrun.swg>
#include <python/pyrun.swg>
#include <runtime.swg>
#endif

#include "swigutil_py.h"



/*** Manage the Global Interpreter Lock ***/

/* If both Python and APR have threads available, we can optimize ourselves
 * by releasing the global interpreter lock when we drop into our SVN calls.
 *
 * In svn_types.i, svn_swig_py_release_py_lock is called before every
 * function, then svn_swig_py_acquire_py_lock is called after every
 * function.  So, if these functions become no-ops, then Python will
 * start to block...
 *
 * The Subversion libraries can be assumed to be thread-safe *only* when
 * APR_HAS_THREAD is 1.  The APR pool allocations aren't thread-safe unless
 * APR_HAS_THREAD is 1.
 */

#if defined(WITH_THREAD) && APR_HAS_THREADS
#define ACQUIRE_PYTHON_LOCK
#endif

#ifdef ACQUIRE_PYTHON_LOCK
static apr_threadkey_t *_saved_thread_key = NULL;
static apr_pool_t *_saved_thread_pool = NULL;
#endif

void svn_swig_py_release_py_lock(void)
{
#ifdef ACQUIRE_PYTHON_LOCK
  PyThreadState *thread_state;

  if (_saved_thread_key == NULL) {

    /* This is ugly.  We call svn_swig_py_release_py_lock before executing any
       subversion function.  Thus it gets called before any call to
       apr_initialize in our script.  This means we have to call
       apr_initialize ourselves, or otherwise we won't be able to
       create our pool. */
    apr_initialize();
    
    /* Obviously, creating a top-level pool for this is pretty stupid. */
    apr_pool_create(&_saved_thread_pool, NULL);
    apr_threadkey_private_create(&_saved_thread_key, NULL, _saved_thread_pool);
  }

  thread_state = PyEval_SaveThread();
  apr_threadkey_private_set(thread_state, _saved_thread_key);
#endif
}

void svn_swig_py_acquire_py_lock(void)
{
#ifdef ACQUIRE_PYTHON_LOCK
  void *val;
  PyThreadState *thread_state;
  apr_threadkey_private_get(&val, _saved_thread_key);
  thread_state = val;
  PyEval_RestoreThread(thread_state);
#endif
}



/*** Custom SubversionException stuffs. ***/

/* Global SubversionException class object. */
static PyObject *SubversionException = NULL;


PyObject *svn_swig_py_exception_type(void)
{
  Py_INCREF(SubversionException);
  return SubversionException;
}

PyObject *svn_swig_py_register_exception(void)
{
  /* If we haven't created our exception class, do so. */
  if (SubversionException == NULL)
    {
      SubversionException = PyErr_NewException
        ((char *)"libsvn._core.SubversionException", NULL, NULL);
    }

  /* Regardless, return the exception class. */
  return svn_swig_py_exception_type();
}

void svn_swig_py_svn_exception(svn_error_t *err)
{ 
  PyObject *exc_ob, *apr_err_ob;

  if (err == NULL)
    return;

  /* Make an integer for the error code. */
  apr_err_ob = PyInt_FromLong(err->apr_err);
  if (apr_err_ob == NULL)
    return;

  /* Instantiate a SubversionException object. */
  exc_ob = PyObject_CallFunction(SubversionException, (char *)"sO", 
                                 err->message, apr_err_ob);
  if (exc_ob == NULL)
    {
      Py_DECREF(apr_err_ob);
      return;
    }

  /* Set the "apr_err" attribute of the exception to our error code. */
  if (PyObject_SetAttrString(exc_ob, (char *)"apr_err", apr_err_ob) == -1)
    {
      Py_DECREF(apr_err_ob);
      Py_DECREF(exc_ob);
      return;
    }

  /* Finished with the apr_err object. */
  Py_DECREF(apr_err_ob);

  /* Set the error state to our exception object. */
  PyErr_SetObject(SubversionException, exc_ob);

  /* Finished with the exc_ob object. */
  Py_DECREF(exc_ob);
}



/*** Helper/Conversion Routines ***/

static PyObject *make_pointer(const char *typename, void *ptr)
{
  /* ### cache the swig_type_info at some point? */
  return SWIG_NewPointerObj(ptr, SWIG_TypeQuery(typename), 0);
}

/* for use by the "O&" format specifier */
static PyObject *make_ob_pool(void *ptr)
{
  return make_pointer("apr_pool_t *", ptr);
}

/* for use by the "O&" format specifier */
static PyObject *make_ob_window(void *ptr)
{
  return make_pointer("svn_txdelta_window_t *", ptr);
}

/* for use by the "O&" format specifier */
static PyObject *make_ob_status(void *ptr)
{
  return make_pointer("svn_wc_status_t *", ptr);
} 

/* for use by the "O&" format specifier */
static PyObject *make_ob_fs_root(void *ptr)
{
  return make_pointer("svn_fs_root_t *", ptr);
} 


static PyObject *convert_hash(apr_hash_t *hash,
                              PyObject * (*converter_func)(void *value,
                                                           void *ctx),
                              void *ctx)
{
    apr_hash_index_t *hi;
    PyObject *dict = PyDict_New();

    if (dict == NULL)
        return NULL;

    for (hi = apr_hash_first(NULL, hash); hi; hi = apr_hash_next(hi)) {
        const void *key;
        void *val;
        PyObject *value;

        apr_hash_this(hi, &key, NULL, &val);
        value = (*converter_func)(val, ctx);
        if (value == NULL) {
            Py_DECREF(dict);
            return NULL;
        }
        /* ### gotta cast this thing cuz Python doesn't use "const" */
        if (PyDict_SetItemString(dict, (char *)key, value) == -1) {
            Py_DECREF(value);
            Py_DECREF(dict);
            return NULL;
        }
        Py_DECREF(value);
    }

    return dict;
}

static PyObject *convert_to_swigtype(void *value, void *ctx)
{
  /* ctx is a 'swig_type_info *' */
  return SWIG_NewPointerObj(value, ctx, 0);
}

static PyObject *convert_svn_string_t(void *value, void *ctx)
{
  /* ctx is unused */

  const svn_string_t *s = value;

  /* ### borrowing from value in the pool. or should we copy? note
     ### that copying is "safest" */

  /* ### gotta cast this thing cuz Python doesn't use "const" */
  return PyBuffer_FromMemory((void *)s->data, s->len);
}

static PyObject *convert_svn_client_commit_item_t(void *value, void *ctx)
{
  PyObject *list;
  PyObject *path, *kind, *url, *rev, *cf_url, *state;
  svn_client_commit_item_t *item = value;

  /* ctx is unused */

  list = PyList_New(6);

  if (item->path)
    path = PyString_FromString(item->path);
  else
    {
      path = Py_None;
      Py_INCREF(Py_None);
    }

  if (item->url)
    url = PyString_FromString(item->url);
  else
    {
      url = Py_None;
      Py_INCREF(Py_None);
    }
        
  if (item->copyfrom_url)
    cf_url = PyString_FromString(item->copyfrom_url);
  else
    {
      cf_url = Py_None;
      Py_INCREF(Py_None);
    }
        
  kind = PyInt_FromLong(item->kind);
  rev = PyInt_FromLong(item->revision);
  state = PyInt_FromLong(item->state_flags);

  if (! (list && path && kind && url && rev && cf_url && state))
    {
      Py_XDECREF(list);
      Py_XDECREF(path);
      Py_XDECREF(kind);
      Py_XDECREF(url);
      Py_XDECREF(rev);
      Py_XDECREF(cf_url);
      Py_XDECREF(state);
      return NULL;
    }

  PyList_SET_ITEM(list, 0, path);
  PyList_SET_ITEM(list, 1, kind);
  PyList_SET_ITEM(list, 2, url);
  PyList_SET_ITEM(list, 3, rev);
  PyList_SET_ITEM(list, 4, cf_url);
  PyList_SET_ITEM(list, 5, state);
  return list;
}

PyObject *svn_swig_py_prophash_to_dict(apr_hash_t *hash)
{
  return convert_hash(hash, convert_svn_string_t, NULL);
}

PyObject *svn_swig_py_convert_hash(apr_hash_t *hash, swig_type_info *type)
{
  return convert_hash(hash, convert_to_swigtype, type);
}

PyObject *svn_swig_py_c_strings_to_list(char **strings)
{
    PyObject *list = PyList_New(0);
    char *s;

    while ((s = *strings++) != NULL) {
        PyObject *ob = PyString_FromString(s);

        if (ob == NULL)
            goto error;
        if (PyList_Append(list, ob) == -1)
            goto error;
    }

    return list;

  error:
    Py_DECREF(list);
    return NULL;
}

const apr_array_header_t *svn_swig_py_strings_to_array(PyObject *source,
                                                       apr_pool_t *pool)
{
    int targlen;
    apr_array_header_t *temp;

    if (!PySequence_Check(source)) {
        PyErr_SetString(PyExc_TypeError, "not a sequence");
        return NULL;
    }
    targlen = PySequence_Length(source);
    temp = apr_array_make(pool, targlen, sizeof(const char *));
    /* APR_ARRAY_IDX doesn't actually increment the array item count
       (like, say, apr_array_push would). */
    temp->nelts = targlen;
    while (targlen--) {
        PyObject *o = PySequence_GetItem(source, targlen);
        if (o == NULL)
            return NULL;
        if (!PyString_Check(o)) {
            Py_DECREF(o);
            PyErr_SetString(PyExc_TypeError, "not a string");
            return NULL;
        }
        APR_ARRAY_IDX(temp, targlen, const char *) = PyString_AS_STRING(o);
        Py_DECREF(o);
    }
    return temp;
}


/*** apr_array_header_t conversions.  To create a new type of
     converter, simply copy-n-paste one of these function and tweak
     the creation of the PyObject *ob.  ***/

PyObject *svn_swig_py_array_to_list(const apr_array_header_t *array)
{
    PyObject *list = PyList_New(array->nelts);
    int i;

    for (i = 0; i < array->nelts; ++i) {
        PyObject *ob = 
          PyString_FromString(APR_ARRAY_IDX(array, i, const char *));
        if (ob == NULL)
          goto error;
        PyList_SET_ITEM(list, i, ob);
    }
    return list;

  error:
    Py_DECREF(list);
    return NULL;
}

PyObject *svn_swig_py_revarray_to_list(const apr_array_header_t *array)
{
    PyObject *list = PyList_New(array->nelts);
    int i;

    for (i = 0; i < array->nelts; ++i) {
        PyObject *ob 
          = PyInt_FromLong(APR_ARRAY_IDX(array, i, svn_revnum_t));
        if (ob == NULL)
          goto error;
        PyList_SET_ITEM(list, i, ob);
    }
    return list;

  error:
    Py_DECREF(list);
    return NULL;
}

static PyObject *
commit_item_array_to_list(const apr_array_header_t *array)
{
    PyObject *list = PyList_New(array->nelts);
    int i;

    for (i = 0; i < array->nelts; ++i) {
        PyObject *ob = convert_svn_client_commit_item_t
          (APR_ARRAY_IDX(array, i, svn_client_commit_item_t *), NULL);
        if (ob == NULL)
          goto error;
        PyList_SET_ITEM(list, i, ob);
    }
    return list;

  error:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?