Robert Ancell added the comment:

I've attached proof-of-concept showing how os.environ would ideally
work. It'll only work in Posix, etc etc.

Reading into it more there are a lot of general issues with environments
and memory allocation which is why I suspect Python doesn't use
putenv... See putenv(3) for details.

Compile with:
gcc -shared -o environmodule.so -g -Wall -I /usr/include/python2.5
environmodule.c

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1159>
__________________________________
#include "Python.h"

#include <stdlib.h>

static PyObject *environ_getenv(PyObject *self, PyObject *args)
{
    char *name, *result;
    
    if(!PyArg_ParseTuple(args, "s", &name))
        return NULL;
    
    result = getenv(name);
    
    if(result == NULL)
        Py_RETURN_NONE;
    else
        return PyString_FromString(result);
}

static PyObject *environ_putenv(PyObject *self, PyObject *args)
{
    int result;
    char *name, *value, *buffer;
    
    if (!PyArg_ParseTuple(args, "ss", &name, &value))
        return NULL;
    
    buffer = malloc(sizeof(char) * (strlen(name) + 1 + strlen(value)));
    sprintf(buffer, "%s=%s", name, value);    
    result = putenv(buffer);
    
    return PyInt_FromLong((long)result);
}


/* Environment iterator */

typedef struct {
    PyObject_HEAD
    int offset;
} environ_EnvironIterObject;

static PyTypeObject environ_EnvironIterType = {
    PyObject_HEAD_INIT(NULL)
        0,                                 /*ob_size*/
        "environ.EnvironIter",             /*tp_name*/
        sizeof(environ_EnvironIterObject)  /*tp_basicsize*/
};

static PyObject *Environ_iternext(PyObject *object)
{
    environ_EnvironIterObject *o = (environ_EnvironIterObject *)object;
    char *value;
    int i;
    
    /* Must count from the start in case the environment has shrunk since the last iteration */
    for(i = 0; i < o->offset && environ[i]; i++)
    value = environ[i];
    o->offset++;
    
    if(value == NULL)
        return NULL;
    else
        return PyString_FromString(value);
}


/* Environment object */

typedef struct {
    PyObject_HEAD
} environ_EnvironObject;

static PyTypeObject environ_EnvironType = {
    PyObject_HEAD_INIT(NULL)
        0,                             /*ob_size*/
        "environ.Environ",             /*tp_name*/
        sizeof(environ_EnvironObject)  /*tp_basicsize*/
};

static PyObject *Environ_getitem(PyObject *self, PyObject *arg)
{
    char *result, *name;
    
    name = PyString_AsString(arg);
    result = getenv(name);
    
    if(result == NULL)
        Py_RETURN_NONE;
    else
        return PyString_FromString(result); /* FIXME: Should split into a 2-tuple */
}

static int Environ_setitem(PyObject *self, PyObject *key, PyObject *v)
{
    int result;
    char *name, *value, *buffer;
    
    name = PyString_AsString(key);
    value = PyString_AsString(v);
    
    /* FIXME: free() the current value if we set it (i.e. getenv() == malloced_value + len(name) + len('=')) */
    
    /* FIXME: We need to remember this malloc so we can free() it later */
    buffer = malloc(sizeof(char) * (strlen(name) + 1 + strlen(value)));
    sprintf(buffer, "%s=%s", name, value);
    result = putenv(buffer);
    
    return 0;
}

static PyMethodDef Environ_methods[] = {
    {NULL}
};

static Py_ssize_t Environ_length(PyObject *mp)
{
    int count;
    for(count = 0; environ[count] != NULL; count++);
    return count;
}

static PyMappingMethods environ_as_mapping = {
	(lenfunc)Environ_length, /*mp_length*/
	(binaryfunc)Environ_getitem, /*mp_subscript*/
	(objobjargproc)Environ_setitem, /*mp_ass_subscript*/
};

static PyObject *Environ_iter(PyObject *object)
{
    /* NOTE: If the environment is changed during iteration it will be safe but unpredictable */
    return environ_EnvironIterType.tp_alloc(&environ_EnvironIterType, 0);
}


/* Module initialisation */

static PyMethodDef environ_methods[] = {
    {"getenv", environ_getenv, METH_VARARGS, ""},
    {"putenv", environ_putenv, METH_VARARGS, ""},
    {NULL}
};

PyMODINIT_FUNC initenviron(void)
{
    PyObject *m, *environ;

    environ_EnvironType.tp_flags = Py_TPFLAGS_DEFAULT;
    environ_EnvironType.tp_doc = "Environment object";
    environ_EnvironType.tp_new = PyType_GenericNew;
    environ_EnvironType.tp_iter = Environ_iter;
    environ_EnvironType.tp_methods = Environ_methods;
    if(PyType_Ready(&environ_EnvironType) < 0)
        return;

    environ_EnvironIterType.tp_flags = Py_TPFLAGS_DEFAULT;
    environ_EnvironIterType.tp_doc = "Environment iterator";
    environ_EnvironIterType.tp_new = PyType_GenericNew;
    environ_EnvironIterType.tp_iternext = Environ_iternext;
    environ_EnvironIterType.tp_as_mapping = &environ_as_mapping;
    if(PyType_Ready(&environ_EnvironIterType) < 0)
        return;

    m = Py_InitModule3("environ",
                       environ_methods,
                       "Module to test potential os.environ replacement");
    
    environ = environ_EnvironType.tp_alloc(&environ_EnvironType, 0);
    PyModule_AddObject(m, "environ", environ);
}
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to