Index: Modules/fcntlmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/fcntlmodule.c,v retrieving revision 2.34 diff -u -r2.34 fcntlmodule.c --- Modules/fcntlmodule.c 3 Mar 2002 02:59:15 -0000 2.34 +++ Modules/fcntlmodule.c 14 May 2002 12:01:52 -0000 @@ -150,6 +150,104 @@ corresponding to the return value of the ioctl call in the C code."; +/* ioctl2(fd, opt, arg) */ + +static PyObject * +fcntl_ioctl2(PyObject *self, PyObject *args) +{ + int fd; + int code; + int ret; + char *str; + int len; + char buf[1024]; + int arg; + PyObject *result, *retcode, *retval, *argp; + + if (!PyArg_ParseTuple(args, "O&iO;ioctl2 requires a file or file " + "descriptor, an integer and a third integer or a string", + conv_descriptor, &fd, &code, &argp)) { + return NULL; + } else { + if (PyString_Check(argp)) { + + if (PyString_AsStringAndSize(argp, &str, &len)) + return NULL; + + if (len > sizeof(buf)) { + PyErr_SetString(PyExc_ValueError, + "ioctl2 string arg too long"); + return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, buf); + Py_END_ALLOW_THREADS + + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + retval = PyString_FromStringAndSize(buf, len); + + if (!retval) + return NULL; + + } else if (PyInt_Check(argp)) { + arg = (int)PyInt_AsLong(argp); + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, arg); + Py_END_ALLOW_THREADS + + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + + } + /* In the arg3==int case, don't return arg3 */ + Py_INCREF(Py_None); + retval = Py_None; + + } else { + PyErr_SetString(PyExc_TypeError, + "need a string or integer for the 3rd arg"); + return NULL; + } + + result = PyTuple_New(2); + if (!result) { + Py_DECREF(retval); + return NULL; + } + retcode = PyInt_FromLong((long)ret); + if (!retcode) { + Py_DECREF(retval); + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, 0, retcode); + PyTuple_SET_ITEM(result, 1, retval); + return result; + } +} + +static char ioctl2_doc [] = +"ioctl2(fd, opt, arg)\n\ +\n\ +Perform the requested operation on file descriptor fd. The operation\n\ +is defined by op and is operating system dependent. Typically these\n\ +codes can be retrieved from the library module IOCTL. The argument arg\n\ +may be an int or a string. Unlike ioctl, this call requires the third\n\ +argument. The return value of this call is a tuple of (return_code, \n\ +return_value). The return_code is an integer corresponding to the return \n\ +value of the ioctl call in the C code. If arg is given as a string, the \n\ +return_value in the tuple is a string of that length, containing the\n\ +resulting value put in the arg buffer by the operating system. If arg is \n\ +an int, return_value will be None.\n\ +The length of the arg string is not allowed to exceed 1024 bytes.\n"; + + /* flock(fd, operation) */ static PyObject * @@ -313,6 +411,7 @@ static PyMethodDef fcntl_methods[] = { {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, + {"ioctl2", fcntl_ioctl2, METH_VARARGS, ioctl2_doc}, {"flock", fcntl_flock, METH_VARARGS, flock_doc}, {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, {NULL, NULL} /* sentinel */ ------ File test_ioctl.py: import unittest from test_support import TestSkipped, run_unittest import os, struct try: import fcntl, termios except ImportError: raise TestSkipped("No fcntl or termios module") if not hasattr(termios,'TIOCGPGRP'): raise TestSkipped("termios module doesn't have TIOCGPGRP") class IoctlTests(unittest.TestCase): def test_ioctl(self): pgrp = os.getpgrp() tty = open("/dev/tty", "r") r = fcntl.ioctl(tty, termios.TIOCGPGRP, " ") self.assertEquals( pgrp, struct.unpack("i",r)[0] ) def test_ioctl2(self): pgrp = os.getpgrp() tty = open("/dev/tty", "r") r = fcntl.ioctl2(tty, termios.TIOCGPGRP, " ") self.assertEquals(r[0], 0) self.assertEquals(pgrp, struct.unpack("i",r[1])[0]) def test_main(): run_unittest(IoctlTests) if __name__ == "__main__": test_main()