From trentm@activestate.com Thu Jun 1 10:17:37 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 02:17:37 -0700 Subject: [Patches] fix Win32 build (add exceptions.c) Message-ID: <20000601021737.A19610@activestate.com> Discussion: The new exceptions.c breaks the Windows build. This patch adds excpetions.c to the python16.dsp project. Guido already +1'd but it has not gone in yet. (Is noone building on Windows?) Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use `patch -p8'): *** /home/trentm/main/contrib/python/dist/src/PCbuild/python16.dsp Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PCbuild/python16.dsp Wed May 31 23:54:20 2000 *************** *** 540,545 **** --- 540,560 ---- # end source file # begin source file + source=..\python\exceptions.c + + !if "$(cfg)" == "python16 - win32 release" + + !elseif "$(cfg)" == "python16 - win32 debug" + + !elseif "$(cfg)" == "python16 - win32 alpha debug" + + !elseif "$(cfg)" == "python16 - win32 alpha release" + + !endif + + # end source file + # begin source file + source=..\objects\fileobject.c !if "$(cfg)" == "python16 - win32 release" -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 10:20:33 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 02:20:33 -0700 Subject: [Patches] fix test_math.py crash on Win32 (no math.rint()) Message-ID: <20000601022033.B19610@activestate.com> Discussion: With the (relatively recent) platform-conditional addition of math.rint to the math module, the associate test in test_math causes 'test_math' to crash on platforms without rint (i.e. Win32). THis patch makes test_math.py tolerant of a platform not having rint. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_math.py Thu Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_math.py Wed May 31 23:54:16 2000 *************** *** 130,139 **** testit('pow(2,-1)', math.pow(2,-1), 0.5) print 'rint' ! testit('rint(0.7)', math.rint(0.7), 1) ! testit('rint(-0.3)', math.rint(-0.3), 0) ! testit('rint(2.5)', math.rint(2.5), 2) ! testit('rint(3.5)', math.rint(3.5), 4) print 'sin' testit('sin(0)', math.sin(0), 0) --- 130,143 ---- testit('pow(2,-1)', math.pow(2,-1), 0.5) print 'rint' ! try: ! testit('rint(0.7)', math.rint(0.7), 1) ! testit('rint(-0.3)', math.rint(-0.3), 0) ! testit('rint(2.5)', math.rint(2.5), 2) ! testit('rint(3.5)', math.rint(3.5), 4) ! except AttributeError: ! # this platform does not have rint, that is fine, skip the test ! pass print 'sin' testit('sin(0)', math.sin(0), 0) -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 10:30:53 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 02:30:53 -0700 Subject: [Patches] fix arraymodule for overflow checking (was: hey, who broke the array module?) In-Reply-To: <20000515140944.B20418@activestate.com> References: <006e01bfbd06$6ba21120$34aab5d4@hagrid> <20000515140944.B20418@activestate.com> Message-ID: <20000601023053.A23428@activestate.com> This is a revival post (i.e. the patch previously got ignored, I have resynced it with CVS and resubmitted). Discussion: The cause: Relatively recent (last month) patches to getargs.c added overflow checking to the PyArg_Parse*() integral formatters thereby restricting 'b' to unsigned char value and 'h','i', and 'l' to signed integral values (i.e. if the incoming value is outside of the specified bounds you get an OverflowError, previous it silently overflowed). The problem: This broke the array module (as Fredrik pointed out) because *its* formatters relied on the loose allowance of signed and unsigned ranges being able to pass through PyArg_Parse*()'s formatters. The fix: This patch fixes the array module to work with the more strict bounds checking now in PyArg_Parse*(). How: If the type signature of a formatter in the arraymodule exactly matches one in PyArg_Parse*(), then use that directly. If there is no equivalent type signature in PyArg_Parse*() (e.g. there is no unsigned int formatter in PyArg_Parse*()), then use the next one up and do some extra bounds checking in the array module. Testing: test_array.py was also extended to check that one can set the full range of values for each of the integral signed and unsigned array types. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c Wed May 31 23:54:17 2000 *************** *** 114,124 **** int i; PyObject *v; { ! char x; ! if (!PyArg_Parse(v, "b;array item must be integer", &x)) return -1; if (i >= 0) ! ((char *)ap->ob_item)[i] = x; return 0; } --- 114,137 ---- int i; PyObject *v; { ! short x; ! /* PyArg_Parse's 'b' formatter is for an unsigned char, therefore ! must use the next size up that is signed ('h') and manually do ! the overflow checking */ ! if (!PyArg_Parse(v, "h;array item must be integer", &x)) ! return -1; ! else if (x < CHAR_MIN) { ! PyErr_SetString(PyExc_OverflowError, ! "signed char is less than minimum"); ! return -1; ! } ! else if (x > CHAR_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "signed char is greater than maximum"); return -1; + } if (i >= 0) ! ((char *)ap->ob_item)[i] = (char)x; return 0; } *************** *** 131,137 **** return PyInt_FromLong(x); } ! #define BB_setitem b_setitem static PyObject * h_getitem(ap, i) --- 144,163 ---- return PyInt_FromLong(x); } ! static int ! BB_setitem(ap, i, v) ! arrayobject *ap; ! int i; ! PyObject *v; ! { ! unsigned char x; ! /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ ! if (!PyArg_Parse(v, "b;array item must be integer", &x)) ! return -1; ! if (i >= 0) ! ((char *)ap->ob_item)[i] = x; ! return 0; ! } static PyObject * h_getitem(ap, i) *************** *** 148,153 **** --- 174,180 ---- PyObject *v; { short x; + /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ if (!PyArg_Parse(v, "h;array item must be integer", &x)) return -1; if (i >= 0) *************** *** 163,169 **** return PyInt_FromLong((long) ((unsigned short *)ap->ob_item)[i]); } ! #define HH_setitem h_setitem static PyObject * i_getitem(ap, i) --- 190,220 ---- return PyInt_FromLong((long) ((unsigned short *)ap->ob_item)[i]); } ! static int ! HH_setitem(ap, i, v) ! arrayobject *ap; ! int i; ! PyObject *v; ! { ! int x; ! /* PyArg_Parse's 'h' formatter is for a signed short, therefore ! must use the next size up and manually do the overflow checking */ ! if (!PyArg_Parse(v, "i;array item must be integer", &x)) ! return -1; ! else if (x < 0) { ! PyErr_SetString(PyExc_OverflowError, ! "unsigned short is less than minimum"); ! return -1; ! } ! else if (x > USHRT_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "unsigned short is greater than maximum"); ! return -1; ! } ! if (i >= 0) ! ((short *)ap->ob_item)[i] = (short)x; ! return 0; ! } static PyObject * i_getitem(ap, i) *************** *** 180,185 **** --- 231,237 ---- PyObject *v; { int x; + /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ if (!PyArg_Parse(v, "i;array item must be integer", &x)) return -1; if (i >= 0) *************** *** 209,219 **** return -1; } else { ! if (!PyArg_Parse(v, "l;array item must be integer", &x)) return -1; } if (i >= 0) ! ((unsigned int *)ap->ob_item)[i] = x; return 0; } --- 261,285 ---- return -1; } else { ! long y; ! if (!PyArg_Parse(v, "l;array item must be integer", &y)) return -1; + if (y < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is less than minimum"); + return -1; + } + x = (unsigned long)y; + + } + if (x > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is greater than maximum"); + return -1; } + if (i >= 0) ! ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; return 0; } *************** *** 260,268 **** return -1; } else { ! if (!PyArg_Parse(v, "l;array item must be integer", &x)) return -1; } if (i >= 0) ((unsigned long *)ap->ob_item)[i] = x; return 0; --- 326,348 ---- return -1; } else { ! long y; ! if (!PyArg_Parse(v, "l;array item must be integer", &y)) ! return -1; ! if (y < 0) { ! PyErr_SetString(PyExc_OverflowError, ! "unsigned long is less than minimum"); return -1; + } + x = (unsigned long)y; + + } + if (x > ULONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned long is greater than maximum"); + return -1; } + if (i >= 0) ((unsigned long *)ap->ob_item)[i] = x; return 0; *************** *** 721,728 **** arrayobject *self; PyObject *args; { ! return Py_BuildValue("ll", ! (long)(self->ob_item), (long)(self->ob_size)); } static char buffer_info_doc [] = --- 801,813 ---- arrayobject *self; PyObject *args; { ! PyObject* retval = PyTuple_New(2); ! if (!retval) return NULL; ! ! PyTuple_SET_ITEM(retval, 0, PyLong_FromVoidPtr(self->ob_item)); ! PyTuple_SET_ITEM(retval, 1, PyInt_FromLong((long)(self->ob_size))); ! ! return retval; } static char buffer_info_doc [] = *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_array.py Thu Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_array.py Wed May 31 23:54:16 2000 *************** *** 15,20 **** --- 15,58 ---- unlink(TESTFN) + def testoverflow(type, lowerLimit, upperLimit): + # should not overflow assigning lower limit + if verbose: + print "overflow test: array(%s, [%s])" % (`type`, `lowerLimit`) + try: + a = array.array(type, [lowerLimit]) + except: + raise TestFailed, "array(%s) overflowed assigning %s" %\ + (`type`, `lowerLimit`) + # should overflow assigning less than lower limit + if verbose: + print "overflow test: array(%s, [%s])" % (`type`, `lowerLimit-1`) + try: + a = array.array(type, [lowerLimit-1]) + raise TestFailed, "array(%s) did not overflow assigning %s" %\ + (`type`, `lowerLimit-1`) + except OverflowError: + pass + # should not overflow assigning upper limit + if verbose: + print "overflow test: array(%s, [%s])" % (`type`, `upperLimit`) + try: + a = array.array(type, [upperLimit]) + except: + raise TestFailed, "array(%s) overflowed assigning %s" %\ + (`type`, `upperLimit`) + # should overflow assigning more than upper limit + if verbose: + print "overflow test: array(%s, [%s])" % (`type`, `upperLimit+1`) + try: + a = array.array(type, [upperLimit+1]) + raise TestFailed, "array(%s) did not overflow assigning %s" %\ + (`type`, `upperLimit+1`) + except OverflowError: + pass + + + def testtype(type, example): a = array.array(type) *************** *** 81,86 **** if a != array.array(type, [1, 1, 2, 3, 4, 5, 5]): raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` ! main() ! --- 119,138 ---- if a != array.array(type, [1, 1, 2, 3, 4, 5, 5]): raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` ! # test that overflow exceptions are raised as expected for assignment ! # to array of specific integral types ! from math import pow ! if type in ('b', 'h', 'i', 'l'): ! # check signed and unsigned versions ! a = array.array(type) ! signedLowerLimit = -1 * long(pow(2, a.itemsize * 8 - 1)) ! signedUpperLimit = long(pow(2, a.itemsize * 8 - 1)) - 1L ! unsignedLowerLimit = 0 ! unsignedUpperLimit = long(pow(2, a.itemsize * 8)) - 1L ! testoverflow(type, signedLowerLimit, signedUpperLimit) ! testoverflow(type.upper(), unsignedLowerLimit, unsignedUpperLimit) ! ! ! main() ! -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 10:34:28 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 02:34:28 -0700 Subject: [Patches] Fix for bug PR#341 In-Reply-To: <20000530113910.H18024@activestate.com> References: <392FEED2.90E262CB@lemburg.com> <200005301513.KAA06165@cj20424-a.reston1.va.home.com> <20000530113910.H18024@activestate.com> Message-ID: <20000601023428.B23428@activestate.com> Discussion: This patch fixes the string formatting overflow problem. It tries to do a little better than MAL's magic nunumber (50) check. If this looks good then I can do the same for unicodeobject.c [Tim P on MAL's original patch] > but I'll join Fred in objecting to the code > it's mimicking: not only do magic numbers suck, but these particular magic > numbers implicitly rely on PyString_Format's tmpbuf vector being declared of > another magical size larger than them. As usual, flaky code gets flakier. My patch still uses the magic number for the temporary buffer. This seems to me a good practical limit. With the patch this buffer can no longer overflow (as well, it is faster than malloc'ing a perfect sized buffer every time). [MAL] > A redesign would, of course, use a malloced buffer, the n-variants > of printf() and add long support ;-) ... maybe for 1.7. No long support in this patch :( [Guido on MAL's original patch] > Having read the patch and the discussion about magic numbers, I agree > with Marc-Andre: let's apply the quick fix now, worry about > correctness later. Maybe this patch is preferable. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Objects/stringobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/stringobject.c Wed May 31 23:54:19 2000 *************** *** 237,245 **** string_repr(op) register PyStringObject *op; { ! /* XXX overflow? */ ! int newsize = 2 + 4 * op->ob_size * sizeof(char); ! PyObject *v = PyString_FromStringAndSize((char *)NULL, newsize); if (v == NULL) { return NULL; } --- 242,254 ---- string_repr(op) register PyStringObject *op; { ! size_t newsize = 2 + 4 * op->ob_size * sizeof(char); ! PyObject *v; ! if (newsize > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "string is too large to make repr"); ! } ! v = PyString_FromStringAndSize((char *)NULL, newsize); if (v == NULL) { return NULL; } *************** *** 2317,2352 **** #define F_ZERO (1<<4) static int ! formatfloat(buf, flags, prec, type, v) char *buf; int flags; int prec; int type; PyObject *v; { char fmt[20]; double x; if (!PyArg_Parse(v, "d;float argument required", &x)) return -1; if (prec < 0) prec = 6; - if (prec > 50) - prec = 50; /* Arbitrary limitation */ if (type == 'f' && fabs(x)/1e25 >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type); sprintf(buf, fmt, x); return strlen(buf); } static int ! formatint(buf, flags, prec, type, v) char *buf; int flags; int prec; int type; PyObject *v; { char fmt[20]; long x; if (!PyArg_Parse(v, "l;int argument required", &x)) --- 2326,2377 ---- #define F_ZERO (1<<4) static int ! formatfloat(buf, buflen, flags, prec, type, v) char *buf; + size_t buflen; int flags; int prec; int type; PyObject *v; { + /* fmt = '%#.' + `prec` + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ char fmt[20]; double x; if (!PyArg_Parse(v, "d;float argument required", &x)) return -1; if (prec < 0) prec = 6; if (type == 'f' && fabs(x)/1e25 >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type); + /* worst case length calc to ensure no buffer overrun: + fmt = %#.g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase by one to 10+prec. */ + if (buflen <= (size_t)10 + (size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted float is too long (precision too long?)"); + return -1; + } sprintf(buf, fmt, x); return strlen(buf); } static int ! formatint(buf, buflen, flags, prec, type, v) char *buf; + size_t buflen; int flags; int prec; int type; PyObject *v; { + /* fmt = '%#.' + `prec` + 'l' + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/ char fmt[20]; long x; if (!PyArg_Parse(v, "l;int argument required", &x)) *************** *** 2354,2368 **** if (prec < 0) prec = 1; sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type); sprintf(buf, fmt, x); return strlen(buf); } static int ! formatchar(buf, v) char *buf; PyObject *v; { if (PyString_Check(v)) { if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) return -1; --- 2379,2402 ---- if (prec < 0) prec = 1; sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type); + /* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal)) + worst case buf = '0x' + [0-9]*prec, where prec >= 11 */ + if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted integer is too long (precision too long?)"); + return -1; + } sprintf(buf, fmt, x); return strlen(buf); } static int ! formatchar(buf, buflen, v) char *buf; + size_t buflen; PyObject *v; { + /* presume that the buffer is at least 2 characters long */ if (PyString_Check(v)) { if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) return -1; *************** *** 2436,2442 **** char *buf; int sign; int len; ! char tmpbuf[120]; /* For format{float,int,char}() */ char *fmt_start = fmt; fmt++; --- 2470,2477 ---- char *buf; int sign; int len; ! #define TMPBUFLEN (size_t)120 ! char tmpbuf[TMPBUFLEN]; /* For format{float,int,char}() */ char *fmt_start = fmt; fmt++; *************** *** 2618,2624 **** if (c == 'i') c = 'd'; buf = tmpbuf; ! len = formatint(buf, flags, prec, c, v); if (len < 0) goto error; sign = (c == 'd'); --- 2653,2659 ---- if (c == 'i') c = 'd'; buf = tmpbuf; ! len = formatint(buf, TMPBUFLEN, flags, prec, c, v); if (len < 0) goto error; sign = (c == 'd'); *************** *** 2643,2649 **** case 'g': case 'G': buf = tmpbuf; ! len = formatfloat(buf, flags, prec, c, v); if (len < 0) goto error; sign = 1; --- 2678,2684 ---- case 'g': case 'G': buf = tmpbuf; ! len = formatfloat(buf, TMPBUFLEN, flags, prec, c, v); if (len < 0) goto error; sign = 1; *************** *** 2652,2658 **** break; case 'c': buf = tmpbuf; ! len = formatchar(buf, v); if (len < 0) goto error; break; --- 2687,2693 ---- break; case 'c': buf = tmpbuf; ! len = formatchar(buf, TMPBUFLEN, v); if (len < 0) goto error; break; -- Trent Mick trentm@activestate.com From trentm@ActiveState.com Thu Jun 1 10:43:59 2000 From: trentm@ActiveState.com (Trent Mick) Date: Thu, 1 Jun 2000 02:43:59 -0700 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <20000511215433.A31196@activestate.com> References: <20000510131446.A25926@activestate.com> <000b01bfbaff$43d320c0$2aa0143f@tim> <20000511215433.A31196@activestate.com> Message-ID: <20000601024359.C23428@activestate.com> This is a revival post. Tim, Guido, we had discussed this a while ago and I think that my patch was acceptible to you both. Actually I believe that you both said "I'm cowardly awaiting a patch submission that Tim approves of". [Tim said] > ... looks good! The simplification makes up for the extra cost > of the function call, too . Albeit that was refering to the _Py_HashDouble algorithm and not necessaril;y the whole patch. :) Discussion: This patch addresses two main issues: (1) There exist some non-fatal errors in some of the hash algorithms. For exmaple, in float_hash and complex_hash a certain part of the value is not included in the hash calculation. See Tim's, Guido's, and my discussion of this on python-dev in May under the title "fix float_hash and complex_hash for 64-bit *nix" (2) The hash algorithms that use pointers (e.g. func_hash, code_hash) are universally not correct on Win64 (they assume that sizeof(long) == sizeof(void*)) As well, this patch significantly cleans up the hash code. It adds the two function _Py_HashDouble and _PyHash_VoidPtr that the various hashing routine are changed to use. These help maintain the hash function invariant: (a==b) => (hash(a)==hash(b))) I have added Lib/test/test_hash.py and Lib/test/output/test_hash to test this for some cases. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Include/object.h Thu Jun 1 00:13:37 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Include/object.h Wed May 31 23:54:13 2000 *************** *** 287,292 **** --- 287,296 ---- /* tstate dict key for PyObject_Compare helper */ extern PyObject *_PyCompareState_Key; + /* Helpers for hash functions */ + extern DL_IMPORT(long) _Py_HashDouble Py_PROTO((double)); + extern DL_IMPORT(long) _Py_HashPointer Py_PROTO((void*)); + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/object.c Wed May 31 23:54:19 2000 *************** *** 33,38 **** --- 33,40 ---- #include "Python.h" + #include "mymath.h" + /* just for trashcan: */ #include "compile.h" #include "frameobject.h" *************** *** 506,511 **** --- 508,569 ---- return result; } + + /* Set of hash utility functions to help maintaining the invariant that + iff a==b then hash(a)==hash(b) + + All the utility functions (_Py_Hash*()) return "-1" to signify an error. + */ + + long + _Py_HashDouble(v) + double v; + { + /* Use frexp to get at the bits in the double. + * Since the VAX D double format has 56 mantissa bits, which is the + * most of any double format in use, each of these parts may have as + * many as (but no more than) 56 significant bits. + * So, assuming sizeof(long) >= 4, each part can be broken into two longs; + * frexp and multiplication are used to do that. + * Also, since the Cray double format has 15 exponent bits, which is the + * most of any double format in use, shifting the exponent field left by + * 15 won't overflow a long (again assuming sizeof(long) >= 4). + */ + int expo; + long hipart; + + v = frexp(v, &expo); + v = v * 2147483648.0; /* 2**31 */ + hipart = (long)v; /* Take the top 32 bits */ + v = (v - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ + + return hipart + (long)v + (expo << 15); /* Combine everything */ + } + + long + _Py_HashPointer(p) + void *p; + { + #if SIZEOF_LONG >= SIZEOF_VOID_P + return (long)p; + #else + /* convert to a Python long and hash that */ + PyObject* longobj; + long x; + + if ((longobj = PyLong_FromVoidPtr(p)) == NULL) { + x = -1; + goto finally; + } + x = PyObject_Hash(longobj); + + finally: + Py_XDECREF(longobj); + return x; + #endif + } + + long PyObject_Hash(v) PyObject *v; *************** *** 513,520 **** PyTypeObject *tp = v->ob_type; if (tp->tp_hash != NULL) return (*tp->tp_hash)(v); ! if (tp->tp_compare == NULL) ! return (long) v; /* Use address as hash value */ /* If there's a cmp but no hash defined, the object can't be hashed */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; --- 571,579 ---- PyTypeObject *tp = v->ob_type; if (tp->tp_hash != NULL) return (*tp->tp_hash)(v); ! if (tp->tp_compare == NULL) { ! return _Py_HashPointer(v); /* Use address as hash value */ ! } /* If there's a cmp but no hash defined, the object can't be hashed */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/floatobject.c Wed May 31 23:54:19 2000 *************** *** 59,65 **** --- 59,71 ---- #endif #ifndef LONG_MAX + #if SIZEOF_LONG == 4 #define LONG_MAX 0X7FFFFFFFL + #elif SIZEOF_LONG == 8 + #define LONG_MAX 0X7FFFFFFFFFFFFFFFL + #else + #error "could not set LONG_MAX" + #endif #endif #ifndef LONG_MIN *************** *** 357,368 **** return (i < j) ? -1 : (i > j) ? 1 : 0; } static long float_hash(v) PyFloatObject *v; { double intpart, fractpart; - int expo; long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons --- 363,374 ---- return (i < j) ? -1 : (i > j) ? 1 : 0; } + static long float_hash(v) PyFloatObject *v; { double intpart, fractpart; long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons *************** *** 379,385 **** #endif if (fractpart == 0.0) { ! if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->ob_fval); if (w == NULL) --- 385,391 ---- #endif if (fractpart == 0.0) { ! if (intpart > LONG_MAX || -intpart > LONG_MAX) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->ob_fval); if (w == NULL) *************** *** 393,406 **** else { /* Note -- if you change this code, also change the copy in complexobject.c */ ! long hipart; ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x = hipart + (long)fractpart + (long)intpart + (expo << 15); ! /* Combine everything */ } if (x == -1) x = -2; --- 399,407 ---- else { /* Note -- if you change this code, also change the copy in complexobject.c */ ! x = _Py_HashDouble(v->ob_fval); ! if (x == -1) ! return -1; } if (x == -1) x = -2; *** /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/complexobject.c Wed May 31 23:54:19 2000 *************** *** 285,292 **** PyComplexObject *v; { double intpart, fractpart; ! int expo; ! long hipart, x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ --- 285,291 ---- PyComplexObject *v; { double intpart, fractpart; ! long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ *************** *** 302,308 **** #endif if (fractpart == 0.0 && v->cval.imag == 0.0) { ! if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->cval.real); if (w == NULL) --- 301,307 ---- #endif if (fractpart == 0.0 && v->cval.imag == 0.0) { ! if (intpart > LONG_MAX || -intpart > LONG_MAX) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->cval.real); if (w == NULL) *************** *** 314,349 **** x = (long)intpart; } else { ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x = hipart + (long)fractpart + (long)intpart + (expo << 15); ! /* Combine everything */ if (v->cval.imag != 0.0) { /* Hash the imaginary part */ /* XXX Note that this hashes complex(x, y) to the same value as complex(y, x). Still better than it used to be :-) */ ! #ifdef MPW ! { ! extended e; ! fractpart = modf(v->cval.imag, &e); ! intpart = e; ! } ! #else ! fractpart = modf(v->cval.imag, &intpart); ! #endif ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = ! (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x ^= hipart + (long)fractpart + ! (long)intpart + (expo << 15); ! /* Combine everything */ } } if (x == -1) --- 313,330 ---- x = (long)intpart; } else { ! x = _Py_HashDouble(v->cval.real); ! if (x == -1) ! return -1; if (v->cval.imag != 0.0) { /* Hash the imaginary part */ /* XXX Note that this hashes complex(x, y) to the same value as complex(y, x). Still better than it used to be :-) */ ! long y = _Py_HashDouble(v->cval.imag); ! if (y == -1) ! return -1; ! x += y; } } if (x == -1) *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/classobject.c Wed May 31 23:54:19 2000 *************** *** 823,832 **** func = instance_getattr(inst, cmpstr); if (func == NULL) { PyErr_Clear(); ! outcome = (long)inst; ! if (outcome == -1) ! outcome = -2; ! return outcome; } PyErr_SetString(PyExc_TypeError, "unhashable instance"); return -1; --- 823,829 ---- func = instance_getattr(inst, cmpstr); if (func == NULL) { PyErr_Clear(); ! return _Py_HashPointer(inst); } PyErr_SetString(PyExc_TypeError, "unhashable instance"); return -1; *** /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/funcobject.c Wed May 31 23:54:19 2000 *************** *** 231,240 **** func_hash(f) PyFunctionObject *f; { ! long h; h = PyObject_Hash(f->func_code); if (h == -1) return h; ! h = h ^ (long)f->func_globals; if (h == -1) h = -2; return h; } --- 231,242 ---- func_hash(f) PyFunctionObject *f; { ! long h,x; h = PyObject_Hash(f->func_code); if (h == -1) return h; ! x = _Py_HashPointer(f->func_globals); ! if (x == -1) return x; ! h ^= x; if (h == -1) h = -2; return h; } *** /home/trentm/main/contrib/python/dist/src/PC/winreg.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/winreg.c Wed May 31 23:54:20 2000 *************** *** 421,427 **** /* Just use the address. XXX - should we use the handle value? */ ! return (long)ob; } --- 421,427 ---- /* Just use the address. XXX - should we use the handle value? */ ! return _Py_HashPointer(ob); } *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_hash.py Thu Jun 1 00:40:23 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_hash.py Wed May 31 23:54:16 2000 *************** *** 0 **** --- 1,26 ---- + # test the invariant that + # iff a==b then hash(a)==hash(b) + # + + import test_support + + + def same_hash(*objlist): + # hash each object given an raise TestFailed if + # the hash values are not all the same + hashed = map(hash, objlist) + for h in hashed[1:]: + if h != hashed[0]: + raise TestFailed, "hashed values differ: %s" % `objlist` + + + + same_hash(1, 1L, 1.0, 1.0+0.0j) + same_hash(int(1), long(1), float(1), complex(1)) + + same_hash(long(1.23e300), float(1.23e300)) + + same_hash(float(0.5), complex(0.5, 0.0)) + + + *** /home/trentm/main/contrib/python/dist/src/Lib/test/output/test_hash Thu Jun 1 00:40:23 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/output/test_hash Wed May 31 23:54:16 2000 *************** *** 0 **** --- 1 ---- + test_hash -- Trent Mick trentm@activestate.com From Moshe Zadka Thu Jun 1 10:50:32 2000 From: Moshe Zadka (Moshe Zadka) Date: Thu, 1 Jun 2000 12:50:32 +0300 (IDT) Subject: [Patches] fix test_math.py crash on Win32 (no math.rint()) In-Reply-To: <20000601022033.B19610@activestate.com> Message-ID: On Thu, 1 Jun 2000, Trent Mick wrote: > Discussion: > > With the (relatively recent) platform-conditional addition of math.rint to the > math module, the associate test in test_math causes 'test_math' to crash on > platforms without rint (i.e. Win32). THis patch makes test_math.py tolerant of > a platform not having rint. +1 on the purpose, -0 on the implementation: why not have a try: math.rint except AttributeError: pass else: ....tests with math.rint.... Since I'm extremely paranoid person, I'm afraid this will mask true AttributeError's in math.rint (it can happen in a sufficiently twisted world.) -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From fdrake@acm.org Thu Jun 1 15:09:15 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Thu, 1 Jun 2000 10:09:15 -0400 (EDT) Subject: [Patches] fix Win32 build (add exceptions.c) In-Reply-To: <20000601021737.A19610@activestate.com> References: <20000601021737.A19610@activestate.com> Message-ID: <14646.28299.533556.784379@cj42289-a.reston1.va.home.com> Trent Mick writes: > The new exceptions.c breaks the Windows build. This patch adds excpetions.c > to the python16.dsp project. Guido already +1'd but it has not gone in yet. > (Is noone building on Windows?) I've set up a Windows build environment, but don't have the CVS and SSH software properly connected yet. I'll try and get to this today, since I've been meaning to get these build adjustements checked in. Thanks for the reminder! -Fred -- Fred L. Drake, Jr. PythonLabs at BeOpen.com From fdrake@acm.org Thu Jun 1 15:12:23 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Thu, 1 Jun 2000 10:12:23 -0400 (EDT) Subject: [Patches] fix test_math.py crash on Win32 (no math.rint()) In-Reply-To: References: <20000601022033.B19610@activestate.com> Message-ID: <14646.28487.910777.855196@cj42289-a.reston1.va.home.com> Moshe Zadka writes: > +1 on the purpose, -0 on the implementation: > > why not have a > > > try: > math.rint > except AttributeError: > pass > else: > ....tests with math.rint.... This is the appropriate way to make this test; Trent, can you post an updated patch? Thanks. > Since I'm extremely paranoid person, I'm afraid this will mask true > AttributeError's in math.rint (it can happen in a sufficiently twisted world.) That would be a *really* twisted world! -Fred -- Fred L. Drake, Jr. PythonLabs at BeOpen.com From trentm@activestate.com Thu Jun 1 18:51:25 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 10:51:25 -0700 Subject: [Patches] fix test_math.py crash on Win32 (no math.rint()) In-Reply-To: <14646.28487.910777.855196@cj42289-a.reston1.va.home.com> References: <20000601022033.B19610@activestate.com> <14646.28487.910777.855196@cj42289-a.reston1.va.home.com> Message-ID: <20000601105125.D24708@activestate.com> On Thu, Jun 01, 2000 at 10:12:23AM -0400, Fred L. Drake, Jr. wrote: > > Moshe Zadka writes: > > +1 on the purpose, -0 on the implementation: > > > > why not have a > > > > > > try: > > math.rint > > except AttributeError: > > pass > > else: > > ....tests with math.rint.... > > This is the appropriate way to make this test; Trent, can you post > an updated patch? Thanks. > Yes, you guys are right. Here is the new patch Discussion: With the (relatively recent) platform-conditional addition of math.rint to the math module, the associate test in test_math causes 'test_math' to crash on platforms without rint (i.e. Win32). THis patch makes test_math.py tolerant of a platform not having rint. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_math.py Thu Jun 1 10:39:07 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_math.py Thu Jun 1 10:38:40 2000 *************** *** 130,139 **** testit('pow(2,-1)', math.pow(2,-1), 0.5) print 'rint' ! testit('rint(0.7)', math.rint(0.7), 1) ! testit('rint(-0.3)', math.rint(-0.3), 0) ! testit('rint(2.5)', math.rint(2.5), 2) ! testit('rint(3.5)', math.rint(3.5), 4) print 'sin' testit('sin(0)', math.sin(0), 0) --- 130,145 ---- testit('pow(2,-1)', math.pow(2,-1), 0.5) print 'rint' ! try: ! math.rint ! except AttributeError: ! # this platform does not have rint, that is fine, skip the test ! pass ! else: ! testit('rint(0.7)', math.rint(0.7), 1) ! testit('rint(-0.3)', math.rint(-0.3), 0) ! testit('rint(2.5)', math.rint(2.5), 2) ! testit('rint(3.5)', math.rint(3.5), 4) print 'sin' testit('sin(0)', math.sin(0), 0) -- Trent Mick trentm@activestate.com From fdrake@acm.org Thu Jun 1 18:59:32 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Thu, 1 Jun 2000 13:59:32 -0400 (EDT) Subject: [Patches] fix test_math.py crash on Win32 (no math.rint()) In-Reply-To: <20000601105125.D24708@activestate.com> References: <20000601022033.B19610@activestate.com> <14646.28487.910777.855196@cj42289-a.reston1.va.home.com> <20000601105125.D24708@activestate.com> Message-ID: <14646.42116.771315.348595@cj42289-a.reston1.va.home.com> Trent Mick writes: > Yes, you guys are right. Here is the new patch Trent, Thanks, I've checked it in. -Fred -- Fred L. Drake, Jr. PythonLabs at BeOpen.com From trentm@ActiveState.com Thu Jun 1 19:09:57 2000 From: trentm@ActiveState.com (Trent Mick) Date: Thu, 1 Jun 2000 11:09:57 -0700 Subject: [Patches] Re: bug in PyLong_FromLongLong (PR#324) In-Reply-To: <20000511145241.A15936@activestate.com> References: <200005111323.JAA00637@eric.cnri.reston.va.us> <20000511145241.A15936@activestate.com> Message-ID: <20000601110956.A24915@activestate.com> This is a revival post. Guido, you asked me to submit a patch for this a while back and I did, but the patch got lost in the fun of recent times. Here it is again. Discussion: This patch fixes bug PR#324. [Thomas Malik] > there's a bug in PyLong_FromLongLong, resulting in truncation of negative 64 bi > t > integers. PyLong_FromLongLong starts with: > if( ival <= (LONG_LONG)LONG_MAX ) { > return PyLong_FromLong( (long)ival ); > } > else if( ival <= (unsigned LONG_LONG)ULONG_MAX ) { > return PyLong_FromUnsignedLong( (unsigned long)ival ); > } > else { > .... > > Now, if ival is smaller than -LONG_MAX, it falls outside the long integer range > (being a 64 bit negative integer), but gets handled by the first if-then-case i > n > above code ('cause it is, of course, smaller than LONG_MAX). This results in > truncation of the 64 bit negative integer to a more or less arbitrary 32 bit > number. The way to fix it is to compare the absolute value of imax against > LONG_MAX in the first condition. The second condition (ULONG_MAX) must, at > least, check wether ival is positive. This patch correct bounds checking in PyLong_FromLongLong. Currently, it does not check properly for negative values when checking to see if the incoming value fits in a long or unsigned long. This results in possible silent truncation of the value for very large negative values. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Objects/longobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/longobject.c Wed May 31 23:54:19 2000 *************** *** 355,364 **** /* In case the compiler is faking it. */ return PyLong_FromLong( (long)ival ); #else ! if( ival <= (LONG_LONG)LONG_MAX ) { return PyLong_FromLong( (long)ival ); } ! else if( ival <= (unsigned LONG_LONG)ULONG_MAX ) { return PyLong_FromUnsignedLong( (unsigned long)ival ); } else { --- 355,364 ---- /* In case the compiler is faking it. */ return PyLong_FromLong( (long)ival ); #else ! if ((LONG_LONG)LONG_MIN <= ival && ival <= (LONG_LONG)LONG_MAX) { return PyLong_FromLong( (long)ival ); } ! else if (0 <= ival && ival <= (unsigned LONG_LONG)ULONG_MAX) { return PyLong_FromUnsignedLong( (unsigned long)ival ); } else { -- Trent Mick trentm@activestate.com From fdrake@acm.org Thu Jun 1 19:30:05 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Thu, 1 Jun 2000 14:30:05 -0400 (EDT) Subject: [Patches] Re: bug in PyLong_FromLongLong (PR#324) In-Reply-To: <20000601110956.A24915@activestate.com> References: <200005111323.JAA00637@eric.cnri.reston.va.us> <20000511145241.A15936@activestate.com> <20000601110956.A24915@activestate.com> Message-ID: <14646.43949.727144.434058@cj42289-a.reston1.va.home.com> Trent Mick writes: > This is a revival post. Guido, you asked me to submit a patch for this a > while back and I did, but the patch got lost in the fun of recent times. Here > it is again. I'll have it in once the test suite has completed; thanks! -Fred -- Fred L. Drake, Jr. PythonLabs at BeOpen.com From trentm@activestate.com Thu Jun 1 20:35:22 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 12:35:22 -0700 Subject: [Patches] simple compiler warning fix (export _PyImport_Fini) Message-ID: <20000601123522.A9463@activestate.com> Discussion: This patch cleans up a compilation warning. _PyImport_Fini() is meant to be exported by import.c but is not mentioned in Include/import.h (_PyImport_Init *is* mentioned there). It is called in Python/pythonrun.c. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Include/import.h Thu Jun 1 00:13:37 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Include/import.h Wed May 31 23:54:13 2000 *************** *** 53,58 **** --- 53,59 ---- extern DL_IMPORT(PyObject *)_PyImport_FindExtension Py_PROTO((char *, char *)); extern DL_IMPORT(PyObject *)_PyImport_FixupExtension Py_PROTO((char *, char *)); + extern DL_IMPORT(void) _PyImport_Fini Py_PROTO((void)); struct _inittab { char *name; -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 21:14:12 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 13:14:12 -0700 Subject: [Patches] changes to configure.in and PC/config.h for 64-bit systems Message-ID: <20000601131412.B9463@activestate.com> Discussion: This patch extends PC/config.h and configure.in as appropriate for 64-bit readiness (the config values are needed for patches that I will be submitting later today. The changes are as follows: - add SIZEOF_OFF_T #define's to PC/config.h (it was already in configure.in) - add SIZEOF_TIME_T #define to PC/config.h and configure Needed for some buffer overflow checking because sizeof(time_t) is different on Win64. - add SIZEOF_FPOS_T #define Needed for the Win64 large file support implementation. - add SIZEOF_HKEY in PC/config.h only Needed for proper Win32 vs. Win64 handling in PC/winreg.c - #define HAVE_LARGEFILE_SUPPORT for Win64 - typedef long intptr_t; for all Windows except Win64 (which defines it itself) This is a new ANSI (I think) type that is useful (and used by me) for proper handling in msvcrtmodule.c and posixmodule.c - indent the nested #ifdef's and #defines in PC/config.h This is *so* much more readable. There cannot be a compiler compatibilty issue here can there? Perl uses indented #defines and it compiles with everything. Note: The regenerated 'configure' is included as well (I bumped the configure.in internal version number, as Guido say he usually does). Don't worry about looking at the diff for it, it is huge and all the info is in configure.in. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/PC/config.h Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/config.h Thu Jun 1 12:47:45 2000 *************** *** 233,255 **** /* End of compilers - finish up */ #if defined(MS_WIN64) /* maintain "win32" sys.platform for backward compatibility of Python code, the Win64 API should be close enough to the Win32 API to make this preferable */ ! #define PLATFORM "win32" ! #define SIZEOF_VOID_P 8 #elif defined(MS_WIN32) ! #define PLATFORM "win32" ! #ifdef _M_ALPHA ! #define SIZEOF_VOID_P 8 ! #else ! #define SIZEOF_VOID_P 4 ! #endif #elif defined(MS_WIN16) ! #define PLATFORM "win16" #else ! #define PLATFORM "dos" #endif --- 233,277 ---- /* End of compilers - finish up */ + /* define the ANSI intptr_t type for portable use of a pointer sized + integer */ + #include + #if defined(MS_WINDOWS) && !defined(MS_WIN64) + typedef long intptr_t; + #endif + #if defined(MS_WIN64) /* maintain "win32" sys.platform for backward compatibility of Python code, the Win64 API should be close enough to the Win32 API to make this preferable */ ! # define PLATFORM "win32" ! # define SIZEOF_VOID_P 8 ! # define SIZEOF_TIME_T 8 ! # define SIZEOF_OFF_T 4 ! # define SIZEOF_FPOS_T 8 ! # define SIZEOF_HKEY 8 ! /* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, ! sizeof(off_t) > sizeof(long), and sizeof(LONG_LONG) >= sizeof(off_t). ! On Win64 the second condition is not true, but if fpos_t replaces off_t ! then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 ! should define this. */ ! # define HAVE_LARGEFILE_SUPPORT #elif defined(MS_WIN32) ! # define PLATFORM "win32" ! # ifdef _M_ALPHA ! # define SIZEOF_VOID_P 8 ! # define SIZEOF_TIME_T 8 ! # else ! # define SIZEOF_VOID_P 4 ! # define SIZEOF_TIME_T 4 ! # define SIZEOF_OFF_T 4 ! # define SIZEOF_FPOS_T 8 ! # define SIZEOF_HKEY 4 ! # endif #elif defined(MS_WIN16) ! # define PLATFORM "win16" #else ! # define PLATFORM "dos" #endif *** /home/trentm/main/contrib/python/dist/src/configure.in Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/configure.in Wed May 31 23:54:21 2000 *************** *** 1,5 **** dnl Process this file with autoconf 2.0 or later to make a configure script. ! AC_REVISION($Revision: 1.124 $) AC_PREREQ(2.0) AC_INIT(Include/object.h) AC_CONFIG_HEADER(config.h) --- 1,5 ---- dnl Process this file with autoconf 2.0 or later to make a configure script. ! AC_REVISION($Revision: 1.125 $) AC_PREREQ(2.0) AC_INIT(Include/object.h) AC_CONFIG_HEADER(config.h) *************** *** 389,394 **** --- 389,395 ---- AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(float) AC_CHECK_SIZEOF(double) + AC_CHECK_SIZEOF(fpos_t) AC_MSG_CHECKING(for long long support) have_long_long=no *************** *** 423,428 **** --- 424,445 ---- else AC_MSG_RESULT(no) fi + + # AC_CHECK_SIZEOF() doesn't include . + AC_MSG_CHECKING(size of time_t) + AC_CACHE_VAL(ac_cv_sizeof_time_t, + [AC_TRY_RUN([#include + #include + main() + { + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(time_t)); + exit(0); + }], ac_cv_sizeof_time_t=`cat conftestval`, ac_cv_sizeof_time_t=0) + ]) + AC_MSG_RESULT($ac_cv_sizeof_time_t) + AC_DEFINE_UNQUOTED(SIZEOF_TIME_T, $ac_cv_sizeof_time_t) # Minor variations in building a framework between NextStep versions 4 and 5 *** /home/trentm/main/contrib/python/dist/src/configure Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/configure Wed May 31 23:54:21 2000 *************** *** 1,6 **** #! /bin/sh ! # From configure.in Revision: 1.123 # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 --- 1,6 ---- #! /bin/sh ! # From configure.in Revision: 1.125 # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 *************** *** 2233,2251 **** EOF echo $ac_n "checking for long long support""... $ac_c" 1>&6 ! echo "configure:2239: checking for long long support" >&5 have_long_long=no cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_LONG_LONG 1 --- 2233,2290 ---- EOF + echo $ac_n "checking size of fpos_t""... $ac_c" 1>&6 + echo "configure:2238: checking size of fpos_t" >&5 + if eval "test \"`echo '$''{'ac_cv_sizeof_fpos_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } + else + cat > conftest.$ac_ext < + main() + { + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(fpos_t)); + exit(0); + } + EOF + if { (eval echo configure:2257: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null + then + ac_cv_sizeof_fpos_t=`cat conftestval` + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_fpos_t=0 + fi + rm -fr conftest* + fi + + fi + echo "$ac_t""$ac_cv_sizeof_fpos_t" 1>&6 + cat >> confdefs.h <&6 ! echo "configure:2278: checking for long long support" >&5 have_long_long=no cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_LONG_LONG 1 *************** *** 2259,2265 **** echo "$ac_t""$have_long_long" 1>&6 if test "$have_long_long" = yes ; then echo $ac_n "checking size of long long""... $ac_c" 1>&6 ! echo "configure:2263: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 2298,2304 ---- echo "$ac_t""$have_long_long" 1>&6 if test "$have_long_long" = yes ; then echo $ac_n "checking size of long long""... $ac_c" 1>&6 ! echo "configure:2302: checking size of long long" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_long_long'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 2267,2273 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() --- 2306,2312 ---- { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < main() *************** *** 2278,2284 **** exit(0); } EOF ! if { (eval echo configure:2282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long_long=`cat conftestval` else --- 2317,2323 ---- exit(0); } EOF ! if { (eval echo configure:2321: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_long_long=`cat conftestval` else *************** *** 2301,2307 **** # Hmph. AC_CHECK_SIZEOF() doesn't include . echo $ac_n "checking size of off_t""... $ac_c" 1>&6 ! echo "configure:2305: checking size of off_t" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 2340,2346 ---- # Hmph. AC_CHECK_SIZEOF() doesn't include . echo $ac_n "checking size of off_t""... $ac_c" 1>&6 ! echo "configure:2344: checking size of off_t" >&5 if eval "test \"`echo '$''{'ac_cv_sizeof_off_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 2309,2315 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include --- 2348,2354 ---- { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #include *************** *** 2321,2327 **** exit(0); } EOF ! if { (eval echo configure:2325: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_off_t=`cat conftestval` else --- 2360,2366 ---- exit(0); } EOF ! if { (eval echo configure:2364: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_sizeof_off_t=`cat conftestval` else *************** *** 2343,2349 **** echo $ac_n "checking whether to enable large file support""... $ac_c" 1>&6 ! echo "configure:2347: checking whether to enable large file support" >&5 if test "$have_long_long" = yes -a \ "$ac_cv_sizeof_off_t" -gt "$ac_cv_sizeof_long" -a \ "$ac_cv_sizeof_long_long" -ge "$ac_cv_sizeof_off_t"; then --- 2382,2388 ---- echo $ac_n "checking whether to enable large file support""... $ac_c" 1>&6 ! echo "configure:2386: checking whether to enable large file support" >&5 if test "$have_long_long" = yes -a \ "$ac_cv_sizeof_off_t" -gt "$ac_cv_sizeof_long" -a \ "$ac_cv_sizeof_long_long" -ge "$ac_cv_sizeof_off_t"; then *************** *** 2356,2361 **** --- 2395,2443 ---- echo "$ac_t""no" 1>&6 fi + # AC_CHECK_SIZEOF() doesn't include . + echo $ac_n "checking size of time_t""... $ac_c" 1>&6 + echo "configure:2401: checking size of time_t" >&5 + if eval "test \"`echo '$''{'ac_cv_sizeof_time_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } + else + cat > conftest.$ac_ext < + #include + main() + { + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(time_t)); + exit(0); + } + EOF + if { (eval echo configure:2421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null + then + ac_cv_sizeof_time_t=`cat conftestval` + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_sizeof_time_t=0 + fi + rm -fr conftest* + fi + + + fi + + echo "$ac_t""$ac_cv_sizeof_time_t" 1>&6 + cat >> confdefs.h <&6 ! echo "configure:2373: checking for --with-next-framework" >&5 if test "$with_next_framework" then OPT="$OPT -fno-common" --- 2451,2457 ---- esac echo $ac_n "checking for --with-next-framework""... $ac_c" 1>&6 ! echo "configure:2455: checking for --with-next-framework" >&5 if test "$with_next_framework" then OPT="$OPT -fno-common" *************** *** 2386,2392 **** fi echo $ac_n "checking for --with-dyld""... $ac_c" 1>&6 ! echo "configure:2390: checking for --with-dyld" >&5 if test "$with_next_framework" -o "$with_dyld" then if test "$with_dyld" --- 2468,2474 ---- fi echo $ac_n "checking for --with-dyld""... $ac_c" 1>&6 ! echo "configure:2472: checking for --with-dyld" >&5 if test "$with_next_framework" -o "$with_dyld" then if test "$with_dyld" *************** *** 2412,2418 **** # SO is the extension of shared libraries `(including the dot!) # -- usually .so, .sl on HP-UX echo $ac_n "checking SO""... $ac_c" 1>&6 ! echo "configure:2416: checking SO" >&5 if test -z "$SO" then case $ac_sys_system in --- 2494,2500 ---- # SO is the extension of shared libraries `(including the dot!) # -- usually .so, .sl on HP-UX echo $ac_n "checking SO""... $ac_c" 1>&6 ! echo "configure:2498: checking SO" >&5 if test -z "$SO" then case $ac_sys_system in *************** *** 2426,2432 **** # (Shared libraries in this instance are shared modules to be loaded into # Python, as opposed to building Python itself as a shared library.) echo $ac_n "checking LDSHARED""... $ac_c" 1>&6 ! echo "configure:2430: checking LDSHARED" >&5 if test -z "$LDSHARED" then case $ac_sys_system/$ac_sys_release in --- 2508,2514 ---- # (Shared libraries in this instance are shared modules to be loaded into # Python, as opposed to building Python itself as a shared library.) echo $ac_n "checking LDSHARED""... $ac_c" 1>&6 ! echo "configure:2512: checking LDSHARED" >&5 if test -z "$LDSHARED" then case $ac_sys_system/$ac_sys_release in *************** *** 2471,2477 **** # CCSHARED are the C *flags* used to create objects to go into a shared # library (module) -- this is only needed for a few systems echo $ac_n "checking CCSHARED""... $ac_c" 1>&6 ! echo "configure:2475: checking CCSHARED" >&5 if test -z "$CCSHARED" then case $ac_sys_system/$ac_sys_release in --- 2553,2559 ---- # CCSHARED are the C *flags* used to create objects to go into a shared # library (module) -- this is only needed for a few systems echo $ac_n "checking CCSHARED""... $ac_c" 1>&6 ! echo "configure:2557: checking CCSHARED" >&5 if test -z "$CCSHARED" then case $ac_sys_system/$ac_sys_release in *************** *** 2494,2500 **** # LINKFORSHARED are the flags passed to the $(CC) command that links # the python executable -- this is only needed for a few systems echo $ac_n "checking LINKFORSHARED""... $ac_c" 1>&6 ! echo "configure:2498: checking LINKFORSHARED" >&5 if test -z "$LINKFORSHARED" then case $ac_sys_system/$ac_sys_release in --- 2576,2582 ---- # LINKFORSHARED are the flags passed to the $(CC) command that links # the python executable -- this is only needed for a few systems echo $ac_n "checking LINKFORSHARED""... $ac_c" 1>&6 ! echo "configure:2580: checking LINKFORSHARED" >&5 if test -z "$LINKFORSHARED" then case $ac_sys_system/$ac_sys_release in *************** *** 2530,2536 **** # checks for libraries echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 ! echo "configure:2534: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2612,2618 ---- # checks for libraries echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 ! echo "configure:2616: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2538,2544 **** ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2631,2637 ---- dlopen() ; return 0; } EOF ! if { (eval echo configure:2635: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2577,2583 **** fi # Dynamic linking for SunOS/Solaris and SYSV echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 ! echo "configure:2581: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2659,2665 ---- fi # Dynamic linking for SunOS/Solaris and SYSV echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 ! echo "configure:2663: checking for shl_load in -ldld" >&5 ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2585,2591 **** ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2678,2684 ---- shl_load() ; return 0; } EOF ! if { (eval echo configure:2682: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2627,2642 **** # checks for system dependent C++ extensions support case "$ac_sys_system" in AIX*) echo $ac_n "checking for genuine AIX C++ extensions support""... $ac_c" 1>&6 ! echo "configure:2631: checking for genuine AIX C++ extensions support" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* cat >> confdefs.h <<\EOF #define AIX_GENUINE_CPLUSPLUS 1 --- 2709,2724 ---- # checks for system dependent C++ extensions support case "$ac_sys_system" in AIX*) echo $ac_n "checking for genuine AIX C++ extensions support""... $ac_c" 1>&6 ! echo "configure:2713: checking for genuine AIX C++ extensions support" >&5 cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* cat >> confdefs.h <<\EOF #define AIX_GENUINE_CPLUSPLUS 1 *************** *** 2660,2666 **** IRIX*) ;; *) echo $ac_n "checking for t_open in -lnsl""... $ac_c" 1>&6 ! echo "configure:2664: checking for t_open in -lnsl" >&5 ac_lib_var=`echo nsl'_'t_open | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2742,2748 ---- IRIX*) ;; *) echo $ac_n "checking for t_open in -lnsl""... $ac_c" 1>&6 ! echo "configure:2746: checking for t_open in -lnsl" >&5 ac_lib_var=`echo nsl'_'t_open | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2668,2674 **** ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2761,2767 ---- t_open() ; return 0; } EOF ! if { (eval echo configure:2765: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2700,2706 **** fi # SVR4 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 ! echo "configure:2704: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2782,2788 ---- fi # SVR4 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 ! echo "configure:2786: checking for socket in -lsocket" >&5 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2708,2714 **** ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2801,2807 ---- socket() ; return 0; } EOF ! if { (eval echo configure:2805: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2740,2746 **** fi # SVR4 sockets echo $ac_n "checking for socket in -lnet""... $ac_c" 1>&6 ! echo "configure:2744: checking for socket in -lnet" >&5 ac_lib_var=`echo net'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2822,2828 ---- fi # SVR4 sockets echo $ac_n "checking for socket in -lnet""... $ac_c" 1>&6 ! echo "configure:2826: checking for socket in -lnet" >&5 ac_lib_var=`echo net'_'socket | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2748,2754 **** ac_save_LIBS="$LIBS" LIBS="-lnet $LIBS $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2841,2847 ---- socket() ; return 0; } EOF ! if { (eval echo configure:2845: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2783,2789 **** esac echo $ac_n "checking for --with-libs""... $ac_c" 1>&6 ! echo "configure:2787: checking for --with-libs" >&5 # Check whether --with-libs or --without-libs was given. if test "${with_libs+set}" = set; then withval="$with_libs" --- 2865,2871 ---- esac echo $ac_n "checking for --with-libs""... $ac_c" 1>&6 ! echo "configure:2869: checking for --with-libs" >&5 # Check whether --with-libs or --without-libs was given. if test "${with_libs+set}" = set; then withval="$with_libs" *************** *** 2797,2803 **** echo $ac_n "checking for --with(out)-readline""... $ac_c" 1>&6 ! echo "configure:2801: checking for --with(out)-readline" >&5 # Check whether --with-readline or --without-readline was given. if test "${with_readline+set}" = set; then withval="$with_readline" --- 2879,2885 ---- echo $ac_n "checking for --with(out)-readline""... $ac_c" 1>&6 ! echo "configure:2883: checking for --with(out)-readline" >&5 # Check whether --with-readline or --without-readline was given. if test "${with_readline+set}" = set; then withval="$with_readline" *************** *** 2812,2818 **** USE_THREAD_MODULE="#" echo $ac_n "checking for --with-dec-threads""... $ac_c" 1>&6 ! echo "configure:2816: checking for --with-dec-threads" >&5 # Check whether --with-dec-threads or --without-dec-threads was given. if test "${with_dec_threads+set}" = set; then --- 2894,2900 ---- USE_THREAD_MODULE="#" echo $ac_n "checking for --with-dec-threads""... $ac_c" 1>&6 ! echo "configure:2898: checking for --with-dec-threads" >&5 # Check whether --with-dec-threads or --without-dec-threads was given. if test "${with_dec_threads+set}" = set; then *************** *** 2828,2834 **** echo $ac_n "checking for --with-threads""... $ac_c" 1>&6 ! echo "configure:2832: checking for --with-threads" >&5 # Check whether --with-threads or --without-threads was given. if test "${with_threads+set}" = set; then withval="$with_threads" --- 2910,2916 ---- echo $ac_n "checking for --with-threads""... $ac_c" 1>&6 ! echo "configure:2914: checking for --with-threads" >&5 # Check whether --with-threads or --without-threads was given. if test "${with_threads+set}" = set; then withval="$with_threads" *************** *** 2842,2848 **** echo $ac_n "checking for --with-thread""... $ac_c" 1>&6 ! echo "configure:2846: checking for --with-thread" >&5 # Check whether --with-thread or --without-thread was given. if test "${with_thread+set}" = set; then withval="$with_thread" --- 2924,2930 ---- echo $ac_n "checking for --with-thread""... $ac_c" 1>&6 ! echo "configure:2928: checking for --with-thread" >&5 # Check whether --with-thread or --without-thread was given. if test "${with_thread+set}" = set; then withval="$with_thread" *************** *** 2858,2874 **** ac_safe=`echo "mach/cthreads.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for mach/cthreads.h""... $ac_c" 1>&6 ! echo "configure:2862: checking for mach/cthreads.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:2872: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* --- 2940,2956 ---- ac_safe=`echo "mach/cthreads.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for mach/cthreads.h""... $ac_c" 1>&6 ! echo "configure:2944: checking for mach/cthreads.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:2954: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* *************** *** 2897,2903 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pth_init in -lpth""... $ac_c" 1>&6 ! echo "configure:2901: checking for pth_init in -lpth" >&5 ac_lib_var=`echo pth'_'pth_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2979,2985 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for pth_init in -lpth""... $ac_c" 1>&6 ! echo "configure:2983: checking for pth_init in -lpth" >&5 ac_lib_var=`echo pth'_'pth_init | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2905,2911 **** ac_save_LIBS="$LIBS" LIBS="-lpth $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2998,3004 ---- pth_init() ; return 0; } EOF ! if { (eval echo configure:3002: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2945,2951 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 ! echo "configure:2949: checking for pthread_create in -lpthread" >&5 ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3027,3033 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6 ! echo "configure:3031: checking for pthread_create in -lpthread" >&5 ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2953,2959 **** ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3046,3052 ---- pthread_create() ; return 0; } EOF ! if { (eval echo configure:3050: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2993,3004 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_detach""... $ac_c" 1>&6 ! echo "configure:2997: checking for pthread_detach" >&5 if eval "test \"`echo '$''{'ac_cv_func_pthread_detach'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 echo $ac_n "checking for pthread_detach""... $ac_c" 1>&6 ! echo "configure:3079: checking for pthread_detach" >&5 if eval "test \"`echo '$''{'ac_cv_func_pthread_detach'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_pthread_detach=yes" else --- 3103,3109 ---- ; return 0; } EOF ! if { (eval echo configure:3107: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_pthread_detach=yes" else *************** *** 3049,3065 **** ac_safe=`echo "kernel/OS.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for kernel/OS.h""... $ac_c" 1>&6 ! echo "configure:3053: checking for kernel/OS.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:3063: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* --- 3131,3147 ---- ac_safe=`echo "kernel/OS.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for kernel/OS.h""... $ac_c" 1>&6 ! echo "configure:3135: checking for kernel/OS.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:3145: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* *************** *** 3088,3094 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6 ! echo "configure:3092: checking for pthread_create in -lpthreads" >&5 ac_lib_var=`echo pthreads'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3170,3176 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lpthreads""... $ac_c" 1>&6 ! echo "configure:3174: checking for pthread_create in -lpthreads" >&5 ac_lib_var=`echo pthreads'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3096,3102 **** ac_save_LIBS="$LIBS" LIBS="-lpthreads $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3189,3195 ---- pthread_create() ; return 0; } EOF ! if { (eval echo configure:3193: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3136,3142 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6 ! echo "configure:3140: checking for pthread_create in -lc_r" >&5 ac_lib_var=`echo c_r'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3218,3224 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lc_r""... $ac_c" 1>&6 ! echo "configure:3222: checking for pthread_create in -lc_r" >&5 ac_lib_var=`echo c_r'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3144,3150 **** ac_save_LIBS="$LIBS" LIBS="-lc_r $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3237,3243 ---- pthread_create() ; return 0; } EOF ! if { (eval echo configure:3241: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3184,3190 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for __d6_pthread_create in -lthread""... $ac_c" 1>&6 ! echo "configure:3188: checking for __d6_pthread_create in -lthread" >&5 ac_lib_var=`echo thread'_'__d6_pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3266,3272 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for __d6_pthread_create in -lthread""... $ac_c" 1>&6 ! echo "configure:3270: checking for __d6_pthread_create in -lthread" >&5 ac_lib_var=`echo thread'_'__d6_pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3192,3198 **** ac_save_LIBS="$LIBS" LIBS="-lthread $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3285,3291 ---- __d6_pthread_create() ; return 0; } EOF ! if { (eval echo configure:3289: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3232,3238 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lcma""... $ac_c" 1>&6 ! echo "configure:3236: checking for pthread_create in -lcma" >&5 ac_lib_var=`echo cma'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3314,3320 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking for pthread_create in -lcma""... $ac_c" 1>&6 ! echo "configure:3318: checking for pthread_create in -lcma" >&5 ac_lib_var=`echo cma'_'pthread_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3240,3246 **** ac_save_LIBS="$LIBS" LIBS="-lcma $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3333,3339 ---- pthread_create() ; return 0; } EOF ! if { (eval echo configure:3337: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3299,3305 **** echo $ac_n "checking for usconfig in -lmpc""... $ac_c" 1>&6 ! echo "configure:3303: checking for usconfig in -lmpc" >&5 ac_lib_var=`echo mpc'_'usconfig | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3381,3387 ---- echo $ac_n "checking for usconfig in -lmpc""... $ac_c" 1>&6 ! echo "configure:3385: checking for usconfig in -lmpc" >&5 ac_lib_var=`echo mpc'_'usconfig | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3307,3313 **** ac_save_LIBS="$LIBS" LIBS="-lmpc $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3400,3406 ---- usconfig() ; return 0; } EOF ! if { (eval echo configure:3404: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3344,3350 **** fi echo $ac_n "checking for thr_create in -lthread""... $ac_c" 1>&6 ! echo "configure:3348: checking for thr_create in -lthread" >&5 ac_lib_var=`echo thread'_'thr_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3426,3432 ---- fi echo $ac_n "checking for thr_create in -lthread""... $ac_c" 1>&6 ! echo "configure:3430: checking for thr_create in -lthread" >&5 ac_lib_var=`echo thread'_'thr_create | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3352,3358 **** ac_save_LIBS="$LIBS" LIBS="-lthread $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3445,3451 ---- thr_create() ; return 0; } EOF ! if { (eval echo configure:3449: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3399,3405 **** DLINCLDIR=/ echo $ac_n "checking for --with-sgi-dl""... $ac_c" 1>&6 ! echo "configure:3403: checking for --with-sgi-dl" >&5 # Check whether --with-sgi-dl or --without-sgi-dl was given. if test "${with_sgi_dl+set}" = set; then withval="$with_sgi_dl" --- 3481,3487 ---- DLINCLDIR=/ echo $ac_n "checking for --with-sgi-dl""... $ac_c" 1>&6 ! echo "configure:3485: checking for --with-sgi-dl" >&5 # Check whether --with-sgi-dl or --without-sgi-dl was given. if test "${with_sgi_dl+set}" = set; then withval="$with_sgi_dl" *************** *** 3423,3429 **** echo $ac_n "checking for --with-dl-dld""... $ac_c" 1>&6 ! echo "configure:3427: checking for --with-dl-dld" >&5 # Check whether --with-dl-dld or --without-dl-dld was given. if test "${with_dl_dld+set}" = set; then withval="$with_dl_dld" --- 3505,3511 ---- echo $ac_n "checking for --with-dl-dld""... $ac_c" 1>&6 ! echo "configure:3509: checking for --with-dl-dld" >&5 # Check whether --with-dl-dld or --without-dl-dld was given. if test "${with_dl_dld+set}" = set; then withval="$with_dl_dld" *************** *** 3450,3461 **** # the dlopen() function means we might want to use dynload_shlib.o. some # platforms, such as AIX, have dlopen(), but don't want to use it. echo $ac_n "checking for dlopen""... $ac_c" 1>&6 ! echo "configure:3454: checking for dlopen" >&5 if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3536: checking for dlopen" >&5 if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else --- 3560,3566 ---- ; return 0; } EOF ! if { (eval echo configure:3564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_dlopen=yes" else *************** *** 3502,3508 **** # loading of modules. echo $ac_n "checking DYNLOADFILE""... $ac_c" 1>&6 ! echo "configure:3506: checking DYNLOADFILE" >&5 if test -z "$DYNLOADFILE" then case $ac_sys_system/$ac_sys_release in --- 3584,3590 ---- # loading of modules. echo $ac_n "checking DYNLOADFILE""... $ac_c" 1>&6 ! echo "configure:3588: checking DYNLOADFILE" >&5 if test -z "$DYNLOADFILE" then case $ac_sys_system/$ac_sys_release in *************** *** 3541,3552 **** truncate uname waitpid do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3545: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3627: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3651,3657 ---- ; return 0; } EOF ! if { (eval echo configure:3655: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3598,3609 **** for ac_func in fseek64 fseeko fstatvfs ftell64 ftello statvfs do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3602: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3684: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3708,3714 ---- ; return 0; } EOF ! if { (eval echo configure:3712: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3654,3665 **** for ac_func in dup2 getcwd strdup strerror memmove do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3658: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3740: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3764,3770 ---- ; return 0; } EOF ! if { (eval echo configure:3768: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3709,3720 **** echo $ac_n "checking for getpgrp""... $ac_c" 1>&6 ! echo "configure:3713: checking for getpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3795: checking for getpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpgrp=yes" else --- 3819,3825 ---- ; return 0; } EOF ! if { (eval echo configure:3823: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpgrp=yes" else *************** *** 3752,3765 **** if eval "test \"`echo '$ac_cv_func_'getpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { getpgrp(0); ; return 0; } EOF ! if { (eval echo configure:3763: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define GETPGRP_HAVE_ARG 1 --- 3834,3847 ---- if eval "test \"`echo '$ac_cv_func_'getpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { getpgrp(0); ; return 0; } EOF ! if { (eval echo configure:3845: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define GETPGRP_HAVE_ARG 1 *************** *** 3775,3786 **** fi echo $ac_n "checking for setpgrp""... $ac_c" 1>&6 ! echo "configure:3779: checking for setpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3861: checking for setpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setpgrp=yes" else --- 3885,3891 ---- ; return 0; } EOF ! if { (eval echo configure:3889: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setpgrp=yes" else *************** *** 3818,3831 **** if eval "test \"`echo '$ac_cv_func_'setpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { setpgrp(0,0); ; return 0; } EOF ! if { (eval echo configure:3829: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SETPGRP_HAVE_ARG 1 --- 3900,3913 ---- if eval "test \"`echo '$ac_cv_func_'setpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { setpgrp(0,0); ; return 0; } EOF ! if { (eval echo configure:3911: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SETPGRP_HAVE_ARG 1 *************** *** 3841,3852 **** fi echo $ac_n "checking for gettimeofday""... $ac_c" 1>&6 ! echo "configure:3845: checking for gettimeofday" >&5 if eval "test \"`echo '$''{'ac_cv_func_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3927: checking for gettimeofday" >&5 if eval "test \"`echo '$''{'ac_cv_func_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettimeofday=yes" else --- 3951,3957 ---- ; return 0; } EOF ! if { (eval echo configure:3955: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettimeofday=yes" else *************** *** 3884,3897 **** if eval "test \"`echo '$ac_cv_func_'gettimeofday`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { gettimeofday((struct timeval*)0,(struct timezone*)0); ; return 0; } EOF ! if { (eval echo configure:3895: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 3966,3979 ---- if eval "test \"`echo '$ac_cv_func_'gettimeofday`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { gettimeofday((struct timeval*)0,(struct timezone*)0); ; return 0; } EOF ! if { (eval echo configure:3977: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 3910,3921 **** # checks for structures echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:3914: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 3992,4003 ---- # checks for structures echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:3996: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 3924,3930 **** struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:3928: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else --- 4006,4012 ---- struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:4010: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else *************** *** 3945,3956 **** fi echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 ! echo "configure:3949: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 4027,4038 ---- fi echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 ! echo "configure:4031: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 3958,3964 **** struct tm *tp; tp->tm_sec; ; return 0; } EOF ! if { (eval echo configure:3962: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else --- 4040,4046 ---- struct tm *tp; tp->tm_sec; ; return 0; } EOF ! if { (eval echo configure:4044: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else *************** *** 3979,3990 **** fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 ! echo "configure:3983: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> --- 4061,4072 ---- fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 ! echo "configure:4065: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> *************** *** 3992,3998 **** struct tm tm; tm.tm_zone; ; return 0; } EOF ! if { (eval echo configure:3996: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else --- 4074,4080 ---- struct tm tm; tm.tm_zone; ; return 0; } EOF ! if { (eval echo configure:4078: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else *************** *** 4012,4023 **** else echo $ac_n "checking for tzname""... $ac_c" 1>&6 ! echo "configure:4016: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ --- 4094,4105 ---- else echo $ac_n "checking for tzname""... $ac_c" 1>&6 ! echo "configure:4098: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ *************** *** 4027,4033 **** atoi(*tzname); ; return 0; } EOF ! if { (eval echo configure:4031: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else --- 4109,4115 ---- atoi(*tzname); ; return 0; } EOF ! if { (eval echo configure:4113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else *************** *** 4050,4068 **** echo $ac_n "checking for time.h that defines altzone""... $ac_c" 1>&6 ! echo "configure:4054: checking for time.h that defines altzone" >&5 if eval "test \"`echo '$''{'ac_cv_header_time_altzone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return altzone; ; return 0; } EOF ! if { (eval echo configure:4066: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time_altzone=yes else --- 4132,4150 ---- echo $ac_n "checking for time.h that defines altzone""... $ac_c" 1>&6 ! echo "configure:4136: checking for time.h that defines altzone" >&5 if eval "test \"`echo '$''{'ac_cv_header_time_altzone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return altzone; ; return 0; } EOF ! if { (eval echo configure:4148: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time_altzone=yes else *************** *** 4084,4092 **** was_it_defined=no echo $ac_n "checking whether sys/select.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:4088: checking whether sys/select.h and sys/time.h may both be included" >&5 cat > conftest.$ac_ext < --- 4166,4174 ---- was_it_defined=no echo $ac_n "checking whether sys/select.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:4170: checking whether sys/select.h and sys/time.h may both be included" >&5 cat > conftest.$ac_ext < *************** *** 4097,4103 **** ; ; return 0; } EOF ! if { (eval echo configure:4101: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SYS_SELECT_WITH_SYS_TIME 1 --- 4179,4185 ---- ; ; return 0; } EOF ! if { (eval echo configure:4183: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SYS_SELECT_WITH_SYS_TIME 1 *************** *** 4113,4126 **** # checks for compiler characteristics echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 ! echo "configure:4117: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&6 ! echo "configure:4199: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else --- 4234,4240 ---- volatile char c = 255; exit(c < 0); } EOF ! if { (eval echo configure:4238: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else *************** *** 4176,4187 **** fi echo $ac_n "checking for working const""... $ac_c" 1>&6 ! echo "configure:4180: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4262: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else --- 4312,4318 ---- ; return 0; } EOF ! if { (eval echo configure:4316: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else *************** *** 4251,4271 **** fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:4255: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else --- 4333,4353 ---- fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:4337: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else *************** *** 4293,4308 **** works=no echo $ac_n "checking for working volatile""... $ac_c" 1>&6 ! echo "configure:4297: checking for working volatile" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else --- 4375,4390 ---- works=no echo $ac_n "checking for working volatile""... $ac_c" 1>&6 ! echo "configure:4379: checking for working volatile" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else *************** *** 4319,4334 **** works=no echo $ac_n "checking for working signed char""... $ac_c" 1>&6 ! echo "configure:4323: checking for working signed char" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else --- 4401,4416 ---- works=no echo $ac_n "checking for working signed char""... $ac_c" 1>&6 ! echo "configure:4405: checking for working signed char" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else *************** *** 4345,4360 **** have_prototypes=no echo $ac_n "checking for prototypes""... $ac_c" 1>&6 ! echo "configure:4349: checking for prototypes" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_PROTOTYPES 1 --- 4427,4442 ---- have_prototypes=no echo $ac_n "checking for prototypes""... $ac_c" 1>&6 ! echo "configure:4431: checking for prototypes" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_PROTOTYPES 1 *************** *** 4369,4377 **** works=no echo $ac_n "checking for variable length prototypes and stdarg.h""... $ac_c" 1>&6 ! echo "configure:4373: checking for variable length prototypes and stdarg.h" >&5 cat > conftest.$ac_ext < --- 4451,4459 ---- works=no echo $ac_n "checking for variable length prototypes and stdarg.h""... $ac_c" 1>&6 ! echo "configure:4455: checking for variable length prototypes and stdarg.h" >&5 cat > conftest.$ac_ext < *************** *** 4388,4394 **** return foo(10, "", 3.14); ; return 0; } EOF ! if { (eval echo configure:4392: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_STDARG_PROTOTYPES 1 --- 4470,4476 ---- return foo(10, "", 3.14); ; return 0; } EOF ! if { (eval echo configure:4474: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_STDARG_PROTOTYPES 1 *************** *** 4404,4419 **** if test "$have_prototypes" = yes; then bad_prototypes=no echo $ac_n "checking for bad exec* prototypes""... $ac_c" 1>&6 ! echo "configure:4408: checking for bad exec* prototypes" >&5 cat > conftest.$ac_ext < int main() { char **t;execve("@",t,t); ; return 0; } EOF ! if { (eval echo configure:4417: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 4486,4501 ---- if test "$have_prototypes" = yes; then bad_prototypes=no echo $ac_n "checking for bad exec* prototypes""... $ac_c" 1>&6 ! echo "configure:4490: checking for bad exec* prototypes" >&5 cat > conftest.$ac_ext < int main() { char **t;execve("@",t,t); ; return 0; } EOF ! if { (eval echo configure:4499: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 4430,4441 **** bad_forward=no echo $ac_n "checking for bad static forward""... $ac_c" 1>&6 ! echo "configure:4434: checking for bad static forward" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&6 ! echo "configure:4516: checking for bad static forward" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else --- 4533,4539 ---- } EOF ! if { (eval echo configure:4537: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else *************** *** 4470,4478 **** va_list_is_array=no echo $ac_n "checking whether va_list is an array""... $ac_c" 1>&6 ! echo "configure:4474: checking whether va_list is an array" >&5 cat > conftest.$ac_ext <&6 ! echo "configure:4556: checking whether va_list is an array" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 4567,4573 ---- va_list list1, list2; list1 = list2; ; return 0; } EOF ! if { (eval echo configure:4571: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 4501,4512 **** # sigh -- gethostbyname_r is a mess; it can have 3, 5 or 6 arguments :-( echo $ac_n "checking for gethostbyname_r""... $ac_c" 1>&6 ! echo "configure:4505: checking for gethostbyname_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4587: checking for gethostbyname_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname_r=yes" else --- 4611,4617 ---- ; return 0; } EOF ! if { (eval echo configure:4615: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname_r=yes" else *************** *** 4549,4559 **** EOF echo $ac_n "checking gethostbyname_r with 6 args""... $ac_c" 1>&6 ! echo "configure:4553: checking gethostbyname_r with 6 args" >&5 OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat > conftest.$ac_ext < --- 4631,4641 ---- EOF echo $ac_n "checking gethostbyname_r with 6 args""... $ac_c" 1>&6 ! echo "configure:4635: checking gethostbyname_r with 6 args" >&5 OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat > conftest.$ac_ext < *************** *** 4570,4576 **** ; return 0; } EOF ! if { (eval echo configure:4574: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4652,4658 ---- ; return 0; } EOF ! if { (eval echo configure:4656: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4590,4598 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 5 args""... $ac_c" 1>&6 ! echo "configure:4594: checking gethostbyname_r with 5 args" >&5 cat > conftest.$ac_ext < --- 4672,4680 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 5 args""... $ac_c" 1>&6 ! echo "configure:4676: checking gethostbyname_r with 5 args" >&5 cat > conftest.$ac_ext < *************** *** 4609,4615 **** ; return 0; } EOF ! if { (eval echo configure:4613: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4691,4697 ---- ; return 0; } EOF ! if { (eval echo configure:4695: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4629,4637 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 3 args""... $ac_c" 1>&6 ! echo "configure:4633: checking gethostbyname_r with 3 args" >&5 cat > conftest.$ac_ext < --- 4711,4719 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 3 args""... $ac_c" 1>&6 ! echo "configure:4715: checking gethostbyname_r with 3 args" >&5 cat > conftest.$ac_ext < *************** *** 4646,4652 **** ; return 0; } EOF ! if { (eval echo configure:4650: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4728,4734 ---- ; return 0; } EOF ! if { (eval echo configure:4732: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4680,4691 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 ! echo "configure:4684: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 ! echo "configure:4766: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else --- 4790,4796 ---- ; return 0; } EOF ! if { (eval echo configure:4794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else *************** *** 4744,4750 **** # Linux requires this for correct f.p. operations echo $ac_n "checking for __fpu_control in -lieee""... $ac_c" 1>&6 ! echo "configure:4748: checking for __fpu_control in -lieee" >&5 ac_lib_var=`echo ieee'_'__fpu_control | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 4826,4832 ---- # Linux requires this for correct f.p. operations echo $ac_n "checking for __fpu_control in -lieee""... $ac_c" 1>&6 ! echo "configure:4830: checking for __fpu_control in -lieee" >&5 ac_lib_var=`echo ieee'_'__fpu_control | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 4752,4758 **** ac_save_LIBS="$LIBS" LIBS="-lieee $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 4845,4851 ---- __fpu_control() ; return 0; } EOF ! if { (eval echo configure:4849: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 4793,4799 **** # Check for --with-fpectl echo $ac_n "checking for --with-fpectl""... $ac_c" 1>&6 ! echo "configure:4797: checking for --with-fpectl" >&5 # Check whether --with-fpectl or --without-fpectl was given. if test "${with_fpectl+set}" = set; then withval="$with_fpectl" --- 4875,4881 ---- # Check for --with-fpectl echo $ac_n "checking for --with-fpectl""... $ac_c" 1>&6 ! echo "configure:4879: checking for --with-fpectl" >&5 # Check whether --with-fpectl or --without-fpectl was given. if test "${with_fpectl+set}" = set; then withval="$with_fpectl" *************** *** 4818,4824 **** *) LIBM=-lm esac echo $ac_n "checking for --with-libm=STRING""... $ac_c" 1>&6 ! echo "configure:4822: checking for --with-libm=STRING" >&5 # Check whether --with-libm or --without-libm was given. if test "${with_libm+set}" = set; then withval="$with_libm" --- 4900,4906 ---- *) LIBM=-lm esac echo $ac_n "checking for --with-libm=STRING""... $ac_c" 1>&6 ! echo "configure:4904: checking for --with-libm=STRING" >&5 # Check whether --with-libm or --without-libm was given. if test "${with_libm+set}" = set; then withval="$with_libm" *************** *** 4839,4845 **** # check for --with-libc=... echo $ac_n "checking for --with-libc=STRING""... $ac_c" 1>&6 ! echo "configure:4843: checking for --with-libc=STRING" >&5 # Check whether --with-libc or --without-libc was given. if test "${with_libc+set}" = set; then withval="$with_libc" --- 4921,4927 ---- # check for --with-libc=... echo $ac_n "checking for --with-libc=STRING""... $ac_c" 1>&6 ! echo "configure:4925: checking for --with-libc=STRING" >&5 # Check whether --with-libc or --without-libc was given. if test "${with_libc+set}" = set; then withval="$with_libc" *************** *** 4863,4874 **** for ac_func in hypot do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4867: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4949: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4973,4979 ---- ; return 0; } EOF ! if { (eval echo configure:4977: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4918,4929 **** for ac_func in hypot do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4922: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:5004: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 5028,5034 ---- ; return 0; } EOF ! if { (eval echo configure:5032: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4980,4991 **** for ac_func in rint do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4984: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:5066: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 5090,5096 ---- ; return 0; } EOF ! if { (eval echo configure:5094: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 5036,5042 **** # check for getopt echo $ac_n "checking for genuine getopt""... $ac_c" 1>&6 ! echo "configure:5040: checking for genuine getopt" >&5 if eval "test \"`echo '$''{'ac_cv_func_getopt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 5118,5124 ---- # check for getopt echo $ac_n "checking for genuine getopt""... $ac_c" 1>&6 ! echo "configure:5122: checking for genuine getopt" >&5 if eval "test \"`echo '$''{'ac_cv_func_getopt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 5044,5050 **** ac_cv_func_getopt=no else cat > conftest.$ac_ext < extern int optind, opterr, getopt(); --- 5126,5132 ---- ac_cv_func_getopt=no else cat > conftest.$ac_ext < extern int optind, opterr, getopt(); *************** *** 5056,5062 **** exit(0); } EOF ! if { (eval echo configure:5060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_getopt=yes else --- 5138,5144 ---- exit(0); } EOF ! if { (eval echo configure:5142: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_getopt=yes else *************** *** 5074,5080 **** # check whether malloc(0) returns NULL or not echo $ac_n "checking what malloc(0) returns""... $ac_c" 1>&6 ! echo "configure:5078: checking what malloc(0) returns" >&5 if eval "test \"`echo '$''{'ac_cv_malloc_zero'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 5156,5162 ---- # check whether malloc(0) returns NULL or not echo $ac_n "checking what malloc(0) returns""... $ac_c" 1>&6 ! echo "configure:5160: checking what malloc(0) returns" >&5 if eval "test \"`echo '$''{'ac_cv_malloc_zero'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 5082,5088 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #ifdef HAVE_STDLIB --- 5164,5170 ---- { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #ifdef HAVE_STDLIB *************** *** 5101,5107 **** exit(0); } EOF ! if { (eval echo configure:5105: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_malloc_zero=nonnull else --- 5183,5189 ---- exit(0); } EOF ! if { (eval echo configure:5187: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_malloc_zero=nonnull else *************** *** 5127,5143 **** # check for wchar.h ac_safe=`echo "wchar.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for wchar.h""... $ac_c" 1>&6 ! echo "configure:5131: checking for wchar.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:5141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* --- 5209,5225 ---- # check for wchar.h ac_safe=`echo "wchar.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for wchar.h""... $ac_c" 1>&6 ! echo "configure:5213: checking for wchar.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:5223: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* *************** *** 5167,5178 **** # check for usable wchar_t usable_wchar_t="unkown" echo $ac_n "checking for usable wchar_t""... $ac_c" 1>&6 ! echo "configure:5171: checking for usable wchar_t" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&6 ! echo "configure:5253: checking for usable wchar_t" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then cat >> confdefs.h <<\EOF #define HAVE_USABLE_WCHAR_T 1 --- 5268,5274 ---- } EOF ! if { (eval echo configure:5272: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then cat >> confdefs.h <<\EOF #define HAVE_USABLE_WCHAR_T 1 *************** *** 5205,5218 **** # check for endianness echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 ! echo "configure:5209: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include --- 5287,5300 ---- # check for endianness echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 ! echo "configure:5291: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include *************** *** 5223,5233 **** #endif ; return 0; } EOF ! if { (eval echo configure:5227: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include --- 5305,5315 ---- #endif ; return 0; } EOF ! if { (eval echo configure:5309: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include *************** *** 5238,5244 **** #endif ; return 0; } EOF ! if { (eval echo configure:5242: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else --- 5320,5326 ---- #endif ; return 0; } EOF ! if { (eval echo configure:5324: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else *************** *** 5258,5264 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else --- 5353,5359 ---- exit (u.c[sizeof (long) - 1] == 1); } EOF ! if { (eval echo configure:5357: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else *************** *** 5297,5303 **** # Check for --with-wctype-functions echo $ac_n "checking for --with-wctype-functions""... $ac_c" 1>&6 ! echo "configure:5301: checking for --with-wctype-functions" >&5 # Check whether --with-wctype-functions or --without-wctype-functions was given. if test "${with_wctype_functions+set}" = set; then withval="$with_wctype_functions" --- 5379,5385 ---- # Check for --with-wctype-functions echo $ac_n "checking for --with-wctype-functions""... $ac_c" 1>&6 ! echo "configure:5383: checking for --with-wctype-functions" >&5 # Check whether --with-wctype-functions or --without-wctype-functions was given. if test "${with_wctype_functions+set}" = set; then withval="$with_wctype_functions" *************** *** 5322,5333 **** #endif EOF echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 ! echo "configure:5326: checking for socklen_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS --- 5404,5415 ---- #endif EOF echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 ! echo "configure:5408: checking for socklen_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 21:28:28 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 13:28:28 -0700 Subject: [Patches] changes to configure.in and PC/config.h for 64-bit systems In-Reply-To: <20000601131412.B9463@activestate.com> References: <20000601131412.B9463@activestate.com> Message-ID: <20000601132828.C9463@activestate.com> Sorry sorry, I apologize to those of you with slow connections for sending such a big patch. I could have held off on sending 'configure'. I realized it was big, but not *that* big. SOrry. Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 21:38:31 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 13:38:31 -0700 Subject: [Patches] overflow checking for modification time (64-bit, import.c) Message-ID: <20000601133831.A17175@activestate.com> Discussion: This patch fixes possible overflow in the use of PyOS_GetLastModificationTime in getmtime.c and Python/import.c. Currently PyOS_GetLastModificationTime returns a C long. This can overflow on Win64 where sizeof(time_t) > sizeof(long). Besides it should logically return a time_t anyway (this patch changes this). As well, import.c uses PyOS_GetLastModificationTime for .pyc timestamping. There has been recent discussion about the .pyc header format on python-dev. This patch adds oveflow checking to import.c so that an exception will be raised if the modification time overflows. There are a few other minor 64-bit readiness changes made to the module as well: - size_t instead of int or long for function-local buffer and string length variables - one buffer overflow check was added (raises an exception on possible overflow, this overflow chance exists on 32-bit platforms as well), no other possible buffer overflows existed (from my analysis anyway) Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Python/getmtime.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/getmtime.c Wed May 31 23:54:20 2000 *************** *** 33,45 **** /* (A separate file because this may be OS dependent) */ #include "config.h" #include #include #include ! long PyOS_GetLastModificationTime(path, fp) char *path; FILE *fp; --- 33,46 ---- /* (A separate file because this may be OS dependent) */ + #include "Python.h" #include "config.h" #include #include #include ! time_t PyOS_GetLastModificationTime(path, fp) char *path; FILE *fp; *** /home/trentm/main/contrib/python/dist/src/Python/import.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/import.c Wed May 31 23:54:20 2000 *************** *** 74,80 **** #endif ! extern long PyOS_GetLastModificationTime(); /* In getmtime.c */ /* Magic word to reject .pyc files generated by other Python versions */ /* Change for each incompatible change */ --- 74,80 ---- #endif ! extern time_t PyOS_GetLastModificationTime(); /* In getmtime.c */ /* Magic word to reject .pyc files generated by other Python versions */ /* Change for each incompatible change */ *************** *** 549,557 **** make_compiled_pathname(pathname, buf, buflen) char *pathname; char *buf; ! int buflen; { ! int len; len = strlen(pathname); if (len+2 > buflen) --- 549,557 ---- make_compiled_pathname(pathname, buf, buflen) char *pathname; char *buf; ! size_t buflen; { ! size_t len; len = strlen(pathname); if (len+2 > buflen) *************** *** 732,738 **** char *pathname; FILE *fp; { ! long mtime; FILE *fpc; char buf[MAXPATHLEN+1]; char *cpathname; --- 732,738 ---- char *pathname; FILE *fp; { ! time_t mtime; FILE *fpc; char buf[MAXPATHLEN+1]; char *cpathname; *************** *** 740,746 **** PyObject *m; mtime = PyOS_GetLastModificationTime(pathname, fp); ! cpathname = make_compiled_pathname(pathname, buf, MAXPATHLEN+1); if (cpathname != NULL && (fpc = check_compiled_module(pathname, mtime, cpathname))) { co = read_compiled_module(cpathname, fpc); --- 740,759 ---- PyObject *m; mtime = PyOS_GetLastModificationTime(pathname, fp); ! if (mtime == -1) ! return NULL; ! #if SIZEOF_TIME_T > 4 ! /* Python's .pyc timestamp handling presumes that the timestamp fits ! in 4 bytes. This will be fine until sometime in the year 2038, ! when a 4-byte signed time_t will overflow. ! */ ! if (mtime >> 32) { ! PyErr_SetString(PyExc_OverflowError, ! "modification time overflows a 4 bytes"); ! return NULL; ! } ! #endif ! cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN+1); if (cpathname != NULL && (fpc = check_compiled_module(pathname, mtime, cpathname))) { co = read_compiled_module(cpathname, fpc); *************** *** 771,777 **** /* Forward */ static PyObject *load_module Py_PROTO((char *, FILE *, char *, int)); static struct filedescr *find_module Py_PROTO((char *, PyObject *, ! char *, int, FILE **)); static struct _frozen *find_frozen Py_PROTO((char *name)); /* Load a package and return its module object WITH INCREMENTED --- 784,790 ---- /* Forward */ static PyObject *load_module Py_PROTO((char *, FILE *, char *, int)); static struct filedescr *find_module Py_PROTO((char *, PyObject *, ! char *, size_t, FILE **)); static struct _frozen *find_frozen Py_PROTO((char *name)); /* Load a package and return its module object WITH INCREMENTED *************** *** 869,878 **** PyObject *path; /* Output parameters: */ char *buf; ! int buflen; FILE **p_fp; { ! int i, npath, len, namelen; struct _frozen *f; struct filedescr *fdp = NULL; FILE *fp = NULL; --- 882,892 ---- PyObject *path; /* Output parameters: */ char *buf; ! size_t buflen; FILE **p_fp; { ! int i, npath; ! size_t len, namelen; struct _frozen *f; struct filedescr *fdp = NULL; FILE *fp = NULL; *************** *** 882,887 **** --- 896,905 ---- static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; char name[MAXPATHLEN+1]; + if (strlen(realname) > MAXPATHLEN) { + PyErr_SetString(PyExc_OverflowError, "module name is too long"); + return NULL; + } strcpy(name, realname); if (path != NULL && PyString_Check(path)) { *************** *** 933,939 **** if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) continue; /* Too long */ strcpy(buf, PyString_AsString(v)); ! if ((int)strlen(buf) != len) continue; /* v contains '\0' */ #ifdef macintosh #ifdef INTERN_STRINGS --- 951,957 ---- if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) continue; /* Too long */ strcpy(buf, PyString_AsString(v)); ! if (strlen(buf) != len) continue; /* v contains '\0' */ #ifdef macintosh #ifdef INTERN_STRINGS *************** *** 1181,1188 **** find_init_module(buf) char *buf; { ! int save_len = strlen(buf); ! int i = save_len; struct stat statbuf; if (save_len + 13 >= MAXPATHLEN) --- 1199,1206 ---- find_init_module(buf) char *buf; { ! size_t save_len = strlen(buf); ! size_t i = save_len; struct stat statbuf; if (save_len + 13 >= MAXPATHLEN) *************** *** 1577,1583 **** else { char *start = PyString_AS_STRING(modname); char *lastdot = strrchr(start, '.'); ! int len; if (lastdot == NULL) return Py_None; len = lastdot - start; --- 1595,1601 ---- else { char *start = PyString_AS_STRING(modname); char *lastdot = strrchr(start, '.'); ! size_t len; if (lastdot == NULL) return Py_None; len = lastdot - start; *************** *** 1612,1618 **** { char *name = *p_name; char *dot = strchr(name, '.'); ! int len; char *p; PyObject *result; --- 1630,1636 ---- { char *name = *p_name; char *dot = strchr(name, '.'); ! size_t len; char *p; PyObject *result; -- Trent Mick trentm@activestate.com From trentm@activestate.com Thu Jun 1 22:19:45 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 14:19:45 -0700 Subject: [Patches] largefile support for Win64 (and some other fixes) Message-ID: <20000601141945.A17399@activestate.com> Discussion: This patch adds largefile support for Win64 and Linux64 (the latter already motly worked I think), and fixes some possible buffer overflows on all systems with largefile support. NOTE: this patch depends on my earlier patch to PC/config.h and configure.in for SIZEOF_OFF_T and SIZEOF_FPOS_T. (see: "[Patches] changes to configure.in and PC/config.h for 64-bit systems") Win64 largefile support involved fixing file_seek, file_tell, and file_truncate to properly handle large indeces and to use the proper Win64 system APIs. Win64 does not have 64-bit capable versions of ftell and fseek, this could be worked around with fgetpos() and fsetpos() (and _telli64(), and 64-bit tell()). _portable_ftell() and _portable_fseek() were written to hold the platform dependent logic. You are still restricted to 32-bits for single reads and writes. Previously _chsize was used blindly as the replacement for ftruncate() in Win32. In fact, _chsize() is not 64-bit capable so and appropriate overflow check was added. There are some type histrionics involved because off_t is only 32-bits on Win64. fpos_t is 64-bits, however, so fpos_t is used for Win64. As well, the patch adds some necessary overflow checks (raising OverflowError when an overflow is detected). See file_read for example. A forthcoming patch adds a test to the test suite for this largefile support. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Objects/fileobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/fileobject.c Thu Jun 1 13:53:50 2000 *************** *** 43,50 **** #endif #ifdef MS_WIN32 - #define ftruncate _chsize #define fileno _fileno #define HAVE_FTRUNCATE #endif --- 43,50 ---- #endif #ifdef MS_WIN32 #define fileno _fileno + /* can (almost fully) duplicate with _chsize, see file_truncate */ #define HAVE_FTRUNCATE #endif *************** *** 68,73 **** --- 68,79 ---- #include #endif + /* define the appropriate 64-bit capable tell() function */ + #ifdef MS_WIN64 + # define TELL64 _telli64 + #endif + + typedef struct { PyObject_HEAD FILE *f_fp; *************** *** 256,261 **** --- 262,338 ---- return Py_None; } + + /* a portable fseek() function + return 0 on success, non-zero on failure (with errno set) */ + int + _portable_fseek(fp, offset, whence) + FILE* fp; + #if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8 + fpos_t offset; + #else + off_t offset; + #endif + int whence; + { + #if defined(HAVE_FSEEKO) + return fseeko(fp, offset, whence); + #elif defined(HAVE_FSEEK64) + return fseek64(fp, offset, whence); + #elif defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_FPOS_T >= 8 + /* lacking a 64-bit capable fseek() (as Win64 does) use a 64-bit capable + fsetpos() and tell() to implement fseek()*/ + fpos_t pos; + switch (whence) { + case SEEK_CUR: + if (fgetpos(fp, &pos) != 0) + return -1; + offset += pos; + break; + case SEEK_END: + /* do a "no-op" seek first to sync the buffering so that + the low-level tell() can be used correctly */ + if (fseek(fp, 0, SEEK_END) != 0) + return -1; + if ((pos = TELL64(fileno(fp))) == -1L) + return -1; + offset += pos; + break; + /* case SEEK_SET: break; */ + } + return fsetpos(fp, &offset); + #else + return fseek(fp, offset, whence); + #endif + } + + + /* a portable ftell() function + Return -1 on failure with errno set appropriately, current file + position on success */ + #if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8 + fpos_t + #else + off_t + #endif + _portable_ftell(fp) + FILE* fp; + { + #if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT) + return ftello(fp); + #elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT) + return ftell64(fp); + #elif SIZEOF_FPOS_T >= 8 && defined(HAVE_LARGEFILE_SUPPORT) + fpos_t pos; + if (fgetpos(fp, &pos) != 0) + return -1; + return pos; + #else + return ftell(fp); + #endif + } + + static PyObject * file_seek(f, args) PyFileObject *f; *************** *** 263,269 **** --- 340,350 ---- { int whence; int ret; + #if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8 + fpos_t offset, pos; + #else off_t offset; + #endif /* !MS_WIN64 */ PyObject *offobj; if (f->f_fp == NULL) *************** *** 279,294 **** #endif if (PyErr_Occurred()) return NULL; Py_BEGIN_ALLOW_THREADS errno = 0; ! #if defined(HAVE_FSEEKO) ! ret = fseeko(f->f_fp, offset, whence); ! #elif defined(HAVE_FSEEK64) ! ret = fseek64(f->f_fp, offset, whence); ! #else ! ret = fseek(f->f_fp, offset, whence); ! #endif Py_END_ALLOW_THREADS if (ret != 0) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); --- 360,371 ---- #endif if (PyErr_Occurred()) return NULL; + Py_BEGIN_ALLOW_THREADS errno = 0; ! ret = _portable_fseek(f->f_fp, offset, whence); Py_END_ALLOW_THREADS + if (ret != 0) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); *************** *** 298,303 **** --- 375,381 ---- return Py_None; } + #ifdef HAVE_FTRUNCATE static PyObject * file_truncate(f, args) *************** *** 305,311 **** --- 383,393 ---- PyObject *args; { int ret; + #if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8 + fpos_t newsize; + #else off_t newsize; + #endif PyObject *newsizeobj; if (f->f_fp == NULL) *************** *** 327,339 **** /* Default to current position*/ Py_BEGIN_ALLOW_THREADS errno = 0; ! #if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT) ! newsize = ftello(f->f_fp); ! #elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT) ! newsize = ftell64(f->f_fp); ! #else ! newsize = ftell(f->f_fp); ! #endif Py_END_ALLOW_THREADS if (newsize == -1) { PyErr_SetFromErrno(PyExc_IOError); --- 409,415 ---- /* Default to current position*/ Py_BEGIN_ALLOW_THREADS errno = 0; ! newsize = _portable_ftell(f->f_fp); Py_END_ALLOW_THREADS if (newsize == -1) { PyErr_SetFromErrno(PyExc_IOError); *************** *** 345,363 **** errno = 0; ret = fflush(f->f_fp); Py_END_ALLOW_THREADS ! if (ret == 0) { ! Py_BEGIN_ALLOW_THREADS errno = 0; ! ret = ftruncate(fileno(f->f_fp), newsize); Py_END_ALLOW_THREADS } ! if (ret != 0) { ! PyErr_SetFromErrno(PyExc_IOError); ! clearerr(f->f_fp); ! return NULL; ! } Py_INCREF(Py_None); return Py_None; } #endif /* HAVE_FTRUNCATE */ --- 421,457 ---- errno = 0; ret = fflush(f->f_fp); Py_END_ALLOW_THREADS ! if (ret != 0) goto onioerror; ! ! #ifdef MS_WIN32 ! /* can use _chsize; if, however, the newsize overflows 32-bits then ! _chsize is *not* adequate; in this case, an OverflowError is raised */ ! if (newsize > LONG_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "the new size is too long for _chsize (it is limited to 32-bit values)"); ! return NULL; ! } else { ! Py_BEGIN_ALLOW_THREADS errno = 0; ! ret = _chsize(fileno(f->f_fp), newsize); Py_END_ALLOW_THREADS + if (ret != 0) goto onioerror; } ! #else ! Py_BEGIN_ALLOW_THREADS ! errno = 0; ! ret = ftruncate(fileno(f->f_fp), newsize); ! Py_END_ALLOW_THREADS ! if (ret != 0) goto onioerror; ! #endif /* !MS_WIN32 */ ! Py_INCREF(Py_None); return Py_None; + + onioerror: + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; } #endif /* HAVE_FTRUNCATE */ *************** *** 366,395 **** PyFileObject *f; PyObject *args; { ! off_t offset; if (f->f_fp == NULL) return err_closed(); if (!PyArg_NoArgs(args)) return NULL; Py_BEGIN_ALLOW_THREADS errno = 0; ! #if defined(HAVE_FTELLO) && defined(HAVE_LARGEFILE_SUPPORT) ! offset = ftello(f->f_fp); ! #elif defined(HAVE_FTELL64) && defined(HAVE_LARGEFILE_SUPPORT) ! offset = ftell64(f->f_fp); ! #else ! offset = ftell(f->f_fp); ! #endif Py_END_ALLOW_THREADS ! if (offset == -1) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); return NULL; } #if !defined(HAVE_LARGEFILE_SUPPORT) ! return PyInt_FromLong(offset); #else ! return PyLong_FromLongLong(offset); #endif } --- 460,488 ---- PyFileObject *f; PyObject *args; { ! #if defined(HAVE_LARGEFILE_SUPPORT) && SIZEOF_OFF_T < 8 && SIZEOF_FPOS_T >= 8 ! fpos_t pos; ! #else ! off_t pos; ! #endif ! if (f->f_fp == NULL) return err_closed(); if (!PyArg_NoArgs(args)) return NULL; Py_BEGIN_ALLOW_THREADS errno = 0; ! pos = _portable_ftell(f->f_fp); Py_END_ALLOW_THREADS ! if (pos == -1) { PyErr_SetFromErrno(PyExc_IOError); clearerr(f->f_fp); return NULL; } #if !defined(HAVE_LARGEFILE_SUPPORT) ! return PyInt_FromLong(pos); #else ! return PyLong_FromLongLong(pos); #endif } *************** *** 530,535 **** --- 623,633 ---- buffersize = new_buffersize(f, (size_t)0); else buffersize = bytesrequested; + if (buffersize > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "requested number of bytes is more than a Python string can hold"); + return NULL; + } v = PyString_FromStringAndSize((char *)NULL, buffersize); if (v == NULL) return NULL; *************** *** 568,574 **** PyObject *args; { char *ptr; ! int ntodo, ndone, nnow; if (f->f_fp == NULL) return err_closed(); --- 666,672 ---- PyObject *args; { char *ptr; ! size_t ntodo, ndone, nnow; if (f->f_fp == NULL) return err_closed(); *************** *** 590,596 **** ndone += nnow; ntodo -= nnow; } ! return PyInt_FromLong(ndone); } --- 688,694 ---- ndone += nnow; ntodo -= nnow; } ! return PyInt_FromLong((long)ndone); } *************** *** 609,615 **** register FILE *fp; register int c; register char *buf, *end; ! int n1, n2; PyObject *v; fp = f->f_fp; --- 707,713 ---- register FILE *fp; register int c; register char *buf, *end; ! size_t n1, n2; PyObject *v; fp = f->f_fp; *************** *** 648,653 **** --- 746,756 ---- break; n1 = n2; n2 += 1000; + if (n2 > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + return NULL; + } Py_BLOCK_THREADS if (_PyString_Resize(&v, n2) < 0) return NULL; *************** *** 793,798 **** --- 896,906 ---- /* Need a larger buffer to fit this line */ nfilled += nread; buffersize *= 2; + if (buffersize > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is too long for a Python string"); + goto error; + } if (big_buffer == NULL) { /* Create the big buffer */ big_buffer = PyString_FromStringAndSize( -- Trent Mick trentm@activestate.com From mhammond@skippinet.com.au Fri Jun 2 01:16:12 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 2 Jun 2000 10:16:12 +1000 Subject: [Patches] Windows Python project file hosed? Message-ID: Im not sure what happened, but the patch for "exceptions.c" had all its case screwed up, and MSVC refused to load the project for me. This solves the problem. diff -r1.4 python16.dsp 545c545 < !if "$(cfg)" == "python16 - win32 release" --- > !IF "$(CFG)" == "python16 - Win32 Release" 547c547 < !elseif "$(cfg)" == "python16 - win32 debug" --- > !ELSEIF "$(CFG)" == "python16 - Win32 Debug" 549c549 < !elseif "$(cfg)" == "python16 - win32 alpha debug" --- > !ELSEIF "$(CFG)" == "python16 - Win32 Alpha Debug" 551c551 < !elseif "$(cfg)" == "python16 - win32 alpha release" --- > !ELSEIF "$(CFG)" == "python16 - Win32 Alpha Release" 553c553 < !endif --- > !ENDIF 555,556c555,556 < # end source file < # begin source file --- > # End Source File > # Begin Source File Release info: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Mark. From trentm@activestate.com Fri Jun 2 02:29:01 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 18:29:01 -0700 Subject: [Patches] Windows Python project file hosed? In-Reply-To: References: Message-ID: <20000601182901.B24011@activestate.com> On Fri, Jun 02, 2000 at 10:16:12AM +1000, Mark Hammond wrote: > Im not sure what happened, but the patch for "exceptions.c" had all its > case screwed up, and MSVC refused to load the project for me. This solves > the problem. > Somehow that happened on my end when I was writing the email. Sorry about that. I don't know how it happened Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 02:48:39 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 18:48:39 -0700 Subject: [Patches] test largefile support (test_largefile.py) Message-ID: <20000601184839.A24306@activestate.com> Discussion: This patch adds a test for largefiles (creating, seeking, telling, etc.). The test skips if there is no largefile support. There is one further problem. The test basically involves creating a file greater than 2GB and playing with it. On UN*X systems with sparse files this is no problem. On Win64 (which I have heard *can* do sparse files, but not in Python yet), however, >2GB space and a *long* time is required to run the test. I don't think it is reasonable to turn this on by default... so here is what I did. I extended regrtest.py to accept the --have-resources switch. This sets test_support.use_large_resources, which is checked in test_largefile.py. By default 'use_large_resources' is false. On Win64, then, by default the largefile test is skipped but can be run via the --have-resources switch to regrtest.py or by running the test directly. This seems to me the Right Thing. The affected files are: Lib/test/regrtest.py Lib/test/test_support.py Lib/test/test_largefile.py (new) Lib/test/output/test_largefile (new) Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Lib/test/regrtest.py Thu Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/regrtest.py Thu Jun 1 16:11:30 2000 *************** *** 13,18 **** --- 13,19 ---- -g: generate -- write the output file for a test instead of comparing it -x: exclude -- arguments are tests to *exclude* -s: single -- run only a single test (see below) + --have-resources -- run tests that require large resources (time/space) If non-option arguments are present, they are names for tests to run, unless -x is given, in which case they are names for tests not to run. *************** *** 56,62 **** """ try: ! opts, args = getopt.getopt(sys.argv[1:], 'vgqxs') except getopt.error, msg: print msg print __doc__ --- 57,63 ---- """ try: ! opts, args = getopt.getopt(sys.argv[1:], 'vgqxs', ['have-resources']) except getopt.error, msg: print msg print __doc__ *************** *** 66,77 **** --- 67,80 ---- generate = 0 exclude = 0 single = 0 + use_large_resources = 0 for o, a in opts: if o == '-v': verbose = verbose+1 if o == '-q': quiet = 1; verbose = 0 if o == '-g': generate = 1 if o == '-x': exclude = 1 if o == '-s': single = 1 + if o == '--have-resources': use_large_resources = 1 if generate and verbose: print "-g and -v don't go together!" return 2 *************** *** 105,123 **** if single: tests = tests[:1] test_support.verbose = verbose # Tell tests to be moderately quiet save_modules = sys.modules.keys() for test in tests: if not quiet: print test ! ok = runtest(test, generate, verbose, testdir) if ok > 0: good.append(test) elif ok == 0: bad.append(test) else: - if not quiet: - print "test", test, - print "skipped -- an optional feature could not be imported" skipped.append(test) # Unload the newly imported modules (best effort finalization) for module in sys.modules.keys(): --- 108,124 ---- if single: tests = tests[:1] test_support.verbose = verbose # Tell tests to be moderately quiet + test_support.use_large_resources = use_large_resources save_modules = sys.modules.keys() for test in tests: if not quiet: print test ! ok = runtest(test, generate, verbose, quiet, testdir) if ok > 0: good.append(test) elif ok == 0: bad.append(test) else: skipped.append(test) # Unload the newly imported modules (best effort finalization) for module in sys.modules.keys(): *************** *** 178,189 **** tests.sort() return stdtests + tests ! def runtest(test, generate, verbose, testdir = None): """Run a single test. test -- the name of the test generate -- if true, generate output, instead of running the test and comparing it to a previously created output file verbose -- if true, print more messages testdir -- test directory """ test_support.unload(test) --- 179,191 ---- tests.sort() return stdtests + tests ! def runtest(test, generate, verbose, quiet, testdir = None): """Run a single test. test -- the name of the test generate -- if true, generate output, instead of running the test and comparing it to a previously created output file verbose -- if true, print more messages + quiet -- if true, don't print 'skipped' messages (probably redundant) testdir -- test directory """ test_support.unload(test) *************** *** 210,218 **** --- 212,225 ---- finally: sys.stdout = save_stdout except ImportError, msg: + if not quiet: + print "test", test, + print "skipped -- an optional feature could not be imported" return -1 except KeyboardInterrupt, v: raise KeyboardInterrupt, v, sys.exc_info()[2] + except test_support.TestSkipped, msg: + print "test", test, "skipped --", msg except test_support.TestFailed, msg: print "test", test, "failed --", msg return 0 *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_support.py Thu Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_support.py Thu Jun 1 15:52:04 2000 *************** *** 1,8 **** --- 1,10 ---- # Python test set -- supporting definitions. TestFailed = 'test_support -- test failed' # Exception + TestSkipped = 'test_support -- test skipped' # Exception verbose = 1 # Flag set to 0 by regrtest.py + use_large_resources = 1 # Flag set to 0 by regrtest.py def unload(name): import sys *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_largefile.py Thu Jun 1 18:30:28 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_largefile.py Thu Jun 1 17:25:23 2000 *************** *** 0 **** --- 1,129 ---- + #!python + + #---------------------------------------------------------------------- + # test largefile support on system where this makes sense + # + #XXX how to only run this when support is there + #XXX how to only optionally run this, it will take along time + #---------------------------------------------------------------------- + + import test_support + import os, struct, stat, sys + + + # only run if the current system support large files + f = open(test_support.TESTFN, 'w') + try: + # 2**31 == 2147483648 + f.seek(2147483649L) + except OverflowError: + raise test_support.TestSkipped, "platform does not have largefile support" + else: + f.close() + + + # create >2GB file (2GB = 2147483648 bytes) + size = 2500000000L + name = test_support.TESTFN + + + # on Windows this test comsumes large resources: + # it takes a long time to build the >2GB file and takes >2GB of disk space + # therefore test_support.use_large_resources must be defined to run this test + if sys.platform[:3] == 'win' and not test_support.use_large_resources: + raise test_support.TestSkipped, \ + "test requires %s bytes and a long time to run" % str(size) + + + + def expect(got_this, expect_this): + if test_support.verbose: + print '%s =?= %s ...' % (`got_this`, `expect_this`), + if got_this != expect_this: + if test_support.verbose: + print 'no' + raise test_support.TestFailed, 'got %s, but expected %s' %\ + (str(got_this), str(expect_this)) + else: + if test_support.verbose: + print 'yes' + + + # test that each file function works as expected for a large (i.e. >2GB, do + # we have to check >4GB) files + + if test_support.verbose: + print 'create large file via seek (may be sparse file) ...' + f = open(name, 'w') + f.seek(size) + f.write('a') + f.flush() + expect(os.fstat(f.fileno())[stat.ST_SIZE], size+1) + if test_support.verbose: + print 'check file size with os.fstat' + f.close() + if test_support.verbose: + print 'check file size with os.stat' + expect(os.stat(name)[stat.ST_SIZE], size+1) + + if test_support.verbose: + print 'play around with seek() and read() with the built largefile' + f = open(name, 'r') + expect(f.tell(), 0) + expect(f.read(1), '\000') + expect(f.tell(), 1) + f.seek(0) + expect(f.tell(), 0) + f.seek(0, 0) + expect(f.tell(), 0) + f.seek(42) + expect(f.tell(), 42) + f.seek(42, 0) + expect(f.tell(), 42) + f.seek(42, 1) + expect(f.tell(), 84) + f.seek(0, 1) + expect(f.tell(), 84) + f.seek(0, 2) # seek from the end + expect(f.tell(), size + 1 + 0) + f.seek(-10, 2) + expect(f.tell(), size + 1 - 10) + f.seek(-size-1, 2) + expect(f.tell(), 0) + f.seek(size) + expect(f.tell(), size) + expect(f.read(1), 'a') # the 'a' that was written at the end of the file above + f.close() + + if test_support.verbose: + print 'play around with os.lseek() with the built largefile' + f = open(name, 'r') + expect(os.lseek(f.fileno(), 0, 0), 0) + expect(os.lseek(f.fileno(), 42, 0), 42) + expect(os.lseek(f.fileno(), 42, 1), 84) + expect(os.lseek(f.fileno(), 0, 1), 84) + expect(os.lseek(f.fileno(), 0, 2), size+1+0) + expect(os.lseek(f.fileno(), -10, 2), size+1-10) + expect(os.lseek(f.fileno(), -size-1, 2), 0) + expect(os.lseek(f.fileno(), size, 0), size) + expect(f.read(1), 'a') # the 'a' that was written at the end of the file above + f.close() + + + # XXX add tests for truncate if it exists + # XXX has truncate ever worked on Windows? specifically on WinNT I get: + # "IOError: [Errno 13] Permission denied" + ##try: + ## newsize = size - 10 + ## f.seek(newsize) + ## f.truncate() + ## expect(f.tell(), newsize) + ## newsize = newsize - 1 + ## f.seek(0) + ## f.truncate(newsize) + ## expect(f.tell(), newsize) + ##except AttributeError: + ## pass + + os.unlink(name) + *** /home/trentm/main/contrib/python/dist/src/Lib/test/output/test_largefile Thu Jun 1 18:30:29 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/output/test_largefile Thu Jun 1 17:20:53 2000 *************** *** 0 **** --- 1 ---- + test_largefile -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 02:53:21 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 18:53:21 -0700 Subject: [Patches] fix timemodule.c for Win64 Message-ID: <20000601185321.B24306@activestate.com> Discussion: Mark Hammond provided (a long time ago) a better Win32 specific time_clock implementation in timemodule.c. The library for this implementation does not exist on Win64 (yet, at least). This patch makes Win64 fall back on the system's clock() function for time_clock(). Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/timemodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/timemodule.c Wed May 31 23:54:18 2000 *************** *** 89,99 **** #endif /* MS_WINDOWS */ #endif /* !__WATCOMC__ || __QNX__ */ ! #ifdef MS_WIN32 ! /* Win32 has better clock replacement */ #include #undef HAVE_CLOCK /* We have our own version down below */ ! #endif /* MS_WIN32 */ #if defined(PYCC_VACPP) #include --- 89,100 ---- #endif /* MS_WINDOWS */ #endif /* !__WATCOMC__ || __QNX__ */ ! #if defined(MS_WIN32) && !defined(MS_WIN64) ! /* Win32 has better clock replacement ! XXX Win64 does not yet, but might when the platform matures. */ #include #undef HAVE_CLOCK /* We have our own version down below */ ! #endif /* MS_WIN32 && !MS_WIN64 */ #if defined(PYCC_VACPP) #include *************** *** 190,196 **** } #endif /* HAVE_CLOCK */ ! #ifdef MS_WIN32 /* Due to Mark Hammond */ static PyObject * time_clock(self, args) --- 191,197 ---- } #endif /* HAVE_CLOCK */ ! #if defined(MS_WIN32) && !defined(MS_WIN64) /* Due to Mark Hammond */ static PyObject * time_clock(self, args) *************** *** 226,232 **** } #define HAVE_CLOCK /* So it gets included in the methods */ ! #endif /* MS_WIN32 */ #ifdef HAVE_CLOCK static char clock_doc[] = --- 227,233 ---- } #define HAVE_CLOCK /* So it gets included in the methods */ ! #endif /* MS_WIN32 && !MS_WIN64 */ #ifdef HAVE_CLOCK static char clock_doc[] = -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 03:22:13 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 19:22:13 -0700 Subject: [Patches] fix posixmodule for 64-bit systems (mainly Win64) Message-ID: <20000601192213.C24306@activestate.com> Discussion: This patch fixes the posix module for large file support mainly on Win64, although some general cleanup is done as well. The changes are: - abstract stat->STAT, fstat->FSTAT, and struct stat->STRUCT_STAT This is because stat() etc. are not the correct functions to use on Win64 (nor maybe on other platforms?, if not then it is now trivial to select the appropriate one). On Win64 the appropriate system functions are _stati64(), etc. - add _pystat_fromstructstat(), it builds the return tuple for the fstat system call. This functionality was being duplicated. As well the construction of the tuple was modified to ensure no overflow of the time_t elements (sizeof(time_t) > sizeof(long) on Win64). - add overflow protection for the return values of posix_spawnv and posix_spawnve - use the proper 64-bit capable lseek() on Win64 - use intptr_t instead of long where appropriate from Win32/64 blocks (sizeof(void*) > sizeof(long) on Win64) Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/posixmodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/posixmodule.c Wed May 31 23:54:18 2000 *************** *** 284,289 **** --- 283,300 ---- #define USE_TMPNAM_R #endif + /* choose the appropriate stat and fstat functions and return structs */ + #ifdef MS_WIN64 + # define STAT _stati64 + # define FSTAT _fstati64 + # define STRUCT_STAT struct _stati64 + #else + # define STAT stat + # define FSTAT fstat + # define STRUCT_STAT struct stat + #endif + + /* Return a dictionary corresponding to the POSIX environment table */ #if !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) ) *************** *** 539,552 **** return Py_None; } static PyObject * posix_do_stat(self, args, format, statfunc) PyObject *self; PyObject *args; char *format; ! int (*statfunc) Py_FPROTO((const char *, struct stat *)); { ! struct stat st; char *path; int res; --- 550,613 ---- return Py_None; } + + + /* pack a system stat C structure into the Python stat tuple + (used by posix_stat() and posix_fstat()) */ + static PyObject* + _pystat_fromstructstat(st) + STRUCT_STAT st; + { + PyObject *v = PyTuple_New(10); + if (v == NULL) + return NULL; + + PyTuple_SetItem(v, 0, PyInt_FromLong((long)st.st_mode)); + #ifdef HAVE_LARGEFILE_SUPPORT + PyTuple_SetItem(v, 1, PyLong_FromLongLong((LONG_LONG)st.st_ino)); + #else + PyTuple_SetItem(v, 1, PyInt_FromLong((long)st.st_ino)); + #endif + #if defined(HAVE_LONG_LONG) && !defined(MS_WINDOWS) + PyTuple_SetItem(v, 2, PyLong_FromLongLong((LONG_LONG)st.st_dev)); + #else + PyTuple_SetItem(v, 2, PyInt_FromLong((long)st.st_dev)); + #endif + PyTuple_SetItem(v, 3, PyInt_FromLong((long)st.st_nlink)); + PyTuple_SetItem(v, 4, PyInt_FromLong((long)st.st_uid)); + PyTuple_SetItem(v, 5, PyInt_FromLong((long)st.st_gid)); + #ifdef HAVE_LARGEFILE_SUPPORT + PyTuple_SetItem(v, 6, PyLong_FromLongLong((LONG_LONG)st.st_size)); + #else + PyTuple_SetItem(v, 6, PyInt_FromLong(st.st_size)); + #endif + #if SIZEOF_TIME_T > SIZEOF_LONG + PyTuple_SetItem(v, 7, PyLong_FromLongLong((LONG_LONG)st.st_atime)); + PyTuple_SetItem(v, 8, PyLong_FromLongLong((LONG_LONG)st.st_mtime)); + PyTuple_SetItem(v, 9, PyLong_FromLongLong((LONG_LONG)st.st_ctime)); + #else + PyTuple_SetItem(v, 7, PyInt_FromLong((long)st.st_atime)); + PyTuple_SetItem(v, 8, PyInt_FromLong((long)st.st_mtime)); + PyTuple_SetItem(v, 9, PyInt_FromLong((long)st.st_ctime)); + #endif + + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + + return v; + } + + static PyObject * posix_do_stat(self, args, format, statfunc) PyObject *self; PyObject *args; char *format; ! int (*statfunc) Py_FPROTO((const char *, STRUCT_STAT *)); { ! STRUCT_STAT st; char *path; int res; *************** *** 585,615 **** Py_END_ALLOW_THREADS if (res != 0) return posix_error_with_filename(path); ! #if !defined(HAVE_LARGEFILE_SUPPORT) ! return Py_BuildValue("(llllllllll)", ! (long)st.st_mode, ! (long)st.st_ino, ! (long)st.st_dev, ! (long)st.st_nlink, ! (long)st.st_uid, ! (long)st.st_gid, ! (long)st.st_size, ! (long)st.st_atime, ! (long)st.st_mtime, ! (long)st.st_ctime); ! #else ! return Py_BuildValue("(lLllllLlll)", ! (long)st.st_mode, ! (LONG_LONG)st.st_ino, ! (long)st.st_dev, ! (long)st.st_nlink, ! (long)st.st_uid, ! (long)st.st_gid, ! (LONG_LONG)st.st_size, ! (long)st.st_atime, ! (long)st.st_mtime, ! (long)st.st_ctime); ! #endif } --- 646,653 ---- Py_END_ALLOW_THREADS if (res != 0) return posix_error_with_filename(path); ! ! return _pystat_fromstructstat(st); } *************** *** 1158,1164 **** PyObject *self; PyObject *args; { ! return posix_do_stat(self, args, "s:stat", stat); } --- 1197,1203 ---- PyObject *self; PyObject *args; { ! return posix_do_stat(self, args, "s:stat", STAT); } *************** *** 1546,1551 **** --- 1585,1591 ---- PyObject *argv; char **argvlist; int mode, i, argc; + intptr_t spawnval; PyObject *(*getitem) Py_PROTO((PyObject *, int)); /* spawnv has three arguments: (mode, path, argv), where *************** *** 1580,1593 **** if (mode == _OLD_P_OVERLAY) mode = _P_OVERLAY; ! i = _spawnv(mode, path, argvlist); PyMem_DEL(argvlist); ! if (i == -1) return posix_error(); else ! return Py_BuildValue("i", i); } --- 1620,1637 ---- if (mode == _OLD_P_OVERLAY) mode = _P_OVERLAY; ! spawnval = _spawnv(mode, path, argvlist); PyMem_DEL(argvlist); ! if (spawnval == -1) return posix_error(); else ! #if SIZEOF_LONG == SIZE_VOID_P ! return Py_BuildValue("l", spawnval); ! #else ! return Py_BuildValue("L", spawnval); ! #endif } *************** *** 1611,1616 **** --- 1655,1661 ---- char **envlist; PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; int mode, i, pos, argc, envc; + intptr_t spawnval; PyObject *(*getitem) Py_PROTO((PyObject *, int)); /* spawnve has four arguments: (mode, path, argv, env), where *************** *** 1688,1698 **** if (mode == _OLD_P_OVERLAY) mode = _P_OVERLAY; ! i = _spawnve(mode, path, argvlist, envlist); ! if (i == -1) (void) posix_error(); else ! res = Py_BuildValue("i", i); fail_2: while (--envc >= 0) --- 1733,1747 ---- if (mode == _OLD_P_OVERLAY) mode = _P_OVERLAY; ! spawnval = _spawnve(mode, path, argvlist, envlist); ! if (spawnval == -1) (void) posix_error(); else ! #if SIZEOF_LONG == SIZE_VOID_P ! res = Py_BuildValue("l", spawnval); ! #else ! res = Py_BuildValue("L", spawnval); ! #endif fail_2: while (--envc >= 0) *************** *** 2269,2275 **** #ifdef HAVE_LSTAT return posix_do_stat(self, args, "s:lstat", lstat); #else /* !HAVE_LSTAT */ ! return posix_do_stat(self, args, "s:lstat", stat); #endif /* !HAVE_LSTAT */ } --- 2318,2324 ---- #ifdef HAVE_LSTAT return posix_do_stat(self, args, "s:lstat", lstat); #else /* !HAVE_LSTAT */ ! return posix_do_stat(self, args, "s:lstat", STAT); #endif /* !HAVE_LSTAT */ } *************** *** 2593,2599 **** --- 2642,2652 ---- PyObject *args; { int fd, how; + #ifdef MS_WIN64 + LONG_LONG pos, res; + #else off_t pos, res; + #endif PyObject *posobj; if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how)) return NULL; *************** *** 2616,2622 **** --- 2669,2679 ---- return NULL; Py_BEGIN_ALLOW_THREADS + #ifdef MS_WIN64 + res = _lseeki64(fd, pos, how); + #else res = lseek(fd, pos, how); + #endif Py_END_ALLOW_THREADS if (res < 0) return posix_error(); *************** *** 2690,2729 **** PyObject *args; { int fd; ! struct stat st; int res; if (!PyArg_ParseTuple(args, "i:fstat", &fd)) return NULL; Py_BEGIN_ALLOW_THREADS ! res = fstat(fd, &st); Py_END_ALLOW_THREADS if (res != 0) return posix_error(); ! #if !defined(HAVE_LARGEFILE_SUPPORT) ! return Py_BuildValue("(llllllllll)", ! (long)st.st_mode, ! (long)st.st_ino, ! (long)st.st_dev, ! (long)st.st_nlink, ! (long)st.st_uid, ! (long)st.st_gid, ! (long)st.st_size, ! (long)st.st_atime, ! (long)st.st_mtime, ! (long)st.st_ctime); ! #else ! return Py_BuildValue("(lLllllLlll)", ! (long)st.st_mode, ! (LONG_LONG)st.st_ino, ! (long)st.st_dev, ! (long)st.st_nlink, ! (long)st.st_uid, ! (long)st.st_gid, ! (LONG_LONG)st.st_size, ! (long)st.st_atime, ! (long)st.st_mtime, ! (long)st.st_ctime); ! #endif } --- 2747,2763 ---- PyObject *args; { int fd; ! STRUCT_STAT st; int res; if (!PyArg_ParseTuple(args, "i:fstat", &fd)) return NULL; Py_BEGIN_ALLOW_THREADS ! res = FSTAT(fd, &st); Py_END_ALLOW_THREADS if (res != 0) return posix_error(); ! ! return _pystat_fromstructstat(st); } *************** *** 2804,2811 **** Py_END_ALLOW_THREADS if (!ok) return posix_error(); ! read_fd = _open_osfhandle((long)read, 0); ! write_fd = _open_osfhandle((long)write, 1); return Py_BuildValue("(ii)", read_fd, write_fd); #endif /* MS_WIN32 */ #endif --- 2838,2845 ---- Py_END_ALLOW_THREADS if (!ok) return posix_error(); ! read_fd = _open_osfhandle((intptr_t)read, 0); ! write_fd = _open_osfhandle((intptr_t)write, 1); return Py_BuildValue("(ii)", read_fd, write_fd); #endif /* MS_WIN32 */ #endif *************** *** 3467,3475 **** } if (PyString_Check(arg)) { /* look up the value in the table using a binary search */ ! int lo = 0; ! int hi = tablesize; ! int cmp, mid; char *confname = PyString_AS_STRING(arg); while (lo < hi) { mid = (lo + hi) / 2; --- 3501,3510 ---- } if (PyString_Check(arg)) { /* look up the value in the table using a binary search */ ! size_t lo = 0; ! size_t mid; ! size_t hi = tablesize; ! int cmp; char *confname = PyString_AS_STRING(arg); while (lo < hi) { mid = (lo + hi) / 2; -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 03:33:13 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 19:33:13 -0700 Subject: [Patches] fix Sleep() overflow condition in time module Message-ID: <20000601193313.A24906@activestate.com> Discussion: This patch fixes a possible overflow in the Sleep system call on Win32/64 in the time_sleep() function in the time module. For very large values of the give time to sleep the number of milliseconds can overflow and give unexpected sleep intervals. THis patch raises an OverflowError if the value overflows. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/timemodule.c Thu Jun 1 18:49:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/timemodule.c Wed May 31 23:54:18 2000 *************** *** 835,844 **** } #else /* !MSDOS */ #ifdef MS_WIN32 ! /* XXX Can't interrupt this sleep */ ! Py_BEGIN_ALLOW_THREADS ! Sleep((int)(secs*1000)); ! Py_END_ALLOW_THREADS #else /* !MS_WIN32 */ #ifdef PYOS_OS2 /* This Sleep *IS* Interruptable by Exceptions */ --- 835,851 ---- } #else /* !MSDOS */ #ifdef MS_WIN32 ! { ! double millisecs = secs * 1000.0; ! if (millisecs > (double)ULONG_MAX) { ! PyErr_SetString(PyExc_OverflowError, "sleep length is too large"); ! return -1; ! } ! /* XXX Can't interrupt this sleep */ ! Py_BEGIN_ALLOW_THREADS ! Sleep((unsigned long)millisecs); ! Py_END_ALLOW_THREADS ! } #else /* !MS_WIN32 */ #ifdef PYOS_OS2 /* This Sleep *IS* Interruptable by Exceptions */ -- Trent Mick trentm@activestate.com From jeremy@beopen.com Fri Jun 2 03:35:16 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Thu, 1 Jun 2000 22:35:16 -0400 (EDT) Subject: [Patches] Windows Python project file hosed? In-Reply-To: <20000601182901.B24011@activestate.com> References: <20000601182901.B24011@activestate.com> Message-ID: <14647.7524.652212.324806@localhost.localdomain> Oops. I noticed that the case was different, but checked it without actually testing. I'll be more careful in the future. Jeremy From trentm@activestate.com Fri Jun 2 04:02:08 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 20:02:08 -0700 Subject: [Patches] fix mmap module (borken seek, 64-bit stuff, overflows) Message-ID: <20000601200208.A25330@activestate.com> Discussion: This patch fixes some issues in the mmap module. The changes are: - The use of HFILE for Win32 is no longer appropriate for Win32/64, all of the associated system calls use a pointer length integer, hence HFILE is replaced with INT_PTR (a Windows world typedef for this) - Do proper bounds checking limiting the length of a mmap'd file to [0, INT_MAX] (see _GetMapSize()). INT_MAX is chosen because this is the current restriction on the length of Python objects and a mmap'd file larger than this cannot be used effectively anyway. For instance a mmap'd file longer than INT_MAX cannot be sliced beyond INT_MAX, or indexed, etc. Until the limit on the size of Python objects increases then there is little use in having larger mmap'd files. - The mmap_seek is fairly significantly broken (seeking from the current position or from the end are both borken, IIRC). This patch fixes that, checks for possible out of range seek values, and extends test_mmap.py to test this stuff. - Use a C int for variables associated with the length field of Python objects, this is what it is and the distinction matters on Linux64, for example. - Use safe number literals. (some unsigned)0xFFFFFFFF -> (some unsigned)-1 The former does not give the intended result iff 'some unsigned' is > 32-bits. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/mmapmodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/mmapmodule.c Wed May 31 23:54:18 2000 *************** *** 44,50 **** #ifdef MS_WIN32 HANDLE map_handle; ! HFILE file_handle; char * tagname; #endif --- 44,50 ---- #ifdef MS_WIN32 HANDLE map_handle; ! INT_PTR file_handle; char * tagname; #endif *************** *** 118,124 **** char value; char * where; CHECK_VALID(NULL); ! if (self->pos >= 0 && self->pos < self->size) { where = self->data + self->pos; value = (char) *(where); self->pos += 1; --- 118,124 ---- char value; char * where; CHECK_VALID(NULL); ! if (self->pos < self->size) { where = self->data + self->pos; value = (char) *(where); self->pos += 1; *************** *** 146,152 **** else ++eol; /* we're interested in the position after the newline. */ ! result = PyString_FromStringAndSize(start, (long) (eol - start)); self->pos += (eol - start); return (result); } --- 146,152 ---- else ++eol; /* we're interested in the position after the newline. */ ! result = PyString_FromStringAndSize(start, (int) (eol - start)); self->pos += (eol - start); return (result); } *************** *** 175,186 **** mmap_find_method (mmap_object *self, PyObject *args) { ! long start = self->pos; char * needle; int len; CHECK_VALID(NULL); ! if (!PyArg_ParseTuple (args, "s#|l", &needle, &len, &start)) { return NULL; } else { char * p = self->data+self->pos; --- 175,186 ---- mmap_find_method (mmap_object *self, PyObject *args) { ! int start = self->pos; char * needle; int len; CHECK_VALID(NULL); ! if (!PyArg_ParseTuple (args, "s#|i", &needle, &len, &start)) { return NULL; } else { char * p = self->data+self->pos; *************** *** 193,200 **** } if (!*n) { return Py_BuildValue ( ! "l", ! (long) (p - (self->data + start))); } p++; } --- 193,200 ---- } if (!*n) { return Py_BuildValue ( ! "i", ! (int) (p - (self->data + start))); } p++; } *************** *** 246,252 **** CHECK_VALID(NULL); #ifdef MS_WIN32 ! if (self->file_handle != (HFILE) 0xFFFFFFFF) { return (Py_BuildValue ( "l", GetFileSize ((HANDLE)self->file_handle, NULL))); --- 246,252 ---- CHECK_VALID(NULL); #ifdef MS_WIN32 ! if (self->file_handle != (INT_PTR) -1) { return (Py_BuildValue ( "l", GetFileSize ((HANDLE)self->file_handle, NULL))); *************** *** 383,421 **** static PyObject * mmap_seek_method (mmap_object * self, PyObject * args) { ! /* ptrdiff_t dist; */ ! long dist; int how=0; CHECK_VALID(NULL); ! if (!PyArg_ParseTuple (args, "l|i", &dist, &how)) { return(NULL); } else { ! unsigned long where; switch (how) { ! case 0: where = dist; break; ! case 1: where = self->pos + dist; break; ! case 2: ! where = self->size - dist; break; default: PyErr_SetString (PyExc_ValueError, "unknown seek type"); return NULL; } ! if ((where >= 0) && (where < (self->size))) { ! self->pos = where; ! Py_INCREF (Py_None); ! return (Py_None); ! } else { ! PyErr_SetString (PyExc_ValueError, ! "seek out of range"); ! return NULL; ! } } } static PyObject * --- 383,426 ---- static PyObject * mmap_seek_method (mmap_object * self, PyObject * args) { ! int dist; int how=0; CHECK_VALID(NULL); ! if (!PyArg_ParseTuple (args, "i|i", &dist, &how)) { return(NULL); } else { ! size_t where; switch (how) { ! case 0: /* relative to start */ ! if (dist < 0) ! goto onoutofrange; where = dist; break; ! case 1: /* relative to current position */ ! if ((int)self->pos + dist < 0) ! goto onoutofrange; where = self->pos + dist; break; ! case 2: /* relative to end */ ! if ((int)self->size + dist < 0) ! goto onoutofrange; ! where = self->size + dist; break; default: PyErr_SetString (PyExc_ValueError, "unknown seek type"); return NULL; } ! if (where > self->size) ! goto onoutofrange; ! self->pos = where; ! Py_INCREF (Py_None); ! return (Py_None); } + + onoutofrange: + PyErr_SetString (PyExc_ValueError, "seek out of range"); + return NULL; } static PyObject * *************** *** 689,711 **** 0, /*tp_doc*/ }; #ifdef UNIX static PyObject * new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict) { mmap_object * m_obj; ! unsigned long map_size; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; char * filename; int namelen; char *keywords[] = {"file", "size", "flags", "prot", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, ! "il|ii", keywords, ! &fd, &map_size, &flags, &prot) ) return NULL; ! m_obj = PyObject_New (mmap_object, &mmap_object_type); if (m_obj == NULL) {return NULL;} m_obj->size = (size_t) map_size; --- 694,777 ---- 0, /*tp_doc*/ }; + + /* extract the map size from the given PyObject + + The map size is restricted to [0, INT_MAX] because this is the current + Python limitation on object sizes. Although the mmap object *could* handle + a larger map size, there is no point because all the useful operations + (len(), slicing(), sequence indexing) are limited by a C int. + + Returns -1 on error, with an apprpriate Python exception raised. On + success, the map size is returned. */ + static int + _GetMapSize(o) + PyObject *o; + { + if (PyInt_Check(o)) { + long i = PyInt_AsLong(o); + if (PyErr_Occurred()) + return -1; + if (i < 0) + goto onnegoverflow; + if (i > INT_MAX) + goto onposoverflow; + return (int)i; + } + else if (PyLong_Check(o)) { + long i = PyLong_AsLong(o); + if (PyErr_Occurred()) { + /* yes negative overflow is mistaken for positive overflow + but not worth the trouble to check sign of 'i' */ + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + goto onposoverflow; + else + return -1; + } + if (i < 0) + goto onnegoverflow; + if (i > INT_MAX) + goto onposoverflow; + return (int)i; + } + else { + PyErr_SetString(PyExc_TypeError, + "map size must be an integral value"); + return -1; + } + + onnegoverflow: + PyErr_SetString(PyExc_OverflowError, + "memory mapped size must be positive"); + return -1; + + onposoverflow: + PyErr_SetString(PyExc_OverflowError, + "memory mapped size is too large (limited by C int)"); + return -1; + } + #ifdef UNIX static PyObject * new_mmap_object (PyObject * self, PyObject * args, PyObject *kwdict) { mmap_object * m_obj; ! PyObject *map_size_obj = NULL; ! int map_size; int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; char * filename; int namelen; char *keywords[] = {"file", "size", "flags", "prot", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, ! "iO|ii", keywords, ! &fd, &map_size_obj, &flags, &prot) ) return NULL; ! map_size = _GetMapSize(map_size_obj); ! if (map_size < 0) ! return NULL; ! m_obj = PyObject_New (mmap_object, &mmap_object_type); if (m_obj == NULL) {return NULL;} m_obj->size = (size_t) map_size; *************** *** 728,751 **** new_mmap_object (PyObject * self, PyObject * args) { mmap_object * m_obj; ! unsigned long map_size; char * tagname = ""; DWORD dwErr = 0; int fileno; ! HFILE fh = 0; /* Patch the object type */ mmap_object_type.ob_type = &PyType_Type; if (!PyArg_ParseTuple(args, ! "il|z", &fileno, ! &map_size, &tagname) ) return NULL; /* if an actual filename has been specified */ if (fileno != 0) { fh = _get_osfhandle(fileno); --- 794,822 ---- new_mmap_object (PyObject * self, PyObject * args) { mmap_object * m_obj; ! PyObject *map_size_obj = NULL; ! int map_size; char * tagname = ""; DWORD dwErr = 0; int fileno; ! INT_PTR fh = 0; /* Patch the object type */ mmap_object_type.ob_type = &PyType_Type; if (!PyArg_ParseTuple(args, ! "iO|z", &fileno, ! &map_size_obj, &tagname) ) return NULL; + map_size = _GetMapSize(map_size_obj); + if (map_size < 0) + return NULL; + /* if an actual filename has been specified */ if (fileno != 0) { fh = _get_osfhandle(fileno); *************** *** 768,774 **** } } else { ! m_obj->file_handle = (HFILE) 0xFFFFFFFF; m_obj->size = map_size; } --- 839,845 ---- } } else { ! m_obj->file_handle = (INT_PTR) -1; m_obj->size = map_size; } *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_mmap.py Thu Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_mmap.py Wed May 31 23:54:16 2000 *************** *** 58,64 **** assert start == PAGESIZE assert end == PAGESIZE + 6 ! m.close() os.unlink("foo") print ' Test passed' --- 58,99 ---- assert start == PAGESIZE assert end == PAGESIZE + 6 ! ! # test seeking around (try to overflow the seek implementation) ! m.seek(0,0) ! print ' Seek to zeroth byte' ! assert m.tell() == 0 ! m.seek(42,1) ! print ' Seek to 42nd byte' ! assert m.tell() == 42 ! m.seek(0,2) ! print ' Seek to last byte' ! assert m.tell() == len(m) ! ! print ' Try to seek to negative position...' ! try: ! m.seek(-1) ! except ValueError: ! pass ! else: ! assert 0, 'expected a ValueError but did not get it' ! ! print ' Try to seek beyond end of mmap...' ! try: ! m.seek(1,2) ! except ValueError: ! pass ! else: ! assert 0, 'expected a ValueError but did not get it' ! ! print ' Try to seek to negative position...' ! try: ! m.seek(-len(m)-1,2) ! except ValueError: ! pass ! else: ! assert 0, 'expected a ValueError but did not get it' ! m.close() os.unlink("foo") print ' Test passed' -- Trent Mick trentm@activestate.com From mhammond@skippinet.com.au Fri Jun 2 04:04:11 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 2 Jun 2000 13:04:11 +1000 Subject: [Patches] Windows Python project file hosed? In-Reply-To: <14647.7524.652212.324806@localhost.localdomain> Message-ID: To be honest, I would rather see checkins from certain people (including myself and Trent :-) happen even if you dont have the ability to test the change. Id rather keep the turnover rate of patches high and occasionaly deal with a little problem like this... Mark. > -----Original Message----- > From: patches-admin@python.org [mailto:patches-admin@python.org]On > Behalf Of Jeremy Hylton > Sent: Friday, 2 June 2000 12:35 PM > To: Trent Mick > Cc: Mark Hammond; patches@python.org > Subject: Re: [Patches] Windows Python project file hosed? > > > Oops. I noticed that the case was different, but checked it without > actually testing. I'll be more careful in the future. > > Jeremy > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches > From trentm@activestate.com Fri Jun 2 04:12:21 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 20:12:21 -0700 Subject: [Patches] Windows Python project file hosed? In-Reply-To: References: <14647.7524.652212.324806@localhost.localdomain> Message-ID: <20000601201221.B25330@activestate.com> On Fri, Jun 02, 2000 at 01:04:11PM +1000, Mark Hammond wrote: > To be honest, I would rather see checkins from certain people (including > myself and Trent :-) happen even if you dont have the ability to test the > change. Id rather keep the turnover rate of patches high and occasionaly > deal with a little problem like this... I agree, but of course I look fairly biased given all the patches I am submitting today. I certainly hope the patches for Win64 don't have to wait until someone at CNRI^H^H^H^HBeOpen gets an Itanium box to test it on. :) Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 04:15:32 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 20:15:32 -0700 Subject: [Patches] fix mmap module (borken seek, 64-bit stuff, overflows) In-Reply-To: <20000601200208.A25330@activestate.com> References: <20000601200208.A25330@activestate.com> Message-ID: <20000601201532.C25330@activestate.com> On Thu, Jun 01, 2000 at 08:02:08PM -0700, Trent Mick wrote: > This patch fixes that, > checks for possible out of range seek values, and extends test_mmap.py = to > test this stuff. Oops, forgot to add the changes to Lib/test/output/test_mmap, without which test_mmap.py fails on comparison. Here it is: Patch: *** /home/trentm/main/contrib/python/dist/src/Lib/test/output/test_mmap Thu= Jun 1 00:13:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/output/test_mma= p Wed May 31 23:54:16 2000 *************** *** 9,12 **** --- 9,18 ---- Contents of first 3 bytes: '3\000\000' Contents of second page: =00foobar=00 Regex match on mmap (page start, length of match): 1.0 6 + Seek to zeroth byte + Seek to 42nd byte + Seek to last byte + Try to seek to negative position... + Try to seek beyond end of mmap... + Try to seek to negative position... Test passed Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. --=20 Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 04:47:57 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 1 Jun 2000 20:47:57 -0700 Subject: [Patches] fix up msvcrtmodule.c and winreg.c for Win64 Message-ID: <20000601204757.A26332@activestate.com> Discussion: Fix PC/msvcrtmodule.c and PC/winreg.c for Win64. Basically: - sizeof(HKEY) > sizeof(long) on Win64, so use PyLong_FromVoidPtr() instead of PyInt_FromLong() to return HKEY values on Win64 - Check for string overflow of an arbitrary registry value (I know that ensuring that a registry value does not overflow 2**31 characters seems ridiculous but it is *possible*). Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/PC/msvcrtmodule.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/msvcrtmodule.c Wed May 31 23:54:19 2000 *************** *** 90,96 **** static PyObject *msvcrt_get_osfhandle(PyObject *self, PyObject *args) { int fd; ! long handle; if (!PyArg_ParseTuple(args,"i:get_osfhandle", &fd)) return NULL; --- 90,96 ---- static PyObject *msvcrt_get_osfhandle(PyObject *self, PyObject *args) { int fd; ! intptr_t handle; if (!PyArg_ParseTuple(args,"i:get_osfhandle", &fd)) return NULL; *************** *** 99,105 **** if (handle == -1) return PyErr_SetFromErrno(PyExc_IOError); ! return PyInt_FromLong(handle); } /* Console I/O */ --- 99,108 ---- if (handle == -1) return PyErr_SetFromErrno(PyExc_IOError); ! /* technically 'handle' is not a pointer, but a integer as ! large as a pointer, Python's *VoidPtr interface is the ! most appropriate here */ ! return PyLong_FromVoidPtr((void*)handle); } /* Console I/O */ *** /home/trentm/main/contrib/python/dist/src/PC/winreg.c Thu Jun 1 01:02:33 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/winreg.c Wed May 31 23:54:20 2000 *************** *** 590,596 **** *pHANDLE = (HKEY)PyLong_AsVoidPtr(ob); if (PyErr_Occurred()) return FALSE; - *pHANDLE = (HKEY)PyInt_AsLong(ob); } else { PyErr_SetString( --- 590,595 ---- *************** *** 626,637 **** --- 625,645 ---- if (PyHKEY_Check(obHandle)) { ok = PyHKEY_Close(obHandle); } + #if SIZEOF_LONG >= SIZEOF_HKEY else if (PyInt_Check(obHandle)) { long rc = RegCloseKey((HKEY)PyInt_AsLong(obHandle)); ok = (rc == ERROR_SUCCESS); if (!ok) PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); } + #else + else if (PyLong_Check(obHandle)) { + long rc = RegCloseKey((HKEY)PyLong_AsVoidPtr(obHandle)); + ok = (rc == ERROR_SUCCESS); + if (!ok) + PyErr_SetFromWindowsErrWithFunction(rc, "RegCloseKey"); + } + #endif else { PyErr_SetString( PyExc_TypeError, *************** *** 878,890 **** fixupMultiSZ(str, retDataBuf, retDataSize); obData = PyList_New(s); for (index = 0; index < s; index++) { PyList_SetItem(obData, index, PyUnicode_DecodeMBCS( (const char *)str[index], ! _mbstrlen(str[index]), NULL) ); } --- 886,907 ---- fixupMultiSZ(str, retDataBuf, retDataSize); obData = PyList_New(s); + if (obData == NULL) + return NULL; for (index = 0; index < s; index++) { + size_t len = _mbstrlen(str[index]); + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "registry string is too long for a Python string"); + Py_DECREF(obData); + return NULL; + } PyList_SetItem(obData, index, PyUnicode_DecodeMBCS( (const char *)str[index], ! (int)len, NULL) ); } -- Trent Mick trentm@activestate.com From loewis@informatik.hu-berlin.de Fri Jun 2 08:01:41 2000 From: loewis@informatik.hu-berlin.de (Martin von Loewis) Date: Fri, 2 Jun 2000 09:01:41 +0200 (MET DST) Subject: [Patches] Translating doc strings Message-ID: <200006020701.JAA28620@pandora> --Multipart_Fri_Jun__2_09:01:40_2000-1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable To simplify usage of Python for people who don't speak English well, I'd like to start a project translating the doc strings in the Python library. This has two aspects: 1. there must be a simple way to access the translated doc strings 2. there must be actual translations to the various native languages of Python users. Since the second task is much more complicated, I submit a snapshot of this project, namely, a message catalog of the doc strings in the Python libraries, taken from the CVS; along with a snapshot of the German translations. I intend to complete the German translations in the coming weeks, but I want to give other translators a chance to also start working on that. Please note that extracting the docstrings was not straight-forward; I've used Fran=E7ois Pinard's most excellent po-utils 0.5 as a starting point, and enhanced it with the capability to recognize __doc__[] in C code, so that I would also get (most of) the doc strings in C modules. I plan to update this catalog a few times before Python 1.6 is released, so that translators can update their translations. A key point is finding translators. I propose to use the infrastructure of the GNU translation project for that: There are established teams for all major languages, and an infrastructure (also maintained by Fran=E7ois) where notifications about new catalogs are automatically distributed to the teams. That should not stop volunteers which don't currently participate in the GNU translation project from translating - however, they should announce that they plan to work on translating these messages to avoid duplication of work. Another matter is where the catalogs should live in the Python source tree. I propose to have a Misc/po directory, which will contain both the PO catalogues, as well as the binary .mo objects; only the latter will be installed during the installation process. Please let me know what you think, in particular, whether I can submit the catalog to the translation teams. Regards, Martin --Multipart_Fri_Jun__2_09:01:40_2000-1 Content-Type: application/octet-stream; type=tar+gzip Content-Disposition: attachment; filename="doc.tgz" Content-Transfer-Encoding: base64 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 98ep4HyPBtN3aHWWEn2a6ReOk0HwKZcpwn08hi0jXYfh9i+kCzT1KFy1Ql5FcLZ+VmXHTn1/i3YE wRvu3tg+n+HxS6qybEbCMC6tre5r1iDT+bni5PDeUexWQFlodK0gEqN7m0RdPjAM94fJOpmjjXVr 9jxWFtlEhpmkzSTl1hzJMGadUVt3RJzttFy7c1PbG/bfg5Fjtw63RSM5ztO12P8ykC1dI867xamR ixOdkqZKxS4vfsDkSPDgorzR5W4eFXSNvN921WYAX5InQjcWL15fHByLmjtACVF11nfD68HWcdQz zzgi3HdIPCtcirBBx2ypAaTf0OgtO6najjDIBcBvN1o2/v7WP/0KxTqcN6Ty6v2tLX/0/a2R+mDS BRMXn4ZTG+NHo/L36ShU6MrsGo9rrFJXAJ8g6TRcYYHwPucpfQ7vmzvLlNwozSK4To2VRPQL39v1 p2OIk3JvbQk3DHI9U6pdITVgGmluBXcnPrgLK6bvTNkZ5IvFjcspgHwSk4usuSb/tYlwFIMPNfso kDq/Me+SX7hdGa1YkX9zlTUB2QSpWCQE5KdrEMkHg0MS8d6+Ow2cmfxhnp3P5mTx0pSTsnBSVXzY nQmJRiFqmWwCJ6bI05wBeSMa8um9e3A5EwGhMQpkEQPD58lcz4zxrqdkLyp6HwRjDNTlmzZybWSP RVzIBWn9t9Z565wBOZ2v7NQF83UuHG1vW/WsLrqP8nzj+WnPol3hgCft0IYX2meQ81EfOStvo/d9 RnKviwsVGL0nhxNs5TPXm1SNn8RxfS/SpVYwAEz1bB2U0jVUU6a+js4NCuNc5Y0X8y5gIfkXcAJ0 Ek2LD+X6g7ipWd8+5bbLOfL3kybbbLlybYjRXb5KtzTY3iCBTRupZkt3QP/XXd2TPd0EuJsKicVI gAxav05apcYoOxl0EugdpojieALH1al8PsXmptt32DqgxEA1gwmJli8bJxiZAgPMtyHWTyoootMF +kqol6nrzuCbj1N7+W5VG3e1LmeJvj7SfgluNM0J7wRXeT4pmx+tOU0j35fjuT5LzIm5G9PpvjMu v8s2iJd6iWl5344xRXowpfzCbvzFB7E5e72P4t4ISNMXoT5n8wUiVEb6ufN8FOsJqQQzt6l0Aus7 dXwG5HbrKWPiNdmzxF07SbonbeDVk29fvnj+9t00hw5F2/5GI7nGFp1sekXYSg2A0vo5AvrsI//7 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 --Multipart_Fri_Jun__2_09:01:40_2000-1-- From trentm@activestate.com Fri Jun 2 08:15:53 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 00:15:53 -0700 Subject: [Patches] changes to configure.in and PC/config.h for 64-bit systems In-Reply-To: <20000601131412.B9463@activestate.com> References: <20000601131412.B9463@activestate.com> Message-ID: <20000602001552.A3205@activestate.com> On Thu, Jun 01, 2000 at 01:14:12PM -0700, Trent Mick wrote: > Discussion: > > This patch extends PC/config.h and configure.in as appropriate for 64-bit > readiness (the config values are needed for patches that I will be submitting > later today. The changes are as follows: > Oops, in the previous patch for PC/config.h and configure.in I forgot to submit changes to acconfig.h as well. This provides the changes to acconfig.h to #define SIZEOF_TIME_T and SIZEOF_FPOS_T in config.h. The changes to the regenerated 'config.h.in' (via autoheader) are included as well. If you would rather, I can submit the whole patch (for all the config system files) together. NOTE: About the HAVE_SYS_SOCKET_H addition in config.h.in: I presume that is coming from a newer version of autoheader or a different environment for it on my machine. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/acconfig.h Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/acconfig.h Wed May 31 23:54:21 2000 *************** *** 151,156 **** --- 151,159 ---- /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T + /* The number of bytes in a time_t. */ + #undef SIZEOF_TIME_T + /* Defined to enable large file support when an off_t is bigger than a long and long long is available and at least as big as an off_t. You may need to add some flags for configuration and compilation to enable this mode. *** /home/trentm/main/contrib/python/dist/src/config.h.in Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/config.h.in Thu Jun 1 23:42:08 2000 *************** *** 213,218 **** --- 213,221 ---- /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T + /* The number of bytes in a time_t. */ + #undef SIZEOF_TIME_T + /* Defined to enable large file support when an off_t is bigger than a long and long long is available and at least as big as an off_t. You may need to add some flags for configuration and compilation to enable this mode. *************** *** 234,239 **** --- 237,245 ---- /* The number of bytes in a float. */ #undef SIZEOF_FLOAT + /* The number of bytes in a fpos_t. */ + #undef SIZEOF_FPOS_T + /* The number of bytes in a int. */ #undef SIZEOF_INT *************** *** 527,532 **** --- 533,541 ---- /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H + + /* Define if you have the header file. */ + #undef HAVE_SYS_SOCKET_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 08:50:06 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 00:50:06 -0700 Subject: [Patches] fix socket module for 64-bits (mostly Win64) Message-ID: <20000602005006.A8849@activestate.com> Discussion: This patch fixes possible overflows in the socket module for 64-bit platforms (mainly Win64). The changes are: - abstract the socket type to SOCKET_T (this is SOCKET on Windows, int on Un*x), this is necessary because sizeof(SOCKET) > sizeof(int) on Win64 - use INVALID_SOCKET on Win32/64 for an error return value for accept() - ensure no overflow of the socket variable for: (1) a PyObject return value (use PyLong_FromLongLong if necessary); and (2) printf formatting in repr() Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Modules/socketmodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/socketmodule.c Fri Jun 2 00:31:44 2000 *************** *** 221,226 **** --- 221,240 ---- #define FORCE_ANSI_FUNC_DEFS #endif + /* abstract the socket file descriptor type */ + #ifdef MS_WINDOWS + typedef SOCKET SOCKET_T; + # ifdef MS_WIN64 + # define SIZEOF_SOCKET_T 8 + # else + # define SIZEOF_SOCKET_T 4 + # endif + #else + typedef int SOCKET_T; + # define SIZEOF_SOCKET_T SIZEOF_INT + #endif + + #if defined(PYOS_OS2) #define SOCKETCLOSE soclose #define NO_DUP /* Sockets are Not Actual File Handles under OS/2 */ *************** *** 337,343 **** typedef struct { PyObject_HEAD ! int sock_fd; /* Socket file descriptor */ int sock_family; /* Address family, e.g., AF_INET */ int sock_type; /* Socket type, e.g., SOCK_STREAM */ int sock_proto; /* Protocol type, usually 0 */ --- 351,357 ---- typedef struct { PyObject_HEAD ! SOCKET_T sock_fd; /* Socket file descriptor */ int sock_family; /* Address family, e.g., AF_INET */ int sock_type; /* Socket type, e.g., SOCK_STREAM */ int sock_proto; /* Protocol type, usually 0 */ *************** *** 387,393 **** in NEWOBJ()). */ static PySocketSockObject * ! BUILD_FUNC_DEF_4(PySocketSock_New,int,fd, int,family, int,type, int,proto) { PySocketSockObject *s; PySocketSock_Type.ob_type = &PyType_Type; --- 401,407 ---- in NEWOBJ()). */ static PySocketSockObject * ! BUILD_FUNC_DEF_4(PySocketSock_New,SOCKET_T,fd, int,family, int,type, int,proto) { PySocketSockObject *s; PySocketSock_Type.ob_type = &PyType_Type; *************** *** 666,672 **** BUILD_FUNC_DEF_2(PySocketSock_accept,PySocketSockObject *,s, PyObject *,args) { char addrbuf[256]; ! int newfd; socklen_t addrlen; PyObject *sock = NULL; PyObject *addr = NULL; --- 680,686 ---- BUILD_FUNC_DEF_2(PySocketSock_accept,PySocketSockObject *,s, PyObject *,args) { char addrbuf[256]; ! SOCKET_T newfd; socklen_t addrlen; PyObject *sock = NULL; PyObject *addr = NULL; *************** *** 679,685 **** --- 693,703 ---- Py_BEGIN_ALLOW_THREADS newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen); Py_END_ALLOW_THREADS + #ifdef MS_WINDOWS + if (newfd == INVALID_SOCKET) + #else if (newfd < 0) + #endif return PySocket_Err(); /* Create the new object with unspecified family, *************** *** 968,974 **** --- 986,996 ---- { if (!PyArg_ParseTuple(args, ":fileno")) return NULL; + #if SIZEOF_SOCKET_T <= SIZEOF_LONG return PyInt_FromLong((long) s->sock_fd); + #else + return PyLong_FromLongLong((LONG_LONG)s->sock_fd); + #endif } static char fileno_doc[] = *************** *** 983,989 **** static PyObject * BUILD_FUNC_DEF_2(PySocketSock_dup,PySocketSockObject *,s, PyObject *,args) { ! int newfd; PyObject *sock; if (!PyArg_ParseTuple(args, ":dup")) return NULL; --- 1005,1011 ---- static PyObject * BUILD_FUNC_DEF_2(PySocketSock_dup,PySocketSockObject *,s, PyObject *,args) { ! SOCKET_T newfd; PyObject *sock; if (!PyArg_ParseTuple(args, ":dup")) return NULL; *************** *** 1109,1115 **** --- 1131,1141 ---- extern int fclose Py_PROTO((FILE *)); char *mode = "r"; int bufsize = -1; + #ifdef MS_WIN32 + intptr_t fd; + #else int fd; + #endif FILE *fp; PyObject *f; *************** *** 1387,1395 **** BUILD_FUNC_DEF_1(PySocketSock_repr,PySocketSockObject *,s) { char buf[512]; sprintf(buf, ! "", ! s->sock_fd, s->sock_family, s->sock_type, s->sock_proto); return PyString_FromString(buf); } --- 1413,1431 ---- BUILD_FUNC_DEF_1(PySocketSock_repr,PySocketSockObject *,s) { char buf[512]; + #if SIZEOF_SOCKET_T > SIZEOF_LONG + if (s->sock_fd > LONG_MAX) { + /* this can occur on Win64, and actually there is a special + ugly printf formatter for decimal pointer length integer + printing, only bother if necessary*/ + PyErr_SetString(PyExc_OverflowError, + "no printf formatter to display the socket descriptor in decimal"); + return NULL; + } + #endif sprintf(buf, ! "", ! (long)s->sock_fd, s->sock_family, s->sock_type, s->sock_proto); return PyString_FromString(buf); } *************** *** 1716,1726 **** BUILD_FUNC_DEF_2(PySocket_socket,PyObject *,self, PyObject *,args) { PySocketSockObject *s; ! #ifdef MS_WINDOWS ! SOCKET fd; ! #else ! int fd; ! #endif int family, type, proto = 0; if (!PyArg_ParseTuple(args, "ii|i:socket", &family, &type, &proto)) return NULL; --- 1752,1758 ---- BUILD_FUNC_DEF_2(PySocket_socket,PyObject *,self, PyObject *,args) { PySocketSockObject *s; ! SOCKET_T fd; int family, type, proto = 0; if (!PyArg_ParseTuple(args, "ii|i:socket", &family, &type, &proto)) return NULL; *************** *** 1766,1772 **** BUILD_FUNC_DEF_2(PySocket_fromfd,PyObject *,self, PyObject *,args) { PySocketSockObject *s; ! int fd, family, type, proto = 0; if (!PyArg_ParseTuple(args, "iii|i:fromfd", &fd, &family, &type, &proto)) return NULL; --- 1798,1805 ---- BUILD_FUNC_DEF_2(PySocket_fromfd,PyObject *,self, PyObject *,args) { PySocketSockObject *s; ! SOCKET_T fd; ! int family, type, proto = 0; if (!PyArg_ParseTuple(args, "iii|i:fromfd", &fd, &family, &type, &proto)) return NULL; *************** *** 2113,2119 **** static PyObject *SSL_SSLwrite(SSLObject *self, PyObject *args) { char *data; ! int len = 0; if (!PyArg_ParseTuple(args, "s|i:write", &data, &len)) return NULL; --- 2146,2152 ---- static PyObject *SSL_SSLwrite(SSLObject *self, PyObject *args) { char *data; ! size_t len = 0; if (!PyArg_ParseTuple(args, "s|i:write", &data, &len)) return NULL; -- Trent Mick trentm@activestate.com From mal@lemburg.com Fri Jun 2 09:53:13 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 02 Jun 2000 10:53:13 +0200 Subject: [Patches] Fix for bug PR#341 References: <392FEED2.90E262CB@lemburg.com> <200005301513.KAA06165@cj20424-a.reston1.va.home.com> <20000530113910.H18024@activestate.com> <20000601023428.B23428@activestate.com> Message-ID: <393775F9.9E734DF8@lemburg.com> Trent Mick wrote: > > Discussion: > > This patch fixes the string formatting overflow problem. It tries to do a > little better than MAL's magic nunumber (50) check. If this looks good then I > can do the same for unicodeobject.c > > [Tim P on MAL's original patch] > > but I'll join Fred in objecting to the code > > it's mimicking: not only do magic numbers suck, but these particular magic > > numbers implicitly rely on PyString_Format's tmpbuf vector being declared of > > another magical size larger than them. As usual, flaky code gets flakier. > > My patch still uses the magic number for the temporary buffer. This seems to me > a good practical limit. With the patch this buffer can no longer overflow (as > well, it is faster than malloc'ing a perfect sized buffer every time). > > [MAL] > > A redesign would, of course, use a malloced buffer, the n-variants > > of printf() and add long support ;-) ... maybe for 1.7. > > No long support in this patch :( > > [Guido on MAL's original patch] > > Having read the patch and the discussion about magic numbers, I agree > > with Marc-Andre: let's apply the quick fix now, worry about > > correctness later. > > Maybe this patch is preferable. Yep. The patch doesn't yet address the general case (use malloc etc.), but makes things a little more flexbile. (Even though I find some tests size_t vs. INT_MAX overkill -- noone will store 2GB strings in memory ;-) > int sign; > int len; > ! #define TMPBUFLEN (size_t)120 > ! char tmpbuf[TMPBUFLEN]; /* For format{float,int,char}() */ > char *fmt_start = fmt; You should move this #define outside of the function for better visibility (and perhaps add a comment). > fmt++; > *************** > *** 2618,2624 **** > if (c == 'i') > c = 'd'; > buf = tmpbuf; > ! len = formatint(buf, flags, prec, c, v); > if (len < 0) > goto error; > sign = (c == 'd'); > --- 2653,2659 ---- > if (c == 'i') > c = 'd'; > buf = tmpbuf; > ! len = formatint(buf, TMPBUFLEN, flags, prec, c, v); All of these direct references to TMPBUFLEN should be changed to sizeof(buf) for clarity. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From mal@lemburg.com Fri Jun 2 12:53:10 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 02 Jun 2000 13:53:10 +0200 Subject: [Patches] Fix for bug PR#341 References: <392FEED2.90E262CB@lemburg.com> <200005301513.KAA06165@cj20424-a.reston1.va.home.com> <20000530113910.H18024@activestate.com> <20000601023428.B23428@activestate.com> Message-ID: <3937A026.19A8EA4D@lemburg.com> [Trent's patch to fix the %d formatting buffer overflow problem] I just noted that the patch is only for stringobject.c. Could you submit the same patch for unicodeobject.c too (it uses more or less the same code for formatting) ? -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From mal@lemburg.com Fri Jun 2 13:57:06 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 02 Jun 2000 14:57:06 +0200 Subject: [Patches] Unicode patch set 2000-06-02 Message-ID: <3937AF22.3B55C125@lemburg.com> This is a multi-part message in MIME format. --------------BEC51DD4A0A70FF5B2F902AD Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit This patch set moves the Unicode implementation into the direction put forward in the recent default encoding discussions on python-dev. Discussion: ----------- The patch implements the new strategy to use ASCII as default encoding assumption whenever 8-bit strings and Unicode meet. Strings are assumed to be encoded in 7-bit ASCII when being coerced to Unicode. Characters having the top bit set will cause an exception to be raised. To enhance flexibility and provide better means of customization, the patch adds to this default setting the ability to set the default encoding depending on the current locale set on the machine running Python. The locale.py module was extended with a locale aliasing engine which not only knows about many commonly used locale names, but also defines default encodings for these. The default encoding is now set according to the values obtained from the locale.py get_default() API in site.py. If no locale is set or the locale is unkown, site.py will again default to ASCII. All of the above in accordance with Guido's proposal to choose ASCII as default encoding and to complement this default with locale awareness. Note that the global is not a per thread setting -- it may only be modified in site.py. Patch Set Contents: ------------------- Modules/Setup.in: The locale module is turned on per default. Objects/unicodeobject.c: Change the default encoding to 'ascii' (it was previously defined as UTF-8). Note: The implementation still uses UTF-8 to implement the buffer protocol, so C APIs will still see UTF-8. This is on purpose: rather than fixing the Unicode implementation, the C APIs should be made Unicode aware. Python/sysmodule.c: Changed the API names for setting the default encoding. These are now in line with the other hooks API names (no underscores). Lib/encodings/aliases.py: Added some more codec aliases. Some of them are needed by the new locale.py encoding support. Lib/encodings/undefined.py: New codec which always raises an exception when used. This codec can be used to effectively switch off string coercion to Unicode. Lib/locale.py: New locale name aliasing engine by Marc-André Lemburg (mal@lemburg.com). The engine also supports specifying locale encodings, a feature which is used by the new default encoding support in site.py. Lib/site.py: Added support to set the default encoding of strings at startup time to the values defined by the C locale. The sys.setdefaultencoding() API is deleted after having set up the encoding, so that user code cannot subsequentely change the setting. This effectively means that only site.py may alter the default setting. _____________________________________________________________________ License Transfer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ --------------BEC51DD4A0A70FF5B2F902AD Content-Type: text/plain; charset=us-ascii; name="Unicode-Implementation-2000-06-02.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Unicode-Implementation-2000-06-02.patch" Only in CVS-Python: .cvsignore diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Modules/Setup.in Python+Unicode/Modules/Setup.in --- CVS-Python/Modules/Setup.in Thu May 4 00:34:12 2000 +++ Python+Unicode/Modules/Setup.in Sat May 27 18:21:46 2000 @@ -140,7 +140,7 @@ unicodedata unicodedata.c unicodedatabase.c # static Unicode character database -#_locale _localemodule.c # access to ISO C locale support +_locale _localemodule.c # access to ISO C locale support # Modules with some UNIX dependencies -- on by default: diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Objects/unicodeobject.c Python+Unicode/Objects/unicodeobject.c --- CVS-Python/Objects/unicodeobject.c Tue May 9 21:54:43 2000 +++ Python+Unicode/Objects/unicodeobject.c Fri Jun 2 13:54:42 2000 @@ -4710,7 +4710,7 @@ /* Init the implementation */ unicode_empty = _PyUnicode_New(0); - strcpy(unicode_default_encoding, "utf-8"); + strcpy(unicode_default_encoding, "ascii"); } /* Finalize the Unicode implementation */ diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Python/sysmodule.c Python+Unicode/Python/sysmodule.c --- CVS-Python/Python/sysmodule.c Tue May 9 21:57:01 2000 +++ Python+Unicode/Python/sysmodule.c Fri Jun 2 13:56:18 2000 @@ -143,28 +143,28 @@ exit status will be one (i.e., failure)."; static PyObject * -sys_get_string_encoding(self, args) +sys_getdefaultencoding(self, args) PyObject *self; PyObject *args; { - if (!PyArg_ParseTuple(args, ":get_string_encoding")) + if (!PyArg_ParseTuple(args, ":getdefaultencoding")) return NULL; return PyString_FromString(PyUnicode_GetDefaultEncoding()); } -static char get_string_encoding_doc[] = -"get_string_encoding() -> string\n\ +static char getdefaultencoding_doc[] = +"getdefaultencoding() -> string\n\ \n\ Return the current default string encoding used by the Unicode \n\ implementation."; static PyObject * -sys_set_string_encoding(self, args) +sys_setdefaultencoding(self, args) PyObject *self; PyObject *args; { char *encoding; - if (!PyArg_ParseTuple(args, "s:set_string_encoding", &encoding)) + if (!PyArg_ParseTuple(args, "s:setdefaultencoding", &encoding)) return NULL; if (PyUnicode_SetDefaultEncoding(encoding)) return NULL; @@ -172,8 +172,8 @@ return Py_None; } -static char set_string_encoding_doc[] = -"set_string_encoding(encoding)\n\ +static char setdefaultencoding_doc[] = +"setdefaultencoding(encoding)\n\ \n\ Set the current default string encoding used by the Unicode implementation."; @@ -301,7 +301,7 @@ /* Might as well keep this in alphabetic order */ {"exc_info", sys_exc_info, 1, exc_info_doc}, {"exit", sys_exit, 0, exit_doc}, - {"get_string_encoding", sys_get_string_encoding, 1, get_string_encoding_doc}, + {"getdefaultencoding", sys_getdefaultencoding, 1, getdefaultencoding_doc}, #ifdef COUNT_ALLOCS {"getcounts", sys_getcounts, 1}, #endif @@ -315,7 +315,7 @@ #ifdef USE_MALLOPT {"mdebug", sys_mdebug, 1}, #endif - {"set_string_encoding", sys_set_string_encoding, 1, set_string_encoding_doc}, + {"setdefaultencoding", sys_setdefaultencoding, 1, setdefaultencoding_doc}, {"setcheckinterval", sys_setcheckinterval, 1, setcheckinterval_doc}, {"setprofile", sys_setprofile, 0, setprofile_doc}, {"settrace", sys_settrace, 0, settrace_doc}, Only in CVS-Python: .cvsignore diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/encodings/aliases.py Python+Unicode/Lib/encodings/aliases.py --- CVS-Python/Lib/encodings/aliases.py Wed Apr 5 22:11:18 2000 +++ Python+Unicode/Lib/encodings/aliases.py Tue May 30 19:52:23 2000 @@ -18,6 +18,8 @@ 'utf': 'utf_8', 'utf8': 'utf_8', 'u8': 'utf_8', + 'utf8@ucs2': 'utf_8', + 'utf8@ucs4': 'utf_8', # UTF-16 'utf16': 'utf_16', @@ -31,6 +33,8 @@ 'us_ascii': 'ascii', # ISO + '8859': 'latin_1', + 'iso8859': 'latin_1', 'iso8859_1': 'latin_1', 'iso_8859_1': 'latin_1', 'iso_8859_10': 'iso8859_10', @@ -47,6 +51,7 @@ 'iso_8859_9': 'iso8859_9', # Mac + 'maclatin2': 'mac_latin2', 'maccentraleurope': 'mac_latin2', 'maccyrillic': 'mac_cyrillic', 'macgreek': 'mac_greek', @@ -56,5 +61,22 @@ # MBCS 'dbcs': 'mbcs', + + # Code pages + '437': 'cp437', + + # CJK + # + # The codecs for these encodings are not distributed with the + # Python core, but are included here for reference, since the + # locale module relies on having these aliases available. + # + 'jis_7': 'jis_7', + 'iso_2022_jp': 'jis_7', + 'ujis': 'euc_jp', + 'ajec': 'euc_jp', + 'eucjp': 'euc_jp', + 'tis260': 'tactis', + 'sjis': 'shift_jis', } diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/encodings/undefined.py Python+Unicode/Lib/encodings/undefined.py --- CVS-Python/Lib/encodings/undefined.py Thu Jan 1 01:00:00 1970 +++ Python+Unicode/Lib/encodings/undefined.py Sat May 27 18:14:23 2000 @@ -0,0 +1,34 @@ +""" Python 'undefined' Codec + + This codec will always raise a ValueError exception when being + used. It is intended for use by the site.py file to switch off + automatic string to Unicode coercion. + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +(c) Copyright CNRI, All Rights Reserved. NO WARRANTY. + +""" +import codecs + +### Codec APIs + +class Codec(codecs.Codec): + + def encode(self,input,errors='strict'): + raise UnicodeError, "undefined encoding" + + def decode(self,input,errors='strict'): + raise UnicodeError, "undefined encoding" + +class StreamWriter(Codec,codecs.StreamWriter): + pass + +class StreamReader(Codec,codecs.StreamReader): + pass + +### encodings module API + +def getregentry(): + + return (Codec().encode,Codec().decode,StreamReader,StreamWriter) diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/locale.py Python+Unicode/Lib/locale.py --- CVS-Python/Lib/locale.py Fri Feb 4 16:39:29 2000 +++ Python+Unicode/Lib/locale.py Fri Jun 2 14:28:00 2000 @@ -1,10 +1,26 @@ -"""Support for number formatting using the current locale settings.""" +""" Locale support. -# Author: Martin von Loewis + The module provides low-level access to the C lib's locale APIs + and adds high level number formatting APIs as well as a locale + aliasing engine to complement these. + + The aliasing engine includes support for many commonly used locale + names and maps them to values suitable for passing to the C lib's + setlocale() function. It also includes default encodings for all + supported locale names. + +""" -from _locale import * import string +### C lib locale APIs + +from _locale import * + +### Number formatting APIs + +# Author: Martin von Loewis + #perform the grouping from right to left def _group(s): conv=localeconv() @@ -25,7 +41,9 @@ else: result=s[-group:] s=s[:-group] - if s and result: + if not result: + return s + if s: result=s+conv['thousands_sep']+result return result @@ -34,7 +52,7 @@ but takes the current locale into account. Grouping is applied if the third parameter is true.""" result = f % val - fields = string.splitfields(result,".") + fields = string.split(result, ".") if grouping: fields[0]=_group(fields[0]) if len(fields)==2: @@ -51,11 +69,15 @@ def atof(str,func=string.atof): "Parses a string as a float according to the locale settings." #First, get rid of the grouping - s=string.splitfields(str,localeconv()['thousands_sep']) - str=string.join(s,"") + ts = localeconv()['thousands_sep'] + if ts: + s=string.split(str,ts) + str=string.join(s, "") #next, replace the decimal point with a dot - s=string.splitfields(str,localeconv()['decimal_point']) - str=string.join(s,'.') + dd = localeconv()['decimal_point'] + if dd: + s=string.split(str,dd) + str=string.join(s,'.') #finally, parse the string return func(str) @@ -63,7 +85,7 @@ "Converts a string to an integer according to the locale settings." return atof(str,string.atoi) -def test(): +def _test(): setlocale(LC_ALL,"") #do grouping s1=format("%d",123456789,1) @@ -71,7 +93,479 @@ #standard formatting s1=str(3.14) print s1,"is",atof(s1) + +### Locale name aliasing engine + +# Author: Marc-Andre Lemburg, mal@lemburg.com + +def normalize(localename): + + """ Returns a normalized locale code for the given locale + name. + + The returned locale code is formatted for use with + setlocale(). + + If normalization fails, the original name is returned + unchanged. + + If the given encoding is not known, the function defaults to + the default encoding for the locale code just like setlocale() + does. + + """ + # Normalize the locale name and extract the encoding + fullname = string.lower(localename) + if ':' in fullname: + # ':' is sometimes used as encoding delimiter. + fullname = string.replace(fullname, ':', '.') + if '.' in fullname: + langname, encoding = string.split(fullname, '.')[:2] + fullname = langname + '.' + encoding + else: + langname = fullname + encoding = '' + + # First lookup: fullname (possibly with encoding) + code = locale_alias.get(fullname, None) + if code is not None: + return code + + # Second try: langname (without encoding) + code = locale_alias.get(langname, None) + if code is not None: + if '.' in code: + langname, defenc = string.split(code, '.') + else: + langname = code + defenc = '' + if encoding: + encoding = encoding_alias.get(encoding, encoding) + else: + encoding = defenc + if encoding: + return langname + '.' + encoding + else: + return langname + + else: + return localename + +def _parse_localename(localename): + + """ Parses the locale code for localename and returns the + result as tuple (language code, encoding). + + The localename is normalized and passed through the locale + alias engine. A ValueError is raised in case the locale name + cannot be parsed. + + The language code corresponds to RFC 1766. code and encoding + can be None in case the values cannot be determined or are + unkown to this implementation. + + """ + code = normalize(localename) + if '.' in code: + return string.split(code, '.')[:2] + elif code == 'C': + return None, None + else: + raise ValueError,'unkown locale: %s' % localename + return l + +def _build_localename(localetuple): + + """ Builds a locale code from the given tuple (language code, + encoding). + + No aliasing or normalizing takes place. + + """ + language, encoding = localetuple + if language is None: + language = 'C' + if encoding is None: + return language + else: + return language + '.' + encoding + +def get_default(envvars=('LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG')): + + """ Tries to determine the default locale settings and returns + them as tuple (language code, encoding). + + According to POSIX, a program which has not called + setlocale(LC_ALL,"") runs using the portable 'C' locale. + Calling setlocale(LC_ALL,"") lets it use the default locale as + defined by the LANG variable. Since we don't want to interfere + with the current locale setting we thus emulate the behaviour + in the way described above. + + To maintain compatibility with other platforms, not only the + LANG variable is tested, but a list of variables given as + envvars parameter. The first found to be defined will be + used. envvars defaults to the search path used in GNU gettext; + it must always contain the variable name 'LANG'. + + Except for the code 'C', the language code corresponds to RFC + 1766. code and encoding can be None in case the values cannot + be determined. + + """ + import os + lookup = os.environ.get + for variable in envvars: + localename = lookup(variable,None) + if localename is not None: + break + else: + localename = 'C' + return _parse_localename(localename) + +def get_locale(category=LC_CTYPE): + + """ Returns the current setting for the given locale category as + tuple (language code, encoding). + + category may be one of the LC_* value except LC_ALL. It + defaults to LC_CTYPE. + + Except for the code 'C', the language code corresponds to RFC + 1766. code and encoding can be None in case the values cannot + be determined. + + """ + localename = setlocale(category) + if category == LC_ALL and ';' in localename: + raise TypeError,'category LC_ALL is not supported' + return _parse_localename(localename) + +def set_locale(localetuple, category=LC_ALL): + + """ Set the locale according to the localetuple (language code, + encoding) as returned by get_locale() and get_default(). + + The given codes are passed through the locale aliasing engine + before being given to setlocale() for processing. + + category may be given as one of the LC_* values. It defaults + to LC_ALL. + + """ + setlocale(category, normalize(_build_localename(localetuple))) + +def set_to_default(category=LC_ALL): + + """ Sets the locale for category to the default setting. + + The default setting is determined by calling + get_default(). category defaults to LC_ALL. + + """ + setlocale(category, _build_localename(get_default())) + +### Database +# +# The following data was extracted from the locale.alias file which +# comes with X11 and then hand edited removing the explicit encoding +# definitions and adding some more aliases. The file is usually +# available as /usr/lib/X11/locale/locale.alias. +# + +# +# The encoding_alias table maps lowercase encoding alias names to C +# locale encoding names (case-sensitive). +# +encoding_alias = { + '437': 'C', + 'c': 'C', + 'iso8859': 'ISO8859-1', + '8859': 'ISO8859-1', + '88591': 'ISO8859-1', + 'ascii': 'ISO8859-1', + 'en': 'ISO8859-1', + 'iso88591': 'ISO8859-1', + 'iso_8859-1': 'ISO8859-1', + '885915': 'ISO8859-15', + 'iso885915': 'ISO8859-15', + 'iso_8859-15': 'ISO8859-15', + 'iso8859-2': 'ISO8859-2', + 'iso88592': 'ISO8859-2', + 'iso_8859-2': 'ISO8859-2', + 'iso88595': 'ISO8859-5', + 'iso88596': 'ISO8859-6', + 'iso88597': 'ISO8859-7', + 'iso88598': 'ISO8859-8', + 'iso88599': 'ISO8859-9', + 'iso-2022-jp': 'JIS7', + 'jis': 'JIS7', + 'jis7': 'JIS7', + 'sjis': 'SJIS', + 'tis620': 'TACTIS', + 'ajec': 'eucJP', + 'eucjp': 'eucJP', + 'ujis': 'eucJP', + 'utf-8': 'utf', + 'utf8': 'utf', + 'utf8@ucs4': 'utf', +} + +# +# The locale_alias table maps lowercase alias names to C locale names +# (case-sensitive). Encodings are always separated from the locale +# name using a dot ('.'); they should only be given in case the +# language name is needed to interpret the given encoding alias +# correctly (CJK codes often have this need). +# +locale_alias = { + 'american': 'en_US.ISO8859-1', + 'ar': 'ar_AA.ISO8859-6', + 'ar_aa': 'ar_AA.ISO8859-6', + 'ar_sa': 'ar_SA.ISO8859-6', + 'arabic': 'ar_AA.ISO8859-6', + 'bg': 'bg_BG.ISO8859-5', + 'bg_bg': 'bg_BG.ISO8859-5', + 'bulgarian': 'bg_BG.ISO8859-5', + 'c-french': 'fr_CA.ISO8859-1', + 'c': 'C', + 'c_c': 'C', + 'cextend': 'en_US.ISO8859-1', + 'chinese-s': 'zh_CN.eucCN', + 'chinese-t': 'zh_TW.eucTW', + 'croatian': 'hr_HR.ISO8859-2', + 'cs': 'cs_CZ.ISO8859-2', + 'cs_cs': 'cs_CZ.ISO8859-2', + 'cs_cz': 'cs_CZ.ISO8859-2', + 'cz': 'cz_CZ.ISO8859-2', + 'cz_cz': 'cz_CZ.ISO8859-2', + 'czech': 'cs_CS.ISO8859-2', + 'da': 'da_DK.ISO8859-1', + 'da_dk': 'da_DK.ISO8859-1', + 'danish': 'da_DK.ISO8859-1', + 'de': 'de_DE.ISO8859-1', + 'de_at': 'de_AT.ISO8859-1', + 'de_ch': 'de_CH.ISO8859-1', + 'de_de': 'de_DE.ISO8859-1', + 'dutch': 'nl_BE.ISO8859-1', + 'ee': 'ee_EE.ISO8859-4', + 'el': 'el_GR.ISO8859-7', + 'el_gr': 'el_GR.ISO8859-7', + 'en': 'en_US.ISO8859-1', + 'en_au': 'en_AU.ISO8859-1', + 'en_ca': 'en_CA.ISO8859-1', + 'en_gb': 'en_GB.ISO8859-1', + 'en_ie': 'en_IE.ISO8859-1', + 'en_nz': 'en_NZ.ISO8859-1', + 'en_uk': 'en_GB.ISO8859-1', + 'en_us': 'en_US.ISO8859-1', + 'eng_gb': 'en_GB.ISO8859-1', + 'english': 'en_EN.ISO8859-1', + 'english_uk': 'en_GB.ISO8859-1', + 'english_united-states': 'en_US.ISO8859-1', + 'english_us': 'en_US.ISO8859-1', + 'es': 'es_ES.ISO8859-1', + 'es_ar': 'es_AR.ISO8859-1', + 'es_bo': 'es_BO.ISO8859-1', + 'es_cl': 'es_CL.ISO8859-1', + 'es_co': 'es_CO.ISO8859-1', + 'es_cr': 'es_CR.ISO8859-1', + 'es_ec': 'es_EC.ISO8859-1', + 'es_es': 'es_ES.ISO8859-1', + 'es_gt': 'es_GT.ISO8859-1', + 'es_mx': 'es_MX.ISO8859-1', + 'es_ni': 'es_NI.ISO8859-1', + 'es_pa': 'es_PA.ISO8859-1', + 'es_pe': 'es_PE.ISO8859-1', + 'es_py': 'es_PY.ISO8859-1', + 'es_sv': 'es_SV.ISO8859-1', + 'es_uy': 'es_UY.ISO8859-1', + 'es_ve': 'es_VE.ISO8859-1', + 'et': 'et_EE.ISO8859-4', + 'et_ee': 'et_EE.ISO8859-4', + 'fi': 'fi_FI.ISO8859-1', + 'fi_fi': 'fi_FI.ISO8859-1', + 'finnish': 'fi_FI.ISO8859-1', + 'fr': 'fr_FR.ISO8859-1', + 'fr_be': 'fr_BE.ISO8859-1', + 'fr_ca': 'fr_CA.ISO8859-1', + 'fr_ch': 'fr_CH.ISO8859-1', + 'fr_fr': 'fr_FR.ISO8859-1', + 'fre_fr': 'fr_FR.ISO8859-1', + 'french': 'fr_FR.ISO8859-1', + 'french_france': 'fr_FR.ISO8859-1', + 'ger_de': 'de_DE.ISO8859-1', + 'german': 'de_DE.ISO8859-1', + 'german_germany': 'de_DE.ISO8859-1', + 'greek': 'el_GR.ISO8859-7', + 'hebrew': 'iw_IL.ISO8859-8', + 'hr': 'hr_HR.ISO8859-2', + 'hr_hr': 'hr_HR.ISO8859-2', + 'hu': 'hu_HU.ISO8859-2', + 'hu_hu': 'hu_HU.ISO8859-2', + 'hungarian': 'hu_HU.ISO8859-2', + 'icelandic': 'is_IS.ISO8859-1', + 'id': 'id_ID.ISO8859-1', + 'id_id': 'id_ID.ISO8859-1', + 'is': 'is_IS.ISO8859-1', + 'is_is': 'is_IS.ISO8859-1', + 'iso-8859-1': 'en_US.ISO8859-1', + 'iso-8859-15': 'en_US.ISO8859-15', + 'iso8859-1': 'en_US.ISO8859-1', + 'iso8859-15': 'en_US.ISO8859-15', + 'iso_8859_1': 'en_US.ISO8859-1', + 'iso_8859_15': 'en_US.ISO8859-15', + 'it': 'it_IT.ISO8859-1', + 'it_ch': 'it_CH.ISO8859-1', + 'it_it': 'it_IT.ISO8859-1', + 'italian': 'it_IT.ISO8859-1', + 'iw': 'iw_IL.ISO8859-8', + 'iw_il': 'iw_IL.ISO8859-8', + 'ja': 'ja_JP.eucJP', + 'ja.jis': 'ja_JP.JIS7', + 'ja.sjis': 'ja_JP.SJIS', + 'ja_jp': 'ja_JP.eucJP', + 'ja_jp.ajec': 'ja_JP.eucJP', + 'ja_jp.euc': 'ja_JP.eucJP', + 'ja_jp.eucjp': 'ja_JP.eucJP', + 'ja_jp.iso-2022-jp': 'ja_JP.JIS7', + 'ja_jp.jis': 'ja_JP.JIS7', + 'ja_jp.jis7': 'ja_JP.JIS7', + 'ja_jp.mscode': 'ja_JP.SJIS', + 'ja_jp.sjis': 'ja_JP.SJIS', + 'ja_jp.ujis': 'ja_JP.eucJP', + 'japan': 'ja_JP.eucJP', + 'japanese': 'ja_JP.SJIS', + 'japanese-euc': 'ja_JP.eucJP', + 'japanese.euc': 'ja_JP.eucJP', + 'jp_jp': 'ja_JP.eucJP', + 'ko': 'ko_KR.eucKR', + 'ko_kr': 'ko_KR.eucKR', + 'ko_kr.euc': 'ko_KR.eucKR', + 'korean': 'ko_KR.eucKR', + 'lt': 'lt_LT.ISO8859-4', + 'lv': 'lv_LV.ISO8859-4', + 'mk': 'mk_MK.ISO8859-5', + 'mk_mk': 'mk_MK.ISO8859-5', + 'nl': 'nl_NL.ISO8859-1', + 'nl_be': 'nl_BE.ISO8859-1', + 'nl_nl': 'nl_NL.ISO8859-1', + 'no': 'no_NO.ISO8859-1', + 'no_no': 'no_NO.ISO8859-1', + 'norwegian': 'no_NO.ISO8859-1', + 'pl': 'pl_PL.ISO8859-2', + 'pl_pl': 'pl_PL.ISO8859-2', + 'polish': 'pl_PL.ISO8859-2', + 'portuguese': 'pt_PT.ISO8859-1', + 'portuguese_brazil': 'pt_BR.ISO8859-1', + 'posix': 'C', + 'posix-utf2': 'C', + 'pt': 'pt_PT.ISO8859-1', + 'pt_br': 'pt_BR.ISO8859-1', + 'pt_pt': 'pt_PT.ISO8859-1', + 'ro': 'ro_RO.ISO8859-2', + 'ro_ro': 'ro_RO.ISO8859-2', + 'ru': 'ru_RU.ISO8859-5', + 'ru_ru': 'ru_RU.ISO8859-5', + 'rumanian': 'ro_RO.ISO8859-2', + 'russian': 'ru_RU.ISO8859-5', + 'serbocroatian': 'sh_YU.ISO8859-2', + 'sh': 'sh_YU.ISO8859-2', + 'sh_hr': 'sh_HR.ISO8859-2', + 'sh_sp': 'sh_YU.ISO8859-2', + 'sh_yu': 'sh_YU.ISO8859-2', + 'sk': 'sk_SK.ISO8859-2', + 'sk_sk': 'sk_SK.ISO8859-2', + 'sl': 'sl_CS.ISO8859-2', + 'sl_cs': 'sl_CS.ISO8859-2', + 'sl_si': 'sl_SI.ISO8859-2', + 'slovak': 'sk_SK.ISO8859-2', + 'slovene': 'sl_CS.ISO8859-2', + 'sp': 'sp_YU.ISO8859-5', + 'sp_yu': 'sp_YU.ISO8859-5', + 'spanish': 'es_ES.ISO8859-1', + 'spanish_spain': 'es_ES.ISO8859-1', + 'sr_sp': 'sr_SP.ISO8859-2', + 'sv': 'sv_SE.ISO8859-1', + 'sv_se': 'sv_SE.ISO8859-1', + 'swedish': 'sv_SE.ISO8859-1', + 'th_th': 'th_TH.TACTIS', + 'tr': 'tr_TR.ISO8859-9', + 'tr_tr': 'tr_TR.ISO8859-9', + 'turkish': 'tr_TR.ISO8859-9', + 'univ': 'en_US.utf', + 'universal': 'en_US.utf', + 'zh': 'zh_CN.eucCN', + 'zh_cn': 'zh_CN.eucCN', + 'zh_cn.big5': 'zh_TW.eucTW', + 'zh_cn.euc': 'zh_CN.eucCN', + 'zh_tw': 'zh_TW.eucTW', + 'zh_tw.euc': 'zh_TW.eucTW', +} + +def _print_locale(): + + """ Test function. + """ + categories = {} + def _init_categories(categories=categories): + for k,v in globals().items(): + if k[:3] == 'LC_': + categories[k] = v + _init_categories() + del categories['LC_ALL'] + + print 'Locale defaults as determined by get_default():' + print '-'*72 + lang, enc = get_default() + print 'Language: ', lang or '(undefined)' + print 'Encoding: ', enc or '(undefined)' + print + + print 'Locale settings on startup:' + print '-'*72 + for name,category in categories.items(): + print name,'...' + lang, enc = get_locale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print + + set_to_default() + print + print 'Locale settings after calling set_to_default():' + print '-'*72 + for name,category in categories.items(): + print name,'...' + lang, enc = get_locale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print + + try: + setlocale(LC_ALL,"") + except: + print 'NOTE:' + print 'setlocale(LC_ALL,"") does not support the default locale' + print 'given in the OS environment variables.' + else: + print + print 'Locale settings after calling setlocale(LC_ALL,""):' + print '-'*72 + for name,category in categories.items(): + print name,'...' + lang, enc = get_locale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print +### if __name__=='__main__': - test() + print 'Locale aliasing:' + print + _print_locale() + print + print 'Number formatting:' + print + _test() diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -x core -x config.* -x libpython* -x python -x Setup -x Setup.local -x Setup.thread -x hassignal -x Makefile.pre -x configure -x *.bak -x *.s -x DEADJOE -x *.rej -x *.orig -x Demo -x CVS -x Doc -x *.orig -x .#* -x distutils -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/site.py Python+Unicode/Lib/site.py --- CVS-Python/Lib/site.py Wed Nov 25 16:57:47 1998 +++ Python+Unicode/Lib/site.py Fri Jun 2 14:53:59 2000 @@ -119,10 +119,45 @@ __builtin__.quit = __builtin__.exit = exit del exit +# +# Set the string encoding used by the Unicode implementation to the +# encoding used by the default locale of this system. If the default +# encoding cannot be determined or is unkown, it defaults to 'ascii'. +# +def locale_aware_defaultencoding(): + import locale + code, encoding = locale.get_default() + if encoding is None: + encoding = 'ascii' + try: + sys.setdefaultencoding(encoding) + except LookupError: + sys.setdefaultencoding('ascii') + +if 1: + # Enable to support locale aware default string encodings. + locale_aware_defaultencoding() +elif 0: + # Enable to switch off string to Unicode coercion and implicit + # Unicode to string conversion. + sys.setdefaultencoding('undefined') +elif 0: + # Enable to hard-code a site specific default string encoding. + sys.setdefaultencoding('ascii') + +# +# Run custom site specific code, if available. +# try: - import sitecustomize # Run arbitrary site specific code + import sitecustomize except ImportError: - pass # No site customization module + pass + +# +# Remove sys.setdefaultencoding() so that users cannot change the +# encoding after initialization. +# +del sys.setdefaultencoding def _test(): print "sys.path = [" --------------BEC51DD4A0A70FF5B2F902AD-- From trentm@activestate.com Fri Jun 2 18:13:01 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 10:13:01 -0700 Subject: [Patches] Fix for bug PR#341 In-Reply-To: <393775F9.9E734DF8@lemburg.com> References: <392FEED2.90E262CB@lemburg.com> <200005301513.KAA06165@cj20424-a.reston1.va.home.com> <20000530113910.H18024@activestate.com> <20000601023428.B23428@activestate.com> <393775F9.9E734DF8@lemburg.com> Message-ID: <20000602101301.B13578@activestate.com> Here is the new patch with MAL's suggested changes and similar changes for unicodeobject.c. As well, I have add a test (test_format) for the test suite for this stuff. Refresher: this is a patch to fix possible int/char/float formatting overflow in string and unicode objjects. > > Maybe this patch is preferable. > > Yep. The patch doesn't yet address the general case (use malloc etc.), > but makes things a little more flexbile. > > (Even though I find some tests size_t vs. INT_MAX overkill -- > noone will store 2GB strings in memory ;-) There is great comfort in *knowing* that something will not silently overflow. But, yes, someone is just asking for trouble if they play with strings that big. > > > int sign; > > int len; > > ! #define TMPBUFLEN (size_t)120 > > ! char tmpbuf[TMPBUFLEN]; /* For format{float,int,char}() */ > > char *fmt_start = fmt; > > You should move this #define outside of the function for Done... > better visibility (and perhaps add a comment). ... and done. > > fmt++; > > *************** > > *** 2618,2624 **** > > if (c == 'i') > > c = 'd'; > > buf = tmpbuf; > > ! len = formatint(buf, flags, prec, c, v); > > if (len < 0) > > goto error; > > sign = (c == 'd'); > > --- 2653,2659 ---- > > if (c == 'i') > > c = 'd'; > > buf = tmpbuf; > > ! len = formatint(buf, TMPBUFLEN, flags, prec, c, v); > > All of these direct references to TMPBUFLEN should > be changed to sizeof(buf) for clarity. Actually sizeof(tmpbuf), sizeof(buf) == sizeof(char*). This is why this new patch changes 'buf' to 'pbuf'. This is more self documenting to me. In any case, you are right, this is clearer. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): *** /home/trentm/main/contrib/python/dist/src/Objects/unicodeobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/unicodeobject.c Fri Jun 2 10:02:12 2000 *************** *** 4218,4228 **** --- 4218,4231 ---- static int formatfloat(Py_UNICODE *buf, + size_t buflen, int flags, int prec, int type, PyObject *v) { + /* fmt = '%#.' + `prec` + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ char fmt[20]; double x; *************** *** 4231,4251 **** return -1; if (prec < 0) prec = 6; - if (prec > 50) - prec = 50; /* Arbitrary limitation */ if (type == 'f' && (fabs(x) / 1e25) >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags & F_ALT) ? "#" : "", prec, type); return usprintf(buf, fmt, x); } static int formatint(Py_UNICODE *buf, int flags, int prec, int type, PyObject *v) { char fmt[20]; long x; --- 4234,4267 ---- return -1; if (prec < 0) prec = 6; if (type == 'f' && (fabs(x) / 1e25) >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags & F_ALT) ? "#" : "", prec, type); + /* worst case length calc to ensure no buffer overrun: + fmt = %#.g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase by one to 10+prec. */ + if (buflen <= (size_t)10 + (size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted float is too long (precision too long?)"); + return -1; + } return usprintf(buf, fmt, x); } static int formatint(Py_UNICODE *buf, + size_t buflen, int flags, int prec, int type, PyObject *v) { + /* fmt = '%#.' + `prec` + 'l' + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/ char fmt[20]; long x; *************** *** 4255,4267 **** --- 4271,4292 ---- if (prec < 0) prec = 1; sprintf(fmt, "%%%s.%dl%c", (flags & F_ALT) ? "#" : "", prec, type); + /* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal)) + worst case buf = '0x' + [0-9]*prec, where prec >= 11 */ + if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted integer is too long (precision too long?)"); + return -1; + } return usprintf(buf, fmt, x); } static int formatchar(Py_UNICODE *buf, + size_t buflen, PyObject *v) { + /* presume that the buffer is at least 2 characters long */ if (PyUnicode_Check(v)) buf[0] = PyUnicode_AS_UNICODE(v)[0]; *************** *** 4280,4285 **** --- 4305,4320 ---- return 1; } + /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) + + FORMATBUFLEN is the length of the buffer in which the floats, ints, & + chars are formatted. XXX This is a magic number. Each formatting + routine does bounds checking to ensure no overflow, but a better + solution may be to malloc a buffer of appropriate size for each + format. For now, the current solution is sufficient. + */ + #define FORMATBUFLEN (size_t)120 + PyObject *PyUnicode_Format(PyObject *format, PyObject *args) { *************** *** 4339,4348 **** Py_UNICODE fill; PyObject *v = NULL; PyObject *temp = NULL; ! Py_UNICODE *buf; Py_UNICODE sign; int len; ! Py_UNICODE tmpbuf[120]; /* For format{float,int,char}() */ fmt++; if (*fmt == '(') { --- 4374,4383 ---- Py_UNICODE fill; PyObject *v = NULL; PyObject *temp = NULL; ! Py_UNICODE *pbuf; Py_UNICODE sign; int len; ! Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ fmt++; if (*fmt == '(') { *************** *** 4492,4499 **** switch (c) { case '%': ! buf = tmpbuf; ! buf[0] = '%'; len = 1; break; --- 4527,4535 ---- switch (c) { case '%': ! pbuf = formatbuf; ! /* presume that buffer length is at least 1 */ ! pbuf[0] = '%'; len = 1; break; *************** *** 4529,4535 **** if (temp == NULL) goto onError; } ! buf = PyUnicode_AS_UNICODE(temp); len = PyUnicode_GET_SIZE(temp); if (prec >= 0 && len > prec) len = prec; --- 4565,4571 ---- if (temp == NULL) goto onError; } ! pbuf = PyUnicode_AS_UNICODE(temp); len = PyUnicode_GET_SIZE(temp); if (prec >= 0 && len > prec) len = prec; *************** *** 4543,4550 **** case 'X': if (c == 'i') c = 'd'; ! buf = tmpbuf; ! len = formatint(buf, flags, prec, c, v); if (len < 0) goto onError; sign = (c == 'd'); --- 4579,4587 ---- case 'X': if (c == 'i') c = 'd'; ! pbuf = formatbuf; ! len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), ! flags, prec, c, v); if (len < 0) goto onError; sign = (c == 'd'); *************** *** 4552,4560 **** fill = '0'; if ((flags&F_ALT) && (c == 'x' || c == 'X') && ! buf[0] == '0' && buf[1] == c) { ! *res++ = *buf++; ! *res++ = *buf++; rescnt -= 2; len -= 2; width -= 2; --- 4589,4597 ---- fill = '0'; if ((flags&F_ALT) && (c == 'x' || c == 'X') && ! pbuf[0] == '0' && pbuf[1] == c) { ! *res++ = *pbuf++; ! *res++ = *pbuf++; rescnt -= 2; len -= 2; width -= 2; *************** *** 4569,4576 **** case 'f': case 'g': case 'G': ! buf = tmpbuf; ! len = formatfloat(buf, flags, prec, c, v); if (len < 0) goto onError; sign = 1; --- 4606,4614 ---- case 'f': case 'g': case 'G': ! pbuf = formatbuf; ! len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), ! flags, prec, c, v); if (len < 0) goto onError; sign = 1; *************** *** 4579,4586 **** break; case 'c': ! buf = tmpbuf; ! len = formatchar(buf, v); if (len < 0) goto onError; break; --- 4617,4624 ---- break; case 'c': ! pbuf = formatbuf; ! len = formatchar(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), v); if (len < 0) goto onError; break; *************** *** 4592,4599 **** goto onError; } if (sign) { ! if (*buf == '-' || *buf == '+') { ! sign = *buf++; len--; } else if (flags & F_SIGN) --- 4630,4637 ---- goto onError; } if (sign) { ! if (*pbuf == '-' || *pbuf == '+') { ! sign = *pbuf++; len--; } else if (flags & F_SIGN) *************** *** 4629,4635 **** } if (sign && fill == ' ') *res++ = sign; ! memcpy(res, buf, len * sizeof(Py_UNICODE)); res += len; rescnt -= len; while (--width >= len) { --- 4667,4673 ---- } if (sign && fill == ' ') *res++ = sign; ! memcpy(res, pbuf, len * sizeof(Py_UNICODE)); res += len; rescnt -= len; while (--width >= len) { *** /home/trentm/main/contrib/python/dist/src/Objects/stringobject.c Fri Jun 2 08:45:50 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/stringobject.c Fri Jun 2 09:10:18 2000 *************** *** 124,131 **** PyString_FromString(str) const char *str; { ! register unsigned int size = strlen(str); register PyStringObject *op; #ifndef DONT_SHARE_SHORT_STRINGS if (size == 0 && (op = nullstring) != NULL) { #ifdef COUNT_ALLOCS --- 124,136 ---- PyString_FromString(str) const char *str; { ! register size_t size = strlen(str); register PyStringObject *op; + if (size > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "string is too long for a Python string"); + return NULL; + } #ifndef DONT_SHARE_SHORT_STRINGS if (size == 0 && (op = nullstring) != NULL) { #ifdef COUNT_ALLOCS *************** *** 237,245 **** string_repr(op) register PyStringObject *op; { ! /* XXX overflow? */ ! int newsize = 2 + 4 * op->ob_size * sizeof(char); ! PyObject *v = PyString_FromStringAndSize((char *)NULL, newsize); if (v == NULL) { return NULL; } --- 242,254 ---- string_repr(op) register PyStringObject *op; { ! size_t newsize = 2 + 4 * op->ob_size * sizeof(char); ! PyObject *v; ! if (newsize > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "string is too large to make repr"); ! } ! v = PyString_FromStringAndSize((char *)NULL, newsize); if (v == NULL) { return NULL; } *************** *** 2317,2352 **** #define F_ZERO (1<<4) static int ! formatfloat(buf, flags, prec, type, v) char *buf; int flags; int prec; int type; PyObject *v; { char fmt[20]; double x; if (!PyArg_Parse(v, "d;float argument required", &x)) return -1; if (prec < 0) prec = 6; - if (prec > 50) - prec = 50; /* Arbitrary limitation */ if (type == 'f' && fabs(x)/1e25 >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type); sprintf(buf, fmt, x); return strlen(buf); } static int ! formatint(buf, flags, prec, type, v) char *buf; int flags; int prec; int type; PyObject *v; { char fmt[20]; long x; if (!PyArg_Parse(v, "l;int argument required", &x)) --- 2326,2377 ---- #define F_ZERO (1<<4) static int ! formatfloat(buf, buflen, flags, prec, type, v) char *buf; + size_t buflen; int flags; int prec; int type; PyObject *v; { + /* fmt = '%#.' + `prec` + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ char fmt[20]; double x; if (!PyArg_Parse(v, "d;float argument required", &x)) return -1; if (prec < 0) prec = 6; if (type == 'f' && fabs(x)/1e25 >= 1e25) type = 'g'; sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type); + /* worst case length calc to ensure no buffer overrun: + fmt = %#.g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase by one to 10+prec. */ + if (buflen <= (size_t)10 + (size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted float is too long (precision too long?)"); + return -1; + } sprintf(buf, fmt, x); return strlen(buf); } static int ! formatint(buf, buflen, flags, prec, type, v) char *buf; + size_t buflen; int flags; int prec; int type; PyObject *v; { + /* fmt = '%#.' + `prec` + 'l' + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/ char fmt[20]; long x; if (!PyArg_Parse(v, "l;int argument required", &x)) *************** *** 2354,2368 **** if (prec < 0) prec = 1; sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type); sprintf(buf, fmt, x); return strlen(buf); } static int ! formatchar(buf, v) char *buf; PyObject *v; { if (PyString_Check(v)) { if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) return -1; --- 2379,2402 ---- if (prec < 0) prec = 1; sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type); + /* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal)) + worst case buf = '0x' + [0-9]*prec, where prec >= 11 */ + if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted integer is too long (precision too long?)"); + return -1; + } sprintf(buf, fmt, x); return strlen(buf); } static int ! formatchar(buf, buflen, v) char *buf; + size_t buflen; PyObject *v; { + /* presume that the buffer is at least 2 characters long */ if (PyString_Check(v)) { if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) return -1; *************** *** 2376,2382 **** } ! /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */ PyObject * PyString_Format(format, args) --- 2410,2424 ---- } ! /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) ! ! FORMATBUFLEN is the length of the buffer in which the floats, ints, & ! chars are formatted. XXX This is a magic number. Each formatting ! routine does bounds checking to ensure no overflow, but a better ! solution may be to malloc a buffer of appropriate size for each ! format. For now, the current solution is sufficient. ! */ ! #define FORMATBUFLEN (size_t)120 PyObject * PyString_Format(format, args) *************** *** 2433,2442 **** int fill; PyObject *v = NULL; PyObject *temp = NULL; ! char *buf; int sign; int len; ! char tmpbuf[120]; /* For format{float,int,char}() */ char *fmt_start = fmt; fmt++; --- 2475,2484 ---- int fill; PyObject *v = NULL; PyObject *temp = NULL; ! char *pbuf; int sign; int len; ! char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ char *fmt_start = fmt; fmt++; *************** *** 2584,2590 **** fill = ' '; switch (c) { case '%': ! buf = "%"; len = 1; break; case 's': --- 2626,2632 ---- fill = ' '; switch (c) { case '%': ! pbuf = "%"; len = 1; break; case 's': *************** *** 2604,2610 **** "%s argument has non-string str()"); goto error; } ! buf = PyString_AsString(temp); len = PyString_Size(temp); if (prec >= 0 && len > prec) len = prec; --- 2646,2652 ---- "%s argument has non-string str()"); goto error; } ! pbuf = PyString_AsString(temp); len = PyString_Size(temp); if (prec >= 0 && len > prec) len = prec; *************** *** 2617,2624 **** case 'X': if (c == 'i') c = 'd'; ! buf = tmpbuf; ! len = formatint(buf, flags, prec, c, v); if (len < 0) goto error; sign = (c == 'd'); --- 2659,2666 ---- case 'X': if (c == 'i') c = 'd'; ! pbuf = formatbuf; ! len = formatint(pbuf, sizeof(formatbuf), flags, prec, c, v); if (len < 0) goto error; sign = (c == 'd'); *************** *** 2626,2634 **** fill = '0'; if ((flags&F_ALT) && (c == 'x' || c == 'X') && ! buf[0] == '0' && buf[1] == c) { ! *res++ = *buf++; ! *res++ = *buf++; rescnt -= 2; len -= 2; width -= 2; --- 2668,2676 ---- fill = '0'; if ((flags&F_ALT) && (c == 'x' || c == 'X') && ! pbuf[0] == '0' && pbuf[1] == c) { ! *res++ = *pbuf++; ! *res++ = *pbuf++; rescnt -= 2; len -= 2; width -= 2; *************** *** 2642,2649 **** case 'f': case 'g': case 'G': ! buf = tmpbuf; ! len = formatfloat(buf, flags, prec, c, v); if (len < 0) goto error; sign = 1; --- 2684,2691 ---- case 'f': case 'g': case 'G': ! pbuf = formatbuf; ! len = formatfloat(pbuf, sizeof(formatbuf), flags, prec, c, v); if (len < 0) goto error; sign = 1; *************** *** 2651,2658 **** fill = '0'; break; case 'c': ! buf = tmpbuf; ! len = formatchar(buf, v); if (len < 0) goto error; break; --- 2693,2700 ---- fill = '0'; break; case 'c': ! pbuf = formatbuf; ! len = formatchar(pbuf, sizeof(formatbuf), v); if (len < 0) goto error; break; *************** *** 2663,2670 **** goto error; } if (sign) { ! if (*buf == '-' || *buf == '+') { ! sign = *buf++; len--; } else if (flags & F_SIGN) --- 2705,2712 ---- goto error; } if (sign) { ! if (*pbuf == '-' || *pbuf == '+') { ! sign = *pbuf++; len--; } else if (flags & F_SIGN) *************** *** 2700,2706 **** } if (sign && fill == ' ') *res++ = sign; ! memcpy(res, buf, len); res += len; rescnt -= len; while (--width >= len) { --- 2742,2748 ---- } if (sign && fill == ' ') *res++ = sign; ! memcpy(res, pbuf, len); res += len; rescnt -= len; while (--width >= len) { *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_format.py Fri Jun 2 10:06:56 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_format.py Fri Jun 2 10:04:32 2000 *************** *** 0 **** --- 1,52 ---- + from test_support import verbose + import string, sys + + # test string formatting operator (I am not sure if this is being tested + # elsewhere but, surely, some of the given cases are *not* tested because + # they crash python) + # test on unicode strings as well + + def testformat(formatstr, args, output=None): + if verbose: + if output: + print "%s %% %s =? %s ..." %\ + (repr(formatstr), repr(args), repr(output)), + else: + print "%s %% %s works? ..." % (repr(formatstr), repr(args)), + try: + result = formatstr % args + except OverflowError: + if verbose: + print 'overflow (this is fine)' + else: + if output and result != output: + if verbose: + print 'no' + print "%s %% %s == %s != %s" %\ + (repr(formatstr), repr(args), repr(result), repr(output)) + else: + if verbose: + print 'yes' + + def testboth(formatstr, *args): + testformat(formatstr, *args) + testformat(unicode(formatstr), *args) + + + testboth("%.1d", (1,), "1") + testboth("%.*d", (sys.maxint,1)) # expect overflow + testboth("%.100d", (1,), '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001') + testboth("%#.117x", (1,), '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001') + testboth("%#.118x", (1,), '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001') + + testboth("%f", (1.0,), "1.000000") + # these are trying to test the limits of the internal magic-number-length + # formatting buffer, if that number changes then these tests are less + # effective + testboth("%#.*g", (109, -1.e+49/3.)) + testboth("%#.*g", (110, -1.e+49/3.)) + testboth("%#.*g", (110, -1.e+100/3.)) + + # test some ridiculously large precision, expect overflow + testboth('%12.*f', (123456, 1.0)) + *** /home/trentm/main/contrib/python/dist/src/Lib/test/output/test_format Fri Jun 2 10:06:56 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/output/test_format Wed May 31 23:54:16 2000 *************** *** 0 **** --- 1 ---- + test_format -- Trent Mick trentm@activestate.com From htw7192@htw-dresden.de Fri Jun 2 18:51:06 2000 From: htw7192@htw-dresden.de (Rene Liebscher) Date: Fri, 2 Jun 2000 19:51:06 +0200 (DFT) Subject: [Patches] Extension building on Win32 using Gnu C Message-ID: This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. Send mail to mime@docserver.cac.washington.edu for more info. ---1925705967-1682430998-959968266=:38558 Content-Type: TEXT/PLAIN; charset=US-ASCII I want to provide a patch which makes it possible to use the Gnu Win32 compilers (cygwin and mingw32) to build extensions. It is not intended to make python1.6 be able to be build with these compilers, there you would need at least a special makefile and probably even more support. It introduces a section for Gnu C in the PC specific config.h file. Also it makes some type definitions available for dll functions (you have to declare all types which are used by the dll interface. If you don't, you get warnings about incompatible types and so on) This is done by some #defines, which are empty for all others. I have compiled the patched version on linux and Window MS Visual C++ and both are still working. I also tried to build an extension module with Gnu C which worked too. To build extensions with Gnu C on Win32, you also need an import library. This library cannot be build by MSVC, but every one who uses Gnu C on Win32 can build it for himself (with dlltool), if the def-file for the dll-file is provided. So this file should be included in the distribution. Kind regards Rene Liebscher R.Liebscher@gmx.de ---1925705967-1682430998-959968266=:38558 Content-Type: TEXT/PLAIN; charset=US-ASCII; name="python.patch" Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename="python.patch" ZGlmZiAtQmNyTiAtLW1pbmltYWwgcHl0aG9uLm9yaWcvZGlzdC9zcmMvSW5j bHVkZS9QeXRob24uaCBweXRob24ucGF0Y2hlZC9kaXN0L3NyYy9JbmNsdWRl L1B5dGhvbi5oDQoqKiogcHl0aG9uLm9yaWcvZGlzdC9zcmMvSW5jbHVkZS9Q eXRob24uaAlTdW4gTWF5IDI4IDIyOjI5OjQ4IDIwMDANCi0tLSBweXRob24u cGF0Y2hlZC9kaXN0L3NyYy9JbmNsdWRlL1B5dGhvbi5oCVR1ZSBNYXkgMzAg MTA6MjQ6NDAgMjAwMA0KKioqKioqKioqKioqKioqDQoqKiogNDYsNTEgKioq Kg0KLS0tIDQ2LDYyIC0tLS0NCiAgI2RlZmluZSBETF9FWFBPUlQoUlRZUEUp IFJUWVBFDQogICNlbmRpZg0KICANCisgLyogVGhlIG5leHQgYXJlIHVzZWQg YnkgdGhlIEdudSBDLWNvbXBpbGVycyBvbiBXaW4zMiwgZm9yIGFsbCBvdGhl cnMNCisgICAgdGhleSB3aWxsIGJlIGRlZmluZWQgYXMgZW1wdHkgKi8gDQor IC8qIERlZmluaXRpb24gb2YgZXZlcnkgdHlwZSwgdmFyaWFibGVzIG9mIHdo aWNoIG1heSBiZSBpbXBvcnRlZCBmcm9tIERMTCwNCisgICAgbXVzdCBiZSB3 cmFwcGVkIGluIERMX0NMQVNTSU1QT1JUX0JFRy9ETF9DTEFTU0lNUE9SVF9F TkQgYnJhY2tldHMgKi8NCisgI2lmbmRlZiBETF9DTEFTU0lNUE9SVF9CRUcN CisgI2RlZmluZSBETF9DTEFTU0lNUE9SVF9CRUcNCisgI2VuZGlmDQorICNp Zm5kZWYgRExfQ0xBU1NJTVBPUlRfRU5EDQorICNkZWZpbmUgRExfQ0xBU1NJ TVBPUlRfRU5EDQorICNlbmRpZg0KKyANCiAgI2lmZGVmIFNZTUFOVEVDX19D Rk02OEtfXw0KICAjZGVmaW5lIFVzaW5nU2hhcmVkTGlicw0KICAjZW5kaWYN CmRpZmYgLUJjck4gLS1taW5pbWFsIHB5dGhvbi5vcmlnL2Rpc3Qvc3JjL0lu Y2x1ZGUvb2JqZWN0LmggcHl0aG9uLnBhdGNoZWQvZGlzdC9zcmMvSW5jbHVk ZS9vYmplY3QuaA0KKioqIHB5dGhvbi5vcmlnL2Rpc3Qvc3JjL0luY2x1ZGUv b2JqZWN0LmgJTW9uIEFwciAyNCAxNzo0MDo0NSAyMDAwDQotLS0gcHl0aG9u LnBhdGNoZWQvZGlzdC9zcmMvSW5jbHVkZS9vYmplY3QuaAlUdWUgTWF5IDMw IDEwOjM0OjMzIDIwMDANCioqKioqKioqKioqKioqKg0KKioqIDEwNywxMjAg KioqKg0KICAJUHlPYmplY3RfSEVBRCBcDQogIAlpbnQgb2Jfc2l6ZTsgLyog TnVtYmVyIG9mIGl0ZW1zIGluIHZhcmlhYmxlIHBhcnQgKi8NCiAgIA0KISB0 eXBlZGVmIHN0cnVjdCBfb2JqZWN0IHsNCiAgCVB5T2JqZWN0X0hFQUQNCiEg fSBQeU9iamVjdDsNCiAgDQotIHR5cGVkZWYgc3RydWN0IHsNCi0gCVB5T2Jq ZWN0X1ZBUl9IRUFEDQotIH0gUHlWYXJPYmplY3Q7DQogIA0KICANCiAgLyoN CiAgVHlwZSBvYmplY3RzIGNvbnRhaW4gYSBzdHJpbmcgY29udGFpbmluZyB0 aGUgdHlwZSBuYW1lICh0byBoZWxwIHNvbWV3aGF0DQotLS0gMTA3LDEyMCAt LS0tDQogIAlQeU9iamVjdF9IRUFEIFwNCiAgCWludCBvYl9zaXplOyAvKiBO dW1iZXIgb2YgaXRlbXMgaW4gdmFyaWFibGUgcGFydCAqLw0KICAgDQohIHR5 cGVkZWYgRExfQ0xBU1NJTVBPUlRfQkVHIHN0cnVjdCBfb2JqZWN0IHsNCiAg CVB5T2JqZWN0X0hFQUQNCiEgfSBETF9DTEFTU0lNUE9SVF9FTkQgUHlPYmpl Y3Q7DQogIA0KICANCisgdHlwZWRlZiBETF9DTEFTU0lNUE9SVF9CRUcgc3Ry dWN0IHsNCisgCVB5T2JqZWN0X1ZBUl9IRUFEDQorIH0gRExfQ0xBU1NJTVBP UlRfRU5EIFB5VmFyT2JqZWN0Ow0KICANCiAgLyoNCiAgVHlwZSBvYmplY3Rz IGNvbnRhaW4gYSBzdHJpbmcgY29udGFpbmluZyB0aGUgdHlwZSBuYW1lICh0 byBoZWxwIHNvbWV3aGF0DQoqKioqKioqKioqKioqKioNCioqKiAxNDYsMTUy ICoqKioNCiAgdHlwZWRlZiBpbnQgKCpnZXRjaGFyYnVmZmVycHJvYykgUHlf UFJPVE8oKFB5T2JqZWN0ICosIGludCwgY29uc3QgY2hhciAqKikpOw0KICB0 eXBlZGVmIGludCAoKm9iam9ianByb2MpIFB5X1BST1RPKChQeU9iamVjdCAq LCBQeU9iamVjdCAqKSk7DQogIA0KISB0eXBlZGVmIHN0cnVjdCB7DQogIAli aW5hcnlmdW5jIG5iX2FkZDsNCiAgCWJpbmFyeWZ1bmMgbmJfc3VidHJhY3Q7 DQogIAliaW5hcnlmdW5jIG5iX211bHRpcGx5Ow0KLS0tIDE0NiwxNTIgLS0t LQ0KICB0eXBlZGVmIGludCAoKmdldGNoYXJidWZmZXJwcm9jKSBQeV9QUk9U TygoUHlPYmplY3QgKiwgaW50LCBjb25zdCBjaGFyICoqKSk7DQogIHR5cGVk ZWYgaW50ICgqb2Jqb2JqcHJvYykgUHlfUFJPVE8oKFB5T2JqZWN0ICosIFB5 T2JqZWN0ICopKTsNCiAgDQohIHR5cGVkZWYgRExfQ0xBU1NJTVBPUlRfQkVH IHN0cnVjdCB7DQogIAliaW5hcnlmdW5jIG5iX2FkZDsNCiAgCWJpbmFyeWZ1 bmMgbmJfc3VidHJhY3Q7DQogIAliaW5hcnlmdW5jIG5iX211bHRpcGx5Ow0K KioqKioqKioqKioqKioqDQoqKiogMTcwLDE3OCAqKioqDQogIAl1bmFyeWZ1 bmMgbmJfZmxvYXQ7DQogIAl1bmFyeWZ1bmMgbmJfb2N0Ow0KICAJdW5hcnlm dW5jIG5iX2hleDsNCiEgfSBQeU51bWJlck1ldGhvZHM7DQogIA0KISB0eXBl ZGVmIHN0cnVjdCB7DQogIAlpbnF1aXJ5IHNxX2xlbmd0aDsNCiAgCWJpbmFy eWZ1bmMgc3FfY29uY2F0Ow0KICAJaW50YXJnZnVuYyBzcV9yZXBlYXQ7DQot LS0gMTcwLDE3OCAtLS0tDQogIAl1bmFyeWZ1bmMgbmJfZmxvYXQ7DQogIAl1 bmFyeWZ1bmMgbmJfb2N0Ow0KICAJdW5hcnlmdW5jIG5iX2hleDsNCiEgfSBE TF9DTEFTU0lNUE9SVF9FTkQgUHlOdW1iZXJNZXRob2RzOw0KICANCiEgdHlw ZWRlZiBETF9DTEFTU0lNUE9SVF9CRUcgc3RydWN0IHsNCiAgCWlucXVpcnkg c3FfbGVuZ3RoOw0KICAJYmluYXJ5ZnVuYyBzcV9jb25jYXQ7DQogIAlpbnRh cmdmdW5jIHNxX3JlcGVhdDsNCioqKioqKioqKioqKioqKg0KKioqIDE4MSwy MDAgKioqKg0KICAJaW50b2JqYXJncHJvYyBzcV9hc3NfaXRlbTsNCiAgCWlu dGludG9iamFyZ3Byb2Mgc3FfYXNzX3NsaWNlOw0KICAJb2Jqb2JqcHJvYyBz cV9jb250YWluczsNCiEgfSBQeVNlcXVlbmNlTWV0aG9kczsNCiAgDQohIHR5 cGVkZWYgc3RydWN0IHsNCiAgCWlucXVpcnkgbXBfbGVuZ3RoOw0KICAJYmlu YXJ5ZnVuYyBtcF9zdWJzY3JpcHQ7DQogIAlvYmpvYmphcmdwcm9jIG1wX2Fz c19zdWJzY3JpcHQ7DQohIH0gUHlNYXBwaW5nTWV0aG9kczsNCiAgDQohIHR5 cGVkZWYgc3RydWN0IHsNCiAgCWdldHJlYWRidWZmZXJwcm9jIGJmX2dldHJl YWRidWZmZXI7DQogIAlnZXR3cml0ZWJ1ZmZlcnByb2MgYmZfZ2V0d3JpdGVi dWZmZXI7DQogIAlnZXRzZWdjb3VudHByb2MgYmZfZ2V0c2VnY291bnQ7DQog IAlnZXRjaGFyYnVmZmVycHJvYyBiZl9nZXRjaGFyYnVmZmVyOw0KISB9IFB5 QnVmZmVyUHJvY3M7DQogIAkNCiAgDQogIHR5cGVkZWYgdm9pZCAoKmRlc3Ry dWN0b3IpIFB5X1BST1RPKChQeU9iamVjdCAqKSk7DQotLS0gMTgxLDIwMCAt LS0tDQogIAlpbnRvYmphcmdwcm9jIHNxX2Fzc19pdGVtOw0KICAJaW50aW50 b2JqYXJncHJvYyBzcV9hc3Nfc2xpY2U7DQogIAlvYmpvYmpwcm9jIHNxX2Nv bnRhaW5zOw0KISB9IERMX0NMQVNTSU1QT1JUX0VORCBQeVNlcXVlbmNlTWV0 aG9kczsNCiAgDQohIHR5cGVkZWYgRExfQ0xBU1NJTVBPUlRfQkVHIHN0cnVj dCB7DQogIAlpbnF1aXJ5IG1wX2xlbmd0aDsNCiAgCWJpbmFyeWZ1bmMgbXBf c3Vic2NyaXB0Ow0KICAJb2Jqb2JqYXJncHJvYyBtcF9hc3Nfc3Vic2NyaXB0 Ow0KISB9IERMX0NMQVNTSU1QT1JUX0VORCBQeU1hcHBpbmdNZXRob2RzOw0K ICANCiEgdHlwZWRlZiBETF9DTEFTU0lNUE9SVF9CRUcgc3RydWN0IHsNCiAg CWdldHJlYWRidWZmZXJwcm9jIGJmX2dldHJlYWRidWZmZXI7DQogIAlnZXR3 cml0ZWJ1ZmZlcnByb2MgYmZfZ2V0d3JpdGVidWZmZXI7DQogIAlnZXRzZWdj b3VudHByb2MgYmZfZ2V0c2VnY291bnQ7DQogIAlnZXRjaGFyYnVmZmVycHJv YyBiZl9nZXRjaGFyYnVmZmVyOw0KISB9IERMX0NMQVNTSU1QT1JUX0VORCBQ eUJ1ZmZlclByb2NzOw0KICAJDQogIA0KICB0eXBlZGVmIHZvaWQgKCpkZXN0 cnVjdG9yKSBQeV9QUk9UTygoUHlPYmplY3QgKikpOw0KKioqKioqKioqKioq KioqDQoqKiogMjA3LDIxMyAqKioqDQogIHR5cGVkZWYgUHlPYmplY3QgKigq cmVwcmZ1bmMpIFB5X1BST1RPKChQeU9iamVjdCAqKSk7DQogIHR5cGVkZWYg bG9uZyAoKmhhc2hmdW5jKSBQeV9QUk9UTygoUHlPYmplY3QgKikpOw0KICAN CiEgdHlwZWRlZiBzdHJ1Y3QgX3R5cGVvYmplY3Qgew0KICAJUHlPYmplY3Rf VkFSX0hFQUQNCiAgCWNoYXIgKnRwX25hbWU7IC8qIEZvciBwcmludGluZyAq Lw0KICAJaW50IHRwX2Jhc2ljc2l6ZSwgdHBfaXRlbXNpemU7IC8qIEZvciBh bGxvY2F0aW9uICovDQotLS0gMjA3LDIxMyAtLS0tDQogIHR5cGVkZWYgUHlP YmplY3QgKigqcmVwcmZ1bmMpIFB5X1BST1RPKChQeU9iamVjdCAqKSk7DQog IHR5cGVkZWYgbG9uZyAoKmhhc2hmdW5jKSBQeV9QUk9UTygoUHlPYmplY3Qg KikpOw0KICANCiEgdHlwZWRlZiBETF9DTEFTU0lNUE9SVF9CRUcgc3RydWN0 IF90eXBlb2JqZWN0IHsNCiAgCVB5T2JqZWN0X1ZBUl9IRUFEDQogIAljaGFy ICp0cF9uYW1lOyAvKiBGb3IgcHJpbnRpbmcgKi8NCiAgCWludCB0cF9iYXNp Y3NpemUsIHRwX2l0ZW1zaXplOyAvKiBGb3IgYWxsb2NhdGlvbiAqLw0KKioq KioqKioqKioqKioqDQoqKiogMjU2LDI2MiAqKioqDQogIAlpbnQgdHBfbWF4 YWxsb2M7DQogIAlzdHJ1Y3QgX3R5cGVvYmplY3QgKnRwX25leHQ7DQogICNl bmRpZg0KISB9IFB5VHlwZU9iamVjdDsNCiAgDQogIGV4dGVybiBETF9JTVBP UlQoUHlUeXBlT2JqZWN0KSBQeVR5cGVfVHlwZTsgLyogVGhlIHR5cGUgb2Yg dHlwZSBvYmplY3RzICovDQogIA0KLS0tIDI1NiwyNjIgLS0tLQ0KICAJaW50 IHRwX21heGFsbG9jOw0KICAJc3RydWN0IF90eXBlb2JqZWN0ICp0cF9uZXh0 Ow0KICAjZW5kaWYNCiEgfSBETF9DTEFTU0lNUE9SVF9FTkQgUHlUeXBlT2Jq ZWN0Ow0KICANCiAgZXh0ZXJuIERMX0lNUE9SVChQeVR5cGVPYmplY3QpIFB5 VHlwZV9UeXBlOyAvKiBUaGUgdHlwZSBvZiB0eXBlIG9iamVjdHMgKi8NCiAg DQpkaWZmIC1CY3JOIC0tbWluaW1hbCBweXRob24ub3JpZy9kaXN0L3NyYy9Q Qy9jb25maWcuaCBweXRob24ucGF0Y2hlZC9kaXN0L3NyYy9QQy9jb25maWcu aA0KKioqIHB5dGhvbi5vcmlnL2Rpc3Qvc3JjL1BDL2NvbmZpZy5oCVdlZCBN YXkgMTAgMTU6MjU6MzIgMjAwMA0KLS0tIHB5dGhvbi5wYXRjaGVkL2Rpc3Qv c3JjL1BDL2NvbmZpZy5oCVR1ZSBNYXkgMzAgMTA6Mzc6NTUgMjAwMA0KKioq KioqKioqKioqKioqDQoqKiogNDIsNDcgKioqKg0KLS0tIDQyLDc5IC0tLS0N CiAgI2RlZmluZSBQUkVGSVggIiINCiAgI2RlZmluZSBFWEVDX1BSRUZJWCAi Ig0KICANCisgLyogZWdjcy9nbnUtd2luMzIgZGVmaW5lcyBfX0dOVUNfXyBh bmQgX1dJTjMyICovDQorIA0KKyAjaWYgZGVmaW5lZChfX0dOVUNfXykgJiYg ZGVmaW5lZChfV0lOMzIpDQorICNkZWZpbmUgTlQJLyogTlQgaXMgb2Jzb2xl dGUgLSBwbGVhc2UgdXNlIE1TX1dJTjMyIGluc3RlYWQgKi8NCisgI2RlZmlu ZSBNU19XSU4zMg0KKyAjZGVmaW5lIE1TX1dJTkRPV1MNCisgI2RlZmluZSBI QVZFX0NMT0NLDQorICNkZWZpbmUgSEFWRV9TVFJGVElNRQ0KKyAjZGVmaW5l IEhBVkVfU1RSRVJST1INCisgI2RlZmluZSBOVF9USFJFQURTDQorICNkZWZp bmUgV0lUSF9USFJFQUQNCisgI2RlZmluZSBXT1JEX0JJVCAzMg0KKyAjZGVm aW5lIEhBVkVfTE9OR19MT05HIDENCisgI2RlZmluZSBMT05HX0xPTkcgbG9u ZyBsb25nDQorICNkZWZpbmUgUFlUSE9OUEFUSCAiLlxcRExMczsuXFxsaWI7 LlxcbGliXFxwbGF0LXdpbjsuXFxsaWJcXGxpYi10ayINCisgDQorICNpZm5k ZWYgTVNfTk9fQ09SRURMTA0KKyAjZGVmaW5lIE1TX0NPUkVETEwJLyogUHl0 aG9uIGNvcmUgaXMgaW4gYSBETEwgKi8NCisgI2lmbmRlZiBVU0VfRExfRVhQ T1JUDQorICNkZWZpbmUgVVNFX0RMX0lNUE9SVA0KKyAjZW5kaWYgLyogIVVT RV9ETF9FWFBPUlQgKi8NCisgI2VuZGlmIC8qICFNU19OT19DT1JFRExMICov DQorIA0KKyAjaWZkZWYgVVNFX0RMX0lNUE9SVA0KKyAjZGVmaW5lIERMX0lN UE9SVChzeW0pIF9fZGVjbHNwZWMoZGxsaW1wb3J0KSBzeW0NCisgLyogRGVm aW5pdGlvbiBvZiBldmVyeSB0eXBlLCB2YXJpYWJsZXMgb2Ygd2hpY2ggbWF5 IGJlIGltcG9ydGVkIGZyb20gRExMLA0KKyAgICBtdXN0IGJlIHdyYXBwZWQg aW4gRExfQ0xBU1NJTVBPUlRfQkVHL0RMX0NMQVNTSU1QT1JUX0VORCBicmFj a2V0cyAqLw0KKyAjZGVmaW5lIERMX0NMQVNTSU1QT1JUX0JFRw0KKyAjZGVm aW5lIERMX0NMQVNTSU1QT1JUX0VORCBfX2RlY2xzcGVjKGRsbGltcG9ydCkN CisgI2VuZGlmIC8qIFVTRV9ETF9JTVBPUlQgKi8NCisgI2VuZGlmIC8qIChk ZWZpbmVkKF9fR05VQ19fKSAmJiBkZWZpbmVkKF9XSU4zMikpICovDQorIA0K ICAvKiBNaWNyb3NvZnQgQyBkZWZpbmVzIF9NU0NfVkVSICovDQogICNpZmRl ZiBfTVNDX1ZFUg0KICANCg== ---1925705967-1682430998-959968266=:38558-- From mal@lemburg.com Fri Jun 2 20:10:08 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 02 Jun 2000 21:10:08 +0200 Subject: [Patches] Fix for bug PR#341 References: <392FEED2.90E262CB@lemburg.com> <200005301513.KAA06165@cj20424-a.reston1.va.home.com> <20000530113910.H18024@activestate.com> <20000601023428.B23428@activestate.com> <393775F9.9E734DF8@lemburg.com> <20000602101301.B13578@activestate.com> Message-ID: <39380690.C166AB0F@lemburg.com> [Trent's new modified patch for both strings and Unicode objects] Great work Trent, thanks :-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From trentm@activestate.com Fri Jun 2 21:10:58 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 13:10:58 -0700 Subject: [Patches] Re: [Python-Dev] PyMarshal_WriteLongToFile: writes 'long' or 32-bit integer? In-Reply-To: References: <20000602111417.A17233@activestate.com> Message-ID: <20000602131058.A22280@activestate.com> On Fri, Jun 02, 2000 at 09:45:25PM +0200, Peter Funk wrote: > Hi, > > Trent Mick: > [...] > > PyMarshal_WriteLongToFile your long is truncated to 32-bits. However, if you > > write a long indirectly by PyMarshal_WriteObjectToFile, where that Python > > object is or contains a PyInt (C long), then the long is *not* truncated. > > > > Options: > > > > 1. leave it, who cares > > > > 2. - change PyMarshal_WriteLongToFile to write 64-bits if long is 64-bits > > - add something like PyMarshal_WriteInt32ToFile for the benefit of users > > like import.c that want to control exactly how many bytes get written > > > > 3. - change PyMarshal_WriteLongToFile to raise an exception if the long > > overflows a 32-bit range > > We should try to achieve the following goal: .pyc files should be portable > from 32 bit systems to 64 bit systems and vice versa. This means > always truncating to 32 bits and raising an exception, if an overflow > occurs. > Or offer PyMarshal_WriteInt32ToFile for import.c and import.c itself can do the overflow checking on the time stamp. That is the RIght THing(TM) IMO. Anyway, my question was intended to be more about the subtlety of marshal functions rather than the .pyc file headers. No question that the .pyc's should be portable. Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 2 19:50:59 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 11:50:59 -0700 Subject: [Patches] printf("%lx") -> printf("%p") for pointers : win64 cares In-Reply-To: <000501bfbcac$329b5260$3f2d153f@tim> References: <20000512234115.B6689@activestate.com> <000501bfbcac$329b5260$3f2d153f@tim> Message-ID: <20000602115059.A17912@activestate.com> This is a revival submission. This got discussed (at least by Tim and I) and then it died. Background: The common technique for printing out a pointer has been to cast to a long and use the "%lx" printf modifier. This is incorrect on Win64 where casting to a long truncates the pointer. The "%p" formatter should be used instead. before (with a debugging printf of my own): >>> class spam: pass ... >>> repr(spam) real pointer value is 000003FFFFC58340 # my own printf in the class_repr fn '' >>> after: >>> class spam: pass ... >>> repr(spam) '' >>> The problem as stated by Tim: > Unfortunately, the C committee refused to define what %p conversion "looks > like" -- they explicitly allowed it to be implementation-defined. Older > versions of Microsoft C even stuck a colon in the middle of the address (in > the days of segment+offset addressing)! The result is that the hex value of a pointer will maybe/maybe not have a 0x prepended to it. [Tim answers some question of mine about this problem] > > I.e. does Python promise the repr output to look EXACTLY the way it does? > > No. > > > Will reasonable code out there break? > > Probably, but not much. I'm sure much more code will break due to 1.6 > dropping the trailing "L" on str(long), for example. > > ... > > Given that %p is "implementation defined" do you see this patch > > going in > > I'd put it in, if I were Guido. From here is Guido's call, I guess. So here is the patch (again). Notes on the patch: There are two main classes of changes: - in the various repr() functions that print out pointers - debugging printf's in the various thread_*.h files (these are why the patch is large) Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: diff -c3 /home/trentm/main/contrib/python/dist/src/Modules/_tkinter.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/_tkinter.c *** /home/trentm/main/contrib/python/dist/src/Modules/_tkinter.c Thu May 4 08:55:17 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/_tkinter.c Fri May 12 12:03:24 2000 *************** *** 1705,1711 **** TkttObject *v = (TkttObject *)self; char buf[100]; ! sprintf(buf, "", (long)v, v->func == NULL ? ", handler deleted" : ""); return PyString_FromString(buf); } --- 1705,1711 ---- TkttObject *v = (TkttObject *)self; char buf[100]; ! sprintf(buf, "", v, v->func == NULL ? ", handler deleted" : ""); return PyString_FromString(buf); } diff -c3 /home/trentm/main/contrib/python/dist/src/Modules/flmodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/flmodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/flmodule.c Wed May 3 16:44:32 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/flmodule.c Fri May 12 12:06:53 2000 *************** *** 435,442 **** genericobject *g; { char buf[100]; ! sprintf(buf, "", ! (long)g, g->ob_generic->objclass); return PyString_FromString(buf); } --- 435,442 ---- genericobject *g; { char buf[100]; ! sprintf(buf, "", ! g, g->ob_generic->objclass); return PyString_FromString(buf); } *************** *** 1906,1913 **** formobject *f; { char buf[100]; ! sprintf(buf, "", ! (long)f, f->ob_form->window); return PyString_FromString(buf); } --- 1906,1913 ---- formobject *f; { char buf[100]; ! sprintf(buf, "", ! f, f->ob_form->window); return PyString_FromString(buf); } diff -c3 /home/trentm/main/contrib/python/dist/src/Modules/mpzmodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/mpzmodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/mpzmodule.c Wed May 3 16:44:32 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/mpzmodule.c Fri May 12 12:11:40 2000 *************** *** 262,268 **** #ifdef MPZ_DEBUG fprintf(stderr, ! "mpz_format: cp (str end) 0x%x, begin 0x%x, diff %d, i %d\n", cp, PyString_AS_STRING(strobjp), cp - PyString_AS_STRING(strobjp), i); #endif /* def MPZ_DEBUG */ --- 262,268 ---- #ifdef MPZ_DEBUG fprintf(stderr, ! "mpz_format: cp (str end) %p, begin %p, diff %d, i %d\n", cp, PyString_AS_STRING(strobjp), cp - PyString_AS_STRING(strobjp), i); #endif /* def MPZ_DEBUG */ *************** *** 1765,1771 **** Py_FatalError("mp_allocate failure"); #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_allocate : address 0x%08x\n", res); #endif /* def MPZ_DEBUG */ MP_SET_TEST(res,alloc_size); --- 1765,1771 ---- Py_FatalError("mp_allocate failure"); #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_allocate : address %08p\n", res); #endif /* def MPZ_DEBUG */ MP_SET_TEST(res,alloc_size); *************** *** 1782,1788 **** void *res; #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_reallocate: old address 0x%08x, old size %ld\n", ptr, old_size); #endif /* def MPZ_DEBUG */ --- 1782,1788 ---- void *res; #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_reallocate: old address %08p, old size %ld\n", ptr, old_size); #endif /* def MPZ_DEBUG */ *************** *** 1792,1798 **** Py_FatalError("mp_reallocate failure"); #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_reallocate: new address 0x%08x, new size %ld\n", res, new_size); #endif /* def MPZ_DEBUG */ --- 1792,1798 ---- Py_FatalError("mp_reallocate failure"); #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_reallocate: new address %08p, new size %ld\n", res, new_size); #endif /* def MPZ_DEBUG */ *************** *** 1808,1814 **** { #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_free : old address 0x%08x, old size %ld\n", ptr, size); #endif /* def MPZ_DEBUG */ --- 1808,1814 ---- { #ifdef MPZ_DEBUG ! fprintf(stderr, "mp_free : old address %08p, old size %ld\n", ptr, size); #endif /* def MPZ_DEBUG */ diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_beos.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_beos.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_beos.h Mon Dec 21 11:32:29 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_beos.h Fri May 12 12:50:37 2000 *************** *** 262,268 **** return (PyThread_type_lock)NULL; } ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } --- 262,268 ---- return (PyThread_type_lock)NULL; } ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } *************** *** 270,276 **** { status_t retval; ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); retval = benaphore_destroy( (benaphore_t *)lock ); if( retval != EOK ) { --- 270,276 ---- { status_t retval; ! dprintf(("PyThread_free_lock(%p) called\n", lock)); retval = benaphore_destroy( (benaphore_t *)lock ); if( retval != EOK ) { *************** *** 284,290 **** int success; status_t retval; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); if( waitflag ) { retval = benaphore_lock( (benaphore_t *)lock ); --- 284,290 ---- int success; status_t retval; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); if( waitflag ) { retval = benaphore_lock( (benaphore_t *)lock ); *************** *** 300,306 **** /* TODO: that's bad, raise an exception */ } ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } --- 300,306 ---- /* TODO: that's bad, raise an exception */ } ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } *************** *** 308,314 **** { status_t retval; ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); retval = benaphore_unlock( (benaphore_t *)lock ); if( retval != EOK ) { --- 308,314 ---- { status_t retval; ! dprintf(("PyThread_release_lock(%p) called\n", lock)); retval = benaphore_unlock( (benaphore_t *)lock ); if( retval != EOK ) { *************** *** 336,342 **** return 0; } ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } --- 336,342 ---- return 0; } ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } *************** *** 344,350 **** { status_t retval; ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); retval = delete_sem( (sem_id)sema ); if( retval != B_NO_ERROR ) { --- 344,350 ---- { status_t retval; ! dprintf(("PyThread_free_sema(%p) called\n", sema)); retval = delete_sem( (sem_id)sema ); if( retval != B_NO_ERROR ) { *************** *** 357,363 **** { status_t retval; ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); if( waitflag ) { retval = acquire_sem( (sem_id)sema ); --- 357,363 ---- { status_t retval; ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); if( waitflag ) { retval = acquire_sem( (sem_id)sema ); *************** *** 370,376 **** return 0; } ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return -1; } --- 370,376 ---- return 0; } ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return -1; } *************** *** 378,384 **** { status_t retval; ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); retval = release_sem( (sem_id)sema ); if( retval != B_NO_ERROR ) { --- 378,384 ---- { status_t retval; ! dprintf(("PyThread_up_sema(%p)\n", sema)); retval = release_sem( (sem_id)sema ); if( retval != B_NO_ERROR ) { diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_cthread.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_cthread.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_cthread.h Mon Dec 21 11:32:30 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_cthread.h Fri May 12 12:53:34 2000 *************** *** 129,141 **** free((void *) lock); lock = 0; } ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); mutex_free(lock); } --- 129,141 ---- free((void *) lock); lock = 0; } ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%p) called\n", lock)); mutex_free(lock); } *************** *** 143,162 **** { int success = FALSE; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); if (waitflag) { /* blocking */ mutex_lock(lock); success = TRUE; } else { /* non blocking */ success = mutex_try_lock(lock); } ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); mutex_unlock((mutex_t )lock); } --- 143,162 ---- { int success = FALSE; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); if (waitflag) { /* blocking */ mutex_lock(lock); success = TRUE; } else { /* non blocking */ success = mutex_try_lock(lock); } ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%p) called\n", lock)); mutex_unlock((mutex_t )lock); } *************** *** 181,203 **** if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); } --- 181,203 ---- if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%p) called\n", sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%p)\n", sema)); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_foobar.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_foobar.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_foobar.h Mon Dec 21 11:32:30 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_foobar.h Fri May 12 12:55:37 2000 *************** *** 108,134 **** if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); } int PyThread_acquire_lock _P2(lock, PyThread_type_lock lock, waitflag, int waitflag) { int success; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); } /* --- 108,134 ---- if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%p) called\n", lock)); } int PyThread_acquire_lock _P2(lock, PyThread_type_lock lock, waitflag, int waitflag) { int success; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%p) called\n", lock)); } /* *************** *** 140,162 **** if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); } --- 140,162 ---- if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%p) called\n", sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%p)\n", sema)); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_lwp.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_lwp.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_lwp.h Mon Dec 21 11:32:31 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_lwp.h Fri May 12 12:57:29 2000 *************** *** 137,149 **** lock->lock_locked = 0; (void) mon_create(&lock->lock_monitor); (void) cv_create(&lock->lock_condvar, lock->lock_monitor); ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); mon_destroy(((struct lock *) lock)->lock_monitor); free((char *) lock); } --- 137,149 ---- lock->lock_locked = 0; (void) mon_create(&lock->lock_monitor); (void) cv_create(&lock->lock_condvar, lock->lock_monitor); ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%p) called\n", lock)); mon_destroy(((struct lock *) lock)->lock_monitor); free((char *) lock); } *************** *** 152,158 **** { int success; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); success = 0; (void) mon_enter(((struct lock *) lock)->lock_monitor); --- 152,158 ---- { int success; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); success = 0; (void) mon_enter(((struct lock *) lock)->lock_monitor); *************** *** 165,177 **** } cv_broadcast(((struct lock *) lock)->lock_condvar); mon_exit(((struct lock *) lock)->lock_monitor); ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); (void) mon_enter(((struct lock *) lock)->lock_monitor); ((struct lock *) lock)->lock_locked = 0; cv_broadcast(((struct lock *) lock)->lock_condvar); --- 165,177 ---- } cv_broadcast(((struct lock *) lock)->lock_condvar); mon_exit(((struct lock *) lock)->lock_monitor); ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%p) called\n", lock)); (void) mon_enter(((struct lock *) lock)->lock_monitor); ((struct lock *) lock)->lock_locked = 0; cv_broadcast(((struct lock *) lock)->lock_condvar); *************** *** 188,210 **** if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); } --- 188,210 ---- if (!initialized) PyThread_init_thread(); ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%p) called\n", sema)); } int PyThread_down_sema _P2(sema, PyThread_type_sema sema, waitflag, int waitflag) { ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return -1; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%p)\n", sema)); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_nt.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_nt.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_nt.h Fri May 12 10:08:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_nt.h Fri May 12 12:59:50 2000 *************** *** 266,279 **** aLock = AllocNonRecursiveMutex() ; ! dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); FreeNonRecursiveMutex(aLock) ; } --- 270,283 ---- aLock = AllocNonRecursiveMutex() ; ! dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); FreeNonRecursiveMutex(aLock) ; } *************** *** 288,308 **** { int success ; ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag)); success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ; ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) -> %d\n", PyThread_get_thread_ident(),(long)aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) ! dprintf(("%ld: Could not PyThread_release_lock(%lx) error: %l\n", PyThread_get_thread_ident(), (long)aLock, GetLastError())); } /* --- 292,312 ---- { int success ; ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag == 1 ? INFINITE : 0)) == WAIT_OBJECT_0 ; ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) ! dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); } /* *************** *** 321,334 **** INT_MAX, /* Maximum value */ NULL); /* Name of semaphore */ ! dprintf(("%ld: PyThread_allocate_sema() -> %lx\n", PyThread_get_thread_ident(), (long)aSemaphore)); return (PyThread_type_sema) aSemaphore; } void PyThread_free_sema(PyThread_type_sema aSemaphore) { ! dprintf(("%ld: PyThread_free_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore)); CloseHandle((HANDLE) aSemaphore); } --- 325,338 ---- INT_MAX, /* Maximum value */ NULL); /* Name of semaphore */ ! dprintf(("%ld: PyThread_allocate_sema() -> %p\n", PyThread_get_thread_ident(), aSemaphore)); return (PyThread_type_sema) aSemaphore; } void PyThread_free_sema(PyThread_type_sema aSemaphore) { ! dprintf(("%ld: PyThread_free_sema(%p) called\n", PyThread_get_thread_ident(), aSemaphore)); CloseHandle((HANDLE) aSemaphore); } *************** *** 340,350 **** { DWORD waitResult; ! dprintf(("%ld: PyThread_down_sema(%lx) called\n", PyThread_get_thread_ident(), (long)aSemaphore)); waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE); ! dprintf(("%ld: PyThread_down_sema(%lx) return: %l\n", PyThread_get_thread_ident(),(long) aSemaphore, waitResult)); return 0; } --- 344,354 ---- { DWORD waitResult; ! dprintf(("%ld: PyThread_down_sema(%p) called\n", PyThread_get_thread_ident(), aSemaphore)); waitResult = WaitForSingleObject( (HANDLE) aSemaphore, INFINITE); ! dprintf(("%ld: PyThread_down_sema(%p) return: %l\n", PyThread_get_thread_ident(), aSemaphore, waitResult)); return 0; } *************** *** 355,359 **** 1, /* increment count by one */ NULL); /* not interested in previous count */ ! dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore)); } --- 359,363 ---- 1, /* increment count by one */ NULL); /* not interested in previous count */ ! dprintf(("%ld: PyThread_up_sema(%p)\n", PyThread_get_thread_ident(), aSemaphore)); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_os2.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_os2.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_os2.h Mon Dec 21 11:32:33 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_os2.h Fri May 12 13:01:55 2000 *************** *** 141,154 **** 0, /* shared ? */ 0); /* initial state */ ! dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); DosCloseMutexSem((HMTX)aLock); } --- 141,154 ---- 0, /* shared ? */ 0); /* initial state */ ! dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); DosCloseMutexSem((HMTX)aLock); } *************** *** 166,173 **** PID pid = 0; TID tid = 0; ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(), ! (long)aLock, waitflag)); DosQueryMutexSem((HMTX)aLock,&pid,&tid,&count); if( tid == PyThread_get_thread_ident() ) { /* if we own this lock */ --- 166,173 ---- PID pid = 0; TID tid = 0; ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(), ! aLock, waitflag)); DosQueryMutexSem((HMTX)aLock,&pid,&tid,&count); if( tid == PyThread_get_thread_ident() ) { /* if we own this lock */ *************** *** 181,199 **** } } ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) -> %d\n", ! PyThread_get_thread_ident(),(long)aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); if ( DosReleaseMutexSem( (HMTX) aLock ) != 0 ) { ! dprintf(("%ld: Could not PyThread_release_lock(%lx) error: %l\n", ! PyThread_get_thread_ident(), (long)aLock, GetLastError())); } } --- 181,199 ---- } } ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", ! PyThread_get_thread_ident(),aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); if ( DosReleaseMutexSem( (HMTX) aLock ) != 0 ) { ! dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", ! PyThread_get_thread_ident(), aLock, GetLastError())); } } *************** *** 217,221 **** void PyThread_up_sema(PyThread_type_sema aSemaphore) { ! dprintf(("%ld: PyThread_up_sema(%lx)\n", PyThread_get_thread_ident(), (long)aSemaphore)); } --- 217,221 ---- void PyThread_up_sema(PyThread_type_sema aSemaphore) { ! dprintf(("%ld: PyThread_up_sema(%p)\n", PyThread_get_thread_ident(), aSemaphore)); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_pth.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_pth.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_pth.h Mon May 8 06:36:49 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_pth.h Fri May 12 13:11:04 2000 *************** *** 168,174 **** lock = NULL; } } ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } --- 168,174 ---- lock = NULL; } } ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } *************** *** 177,183 **** pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); free((void *)thelock); } --- 177,183 ---- pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_free_lock(%p) called\n", lock)); free((void *)thelock); } *************** *** 188,194 **** pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL); CHECK_STATUS("pth_mutex_acquire[1]"); --- 188,194 ---- pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL); CHECK_STATUS("pth_mutex_acquire[1]"); *************** *** 215,221 **** success = 1; } if (error) success = 0; ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } --- 215,221 ---- success = 1; } if (error) success = 0; ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } *************** *** 224,230 **** pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); status = pth_mutex_acquire( &thelock->mut, 0, NULL ); CHECK_STATUS("pth_mutex_acquire[3]"); --- 224,230 ---- pth_lock *thelock = (pth_lock *)lock; int status, error = 0; ! dprintf(("PyThread_release_lock(%p) called\n", lock)); status = pth_mutex_acquire( &thelock->mut, 0, NULL ); CHECK_STATUS("pth_mutex_acquire[3]"); *************** *** 270,276 **** sema = NULL; } } ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } --- 270,276 ---- sema = NULL; } } ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } *************** *** 279,285 **** int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); free((void *) thesema); } --- 279,285 ---- int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_free_sema(%p) called\n", sema)); free((void *) thesema); } *************** *** 288,294 **** int status, error = 0, success; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); status = pth_mutex_acquire(&thesema->mutex, !waitflag, NULL); CHECK_STATUS("pth_mutex_acquire"); if (waitflag) { --- 288,294 ---- int status, error = 0, success; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); status = pth_mutex_acquire(&thesema->mutex, !waitflag, NULL); CHECK_STATUS("pth_mutex_acquire"); if (waitflag) { *************** *** 308,314 **** success = 0; status = pth_mutex_release(&thesema->mutex); CHECK_STATUS("pth_mutex_release"); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return success; } --- 308,314 ---- success = 0; status = pth_mutex_release(&thesema->mutex); CHECK_STATUS("pth_mutex_release"); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return success; } *************** *** 317,323 **** int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); status = pth_mutex_acquire(&thesema->mutex, 0, NULL); CHECK_STATUS("pth_mutex_acquire"); thesema->value++; --- 317,323 ---- int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_up_sema(%p)\n", sema)); status = pth_mutex_acquire(&thesema->mutex, 0, NULL); CHECK_STATUS("pth_mutex_acquire"); thesema->value++; diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_pthread.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_pthread.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_pthread.h Mon Mar 15 12:27:53 1999 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_pthread.h Fri May 12 13:03:22 2000 *************** *** 272,278 **** } } ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } --- 272,278 ---- } } ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } *************** *** 281,287 **** pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); status = pthread_mutex_destroy( &thelock->mut ); CHECK_STATUS("pthread_mutex_destroy"); --- 281,287 ---- pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_free_lock(%p) called\n", lock)); status = pthread_mutex_destroy( &thelock->mut ); CHECK_STATUS("pthread_mutex_destroy"); *************** *** 298,304 **** pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); --- 298,304 ---- pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); *************** *** 325,331 **** success = 1; } if (error) success = 0; ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } --- 325,331 ---- success = 1; } if (error) success = 0; ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } *************** *** 334,340 **** pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[3]"); --- 334,340 ---- pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; ! dprintf(("PyThread_release_lock(%p) called\n", lock)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[3]"); *************** *** 382,388 **** sema = NULL; } } ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } --- 382,388 ---- sema = NULL; } } ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } *************** *** 391,397 **** int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); status = pthread_cond_destroy(&thesema->cond); CHECK_STATUS("pthread_cond_destroy"); status = pthread_mutex_destroy(&thesema->mutex); --- 391,397 ---- int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_free_sema(%p) called\n", sema)); status = pthread_cond_destroy(&thesema->cond); CHECK_STATUS("pthread_cond_destroy"); status = pthread_mutex_destroy(&thesema->mutex); *************** *** 404,410 **** int status, error = 0, success; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag)); status = pthread_mutex_lock(&thesema->mutex); CHECK_STATUS("pthread_mutex_lock"); if (waitflag) { --- 404,410 ---- int status, error = 0, success; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag)); status = pthread_mutex_lock(&thesema->mutex); CHECK_STATUS("pthread_mutex_lock"); if (waitflag) { *************** *** 424,430 **** success = 0; status = pthread_mutex_unlock(&thesema->mutex); CHECK_STATUS("pthread_mutex_unlock"); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return success; } --- 424,430 ---- success = 0; status = pthread_mutex_unlock(&thesema->mutex); CHECK_STATUS("pthread_mutex_unlock"); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return success; } *************** *** 433,439 **** int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); status = pthread_mutex_lock(&thesema->mutex); CHECK_STATUS("pthread_mutex_lock"); thesema->value++; --- 433,439 ---- int status, error = 0; struct semaphore *thesema = (struct semaphore *) sema; ! dprintf(("PyThread_up_sema(%p)\n", sema)); status = pthread_mutex_lock(&thesema->mutex); CHECK_STATUS("pthread_mutex_lock"); thesema->value++; diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_sgi.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_sgi.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_sgi.h Mon Dec 21 11:32:34 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_sgi.h Fri May 12 13:06:28 2000 *************** *** 119,125 **** if (usconfig(CONF_INITSIZE, size) < 0) perror("usconfig - CONF_INITSIZE (reset)"); addr = (long) dl_getrange(size + HDR_SIZE); ! dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size)); errno = 0; if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) perror("usconfig - CONF_ATTACHADDR (set)"); --- 119,125 ---- if (usconfig(CONF_INITSIZE, size) < 0) perror("usconfig - CONF_INITSIZE (reset)"); addr = (long) dl_getrange(size + HDR_SIZE); ! dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size)); errno = 0; if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) perror("usconfig - CONF_ATTACHADDR (set)"); *************** *** 157,163 **** (void) usinitlock(count_lock); if ((wait_lock = usnewlock(shared_arena)) == NULL) perror("usnewlock (wait_lock)"); ! dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); } /* --- 157,163 ---- (void) usinitlock(count_lock); if ((wait_lock = usnewlock(shared_arena)) == NULL) perror("usnewlock (wait_lock)"); ! dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); } /* *************** *** 224,230 **** if (usconfig(CONF_INITSIZE, size) < 0) perror("usconfig - CONF_INITSIZE (reset)"); addr = (long) dl_getrange(size + HDR_SIZE); ! dprintf(("trying to use addr %lx-%lx for sproc\n", addr, addr+size)); errno = 0; if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && --- 224,230 ---- if (usconfig(CONF_INITSIZE, size) < 0) perror("usconfig - CONF_INITSIZE (reset)"); addr = (long) dl_getrange(size + HDR_SIZE); ! dprintf(("trying to use addr %p-%p for sproc\n", addr, addr+size)); errno = 0; if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && *************** *** 375,387 **** if ((lock = usnewlock(shared_arena)) == NULL) perror("usnewlock"); (void) usinitlock(lock); ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); usfreelock((ulock_t) lock, shared_arena); } --- 375,387 ---- if ((lock = usnewlock(shared_arena)) == NULL) perror("usnewlock"); (void) usinitlock(lock); ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%p) called\n", lock)); usfreelock((ulock_t) lock, shared_arena); } *************** *** 389,395 **** { int success; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); errno = 0; /* clear it just in case */ if (waitflag) success = ussetlock((ulock_t) lock); --- 389,395 ---- { int success; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); errno = 0; /* clear it just in case */ if (waitflag) success = ussetlock((ulock_t) lock); *************** *** 397,409 **** success = uscsetlock((ulock_t) lock, 1); /* Try it once */ if (success < 0) perror(waitflag ? "ussetlock" : "uscsetlock"); ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); if (usunsetlock((ulock_t) lock) < 0) perror("usunsetlock"); } --- 397,409 ---- success = uscsetlock((ulock_t) lock, 1); /* Try it once */ if (success < 0) perror(waitflag ? "ussetlock" : "uscsetlock"); ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%p) called\n", lock)); if (usunsetlock((ulock_t) lock) < 0) perror("usunsetlock"); } *************** *** 420,432 **** if ((sema = usnewsema(shared_arena, value)) == NULL) perror("usnewsema"); ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); usfreesema((usema_t *) sema, shared_arena); } --- 420,432 ---- if ((sema = usnewsema(shared_arena, value)) == NULL) perror("usnewsema"); ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%p) called\n", sema)); usfreesema((usema_t *) sema, shared_arena); } *************** *** 434,453 **** { int success; ! dprintf(("PyThread_down_sema(%lx) called\n", (long) sema)); if (waitflag) success = uspsema((usema_t *) sema); else success = uscpsema((usema_t *) sema); if (success < 0) perror(waitflag ? "uspsema" : "uscpsema"); ! dprintf(("PyThread_down_sema(%lx) return\n", (long) sema)); return success; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); if (usvsema((usema_t *) sema) < 0) perror("usvsema"); } --- 434,453 ---- { int success; ! dprintf(("PyThread_down_sema(%p) called\n", sema)); if (waitflag) success = uspsema((usema_t *) sema); else success = uscpsema((usema_t *) sema); if (success < 0) perror(waitflag ? "uspsema" : "uscpsema"); ! dprintf(("PyThread_down_sema(%p) return\n", sema)); return success; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%p)\n", sema)); if (usvsema((usema_t *) sema) < 0) perror("usvsema"); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_solaris.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_solaris.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_solaris.h Tue Apr 13 07:32:12 1999 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_solaris.h Fri May 12 13:08:14 2000 *************** *** 157,169 **** free((void *) lock); lock = 0; } ! dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%lx) called\n", (long)lock)); mutex_destroy((mutex_t *) lock); free((void *) lock); } --- 157,169 ---- free((void *) lock); lock = 0; } ! dprintf(("PyThread_allocate_lock() -> %p\n", lock)); return (PyThread_type_lock) lock; } void PyThread_free_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_free_lock(%p) called\n", lock)); mutex_destroy((mutex_t *) lock); free((void *) lock); } *************** *** 172,178 **** { int success; ! dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag)); if (waitflag) success = mutex_lock((mutex_t *) lock); else --- 172,178 ---- { int success; ! dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); if (waitflag) success = mutex_lock((mutex_t *) lock); else *************** *** 181,193 **** perror(waitflag ? "mutex_lock" : "mutex_trylock"); else success = !success; /* solaris does it the other way round */ ! dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%lx) called\n", (long)lock)); if (mutex_unlock((mutex_t *) lock)) perror("mutex_unlock"); } --- 181,193 ---- perror(waitflag ? "mutex_lock" : "mutex_trylock"); else success = !success; /* solaris does it the other way round */ ! dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); return success; } void PyThread_release_lock _P1(lock, PyThread_type_lock lock) { ! dprintf(("PyThread_release_lock(%p) called\n", lock)); if (mutex_unlock((mutex_t *) lock)) perror("mutex_unlock"); } *************** *** 208,220 **** free((void *) sema); sema = 0; } ! dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%lx) called\n", (long) sema)); if (sema_destroy((sema_t *) sema)) perror("sema_destroy"); free((void *) sema); --- 208,220 ---- free((void *) sema); sema = 0; } ! dprintf(("PyThread_allocate_sema() -> %p\n", sema)); return (PyThread_type_sema) sema; } void PyThread_free_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_free_sema(%p) called\n", sema)); if (sema_destroy((sema_t *) sema)) perror("sema_destroy"); free((void *) sema); *************** *** 224,230 **** { int success; ! dprintf(("PyThread_down_sema(%lx) called\n", (long) sema)); if (waitflag) success = sema_wait((sema_t *) sema); else --- 224,230 ---- { int success; ! dprintf(("PyThread_down_sema(%p) called\n", sema)); if (waitflag) success = sema_wait((sema_t *) sema); else *************** *** 237,249 **** } else success = !success; ! dprintf(("PyThread_down_sema(%lx) return %d\n", (long) sema, success)); return success; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%lx)\n", (long) sema)); if (sema_post((sema_t *) sema)) perror("sema_post"); } --- 237,249 ---- } else success = !success; ! dprintf(("PyThread_down_sema(%p) return %d\n", sema, success)); return success; } void PyThread_up_sema _P1(sema, PyThread_type_sema sema) { ! dprintf(("PyThread_up_sema(%p)\n", sema)); if (sema_post((sema_t *) sema)) perror("sema_post"); } diff -c3 /home/trentm/main/contrib/python/dist/src/Python/thread_wince.h /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_wince.h *** /home/trentm/main/contrib/python/dist/src/Python/thread_wince.h Thu Apr 8 06:57:06 1999 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_wince.h Fri May 12 13:10:04 2000 *************** *** 144,157 **** 1, /* Is initially signalled */ NULL); /* Name of event */ ! dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", PyThread_get_thread_ident(), (long)aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); CloseHandle(aLock); } --- 144,157 ---- 1, /* Is initially signalled */ NULL); /* Name of event */ ! dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); return (PyThread_type_lock) aLock; } void PyThread_free_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); CloseHandle(aLock); } *************** *** 167,173 **** int success = 1; DWORD waitResult; ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) called\n", PyThread_get_thread_ident(),(long)aLock, waitflag)); #ifndef DEBUG waitResult = WaitForSingleObject(aLock, (waitflag == 1 ? INFINITE : 0)); --- 167,173 ---- int success = 1; DWORD waitResult; ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); #ifndef DEBUG waitResult = WaitForSingleObject(aLock, (waitflag == 1 ? INFINITE : 0)); *************** *** 185,201 **** success = 0; /* We failed */ } ! dprintf(("%ld: PyThread_acquire_lock(%lx, %d) -> %d\n", PyThread_get_thread_ident(),(long)aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%lx) called\n", PyThread_get_thread_ident(),(long)aLock)); if (!SetEvent(aLock)) ! dprintf(("%ld: Could not PyThread_release_lock(%lx) error: %l\n", PyThread_get_thread_ident(), (long)aLock, GetLastError())); } --- 185,201 ---- success = 0; /* We failed */ } ! dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); return success; } void PyThread_release_lock(PyThread_type_lock aLock) { ! dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); if (!SetEvent(aLock)) ! dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); } diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/bufferobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/bufferobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/bufferobject.c Wed May 3 16:44:34 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/bufferobject.c Wed May 3 18:01:15 2000 *************** *** 241,260 **** if ( self->b_base == NULL ) { ! sprintf(buf, "<%s buffer ptr %lx, size %d at %lx>", status, ! (long)self->b_ptr, self->b_size, ! (long)self); } else { ! sprintf(buf, "<%s buffer for %lx, ptr %lx, size %d at %lx>", status, ! (long)self->b_base, ! (long)self->b_ptr, self->b_size, ! (long)self); } return PyString_FromString(buf); --- 241,260 ---- if ( self->b_base == NULL ) { ! sprintf(buf, "<%s buffer ptr %p, size %d at %p>", status, ! self->b_ptr, self->b_size, ! self); } else { ! sprintf(buf, "<%s buffer for %p, ptr %p, size %d at %p>", status, ! self->b_base, ! self->b_ptr, self->b_size, ! self); } return PyString_FromString(buf); diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/classobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/classobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Wed May 3 16:44:34 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/classobject.c Thu May 11 20:31:51 2000 *************** *** 351,361 **** else name = PyString_AsString(op->cl_name); if (mod == NULL || !PyString_Check(mod)) ! sprintf(buf, "", name, (long)op); else ! sprintf(buf, "", PyString_AsString(mod), ! name, (long)op); return PyString_FromString(buf); } --- 351,361 ---- else name = PyString_AsString(op->cl_name); if (mod == NULL || !PyString_Check(mod)) ! sprintf(buf, "", name, op); else ! sprintf(buf, "", PyString_AsString(mod), ! name, op); return PyString_FromString(buf); } *************** *** 757,768 **** cname = "?"; PyErr_Clear(); if (mod == NULL || !PyString_Check(mod)) ! sprintf(buf, "", ! cname, (long)inst); else ! sprintf(buf, "<%.50s.%.50s instance at %lx>", PyString_AsString(mod), ! cname, (long)inst); return PyString_FromString(buf); } res = PyEval_CallObject(func, (PyObject *)NULL); --- 757,768 ---- cname = "?"; PyErr_Clear(); if (mod == NULL || !PyString_Check(mod)) ! sprintf(buf, "", ! cname, inst); else ! sprintf(buf, "<%.50s.%.50s instance at %p>", PyString_AsString(mod), ! cname, inst); return PyString_FromString(buf); } res = PyEval_CallObject(func, (PyObject *)NULL); *************** *** 1638,1645 **** icname = PyString_AsString(iclassname); else icname = "?"; ! sprintf(buf, "", ! fcname, fname, icname, (long)self); } Py_XDECREF(funcname); return PyString_FromString(buf); --- 1635,1642 ---- icname = PyString_AsString(iclassname); else icname = "?"; ! sprintf(buf, "", ! fcname, fname, icname, self); } Py_XDECREF(funcname); return PyString_FromString(buf); diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/fileobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/fileobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/fileobject.c Wed May 3 16:44:34 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/fileobject.c Wed May 3 18:01:16 2000 *************** *** 223,233 **** PyFileObject *f; { char buf[300]; ! sprintf(buf, "<%s file '%.256s', mode '%.10s' at %lx>", f->f_fp == NULL ? "closed" : "open", PyString_AsString(f->f_name), PyString_AsString(f->f_mode), ! (long)f); return PyString_FromString(buf); } --- 223,233 ---- PyFileObject *f; { char buf[300]; ! sprintf(buf, "<%s file '%.256s', mode '%.10s' at %p>", f->f_fp == NULL ? "closed" : "open", PyString_AsString(f->f_name), PyString_AsString(f->f_mode), ! f); return PyString_FromString(buf); } diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/floatobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Wed May 3 16:44:34 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/floatobject.c Thu May 11 20:27:05 2000 *************** *** 805,812 **** char buf[100]; PyFloat_AsString(buf, p); fprintf(stderr, ! "# \n", ! (long)p, p->ob_refcnt, buf); } } list = list->next; --- 806,813 ---- char buf[100]; PyFloat_AsString(buf, p); fprintf(stderr, ! "# \n", ! p, p->ob_refcnt, buf); } } list = list->next; diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/funcobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c Wed May 3 16:44:35 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/funcobject.c Thu May 11 20:28:45 2000 *************** *** 200,210 **** { char buf[140]; if (op->func_name == Py_None) ! sprintf(buf, "", (long)op); else ! sprintf(buf, "", PyString_AsString(op->func_name), ! (long)op); return PyString_FromString(buf); } --- 200,210 ---- { char buf[140]; if (op->func_name == Py_None) ! sprintf(buf, "", op); else ! sprintf(buf, "", PyString_AsString(op->func_name), ! op); return PyString_FromString(buf); } diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/intobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/intobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/intobject.c Tue May 9 07:27:48 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/intobject.c Tue May 9 17:20:56 2000 *************** *** 957,964 **** i++, p++) { if (PyInt_Check(p) && p->ob_refcnt != 0) fprintf(stderr, ! "# \n", ! (long)p, p->ob_refcnt, p->ob_ival); } list = list->next; } --- 957,964 ---- i++, p++) { if (PyInt_Check(p) && p->ob_refcnt != 0) fprintf(stderr, ! "# \n", ! p, p->ob_refcnt, p->ob_ival); } list = list->next; } diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/methodobject.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/methodobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/methodobject.c Wed May 3 16:44:35 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/methodobject.c Thu May 11 20:32:39 2000 *************** *** 148,156 **** sprintf(buf, "", m->m_ml->ml_name); else sprintf(buf, ! "", m->m_ml->ml_name, m->m_self->ob_type->tp_name, ! (long)m->m_self); return PyString_FromString(buf); } --- 148,156 ---- sprintf(buf, "", m->m_ml->ml_name); else sprintf(buf, ! "", m->m_ml->ml_name, m->m_self->ob_type->tp_name, ! m->m_self); return PyString_FromString(buf); } diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/object.c /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/object.c *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Wed May 3 16:44:35 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/object.c Thu May 11 20:30:57 2000 *************** *** 197,208 **** } else { if (op->ob_refcnt <= 0) ! fprintf(fp, "", ! op->ob_refcnt, (long)op); else if (op->ob_type->tp_print == NULL) { if (op->ob_type->tp_repr == NULL) { ! fprintf(fp, "<%s object at %lx>", ! op->ob_type->tp_name, (long)op); } else { PyObject *s; --- 199,210 ---- } else { if (op->ob_refcnt <= 0) ! fprintf(fp, "", ! op->ob_refcnt, op); else if (op->ob_type->tp_print == NULL) { if (op->ob_type->tp_repr == NULL) { ! fprintf(fp, "<%s object at %p>", ! op->ob_type->tp_name, op); } else { PyObject *s; *************** *** 248,255 **** return PyString_FromString(""); else if (v->ob_type->tp_repr == NULL) { char buf[120]; ! sprintf(buf, "<%.80s object at %lx>", ! v->ob_type->tp_name, (long)v); return PyString_FromString(buf); } else { --- 250,257 ---- return PyString_FromString(""); else if (v->ob_type->tp_repr == NULL) { char buf[120]; ! sprintf(buf, "<%.80s object at %p>", ! v->ob_type->tp_name, v); return PyString_FromString(buf); } else { diff -c3 /home/trentm/main/contrib/python/dist/src/Python/compile.c /home/trentm/main/Apps/Perlium/Python/dist/src/Python/compile.c *** /home/trentm/main/contrib/python/dist/src/Python/compile.c Wed May 3 16:44:38 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/compile.c Wed May 3 18:01:23 2000 *************** *** 130,137 **** filename = PyString_AsString(co->co_filename); if (co->co_name && PyString_Check(co->co_name)) name = PyString_AsString(co->co_name); ! sprintf(buf, "", ! name, (long)co, filename, lineno); return PyString_FromString(buf); } --- 130,137 ---- filename = PyString_AsString(co->co_filename); if (co->co_name && PyString_Check(co->co_name)) name = PyString_AsString(co->co_name); ! sprintf(buf, "", ! name, co, filename, lineno); return PyString_FromString(buf); } -- Trent Mick trentm@activestate.com From gstein@lyra.org Fri Jun 2 21:26:45 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 2 Jun 2000 13:26:45 -0700 (PDT) Subject: [Patches] changes to configure.in and PC/config.h for 64-bit systems In-Reply-To: <20000602001552.A3205@activestate.com> Message-ID: On Fri, 2 Jun 2000, Trent Mick wrote: >... > If you would rather, I can submit the whole patch (for all the config system > files) together. It would be nice to see them all together again. You don't need to send a patch for "configure". The configure.in patch will be applied, then "autoconf" will be run to generate the new configure file. Cheers, -g -- Greg Stein, http://www.lyra.org/ From Jack.Jansen@oratrix.com Fri Jun 2 21:59:44 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 22:59:44 +0200 Subject: [Patches] Patch to Modules/pcre.h Message-ID: <39382040.3BF69C34@oratrix.com> This is a multi-part message in MIME format. --------------CE75686B9EBE017773C14352 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Don't include sys/types.h or sys/stat.h if the platform doesn't have it (eg. Carbon, the MacOS9/MacOSX combined development layer). ---- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. --------------CE75686B9EBE017773C14352 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="pcre.diffs" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="pcre.diffs" cvs server: Diffing . Index: pcre.h =================================================================== RCS file: /projects/cvsroot/python/dist/src/Modules/pcre.h,v retrieving revision 2.7 diff -c -r2.7 pcre.h *** pcre.h 1998/05/07 15:32:41 2.7 --- pcre.h 2000/06/02 13:33:19 *************** *** 14,20 **** --- 14,22 ---- /* Have to include stdlib.h in order to ensure that size_t is defined; it is needed here for malloc. */ + #ifndef DONT_HAVE_SYS_TYPES_H #include + #endif #include /* Allow for C++ users */ --------------CE75686B9EBE017773C14352-- From Jack.Jansen@oratrix.com Fri Jun 2 22:00:30 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 23:00:30 +0200 Subject: [Patches] Patch for getmtime.c Message-ID: <3938206D.8300B446@oratrix.com> Don't include sys/types.h or sys/stat.h if the platform doesn't have it (eg. Carbon, the MacOS9/MacOSX combined development layer). ---- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. From Jack.Jansen@oratrix.com Fri Jun 2 22:02:13 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 23:02:13 +0200 Subject: [Patches] Patch to import.c Message-ID: <393820D4.ECC15054@oratrix.com> Don't include sys/types.h or sys/stat.h if the platform doesn't have it (eg. Carbon, the MacOS9/MacOSX combined development layer). Handle comparison of pyc filename slightly different for Carbon compatability (Mac only). ---- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. From Jack.Jansen@oratrix.com Fri Jun 2 22:07:01 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 23:07:01 +0200 Subject: [Patches] Patches to Tools/bgen/bgen Message-ID: <393821F4.DDD41BC2@oratrix.com> This is a multi-part message in MIME format. --------------E35E8D3A3B57D281C34DA3E2 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit These patches contain a new feature, greylists, to allow conditional compilation of certain methods. Greylist items are a string like "#ifdef FOO" plus a list of function names whose wrappers will be generated within such an #if/#ifdef. ---- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. --------------E35E8D3A3B57D281C34DA3E2 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="bgen.diffs" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="bgen.diffs" cvs server: Diffing . cvs server: Diffing bgen Index: bgen/bgenGenerator.py =================================================================== RCS file: /projects/cvsroot/python/dist/src/Tools/bgen/bgen/bgenGenerator.py,v retrieving revision 1.6 diff -c -r1.6 bgenGenerator.py *** bgenGenerator.py 1995/06/18 20:08:28 1.6 --- bgenGenerator.py 2000/06/02 13:31:49 *************** *** 14,33 **** class BaseFunctionGenerator: ! def __init__(self, name): print "<--", name self.name = name self.prefix = name self.objecttype = "PyObject" # Type of _self argument to function def setprefix(self, prefix): self.prefix = prefix def generate(self): print "-->", self.name self.functionheader() self.functionbody() self.functiontrailer() def functionheader(self): Output() --- 14,39 ---- class BaseFunctionGenerator: ! def __init__(self, name, condition=None): print "<--", name self.name = name self.prefix = name self.objecttype = "PyObject" # Type of _self argument to function + self.condition = condition def setprefix(self, prefix): self.prefix = prefix def generate(self): print "-->", self.name + if self.condition: + Output() + Output(self.condition) self.functionheader() self.functionbody() self.functiontrailer() + if self.condition: + Output("#endif") def functionheader(self): Output() *************** *** 50,57 **** --- 56,68 ---- if name is None: name = self.name docstring = self.docstring() + if self.condition: + Output() + Output(self.condition) Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name) Output(" %s},", stringify(docstring)) + if self.condition: + Output("#endif") def docstring(self): return None *************** *** 73,80 **** class ManualGenerator(BaseFunctionGenerator): ! def __init__(self, name, body): ! BaseFunctionGenerator.__init__(self, name) self.body = body def functionbody(self): --- 84,91 ---- class ManualGenerator(BaseFunctionGenerator): ! def __init__(self, name, body, condition=None): ! BaseFunctionGenerator.__init__(self, name, condition=condition) self.body = body def functionbody(self): *************** *** 87,94 **** class FunctionGenerator(BaseFunctionGenerator): ! def __init__(self, returntype, name, *argumentList): ! BaseFunctionGenerator.__init__(self, name) self.returntype = returntype self.argumentList = [] self.setreturnvar() --- 98,105 ---- class FunctionGenerator(BaseFunctionGenerator): ! def __init__(self, returntype, name, *argumentList, **conditionlist): ! BaseFunctionGenerator.__init__(self, name, **conditionlist) self.returntype = returntype self.argumentList = [] self.setreturnvar() Index: bgen/bgenlocations.py =================================================================== RCS file: /projects/cvsroot/python/dist/src/Tools/bgen/bgen/bgenlocations.py,v retrieving revision 1.3 diff -c -r1.3 bgenlocations.py *** bgenlocations.py 1998/02/23 15:30:40 1.3 --- bgenlocations.py 2000/06/02 13:31:49 *************** *** 3,13 **** # # Where to find the Universal Header include files: ! MWERKSDIR="flap:Metrowerks:Metrowerks CodeWarrior:" ! INCLUDEDIR=MWERKSDIR + "MacOS Support:Headers:Universal Headers:" # Where to put the python definitions file: ! TOOLBOXDIR="flap:Jack:Python:Mac:Lib:lib-toolbox:" # Creator for C files: CREATOR="CWIE" --- 3,13 ---- # # Where to find the Universal Header include files: ! MWERKSDIR="Macintosh HD:SWDev:Codewarrior Pro 5:Metrowerks CodeWarrior:" ! INCLUDEDIR=MWERKSDIR + "MacOS Support:Universal:Interfaces:CIncludes:" # Where to put the python definitions file: ! TOOLBOXDIR="Macintosh HD:SWDev:Jack:Python:Mac:Lib:lib-toolbox:" # Creator for C files: CREATOR="CWIE" Index: bgen/scantools.py =================================================================== RCS file: /projects/cvsroot/python/dist/src/Tools/bgen/bgen/scantools.py,v retrieving revision 1.16 diff -c -r1.16 scantools.py *** scantools.py 2000/01/20 20:49:28 1.16 --- scantools.py 2000/06/02 13:31:49 *************** *** 99,110 **** --- 99,121 ---- def initblacklists(self): self.blacklistnames = self.makeblacklistnames() self.blacklisttypes = ["unknown", "-"] + self.makeblacklisttypes() + self.greydictnames = self.greylist2dict(self.makegreylist()) + + def greylist2dict(self, list): + rv = {} + for define, namelist in list: + for name in namelist: + rv[name] = define + return rv def makeblacklistnames(self): return [] def makeblacklisttypes(self): return [] + + def makegreylist(self): + return [] def initrepairinstructions(self): self.repairinstructions = self.makerepairinstructions() *************** *** 395,400 **** --- 406,412 ---- self.defsfile.write("%s = %s\n" % (name, defn)) else: self.defsfile.write("# %s = %s\n" % (name, defn)) + # XXXX No way to handle greylisted names def dofuncspec(self): raw = self.line *************** *** 519,524 **** --- 531,538 ---- self.typeused(atype, amode) self.specfile.write(" (%s, %s, %s),\n" % (atype, `aname`, amode)) + if self.greydictnames.has_key(name): + self.specfile.write(" condition=%s,\n"%`self.greydictnames[name]`) self.specfile.write(")\n") self.specfile.write("%s.append(f)\n\n" % listname) --------------E35E8D3A3B57D281C34DA3E2-- From Jack.Jansen@oratrix.com Fri Jun 2 22:13:21 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 23:13:21 +0200 Subject: [Patches] Patch to fileobject.c Message-ID: <39382370.2279D296@oratrix.com> This is a multi-part message in MIME format. --------------4DB26C1822752BBA52A35D28 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Various includes were halfway the file. Moved to the top to fix problems with multiple includes of files on the Mac. --------------4DB26C1822752BBA52A35D28 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="fileobject.diffs" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="fileobject.diffs" Index: fileobject.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Objects/fileobject.c,v retrieving revision 2.73 diff -c -r2.73 fileobject.c *** fileobject.c 2000/05/03 23:44:34 2.73 --- fileobject.c 2000/06/02 21:09:44 *************** *** 38,43 **** --- 38,63 ---- #include #endif /* DONT_HAVE_SYS_TYPES_H */ + /* We expect that fstat exists on most systems. + It's confirmed on Unix, Mac and Windows. + If you don't have it, add #define DONT_HAVE_FSTAT to your config.h. */ + #ifndef DONT_HAVE_FSTAT + #define HAVE_FSTAT + + #ifndef DONT_HAVE_SYS_TYPES_H + #include + #endif + + #ifndef DONT_HAVE_SYS_STAT_H + #include + #else + #ifdef HAVE_STAT_H + #include + #endif + #endif + + #endif /* DONT_HAVE_FSTAT */ + #ifdef HAVE_UNISTD_H #include #endif *************** *** 445,465 **** return PyInt_FromLong(res); } - /* We expect that fstat exists on most systems. - It's confirmed on Unix, Mac and Windows. - If you don't have it, add #define DONT_HAVE_FSTAT to your config.h. */ - #ifndef DONT_HAVE_FSTAT - #define HAVE_FSTAT - - #ifndef DONT_HAVE_SYS_TYPES_H - #include - #endif - - #ifndef DONT_HAVE_SYS_STAT_H - #include - #endif - - #endif /* DONT_HAVE_FSTAT */ #if BUFSIZ < 8192 #define SMALLCHUNK 8192 --- 465,470 ---- --------------4DB26C1822752BBA52A35D28-- From Jack.Jansen@oratrix.com Fri Jun 2 22:14:27 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Fri, 02 Jun 2000 23:14:27 +0200 Subject: [Patches] Patch to parsetok.c Message-ID: <393823B2.8C18660@oratrix.com> This is a multi-part message in MIME format. --------------401C273F894D7ACCFA1A8F08 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Removed the Mac tab-size-guessing code, which has become obsolete as of tabnanny (and usually didn't work anyway with current editors). --------------401C273F894D7ACCFA1A8F08 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="parsetok.c.diffs" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="parsetok.c.diffs" Index: parsetok.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Parser/parsetok.c,v retrieving revision 2.16 diff -c -r2.16 parsetok.c *** parsetok.c 2000/05/03 23:44:37 2.16 --- parsetok.c 2000/06/02 21:08:23 *************** *** 109,121 **** tok->alterror++; } - #ifdef macintosh - { - int tabsize = guesstabsize(filename); - if (tabsize > 0) - tok->tabsize = tabsize; - } - #endif return parsetok(tok, g, start, err_ret); } --------------401C273F894D7ACCFA1A8F08-- From trentm@activestate.com Fri Jun 2 22:18:24 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 14:18:24 -0700 Subject: [Patches] changes to configure.in and PC/config.h for 64-bit systems In-Reply-To: References: <20000602001552.A3205@activestate.com> Message-ID: <20000602141824.A30580@activestate.com> On Fri, Jun 02, 2000 at 01:26:45PM -0700, Greg Stein wrote: > On Fri, 2 Jun 2000, Trent Mick wrote: > >... > > If you would rather, I can submit the whole patch (for all the config system > > files) together. > > It would be nice to see them all together again. > Here you go: *** /home/trentm/main/contrib/python/dist/src/PC/config.h Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/config.h Thu Jun 1 12:47:45 2000 *************** *** 233,255 **** /* End of compilers - finish up */ #if defined(MS_WIN64) /* maintain "win32" sys.platform for backward compatibility of Python code, the Win64 API should be close enough to the Win32 API to make this preferable */ ! #define PLATFORM "win32" ! #define SIZEOF_VOID_P 8 #elif defined(MS_WIN32) ! #define PLATFORM "win32" ! #ifdef _M_ALPHA ! #define SIZEOF_VOID_P 8 ! #else ! #define SIZEOF_VOID_P 4 ! #endif #elif defined(MS_WIN16) ! #define PLATFORM "win16" #else ! #define PLATFORM "dos" #endif --- 233,277 ---- /* End of compilers - finish up */ + /* define the ANSI intptr_t type for portable use of a pointer sized + integer */ + #include + #if defined(MS_WINDOWS) && !defined(MS_WIN64) + typedef long intptr_t; + #endif + #if defined(MS_WIN64) /* maintain "win32" sys.platform for backward compatibility of Python code, the Win64 API should be close enough to the Win32 API to make this preferable */ ! # define PLATFORM "win32" ! # define SIZEOF_VOID_P 8 ! # define SIZEOF_TIME_T 8 ! # define SIZEOF_OFF_T 4 ! # define SIZEOF_FPOS_T 8 ! # define SIZEOF_HKEY 8 ! /* configure.in defines HAVE_LARGEFILE_SUPPORT iff HAVE_LONG_LONG, ! sizeof(off_t) > sizeof(long), and sizeof(LONG_LONG) >= sizeof(off_t). ! On Win64 the second condition is not true, but if fpos_t replaces off_t ! then this is true. The uses of HAVE_LARGEFILE_SUPPORT imply that Win64 ! should define this. */ ! # define HAVE_LARGEFILE_SUPPORT #elif defined(MS_WIN32) ! # define PLATFORM "win32" ! # ifdef _M_ALPHA ! # define SIZEOF_VOID_P 8 ! # define SIZEOF_TIME_T 8 ! # else ! # define SIZEOF_VOID_P 4 ! # define SIZEOF_TIME_T 4 ! # define SIZEOF_OFF_T 4 ! # define SIZEOF_FPOS_T 8 ! # define SIZEOF_HKEY 4 ! # endif #elif defined(MS_WIN16) ! # define PLATFORM "win16" #else ! # define PLATFORM "dos" #endif *** /home/trentm/main/contrib/python/dist/src/configure.in Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/configure.in Wed May 31 23:54:21 2000 *************** *** 1,5 **** dnl Process this file with autoconf 2.0 or later to make a configure script. ! AC_REVISION($Revision: 1.124 $) AC_PREREQ(2.0) AC_INIT(Include/object.h) AC_CONFIG_HEADER(config.h) --- 1,5 ---- dnl Process this file with autoconf 2.0 or later to make a configure script. ! AC_REVISION($Revision: 1.125 $) AC_PREREQ(2.0) AC_INIT(Include/object.h) AC_CONFIG_HEADER(config.h) *************** *** 389,394 **** --- 389,395 ---- AC_CHECK_SIZEOF(short) AC_CHECK_SIZEOF(float) AC_CHECK_SIZEOF(double) + AC_CHECK_SIZEOF(fpos_t) AC_MSG_CHECKING(for long long support) have_long_long=no *************** *** 423,428 **** --- 424,445 ---- else AC_MSG_RESULT(no) fi + + # AC_CHECK_SIZEOF() doesn't include . + AC_MSG_CHECKING(size of time_t) + AC_CACHE_VAL(ac_cv_sizeof_time_t, + [AC_TRY_RUN([#include + #include + main() + { + FILE *f=fopen("conftestval", "w"); + if (!f) exit(1); + fprintf(f, "%d\n", sizeof(time_t)); + exit(0); + }], ac_cv_sizeof_time_t=`cat conftestval`, ac_cv_sizeof_time_t=0) + ]) + AC_MSG_RESULT($ac_cv_sizeof_time_t) + AC_DEFINE_UNQUOTED(SIZEOF_TIME_T, $ac_cv_sizeof_time_t) # Minor variations in building a framework between NextStep versions 4 and 5 *** /home/trentm/main/contrib/python/dist/src/acconfig.h Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/acconfig.h Wed May 31 23:54:21 2000 *************** *** 151,156 **** --- 151,159 ---- /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T + /* The number of bytes in a time_t. */ + #undef SIZEOF_TIME_T + /* Defined to enable large file support when an off_t is bigger than a long and long long is available and at least as big as an off_t. You may need to add some flags for configuration and compilation to enable this mode. *** /home/trentm/main/contrib/python/dist/src/config.h.in Thu Jun 1 00:13:41 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/config.h.in Thu Jun 1 23:42:08 2000 *************** *** 213,218 **** --- 213,221 ---- /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T + /* The number of bytes in a time_t. */ + #undef SIZEOF_TIME_T + /* Defined to enable large file support when an off_t is bigger than a long and long long is available and at least as big as an off_t. You may need to add some flags for configuration and compilation to enable this mode. *************** *** 234,239 **** --- 237,245 ---- /* The number of bytes in a float. */ #undef SIZEOF_FLOAT + /* The number of bytes in a fpos_t. */ + #undef SIZEOF_FPOS_T + /* The number of bytes in a int. */ #undef SIZEOF_INT *************** *** 527,532 **** --- 533,541 ---- /* Define if you have the header file. */ #undef HAVE_SYS_SELECT_H + + /* Define if you have the header file. */ + #undef HAVE_SYS_SOCKET_H /* Define if you have the header file. */ #undef HAVE_SYS_TIME_H -- Trent Mick trentm@activestate.com From gstein@lyra.org Fri Jun 2 23:26:21 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 2 Jun 2000 15:26:21 -0700 (PDT) Subject: [Patches] PyMarshal_WriteLongToFile: writes 'long' or 32-bit integer? In-Reply-To: <20000602131058.A22280@activestate.com> Message-ID: On Fri, 2 Jun 2000, Trent Mick wrote: > On Fri, Jun 02, 2000 at 09:45:25PM +0200, Peter Funk wrote: >... > > > 3. - change PyMarshal_WriteLongToFile to raise an exception if the long > > > overflows a 32-bit range > > > > We should try to achieve the following goal: .pyc files should be portable > > from 32 bit systems to 64 bit systems and vice versa. This means > > always truncating to 32 bits and raising an exception, if an overflow > > occurs. > > > Or offer PyMarshal_WriteInt32ToFile for import.c and import.c itself can do > the overflow checking on the time stamp. That is the RIght THing(TM) IMO. > > Anyway, my question was intended to be more about the subtlety of marshal > functions rather than the .pyc file headers. No question that the .pyc's > should be portable. I think Peter was referring to integers embedded in the marshalled code in a .pyc, rather than the timestamp. Basically: a marshalled string *must* be portable. That is effectively a language definition. I'm with Peter on this one: marshal.c should raise an exception if an integer overflows the 32-bit value. [ the app writer should use a Long for max portability ] Cheers, -g -- Greg Stein, http://www.lyra.org/ From Jack.Jansen@oratrix.com Fri Jun 2 23:42:56 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Sat, 03 Jun 2000 00:42:56 +0200 Subject: [Patches] Patch to import.c Message-ID: <3938386F.30BD2F46@oratrix.com> This is a multi-part message in MIME format. --------------FA89716025420AE99B4B9785 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Oops, here's the actual patch to import.c. I should get this inferior mail program to warn me when I send something to patches@python.org and don't include an attachment:-) --------------FA89716025420AE99B4B9785 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="import.diffs-" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="import.diffs-" Index: import.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Python/import.c,v retrieving revision 2.134 diff -c -r2.134 import.c *** import.c 2000/05/03 23:44:39 2.134 --- import.c 2000/06/02 13:34:56 *************** *** 60,65 **** --- 60,69 ---- #endif #ifndef DONT_HAVE_SYS_STAT_H #include + #else + #ifdef HAVE_STAT_H + #include + #endif #endif #if defined(PYCC_VACPP) *************** *** 1132,1139 **** name, buf); return 0; } ! p2cstr(fss.name); ! if ( strncmp(name, (char *)fss.name, namelen) != 0 ) { PyErr_Format(PyExc_NameError, "Case mismatch for module name %.100s\n(filename %.300s)", name, fss.name); --- 1136,1142 ---- name, buf); return 0; } ! if ( namelen > fss.name[0] || strncmp(name, (char *)fss.name+1, namelen) != 0 ) { PyErr_Format(PyExc_NameError, "Case mismatch for module name %.100s\n(filename %.300s)", name, fss.name); --------------FA89716025420AE99B4B9785-- From Jack.Jansen@oratrix.com Fri Jun 2 23:44:03 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Sat, 03 Jun 2000 00:44:03 +0200 Subject: [Patches] Another try at a patch to getmtime Message-ID: <393838B2.4060DE80@oratrix.com> This is a multi-part message in MIME format. --------------3A032EE24BA078F4E288C7F3 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Okay, okay.... --------------3A032EE24BA078F4E288C7F3 Content-Type: text/plain; charset=us-ascii; x-mac-type="54455854"; x-mac-creator="522A6368"; name="getmtime.diffs-" Content-Transfer-Encoding: 7bit Content-Description: Unknown Document Content-Disposition: inline; filename="getmtime.diffs-" cvs server: Diffing . Index: getmtime.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Python/getmtime.c,v retrieving revision 2.9 diff -c -r2.9 getmtime.c *** getmtime.c 1997/09/05 07:33:15 2.9 --- getmtime.c 2000/06/02 13:34:55 *************** *** 36,43 **** --- 36,51 ---- #include "config.h" #include + #ifndef DONT_HAVE_SYS_TYPES_H #include + #endif + #ifndef DONT_HAVE_SYS_STAT_H #include + #else + #ifdef HAVE_STAT_H + #include + #endif + #endif long PyOS_GetLastModificationTime(path, fp) --------------3A032EE24BA078F4E288C7F3-- From gstein@lyra.org Fri Jun 2 23:46:56 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 2 Jun 2000 15:46:56 -0700 (PDT) Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: <39382040.3BF69C34@oratrix.com> Message-ID: On Fri, 2 Jun 2000, Jack Jansen wrote: > Don't include sys/types.h or sys/stat.h if the platform doesn't have it (eg. > Carbon, the MacOS9/MacOSX > combined development layer). Hmm... The standard way to do this is to use autoconf to create a HAVE_SYS_TYPES_H define and use that: #ifdef HAVE_SYS_TYPES_H #include #endif In other words, this logic is reversed. Specifically, around line 358 of configure.in, "sys/types.h" should be added. This will result in the HAVE_SYS_TYPES_H define (see config.h). [ this also means that Python's config.h should be included before testing for HAVE_SYS_TYPES_H... :-) ] This recommendation applies to the other patches that are monkeying with conditional header usage. Cheers, -g -- Greg Stein, http://www.lyra.org/ From gstein@lyra.org Fri Jun 2 23:49:32 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 2 Jun 2000 15:49:32 -0700 (PDT) Subject: [Patches] Patch to fileobject.c In-Reply-To: <39382370.2279D296@oratrix.com> Message-ID: On Fri, 2 Jun 2000, Jack Jansen wrote: > Various includes were halfway the file. Moved to the top to fix problems with > multiple includes of files on the Mac. Similar to my previous note, configure.in should also check for "sys/stat.h" and "stat.h" in the AC_CHECK_HEADERS(). (in addition to the sys/types.h) I understand this is basically just a move of the includes, but those includes are just done wrong. DONT_HAVE_* is "not the autoconf way" Cheers, -g -- Greg Stein, http://www.lyra.org/ From jack@oratrix.nl Sat Jun 3 00:03:47 2000 From: jack@oratrix.nl (Jack Jansen) Date: Sat, 03 Jun 2000 01:03:47 +0200 Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: Message by Greg Stein , Fri, 2 Jun 2000 15:46:56 -0700 (PDT) , Message-ID: <20000602230352.117B9D8397@oratrix.oratrix.nl> Recently, Greg Stein said: > The standard way to do this is to use autoconf to create a > HAVE_SYS_TYPES_H define and use that: Hmm, I thought the same, but the DONT_HAVE_SYS_TYPES_H stuff is all over the place already, so I thought I'd just hook onto that. It may be design by Guido (the DONT_HAVE constructs seem to be used for things which are usually available on unix, such as errno.h and sys/types.h) and it could be historical reasons. How about admitting this patch and putting a note in the bugs database that the DONT_HAVE's should be replaced by HAVE's at some point? -- Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++ Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++ www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm From trentm@activestate.com Sat Jun 3 00:23:07 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 16:23:07 -0700 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <20000601024359.C23428@activestate.com> References: <20000510131446.A25926@activestate.com> <000b01bfbaff$43d320c0$2aa0143f@tim> <20000511215433.A31196@activestate.com> <20000601024359.C23428@activestate.com> Message-ID: <20000602162307.A32455@activestate.com> On Thu, Jun 01, 2000 at 02:43:59AM -0700, Trent Mick wrote: > This patch addresses two main issues: > > (2) The hash algorithms that use pointers (e.g. func_hash, code_hash) are > universally not correct on Win64 (they assume that sizeof(long) == > sizeof(void*)) > Yet again, an Oops on my part. Nothing bad, I just missed including my patch to the the method object hash function (meth_hash()) in methodobject.c. The full patch, with *all* the hash code changes is included this time. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Objects/methodobject.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/methodobject.c Fri Jun 2 15:53:43 2000 *************** *** 172,178 **** meth_hash(a) PyCFunctionObject *a; { ! long x; if (a->m_self == NULL) x = 0; else { --- 172,178 ---- meth_hash(a) PyCFunctionObject *a; { ! long x,y; if (a->m_self == NULL) x = 0; else { *************** *** 180,186 **** if (x == -1) return -1; } ! return x ^ (long) a->m_ml->ml_meth; } PyTypeObject PyCFunction_Type = { --- 180,192 ---- if (x == -1) return -1; } ! y = _Py_HashPointer(a->m_ml->ml_meth); ! if (y == -1) ! return -1; ! x ^= y; ! if (x == -1) ! x = -2; ! return x; } PyTypeObject PyCFunction_Type = { *** /home/trentm/main/contrib/python/dist/src/Include/object.h Thu Jun 1 00:13:37 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Include/object.h Wed May 31 23:54:13 2000 *************** *** 287,292 **** --- 287,296 ---- /* tstate dict key for PyObject_Compare helper */ extern PyObject *_PyCompareState_Key; + /* Helpers for hash functions */ + extern DL_IMPORT(long) _Py_HashDouble Py_PROTO((double)); + extern DL_IMPORT(long) _Py_HashPointer Py_PROTO((void*)); + /* Flag bits for printing: */ #define Py_PRINT_RAW 1 /* No string quotes etc. */ *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/object.c Wed May 31 23:54:19 2000 *************** *** 33,38 **** --- 33,40 ---- #include "Python.h" + #include "mymath.h" + /* just for trashcan: */ #include "compile.h" #include "frameobject.h" *************** *** 506,511 **** --- 508,569 ---- return result; } + + /* Set of hash utility functions to help maintaining the invariant that + iff a==b then hash(a)==hash(b) + + All the utility functions (_Py_Hash*()) return "-1" to signify an error. + */ + + long + _Py_HashDouble(v) + double v; + { + /* Use frexp to get at the bits in the double. + * Since the VAX D double format has 56 mantissa bits, which is the + * most of any double format in use, each of these parts may have as + * many as (but no more than) 56 significant bits. + * So, assuming sizeof(long) >= 4, each part can be broken into two longs; + * frexp and multiplication are used to do that. + * Also, since the Cray double format has 15 exponent bits, which is the + * most of any double format in use, shifting the exponent field left by + * 15 won't overflow a long (again assuming sizeof(long) >= 4). + */ + int expo; + long hipart; + + v = frexp(v, &expo); + v = v * 2147483648.0; /* 2**31 */ + hipart = (long)v; /* Take the top 32 bits */ + v = (v - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ + + return hipart + (long)v + (expo << 15); /* Combine everything */ + } + + long + _Py_HashPointer(p) + void *p; + { + #if SIZEOF_LONG >= SIZEOF_VOID_P + return (long)p; + #else + /* convert to a Python long and hash that */ + PyObject* longobj; + long x; + + if ((longobj = PyLong_FromVoidPtr(p)) == NULL) { + x = -1; + goto finally; + } + x = PyObject_Hash(longobj); + + finally: + Py_XDECREF(longobj); + return x; + #endif + } + + long PyObject_Hash(v) PyObject *v; *************** *** 513,520 **** PyTypeObject *tp = v->ob_type; if (tp->tp_hash != NULL) return (*tp->tp_hash)(v); ! if (tp->tp_compare == NULL) ! return (long) v; /* Use address as hash value */ /* If there's a cmp but no hash defined, the object can't be hashed */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; --- 571,579 ---- PyTypeObject *tp = v->ob_type; if (tp->tp_hash != NULL) return (*tp->tp_hash)(v); ! if (tp->tp_compare == NULL) { ! return _Py_HashPointer(v); /* Use address as hash value */ ! } /* If there's a cmp but no hash defined, the object can't be hashed */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/floatobject.c Wed May 31 23:54:19 2000 *************** *** 59,65 **** --- 59,71 ---- #endif #ifndef LONG_MAX + #if SIZEOF_LONG == 4 #define LONG_MAX 0X7FFFFFFFL + #elif SIZEOF_LONG == 8 + #define LONG_MAX 0X7FFFFFFFFFFFFFFFL + #else + #error "could not set LONG_MAX" + #endif #endif #ifndef LONG_MIN *************** *** 357,368 **** return (i < j) ? -1 : (i > j) ? 1 : 0; } static long float_hash(v) PyFloatObject *v; { double intpart, fractpart; - int expo; long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons --- 363,374 ---- return (i < j) ? -1 : (i > j) ? 1 : 0; } + static long float_hash(v) PyFloatObject *v; { double intpart, fractpart; long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons *************** *** 379,385 **** #endif if (fractpart == 0.0) { ! if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->ob_fval); if (w == NULL) --- 385,391 ---- #endif if (fractpart == 0.0) { ! if (intpart > LONG_MAX || -intpart > LONG_MAX) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->ob_fval); if (w == NULL) *************** *** 393,406 **** else { /* Note -- if you change this code, also change the copy in complexobject.c */ ! long hipart; ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x = hipart + (long)fractpart + (long)intpart + (expo << 15); ! /* Combine everything */ } if (x == -1) x = -2; --- 399,407 ---- else { /* Note -- if you change this code, also change the copy in complexobject.c */ ! x = _Py_HashDouble(v->ob_fval); ! if (x == -1) ! return -1; } if (x == -1) x = -2; *** /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/complexobject.c Wed May 31 23:54:19 2000 *************** *** 285,292 **** PyComplexObject *v; { double intpart, fractpart; ! int expo; ! long hipart, x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ --- 285,291 ---- PyComplexObject *v; { double intpart, fractpart; ! long x; /* This is designed so that Python numbers with the same value hash to the same value, otherwise comparisons of mapping keys will turn out weird */ *************** *** 302,308 **** #endif if (fractpart == 0.0 && v->cval.imag == 0.0) { ! if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->cval.real); if (w == NULL) --- 301,307 ---- #endif if (fractpart == 0.0 && v->cval.imag == 0.0) { ! if (intpart > LONG_MAX || -intpart > LONG_MAX) { /* Convert to long int and use its hash... */ PyObject *w = PyLong_FromDouble(v->cval.real); if (w == NULL) *************** *** 314,349 **** x = (long)intpart; } else { ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x = hipart + (long)fractpart + (long)intpart + (expo << 15); ! /* Combine everything */ if (v->cval.imag != 0.0) { /* Hash the imaginary part */ /* XXX Note that this hashes complex(x, y) to the same value as complex(y, x). Still better than it used to be :-) */ ! #ifdef MPW ! { ! extended e; ! fractpart = modf(v->cval.imag, &e); ! intpart = e; ! } ! #else ! fractpart = modf(v->cval.imag, &intpart); ! #endif ! fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (long)fractpart; /* Take the top 32 bits */ ! fractpart = ! (fractpart - (double)hipart) * 2147483648.0; ! /* Get the next 32 bits */ ! x ^= hipart + (long)fractpart + ! (long)intpart + (expo << 15); ! /* Combine everything */ } } if (x == -1) --- 313,330 ---- x = (long)intpart; } else { ! x = _Py_HashDouble(v->cval.real); ! if (x == -1) ! return -1; if (v->cval.imag != 0.0) { /* Hash the imaginary part */ /* XXX Note that this hashes complex(x, y) to the same value as complex(y, x). Still better than it used to be :-) */ ! long y = _Py_HashDouble(v->cval.imag); ! if (y == -1) ! return -1; ! x += y; } } if (x == -1) *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/classobject.c Wed May 31 23:54:19 2000 *************** *** 823,832 **** func = instance_getattr(inst, cmpstr); if (func == NULL) { PyErr_Clear(); ! outcome = (long)inst; ! if (outcome == -1) ! outcome = -2; ! return outcome; } PyErr_SetString(PyExc_TypeError, "unhashable instance"); return -1; --- 823,829 ---- func = instance_getattr(inst, cmpstr); if (func == NULL) { PyErr_Clear(); ! return _Py_HashPointer(inst); } PyErr_SetString(PyExc_TypeError, "unhashable instance"); return -1; *** /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/funcobject.c Wed May 31 23:54:19 2000 *************** *** 231,240 **** func_hash(f) PyFunctionObject *f; { ! long h; h = PyObject_Hash(f->func_code); if (h == -1) return h; ! h = h ^ (long)f->func_globals; if (h == -1) h = -2; return h; } --- 231,242 ---- func_hash(f) PyFunctionObject *f; { ! long h,x; h = PyObject_Hash(f->func_code); if (h == -1) return h; ! x = _Py_HashPointer(f->func_globals); ! if (x == -1) return x; ! h ^= x; if (h == -1) h = -2; return h; } *** /home/trentm/main/contrib/python/dist/src/PC/winreg.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/winreg.c Wed May 31 23:54:20 2000 *************** *** 421,427 **** /* Just use the address. XXX - should we use the handle value? */ ! return (long)ob; } --- 421,427 ---- /* Just use the address. XXX - should we use the handle value? */ ! return _Py_HashPointer(ob); } *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_hash.py Thu Jun 1 00:40:23 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_hash.py Wed May 31 23:54:16 2000 *************** *** 0 **** --- 1,26 ---- + # test the invariant that + # iff a==b then hash(a)==hash(b) + # + + import test_support + + + def same_hash(*objlist): + # hash each object given an raise TestFailed if + # the hash values are not all the same + hashed = map(hash, objlist) + for h in hashed[1:]: + if h != hashed[0]: + raise TestFailed, "hashed values differ: %s" % `objlist` + + + + same_hash(1, 1L, 1.0, 1.0+0.0j) + same_hash(int(1), long(1), float(1), complex(1)) + + same_hash(long(1.23e300), float(1.23e300)) + + same_hash(float(0.5), complex(0.5, 0.0)) + + + *** /home/trentm/main/contrib/python/dist/src/Lib/test/output/test_hash Thu Jun 1 00:40:23 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/output/test_hash Wed May 31 23:54:16 2000 *************** *** 0 **** --- 1 ---- + test_hash -- Trent Mick trentm@activestate.com From trentm@activestate.com Sat Jun 3 01:02:38 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 17:02:38 -0700 Subject: [Patches] Patch to import.c In-Reply-To: <3938386F.30BD2F46@oratrix.com> References: <3938386F.30BD2F46@oratrix.com> Message-ID: <20000602170238.A372@activestate.com> On Sat, Jun 03, 2000 at 12:42:56AM +0200, Jack Jansen wrote: > *** import.c 2000/05/03 23:44:39 2.134 > --- import.c 2000/06/02 13:34:56 > *************** > *** 60,65 **** > --- 60,69 ---- > #endif > #ifndef DONT_HAVE_SYS_STAT_H > #include > + #else > + #ifdef HAVE_STAT_H > + #include > + #endif > #endif > > #if defined(PYCC_VACPP) you could use: #ifndef something #elif defined(something_else) #endif It would read better. Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Sat Jun 3 01:22:39 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 17:22:39 -0700 Subject: [Patches] fix bltinmodule.c for 64-bit platforms Message-ID: <20000602172239.A562@activestate.com> Discussion: Various small fixes to the builtin module to ensure no buffer overflows. - chunk #1: Proper casting to ensure no truncation, and hence no surprises, in the comparison. - chunk #2: The id() function guarantees a unique return value for different objects. It does this by returning the pointer to the object. By returning a PyInt, on Win64 (sizeof(long) < sizeof(void*)) the pointer is truncated and the guarantee may be proven false. The appropriate return function is PyLong_FromVoidPtr, this returns a PyLong if that is necessary to return the pointer without truncation. - chunk #3: Ensure no overflow in raw_input(). Granted the user would have to pass in >2GB of data but it *is* a possible buffer overflow condition. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'patch -p8'): diff -c /home/trentm/main/contrib/python/dist/src/Python/bltinmodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Python/bltinmodule.c *** /home/trentm/main/contrib/python/dist/src/Python/bltinmodule.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/bltinmodule.c Fri Jun 2 15:53:44 2000 *************** *** 832,838 **** return NULL; } str = PyString_AsString(cmd); ! if ((int)strlen(str) != PyString_Size(cmd)) { PyErr_SetString(PyExc_ValueError, "embedded '\\0' in string arg"); return NULL; --- 832,838 ---- return NULL; } str = PyString_AsString(cmd); ! if (strlen(str) != (size_t)PyString_Size(cmd)) { PyErr_SetString(PyExc_ValueError, "embedded '\\0' in string arg"); return NULL; *************** *** 985,991 **** if (!PyArg_ParseTuple(args, "O:id", &v)) return NULL; ! return PyInt_FromLong((long)v); } static char id_doc[] = --- 985,991 ---- if (!PyArg_ParseTuple(args, "O:id", &v)) return NULL; ! return PyLong_FromVoidPtr(v); } static char id_doc[] = *************** *** 1873,1879 **** result = NULL; } else { /* strip trailing '\n' */ ! result = PyString_FromStringAndSize(s, strlen(s)-1); } PyMem_FREE(s); return result; --- 1873,1886 ---- result = NULL; } else { /* strip trailing '\n' */ ! size_t len = strlen(s); ! if (len > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, "input too long"); ! result = NULL; ! } ! else { ! result = PyString_FromStringAndSize(s, (int)(len-1)); ! } } PyMem_FREE(s); return result; -- Trent Mick trentm@activestate.com From trentm@activestate.com Sat Jun 3 01:37:54 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 2 Jun 2000 17:37:54 -0700 Subject: [Patches] fix possible overflow in select() Message-ID: <20000602173753.C562@activestate.com> Dicussion: This patches fixes a possible overflow of the optional timeout parameter for the select() function (selectmodule.c). This timeout is passed in as a double and then truncated to an int. If the double is sufficiently large you can get unexpected results as it overflows. This patch raises an overflow if the given select timeout overflows. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch (use 'pathc -p8'): diff -c /home/trentm/main/contrib/python/dist/src/Modules/selectmodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/selectmodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/selectmodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/selectmodule.c Fri Jun 2 15:53:43 2000 *************** *** 238,244 **** fd_set ifdset, ofdset, efdset; double timeout; struct timeval tv, *tvp; ! int seconds; int imax, omax, emax, max; int n; --- 238,244 ---- fd_set ifdset, ofdset, efdset; double timeout; struct timeval tv, *tvp; ! long seconds; int imax, omax, emax, max; int n; *************** *** 255,264 **** return NULL; } else { ! seconds = (int)timeout; timeout = timeout - (double)seconds; tv.tv_sec = seconds; ! tv.tv_usec = (int)(timeout*1000000.0); tvp = &tv; } --- 255,268 ---- return NULL; } else { ! if (timeout > (double)LONG_MAX) { ! PyErr_SetString(PyExc_OverflowError, "timeout period too long"); ! return NULL; ! } ! seconds = (long)timeout; timeout = timeout - (double)seconds; tv.tv_sec = seconds; ! tv.tv_usec = (long)(timeout*1000000.0); tvp = &tv; } -- Trent Mick trentm@activestate.com From Moshe Zadka Sat Jun 3 08:59:47 2000 From: Moshe Zadka (Moshe Zadka) Date: Sat, 3 Jun 2000 10:59:47 +0300 (IDT) Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: <39382040.3BF69C34@oratrix.com> Message-ID: On Fri, 2 Jun 2000, Jack Jansen wrote: > Don't include sys/types.h or sys/stat.h if the platform doesn't have it (eg. > Carbon, the MacOS9/MacOSX > combined development layer). Your patch only deals with sys/types.h, not sys/stat.h. Otherwise, it looks quite reasonable. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From Moshe Zadka Sat Jun 3 09:02:24 2000 From: Moshe Zadka (Moshe Zadka) Date: Sat, 3 Jun 2000 11:02:24 +0300 (IDT) Subject: [Patches] Patch to fileobject.c In-Reply-To: <39382370.2279D296@oratrix.com> Message-ID: On Fri, 2 Jun 2000, Jack Jansen wrote: > Various includes were halfway the file. Moved to the top to fix problems with > multiple includes of files on the Mac. +1. Why would anybody put includes anywhere but the top? -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From jack@oratrix.nl Sat Jun 3 11:16:38 2000 From: jack@oratrix.nl (Jack Jansen) Date: Sat, 03 Jun 2000 12:16:38 +0200 Subject: [Patches] Patch to import.c In-Reply-To: Message by Trent Mick , Fri, 2 Jun 2000 17:02:38 -0700 , <20000602170238.A372@activestate.com> Message-ID: <20000603101643.0486FD7210@oratrix.oratrix.nl> Recently, Trent Mick said: > you could use: > > #ifndef something > #elif defined(something_else) > #endif Is #elif nowadays supported by all compilers? I still tend to stick with nested #ifdefs, just as I still put my prototypes within conditional code, so as not to break stuff for people with old-fashioned compilers. -- Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++ Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++ www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm From gstein@lyra.org Sat Jun 3 11:26:25 2000 From: gstein@lyra.org (Greg Stein) Date: Sat, 3 Jun 2000 03:26:25 -0700 (PDT) Subject: [Patches] Patch to import.c In-Reply-To: <20000603101643.0486FD7210@oratrix.oratrix.nl> Message-ID: On Sat, 3 Jun 2000, Jack Jansen wrote: > Recently, Trent Mick said: > > you could use: > > > > #ifndef something > > #elif defined(something_else) > > #endif > > Is #elif nowadays supported by all compilers? I still tend to stick > with nested #ifdefs, just as I still put my prototypes within > conditional code, so as not to break stuff for people with > old-fashioned compilers. Python 1.6 is targeted at ANSI compilers. Heck, if you're feeling particularly brain-dead one day, and just want something to do, then go remove all the Py_PROTO macros :-) Cheers, -g -- Greg Stein, http://www.lyra.org/ From jack@oratrix.nl Sat Jun 3 12:05:57 2000 From: jack@oratrix.nl (Jack Jansen) Date: Sat, 03 Jun 2000 13:05:57 +0200 Subject: [Patches] Patch to import.c In-Reply-To: Message by Greg Stein , Sat, 3 Jun 2000 03:26:25 -0700 (PDT) , Message-ID: <20000603110602.63987D7210@oratrix.oratrix.nl> I'm a bit confused as to the current procedure for patches. It used to be that Guido said "yes" or "no", and that was it. Nowadays there seem to be very many people on the patches mailing list, and a patch gets a number of replies ranging from "don't do this" to "can't you do this differently". I've tried to reply to all the issues, but I'm now completely in the dark as to the status of my patches: I'm under the impression that I've defended the case for my patches satisfactorily (hehe:-), but people on the patch mailing list may think that I've some fixing up to do. As I didn't follow discussions on the new patch system: is there a procedure and, if so, could it be documented on python.org/patches? And if there isn't one: could one be designed and documented, please? A time-limit on patch acceptance/rejection would also be nice, if possible: I use the repository to sync my home machine and work machine, which worked fine when Guido alone was responsible as he worked what seems to be 19 hours per day, so patches usually ended up in the repository before I had the chance to cycle from home to work or vv., but with the new procedure it can apparently take a lot longer for patches to appear, so I may have to come up with another scheme to sync my multiple machines... -- Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++ Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++ www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm From gstein@lyra.org Sat Jun 3 11:17:56 2000 From: gstein@lyra.org (Greg Stein) Date: Sat, 3 Jun 2000 03:17:56 -0700 (PDT) Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: <20000602230352.117B9D8397@oratrix.oratrix.nl> Message-ID: On Sat, 3 Jun 2000, Jack Jansen wrote: > Recently, Greg Stein said: > > The standard way to do this is to use autoconf to create a > > HAVE_SYS_TYPES_H define and use that: > > Hmm, I thought the same, but the DONT_HAVE_SYS_TYPES_H stuff is all > over the place already, so I thought I'd just hook onto that. > > It may be design by Guido (the DONT_HAVE constructs seem to be used > for things which are usually available on unix, such as errno.h and > sys/types.h) and it could be historical reasons. How about admitting > this patch and putting a note in the bugs database that the > DONT_HAVE's should be replaced by HAVE's at some point? Seems like a reasonable approach! Cheers, -g -- Greg Stein, http://www.lyra.org/ From akuchlin@mems-exchange.org Sat Jun 3 13:05:10 2000 From: akuchlin@mems-exchange.org (Andrew Kuchling) Date: Sat, 3 Jun 2000 08:05:10 -0400 Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: <20000602230352.117B9D8397@oratrix.oratrix.nl>; from jack@oratrix.nl on Sat, Jun 03, 2000 at 01:03:47AM +0200 References: <20000602230352.117B9D8397@oratrix.oratrix.nl> Message-ID: <20000603080510.B2252@newcnri.cnri.reston.va.us> On Sat, Jun 03, 2000 at 01:03:47AM +0200, Jack Jansen wrote: >Hmm, I thought the same, but the DONT_HAVE_SYS_TYPES_H stuff is all >over the place already, so I thought I'd just hook onto that. I don't even see where DONT_HAVE_SYS_TYPES_H is ever defined: [amk@207-172-111-242 Python-1.6]$ grep -r DONT_HAVE_SYS * Modules/arraymodule.c:#ifndef DONT_HAVE_SYS_TYPES_H Modules/arraymodule.c:#endif /* DONT_HAVE_SYS_TYPES_H */ Modules/selectmodule.c:#ifndef DONT_HAVE_SYS_TYPES_H Objects/fileobject.c:#ifndef DONT_HAVE_SYS_TYPES_H Objects/fileobject.c:#endif /* DONT_HAVE_SYS_TYPES_H */ Objects/fileobject.c:#ifndef DONT_HAVE_SYS_TYPES_H Objects/fileobject.c:#ifndef DONT_HAVE_SYS_STAT_H Python/import.c:#ifndef DONT_HAVE_SYS_TYPES_H Python/import.c:#ifndef DONT_HAVE_SYS_STAT_H [amk@207-172-111-242 Python-1.6]$ Is it defined in some Mac-specific project file? --amk From mhammond@skippinet.com.au Sat Jun 3 15:49:02 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Sun, 4 Jun 2000 00:49:02 +1000 Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: <20000603080510.B2252@newcnri.cnri.reston.va.us> Message-ID: > I don't even see where DONT_HAVE_SYS_TYPES_H is ever defined: ... > Is it defined in some Mac-specific project file? A few existed before, but I know I submitted a couple of the listed ones for Windows CE. However, the CE config.h has never made it into the core, hence you can't find that particular definition... Mark. From thomas@xs4all.net Sun Jun 4 01:09:46 2000 From: thomas@xs4all.net (Thomas Wouters) Date: Sun, 4 Jun 2000 02:09:46 +0200 Subject: [Patches] openpty() and forkpty() Message-ID: <20000604020945.D294@xs4all.nl> --cNdxnHkX5QqsyA0e Content-Type: text/plain; charset=us-ascii Attached is a patch to add openpty() and forkpty() functions to the posix module, if the target platform supports them. openpty() is available on at least glibc-2.1 based (Linux) systems, and BSDI and FreeBSD. I suspect other BSD-alike operating systems have it too, but I'm not in a position to find out. On the systems that have it, openpty() is the 'proper' way to obtain a new pseudo-terminal master/slave pair, especially on Linux 2.1+ systems that use the Unix98 pty's (RedHat in any case, and probably most other distributions too.) I am not sure how standard Unix98 pty's are, but autoconf should at least be able to figure out which systems have openpty. forkpty() is a combination of openpty() and fork(), and basically does exactly what pty.fork() already does. My only reason for including it is symmetry. I also included 'configure' in the patch, which constitutes by far most of it. The actual changes are minimal, but I thought I'd include the configure patch for those who do not have autoconf. (BSDI, for instance ;P) I haven't patched Lib/pty.py yet, mostly because I dont want to go through the effort of rewriting it and figuring out wether 'master_open' and 'slave_open' are meant to be part of the interface or not, until I get some positive feedback on this patch (or at least not too much negative feedback. ;) For the record, in BSDI 4.x at least, openpty() is implemented as a function that does exactly what pty.py currently does. But as it's a shared library, using openpty() should be preferred. (We currently run a few BSDI systems that need more than 256 terminals, and we had to change the name scheme to accomodate. The old names are available, but still overused.) On Linux 2.1+ with Unix98 pty's configured, openpty() does something entirely different. Also, I've included the info pages on these two functions, from glibc 2.1, after the standard disclaimer. (There is no manpage on these functions, at least not on BSDI and Linux.) I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Opening a Pseudo-Terminal Pair ------------------------------ These functions, derived from BSD, are available in the separate `libutil' library, and declared in `pty.h'. - Function: int openpty (int *AMASTER, int *ASLAVE, char *NAME, struct termios *TERMP, struct winsize *WINP) This function allocates and opens a pseudo-terminal pair, returning the file descriptor for the master in *AMASTER, and the file descriptor for the slave in *ASLAVE. If the argument NAME is not a null pointer, the file name of the slave pseudo-terminal device is stored in `*name'. If TERMP is not a null pointer, the terminal attributes of the slave are set to the ones specified in the structure that TERMP points to (*note Terminal Modes::.). Likewise, if the WINP is not a null pointer, the screen size of the slave is set to the values specified in the structure that WINP points to. The normal return value from `openpty' is 0; a value of -1 is returned in case of failure. The following `errno' conditions are defined for this function: `ENOENT' There are no free pseudo-terminal pairs available. *Warning:* Using the `openpty' function with NAME not set to `NULL' is *very dangerous* because it provides no protection against overflowing the string NAME. You should use the `ttyname' function on the file descriptor returned in *SLAVE to find out the file name of the slave pseudo-terminal device instead. - Function: int forkpty (int *AMASTER, char *NAME, struct termios *TERMP, struct winsize *WINP) This function is similar to the `openpty' function, but in addition, forks a new process (*note Creating a Process::.) and makes the newly opened slave pseudo-terminal device the controlling terminal (*note Controlling Terminal::.) for the child process. If the operation is successful, there are then both parent and child processes and both see `forkpty' return, but with different values: it returns a value of 0 in the child process and returns the child's process ID in the parent process. If the allocation of a pseudo-terminal pair or the process creation failed, `forkpty' returns a value of -1 in the parent process. *Warning:* The `forkpty' function has the same problems with respect to the NAME argument as `openpty'. -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! --cNdxnHkX5QqsyA0e Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="openpty.diff" Index: config.h.in =================================================================== RCS file: /cvsroot/python/python/dist/src/config.h.in,v retrieving revision 2.55 diff -c -r2.55 config.h.in *** config.h.in 2000/05/11 18:41:31 2.55 --- config.h.in 2000/06/03 23:37:03 *************** *** 471,476 **** --- 471,482 ---- /* Define if you have the waitpid function. */ #undef HAVE_WAITPID + /* Define if you have the openpty function. */ + #undef HAVE_OPENPTY + + /* Define if you have the forkpty function. */ + #undef HAVE_FORKPTY + /* Define if you have the header file. */ #undef HAVE_DIRENT_H Index: configure =================================================================== RCS file: /cvsroot/python/python/dist/src/configure,v retrieving revision 1.116 diff -c -r1.116 configure *** configure 2000/05/26 12:22:54 1.116 --- configure 2000/06/03 23:37:06 *************** *** 1,6 **** #! /bin/sh ! # From configure.in Revision: 1.123 # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 --- 1,6 ---- #! /bin/sh ! # From configure.in Revision: 1.124 # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.13 *************** *** 3594,3609 **** done # check for long file support functions for ac_func in fseek64 fseeko fstatvfs ftell64 ftello statvfs do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3602: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 + echo "configure:3603: checking for $ac_func" >&5 + if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + cat > conftest.$ac_ext < + /* Override any gcc2 internal prototype to avoid an error. */ + /* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ + char $ac_func(); + + int main() { + + /* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ + #if defined (__stub_$ac_func) || defined (__stub___$ac_func) + choke me + #else + $ac_func(); + #endif + + ; return 0; } + EOF + if { (eval echo configure:3631: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" + fi + rm -f conftest* + fi + + if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 + echo $ac_n "checking for openpty in -lutil""... $ac_c" 1>&6 + echo "configure:3653: checking for openpty in -lutil" >&5 + ac_lib_var=`echo util'_'openpty | sed 'y%./+-%__p_%'` + if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + ac_save_LIBS="$LIBS" + LIBS="-lutil $LIBS" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" + fi + rm -f conftest* + LIBS="$ac_save_LIBS" + + fi + if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF + #define HAVE_OPENPTY 1 + EOF + LIBS="$LIBS -lutil" + else + echo "$ac_t""no" 1>&6 + fi + + fi + done + + for ac_func in forkpty + do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 + echo "configure:3701: checking for $ac_func" >&5 + if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + cat > conftest.$ac_ext < + /* Override any gcc2 internal prototype to avoid an error. */ + /* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ + char $ac_func(); + + int main() { + + /* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ + #if defined (__stub_$ac_func) || defined (__stub___$ac_func) + choke me + #else + $ac_func(); + #endif + + ; return 0; } + EOF + if { (eval echo configure:3729: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" + fi + rm -f conftest* + fi + + if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 + echo $ac_n "checking for forkpty in -lutil""... $ac_c" 1>&6 + echo "configure:3751: checking for forkpty in -lutil" >&5 + ac_lib_var=`echo util'_'forkpty | sed 'y%./+-%__p_%'` + if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + ac_save_LIBS="$LIBS" + LIBS="-lutil $LIBS" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" + fi + rm -f conftest* + LIBS="$ac_save_LIBS" + + fi + if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF + #define HAVE_FORKPTY 1 + EOF + LIBS="$LIBS -lutil" + else + echo "$ac_t""no" 1>&6 + fi + + fi + done + + # check for long file support functions for ac_func in fseek64 fseeko fstatvfs ftell64 ftello statvfs do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3801: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3825,3831 ---- ; return 0; } EOF ! if { (eval echo configure:3829: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3654,3665 **** for ac_func in dup2 getcwd strdup strerror memmove do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3658: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3857: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3881,3887 ---- ; return 0; } EOF ! if { (eval echo configure:3885: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3709,3720 **** echo $ac_n "checking for getpgrp""... $ac_c" 1>&6 ! echo "configure:3713: checking for getpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3912: checking for getpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpgrp=yes" else --- 3936,3942 ---- ; return 0; } EOF ! if { (eval echo configure:3940: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_getpgrp=yes" else *************** *** 3752,3765 **** if eval "test \"`echo '$ac_cv_func_'getpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { getpgrp(0); ; return 0; } EOF ! if { (eval echo configure:3763: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define GETPGRP_HAVE_ARG 1 --- 3951,3964 ---- if eval "test \"`echo '$ac_cv_func_'getpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { getpgrp(0); ; return 0; } EOF ! if { (eval echo configure:3962: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define GETPGRP_HAVE_ARG 1 *************** *** 3775,3786 **** fi echo $ac_n "checking for setpgrp""... $ac_c" 1>&6 ! echo "configure:3779: checking for setpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3978: checking for setpgrp" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setpgrp=yes" else --- 4002,4008 ---- ; return 0; } EOF ! if { (eval echo configure:4006: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_setpgrp=yes" else *************** *** 3818,3831 **** if eval "test \"`echo '$ac_cv_func_'setpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { setpgrp(0,0); ; return 0; } EOF ! if { (eval echo configure:3829: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SETPGRP_HAVE_ARG 1 --- 4017,4030 ---- if eval "test \"`echo '$ac_cv_func_'setpgrp`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { setpgrp(0,0); ; return 0; } EOF ! if { (eval echo configure:4028: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SETPGRP_HAVE_ARG 1 *************** *** 3841,3852 **** fi echo $ac_n "checking for gettimeofday""... $ac_c" 1>&6 ! echo "configure:3845: checking for gettimeofday" >&5 if eval "test \"`echo '$''{'ac_cv_func_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4044: checking for gettimeofday" >&5 if eval "test \"`echo '$''{'ac_cv_func_gettimeofday'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettimeofday=yes" else --- 4068,4074 ---- ; return 0; } EOF ! if { (eval echo configure:4072: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gettimeofday=yes" else *************** *** 3884,3897 **** if eval "test \"`echo '$ac_cv_func_'gettimeofday`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { gettimeofday((struct timeval*)0,(struct timezone*)0); ; return 0; } EOF ! if { (eval echo configure:3895: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 4083,4096 ---- if eval "test \"`echo '$ac_cv_func_'gettimeofday`\" = yes"; then echo "$ac_t""yes" 1>&6 cat > conftest.$ac_ext < int main() { gettimeofday((struct timeval*)0,(struct timezone*)0); ; return 0; } EOF ! if { (eval echo configure:4094: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 3910,3921 **** # checks for structures echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:3914: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 4109,4120 ---- # checks for structures echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:4113: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 3924,3930 **** struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:3928: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else --- 4123,4129 ---- struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:4127: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else *************** *** 3945,3956 **** fi echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 ! echo "configure:3949: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 4144,4155 ---- fi echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 ! echo "configure:4148: checking whether struct tm is in sys/time.h or time.h" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 3958,3964 **** struct tm *tp; tp->tm_sec; ; return 0; } EOF ! if { (eval echo configure:3962: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else --- 4157,4163 ---- struct tm *tp; tp->tm_sec; ; return 0; } EOF ! if { (eval echo configure:4161: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm=time.h else *************** *** 3979,3990 **** fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 ! echo "configure:3983: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> --- 4178,4189 ---- fi echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 ! echo "configure:4182: checking for tm_zone in struct tm" >&5 if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_cv_struct_tm> *************** *** 3992,3998 **** struct tm tm; tm.tm_zone; ; return 0; } EOF ! if { (eval echo configure:3996: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else --- 4191,4197 ---- struct tm tm; tm.tm_zone; ; return 0; } EOF ! if { (eval echo configure:4195: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_struct_tm_zone=yes else *************** *** 4012,4023 **** else echo $ac_n "checking for tzname""... $ac_c" 1>&6 ! echo "configure:4016: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ --- 4211,4222 ---- else echo $ac_n "checking for tzname""... $ac_c" 1>&6 ! echo "configure:4215: checking for tzname" >&5 if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #ifndef tzname /* For SGI. */ *************** *** 4027,4033 **** atoi(*tzname); ; return 0; } EOF ! if { (eval echo configure:4031: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else --- 4226,4232 ---- atoi(*tzname); ; return 0; } EOF ! if { (eval echo configure:4230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* ac_cv_var_tzname=yes else *************** *** 4050,4068 **** echo $ac_n "checking for time.h that defines altzone""... $ac_c" 1>&6 ! echo "configure:4054: checking for time.h that defines altzone" >&5 if eval "test \"`echo '$''{'ac_cv_header_time_altzone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return altzone; ; return 0; } EOF ! if { (eval echo configure:4066: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time_altzone=yes else --- 4249,4267 ---- echo $ac_n "checking for time.h that defines altzone""... $ac_c" 1>&6 ! echo "configure:4253: checking for time.h that defines altzone" >&5 if eval "test \"`echo '$''{'ac_cv_header_time_altzone'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { return altzone; ; return 0; } EOF ! if { (eval echo configure:4265: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time_altzone=yes else *************** *** 4084,4092 **** was_it_defined=no echo $ac_n "checking whether sys/select.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:4088: checking whether sys/select.h and sys/time.h may both be included" >&5 cat > conftest.$ac_ext < --- 4283,4291 ---- was_it_defined=no echo $ac_n "checking whether sys/select.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:4287: checking whether sys/select.h and sys/time.h may both be included" >&5 cat > conftest.$ac_ext < *************** *** 4097,4103 **** ; ; return 0; } EOF ! if { (eval echo configure:4101: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SYS_SELECT_WITH_SYS_TIME 1 --- 4296,4302 ---- ; ; return 0; } EOF ! if { (eval echo configure:4300: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define SYS_SELECT_WITH_SYS_TIME 1 *************** *** 4113,4126 **** # checks for compiler characteristics echo $ac_n "checking whether char is unsigned""... $ac_c" 1>&6 ! echo "configure:4117: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&6 ! echo "configure:4316: checking whether char is unsigned" >&5 if eval "test \"`echo '$''{'ac_cv_c_char_unsigned'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test "$GCC" = yes; then # GCC predefines this symbol on systems where it applies. cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else --- 4351,4357 ---- volatile char c = 255; exit(c < 0); } EOF ! if { (eval echo configure:4355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_char_unsigned=yes else *************** *** 4176,4187 **** fi echo $ac_n "checking for working const""... $ac_c" 1>&6 ! echo "configure:4180: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4379: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else --- 4429,4435 ---- ; return 0; } EOF ! if { (eval echo configure:4433: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else *************** *** 4251,4271 **** fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:4255: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else --- 4450,4470 ---- fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:4454: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else *************** *** 4293,4308 **** works=no echo $ac_n "checking for working volatile""... $ac_c" 1>&6 ! echo "configure:4297: checking for working volatile" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else --- 4492,4507 ---- works=no echo $ac_n "checking for working volatile""... $ac_c" 1>&6 ! echo "configure:4496: checking for working volatile" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else *************** *** 4319,4334 **** works=no echo $ac_n "checking for working signed char""... $ac_c" 1>&6 ! echo "configure:4323: checking for working signed char" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else --- 4518,4533 ---- works=no echo $ac_n "checking for working signed char""... $ac_c" 1>&6 ! echo "configure:4522: checking for working signed char" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* works=yes else *************** *** 4345,4360 **** have_prototypes=no echo $ac_n "checking for prototypes""... $ac_c" 1>&6 ! echo "configure:4349: checking for prototypes" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_PROTOTYPES 1 --- 4544,4559 ---- have_prototypes=no echo $ac_n "checking for prototypes""... $ac_c" 1>&6 ! echo "configure:4548: checking for prototypes" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_PROTOTYPES 1 *************** *** 4369,4377 **** works=no echo $ac_n "checking for variable length prototypes and stdarg.h""... $ac_c" 1>&6 ! echo "configure:4373: checking for variable length prototypes and stdarg.h" >&5 cat > conftest.$ac_ext < --- 4568,4576 ---- works=no echo $ac_n "checking for variable length prototypes and stdarg.h""... $ac_c" 1>&6 ! echo "configure:4572: checking for variable length prototypes and stdarg.h" >&5 cat > conftest.$ac_ext < *************** *** 4388,4394 **** return foo(10, "", 3.14); ; return 0; } EOF ! if { (eval echo configure:4392: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_STDARG_PROTOTYPES 1 --- 4587,4593 ---- return foo(10, "", 3.14); ; return 0; } EOF ! if { (eval echo configure:4591: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_STDARG_PROTOTYPES 1 *************** *** 4404,4419 **** if test "$have_prototypes" = yes; then bad_prototypes=no echo $ac_n "checking for bad exec* prototypes""... $ac_c" 1>&6 ! echo "configure:4408: checking for bad exec* prototypes" >&5 cat > conftest.$ac_ext < int main() { char **t;execve("@",t,t); ; return 0; } EOF ! if { (eval echo configure:4417: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 4603,4618 ---- if test "$have_prototypes" = yes; then bad_prototypes=no echo $ac_n "checking for bad exec* prototypes""... $ac_c" 1>&6 ! echo "configure:4607: checking for bad exec* prototypes" >&5 cat > conftest.$ac_ext < int main() { char **t;execve("@",t,t); ; return 0; } EOF ! if { (eval echo configure:4616: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 4430,4441 **** bad_forward=no echo $ac_n "checking for bad static forward""... $ac_c" 1>&6 ! echo "configure:4434: checking for bad static forward" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&6 ! echo "configure:4633: checking for bad static forward" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else --- 4650,4656 ---- } EOF ! if { (eval echo configure:4654: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else *************** *** 4470,4478 **** va_list_is_array=no echo $ac_n "checking whether va_list is an array""... $ac_c" 1>&6 ! echo "configure:4474: checking whether va_list is an array" >&5 cat > conftest.$ac_ext <&6 ! echo "configure:4673: checking whether va_list is an array" >&5 cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 --- 4684,4690 ---- va_list list1, list2; list1 = list2; ; return 0; } EOF ! if { (eval echo configure:4688: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then : else echo "configure: failed program was:" >&5 *************** *** 4501,4512 **** # sigh -- gethostbyname_r is a mess; it can have 3, 5 or 6 arguments :-( echo $ac_n "checking for gethostbyname_r""... $ac_c" 1>&6 ! echo "configure:4505: checking for gethostbyname_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4704: checking for gethostbyname_r" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname_r'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname_r=yes" else --- 4728,4734 ---- ; return 0; } EOF ! if { (eval echo configure:4732: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname_r=yes" else *************** *** 4549,4559 **** EOF echo $ac_n "checking gethostbyname_r with 6 args""... $ac_c" 1>&6 ! echo "configure:4553: checking gethostbyname_r with 6 args" >&5 OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat > conftest.$ac_ext < --- 4748,4758 ---- EOF echo $ac_n "checking gethostbyname_r with 6 args""... $ac_c" 1>&6 ! echo "configure:4752: checking gethostbyname_r with 6 args" >&5 OLD_CFLAGS=$CFLAGS CFLAGS="$CFLAGS $MY_CPPFLAGS $MY_THREAD_CPPFLAGS $MY_CFLAGS" cat > conftest.$ac_ext < *************** *** 4570,4576 **** ; return 0; } EOF ! if { (eval echo configure:4574: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4769,4775 ---- ; return 0; } EOF ! if { (eval echo configure:4773: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4590,4598 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 5 args""... $ac_c" 1>&6 ! echo "configure:4594: checking gethostbyname_r with 5 args" >&5 cat > conftest.$ac_ext < --- 4789,4797 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 5 args""... $ac_c" 1>&6 ! echo "configure:4793: checking gethostbyname_r with 5 args" >&5 cat > conftest.$ac_ext < *************** *** 4609,4615 **** ; return 0; } EOF ! if { (eval echo configure:4613: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4808,4814 ---- ; return 0; } EOF ! if { (eval echo configure:4812: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4629,4637 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 3 args""... $ac_c" 1>&6 ! echo "configure:4633: checking gethostbyname_r with 3 args" >&5 cat > conftest.$ac_ext < --- 4828,4836 ---- echo "$ac_t""no" 1>&6 echo $ac_n "checking gethostbyname_r with 3 args""... $ac_c" 1>&6 ! echo "configure:4832: checking gethostbyname_r with 3 args" >&5 cat > conftest.$ac_ext < *************** *** 4646,4652 **** ; return 0; } EOF ! if { (eval echo configure:4650: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF --- 4845,4851 ---- ; return 0; } EOF ! if { (eval echo configure:4849: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF *************** *** 4680,4691 **** echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 ! echo "configure:4684: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 echo $ac_n "checking for gethostbyname""... $ac_c" 1>&6 ! echo "configure:4883: checking for gethostbyname" >&5 if eval "test \"`echo '$''{'ac_cv_func_gethostbyname'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else --- 4907,4913 ---- ; return 0; } EOF ! if { (eval echo configure:4911: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_gethostbyname=yes" else *************** *** 4744,4750 **** # Linux requires this for correct f.p. operations echo $ac_n "checking for __fpu_control in -lieee""... $ac_c" 1>&6 ! echo "configure:4748: checking for __fpu_control in -lieee" >&5 ac_lib_var=`echo ieee'_'__fpu_control | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 4943,4949 ---- # Linux requires this for correct f.p. operations echo $ac_n "checking for __fpu_control in -lieee""... $ac_c" 1>&6 ! echo "configure:4947: checking for __fpu_control in -lieee" >&5 ac_lib_var=`echo ieee'_'__fpu_control | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 4752,4758 **** ac_save_LIBS="$LIBS" LIBS="-lieee $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 4962,4968 ---- __fpu_control() ; return 0; } EOF ! if { (eval echo configure:4966: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 4793,4799 **** # Check for --with-fpectl echo $ac_n "checking for --with-fpectl""... $ac_c" 1>&6 ! echo "configure:4797: checking for --with-fpectl" >&5 # Check whether --with-fpectl or --without-fpectl was given. if test "${with_fpectl+set}" = set; then withval="$with_fpectl" --- 4992,4998 ---- # Check for --with-fpectl echo $ac_n "checking for --with-fpectl""... $ac_c" 1>&6 ! echo "configure:4996: checking for --with-fpectl" >&5 # Check whether --with-fpectl or --without-fpectl was given. if test "${with_fpectl+set}" = set; then withval="$with_fpectl" *************** *** 4818,4824 **** *) LIBM=-lm esac echo $ac_n "checking for --with-libm=STRING""... $ac_c" 1>&6 ! echo "configure:4822: checking for --with-libm=STRING" >&5 # Check whether --with-libm or --without-libm was given. if test "${with_libm+set}" = set; then withval="$with_libm" --- 5017,5023 ---- *) LIBM=-lm esac echo $ac_n "checking for --with-libm=STRING""... $ac_c" 1>&6 ! echo "configure:5021: checking for --with-libm=STRING" >&5 # Check whether --with-libm or --without-libm was given. if test "${with_libm+set}" = set; then withval="$with_libm" *************** *** 4839,4845 **** # check for --with-libc=... echo $ac_n "checking for --with-libc=STRING""... $ac_c" 1>&6 ! echo "configure:4843: checking for --with-libc=STRING" >&5 # Check whether --with-libc or --without-libc was given. if test "${with_libc+set}" = set; then withval="$with_libc" --- 5038,5044 ---- # check for --with-libc=... echo $ac_n "checking for --with-libc=STRING""... $ac_c" 1>&6 ! echo "configure:5042: checking for --with-libc=STRING" >&5 # Check whether --with-libc or --without-libc was given. if test "${with_libc+set}" = set; then withval="$with_libc" *************** *** 4863,4874 **** for ac_func in hypot do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4867: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:5066: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 5090,5096 ---- ; return 0; } EOF ! if { (eval echo configure:5094: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4918,4929 **** for ac_func in hypot do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4922: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:5121: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 5145,5151 ---- ; return 0; } EOF ! if { (eval echo configure:5149: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4980,4991 **** for ac_func in rint do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4984: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:5183: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 5207,5213 ---- ; return 0; } EOF ! if { (eval echo configure:5211: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 5036,5042 **** # check for getopt echo $ac_n "checking for genuine getopt""... $ac_c" 1>&6 ! echo "configure:5040: checking for genuine getopt" >&5 if eval "test \"`echo '$''{'ac_cv_func_getopt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 5235,5241 ---- # check for getopt echo $ac_n "checking for genuine getopt""... $ac_c" 1>&6 ! echo "configure:5239: checking for genuine getopt" >&5 if eval "test \"`echo '$''{'ac_cv_func_getopt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 5044,5050 **** ac_cv_func_getopt=no else cat > conftest.$ac_ext < extern int optind, opterr, getopt(); --- 5243,5249 ---- ac_cv_func_getopt=no else cat > conftest.$ac_ext < extern int optind, opterr, getopt(); *************** *** 5056,5062 **** exit(0); } EOF ! if { (eval echo configure:5060: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_getopt=yes else --- 5255,5261 ---- exit(0); } EOF ! if { (eval echo configure:5259: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_func_getopt=yes else *************** *** 5074,5080 **** # check whether malloc(0) returns NULL or not echo $ac_n "checking what malloc(0) returns""... $ac_c" 1>&6 ! echo "configure:5078: checking what malloc(0) returns" >&5 if eval "test \"`echo '$''{'ac_cv_malloc_zero'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 5273,5279 ---- # check whether malloc(0) returns NULL or not echo $ac_n "checking what malloc(0) returns""... $ac_c" 1>&6 ! echo "configure:5277: checking what malloc(0) returns" >&5 if eval "test \"`echo '$''{'ac_cv_malloc_zero'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 5082,5088 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #ifdef HAVE_STDLIB --- 5281,5287 ---- { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext < #ifdef HAVE_STDLIB *************** *** 5101,5107 **** exit(0); } EOF ! if { (eval echo configure:5105: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_malloc_zero=nonnull else --- 5300,5306 ---- exit(0); } EOF ! if { (eval echo configure:5304: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_malloc_zero=nonnull else *************** *** 5127,5143 **** # check for wchar.h ac_safe=`echo "wchar.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for wchar.h""... $ac_c" 1>&6 ! echo "configure:5131: checking for wchar.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:5141: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* --- 5326,5342 ---- # check for wchar.h ac_safe=`echo "wchar.h" | sed 'y%./+-%__p_%'` echo $ac_n "checking for wchar.h""... $ac_c" 1>&6 ! echo "configure:5330: checking for wchar.h" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:5340: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* *************** *** 5167,5178 **** # check for usable wchar_t usable_wchar_t="unkown" echo $ac_n "checking for usable wchar_t""... $ac_c" 1>&6 ! echo "configure:5171: checking for usable wchar_t" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&6 ! echo "configure:5370: checking for usable wchar_t" >&5 if test "$cross_compiling" = yes; then { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then cat >> confdefs.h <<\EOF #define HAVE_USABLE_WCHAR_T 1 --- 5385,5391 ---- } EOF ! if { (eval echo configure:5389: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then cat >> confdefs.h <<\EOF #define HAVE_USABLE_WCHAR_T 1 *************** *** 5205,5218 **** # check for endianness echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 ! echo "configure:5209: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include --- 5404,5417 ---- # check for endianness echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 ! echo "configure:5408: checking whether byte ordering is bigendian" >&5 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. cat > conftest.$ac_ext < #include *************** *** 5223,5233 **** #endif ; return 0; } EOF ! if { (eval echo configure:5227: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include --- 5422,5432 ---- #endif ; return 0; } EOF ! if { (eval echo configure:5426: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* # It does; now see whether it defined to BIG_ENDIAN or not. cat > conftest.$ac_ext < #include *************** *** 5238,5244 **** #endif ; return 0; } EOF ! if { (eval echo configure:5242: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else --- 5437,5443 ---- #endif ; return 0; } EOF ! if { (eval echo configure:5441: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_bigendian=yes else *************** *** 5258,5264 **** { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else --- 5470,5476 ---- exit (u.c[sizeof (long) - 1] == 1); } EOF ! if { (eval echo configure:5474: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then ac_cv_c_bigendian=no else *************** *** 5297,5303 **** # Check for --with-wctype-functions echo $ac_n "checking for --with-wctype-functions""... $ac_c" 1>&6 ! echo "configure:5301: checking for --with-wctype-functions" >&5 # Check whether --with-wctype-functions or --without-wctype-functions was given. if test "${with_wctype_functions+set}" = set; then withval="$with_wctype_functions" --- 5496,5502 ---- # Check for --with-wctype-functions echo $ac_n "checking for --with-wctype-functions""... $ac_c" 1>&6 ! echo "configure:5500: checking for --with-wctype-functions" >&5 # Check whether --with-wctype-functions or --without-wctype-functions was given. if test "${with_wctype_functions+set}" = set; then withval="$with_wctype_functions" *************** *** 5322,5333 **** #endif EOF echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 ! echo "configure:5326: checking for socklen_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS --- 5521,5532 ---- #endif EOF echo $ac_n "checking for socklen_t""... $ac_c" 1>&6 ! echo "configure:5525: checking for socklen_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_socklen_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.124 diff -c -r1.124 configure.in *** configure.in 2000/05/26 12:22:54 1.124 --- configure.in 2000/06/03 23:37:06 *************** *** 770,775 **** --- 770,780 ---- tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname waitpid) + # check for openpty and forkpty + + AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY)] [LIBS="$LIBS -lutil"])) + AC_CHECK_FUNCS(forkpty,, AC_CHECK_LIB(util,forkpty, [AC_DEFINE(HAVE_FORKPTY)] [LIBS="$LIBS -lutil"])) + # check for long file support functions AC_CHECK_FUNCS(fseek64 fseeko fstatvfs ftell64 ftello statvfs) Index: Modules/posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.135 diff -c -r2.135 posixmodule.c *** Modules/posixmodule.c 2000/06/01 02:02:46 2.135 --- Modules/posixmodule.c 2000/06/03 23:37:08 *************** *** 1731,1737 **** --- 1731,1779 ---- } #endif + #ifdef HAVE_OPENPTY + static char posix_openpty__doc__[] = + "openpty() -> (master_fd, slave_fd)\n\ + Open a pseudo-terminal, returning open fd's for both master and slave end.\n"; + static PyObject * + posix_openpty(self, args) + PyObject *self; + PyObject *args; + { + int master_fd, slave_fd; + if (!PyArg_ParseTuple(args, ":openpty")) + return NULL; + if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) + return posix_error(); + return Py_BuildValue("(ii)", master_fd, slave_fd); + } + #endif + + #ifdef HAVE_FORKPTY + static char posix_forkpty__doc__[] = + "forkpty() -> (pid, master_fd)\n\ + Fork a new process with a new pseudo-terminal as controlling tty.\n\n\ + Like fork(), return 0 as pid to child process, and PID of child to parent.\n\ + To both, return fd of newly opened pseudo-terminal.\n"; + + static PyObject * + posix_forkpty(self, args) + PyObject *self; + PyObject *args; + { + int master_fd, pid; + + if (!PyArg_ParseTuple(args, ":forkpty")) + return NULL; + pid = forkpty(&master_fd, NULL, NULL, NULL); + if (pid == -1) + return posix_error(); + PyOS_AfterFork(); + return Py_BuildValue("(ii)", pid, master_fd); + } + #endif + #ifdef HAVE_GETEGID static char posix_getegid__doc__[] = "getegid() -> egid\n\ *************** *** 4514,4519 **** --- 4556,4567 ---- #ifdef HAVE_FORK {"fork", posix_fork, METH_VARARGS, posix_fork__doc__}, #endif /* HAVE_FORK */ + #ifdef HAVE_OPENPTY + {"openpty", posix_openpty, METH_VARARGS, posix_openpty__doc__}, + #endif /* HAVE_OPENPTY */ + #ifdef HAVE_FORKPTY + {"forkpty", posix_forkpty, METH_VARARGS, posix_forkpty__doc__}, + #endif /* HAVE_FORKPTY */ #ifdef HAVE_GETEGID {"getegid", posix_getegid, METH_VARARGS, posix_getegid__doc__}, #endif /* HAVE_GETEGID */ --cNdxnHkX5QqsyA0e-- From tim_one@email.msn.com Sun Jun 4 05:13:38 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sun, 4 Jun 2000 00:13:38 -0400 Subject: [Patches] Patch to import.c In-Reply-To: <20000603101643.0486FD7210@oratrix.oratrix.nl> Message-ID: <000b01bfcddb$42729280$1d2d153f@tim> [Jack Jansen] > Is #elif nowadays supported by all compilers? Since it's been standard C ever since C had a standard <0.5 wink>, my confident guess is that it's supported by all compilers in use by developers. Use it. From tim_one@email.msn.com Sun Jun 4 05:32:39 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sun, 4 Jun 2000 00:32:39 -0400 Subject: [Patches] Patch to import.c In-Reply-To: Message-ID: <000c01bfcddd$eb35c7a0$1d2d153f@tim> [Greg Stein] > Python 1.6 is targeted at ANSI compilers. Heck, if you're feeling > particularly brain-dead one day, and just want something to do, then > go remove all the Py_PROTO macros :-) Let's make the latter my headache. The only editor I'll use for C/C++ programs anymore is Source Insight(*), and the Py_PROTO macros confuse its auto-generated database of program symbols. That is, I'm already motivated to change this, and am well equipped to deal with any subtle floating-point errors that crop up in the process . embracer-of-tedium-ly y'rs - tim (*) http://www.sourcedyn.com/ It's not a particularly good editor, but is a superb code browser. Use it for a month and, like one of the reviews predicted, you'll refuse to work without it! It may be the best reason in the world to use Windows . From tim_one@email.msn.com Sun Jun 4 05:32:42 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sun, 4 Jun 2000 00:32:42 -0400 Subject: [Patches] Patch to import.c In-Reply-To: <20000603110602.63987D7210@oratrix.oratrix.nl> Message-ID: <000d01bfcddd$ec6b8880$1d2d153f@tim> [Jack Jansen] > I'm a bit confused as to the current procedure for patches. It's broken. > It used to be that Guido said "yes" or "no", and that was it. And that's the way he left it, too. But among leaving CNRI, negotiating with BeOpen, and getting married, he's been about the most overloaded person on earth the past few months. Things will get better when he returns from his honeymoon. In the meantime, I'm often going to be too busy moving to Virginia to channel him, so I'm afraid we're all going to have to act like grownups . For starters, we should presume that your Mac patches (& Trent's Win64 patches, and all other patches only the originator is likely to be able to test) do what they claim to do on their platform, and review them mostly for possible unintended breakage on real platforms. > ... > As I didn't follow discussions on the new patch system: is there a > procedure Not really. The "votes" are purely advisory, and Guido still says "yes" or "no". In his absence we should make progress anyway and apologize later. > ... > And if there isn't one: could one be designed and documented, please? Jeez, Jack, you're just implacable today . From jack@oratrix.nl Sun Jun 4 21:24:09 2000 From: jack@oratrix.nl (Jack Jansen) Date: Sun, 04 Jun 2000 22:24:09 +0200 Subject: [Patches] Patch to Modules/pcre.h In-Reply-To: Message by Andrew Kuchling , Sat, 3 Jun 2000 08:05:10 -0400 , <20000603080510.B2252@newcnri.cnri.reston.va.us> Message-ID: <20000604202414.91CAED8397@oratrix.oratrix.nl> Recently, Andrew Kuchling said: > On Sat, Jun 03, 2000 at 01:03:47AM +0200, Jack Jansen wrote: > >Hmm, I thought the same, but the DONT_HAVE_SYS_TYPES_H stuff is all > >over the place already, so I thought I'd just hook onto that. > > I don't even see where DONT_HAVE_SYS_TYPES_H is ever defined: > [...] Don't forget that configure is a unix-specific thing. All other systems have a hand-crafted config.h. And as unix systems always have a sys/types you won't find a test for it in configure. -- Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++ Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++ www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm From mhammond@skippinet.com.au Mon Jun 5 00:18:30 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Mon, 5 Jun 2000 09:18:30 +1000 Subject: [Patches] New sys method to return total reference count in debug builds. Message-ID: When recently tracking down leaks, I found the ability to see the total number of Python references incredibly useful - it made it quite trivial to see which functions were leaking Python object references. This information is exposed in certain builds to the C API, but previously wasn't exposed to Python. This patch addresses this. The function will be exposed in default debug builds on the Windows platform, and any other builds where Py_TRACE_REFS is defined. Another slightly bogus reason for its inclusion is that interactive loops written in Python could now truly mimic the C implemented interactive loop, and print the total number of object references after each statement :-) I decided to use the name 'gettotalrefcount', to be somewhat consistent with the existing 'getrefcount'. There is no docstring, as no other debug only function appears to have one. RCS file: /cvsroot/python/python/dist/src/Python/sysmodule.c,v retrieving revision 2.63 diff -c -r2.63 sysmodule.c *** sysmodule.c 2000/05/09 19:57:01 2.63 --- sysmodule.c 2000/06/04 23:12:17 *************** *** 268,273 **** --- 268,285 ---- return PyInt_FromLong((long) arg->ob_refcnt); } + #ifdef Py_TRACE_REFS + static PyObject * + sys_gettotalrefcount(PyObject *self, PyObject *args) + { + extern long _Py_RefTotal; + if (!PyArg_ParseTuple(args, ":gettotalrefcount")) + return NULL; + return PyInt_FromLong((long) _Py_RefTotal); + } + + #endif /* Py_TRACE_REFS */ + static char getrefcount_doc[] = "getrefcount(object) -> integer\n\ \n\ *************** *** 310,315 **** --- 322,328 ---- #endif #ifdef Py_TRACE_REFS {"getobjects", _Py_GetObjects, 1}, + {"gettotalrefcount", sys_gettotalrefcount, 1}, #endif {"getrefcount", sys_getrefcount, 1, getrefcount_doc}, #ifdef USE_MALLOPT Release info: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Mark. From nascheme@enme.ucalgary.ca Mon Jun 5 18:39:27 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Mon, 5 Jun 2000 11:39:27 -0600 Subject: [Patches] Updated GC patch In-Reply-To: <14651.12289.191631.704477@localhost.localdomain>; from jeremy@beopen.com on Mon, Jun 05, 2000 at 12:43:45AM -0400 References: <20000602232521.B986@newcnri.cnri.reston.va.us> <3938D60E.391AAF31@lemburg.com> <14651.12289.191631.704477@localhost.localdomain> Message-ID: <20000605113927.A1852@acs.ucalgary.ca> On Mon, Jun 05, 2000 at 12:43:45AM -0400, Jeremy Hylton wrote: > I would like to check the patch in soon but I have had some trouble > with segfaults. I found the problem. Here is a new patch for the current CVS sources. Something to note in this version is that with GC enabled PyObject_{NEW, NEW_VAR, DEL} do not know about objects prefixed with PyGCInfo. If an object is involved with GC it must use PyObject_{New, NewVar, Del} or PyGC_{NEW, NEW_VAR, DEL}. Extension types should always use the PyObject functions so that they work with both GC enabled and regular interpreters. Neil Index: 0.6/config.h.in --- 0.6/config.h.in Mon, 05 Jun 2000 00:51:28 -0600 nas (python/3_config.h.i 1.1.2.2 644) +++ gc.8(w)/config.h.in Mon, 05 Jun 2000 02:09:43 -0600 nas (python/3_config.h.i 1.1.2.2 644) @@ -210,6 +210,9 @@ (shared library plus accessory files). */ #undef WITH_NEXT_FRAMEWORK +/* Define if you want cycle garbage collection */ +#undef WITH_CYCLE_GC + /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T Index: 0.6/configure.in --- 0.6/configure.in Mon, 05 Jun 2000 00:51:28 -0600 nas (python/5_configure. 1.1.2.2 644) +++ gc.8(w)/configure.in Mon, 05 Jun 2000 02:09:43 -0600 nas (python/5_configure. 1.1.2.2 644) @@ -1083,6 +1083,17 @@ fi], [AC_MSG_RESULT(no)]) +# Check for GC support +AC_SUBST(USE_GC_MODULE) +USE_GC_MODULE="#" +AC_MSG_CHECKING(for --with-cycle-gc) +AC_ARG_WITH(cycle-gc, [--with-cycle-gc enable garbage collection], [ +AC_MSG_RESULT($withval) +AC_DEFINE(WITH_CYCLE_GC) +USE_GC_MODULE= +], +AC_MSG_RESULT(no)) + # THIS MUST BE LAST, IT CAN BREAK OTHER TESTS! # Add sys/socket.h to confdefs.h cat >> confdefs.h <<\EOF Index: 0.6/Include/object.h --- 0.6/Include/object.h Tue, 25 Apr 2000 17:33:19 -0600 nas (python/o/18_object.h 1.1 644) +++ gc.8(w)/Include/object.h Mon, 05 Jun 2000 02:09:43 -0600 nas (python/o/18_object.h 1.1.1.1 644) @@ -145,6 +145,8 @@ typedef int (*getsegcountproc) Py_PROTO((PyObject *, int *)); typedef int (*getcharbufferproc) Py_PROTO((PyObject *, int, const char **)); typedef int (*objobjproc) Py_PROTO((PyObject *, PyObject *)); +typedef int (*visitproc) Py_PROTO((PyObject *, void *)); +typedef int (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); typedef struct { binaryfunc nb_add; @@ -243,9 +245,13 @@ char *tp_doc; /* Documentation string */ + /* call function for all accessible objects */ + recurseproc tp_recurse; + + /* delete references to contained objects */ + inquiry tp_clear; + /* More spares */ - long tp_xxx5; - long tp_xxx6; long tp_xxx7; long tp_xxx8; @@ -318,6 +324,9 @@ /* PySequenceMethods contains sq_contains */ #define Py_TPFLAGS_HAVE_SEQUENCE_IN (1L<<1) + +/* Objects with a GC info prefix (allocated *before* the object itself!) */ +#define Py_TPFLAGS_HAVE_GCINFO (1L<<2) #define Py_TPFLAGS_DEFAULT (Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_SEQUENCE_IN) Index: 0.6/Include/objimpl.h --- 0.6/Include/objimpl.h Mon, 08 May 2000 12:24:03 -0600 nas (python/o/19_objimpl.h 1.1.2.1 644) +++ gc.8(w)/Include/objimpl.h Mon, 05 Jun 2000 03:53:50 -0600 nas (python/o/19_objimpl.h 1.1.2.1 644) @@ -233,6 +233,66 @@ Note that in C++, the use of the new operator usually implies that the 1st step is performed automatically for you, so in a C++ class constructor you would start directly with PyObject_Init/InitVar. */ + + +#ifdef WITH_CYCLE_GC + +/* + * Garbage Collection Support + * ========================== + */ + +/* To make a new object participate in garbage collection use + PyObject_{New, VarNew, Del} to manage the memory. Set the type flag + Py_TPFLAGS_HAVE_GCINFO and define the type method tp_recurse. Call + PyGC_Insert after all the pointers followed by tp_recurse become + valid (usually just before returning the object from the allocation + method. Call PyGC_Remove before those pointers become invalid + (usually at the top of the deallocation method). Do not use + PyObject_{NEW, NEW_VAR, DEL} on GC objects. */ + +/* These macros should only be used within the interpreter. */ +#define PyGC_NEW(type, typeobj) PyObject_New(type, typeobj) +#define PyGC_NEW_VAR(type, typeobj, n) PyObject_NewVar(type, typeobj, n) +#define PyGC_DEL(op) PyObject_Del((PyObject *)(op)) + +/* Structure *prefixed* to container objects participating in GC */ +typedef struct _gcinfo { + struct _gcinfo *gc_next; + struct _gcinfo *gc_prev; + int gc_refs; +} PyGCInfo; + +/* Add the object into the container set */ +extern DL_IMPORT(void) PyGC_Insert Py_PROTO((PyObject *)); + +/* Remove the object from the container set */ +extern DL_IMPORT(void) PyGC_Remove Py_PROTO((PyObject *)); + +/* Test if a type has GC info */ +#define PyGC_TYPE_HAS_INFO(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GCINFO) + +/* Test if an object has GC info */ +#define PyGC_HAS_INFO(o) PyGC_TYPE_HAS_INFO((o)->ob_type) + +/* Get an object's GC info -- NULL if the object has none */ +#define PyGC_INFO(o) (PyGC_HAS_INFO(o) ? ((PyGCInfo *)(o)-1) : NULL) + +/* Unsafe version of PyGC_INFO() -- only call if PyGC_HAS_INFO(p) is true */ +#define PyGC_INFO_UNSAFE(o) ((PyGCInfo *)(o)-1) + +/* Get the object given the PyGCInfo */ +#define PyGC_OBJ(g) ((PyObject *)((g)+1)) + +#else /* ! WITH_CYCLE_GC */ + +#define PyGC_NEW PyObject_NEW +#define PyGC_NEW_VAR PyObject_NEW_VAR +#define PyGC_DEL PyObject_DEL +#define PyGC_Insert +#define PyGC_Remove + +#endif /* WITH_CYCLE_GC */ #ifdef __cplusplus } Index: 0.6/Modules/Setup.thread.in --- 0.6/Modules/Setup.thread.in Tue, 25 Apr 2000 17:33:19 -0600 nas (python/C/19_Setup.thre 1.1 644) +++ gc.8(w)/Modules/Setup.thread.in Mon, 05 Jun 2000 02:07:03 -0600 nas (python/C/19_Setup.thre 1.1 644) @@ -9,3 +9,6 @@ # support threads. @USE_THREAD_MODULE@thread threadmodule.c + +# Garbage collection enabled with --with-cycle-gc +@USE_GC_MODULE@gc gcmodule.c Index: 0.6/Modules/cPickle.c --- 0.6/Modules/cPickle.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/C/27_cPickle.c 1.1.2.2 644) +++ gc.8(w)/Modules/cPickle.c Mon, 05 Jun 2000 02:22:18 -0600 nas (python/C/27_cPickle.c 1.1.2.2 644) @@ -2893,7 +2893,7 @@ Py_DECREF(inst); goto err; } - + PyGC_Insert((PyObject *)inst); return (PyObject *)inst; } Py_DECREF(__getinitargs__); Index: 0.6/Modules/newmodule.c --- 0.6/Modules/newmodule.c Mon, 08 May 2000 12:24:03 -0600 nas (python/D/13_newmodule. 1.1.2.1 644) +++ gc.8(w)/Modules/newmodule.c Mon, 05 Jun 2000 02:22:37 -0600 nas (python/D/13_newmodule. 1.1.2.1 644) @@ -56,6 +56,7 @@ Py_INCREF(dict); inst->in_class = (PyClassObject *)klass; inst->in_dict = dict; + PyGC_Insert((PyObject *)inst); return (PyObject *)inst; } Index: 0.6/Objects/classobject.c --- 0.6/Objects/classobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/16_classobjec 1.1.2.2 644) +++ gc.8(w)/Objects/classobject.c Mon, 05 Jun 2000 02:09:43 -0600 nas (python/E/16_classobjec 1.1.2.2 644) @@ -111,7 +111,7 @@ } Py_INCREF(bases); } - op = PyObject_NEW(PyClassObject, &PyClass_Type); + op = PyGC_NEW(PyClassObject, &PyClass_Type); if (op == NULL) { Py_DECREF(bases); return NULL; @@ -132,6 +132,7 @@ Py_XINCREF(op->cl_getattr); Py_XINCREF(op->cl_setattr); Py_XINCREF(op->cl_delattr); + PyGC_Insert((PyObject *)op); return (PyObject *) op; } @@ -141,13 +142,14 @@ class_dealloc(op) PyClassObject *op; { + PyGC_Remove((PyObject *)op); Py_DECREF(op->cl_bases); Py_DECREF(op->cl_dict); Py_XDECREF(op->cl_name); Py_XDECREF(op->cl_getattr); Py_XDECREF(op->cl_setattr); Py_XDECREF(op->cl_delattr); - PyObject_DEL(op); + PyGC_DEL(op); } static PyObject * @@ -387,6 +389,21 @@ return res; } +#ifdef WITH_CYCLE_GC +static int +class_recurse(PyClassObject *o, visitproc visit, void *closure) +{ + if (o->cl_bases) visit(o->cl_bases, closure); + if (o->cl_dict) visit(o->cl_dict, closure); + if (o->cl_name) visit(o->cl_name, closure); + if (o->cl_getattr) visit(o->cl_getattr, closure); + if (o->cl_setattr) visit(o->cl_setattr, closure); + if (o->cl_delattr) visit(o->cl_delattr, closure); + return 1; +} +#endif /* WITH_CYCLE_GC */ + + PyTypeObject PyClass_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -407,6 +424,12 @@ (reprfunc)class_str, /*tp_str*/ (getattrofunc)class_getattr, /*tp_getattro*/ (setattrofunc)class_setattr, /*tp_setattro*/ +#ifdef WITH_CYCLE_GC + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)class_recurse, /* tp_recurse */ +#endif }; int @@ -445,12 +468,13 @@ PyErr_BadInternalCall(); return NULL; } - inst = PyObject_NEW(PyInstanceObject, &PyInstance_Type); + inst = PyGC_NEW(PyInstanceObject, &PyInstance_Type); if (inst == NULL) return NULL; Py_INCREF(class); inst->in_class = (PyClassObject *)class; inst->in_dict = PyDict_New(); + PyGC_Insert((PyObject *)inst); if (inst->in_dict == NULL) { Py_DECREF(inst); return NULL; @@ -498,11 +522,12 @@ PyObject *error_type, *error_value, *error_traceback; PyObject *del; static PyObject *delstr; + extern long _Py_RefTotal; + PyGC_Remove((PyObject *)inst); /* Call the __del__ method if it exists. First temporarily revive the object and save the current exception, if any. */ #ifdef Py_TRACE_REFS /* much too complicated if Py_TRACE_REFS defined */ - extern long _Py_RefTotal; inst->ob_type = &PyInstance_Type; _Py_NewReference((PyObject *)inst); _Py_RefTotal--; /* compensate for increment in NEWREF */ @@ -550,6 +575,7 @@ #ifdef COUNT_ALLOCS inst->ob_type->tp_free--; #endif + PyGC_Insert((PyObject *)inst); return; /* __del__ added a reference; don't delete now */ } #ifdef Py_TRACE_REFS @@ -557,11 +583,13 @@ inst->ob_type->tp_free--; /* compensate for increment in UNREF */ #endif _Py_ForgetReference((PyObject *)inst); +#ifndef WITH_CYCLE_GC inst->ob_type = NULL; +#endif #endif /* Py_TRACE_REFS */ Py_DECREF(inst->in_class); Py_XDECREF(inst->in_dict); - PyObject_DEL(inst); + PyGC_DEL(inst); } static PyObject * @@ -849,6 +877,16 @@ return outcome; } +#ifdef WITH_CYCLE_GC +static int +instance_recurse(PyInstanceObject *o, visitproc visit, void *closure) +{ + if (o->in_class) visit((PyObject *)(o->in_class), closure); + if (o->in_dict) visit(o->in_dict, closure); + return 1; +} +#endif /* WITH_CYCLE_GC */ + static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; static int @@ -1472,7 +1510,13 @@ (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /*tp_flags */ +#ifndef WITH_CYCLE_GC + Py_TPFLAGS_DEFAULT, /*tp_flags*/ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)instance_recurse, /* tp_recurse */ +#endif }; Index: 0.6/Objects/dictobject.c --- 0.6/Objects/dictobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/19_dictobject 1.1.2.1 644) +++ gc.8(w)/Objects/dictobject.c Mon, 05 Jun 2000 03:34:06 -0600 nas (python/E/19_dictobject 1.1.2.1 644) @@ -121,7 +121,7 @@ if (dummy == NULL) return NULL; } - mp = PyObject_NEW(dictobject, &PyDict_Type); + mp = PyGC_NEW(dictobject, &PyDict_Type); if (mp == NULL) return NULL; mp->ma_size = 0; @@ -129,6 +129,7 @@ mp->ma_table = NULL; mp->ma_fill = 0; mp->ma_used = 0; + PyGC_Insert((PyObject *)mp); return (PyObject *)mp; } @@ -481,6 +482,7 @@ register int i; register dictentry *ep; Py_TRASHCAN_SAFE_BEGIN(mp) + PyGC_Remove((PyObject *)mp); for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) { if (ep->me_key != NULL) { Py_DECREF(ep->me_key); @@ -491,7 +493,7 @@ } if (mp->ma_table != NULL) PyMem_DEL(mp->ma_table); - PyObject_DEL(mp); + PyGC_DEL(mp); Py_TRASHCAN_SAFE_END(mp) } @@ -1038,6 +1040,33 @@ return Py_None; } +#ifdef WITH_CYCLE_GC +static int +dict_recurse(PyObject *op, visitproc visit, void *closure) +{ + int i = 0; + PyObject *pk; + PyObject *pv; + + while (PyDict_Next(op, &i, &pk, &pv)) { + if (!visit(pk, closure)) { + return 0; + } + if (!visit(pv, closure)) { + return 0; + } + } + return 1; +} + +static int +dict_gc_clear(PyObject *op) +{ + PyDict_Clear(op); + return 0; +} +#endif /* WITH_CYCLE_GC */ + static PyMethodDef mapp_methods[] = { {"has_key", (PyCFunction)dict_has_key, METH_VARARGS}, {"keys", (PyCFunction)dict_keys}, @@ -1073,6 +1102,18 @@ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &dict_as_mapping, /*tp_as_mapping*/ +#ifdef WITH_CYCLE_GC + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)dict_recurse, /* tp_recurse */ + (inquiry)dict_gc_clear, /* tp_clear */ +#endif }; /* For backward compatibility with old dictionary interface */ Index: 0.6/Objects/funcobject.c --- 0.6/Objects/funcobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/23_funcobject 1.1.2.2 644) +++ gc.8(w)/Objects/funcobject.c Mon, 05 Jun 2000 03:34:30 -0600 nas (python/E/23_funcobject 1.1.2.2 644) @@ -40,8 +40,7 @@ PyObject *code; PyObject *globals; { - PyFunctionObject *op = PyObject_NEW(PyFunctionObject, - &PyFunction_Type); + PyFunctionObject *op = PyGC_NEW(PyFunctionObject, &PyFunction_Type); if (op != NULL) { PyObject *doc; PyObject *consts; @@ -63,6 +62,7 @@ Py_INCREF(doc); op->func_doc = doc; } + PyGC_Insert((PyObject *)op); return (PyObject *)op; } @@ -186,12 +186,13 @@ func_dealloc(op) PyFunctionObject *op; { + PyGC_Remove((PyObject *)op); Py_DECREF(op->func_code); Py_DECREF(op->func_globals); Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc); - PyObject_DEL(op); + PyGC_DEL(op); } static PyObject* @@ -239,6 +240,19 @@ return h; } +#ifdef WITH_CYCLE_GC +static int +func_recurse(PyFunctionObject *f, visitproc visit, void *closure) +{ + if (f->func_code) visit(f->func_code, closure); + if (f->func_globals) visit(f->func_globals, closure); + if (f->func_defaults) visit(f->func_defaults, closure); + if (f->func_doc) visit(f->func_doc, closure); + if (f->func_name) visit(f->func_name, closure); + return 1; +} +#endif /* WITH_CYCLE_GC */ + PyTypeObject PyFunction_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, @@ -255,4 +269,14 @@ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)func_hash, /*tp_hash*/ +#ifdef WITH_CYCLE_GC + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)func_recurse, /* tp_recurse */ +#endif }; Index: 0.6/Objects/listobject.c --- 0.6/Objects/listobject.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/25_listobject 1.1.2.3 644) +++ gc.8(w)/Objects/listobject.c Mon, 05 Jun 2000 03:33:46 -0600 nas (python/E/25_listobject 1.1.2.3 644) @@ -71,7 +71,15 @@ return PyErr_NoMemory(); } /* PyObject_NewVar is inlined */ +#ifdef WITH_CYCLE_GC + op = (PyListObject *) PyObject_MALLOC(sizeof(PyGCInfo) + + sizeof(PyListObject)); + if (op != NULL) { + op = (PyListObject *) PyGC_OBJ((PyGCInfo *)op); + } +#else op = (PyListObject *) PyObject_MALLOC(sizeof(PyListObject)); +#endif if (op == NULL) { return PyErr_NoMemory(); } @@ -88,6 +96,7 @@ PyObject_INIT_VAR(op, &PyList_Type, size); for (i = 0; i < size; i++) op->ob_item[i] = NULL; + PyGC_Insert((PyObject *)op); return (PyObject *) op; } @@ -215,6 +224,7 @@ { int i; Py_TRASHCAN_SAFE_BEGIN(op) + PyGC_Remove((PyObject *)op); if (op->ob_item != NULL) { /* Do it backwards, for Christian Tismer. There's a simple test case where somehow this reduces @@ -226,7 +236,7 @@ } PyMem_FREE(op->ob_item); } - PyObject_DEL(op); + PyGC_DEL(op); Py_TRASHCAN_SAFE_END(op) } @@ -1423,6 +1433,29 @@ return NULL; } +#ifdef WITH_CYCLE_GC +static int +list_recurse(PyListObject *o, visitproc visit, void *closure) +{ + int i; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL && !visit(x, closure)) + return 0; + } + return 1; +} + +static int +list_clear(PyListObject *lp) +{ + (void) PyList_SetSlice((PyObject *)lp, 0, lp->ob_size, 0); + return 0; +} +#endif /* WITH_CYCLE_GC */ + static char append_doc[] = "L.append(object) -- append object to end"; static char extend_doc[] = @@ -1489,6 +1522,18 @@ 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ +#ifdef WITH_CYCLE_GC + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)list_recurse, /* tp_recurse */ + (inquiry)list_clear, /* tp_clear */ +#endif }; @@ -1557,5 +1602,16 @@ 0, /*tp_as_number*/ &immutable_list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ +#ifdef WITH_CYCLE_GC + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)list_recurse, /* tp_recurse */ +#endif }; Index: 0.6/Objects/object.c --- 0.6/Objects/object.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/29_object.c 1.1.1.1 644) +++ gc.8(w)/Objects/object.c Mon, 05 Jun 2000 03:17:07 -0600 nas (python/E/29_object.c 1.1.1.1 644) @@ -151,7 +151,21 @@ PyTypeObject *tp; { PyObject *op; - op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); +#ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) { + PyGCInfo *g; + g = (PyGCInfo *) PyObject_MALLOC(sizeof(*g) + + _PyObject_SIZE(tp)); + if (g == NULL) { + op = NULL; + } else { + op = PyGC_OBJ(g); + } + } else +#endif + { + op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); + } if (op == NULL) return PyErr_NoMemory(); return PyObject_INIT(op, tp); @@ -163,7 +177,22 @@ int size; { PyVarObject *op; - op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size)); +#ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) { + PyGCInfo *g; + g = (PyGCInfo *) PyObject_MALLOC(sizeof(*g) + + _PyObject_VAR_SIZE(tp, size)); + if (g == NULL) { + op = NULL; + } else { + op = (PyVarObject *)PyGC_OBJ(g); + } + } else +#endif + { + op = (PyVarObject *) + PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size)); + } if (op == NULL) return (PyVarObject *)PyErr_NoMemory(); return PyObject_INIT_VAR(op, tp, size); @@ -173,7 +202,15 @@ _PyObject_Del(op) PyObject *op; { - PyObject_FREE(op); +#ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(op->ob_type)) { + PyGCInfo *g = PyGC_INFO(op); + PyObject_FREE(g); + } else +#endif + { + PyObject_FREE(op); + } } int @@ -845,8 +882,10 @@ { destructor dealloc = op->ob_type->tp_dealloc; _Py_ForgetReference(op); +#ifndef WITH_CYCLE_GC if (_PyTrash_delete_nesting < PyTrash_UNWIND_LEVEL-1) op->ob_type = NULL; +#endif (*dealloc)(op); } Index: 0.6/Objects/tupleobject.c --- 0.6/Objects/tupleobject.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/33_tupleobjec 1.1.2.3 644) +++ gc.8(w)/Objects/tupleobject.c Mon, 05 Jun 2000 03:31:21 -0600 nas (python/E/33_tupleobjec 1.1.2.3 644) @@ -99,10 +99,17 @@ return PyErr_NoMemory(); } /* PyObject_NewVar is inlined */ +#ifdef WITH_CYCLE_GC + op = (PyTupleObject *) + PyObject_MALLOC(sizeof(PyGCInfo) + nbytes); + if (op != NULL) { + op = (PyTupleObject *) PyGC_OBJ((PyGCInfo *)op); + } +#else op = (PyTupleObject *) PyObject_MALLOC(nbytes); +#endif if (op == NULL) return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyTuple_Type, size); } for (i = 0; i < size; i++) @@ -114,6 +121,7 @@ Py_INCREF(op); /* extra INCREF so that this is never freed */ } #endif + PyGC_Insert((PyObject *)op); return (PyObject *) op; } @@ -180,6 +188,7 @@ register int i; register int len = op->ob_size; Py_TRASHCAN_SAFE_BEGIN(op) + PyGC_Remove((PyObject *)op); if (len > 0) { i = len; while (--i >= 0) @@ -193,7 +202,7 @@ } #endif } - PyObject_DEL(op); + PyGC_DEL(op); done: Py_TRASHCAN_SAFE_END(op) } @@ -420,6 +429,22 @@ return (PyObject *) np; } +#ifdef WITH_CYCLE_GC +static int +tuplerecurse(PyTupleObject *o, visitproc visit, void *closure) +{ + int i; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL && !visit(x, closure)) + return 0; + } + return 1; +} +#endif /* WITH_CYCLE_GC */ + static PySequenceMethods tuple_as_sequence = { (inquiry)tuplelength, /*sq_length*/ (binaryfunc)tupleconcat, /*sq_concat*/ @@ -447,6 +472,16 @@ &tuple_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)tuplehash, /*tp_hash*/ +#ifdef WITH_CYCLE_GC + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GCINFO, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)tuplerecurse, /* tp_recurse */ +#endif }; /* The following function breaks the notion that tuples are immutable: @@ -531,12 +566,25 @@ } else #endif { +#ifdef WITH_CYCLE_GC + PyGCInfo *g = PyGC_INFO((PyObject *)v); + PyGC_Remove((PyObject *)v); + g = PyObject_REALLOC((char *)v, sizeof(*g) + + sizeof(PyTupleObject) + newsize * sizeof(PyObject *)); + if (g == NULL) { + sv = NULL; + } else { + sv = (PyTupleObject *)PyGC_OBJ(g); + } +#else sv = (PyTupleObject *) PyObject_REALLOC((char *)v, sizeof(PyTupleObject) + newsize * sizeof(PyObject *)); +#endif *pv = (PyObject *) sv; if (sv == NULL) { - PyObject_DEL(v); + PyGC_Insert((PyObject *)v); + PyGC_DEL(v); PyErr_NoMemory(); return -1; } @@ -551,6 +599,7 @@ sv->ob_item[i - sizediff] = NULL; } } + PyGC_Insert((PyObject *)sv); sv->ob_size = newsize; return 0; } @@ -571,7 +620,7 @@ while (p) { q = p; p = (PyTupleObject *)(p->ob_item[0]); - PyObject_DEL(q); + PyGC_DEL(q); } } #endif Index: 0.6/PC/config.c --- 0.6/PC/config.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/39_config.c 1.1.2.1 644) +++ gc.8(w)/PC/config.c Mon, 05 Jun 2000 02:09:43 -0600 nas (python/E/39_config.c 1.1.2.1 644) @@ -43,6 +43,9 @@ #endif extern void initcmath(); extern void initerrno(); +#ifdef WITH_CYCLE_GC +extern void initgc(); +#endif #ifndef MS_WIN64 extern void initimageop(); #endif @@ -89,6 +92,9 @@ #endif {"cmath", initcmath}, {"errno", initerrno}, +#ifdef WITH_CYCLE_GC + {"gc", initgc}, +#endif #ifndef MS_WIN64 {"imageop", initimageop}, #endif Index: 0.6/PC/config.h --- 0.6/PC/config.h Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/40_config.h 1.1.2.2 644) +++ gc.8(w)/PC/config.h Mon, 05 Jun 2000 02:09:43 -0600 nas (python/E/40_config.h 1.1.2.2 644) @@ -421,6 +421,9 @@ /* Define if you want to use the GNU readline library */ /* #define WITH_READLINE 1 */ +/* Define if you want cycle garbage collection */ +#define WITH_CYCLE_GC 1 + /* Define if you have clock. */ /* #define HAVE_CLOCK */ Index: 0.6/PCbuild/python16.dsp --- 0.6/PCbuild/python16.dsp Mon, 05 Jun 2000 00:51:28 -0600 nas (python/G/1_python16.d 1.1.1.1 644) +++ gc.8(w)/PCbuild/python16.dsp Mon, 05 Jun 2000 02:09:00 -0600 nas (python/G/1_python16.d 1.1.1.1 644) @@ -660,6 +660,21 @@ # End Source File # Begin Source File +SOURCE=..\Modules\gcmodule.c + +!IF "$(CFG)" == "python16 - Win32 Release" + +!ELSEIF "$(CFG)" == "python16 - Win32 Debug" + +!ELSEIF "$(CFG)" == "python16 - Win32 Alpha Debug" + +!ELSEIF "$(CFG)" == "python16 - Win32 Alpha Release" + +!ENDIF + +# End Source File +# Begin Source File + SOURCE=..\Python\getargs.c !IF "$(CFG)" == "python16 - Win32 Release" Index: 0.6/Modules/gcmodule.c --- 0.6/Modules/gcmodule.c Mon, 05 Jun 2000 03:54:11 -0600 nas () +++ gc.8(w)/Modules/gcmodule.c Mon, 05 Jun 2000 03:37:11 -0600 nas (python/M/10_gcmodule.c 1.3 644) @@ -0,0 +1,678 @@ +/* + + Reference Cycle Garbage Collection + ================================== + + Neil Schemenauer + + Based on a post on the python-dev list. Ideas from Guido van Rossum, + Eric Tiedemann, and various others. + + http://www.enme.calgary.ca/~nascheme/python/gc.html + http://www.python.org/pipermail/python-dev/2000-March/003869.html + http://www.python.org/pipermail/python-dev/2000-March/004010.html + http://www.python.org/pipermail/python-dev/2000-March/004022.html + + For a highlevel view of the collection process, read the collect + function. + + TODO: + use a different interface for set_debug() (keywords)? + inline PyGC_Insert and PyGC_Remove calls? + tune parameters + +*/ + +#include "Python.h" + +/* #define Py_DEBUG */ + +#ifndef WITH_CYCLE_GC +#error "You must define WITH_CYCLE_GC to include this module" +#endif + +/* magic gc_refs value */ +#define GC_MOVED -1 + +/*** Global GC state ***/ + +/* linked lists of container objects */ +static PyGCInfo generation0 = {&generation0, &generation0, 0}; +static PyGCInfo generation1 = {&generation1, &generation1, 0}; +static PyGCInfo generation2 = {&generation2, &generation2, 0}; +static int generation = 0; /* current generation being collected */ + +/* collection frequencies, XXX tune these */ +static int threshold0 = 100; /* net new containers before collection */ +static int threshold1 = 10; /* generation0 collections before collecting 1 */ +static int threshold2 = 10; /* generation1 collections before collecting 2 */ + +/* net new objects allocated since last collection */ +static int allocated = 0; + +/* set for debugging information */ +#define DEBUG_STATS (1<<0) /* print collection statistics */ +#define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ +#define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */ +#define DEBUG_INSTANCES (1<<3) /* print instances */ +#define DEBUG_OBJECTS (1<<4) /* print other objects */ +#define DEBUG_LEAK DEBUG_COLLECTABLE | \ + DEBUG_UNCOLLECTABLE | \ + DEBUG_INSTANCES | \ + DEBUG_OBJECTS +static int debug = DEBUG_LEAK; + +/* list of uncollectable objects */ +static PyObject *garbage = NULL; + + +/*** list functions ***/ + +static void +list_init(PyGCInfo *list) +{ + list->gc_prev = list; + list->gc_next = list; +} + +static void +list_append(PyGCInfo *node, PyGCInfo *list) +{ + node->gc_next = list; + node->gc_prev = list->gc_prev; + node->gc_prev->gc_next = node; + list->gc_prev = node; +} + +static void +list_remove(PyGCInfo *node) +{ + node->gc_prev->gc_next = node->gc_next; + node->gc_next->gc_prev = node->gc_prev; +#ifdef Py_DEBUG + node->gc_prev = NULL; + node->gc_next = NULL; +#endif +} + +static void +list_move(PyGCInfo *from, PyGCInfo *to) +{ + if (from->gc_next == from) { + /* empty from list */ + list_init(to); + } else { + to->gc_next = from->gc_next; + to->gc_next->gc_prev = to; + to->gc_prev = from->gc_prev; + to->gc_prev->gc_next = to; + } + list_init(from); +} + +/* append a list onto another list */ +static void +list_lappend(PyGCInfo *from, PyGCInfo *to) +{ + PyGCInfo *tail; + if (from->gc_next != from) { + tail = to->gc_prev; + tail->gc_next = from->gc_next; + tail->gc_next->gc_prev = tail; + to->gc_prev = from->gc_prev; + to->gc_prev->gc_next = to; + } + list_init(from); +} + +static long +list_size(PyGCInfo *list) +{ + PyGCInfo *gc; + long n = 0; + for (gc = list->gc_next; gc != list; gc = gc->gc_next) { + n++; + } + return n; +} + +/*** end of list stuff ***/ + + +/* Set all gc_refs = ob_refcnt */ +static void +update_refs(PyGCInfo *containers) +{ + PyGCInfo *gc = containers->gc_next; + for (; gc != containers; gc=gc->gc_next) { + gc->gc_refs = PyGC_OBJ(gc)->ob_refcnt; + } +} + +static int +visit_decref(PyObject *op, void *data) +{ + if (op && PyGC_HAS_INFO(op)) { + PyGC_INFO_UNSAFE(op)->gc_refs--; + } + return 1; +} + +/* Subtract internal references from gc_refs */ +static void +subtract_refs(PyGCInfo *containers) +{ + recurseproc recurse; + PyGCInfo *gc = containers->gc_next; + for (; gc != containers; gc=gc->gc_next) { + recurse = PyGC_OBJ(gc)->ob_type->tp_recurse; + (void) recurse(PyGC_OBJ(gc), + (visitproc)visit_decref, + NULL); + } +} + +/* Append objects with gc_refs > 0 to roots list */ +static void +move_roots(PyGCInfo *containers, PyGCInfo *roots) +{ + PyGCInfo *next; + PyGCInfo *gc = containers->gc_next; + while (gc != containers) { + next = gc->gc_next; + if (gc->gc_refs > 0) { + list_remove(gc); + list_append(gc, roots); + gc->gc_refs = GC_MOVED; + } + gc = next; + } +} + +static int +visit_reachable(PyObject *op, PyGCInfo *roots) +{ + PyGCInfo *gc = PyGC_INFO(op); + if (gc && gc->gc_refs != GC_MOVED) { + list_remove(gc); + list_append(gc, roots); + gc->gc_refs = GC_MOVED; + } + return 1; +} + +/* Move objects referenced from reachable to reachable set. */ +static void +move_root_reachable(PyGCInfo *reachable) +{ + recurseproc recurse; + PyGCInfo *gc = reachable->gc_next; + for (; gc != reachable; gc=gc->gc_next) { + /* careful, reachable list is growing here */ + PyObject *op = PyGC_OBJ(gc); + recurse = op->ob_type->tp_recurse; + (void) recurse(op, + (visitproc)visit_reachable, + (void *)reachable); + } +} + +/* move all objects with finalizers (instances with __del__) */ +static void +move_finalizers(PyGCInfo *unreachable, PyGCInfo *finalizers) +{ + PyGCInfo *next; + PyGCInfo *gc = unreachable->gc_next; + static PyObject *delstr; + if (delstr == NULL) { + delstr = PyString_InternFromString("__del__"); + } + for (; gc != unreachable; gc=next) { + PyObject *op = PyGC_OBJ(gc); + next = gc->gc_next; + if (PyInstance_Check(op) && PyObject_HasAttr(op, delstr)) { + list_remove(gc); + list_append(gc, finalizers); + } + } +} + + +/* called by tp_recurse */ +static int +visit_finalizer_reachable(PyObject *op, PyGCInfo *finalizers) +{ + PyGCInfo *gc = PyGC_INFO(op); + if (gc && gc->gc_refs != GC_MOVED) { + list_remove(gc); + list_append(gc, finalizers); + gc->gc_refs = GC_MOVED; + } + return 1; +} + +/* Move objects referenced from roots to roots */ +static void +move_finalizer_reachable(PyGCInfo *finalizers) +{ + recurseproc recurse; + PyGCInfo *gc = finalizers->gc_next; + for (; gc != finalizers; gc=gc->gc_next) { + /* careful, finalizers list is growing here */ + recurse = PyGC_OBJ(gc)->ob_type->tp_recurse; + (void) recurse(PyGC_OBJ(gc), + (visitproc)visit_finalizer_reachable, + (void *)finalizers); + } +} + +static void +debug_instance(PyObject *output, char *msg, PyInstanceObject *inst) +{ + char buf[200]; + char *cname; + /* be careful not to create new dictionaries */ + PyObject *classname = inst->in_class->cl_name; + if (classname != NULL && PyString_Check(classname)) + cname = PyString_AsString(classname); + else + cname = "?"; + sprintf(buf, "gc: %s<%.100s instance at %lx>\n", + msg, cname, (long)inst); + PyFile_WriteString(buf, output); +} + +static void +debug_cycle(PyObject *output, char *msg, PyObject *op) +{ + if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { + debug_instance(output, msg, (PyInstanceObject *)op); + } else if (debug & DEBUG_OBJECTS) { + char buf[200]; + sprintf(buf, "gc: %s<%s 0x%x>\n", + msg, + op->ob_type->tp_name, + (long)op); + PyFile_WriteString(buf, output); + } +} + +/* Handle uncollectable garbage (cycles with finalizers). */ +static void +handle_finalizers(PyGCInfo *finalizers, PyGCInfo *old) +{ + PyGCInfo *gc; + if (garbage == NULL) { + garbage = PyList_New(0); + } + for (gc = finalizers->gc_next; gc != finalizers; + gc = finalizers->gc_next) { + PyObject *op = PyGC_OBJ(gc); + /* Add all instances to a Python accessible list of garbage */ + if (PyInstance_Check(op)) { + PyList_Append(garbage, op); + } + /* We assume that all objects in finalizers are reachable from + * instances. Once we add the instances to the garbage list + * everything is reachable from Python again. */ + list_remove(gc); + list_append(gc, old); + } +} + +/* Break reference cycles by clearing the containers involved. This is + * tricky business as the lists can be changing and we don't know which + * objects may be freed. It is possible I screwed something up here. */ +static void +delete_garbage(PyGCInfo *unreachable, PyGCInfo *old) +{ + inquiry clear; + + while (unreachable->gc_next != unreachable) { + PyGCInfo *gc = unreachable->gc_next; + PyObject *op = PyGC_OBJ(gc); + /* + PyList_Append(garbage, op); + */ + if ((clear = op->ob_type->tp_clear) != NULL) { + Py_INCREF(op); + clear((PyObject *)op); + Py_DECREF(op); + } + /* only try to call tp_clear once for each object */ + if (unreachable->gc_next == gc) { + /* still alive, move it, it may die later */ + list_remove(gc); + list_append(gc, old); + } + } +} + +/* This is the main function. Read this to understand how the + * collection process works. */ +static long +collect(PyGCInfo *young, PyGCInfo *old) +{ + long n = 0; + long m = 0; + PyGCInfo reachable; + PyGCInfo unreachable; + PyGCInfo finalizers; + PyGCInfo *gc; + PyObject *output = NULL; + + if (debug) { + output = PySys_GetObject("stderr"); + } + if (debug & DEBUG_STATS) { + char buf[100]; + sprintf(buf, "gc: collecting generation %d...\n", generation); + PyFile_WriteString(buf,output); + sprintf(buf, "gc: objects in each generation: %d %d %d\n", + list_size(&generation0), + list_size(&generation1), + list_size(&generation2)); + PyFile_WriteString(buf,output); + } + + /* Using ob_refcnt and gc_refs, calculate which objects in the + * container set are reachable from outside the set (ie. have a + * refcount greater than 0 when all the references within the + * set are taken into account */ + update_refs(young); + subtract_refs(young); + + /* Move everything reachable from outside the set into the + * reachable set (ie. gc_refs > 0). Next, move everything + * reachable from objects in the reachable set. */ + list_init(&reachable); + move_roots(young, &reachable); + move_root_reachable(&reachable); + + /* move unreachable objects to a temporary list, new objects can be + * allocated after this point */ + list_init(&unreachable); + list_move(young, &unreachable); + + /* move reachable objects to next generation */ + list_lappend(&reachable, old); + + /* Move objects reachable from finalizers, we can't safely delete + * them. Python programmers should take care not to create such + * things. For Python finalizers means instance objects with + * __del__ methods. */ + list_init(&finalizers); + move_finalizers(&unreachable, &finalizers); + move_finalizer_reachable(&finalizers); + + /* Collect statistics on collectable objects found and print + * debugging information. */ + for (gc = unreachable.gc_next; gc != &unreachable; + gc = gc->gc_next) { + m++; + if (output != NULL && (debug & DEBUG_COLLECTABLE)) { + debug_cycle(output, "collectable ", PyGC_OBJ(gc)); + } + } + /* call tp_clear on objects in the collectable set. This will cause + * the reference cycles to be broken. It may also cause some objects in + * finalizers to be freed */ + delete_garbage(&unreachable, old); + + /* Collect statistics on uncollectable objects found and print + * debugging information. */ + for (gc = finalizers.gc_next; gc != &finalizers; + gc = gc->gc_next) { + n++; + if (output != NULL && (debug & DEBUG_UNCOLLECTABLE)) { + debug_cycle(output, "uncollectable ", PyGC_OBJ(gc)); + } + } + if (output != NULL && (debug & DEBUG_STATS)) { + if (m == 0 && n == 0) { + PyFile_WriteString("gc: done.\n", output); + } else { + char buf[200]; + sprintf(buf, + "gc: done, %d unreachable, %d uncollectable.\n", + n+m, n); + PyFile_WriteString(buf, output); + } + } + + /* Append instances in the uncollectable set to a Python + * reachable list of garbage. The programmer has to deal with + * this if they insist on creating this type of structure. */ + handle_finalizers(&finalizers, old); + + allocated = 0; + PyErr_Clear(); /* in case writing to sys.stderr failed */ + return n+m; +} + +static long +collect_generations(void) +{ + static long collections0 = 0; + static long collections1 = 0; + long n; + + + if (collections1 > threshold2) { + generation = 2; + list_lappend(&generation0, &generation2); + list_lappend(&generation1, &generation2); + if (generation2.gc_next != &generation2) { + n = collect(&generation2, &generation2); + } + collections1 = 0; + } else if (collections0 > threshold1) { + generation = 1; + collections1++; + list_lappend(&generation0, &generation1); + if (generation1.gc_next != &generation1) { + n = collect(&generation1, &generation2); + } + collections0 = 0; + } else { + generation = 0; + collections0++; + if (generation0.gc_next != &generation0) { + n = collect(&generation0, &generation1); + } + } + return n; +} + +void +PyGC_Insert(PyObject *op) +{ + /* collection lock since collecting may cause allocations */ + static int collecting = 0; + +#ifdef Py_DEBUG + if (!PyGC_HAS_INFO(op)) { + abort(); + } +#endif + if (threshold0 && allocated > threshold0 && !collecting) { + collecting++; + collect_generations(); + collecting--; + } + allocated++; + list_append(PyGC_INFO(op), &generation0); +} + +void +PyGC_Remove(PyObject *op) +{ + PyGCInfo *g = PyGC_INFO(op); +#ifdef Py_DEBUG + if (!PyGC_HAS_INFO(op)) { + abort(); + } +#endif + list_remove(g); + if (allocated > 0) { + allocated--; + } +} + + +static char collect__doc__[] = +"collect() -> n\n" +"\n" +"Run a full collection. The number of unreachable objects is returned.\n" +; + +static PyObject * +Py_collect(self, args) + PyObject *self; + PyObject *args; +{ + long n; + + if(!PyArg_ParseTuple(args, "")) /* check no args */ + return NULL; + + generation = 2; + list_lappend(&generation0, &generation2); + list_lappend(&generation1, &generation2); + n = collect(&generation2, &generation2); + + return Py_BuildValue("i", n); +} + +static char set_debug__doc__[] = +"set_debug(flags) -> None\n" +"\n" +"Set the garbage collection debugging flags. Debugging information is\n" +"written to sys.stderr.\n" +"\n" +"flags is an integer and can have the following bits turned on:\n" +"\n" +" DEBUG_STATS - Print statistics during collection.\n" +" DEBUG_COLLECTABLE - Print collectable objects found.\n" +" DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n" +" DEBUG_INSTANCES - Print instance objects.\n" +" DEBUG_OBJECTS - Print objects other than instances.\n" +" DEBUG_LEAK - Debug leaking programs (everything but STATS).\n" +; + +static PyObject * +Py_set_debug(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_ParseTuple(args, "l", &debug)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static char get_debug__doc__[] = +"get_debug() -> flags\n" +"\n" +"Get the garbage collection debugging flags.\n" +; + +static PyObject * +Py_get_debug(self, args) + PyObject *self; + PyObject *args; +{ + if(!PyArg_ParseTuple(args, "")) /* no args */ + return NULL; + + return Py_BuildValue("i", debug); +} + +static char set_thresh__doc__[] = +"set_threshold(threshold0, [threhold1, threshold2]) -> None\n" +"\n" +"Sets the collection thresholds. Setting threshold0 to zero disables\n" +"collection.\n" +; + +static PyObject * +Py_set_thresh(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_ParseTuple(args, "i|ii", &threshold0, + &threshold1, &threshold2)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static char get_thresh__doc__[] = +"get_threshold() -> (threshold0, threshold1, threshold2)\n" +"\n" +"Return the current collection thresholds\n" +; + +static PyObject * +Py_get_thresh(self, args) + PyObject *self; + PyObject *args; +{ + if(!PyArg_ParseTuple(args, "")) /* no args */ + return NULL; + + return Py_BuildValue("(iii)", threshold0, threshold1, threshold2); +} + + +static char gc__doc__ [] = +"This module provides access to the garbage collector for reference cycles.\n" +"\n" +"collect() -- Do a full collection right now.\n" +"set_debug() -- Set debugging flags.\n" +"get_debug() -- Get debugging flags.\n" +"set_threshold() -- Set the collection thresholds.\n" +"get_threshold() -- Return the current the collection thresholds.\n" +; + +static PyMethodDef GcMethods[] = { + {"set_debug", Py_set_debug, METH_VARARGS, set_debug__doc__}, + {"get_debug", Py_get_debug, METH_VARARGS, get_debug__doc__}, + {"set_threshold", Py_set_thresh, METH_VARARGS, set_thresh__doc__}, + {"get_threshold", Py_get_thresh, METH_VARARGS, get_thresh__doc__}, + {"collect", Py_collect, METH_VARARGS, collect__doc__}, + {NULL, NULL} /* Sentinel */ +}; + +void +initgc(void) +{ + PyObject *m; + PyObject *d; + + m = Py_InitModule4("gc", + GcMethods, + gc__doc__, + NULL, + PYTHON_API_VERSION); + d = PyModule_GetDict(m); + if (garbage == NULL) { + garbage = PyList_New(0); + } + PyDict_SetItemString(d, "garbage", garbage); + PyDict_SetItemString(d, "DEBUG_STATS", + PyInt_FromLong(DEBUG_STATS)); + PyDict_SetItemString(d, "DEBUG_COLLECTABLE", + PyInt_FromLong(DEBUG_COLLECTABLE)); + PyDict_SetItemString(d, "DEBUG_UNCOLLECTABLE", + PyInt_FromLong(DEBUG_UNCOLLECTABLE)); + PyDict_SetItemString(d, "DEBUG_INSTANCES", + PyInt_FromLong(DEBUG_INSTANCES)); + PyDict_SetItemString(d, "DEBUG_OBJECTS", + PyInt_FromLong(DEBUG_OBJECTS)); + PyDict_SetItemString(d, "DEBUG_LEAK", + PyInt_FromLong(DEBUG_LEAK)); +} + Index: 0.6/Lib/test/test_gc.py --- 0.6/Lib/test/test_gc.py Mon, 05 Jun 2000 03:54:11 -0600 nas () +++ gc.8(w)/Lib/test/test_gc.py Mon, 05 Jun 2000 02:09:43 -0600 nas (python/M/12_test_gc.py 1.1 644) @@ -0,0 +1,90 @@ +import gc + +def test_list(): + l = [] + l.append(l) + print 'list 0x%x' % id(l) + gc.collect() + del l + assert gc.collect() == 1 + +def test_dict(): + d = {} + d[1] = d + print 'dict 0x%x' % id(d) + gc.collect() + del d + assert gc.collect() == 1 + +def test_tuple(): + l = [] + t = (l,) + l.append(t) + print 'list 0x%x' % id(l) + print 'tuple 0x%x' % id(t) + gc.collect() + del t + del l + assert gc.collect() == 2 + +def test_class(): + class A: + pass + A.a = A + print 'class 0x%x' % id(A) + gc.collect() + del A + assert gc.collect() > 0 + +def test_instance(): + class A: + pass + a = A() + a.a = a + print repr(a) + gc.collect() + del a + assert gc.collect() > 0 + +def test_finalizer(): + class A: + def __del__(self): pass + class B: + pass + a = A() + a.a = a + id_a = id(a) + b = B() + b.b = b + print 'a', repr(a) + print 'b', repr(b) + gc.collect() + gc.garbage[:] = [] + del a + del b + assert gc.collect() > 0 + assert id(gc.garbage[0]) == id_a + +def test_function(): + d = {} + exec("def f(): pass\n") in d + print 'dict 0x%x' % id(d) + print 'func 0x%x' % id(d['f']) + gc.collect() + del d + assert gc.collect() == 2 + + +def test_all(): + debug = gc.get_debug() + gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS) + test_list() + test_dict() + test_tuple() + test_class() + test_instance() + test_finalizer() + test_function() + gc.set_debug(debug) + +test_all() From trentm@activestate.com Mon Jun 5 23:37:20 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 15:37:20 -0700 Subject: [Patches] simple 64-bit fixes in Modules/ dir Message-ID: <20000605153720.A11994@activestate.com> Discussion: This patch is one of a set of five (one per python/dist/src/* directory). They have been broken up to keep the patches small such that people might spend the time to review them. If one single patch would be prefered I can provide that. This patch makes some simple changes for the benefit of 64-bit platforms (to avoid possible overflows where C data types have changed sizes and to eliminate unnecessary warnings). Each change fits into one of the following categories: - Change a local variable declaration from int to size_t where appropriate. This is typically done for variables that hold strlen() or sizeof() results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t avoids a downcast warning (or overflow). The variable is often later downcast to an int anyway but it is (IMO) more appropriate to do the downcast where the downcast is necessary and not before. 32-bit platforms are not affected by this change. - Change (int) casts to (size_t) casts within comparisons where appropriate. This can avoid an unnecessary possible overflow (in somecases) and a warning on 64-bit platforms. - Remove pointer downcasts to (long) for comparison (see Objects/object.c). This is unreliable on Win64 where sizeof(void*) > sizeof(long). - Add a check for int overflow and raise and OverflowError where it cannot be proven a priori that int will not overflow. This is usually associated with string lengths. While it may seem overkill to have a check to ensure that a string does not overflow 2G characters it *is* a potential for silent overflow. - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging output to print a pointer. %ld results in data loss on Win64. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Modules/_localemodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/_localemodule.c Fri Jun 2 15:53:42 2000 *************** *** 281,287 **** PyObject* args; { char *s,*buf; ! int n1,n2; PyObject *result; if(!PyArg_ParseTuple(args,"s:strxfrm",&s)) return NULL; --- 281,287 ---- PyObject* args; { char *s,*buf; ! size_t n1,n2; PyObject *result; if(!PyArg_ParseTuple(args,"s:strxfrm",&s)) return NULL; *** /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c Thu Jun 1 01:38:58 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c Fri Jun 2 15:53:42 2000 *************** *** 1022,1028 **** if (n > 0) { char *item = self->ob_item; int itemsize = self->ob_descr->itemsize; ! int nread; int newlength; size_t newbytes; /* Be careful here about overflow */ --- 1022,1028 ---- if (n > 0) { char *item = self->ob_item; int itemsize = self->ob_descr->itemsize; ! size_t nread; int newlength; size_t newbytes; /* Be careful here about overflow */ *************** *** 1040,1046 **** self->ob_size += n; nread = fread(item + (self->ob_size - n) * itemsize, itemsize, n, fp); ! if (nread < n) { self->ob_size -= (n - nread); PyMem_RESIZE(item, char, self->ob_size*itemsize); self->ob_item = item; --- 1040,1046 ---- self->ob_size += n; nread = fread(item + (self->ob_size - n) * itemsize, itemsize, n, fp); ! if (nread < (size_t)n) { self->ob_size -= (n - nread); PyMem_RESIZE(item, char, self->ob_size*itemsize); self->ob_item = item; *** /home/trentm/main/contrib/python/dist/src/Modules/getpath.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/getpath.c Fri Jun 2 15:53:43 2000 *************** *** 163,169 **** reduce(dir) char *dir; { ! int i = strlen(dir); while (i > 0 && dir[i] != SEP) --i; dir[i] = '\0'; --- 163,169 ---- reduce(dir) char *dir; { ! size_t i = strlen(dir); while (i > 0 && dir[i] != SEP) --i; dir[i] = '\0'; *************** *** 241,247 **** char *buffer; char *stuff; { ! int n, k; if (stuff[0] == SEP) n = 0; else { --- 241,247 ---- char *buffer; char *stuff; { ! size_t n, k; if (stuff[0] == SEP) n = 0; else { *************** *** 262,268 **** char *argv0_path; char *home; { ! int n; char *vpath; /* If PYTHONHOME is set, we believe it unconditionally */ --- 262,268 ---- char *argv0_path; char *home; { ! size_t n; char *vpath; /* If PYTHONHOME is set, we believe it unconditionally */ *************** *** 331,337 **** char *argv0_path; char *home; { ! int n; /* If PYTHONHOME is set, we believe it unconditionally */ if (home) { --- 331,337 ---- char *argv0_path; char *home; { ! size_t n; /* If PYTHONHOME is set, we believe it unconditionally */ if (home) { *************** *** 393,400 **** char argv0_path[MAXPATHLEN+1]; int pfound, efound; /* 1 if found; -1 if found build directory */ char *buf; ! int bufsz; ! int prefixsz; char *defpath = pythonpath; #ifdef WITH_NEXT_FRAMEWORK NSModule pythonModule; --- 393,400 ---- char argv0_path[MAXPATHLEN+1]; int pfound, efound; /* 1 if found; -1 if found build directory */ char *buf; ! size_t bufsz; ! size_t prefixsz; char *defpath = pythonpath; #ifdef WITH_NEXT_FRAMEWORK NSModule pythonModule; *************** *** 429,435 **** char *delim = strchr(path, DELIM); if (delim) { ! int len = delim - path; strncpy(progpath, path, len); *(progpath + len) = '\0'; } --- 429,435 ---- char *delim = strchr(path, DELIM); if (delim) { ! size_t len = delim - path; strncpy(progpath, path, len); *(progpath + len) = '\0'; } *************** *** 557,564 **** } if (delim) { ! int len = delim - defpath + 1; ! int end = strlen(buf) + len; strncat(buf, defpath, len); *(buf + end) = '\0'; } --- 557,564 ---- } if (delim) { ! size_t len = delim - defpath + 1; ! size_t end = strlen(buf) + len; strncat(buf, defpath, len); *(buf + end) = '\0'; } *** /home/trentm/main/contrib/python/dist/src/Modules/mpzmodule.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/mpzmodule.c Fri Jun 2 15:53:43 2000 *************** *** 143,149 **** { mpzobject *mpzp = (mpzobject *)objp; PyStringObject *strobjp; ! int i; int cmpres; int taglong; char *cp; --- 143,149 ---- { mpzobject *mpzp = (mpzobject *)objp; PyStringObject *strobjp; ! size_t i; int cmpres; int taglong; char *cp; *** /home/trentm/main/contrib/python/dist/src/Modules/readline.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/readline.c Fri Jun 2 15:53:43 2000 *************** *** 376,382 **** call_readline(prompt) char *prompt; { ! int n; char *p, *q; RETSIGTYPE (*old_inthandler)(); old_inthandler = signal(SIGINT, onintr); --- 376,382 ---- call_readline(prompt) char *prompt; { ! size_t n; char *p, *q; RETSIGTYPE (*old_inthandler)(); old_inthandler = signal(SIGINT, onintr); *** /home/trentm/main/contrib/python/dist/src/Modules/rotormodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/rotormodule.c Fri Jun 2 15:53:43 2000 *************** *** 147,154 **** char *key; { unsigned long k1=995, k2=576, k3=767, k4=671, k5=463; ! int i; ! int len = strlen(key); for (i = 0; i < len; i++) { unsigned short ki = Py_CHARMASK(key[i]); --- 147,154 ---- char *key; { unsigned long k1=995, k2=576, k3=767, k4=671, k5=463; ! size_t i; ! size_t len = strlen(key); for (i = 0; i < len; i++) { unsigned short ki = Py_CHARMASK(key[i]); *** /home/trentm/main/contrib/python/dist/src/Modules/timemodule.c Thu Jun 1 19:34:28 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/timemodule.c Fri Jun 2 15:53:43 2000 *************** *** 379,387 **** PyObject *tup; struct tm buf; const char *fmt; ! int fmtlen, buflen; char *outbuf = 0; ! int i; memset((ANY *) &buf, '\0', sizeof(buf)); --- 379,387 ---- PyObject *tup; struct tm buf; const char *fmt; ! size_t fmtlen, buflen; char *outbuf = 0; ! size_t i; memset((ANY *) &buf, '\0', sizeof(buf)); -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon Jun 5 23:39:34 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 15:39:34 -0700 Subject: [Patches] simple 64-bit fixes in Objects/ dir Message-ID: <20000605153934.B11994@activestate.com> Discussion: This patch is one of a set of five (one per python/dist/src/* directory). They have been broken up to keep the patches small such that people might spend the time to review them. If one single patch would be prefered I can provide that. This patch makes some simple changes for the benefit of 64-bit platforms (to avoid possible overflows where C data types have changed sizes and to eliminate unnecessary warnings). Each change fits into one of the following categories: - Change a local variable declaration from int to size_t where appropriate. This is typically done for variables that hold strlen() or sizeof() results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t avoids a downcast warning (or overflow). The variable is often later downcast to an int anyway but it is (IMO) more appropriate to do the downcast where the downcast is necessary and not before. 32-bit platforms are not affected by this change. - Change (int) casts to (size_t) casts within comparisons where appropriate. This can avoid an unnecessary possible overflow (in somecases) and a warning on 64-bit platforms. - Remove pointer downcasts to (long) for comparison (see Objects/object.c). This is unreliable on Win64 where sizeof(void*) > sizeof(long). - Add a check for int overflow and raise and OverflowError where it cannot be proven a priori that int will not overflow. This is usually associated with string lengths. While it may seem overkill to have a check to ensure that a string does not overflow 2G characters it *is* a potential for silent overflow. - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging output to print a pointer. %ld results in data loss on Win64. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/classobject.c Fri Jun 2 15:53:43 2000 *************** *** 283,289 **** { if (v == NULL || !PyString_Check(v)) return "__name__ must be a string object"; ! if ((long)strlen(PyString_AS_STRING(v)) != PyString_GET_SIZE(v)) return "__name__ must not contain null bytes"; set_slot(&c->cl_name, v); return ""; --- 283,289 ---- { if (v == NULL || !PyString_Check(v)) return "__name__ must be a string object"; ! if (strlen(PyString_AS_STRING(v)) != (size_t)PyString_GET_SIZE(v)) return "__name__ must not contain null bytes"; set_slot(&c->cl_name, v); return ""; *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/object.c Fri Jun 2 15:53:43 2000 *************** *** 367,373 **** if (pair == NULL) { return NULL; } ! if ((long)v <= (long)w) { PyTuple_SET_ITEM(pair, 0, PyLong_FromVoidPtr((void *)v)); PyTuple_SET_ITEM(pair, 1, PyLong_FromVoidPtr((void *)w)); } else { --- 367,373 ---- if (pair == NULL) { return NULL; } ! if (v <= w) { PyTuple_SET_ITEM(pair, 0, PyLong_FromVoidPtr((void *)v)); PyTuple_SET_ITEM(pair, 1, PyLong_FromVoidPtr((void *)w)); } else { -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon Jun 5 23:40:39 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 15:40:39 -0700 Subject: [Patches] simple 64-bit fixes in Parser/ dir Message-ID: <20000605154039.C11994@activestate.com> Discussion: This patch is one of a set of five (one per python/dist/src/* directory). They have been broken up to keep the patches small such that people might spend the time to review them. If one single patch would be prefered I can provide that. This patch makes some simple changes for the benefit of 64-bit platforms (to avoid possible overflows where C data types have changed sizes and to eliminate unnecessary warnings). Each change fits into one of the following categories: - Change a local variable declaration from int to size_t where appropriate. This is typically done for variables that hold strlen() or sizeof() results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t avoids a downcast warning (or overflow). The variable is often later downcast to an int anyway but it is (IMO) more appropriate to do the downcast where the downcast is necessary and not before. 32-bit platforms are not affected by this change. - Change (int) casts to (size_t) casts within comparisons where appropriate. This can avoid an unnecessary possible overflow (in somecases) and a warning on 64-bit platforms. - Remove pointer downcasts to (long) for comparison (see Objects/object.c). This is unreliable on Win64 where sizeof(void*) > sizeof(long). - Add a check for int overflow and raise and OverflowError where it cannot be proven a priori that int will not overflow. This is usually associated with string lengths. While it may seem overkill to have a check to ensure that a string does not overflow 2G characters it *is* a potential for silent overflow. - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging output to print a pointer. %ld results in data loss on Win64. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Parser/myreadline.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Parser/myreadline.c Fri Jun 2 15:53:44 2000 *************** *** 86,92 **** PyOS_StdioReadline(prompt) char *prompt; { ! int n; char *p; n = 100; if ((p = PyMem_MALLOC(n)) == NULL) --- 86,92 ---- PyOS_StdioReadline(prompt) char *prompt; { ! size_t n; char *p; n = 100; if ((p = PyMem_MALLOC(n)) == NULL) *************** *** 95,101 **** if (prompt) fprintf(stderr, "%s", prompt); fflush(stderr); ! switch (my_fgets(p, n, stdin)) { case 0: /* Normal case */ break; case 1: /* Interrupt */ --- 95,101 ---- if (prompt) fprintf(stderr, "%s", prompt); fflush(stderr); ! switch (my_fgets(p, (int)n, stdin)) { case 0: /* Normal case */ break; case 1: /* Interrupt */ *************** *** 116,126 **** #endif n = strlen(p); while (n > 0 && p[n-1] != '\n') { ! int incr = n+2; p = PyMem_REALLOC(p, n + incr); if (p == NULL) return NULL; ! if (my_fgets(p+n, incr, stdin) != 0) break; n += strlen(p+n); } --- 116,129 ---- #endif n = strlen(p); while (n > 0 && p[n-1] != '\n') { ! size_t incr = n+2; p = PyMem_REALLOC(p, n + incr); if (p == NULL) return NULL; ! if (incr > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, "input line too long"); ! } ! if (my_fgets(p+n, (int)incr, stdin) != 0) break; n += strlen(p+n); } *** /home/trentm/main/contrib/python/dist/src/Parser/parsetok.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Parser/parsetok.c Fri Jun 2 15:53:44 2000 *************** *** 143,149 **** for (;;) { char *a, *b; int type; ! int len; char *str; type = PyTokenizer_Get(tok, &a, &b); --- 143,149 ---- for (;;) { char *a, *b; int type; ! size_t len; char *str; type = PyTokenizer_Get(tok, &a, &b); *************** *** 191,197 **** err_ret->lineno = tok->lineno; err_ret->offset = tok->cur - tok->buf; if (tok->buf != NULL) { ! int len = tok->inp - tok->buf; err_ret->text = PyMem_NEW(char, len + 1); if (err_ret->text != NULL) { if (len > 0) --- 191,197 ---- err_ret->lineno = tok->lineno; err_ret->offset = tok->cur - tok->buf; if (tok->buf != NULL) { ! size_t len = tok->inp - tok->buf; err_ret->text = PyMem_NEW(char, len + 1); if (err_ret->text != NULL) { if (len > 0) *** /home/trentm/main/contrib/python/dist/src/Parser/pgenmain.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Parser/pgenmain.c Fri Jun 2 15:53:44 2000 *************** *** 127,133 **** fprintf(stderr, "Parsing error %d, line %d.\n", err.error, err.lineno); if (err.text != NULL) { ! int i; fprintf(stderr, "%s", err.text); i = strlen(err.text); if (i == 0 || err.text[i-1] != '\n') --- 127,133 ---- fprintf(stderr, "Parsing error %d, line %d.\n", err.error, err.lineno); if (err.text != NULL) { ! size_t i; fprintf(stderr, "%s", err.text); i = strlen(err.text); if (i == 0 || err.text[i-1] != '\n') *************** *** 195,201 **** PyOS_Readline(prompt) char *prompt; { ! int n = 1000; char *p = PyMem_MALLOC(n); char *q; if (p == NULL) --- 195,201 ---- PyOS_Readline(prompt) char *prompt; { ! size_t n = 1000; char *p = PyMem_MALLOC(n); char *q; if (p == NULL) *** /home/trentm/main/contrib/python/dist/src/Parser/tokenizer.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Parser/tokenizer.c Fri Jun 2 15:53:44 2000 *************** *** 223,231 **** tok->done = E_EOF; } else if (tok->start != NULL) { ! int start = tok->start - tok->buf; ! int oldlen = tok->cur - tok->buf; ! int newlen = oldlen + strlen(new); char *buf = tok->buf; PyMem_RESIZE(buf, char, newlen+1); tok->lineno++; --- 223,231 ---- tok->done = E_EOF; } else if (tok->start != NULL) { ! size_t start = tok->start - tok->buf; ! size_t oldlen = tok->cur - tok->buf; ! size_t newlen = oldlen + strlen(new); char *buf = tok->buf; PyMem_RESIZE(buf, char, newlen+1); tok->lineno++; -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon Jun 5 23:41:44 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 15:41:44 -0700 Subject: [Patches] simple 64-bit fixes in PC/ dir Message-ID: <20000605154144.D11994@activestate.com> Discussion: This patch is one of a set of five (one per python/dist/src/* directory). They have been broken up to keep the patches small such that people might spend the time to review them. If one single patch would be prefered I can provide that. This patch makes some simple changes for the benefit of 64-bit platforms (to avoid possible overflows where C data types have changed sizes and to eliminate unnecessary warnings). Each change fits into one of the following categories: - Change a local variable declaration from int to size_t where appropriate. This is typically done for variables that hold strlen() or sizeof() results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t avoids a downcast warning (or overflow). The variable is often later downcast to an int anyway but it is (IMO) more appropriate to do the downcast where the downcast is necessary and not before. 32-bit platforms are not affected by this change. - Change (int) casts to (size_t) casts within comparisons where appropriate. This can avoid an unnecessary possible overflow (in somecases) and a warning on 64-bit platforms. - Remove pointer downcasts to (long) for comparison (see Objects/object.c). This is unreliable on Win64 where sizeof(void*) > sizeof(long). - Add a check for int overflow and raise and OverflowError where it cannot be proven a priori that int will not overflow. This is usually associated with string lengths. While it may seem overkill to have a check to ensure that a string does not overflow 2G characters it *is* a potential for silent overflow. - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging output to print a pointer. %ld results in data loss on Win64. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/PC/getpathp.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/getpathp.c Fri Jun 2 15:53:43 2000 *************** *** 134,140 **** reduce(dir) char *dir; { ! int i = strlen(dir); while (i > 0 && !is_sep(dir[i])) --i; dir[i] = '\0'; --- 134,140 ---- reduce(dir) char *dir; { ! size_t i = strlen(dir); while (i > 0 && !is_sep(dir[i])) --i; dir[i] = '\0'; *************** *** 172,178 **** char *buffer; char *stuff; { ! int n, k; if (is_sep(stuff[0])) n = 0; else { --- 172,178 ---- char *buffer; char *stuff; { ! size_t n, k; if (is_sep(stuff[0])) n = 0; else { *************** *** 207,213 **** char *argv0_path; char *landmark; { - /* Search from argv0_path, until landmark is found */ strcpy(prefix, argv0_path); do { --- 207,212 ---- *************** *** 244,250 **** TCHAR *dataBuf = NULL; static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\"); static const TCHAR keySuffix[] = _T("\\PythonPath"); ! int versionLen; DWORD index; TCHAR *keyBuf = NULL; TCHAR *keyBufPtr; --- 243,249 ---- TCHAR *dataBuf = NULL; static const TCHAR keyPrefix[] = _T("Software\\Python\\PythonCore\\"); static const TCHAR keySuffix[] = _T("\\PythonPath"); ! size_t versionLen; DWORD index; TCHAR *keyBuf = NULL; TCHAR *keyBufPtr; *************** *** 402,408 **** char *delim = strchr(path, DELIM); if (delim) { ! int len = delim - path; strncpy(progpath, path, len); *(progpath + len) = '\0'; } --- 401,407 ---- char *delim = strchr(path, DELIM); if (delim) { ! size_t len = delim - path; strncpy(progpath, path, len); *(progpath + len) = '\0'; } *************** *** 429,435 **** { char argv0_path[MAXPATHLEN+1]; char *buf; ! int bufsz; char *pythonhome = Py_GetPythonHome(); char *envpath = getenv("PYTHONPATH"); --- 428,434 ---- { char argv0_path[MAXPATHLEN+1]; char *buf; ! size_t bufsz; char *pythonhome = Py_GetPythonHome(); char *envpath = getenv("PYTHONPATH"); *************** *** 554,560 **** else { char *p = PYTHONPATH; char *q; ! int n; for (;;) { q = strchr(p, DELIM); if (q == NULL) --- 553,559 ---- else { char *p = PYTHONPATH; char *q; ! size_t n; for (;;) { q = strchr(p, DELIM); if (q == NULL) *** /home/trentm/main/contrib/python/dist/src/PC/import_nt.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/PC/import_nt.c Fri Jun 2 15:53:43 2000 *************** *** 33,39 **** // Calculate the size for the sprintf buffer. // Get the size of the chars only, plus 1 NULL. ! int bufSize = sizeof(keyPrefix)-1 + strlen(PyWin_DLLVersionString) + sizeof(keySuffix) + strlen(moduleName) + sizeof(debugString) - 1; // alloca == no free required, but memory only local to fn, also no heap fragmentation! moduleKey = alloca(bufSize); sprintf(moduleKey, "Software\\Python\\PythonCore\\%s\\Modules\\%s%s", PyWin_DLLVersionString, moduleName, debugString); --- 33,39 ---- // Calculate the size for the sprintf buffer. // Get the size of the chars only, plus 1 NULL. ! size_t bufSize = sizeof(keyPrefix)-1 + strlen(PyWin_DLLVersionString) + sizeof(keySuffix) + strlen(moduleName) + sizeof(debugString) - 1; // alloca == no free required, but memory only local to fn, also no heap fragmentation! moduleKey = alloca(bufSize); sprintf(moduleKey, "Software\\Python\\PythonCore\\%s\\Modules\\%s%s", PyWin_DLLVersionString, moduleName, debugString); *************** *** 44,50 **** return NULL; // use the file extension to locate the type entry. for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { ! int extLen=strlen(fdp->suffix); if (modNameSize>extLen && strnicmp(pathBuf+(modNameSize-extLen-1),fdp->suffix,extLen)==0) break; } --- 44,50 ---- return NULL; // use the file extension to locate the type entry. for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { ! size_t extLen = strlen(fdp->suffix); if (modNameSize>extLen && strnicmp(pathBuf+(modNameSize-extLen-1),fdp->suffix,extLen)==0) break; } -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon Jun 5 23:42:46 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 15:42:46 -0700 Subject: [Patches] simple 64-bit fixes in Python/ dir Message-ID: <20000605154246.E11994@activestate.com> Discussion: This patch is one of a set of five (one per python/dist/src/* directory). They have been broken up to keep the patches small such that people might spend the time to review them. If one single patch would be prefered I can provide that. This patch makes some simple changes for the benefit of 64-bit platforms (to avoid possible overflows where C data types have changed sizes and to eliminate unnecessary warnings). Each change fits into one of the following categories: - Change a local variable declaration from int to size_t where appropriate. This is typically done for variables that hold strlen() or sizeof() results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t avoids a downcast warning (or overflow). The variable is often later downcast to an int anyway but it is (IMO) more appropriate to do the downcast where the downcast is necessary and not before. 32-bit platforms are not affected by this change. - Change (int) casts to (size_t) casts within comparisons where appropriate. This can avoid an unnecessary possible overflow (in somecases) and a warning on 64-bit platforms. - Remove pointer downcasts to (long) for comparison (see Objects/object.c). This is unreliable on Win64 where sizeof(void*) > sizeof(long). - Add a check for int overflow and raise and OverflowError where it cannot be proven a priori that int will not overflow. This is usually associated with string lengths. While it may seem overkill to have a check to ensure that a string does not overflow 2G characters it *is* a potential for silent overflow. - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging output to print a pointer. %ld results in data loss on Win64. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Python/ceval.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/ceval.c Fri Jun 2 15:53:44 2000 *************** *** 2876,2882 **** } else { char *s = PyString_AsString(prog); ! if ((int)strlen(s) != PyString_Size(prog)) { PyErr_SetString(PyExc_ValueError, "embedded '\\0' in exec string"); return -1; --- 2876,2882 ---- } else { char *s = PyString_AsString(prog); ! if (strlen(s) != (size_t)PyString_Size(prog)) { PyErr_SetString(PyExc_ValueError, "embedded '\\0' in exec string"); return -1; *** /home/trentm/main/contrib/python/dist/src/Python/codecs.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/codecs.c Fri Jun 2 15:53:44 2000 *************** *** 83,93 **** PyObject *normalizestring(const char *string) { register int i; ! int len = strlen(string); char *p; PyObject *v; ! v = PyString_FromStringAndSize(NULL, len); if (v == NULL) return NULL; p = PyString_AS_STRING(v); --- 83,98 ---- PyObject *normalizestring(const char *string) { register int i; ! size_t len = strlen(string); char *p; PyObject *v; ! if (len > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, "string is too large"); ! return NULL; ! } ! ! v = PyString_FromStringAndSize(NULL, (int)len); if (v == NULL) return NULL; p = PyString_AS_STRING(v); *** /home/trentm/main/contrib/python/dist/src/Python/compile.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/compile.c Fri Jun 2 15:53:44 2000 *************** *** 265,272 **** if (!PyString_Check(v)) continue; p = PyString_AsString(v); ! if ((int)strspn(p, NAME_CHARS) ! != PyString_Size(v)) continue; PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); } --- 265,272 ---- if (!PyString_Check(v)) continue; p = PyString_AsString(v); ! if (strspn(p, NAME_CHARS) ! != (size_t)PyString_Size(v)) continue; PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); } *************** *** 340,346 **** PyObject *exc; char *msg; { ! int n = strlen(msg); PyObject *v; char buffer[30]; char *s; --- 340,346 ---- PyObject *exc; char *msg; { ! size_t n = strlen(msg); PyObject *v; char buffer[30]; char *s; *************** *** 720,731 **** struct compiling *c; char *name; char *buffer; ! int maxlen; { /* Name mangling: __private becomes _classname__private. This is independent from how the name is used. */ char *p; ! int nlen, plen; nlen = strlen(name); if (nlen+2 >= maxlen) return 0; /* Don't mangle __extremely_long_names */ --- 720,731 ---- struct compiling *c; char *name; char *buffer; ! size_t maxlen; { /* Name mangling: __private becomes _classname__private. This is independent from how the name is used. */ char *p; ! size_t nlen, plen; nlen = strlen(name); if (nlen+2 >= maxlen) return 0; /* Don't mangle __extremely_long_names */ *************** *** 761,767 **** char buffer[256]; if (name != NULL && name[0] == '_' && name[1] == '_' && c->c_private != NULL && ! com_mangle(c, name, buffer, (int)sizeof(buffer))) name = buffer; #endif if (name == NULL || (v = PyString_InternFromString(name)) == NULL) { --- 761,767 ---- char buffer[256]; if (name != NULL && name[0] == '_' && name[1] == '_' && c->c_private != NULL && ! com_mangle(c, name, buffer, sizeof(buffer))) name = buffer; #endif if (name == NULL || (v = PyString_InternFromString(name)) == NULL) { *************** *** 883,889 **** char *s; { PyObject *v; ! int len; char *buf; char *p; char *end; --- 883,889 ---- char *s; { PyObject *v; ! size_t len; char *buf; char *p; char *end; *************** *** 908,913 **** --- 908,917 ---- } s++; len = strlen(s); + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "string to parse is too long"); + return NULL; + } if (s[--len] != quote) { PyErr_BadInternalCall(); return NULL; *************** *** 2201,2207 **** char buffer[256]; if (s != NULL && s[0] == '_' && s[1] == '_' && c->c_private != NULL && ! com_mangle(c, s, buffer, (int)sizeof(buffer))) s = buffer; #endif if (PyDict_GetItemString(c->c_locals, s) != NULL) { --- 2205,2211 ---- char buffer[256]; if (s != NULL && s[0] == '_' && s[1] == '_' && c->c_private != NULL && ! com_mangle(c, s, buffer, sizeof(buffer))) s = buffer; #endif if (PyDict_GetItemString(c->c_locals, s) != NULL) { *** /home/trentm/main/contrib/python/dist/src/Python/dynload_win.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/dynload_win.c Fri Jun 2 15:53:44 2000 *************** *** 104,110 **** "DLL load failed with error code %d", errorCode); } else { ! int len; /* For some reason a \r\n is appended to the text */ if (theLength >= 2 && --- 104,110 ---- "DLL load failed with error code %d", errorCode); } else { ! size_t len; /* For some reason a \r\n is appended to the text */ if (theLength >= 2 && *** /home/trentm/main/contrib/python/dist/src/Python/getcwd.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/getcwd.c Fri Jun 2 15:53:44 2000 *************** *** 62,68 **** return NULL; } ret = getwd(localbuf); ! if (ret != NULL && strlen(localbuf) >= size) { errno = ERANGE; return NULL; } --- 62,68 ---- return NULL; } ret = getwd(localbuf); ! if (ret != NULL && strlen(localbuf) >= (size_t)size) { errno = ERANGE; return NULL; } *** /home/trentm/main/contrib/python/dist/src/Python/modsupport.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/modsupport.c Fri Jun 2 15:53:44 2000 *************** *** 355,362 **** Py_INCREF(v); } else { ! if (n < 0) ! n = strlen(str); v = PyString_FromStringAndSize(str, n); } return v; --- 355,369 ---- Py_INCREF(v); } else { ! if (n < 0) { ! size_t m = strlen(str); ! if (m > INT_MAX) { ! PyErr_SetString(PyExc_OverflowError, ! "string too long for Python string"); ! return NULL; ! } ! n = (int)m; ! } v = PyString_FromStringAndSize(str, n); } return v; *** /home/trentm/main/contrib/python/dist/src/Python/sysmodule.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/sysmodule.c Fri Jun 2 15:53:44 2000 *************** *** 491,497 **** Py_XDECREF(v); #ifdef MS_COREDLL PyDict_SetItemString(sysdict, "dllhandle", ! v = PyInt_FromLong((int)PyWin_DLLhModule)); Py_XDECREF(v); PyDict_SetItemString(sysdict, "winver", v = PyString_FromString(PyWin_DLLVersionString)); --- 491,497 ---- Py_XDECREF(v); #ifdef MS_COREDLL PyDict_SetItemString(sysdict, "dllhandle", ! v = PyLong_FromVoidPtr(PyWin_DLLhModule)); Py_XDECREF(v); PyDict_SetItemString(sysdict, "winver", v = PyString_FromString(PyWin_DLLVersionString)); *** /home/trentm/main/contrib/python/dist/src/Python/thread_nt.h Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/thread_nt.h Fri Jun 2 15:53:44 2000 *************** *** 101,106 **** --- 101,109 ---- return mutex->hevent != NULL ; /* TRUE if the mutex is created */ } + #ifdef InterlockedCompareExchange + #undef InterlockedCompareExchange + #endif #define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand))) VOID DeleteNonRecursiveMutex(PNRMUTEX mutex) *************** *** 179,185 **** */ int PyThread_start_new_thread(void (*func)(void *), void *arg) { ! long rv; int success = 0; dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); --- 182,188 ---- */ int PyThread_start_new_thread(void (*func)(void *), void *arg) { ! INT_PTR rv; int success = 0; dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); *************** *** 190,196 **** if (rv != -1) { success = 1; ! dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), rv)); } return success; --- 193,199 ---- if (rv != -1) { success = 1; ! dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", PyThread_get_thread_ident(), rv)); } return success; *** /home/trentm/main/contrib/python/dist/src/Python/traceback.c Thu Jun 1 00:13:40 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Python/traceback.c Fri Jun 2 15:53:44 2000 *************** *** 166,172 **** path = PySys_GetObject("path"); if (path != NULL && PyList_Check(path)) { int npath = PyList_Size(path); ! int taillen = strlen(tail); char namebuf[MAXPATHLEN+1]; for (i = 0; i < npath; i++) { PyObject *v = PyList_GetItem(path, i); --- 166,172 ---- path = PySys_GetObject("path"); if (path != NULL && PyList_Check(path)) { int npath = PyList_Size(path); ! size_t taillen = strlen(tail); char namebuf[MAXPATHLEN+1]; for (i = 0; i < npath; i++) { PyObject *v = PyList_GetItem(path, i); *************** *** 175,186 **** break; } if (PyString_Check(v)) { ! int len; len = PyString_Size(v); if (len + 1 + taillen >= MAXPATHLEN) continue; /* Too long */ strcpy(namebuf, PyString_AsString(v)); ! if ((int)strlen(namebuf) != len) continue; /* v contains '\0' */ if (len > 0 && namebuf[len-1] != SEP) namebuf[len++] = SEP; --- 175,186 ---- break; } if (PyString_Check(v)) { ! size_t len; len = PyString_Size(v); if (len + 1 + taillen >= MAXPATHLEN) continue; /* Too long */ strcpy(namebuf, PyString_AsString(v)); ! if (strlen(namebuf) != len) continue; /* v contains '\0' */ if (len > 0 && namebuf[len-1] != SEP) namebuf[len++] = SEP; -- Trent Mick trentm@activestate.com From mal@lemburg.com Mon Jun 5 23:56:37 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 06 Jun 2000 00:56:37 +0200 Subject: [Patches] simple 64-bit fixes in Objects/ dir References: <20000605153934.B11994@activestate.com> Message-ID: <393C3025.6446A5A0@lemburg.com> > This patch makes some simple changes for the benefit of 64-bit platforms (to > avoid possible overflows where C data types have changed sizes and to > eliminate unnecessary warnings). Each change fits into one of the following > categories: > > - Change a local variable declaration from int to size_t where appropriate. > This is typically done for variables that hold strlen() or sizeof() > results. On 64-bit platforms sizeof(int) < sizeof(size_t), so using size_t > avoids a downcast warning (or overflow). The variable is often later > downcast to an int anyway but it is (IMO) more appropriate to do the > downcast where the downcast is necessary and not before. 32-bit platforms > are not affected by this change. > - Change (int) casts to (size_t) casts within comparisons where appropriate. > This can avoid an unnecessary possible overflow (in somecases) and a > warning on 64-bit platforms. > - Remove pointer downcasts to (long) for comparison (see Objects/object.c). > This is unreliable on Win64 where sizeof(void*) > sizeof(long). > - Add a check for int overflow and raise and OverflowError where it cannot be > proven a priori that int will not overflow. This is usually associated with > string lengths. While it may seem overkill to have a check to ensure that a > string does not overflow 2G characters it *is* a potential for silent > overflow. > - [Python/thread_nt.c] Use %p instead of %ld printf formatter for debugging > output to print a pointer. %ld results in data loss on Win64. Trent, do you have some kind of web page on this ? I think it would be useful for extension package writers to have such a list of things to watch out for handy -- I do for sure, as I'm very keen on getting my mx Extensions to work on 64-bit platforms too. If it's not a web-page, a flat file for Misc/ would be fine as well -- something like Misc/porting-to-64bit.txt Thanks, -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From trentm@activestate.com Tue Jun 6 00:02:49 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 16:02:49 -0700 Subject: [Patches] simple 64-bit fixes in Objects/ dir In-Reply-To: <393C3025.6446A5A0@lemburg.com> References: <20000605153934.B11994@activestate.com> <393C3025.6446A5A0@lemburg.com> Message-ID: <20000605160249.F11994@activestate.com> On Tue, Jun 06, 2000 at 12:56:37AM +0200, M . -A . Lemburg wrote: > If it's not a web-page, a flat file for Misc/ would be > fine as well -- something like Misc/porting-to-64bit.txt No, I don't currently have a web page for porting information/pointers. I'm am just polishing off of all this though. I will try to slap together such a file for inclusion in Misc. Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Tue Jun 6 00:25:49 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 16:25:49 -0700 Subject: [Patches] fix cPickle.c for 64-bit platforms (mainly Win64) Message-ID: <20000605162549.A12671@activestate.com> Discussion: This patch fixes cPickle.c for 64-bit platforms. - The false assumption sizeof(long) == size(void*) exists where PyInt_FromLong is used to represent a pointer. The safe Python call for this is PyLong_FromVoidPtr. (On platforms where the above assumption *is* true a PyInt is returned as before so there is no effective change.) - use size_t instead of int for some varaibles Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Modules/cPickle.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/cPickle.c Fri Jun 2 15:53:42 2000 *************** *** 656,662 **** PyObject *value, *mv; long c_value; char s[30]; ! int len; UNLESS (mv = PyDict_GetItem(self->memo, id)) { PyErr_SetObject(PyExc_KeyError, id); --- 656,662 ---- PyObject *value, *mv; long c_value; char s[30]; ! size_t len; UNLESS (mv = PyDict_GetItem(self->memo, id)) { PyErr_SetObject(PyExc_KeyError, id); *************** *** 717,723 **** static int put2(Picklerobject *self, PyObject *ob) { char c_str[30]; ! int p, len, res = -1; PyObject *py_ob_id = 0, *memo_len = 0, *t = 0; if (self->fast) return 0; --- 717,725 ---- static int put2(Picklerobject *self, PyObject *ob) { char c_str[30]; ! int p; ! size_t len; ! int res = -1; PyObject *py_ob_id = 0, *memo_len = 0, *t = 0; if (self->fast) return 0; *************** *** 727,733 **** p++; /* Make sure memo keys are positive! */ ! UNLESS (py_ob_id = PyInt_FromLong((long)ob)) goto finally; UNLESS (memo_len = PyInt_FromLong(p)) --- 729,735 ---- p++; /* Make sure memo keys are positive! */ ! UNLESS (py_ob_id = PyLong_FromVoidPtr(ob)) goto finally; UNLESS (memo_len = PyInt_FromLong(p)) *************** *** 1255,1261 **** goto finally; } ! UNLESS (py_tuple_id = PyInt_FromLong((long)args)) goto finally; if (len) { --- 1257,1263 ---- goto finally; } ! UNLESS (py_tuple_id = PyLong_FromVoidPtr(args)) goto finally; if (len) { *************** *** 1775,1786 **** } if (args->ob_refcnt > 1) { - long ob_id; int has_key; ! ob_id = (long)args; ! ! UNLESS (py_ob_id = PyInt_FromLong(ob_id)) goto finally; if ((has_key = cPickle_PyMapping_HasKey(self->memo, py_ob_id)) < 0) --- 1777,1785 ---- } if (args->ob_refcnt > 1) { int has_key; ! UNLESS (py_ob_id = PyLong_FromVoidPtr(args)) goto finally; if ((has_key = cPickle_PyMapping_HasKey(self->memo, py_ob_id)) < 0) -- Trent Mick trentm@activestate.com From trentm@activestate.com Tue Jun 6 01:29:39 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 17:29:39 -0700 Subject: [Patches] small bug in posixmodule.c Message-ID: <20000605172939.A22183@activestate.com> Discussion: Fix a small bug in posixmodule.c where a char* is being dereferenced where it should not be. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Modules/posixmodule.c Thu Jun 1 19:19:27 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/posixmodule.c Mon Jun 5 17:20:54 2000 *************** *** 930,936 **** if (FindClose(hFindFile) == FALSE) { errno = GetLastError(); ! return posix_error_with_filename(&name); } return d; --- 929,935 ---- if (FindClose(hFindFile) == FALSE) { errno = GetLastError(); ! return posix_error_with_filename(name); } return d; -- Trent Mick trentm@activestate.com From trentm@activestate.com Tue Jun 6 01:37:02 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 17:37:02 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c Message-ID: <20000605173702.B22183@activestate.com> Discussion: A couple leftover patches of mine that I found lurking around. This patch fixes a couple of warnings for 64-bit platforms. - Though I know that SIG_DFL and SIG_IGN are just small constants, there are cast to function pointers so the appropriate Python call is PyLong_FromVoidPtr so that the pointer value cannot overflow on Win64 where sizeof(long) < sizeof(void*). - Fix a compiler warning by casting the NULL value used in the _PyBuffer_FromMemory call to PyObject*. Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Modules/signalmodule.c Thu Jun 1 00:13:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/signalmodule.c Fri Jun 2 15:53:43 2000 *************** *** 356,366 **** /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); ! x = DefaultHandler = PyInt_FromLong((long)SIG_DFL); if (!x || PyDict_SetItemString(d, "SIG_DFL", x) < 0) goto finally; ! x = IgnoreHandler = PyInt_FromLong((long)SIG_IGN); if (!x || PyDict_SetItemString(d, "SIG_IGN", x) < 0) goto finally; --- 356,366 ---- /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); ! x = DefaultHandler = PyLong_FromVoidPtr(SIG_DFL); if (!x || PyDict_SetItemString(d, "SIG_DFL", x) < 0) goto finally; ! x = IgnoreHandler = PyLong_FromVoidPtr(SIG_IGN); if (!x || PyDict_SetItemString(d, "SIG_IGN", x) < 0) goto finally; *** /home/trentm/main/contrib/python/dist/src/Objects/bufferobject.c Fri Jun 2 11:21:14 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/bufferobject.c Fri Jun 2 15:53:43 2000 *************** *** 166,172 **** void *ptr; int size; { ! return _PyBuffer_FromMemory(NULL, ptr, size, 1); } PyObject * --- 166,172 ---- void *ptr; int size; { ! return _PyBuffer_FromMemory((PyObject*)NULL, ptr, size, 1); } PyObject * *************** *** 174,180 **** void *ptr; int size; { ! return _PyBuffer_FromMemory(NULL, ptr, size, 0); } PyObject * --- 174,180 ---- void *ptr; int size; { ! return _PyBuffer_FromMemory((PyObject*)NULL, ptr, size, 0); } PyObject * -- Trent Mick trentm@activestate.com From gstein@lyra.org Tue Jun 6 01:46:31 2000 From: gstein@lyra.org (Greg Stein) Date: Mon, 5 Jun 2000 17:46:31 -0700 (PDT) Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000605173702.B22183@activestate.com> Message-ID: These casts should not be required. NULL is "all types" ... why the cast? Cheers, -g On Mon, 5 Jun 2000, Trent Mick wrote: >... > *** /home/trentm/main/contrib/python/dist/src/Objects/bufferobject.c Fri Jun 2 11:21:14 2000 > --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/bufferobject.c Fri Jun 2 15:53:43 2000 > *************** > *** 166,172 **** > void *ptr; > int size; > { > ! return _PyBuffer_FromMemory(NULL, ptr, size, 1); > } > > PyObject * > --- 166,172 ---- > void *ptr; > int size; > { > ! return _PyBuffer_FromMemory((PyObject*)NULL, ptr, size, 1); > } > > PyObject * > *************** > *** 174,180 **** > void *ptr; > int size; > { > ! return _PyBuffer_FromMemory(NULL, ptr, size, 0); > } > > PyObject * > --- 174,180 ---- > void *ptr; > int size; > { > ! return _PyBuffer_FromMemory((PyObject*)NULL, ptr, size, 0); > } > > PyObject * > > > -- > Trent Mick > trentm@activestate.com > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches > -- Greg Stein, http://www.lyra.org/ From nascheme@enme.ucalgary.ca Tue Jun 6 02:22:34 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Mon, 5 Jun 2000 19:22:34 -0600 Subject: [Patches] GC with support for PyMethodObjects Message-ID: <20000605192234.A1498@acs.ucalgary.ca> I have added GC support for PyMethodObjects. As always, the latest patch (lightly tested) is at: http://www.enme.ucalgary.ca/~nascheme/python/gc-cycle.diff It is fairly easy to create a reference cycle using method objects: >>> class A: ... def __init__(self): ... self.init = self.__init__ ... >>> A() <__main__.A instance at 81cb66c> >>> 1 1 >>> import gc >>> gc.collect() gc: collectable gc: collectable gc: collectable 3 I was suprised when this change revealed that Jeremy's compiler leaks memory. This can easily be demonstrated by putting the compile.py main() function in a "while 1" loop. Without GC the process size keeps growing. I wonder how many other programs contain similar leaks. Neil -- fortune: Segmentation fault (core dumped) From tim_one@email.msn.com Tue Jun 6 02:30:33 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 5 Jun 2000 21:30:33 -0400 Subject: [Patches] simple 64-bit fixes in Python/ dir In-Reply-To: <20000605154246.E11994@activestate.com> Message-ID: <000f01bfcf56$ced89220$0ca0143f@tim> [posted & mailed] [Trent Mick] > ... > On 64-bit platforms sizeof(int) < sizeof(size_t), so > using size_t avoids a downcast warning (or overflow). I suppose we should be more careful about explaining the need for these changes. For example, the claim above isn't true, as there are 64-bit platforms where sizeof(int) == sizeof(size_t) too (the Cray J90 is one such platform Python kind of runs on today, and indeed even shorts are 64 bits on that one). The problems here are that Python implicitly assumes sizeof(int) == sizeof(size_t), because at the time Python was written size_t didn't exist and the long K&R tradition preceding ANSI C was that strlen returned an int-sized thing and malloc took one. So they're all in the nature of cleaning up after the C committee a decade later . From trentm@activestate.com Tue Jun 6 02:46:42 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 18:46:42 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: References: <20000605173702.B22183@activestate.com> Message-ID: <20000605184642.A25131@activestate.com> On Mon, Jun 05, 2000 at 05:46:31PM -0700, Greg Stein wrote: > These casts should not be required. NULL is "all types" ... why the cast? > > Cheers, > -g > > > *** /home/trentm/main/contrib/python/dist/src/Objects/bufferobject.c Fri Jun 2 11:21:14 2000 > > --- /home/trentm/main/Apps/Perlium/Python/dist/src/Objects/bufferobject.c Fri Jun 2 15:53:43 2000 > > *************** > > *** 166,172 **** > > void *ptr; > > int size; > > { > > ! return _PyBuffer_FromMemory(NULL, ptr, size, 1); > > } > > > > PyObject * > > --- 166,172 ---- > > void *ptr; > > int size; > > { > > ! return _PyBuffer_FromMemory((PyObject*)NULL, ptr, size, 1); > > } > > > > PyObject * Intel's Win64 compiler output: "c:\ia64xdevsdk\bin\Intel64\ecl.exe" -nologo -W3 -GX -Fp".\ia64-temp-release\python16\python16.pch" -YX -Zi -Fd".\ia64-temp-release\python16\\" -Fo".\ia64-temp-release\python16\\" -DWIN32 -Wp64 -Ap64 -DWIN64 -D_WIN64 -FD -c -Od -MD -DNDEBUG -Ic:\ia64xdevsdk\include -Ic:\ia64xdevsdk\include\sys -Ic:\ia64xdevsdk\include\gl -Ic:\ia64xdevsdk\include\mfc -Ic:\ia64xdevsdk\include\atl\include -DDEBUGGING -I"..\Include" -I"..\PC" -DUSE_DL_EXPORT -D_WINDOWS ..\Objects\bufferobject.c bufferobject.c ..\Objects\bufferobject.c(169) : warning #180: argument is incompatible with formal parameter return _PyBuffer_FromMemory(NULL, ptr, size, 1); ^ Adding the cast to a PyObject* gets rid of the warning. Perhaps I am overreacting to an innocuous warning? Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Tue Jun 6 03:00:14 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 19:00:14 -0700 Subject: [Patches] simple 64-bit fixes in Python/ dir In-Reply-To: <000f01bfcf56$ced89220$0ca0143f@tim> References: <20000605154246.E11994@activestate.com> <000f01bfcf56$ced89220$0ca0143f@tim> Message-ID: <20000605190014.A25171@activestate.com> On Mon, Jun 05, 2000 at 09:30:33PM -0400, Tim Peters wrote: > [posted & mailed] > > [Trent Mick] > > ... > > On 64-bit platforms sizeof(int) < sizeof(size_t), so > > using size_t avoids a downcast warning (or overflow). > > I suppose we should be more careful about explaining the need for these > changes. For example, the claim above isn't true, as there are 64-bit > platforms where sizeof(int) == sizeof(size_t) too (the Cray J90 is one such > platform Python kind of runs on today, and indeed even shorts are 64 > bits on that one). > > The problems here are that Python implicitly assumes sizeof(int) == > sizeof(size_t), because at the time Python was written size_t didn't exist > and the long K&R tradition preceding ANSI C was that strlen returned an > int-sized thing and malloc took one. So they're all in the nature of > cleaning up after the C committee a decade later . > Okay, yes, I was being lazy and partially ignorant. Trent -- Trent Mick trentm@activestate.com From tim_one@email.msn.com Tue Jun 6 03:18:08 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 5 Jun 2000 22:18:08 -0400 Subject: [Patches] simple 64-bit fixes in Python/ dir In-Reply-To: <20000605190014.A25171@activestate.com> Message-ID: <001701bfcf5d$75324480$0ca0143f@tim> [Trent Mick] > Okay, yes, I was being lazy and partially ignorant. Well, if you're not yet 40, of *course* you're partially ignorant, but I'd never ever accuse you of being lazy . I surely appreciate all the good work you're doing here! At the same time, I want everyone to realize that the 64-bit world isn't equal to Win84, and we've got to watch out for all *sorts* of stuff (for example, a bit of the code in longobject.c is broken on the 64-bit Cray J90 in ways that aren't broken under Win64; for example, the J90 has the only C compiler I've ever heard of where right shifts of signed integral types do *not* extend the sign bit -- which is fine by ANSI, but catches some of Python's internals by surprise). the-opposite-of-partial-ignorance-is-total-tedium<0.6-wink>-ly y'rs - tim From tim_one@email.msn.com Tue Jun 6 03:49:36 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 5 Jun 2000 22:49:36 -0400 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000605184642.A25131@activestate.com> Message-ID: <001801bfcf61$dac3b6e0$0ca0143f@tim> [Trent Mick] > ... > Intel's Win64 compiler output: > > > "c:\ia64xdevsdk\bin\Intel64\ecl.exe" -nologo -W3 -GX > -Fp".\ia64-temp-release\python16\python16.pch" -YX -Zi > -Fd".\ia64-temp-release\python16\\" > -Fo".\ia64-temp-release\python16\\" -DWIN32 -Wp64 -Ap64 -DWIN64 > -D_WIN64 -FD -c -Od -MD -DNDEBUG -Ic:\ia64xdevsdk\include > -Ic:\ia64xdevsdk\include\sys -Ic:\ia64xdevsdk\include\gl > -Ic:\ia64xdevsdk\include\mfc -Ic:\ia64xdevsdk\include\atl\include > -DDEBUGGING -I"..\Include" -I"..\PC" -DUSE_DL_EXPORT -D_WINDOWS > ..\Objects\bufferobject.c > bufferobject.c > ..\Objects\bufferobject.c(169) : warning #180: argument is > incompatible with formal parameter > return _PyBuffer_FromMemory(NULL, ptr, size, 1); > ^ > > Adding the cast to a PyObject* gets rid of the warning. Perhaps I am > overreacting to an innocuous warning? NO! Not possible to overreact. Python should compile warning-free on every platform it gets built on. Sometimes that will require catering to crippled compilers, but tough luck. The invariable alternative is that warnings get ignored, and the invariable outcome of that is that serious portability bugs go uncaught. More, if I have anything to say about it (and I suspect I will before too long ), the warning level will get cranked tighter on compiles, and "treat warnings as fatal errors" will get enabled. This tedious infrastructure work pays off bigtime over time. [GregS] > These casts should not be required. NULL is "all types" ... why the cast? It could be that the K&R-style declaration of _PyBuffer_FromMemory does not convince this compiler that _PyBuffer_FromMemory has an explicit prototype in scope at the point of call. Trent could try playing with that too. But in any case, "no warnings!" is an excellent rule. From fdrake@beopen.com Tue Jun 6 03:58:25 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Mon, 5 Jun 2000 22:58:25 -0400 (EDT) Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000605184642.A25131@activestate.com> References: <20000605173702.B22183@activestate.com> <20000605184642.A25131@activestate.com> Message-ID: <14652.26833.613337.268731@cj42289-a.reston1.va.home.com> Trent Mick writes: > ..\Objects\bufferobject.c(169) : warning #180: argument is incompatible with formal parameter > return _PyBuffer_FromMemory(NULL, ptr, size, 1); > ^ > > Adding the cast to a PyObject* gets rid of the warning. Perhaps I am > overreacting to an innocuous warning? I think the cast is appropriate simply because of this. I seem to recall seeing some compilers defining NULL as ((void *) 0), so this doesn't seem completely unreasonable. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From trentm@activestate.com Tue Jun 6 04:07:29 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 5 Jun 2000 20:07:29 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <001801bfcf61$dac3b6e0$0ca0143f@tim> References: <20000605184642.A25131@activestate.com> <001801bfcf61$dac3b6e0$0ca0143f@tim> Message-ID: <20000605200729.C25437@activestate.com> On Mon, Jun 05, 2000 at 10:49:36PM -0400, Tim Peters wrote: > [Trent Mick] > > ... > > Intel's Win64 compiler output: > > > > > > "c:\ia64xdevsdk\bin\Intel64\ecl.exe" -nologo -W3 -GX > > -Fp".\ia64-temp-release\python16\python16.pch" -YX -Zi > > -Fd".\ia64-temp-release\python16\\" > > -Fo".\ia64-temp-release\python16\\" -DWIN32 -Wp64 -Ap64 -DWIN64 > > -D_WIN64 -FD -c -Od -MD -DNDEBUG -Ic:\ia64xdevsdk\include > > -Ic:\ia64xdevsdk\include\sys -Ic:\ia64xdevsdk\include\gl > > -Ic:\ia64xdevsdk\include\mfc -Ic:\ia64xdevsdk\include\atl\include > > -DDEBUGGING -I"..\Include" -I"..\PC" -DUSE_DL_EXPORT -D_WINDOWS > > ..\Objects\bufferobject.c > > bufferobject.c > > ..\Objects\bufferobject.c(169) : warning #180: argument is > > incompatible with formal parameter > > return _PyBuffer_FromMemory(NULL, ptr, size, 1); > > ^ > > > > Adding the cast to a PyObject* gets rid of the warning. Perhaps I am > > overreacting to an innocuous warning? > > NO! Not possible to overreact. Python should compile warning-free on every > platform it gets built on. Sometimes that will require catering to crippled > compilers, but tough luck. The invariable alternative is that warnings get > ignored, and the invariable outcome of that is that serious portability bugs > go uncaught. More, if I have anything to say about it (and I suspect I will > before too long ), the warning level will get cranked tighter on > compiles, and "treat warnings as fatal errors" will get enabled. This > tedious infrastructure work pays off bigtime over time. There are a whole schwack of warnings that I am ignoring on the Win64 build. Basically I went through every one and, through code analysis, decided if it could be ignored or not. These were mostly warnings of downcasts, for example int size = sizeof(Py_UNICODE); Which is *not* going to overflow but still generates a warning. > > [GregS] > > These casts should not be required. NULL is "all types" ... why the cast? > > It could be that the K&R-style declaration of _PyBuffer_FromMemory does not > convince this compiler that _PyBuffer_FromMemory has an explicit prototype > in scope at the point of call. Trent could try playing with that too. i Give the man a prize. That was it. We'll just forget that part of the patch then and thank you Tim for changing all function declarations from K&R to ANSI. :) Trent -- Trent Mick trentm@activestate.com From gstein@lyra.org Tue Jun 6 04:22:13 2000 From: gstein@lyra.org (Greg Stein) Date: Mon, 5 Jun 2000 20:22:13 -0700 (PDT) Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <001801bfcf61$dac3b6e0$0ca0143f@tim> Message-ID: On Mon, 5 Jun 2000, Tim Peters wrote: >... > NO! Not possible to overreact. Python should compile warning-free on every > platform it gets built on. Sometimes that will require catering to crippled > compilers, but tough luck. The invariable alternative is that warnings get > ignored, and the invariable outcome of that is that serious portability bugs > go uncaught. More, if I have anything to say about it (and I suspect I will > before too long ), the warning level will get cranked tighter on > compiles, and "treat warnings as fatal errors" will get enabled. This > tedious infrastructure work pays off bigtime over time. Agreed, and I also support the notion of extended checks and "die-on-warning" flags. Heck... I just ran "lint" over mod_dav the other day. Hehe... [ check out "lclint"; found via Freshmeat ] > [GregS] > > These casts should not be required. NULL is "all types" ... why the cast? > > It could be that the K&R-style declaration of _PyBuffer_FromMemory does not > convince this compiler that _PyBuffer_FromMemory has an explicit prototype > in scope at the point of call. Trent could try playing with that too. But > in any case, "no warnings!" is an excellent rule. Yes, this was it, and moving to ANSI decls will help in a lot of cases. My issue was mostly based around seeing a *cast*. IMO, the presence of a cast means that something else is wrong. The cast is going to hide *that*, which can be even worse than trying to get a warning-free compile. In this case, the cast was hiding the K&R declaration. A month or so ago, I was pointing out problems with some casts in a patch to the new mmapmodule.c. Sure enough, the variables were just declared improperly. Removing warnings: Goodness. Using casts: (typically) Badness. Cheers, -g p.s. casts are best used to create a more specific type (PyStringObject*) from a (PyObject*), or (whatever*) from a (void*). -- Greg Stein, http://www.lyra.org/ From Moshe Zadka Tue Jun 6 07:04:22 2000 From: Moshe Zadka (Moshe Zadka) Date: Tue, 6 Jun 2000 09:04:22 +0300 (IDT) Subject: [Patches] small bug in posixmodule.c In-Reply-To: <20000605172939.A22183@activestate.com> Message-ID: On Mon, 5 Jun 2000, Trent Mick wrote: > Fix a small bug in posixmodule.c where a char* is being dereferenced where it > should not be. +1. Obviously a bug -- which some C++ compilers would choke on. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From mwh21@cam.ac.uk Tue Jun 6 17:30:57 2000 From: mwh21@cam.ac.uk (Michael Hudson) Date: Tue, 6 Jun 2000 17:30:57 +0100 (BST) Subject: [Patches] list/tuple error consistency Message-ID: After Skip's pointing out that my error message for listobject.c:list_concat was bogus, it was changed; this TOLP changes tupleboject.c to be consistent. Cheers, Michael I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Index: Objects/tupleobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/tupleobject.c,v retrieving revision 2.34 diff -u -r2.34 tupleobject.c --- Objects/tupleobject.c 2000/06/01 03:12:13 2.34 +++ Objects/tupleobject.c 2000/06/06 16:30:39 @@ -362,7 +362,7 @@ PyTupleObject *np; if (!PyTuple_Check(bb)) { PyErr_Format(PyExc_TypeError, - "can only append tuple (not \"%.200s\") to tuple", + "can only concatenate tuple (not \"%.200s\") to tuple", bb->ob_type->tp_name); return NULL; } From tim_one@email.msn.com Tue Jun 6 20:09:19 2000 From: tim_one@email.msn.com (Tim Peters) Date: Tue, 6 Jun 2000 15:09:19 -0400 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000605200729.C25437@activestate.com> Message-ID: <001c01bfcfea$b73a2040$48a2143f@tim> [Tim, rants about warnings] [Trent Mick] > There are a whole schwack of warnings that I am ignoring on > the Win64 build. Basically I went through every one and, through > code analysis, decided if it could be ignored or not. And all of those you decided to ignore will appear forever more in the Win64 build, and everyone who comes after you (including you, 3 months from now <0.5 wink>) will see them every time they build, so no later than the 3rd build will stop looking at warnings entirely, and after that new and dangerous warnings in new or changed code will simply get overlooked along with the masses of old warnings. That's fine for a project that never leaves your machine, but, sorry, it's simply exceedingly bad practice for group maintainability. > These were mostly warnings of downcasts, for example > > int size = sizeof(Py_UNICODE); > > Which is *not* going to overflow but still generates a warning. The "proper" fix here is to change the decl to size_t. If keeping the decl "int" is important, then the warning is thoroughly appropriate! Casting sizeof's result to int is a bad but expedient wormaround. Defining a SAFE_DOWNCAST macro (that checks that the downcast doesn't lose info in DEBUG mode, and does the downcast without checking in non-DEBUG mode) is a better (but still sucky) wormaround. C is simply a pain in the ass here. [on K&R style declarations failing to act as prototypes] > ... > Give the man a prize. That was it. We'll just forget that part of the > patch then and thank you Tim for changing all function declarations > from K&R to ANSI. :) Believe it or not, I do intend to do that, although I expect resistance from Guido <0.5 wink>. Python's infrastructure is creaking from age, and an update to ANSI C is l-o-n-g overdue. It appears to me that a very large part of your "Win64" efforts have amounted to fighting long-obsolete K&R C assumptions! From trentm@activestate.com Tue Jun 6 20:18:11 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 6 Jun 2000 12:18:11 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <001c01bfcfea$b73a2040$48a2143f@tim> References: <20000605200729.C25437@activestate.com> <001c01bfcfea$b73a2040$48a2143f@tim> Message-ID: <20000606121811.E28943@activestate.com> On Tue, Jun 06, 2000 at 03:09:19PM -0400, Tim Peters wrote: > [Tim, rants about warnings] > > [Trent Mick] > > There are a whole schwack of warnings that I am ignoring on > > the Win64 build. Basically I went through every one and, through > > code analysis, decided if it could be ignored or not. > > And all of those you decided to ignore will appear forever more in the Win64 > build, and everyone who comes after you (including you, 3 months from now > <0.5 wink>) will see them every time they build, so no later than the 3rd > build will stop looking at warnings entirely, and after that new and > dangerous warnings in new or changed code will simply get overlooked along > with the masses of old warnings. That's fine for a project that never > leaves your machine, but, sorry, it's simply exceedingly bad practice for > group maintainability. The problem is that I don't know *how* to properly express to the compiler that this is not a problem. My hope (I acknowledge that it is a hope and not a guarantee) is that those warnings will be cleaned up when I or someelse know how to express this to the compiler. > > > These were mostly warnings of downcasts, for example > > > > int size = sizeof(Py_UNICODE); > > > > Which is *not* going to overflow but still generates a warning. > > The "proper" fix here is to change the decl to size_t. Yes, you are right, but... > If keeping the decl > "int" is important, then the warning is thoroughly appropriate! Casting > sizeof's result to int is a bad but expedient wormaround. Defining a > SAFE_DOWNCAST macro (that checks that the downcast doesn't lose info in > DEBUG mode, and does the downcast without checking in non-DEBUG mode) is a > better (but still sucky) wormaround. C is simply a pain in the ass here. > *Is* there a way to express that the downcast is safe that is not sucky? Trent -- Trent Mick trentm@activestate.com From gstein@lyra.org Tue Jun 6 20:38:57 2000 From: gstein@lyra.org (Greg Stein) Date: Tue, 6 Jun 2000 12:38:57 -0700 (PDT) Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000606121811.E28943@activestate.com> Message-ID: On Tue, 6 Jun 2000, Trent Mick wrote: >... > > If keeping the decl > > "int" is important, then the warning is thoroughly appropriate! Casting > > sizeof's result to int is a bad but expedient wormaround. Defining a > > SAFE_DOWNCAST macro (that checks that the downcast doesn't lose info in > > DEBUG mode, and does the downcast without checking in non-DEBUG mode) is a > > better (but still sucky) wormaround. C is simply a pain in the ass here. > > > > *Is* there a way to express that the downcast is safe that is not sucky? I think that Tim means something like the following: #ifdef DEBUG # define SAFE_DOWNCAST(v) ((v) <= INT_MAX ? (int)(v) : abort()) #else # define SAFE_DOWNCAST(v) ((int)(v)) #endif My INT_MAX check probably isn't right, but this might be what he is getting at. Of course, you would also need other variants for different downcasts. IMO, you *really* should not need to downcast all that often. I see it when I/O occurs (to fit something into a specific size), but type/size mismatches are usually indicative of design/specification errors. IMO #2, you should not tell the compiler to ignore certain warnings/errors (e.g. using pragmas). That is the worst scenario of all. That hides things even worse than a cast. Cheers, -g -- Greg Stein, http://www.lyra.org/ From mwh21@cam.ac.uk Tue Jun 6 21:20:20 2000 From: mwh21@cam.ac.uk (Michael Hudson) Date: Tue, 6 Jun 2000 21:20:20 +0100 (BST) Subject: [Patches] better errors for __getattr__/__repr__ confusion Message-ID: In response to a posting by Fran=E7ois Pinard in comp.lang.python, I cooked up this patch: Index: classobject.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v retrieving revision 2.86 diff -u -r2.86 classobject.c --- classobject.c=092000/05/03 23:44:34=092.86 +++ classobject.c=092000/06/06 20:06:24 @@ -766,6 +766,10 @@ =09=09return PyString_FromString(buf); =09} =09res =3D PyEval_CallObject(func, (PyObject *)NULL); +=09if (res =3D=3D NULL && !PyCallable_Check(func)) { +=09=09PyErr_SetString(PyExc_TypeError, +=09 "lookup for '__repr__' returned an uncallable object"); +=09} =09Py_DECREF(func); =09return res; } Index: object.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.70 diff -u -r2.70 object.c --- object.c=092000/05/03 23:44:35=092.70 +++ object.c=092000/06/06 20:06:24 @@ -290,6 +290,10 @@ =09=09=09return PyObject_Repr(v); =09=09} =09=09res =3D PyEval_CallObject(func, (PyObject *)NULL); +=09=09if (res =3D=3D NULL && !PyCallable_Check(func)) { +=09=09=09PyErr_SetString(PyExc_TypeError, +=09=09 "lookup for '__str__' returned an uncallable object"); +=09=09} =09=09Py_DECREF(func); =09} =09if (res =3D=3D NULL) This means that: [mwh21@atrus build]$ cat s.py=20 class See: def __getattr__(self, key): print '**', key return None print See() [mwh21@atrus build]$ ./python s.py ** __str__ Traceback (most recent call last): File "s.py", line 7, in ? print See() TypeError: lookup for '__str__' returned an uncallable object I'm not wholly convinced that this error is common enough to justify checking for it explicitly, but I've structured things so that (I hope!) there shouldn't be a penalty for code that currently works. Anyway, I thought I'd send it in and see what you lot think of it... Cheers, M. Oh, almost forgot: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. From trentm@activestate.com Tue Jun 6 21:32:28 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 6 Jun 2000 13:32:28 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: References: <20000606121811.E28943@activestate.com> Message-ID: <20000606133228.B5165@activestate.com> On Tue, Jun 06, 2000 at 12:38:57PM -0700, Greg Stein wrote: > On Tue, 6 Jun 2000, Trent Mick wrote: > >... > > > If keeping the decl > > > "int" is important, then the warning is thoroughly appropriate! Casting > > > sizeof's result to int is a bad but expedient wormaround. Defining a > > > SAFE_DOWNCAST macro (that checks that the downcast doesn't lose info in > > > DEBUG mode, and does the downcast without checking in non-DEBUG mode) is a > > > better (but still sucky) wormaround. C is simply a pain in the ass here. > > > > > > > *Is* there a way to express that the downcast is safe that is not sucky? > > I think that Tim means something like the following: > > #ifdef DEBUG > # define SAFE_DOWNCAST(v) ((v) <= INT_MAX ? (int)(v) : abort()) > #else > # define SAFE_DOWNCAST(v) ((int)(v)) > #endif > > My INT_MAX check probably isn't right, but this might be what he is > getting at. Of course, you would also need other variants for different > downcasts. Sure, but then my compiler will still generate a warning on the int downcast that you have there, hence still filling the compile output with junk. > > > IMO, you *really* should not need to downcast all that often. I see it > when I/O occurs (to fit something into a specific size), but type/size > mismatches are usually indicative of design/specification errors. > Right. The main "design error" is in Include/object.h: #define PyObject_VAR_HEAD \ PyObject_HEAD \ int ob_size; /* Number of items in variable part */ This is 'int' where it should be 'size_t'. We all agree. But this is not going to chagne for Python 1.6 (maybe not until 2.0 or 3000). Yes, hopefully all these warnings will then go away and clean up the Win64 build. Good enough Tim? Yes, I presume that there is a "right" answer to fix most of these warnings. It is just that the "right" answer is going to have to wait for a little bit. Until then the Win64 build is going to have gobs of downcast warnings. > IMO #2, you should not tell the compiler to ignore certain > warnings/errors (e.g. using pragmas). That is the worst scenario of all. > That hides things even worse than a cast. Agreeably yours, Trent -- Trent Mick trentm@activestate.com From tim_one@email.msn.com Tue Jun 6 22:00:36 2000 From: tim_one@email.msn.com (Tim Peters) Date: Tue, 6 Jun 2000 17:00:36 -0400 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000606121811.E28943@activestate.com> Message-ID: <002001bfcffa$431b4ee0$48a2143f@tim> [Trent Mick] > ... > The problem is that I don't know *how* to properly express to the compiler > that this is not a problem. Yes you do : change the code so that size_t-valued expressions only get assigned to size_t-declared lvalues. Anything short of that is potentially unsafe (that's why the compiler is warning!), and, like I said, C is a pain in the ass here. > ... > *Is* there a way to express that the downcast is safe that is not sucky? Really not that I know of. You can do some nice tricks with templates in C++, but I know of no reasonable way to write portable code in C that doesn't involve a layer of typedefs and macros. I have to spend the next 4 hours packing boxes, but Greg was on to the flavor of a workable idea. The "is the downcast safe?" test is better expressed not relying on limits.h, like /* DEBUG branch only here */ #define SAFE_DOWNCAST(EXPR, INT_TYPE) \ (INT_TYPE)(EXPR) == (EXPR) ? \ (INT_TYPE)(EXPR) : \ complainBitterly(yadda, yadda, yadda) This is prone to all the problems that come with C's macros, but so it goes. An alternative: /* DEBUG branch only here */ #define SAFE_DOWNCAST(EXPR, INT_TYPE) \ downcaster_ ## INT_TYPE ((WIDEST_INT_TYPE)(EXPR), \ filename and linenumber, etc) That is, use the token-pasting operator to synthesize the name of a type-specific downcasting function. Then EXPR gets evaluated only once, and at least there's a function name to stick a debugger hook on. All in all, better to avoid the need for downcasting at the root! From tim_one@email.msn.com Tue Jun 6 22:00:38 2000 From: tim_one@email.msn.com (Tim Peters) Date: Tue, 6 Jun 2000 17:00:38 -0400 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.cand bufferobject.c In-Reply-To: Message-ID: <002101bfcffa$4458b0e0$48a2143f@tim> [Greg Stein] > ... > IMO #2, you should not tell the compiler to ignore certain > warnings/errors (e.g. using pragmas). That is the worst > scenario of all. That hides things even worse than a cast. Unfortunately, it eventually becomes necessary, as e.g. if you tighten the warnings you can't include MS's own headers without getting a slew of warnings. In C++ it's much worse, as you start getting "warnings" about stuff like functions not getting inlined, or constant expressions in template expansions (often the whole *point* of a template class is to get constant expressions abstracted away!). Etc. But, in general, I heartily agree. From jack@oratrix.nl Tue Jun 6 22:14:10 2000 From: jack@oratrix.nl (Jack Jansen) Date: Tue, 06 Jun 2000 23:14:10 +0200 Subject: Trying again: [Patches] Patch to import.c Message-ID: <20000606211416.10B6ED8397@oratrix.oratrix.nl> --boogadaboogadabooga Content-Type: text/plain; charset="us-ascii" Folks, I posted this message to the patches mailing list last week, but either I missed the reply (we had full disks over the weekend) or nobody replied yet. And I am waiting for these patches, or rather other people who want to play with MacPython and MacOSX are, so I'd really like to know whether I should revise the patches and in what direction or have them checked in.... Hmm, that may all sound a bit pushy, but that isn't the intention. I really just want to know (a) what the status of my patches is and (b) what I can expect in the future.... Jack --boogadaboogadabooga Content-Type: message/rfc822 From jack@oratrix.nl Sat Jun 3 13: 06:03 2000 Delivered-To: jack@oratrix.nl Received: by oratrix.oratrix.nl (Postfix, from userid 201) id 63987D7210; Sat, 3 Jun 2000 13:06:02 +0200 (MET DST) Received: from localhost (localhost [127.0.0.1]) by oratrix.oratrix.nl (Postfix) with ESMTP id 3EED619B1E9A; Sat, 3 Jun 2000 13:05:57 +0200 (MET DST) To: patches@python.org Cc: jack@oratrix.nl Subject: Re: [Patches] Patch to import.c In-Reply-To: Message by Greg Stein , Sat, 3 Jun 2000 03:26:25 -0700 (PDT) , Organisation: Oratrix Development, Valeriusplein 30, 1075 BJ Amsterdam, NL Phone: +31 20 6795452(work), +31 20 6795309 (fax), +31 20 6160335(home) X-Last-Band-Seen: Stiff Little Fingers (Melkweg, 4-5) X-Mini-Review: Absolutely brilliant!!! Date: Sat, 03 Jun 2000 13:05:57 +0200 From: Jack Jansen Return-Path: Message-Id: <20000603110602.63987D7210@oratrix.oratrix.nl> I'm a bit confused as to the current procedure for patches. It used to be that Guido said "yes" or "no", and that was it. Nowadays there seem to be very many people on the patches mailing list, and a patch gets a number of replies ranging from "don't do this" to "can't you do this differently". I've tried to reply to all the issues, but I'm now completely in the dark as to the status of my patches: I'm under the impression that I've defended the case for my patches satisfactorily (hehe:-), but people on the patch mailing list may think that I've some fixing up to do. As I didn't follow discussions on the new patch system: is there a procedure and, if so, could it be documented on python.org/patches? And if there isn't one: could one be designed and documented, please? A time-limit on patch acceptance/rejection would also be nice, if possible: I use the repository to sync my home machine and work machine, which worked fine when Guido alone was responsible as he worked what seems to be 19 hours per day, so patches usually ended up in the repository before I had the chance to cycle from home to work or vv., but with the new procedure it can apparently take a lot longer for patches to appear, so I may have to come up with another scheme to sync my multiple machines... -- Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++ Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++ www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm --boogadaboogadabooga-- From tim_one@email.msn.com Tue Jun 6 22:21:38 2000 From: tim_one@email.msn.com (Tim Peters) Date: Tue, 6 Jun 2000 17:21:38 -0400 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <20000606133228.B5165@activestate.com> Message-ID: <002201bfcffd$3386a1c0$48a2143f@tim> [GregS] > ... > # define SAFE_DOWNCAST(v) ((v) <= INT_MAX ? (int)(v) : abort()) [Trent Mick] > Sure, but then my compiler will still generate a warning on the > int downcast that you have there, hence still filling the compile > output with junk. Will it really? Greg has no *implicit* downcasts in that code, and I'm skeptical that your compiler generates a warning on *explicit* downcasts (the Win32 MS compiler certainly doesn't). That would be very unusual. > ... > Right. The main "design error" is in Include/object.h: > > #define PyObject_VAR_HEAD \ > PyObject_HEAD \ > int ob_size; /* Number of items in variable part */ > > > This is 'int' where it should be 'size_t'. We all agree. But this is > not going to chagne for Python 1.6 (maybe not until 2.0 or 3000). > Yes, hopefully all these warnings will then go away and clean up the > Win64 build. Good enough Tim? Your original example was > int size = sizeof(Py_UNICODE); and changing PyObject_VAR_HEAD will have no effect on that (i.e., that warning will never go away until that specific line of code is changed). > Yes, I presume that there is a "right" answer to fix most of > these warnings. It is just that the "right" answer is going to > have to wait for a little bit. It doesn't "have to". Python *may* decide to limit sizes to int-sized things forever (there's not much *practical* need to expand ob_size -- it would just be "nice" to do so), and so long as it does the code is screwed up the way it is now. > Until then the Win64 build is going to have gobs of downcast warnings. Which is bad. You didn't create the problem, and nobody is going to force you to fix it. Let's just agree that it *is* "a problem". Then we can make progress. it's-not-personal-ly y'rs - tim From trentm@activestate.com Tue Jun 6 22:46:10 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 6 Jun 2000 14:46:10 -0700 Subject: [Patches] fix simple 64-bit warnings/errors in signalmodule.c and bufferobject.c In-Reply-To: <002201bfcffd$3386a1c0$48a2143f@tim> References: <20000606133228.B5165@activestate.com> <002201bfcffd$3386a1c0$48a2143f@tim> Message-ID: <20000606144610.B5788@activestate.com> On Tue, Jun 06, 2000 at 05:21:38PM -0400, Tim Peters wrote: > [GregS] > > ... > > # define SAFE_DOWNCAST(v) ((v) <= INT_MAX ? (int)(v) : abort()) > > [Trent Mick] > > Sure, but then my compiler will still generate a warning on the > > int downcast that you have there, hence still filling the compile > > output with junk. > > Will it really? Greg has no *implicit* downcasts in that code, and I'm > skeptical that your compiler generates a warning on *explicit* downcasts > (the Win32 MS compiler certainly doesn't). That would be very unusual. > my test code (_testmodule.c): -------------------------------------------- #define SAFE_DOWNCAST(v) ((v) <= INT_MAX ? (int)(v) : abort(),0) PyObject* some_function(PyObject *self, PyObject *args) { size_t hello = 1234; int ihello = SAFE_DOWNCAST(hello); } ------------------------------------- Compiler output: ------------------------------------- "c:\ia64xdevsdk\bin\Intel64\ecl.exe" -nologo -W3 -GX -Fp".\ia64-temp-re lease\_test\_test.pch" -YX -Zi -Fd".\ia64-temp-release\_test\\" -Fo".\ia64-temp- release\_test\\" -DWIN32 -Wp64 -Ap64 -DWIN64 -D_WIN64 -FD -c -Od -MD -DNDEBUG -Ic:\ia64xdevsdk\include -Ic:\ia64xdevsdk\include\sys -Ic:\ia64xdevsdk\include\g l -Ic:\ia64xdevsdk\include\mfc -Ic:\ia64xdevsdk\include\atl\include -DDEBUGGING -I"..\Include" -I"..\PC" -I"C:\Program Files\Tcl\include" -D_WINDOWS ..\Module s\_testmodule.c _testmodule.c ..\Modules\_testmodule.c(30) : warning #810: conversion from "unsigned __int64" to "int" may lose significant bits int ihello = SAFE_DOWNCAST(hello); ------------------------------------- ^ ANswer: Yes it *still* complains about the explicit downcast. You think it should not? I don't know if it should. Ideally I should be able to pick and choose my classes of warnings. > Your original example was > > > int size = sizeof(Py_UNICODE); > > and changing PyObject_VAR_HEAD will have no effect on that (i.e., that > warning will never go away until that specific line of code is changed). Yes, I am mixing examples. The one above was fabricated but and is usually tied, later in the code, to a Python string which really is the ob_size issue that I mentioned. > > > Yes, I presume that there is a "right" answer to fix most of > > these warnings. It is just that the "right" answer is going to > > have to wait for a little bit. > > It doesn't "have to". Python *may* decide to limit sizes to int-sized > things forever (there's not much *practical* need to expand ob_size -- it > would just be "nice" to do so), and so long as it does the code is screwed > up the way it is now. > I can't argue with that. Although the change would be practical for *me* given the work I have been doing. :) And it *would* be practical, in a sense, for developpers if it cleaned up a bunch of warnings and/or code with SAFE_DOWNCAST macros all over the place. > > Until then the Win64 build is going to have gobs of downcast warnings. > > Which is bad. You didn't create the problem, and nobody is going to force > you to fix it. Let's just agree that it *is* "a problem". Then we can make > progress. > Yes, I agree it *is* a problem. Trent -- Trent Mick trentm@activestate.com From gward@mems-exchange.org Wed Jun 7 15:27:24 2000 From: gward@mems-exchange.org (Greg Ward) Date: Wed, 7 Jun 2000 10:27:24 -0400 Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: ; from htw7192@htw-dresden.de on Fri, Jun 02, 2000 at 07:51:06PM +0200 References: Message-ID: <20000607102724.E5559@ludwig.cnri.reston.va.us> On 02 June 2000, Rene Liebscher said: > I want to provide a patch which makes it possible > to use the Gnu Win32 compilers (cygwin and mingw32) > to build extensions. Thanks! Comments follow. > --- python.patched/dist/src/Include/Python.h Tue May 30 10:24:40 2000 [...] > + /* The next are used by the Gnu C-compilers on Win32, for all others > + they will be defined as empty */ > + /* Definition of every type, variables of which may be imported from DLL, > + must be wrapped in DL_CLASSIMPORT_BEG/DL_CLASSIMPORT_END brackets */ > + #ifndef DL_CLASSIMPORT_BEG > + #define DL_CLASSIMPORT_BEG > + #endif > + #ifndef DL_CLASSIMPORT_END > + #define DL_CLASSIMPORT_END > + #endif OK, that seems simple enough. > --- python.patched/dist/src/Include/object.h Tue May 30 10:34:33 2000 [...] > --- 107,120 ---- > PyObject_HEAD \ > int ob_size; /* Number of items in variable part */ > > ! typedef DL_CLASSIMPORT_BEG struct _object { > PyObject_HEAD > ! } DL_CLASSIMPORT_END PyObject; > > > + typedef DL_CLASSIMPORT_BEG struct { > + PyObject_VAR_HEAD > + } DL_CLASSIMPORT_END PyVarObject; This strikes me as really weird style. Do those macros really *have* to be wormed into the typedefs in that way? Isn't there a cleaner way to do it? And do these macros have to be used in extensions as well? Eg. if foo.c supplies an extension foo, so is compiled/linked to foo.pyd (a DLL in disguise), do I have to scatter foo.c with DL_CLASSIMPORT_{BEG,END} tags to make it compile with Cygwin? Looks like the rest of the patch is just shoving DL_CLASSIMPORT_{BEG,END} down Python.h's throat, and then a simple addition to config.h. Except for the extreme uglitude of those CLASSIMPORT macros, it seems straightforward enough. Greg -- Greg Ward - software developer gward@mems-exchange.org MEMS Exchange / CNRI voice: +1-703-262-5376 Reston, Virginia, USA fax: +1-703-262-5367 From trentm@activestate.com Wed Jun 7 17:11:53 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 7 Jun 2000 09:11:53 -0700 Subject: [Patches] New sys method to return total reference count in debug builds. In-Reply-To: References: Message-ID: <20000607091153.C26694@activestate.com> On Mon, Jun 05, 2000 at 09:18:30AM +1000, Mark Hammond wrote: > + #ifdef Py_TRACE_REFS > + static PyObject * > + sys_gettotalrefcount(PyObject *self, PyObject *args) > + { > + extern long _Py_RefTotal; > + if (!PyArg_ParseTuple(args, ":gettotalrefcount")) > + return NULL; > + return PyInt_FromLong((long) _Py_RefTotal); > + } I would just drop the (long) cast. It is not necessary and just adds a potential truncation if _Py_RefTotal is ever changed to size_t or something like that. Otherwise, +0. Trent -- Trent Mick trentm@activestate.com From Fredrik Lundh" This is a multi-part message in MIME format. ------=_NextPart_000_000C_01BFD0D1.F2B120A0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable this patch brings the CVS version of SRE in sync with the latest public snapshot. ------=_NextPart_000_000C_01BFD0D1.F2B120A0 Content-Type: application/octet-stream; name="sre-patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="sre-patch" =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sre_parse.py,v retrieving revision 1.3 diff -u -r1.3 sre_parse.py --- dist/src/Lib/sre_parse.py 2000/04/10 17:10:48 1.3 +++ dist/src/Lib/sre_parse.py 2000/06/07 20:35:31 @@ -1,10 +1,8 @@ # # Secret Labs' Regular Expression Engine -# $Id: sre_parse.py,v 1.3 2000/04/10 17:10:48 guido Exp $ +# $Id$ # -# convert re-style regular expression to SRE template. the current -# implementation is somewhat incomplete, and not very fast. should -# definitely be rewritten before Python 1.6 goes beta. +# convert re-style regular expression to sre pattern # # Copyright (c) 1998-2000 by Secret Labs AB. All rights reserved. # @@ -16,13 +14,16 @@ # other compatibility work. # -# FIXME: comments marked with the FIXME tag are open issues. all such -# issues should be closed before the final beta. - import string, sys +import _sre + from sre_constants import * +# FIXME: should be 65535, but the array module currently chokes on +# unsigned integers larger than 32767... +MAXREPEAT = int(2L**(_sre.getcodesize()*8-1))-1 + SPECIAL_CHARS = ".\\[{()*+?^$|" REPEAT_CHARS = "*+?{" @@ -32,6 +33,8 @@ OCTDIGITS = tuple("01234567") HEXDIGITS = tuple("0123456789abcdefABCDEF") +WHITESPACE = tuple(string.whitespace) + ESCAPES = { "\\a": (LITERAL, chr(7)), "\\b": (LITERAL, chr(8)), @@ -55,10 +58,18 @@ "\\Z": (AT, AT_END), # end of string } -class Pattern: - # FIXME: rename class, and store flags in here too! +FLAGS = { + "i": SRE_FLAG_IGNORECASE, + "L": SRE_FLAG_LOCALE, + "m": SRE_FLAG_MULTILINE, + "s": SRE_FLAG_DOTALL, + "t": SRE_FLAG_TEMPLATE, + "x": SRE_FLAG_VERBOSE, +} + +class State: def __init__(self): - self.flags = [] + self.flags = 0 self.groups = 1 self.groupdict = {} def getgroup(self, name=None): @@ -67,9 +78,6 @@ if name: self.groupdict[name] = gid return gid - def setflag(self, flag): - if flag in self.flags: - self.flags.append(flag) class SubPattern: # a subpattern, in intermediate form @@ -78,7 +86,6 @@ if not data: data = [] self.data = data - self.flags = [] self.width = None def __repr__(self): return repr(self.data) @@ -121,8 +128,8 @@ hi = hi + j elif op in (MIN_REPEAT, MAX_REPEAT): i, j = av[2].getwidth() - lo = lo + i * av[0] - hi = hi + j * av[1] + lo = lo + long(i) * av[0] + hi = hi + long(j) * av[1] elif op in (ANY, RANGE, IN, LITERAL, NOT_LITERAL, CATEGORY): lo = lo + 1 hi = hi + 1 @@ -130,47 +137,23 @@ break self.width = int(min(lo, sys.maxint)), int(min(hi, sys.maxint)) return self.width - def set(self, flag): - if not flag in self.flags: - self.flags.append(flag) - def reset(self, flag): - if flag in self.flags: - self.flags.remove(flag) class Tokenizer: def __init__(self, string): - self.string = list(string) + self.index = 0 + self.string = string self.next = self.__next() def __next(self): - if not self.string: + if self.index >= len(self.string): return None - char = self.string[0] + char = self.string[self.index] if char[0] == "\\": try: - c = self.string[1] + c = self.string[self.index + 1] except IndexError: raise SyntaxError, "bogus escape" char = char + c - try: - if c == "x": - # hexadecimal constant - for i in xrange(2, sys.maxint): - c = self.string[i] - if str(c) not in HEXDIGITS: - break - char = char + c - elif str(c) in DIGITS: - # decimal (or octal) number - for i in xrange(2, sys.maxint): - c = self.string[i] - # FIXME: if larger than current number of - # groups, interpret as an octal number - if str(c) not in DIGITS: - break - char = char + c - except IndexError: - pass # use what we've got this far - del self.string[0:len(char)] + self.index = self.index + len(char) return char def match(self, char): if char == self.next: @@ -187,46 +170,87 @@ self.next = self.__next() return this -def _fixescape(escape, character_class=0): - # convert escape to (type, value) - if character_class: - # inside a character class, we'll look in the character - # escapes dictionary first - code = ESCAPES.get(escape) - if code: - return code - code = CATEGORIES.get(escape) - else: - code = CATEGORIES.get(escape) - if code: - return code - code = ESCAPES.get(escape) +def _group(escape, state): + # check if the escape string represents a valid group + try: + group = int(escape[1:]) + if group and group < state.groups: + return group + except ValueError: + pass + return None # not a valid group + +def _class_escape(source, escape): + # handle escape code inside character class + code = ESCAPES.get(escape) + if code: + return code + code = CATEGORIES.get(escape) + if code: + return code + try: + if escape[1:2] == "x": + while source.next in HEXDIGITS: + escape = escape + source.get() + escape = escape[2:] + # FIXME: support unicode characters! + return LITERAL, chr(int(escape[-4:], 16) & 0xff) + elif str(escape[1:2]) in OCTDIGITS: + while source.next in OCTDIGITS: + escape = escape + source.get() + escape = escape[1:] + # FIXME: support unicode characters! + return LITERAL, chr(int(escape[-6:], 8) & 0xff) + if len(escape) == 2: + return LITERAL, escape[1] + except ValueError: + pass + raise SyntaxError, "bogus escape: %s" % repr(escape) + +def _escape(source, escape, state): + # handle escape code in expression + code = CATEGORIES.get(escape) + if code: + return code + code = ESCAPES.get(escape) if code: return code - if not character_class: - try: - group = int(escape[1:]) - # FIXME: only valid if group <= current number of groups - return GROUP, group - except ValueError: - pass try: if escape[1:2] == "x": + while source.next in HEXDIGITS: + escape = escape + source.get() escape = escape[2:] - return LITERAL, chr(int(escape[-2:], 16) & 0xff) + # FIXME: support unicode characters! + return LITERAL, chr(int(escape[-4:], 16) & 0xff) elif str(escape[1:2]) in DIGITS: - return LITERAL, chr(int(escape[1:], 8) & 0xff) - elif len(escape) == 2: + while 1: + group = _group(escape, state) + if group: + if (not source.next or + not _group(escape + source.next, state)): + return GROUP, group + escape = escape + source.get() + elif source.next in OCTDIGITS: + escape = escape + source.get() + else: + break + escape = escape[1:] + # FIXME: support unicode characters! + return LITERAL, chr(int(escape[-6:], 8) & 0xff) + if len(escape) == 2: return LITERAL, escape[1] except ValueError: pass raise SyntaxError, "bogus escape: %s" % repr(escape) -def _branch(subpattern, items): +def _branch(pattern, items): + # form a branch operator from a set of items (FIXME: move this # optimization to the compiler module!) + subpattern = SubPattern(pattern) + # check if all items share a common prefix while 1: prefix = None @@ -257,17 +281,16 @@ for item in items: set.append(item[0]) subpattern.append((IN, set)) - return + return subpattern subpattern.append((BRANCH, (None, items))) + return subpattern -def _parse(source, pattern, flags=()): +def _parse(source, state, flags=0): # parse regular expression pattern into an operator list. - - subpattern = SubPattern(pattern) - this = None + subpattern = SubPattern(state) while 1: @@ -277,6 +300,17 @@ if this is None: break # end of pattern + if state.flags & SRE_FLAG_VERBOSE: + # skip whitespace and comments + if this in WHITESPACE: + continue + if this == "#": + while 1: + this = source.get() + if this in (None, "\n"): + break + continue + if this and this[0] not in SPECIAL_CHARS: subpattern.append((LITERAL, this)) @@ -294,7 +328,7 @@ if this == "]" and set != start: break elif this and this[0] == "\\": - code1 = _fixescape(this, 1) + code1 = _class_escape(source, this) elif this: code1 = LITERAL, this else: @@ -308,7 +342,7 @@ break else: if this[0] == "\\": - code2 = _fixescape(this, 1) + code2 = _class_escape(source, this) else: code2 = LITERAL, this if code1[0] != LITERAL or code2[0] != LITERAL: @@ -321,7 +355,7 @@ code1 = code1[1][0] set.append(code1) - # FIXME: move set optimization to support function + # FIXME: move set optimization to compiler! if len(set)==1 and set[0][0] is LITERAL: subpattern.append(set[0]) # optimization elif len(set)==2 and set[0][0] is NEGATE and set[1][0] is LITERAL: @@ -335,11 +369,11 @@ if this == "?": min, max = 0, 1 elif this == "*": - min, max = 0, sys.maxint + min, max = 0, MAXREPEAT elif this == "+": - min, max = 1, sys.maxint + min, max = 1, MAXREPEAT elif this == "{": - min, max = 0, sys.maxint + min, max = 0, MAXREPEAT lo = hi = "" while str(source.next) in DIGITS: lo = lo + source.get() @@ -358,20 +392,18 @@ else: raise SyntaxError, "not supported" # figure out which item to repeat - # FIXME: should back up to the right mark, right? if subpattern: - index = len(subpattern)-1 - while subpattern[index][0] is MARK: - index = index - 1 - item = subpattern[index:index+1] + item = subpattern[-1:] else: raise SyntaxError, "nothing to repeat" if source.match("?"): - subpattern[index] = (MIN_REPEAT, (min, max, item)) + subpattern[-1] = (MIN_REPEAT, (min, max, item)) else: - subpattern[index] = (MAX_REPEAT, (min, max, item)) + subpattern[-1] = (MAX_REPEAT, (min, max, item)) + elif this == ".": subpattern.append((ANY, None)) + elif this == "(": group = 1 name = None @@ -379,28 +411,41 @@ group = 0 # options if source.match("P"): - # named group: skip forward to end of name + # python extensions if source.match("<"): + # named group: skip forward to end of name name = "" while 1: char = source.get() - if char is None or char == ">": + if char is None: + raise SyntaxError, "unterminated name" + if char == ">": break + # FIXME: check for valid character name = name + char group = 1 + elif source.match("="): + # named backreference + raise SyntaxError, "not yet implemented" + + else: + char = source.get() + if char is None: + raise SyntaxError, "unexpected end of pattern" + raise SyntaxError, "unknown specifier: ?P%s" % char elif source.match(":"): # non-capturing group group = 2 - elif source.match_set("iI"): - pattern.setflag("i") - elif source.match_set("lL"): - pattern.setflag("l") - elif source.match_set("mM"): - pattern.setflag("m") - elif source.match_set("sS"): - pattern.setflag("s") - elif source.match_set("xX"): - pattern.setflag("x") + elif source.match("#"): + # comment + while 1: + char = source.get() + if char is None or char == ")": + break + else: + # flags + while FLAGS.has_key(source.next): + state.flags = state.flags | FLAGS[source.get()] if group: # parse group contents b = [] @@ -408,30 +453,25 @@ # anonymous group group = None else: - group = pattern.getgroup(name) - if group: - subpattern.append((MARK, (group-1)*2)) + group = state.getgroup(name) while 1: - p = _parse(source, pattern, flags) + p = _parse(source, state, flags) if source.match(")"): if b: b.append(p) - _branch(subpattern, b) - else: - subpattern.append((SUBPATTERN, (group, p))) + p = _branch(state, b) + subpattern.append((SUBPATTERN, (group, p))) break elif source.match("|"): b.append(p) else: raise SyntaxError, "group not properly closed" - if group: - subpattern.append((MARK, (group-1)*2+1)) else: - # FIXME: should this really be a while loop? while 1: char = source.get() if char is None or char == ")": break + # FIXME: skip characters? elif this == "^": subpattern.append((AT, AT_BEGINNING)) @@ -440,7 +480,7 @@ subpattern.append((AT, AT_END)) elif this and this[0] == "\\": - code =_fixescape(this) + code = _escape(source, this, state) subpattern.append(code) else: @@ -448,13 +488,14 @@ return subpattern -def parse(source, flags=()): - s = Tokenizer(source) - g = Pattern() +def parse(pattern, flags=0): + # parse 're' pattern into list of (opcode, argument) tuples + source = Tokenizer(pattern) + state = State() b = [] while 1: - p = _parse(s, g, flags) - tail = s.get() + p = _parse(source, state, flags) + tail = source.get() if tail == "|": b.append(p) elif tail == ")": @@ -462,11 +503,30 @@ elif tail is None: if b: b.append(p) - p = SubPattern(g) - _branch(p, b) + p = _branch(state, b) break else: raise SyntaxError, "bogus characters at end of regular expression" + return p + +def parse_replacement(source, pattern): + # parse 're' replacement string into list of literals and + # group references + s = Tokenizer(source) + p = [] + a = p.append + while 1: + this = s.get() + if this is None: + break # end of replacement string + if this and this[0] == "\\": + try: + a(LITERAL, ESCAPES[this]) + except KeyError: + for char in this: + a(LITERAL, char) + else: + a(LITERAL, this) return p if __name__ == "__main__": =================================================================== ------=_NextPart_000_000C_01BFD0D1.F2B120A0-- From gstein@lyra.org Wed Jun 7 22:24:54 2000 From: gstein@lyra.org (Greg Stein) Date: Wed, 7 Jun 2000 14:24:54 -0700 Subject: [Patches] New sys method to return total reference count in debug builds. In-Reply-To: <20000607091153.C26694@activestate.com>; from trentm@activestate.com on Wed, Jun 07, 2000 at 09:11:53AM -0700 References: <20000607091153.C26694@activestate.com> Message-ID: <20000607142454.K2486@lyra.org> On Wed, Jun 07, 2000 at 09:11:53AM -0700, Trent Mick wrote: > On Mon, Jun 05, 2000 at 09:18:30AM +1000, Mark Hammond wrote: > > + #ifdef Py_TRACE_REFS > > + static PyObject * > > + sys_gettotalrefcount(PyObject *self, PyObject *args) > > + { > > + extern long _Py_RefTotal; > > + if (!PyArg_ParseTuple(args, ":gettotalrefcount")) > > + return NULL; > > + return PyInt_FromLong((long) _Py_RefTotal); > > + } > > I would just drop the (long) cast. It is not necessary and just adds a > potential truncation if _Py_RefTotal is ever changed to size_t or something > like that. _Py_RefTotal is a count... it has nothing to do with sizes. I can't imagine that it would be changed to a size_t (and I'd say it *shouldn't*). I'm with you, though: dunno why the cast is in there. Cheers, -g -- Greg Stein, http://www.lyra.org/ From trentm@activestate.com Thu Jun 8 00:29:36 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 7 Jun 2000 16:29:36 -0700 Subject: [Patches] New sys method to return total reference count in debug builds. In-Reply-To: <20000607142454.K2486@lyra.org> References: <20000607091153.C26694@activestate.com> <20000607142454.K2486@lyra.org> Message-ID: <20000607162936.A29573@activestate.com> > _Py_RefTotal is a count... it has nothing to do with sizes. I can't imagine > that it would be changed to a size_t (and I'd say it *shouldn't*). That is why I said "size_t (or something like that)". Yes, you are right, but if sizeof(_Py_RefTotal) == size(void*) then you are guaranteed that it will never overflow. Perhaps I should have said 'intptr_t'. Trent -- Trent Mick trentm@activestate.com From mhammond@skippinet.com.au Thu Jun 8 00:43:13 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Thu, 8 Jun 2000 09:43:13 +1000 Subject: [Patches] New sys method to return total reference count in debug builds. In-Reply-To: <20000607162936.A29573@activestate.com> Message-ID: Points taken. However, looking at the diff in context, the function above is: static PyObject * sys_getrefcount(self, args) PyObject *self; PyObject *args; { PyObject *arg; if (!PyArg_ParseTuple(args, "O:getrefcount", &arg)) return NULL; return PyInt_FromLong((long) arg->ob_refcnt); } You can probably see where the explicit cast to long came from - it was copied from the existing function above it! Should my revised patch also drop the cast here? I assume so, for the same reasons... Mark. From Jack.Jansen@oratrix.com Thu Jun 8 22:53:23 2000 From: Jack.Jansen@oratrix.com (Jack Jansen) Date: Thu, 08 Jun 2000 23:53:23 +0200 Subject: [Patches] Revised patch for import.c Message-ID: <394015D2.A29350BA@oratrix.com> Here's a new version of my previous patch to import.c, using #elif in stead of nested #ifdefs. Use a different way to compare pyc filenames, on the mac only, making it easier to port to macosx. Index: import.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/import.c,v retrieving revision 2.134 diff -c -r2.134 import.c *** import.c 2000/05/03 23:44:39 2.134 --- import.c 2000/06/08 21:50:24 *************** *** 60,65 **** --- 60,67 ---- #endif #ifndef DONT_HAVE_SYS_STAT_H #include + #elif defined(HAVE_STAT_H) + #include #endif #if defined(PYCC_VACPP) *************** *** 1132,1139 **** name, buf); return 0; } ! p2cstr(fss.name); ! if ( strncmp(name, (char *)fss.name, namelen) != 0 ) { PyErr_Format(PyExc_NameError, "Case mismatch for module name %.100s\n(filename %.300s)", name, fss.name); --- 1134,1140 ---- name, buf); return 0; } ! if ( namelen > fss.name[0] || strncmp(name, (char *)fss.name+1, namelen) != 0 ) { PyErr_Format(PyExc_NameError, "Case mismatch for module name %.100s\n(filename %.300s)", name, fss.name); From mhammond@skippinet.com.au Fri Jun 9 05:22:06 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 9 Jun 2000 14:22:06 +1000 Subject: [Patches] Object leak in recursive comparison checker Message-ID: Im fairly confident there is a dictionary leak in the new get_inprogress_dict() function in object.c It is clear that this function returns a dictionary with _no_ reference count added. However, when it creates the dict, it returns an INCREF'd dict. Fortunately, we also stash the reference to this object in another dict, so we can safely DECREF our created reference (well, at least as safely as the other branch can return the existing dict with no new reference) The diff below is a 12 line context diff to help you see all relevant code. If you look at the usage of this function, you can also see the result is never DECREFd. My object reference leak vanished, and the full test suite completes, after making this change... Mark. diff -c -1 -2 -r2.70 object.c *** object.c 2000/05/03 23:44:35 2.70 --- object.c 2000/06/09 04:16:02 *************** *** 342,365 **** --- 342,367 ---- } inprogress = PyDict_GetItem(tstate_dict, _PyCompareState_Key); if (inprogress == NULL) { PyErr_Clear(); inprogress = PyDict_New(); if (inprogress == NULL) return NULL; if (PyDict_SetItem(tstate_dict, _PyCompareState_Key, inprogress) == -1) { Py_DECREF(inprogress); return NULL; } + /* The tstate_dict has a ref - we can now free ours */ + Py_DECREF(inprogress); } return inprogress; } static PyObject * make_pair(v, w) PyObject *v, *w; { PyObject *pair; pair = PyTuple_New(2); if (pair == NULL) { Release info: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Mark. From mhammond@skippinet.com.au Fri Jun 9 06:39:36 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 9 Jun 2000 15:39:36 +1000 Subject: [Patches] New sys method to return total reference count in debug builds. In-Reply-To: Message-ID: Here is a revised patch for the description included below. The revision removes the casts, as discussed here. If there are no comments over the next couple of days, I will check this change in. Mark. > When recently tracking down leaks, I found the ability to see the total > number of Python references incredibly useful - it made it quite > trivial to > see which functions were leaking Python object references. > > This information is exposed in certain builds to the C API, but > previously > wasn't exposed to Python. This patch addresses this. The > function will be > exposed in default debug builds on the Windows platform, and any other > builds where Py_TRACE_REFS is defined. diff -r2.64 sysmodule.c 268c268 < return PyInt_FromLong((long) arg->ob_refcnt); --- > return PyInt_FromLong(arg->ob_refcnt); 270a271,282 > #ifdef Py_TRACE_REFS > static PyObject * > sys_gettotalrefcount(PyObject *self, PyObject *args) > { > extern long _Py_RefTotal; > if (!PyArg_ParseTuple(args, ":gettotalrefcount")) > return NULL; > return PyInt_FromLong(_Py_RefTotal); > } > > #endif /* Py_TRACE_REFS */ > 312a325 > {"gettotalrefcount", sys_gettotalrefcount, 1}, Release info: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Mark. From Fredrik Lundh" Message-ID: <008d01bfd1e3$064db300$f2a6b5d4@hagrid> > this patch brings the CVS version of SRE in sync with the > latest public snapshot. is there any chance that anyone anywhere will check this one in? or did I miss some recent change in procedures? lots of stuff get checked in, but it doesn't seem to match what's posted to this list. maybe it's just my mail connection... From mhammond@skippinet.com.au Fri Jun 9 08:22:58 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 9 Jun 2000 17:22:58 +1000 Subject: [Patches] SRE update In-Reply-To: <008d01bfd1e3$064db300$f2a6b5d4@hagrid> Message-ID: > or did I miss some recent change in procedures? You did - its just that no one knows the new ones yet ;-) I believe that the few new people with checkin privileges arent game enough to start checking in other peoples patches, even from known "good-guys", like yourself and Jack. That is certainly true for me, anyway! Im sure things will be more formalized when Guido returns, but in the meantime you will probably still need to wait for one of the regular BeOpen guys... Mark. From mhammond@skippinet.com.au Fri Jun 9 08:25:04 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 9 Jun 2000 17:25:04 +1000 Subject: [Patches] SRE update In-Reply-To: Message-ID: I wrote: > I believe that the few new people with checkin privileges arent > game enough to start checking in other peoples patches, even > from known "good-guys", like yourself and Jack. That is > certainly true for me, anyway! To further make the point - Im not even game enough to check *my own* patches in that arent 100% windows related - eg, witness my sysmodule patches that Im letting linger for a _long_ time before I do anything about it... Mark. From mwh21@cam.ac.uk Fri Jun 9 13:28:50 2000 From: mwh21@cam.ac.uk (Michael Hudson) Date: 09 Jun 2000 13:28:50 +0100 Subject: [Patches] Re: Obscure Exception message In-Reply-To: Thomas Wouters's message of "Fri, 9 Jun 2000 01:05:19 +0200" References: <75F7304BB41CD411B06600A0C98414FC0A418B@ORSMSX54> <3dr9a7yi91.fsf@amarok.cnri.reston.va.us> <20000609010518.C20700@xs4all.nl> Message-ID: The following message is a courtesy copy of an article that has been posted to comp.lang.python as well. Thomas Wouters writes: > On Thu, Jun 08, 2000 at 05:28:58PM -0400, Andrew M. Kuchling wrote: > > > "Daley, MarkX" writes: > > > TypeError: string member test needs char left operand > > > I have no idea what this is telling me, although the 'char' comment makes me > > > wish I had a flamethrower! > > > Good point. Hmm... how about: > > TypeError: in requires character as left operand > > Put quotes around 'in ': > > TypeError: 'in ' requires character as left operand > The Rapid-Fire-Python-Error-Message-Improver (me) says: Index: stringobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v retrieving revision 2.66 diff -u -r2.66 stringobject.c --- stringobject.c 2000/06/01 03:12:13 2.66 +++ stringobject.c 2000/06/09 12:24:54 @@ -393,7 +393,7 @@ return PyUnicode_Contains(a, el); if (!PyString_Check(el) || PyString_Size(el) != 1) { PyErr_SetString(PyExc_TypeError, - "string member test needs char left operand"); + "'in ' requires character as left operand"); return -1; } c = PyString_AsString(el)[0]; Index: unicodeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/unicodeobject.c,v retrieving revision 2.21 diff -u -r2.21 unicodeobject.c --- unicodeobject.c 2000/05/09 19:54:43 2.21 +++ unicodeobject.c 2000/06/09 12:25:01 @@ -2991,7 +2991,7 @@ /* Check v in u */ if (PyUnicode_GET_SIZE(v) != 1) { PyErr_SetString(PyExc_TypeError, - "string member test needs char left operand"); + "'in ' requires character as left operand"); goto onError; } ch = *PyUnicode_AS_UNICODE(v); and: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Cheers, M. -- 93. When someone says "I want a programming language in which I need only say what I wish done," give him a lollipop. -- Alan Perlis, http://www.cs.yale.edu/homes/perlis-alan/quotes.html From akuchlin@mems-exchange.org Fri Jun 9 16:18:43 2000 From: akuchlin@mems-exchange.org (Andrew M. Kuchling) Date: Fri, 9 Jun 2000 11:18:43 -0400 Subject: [Patches] openpty() and forkpty() In-Reply-To: <20000604020945.D294@xs4all.nl>; from thomas@xs4all.net on Sun, Jun 04, 2000 at 02:09:46AM +0200 References: <20000604020945.D294@xs4all.nl> Message-ID: <20000609111843.D10688@amarok.cnri.reston.va.us> On Sun, Jun 04, 2000 at 02:09:46AM +0200, Thomas Wouters wrote: >Attached is a patch to add openpty() and forkpty() functions to the posix >module, if the target platform supports them. The patch is actually quite small, though it looks large because the patches to the generated configure script are included. If the patches are accepted, we'll regenerate the configure-related files and check them in. Anyway, the patch basically boils down to the following, which looks good. With the addition of a patch to libposix.tex documenting the two new functions, I'd suggest checking it in. --amk >Index: configure.in >=================================================================== >RCS file: /cvsroot/python/python/dist/src/configure.in,v >retrieving revision 1.124 >diff -c -r1.124 configure.in >*** configure.in 2000/05/26 12:22:54 1.124 >--- configure.in 2000/06/03 23:37:06 >*************** >*** 770,775 **** >--- 770,780 ---- > tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ > truncate uname waitpid) > >+ # check for openpty and forkpty >+ >+ AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY)] [LIBS="$LIBS -lutil"])) >+ AC_CHECK_FUNCS(forkpty,, AC_CHECK_LIB(util,forkpty, [AC_DEFINE(HAVE_FORKPTY)] [LIBS="$LIBS -lutil"])) >+ > # check for long file support functions > AC_CHECK_FUNCS(fseek64 fseeko fstatvfs ftell64 ftello statvfs) > >Index: Modules/posixmodule.c >=================================================================== >RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v >retrieving revision 2.135 >diff -c -r2.135 posixmodule.c >*** Modules/posixmodule.c 2000/06/01 02:02:46 2.135 >--- Modules/posixmodule.c 2000/06/03 23:37:08 >*************** >*** 1731,1737 **** >--- 1731,1779 ---- > } > #endif > >+ #ifdef HAVE_OPENPTY >+ static char posix_openpty__doc__[] = >+ "openpty() -> (master_fd, slave_fd)\n\ >+ Open a pseudo-terminal, returning open fd's for both master and slave end.\n"; > >+ static PyObject * >+ posix_openpty(self, args) >+ PyObject *self; >+ PyObject *args; >+ { >+ int master_fd, slave_fd; >+ if (!PyArg_ParseTuple(args, ":openpty")) >+ return NULL; >+ if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) >+ return posix_error(); >+ return Py_BuildValue("(ii)", master_fd, slave_fd); >+ } >+ #endif >+ >+ #ifdef HAVE_FORKPTY >+ static char posix_forkpty__doc__[] = >+ "forkpty() -> (pid, master_fd)\n\ >+ Fork a new process with a new pseudo-terminal as controlling tty.\n\n\ >+ Like fork(), return 0 as pid to child process, and PID of child to parent.\n\ >+ To both, return fd of newly opened pseudo-terminal.\n"; >+ >+ static PyObject * >+ posix_forkpty(self, args) >+ PyObject *self; >+ PyObject *args; >+ { >+ int master_fd, pid; >+ >+ if (!PyArg_ParseTuple(args, ":forkpty")) >+ return NULL; >+ pid = forkpty(&master_fd, NULL, NULL, NULL); >+ if (pid == -1) >+ return posix_error(); >+ PyOS_AfterFork(); >+ return Py_BuildValue("(ii)", pid, master_fd); >+ } >+ #endif >+ > #ifdef HAVE_GETEGID > static char posix_getegid__doc__[] = > "getegid() -> egid\n\ >*************** >*** 4514,4519 **** >--- 4556,4567 ---- > #ifdef HAVE_FORK > {"fork", posix_fork, METH_VARARGS, posix_fork__doc__}, > #endif /* HAVE_FORK */ >+ #ifdef HAVE_OPENPTY >+ {"openpty", posix_openpty, METH_VARARGS, posix_openpty__doc__}, >+ #endif /* HAVE_OPENPTY */ >+ #ifdef HAVE_FORKPTY >+ {"forkpty", posix_forkpty, METH_VARARGS, posix_forkpty__doc__}, >+ #endif /* HAVE_FORKPTY */ > #ifdef HAVE_GETEGID > {"getegid", posix_getegid, METH_VARARGS, posix_getegid__doc__}, > #endif /* HAVE_GETEGID */ From thomas@xs4all.net Fri Jun 9 16:51:23 2000 From: thomas@xs4all.net (Thomas Wouters) Date: Fri, 9 Jun 2000 17:51:23 +0200 Subject: [Patches] openpty() and forkpty() In-Reply-To: <20000609111843.D10688@amarok.cnri.reston.va.us>; from akuchlin@cnri.reston.va.us on Fri, Jun 09, 2000 at 11:18:43AM -0400 References: <20000604020945.D294@xs4all.nl> <20000609111843.D10688@amarok.cnri.reston.va.us> Message-ID: <20000609175123.F7766@xs4all.nl> On Fri, Jun 09, 2000 at 11:18:43AM -0400, Andrew M. Kuchling wrote: > Anyway, the patch basically boils down to the following, which looks > good. With the addition of a patch to libposix.tex documenting the > two new functions, I'd suggest checking it in. Thanx. I have one comment though, something I didn't notice until after I sent the patch in: posixmodule.c should include an include file for for the prototype openpty/forkpty. Unfortunately, the actual file to include differs between Linux and FreeBSD, and is nonexistant on BSDI. On Linux, it should include pty.h, on FreeBSD libutil.h, and on BSDI there simply is no prototype for openpty/forkpty to be found. Should I make autoconf check for the existance of pty.h/libutil.h and include other platforms seperately, once those get found, or should it just provide the prototypes for openpty/forkpty itself ? The prototype does match, on all three systems I am able to check. -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! From bwarsaw@python.org Fri Jun 9 17:22:02 2000 From: bwarsaw@python.org (Barry A. Warsaw) Date: Fri, 9 Jun 2000 12:22:02 -0400 (EDT) Subject: [Patches] Object leak in recursive comparison checker References: Message-ID: <14657.6570.28157.647665@anthem.concentric.net> >>>>> "MH" == Mark Hammond writes: MH> Im fairly confident there is a dictionary leak in the new MH> get_inprogress_dict() function in object.c I thought I had caught this one before leaving CNRI and I /thought/ I had checked almost the identical patch. It must have gotten lost in the transition. +1 -Barry From gstein@lyra.org Sat Jun 10 01:56:14 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 9 Jun 2000 17:56:14 -0700 Subject: [Patches] openpty() and forkpty() In-Reply-To: <20000609175123.F7766@xs4all.nl>; from thomas@xs4all.net on Fri, Jun 09, 2000 at 05:51:23PM +0200 References: <20000604020945.D294@xs4all.nl> <20000609111843.D10688@amarok.cnri.reston.va.us> <20000609175123.F7766@xs4all.nl> Message-ID: <20000609175614.A16880@lyra.org> On Fri, Jun 09, 2000 at 05:51:23PM +0200, Thomas Wouters wrote: > On Fri, Jun 09, 2000 at 11:18:43AM -0400, Andrew M. Kuchling wrote: > > > Anyway, the patch basically boils down to the following, which looks > > good. With the addition of a patch to libposix.tex documenting the > > two new functions, I'd suggest checking it in. > > Thanx. I have one comment though, something I didn't notice until after I > sent the patch in: posixmodule.c should include an include file for for the > prototype openpty/forkpty. Unfortunately, the actual file to include differs > between Linux and FreeBSD, and is nonexistant on BSDI. On Linux, it should > include pty.h, on FreeBSD libutil.h, and on BSDI there simply is no > prototype for openpty/forkpty to be found. > > Should I make autoconf check for the existance of pty.h/libutil.h and Yes. Take a look at the AC_CHECK_HEADERS line in configure.in around line 356. Each header should go in there. When AMK (or whoever folds in the patch) runs "autoheader", the autconf package will regenerate config.h.in with the new HAVE_PTY, etc symbols. > include other platforms seperately, once those get found, or should it just > provide the prototypes for openpty/forkpty itself ? The prototype does > match, on all three systems I am able to check. Have something like this in posixmodule.c: #ifdef HAVE_PTY #include #elifdef HAVE_LIBUTIL #include #else extern int openpty(int *amaster, ... blah blah #endif Cheers, -g p.s. and your patch doesn't need to include 'configure' or 'config.h.in' since they are generated files. -- Greg Stein, http://www.lyra.org/ From esr@snark.thyrsus.com Sat Jun 10 09:49:02 2000 From: esr@snark.thyrsus.com (Eric S. Raymond) Date: Sat, 10 Jun 2000 04:49:02 -0400 Subject: [Patches] Giving Python launch capav\bility Message-ID: <200006100849.EAA18388@snark.thyrsus.com> Patch description: Add a small function to urllib that supports launching a browser on a specified URL. Doc patch included because it's short and explains the function in detail. Disclaimer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. --- liburllib.tex 2000/06/10 08:26:00 1.1 +++ liburllib.tex 2000/06/10 08:36:57 @@ -91,6 +91,18 @@ \function{urlretrieve()}. \end{funcdesc} +\begin{funcdesc}{urlbrowse}{url} +Launch a browser, in background, pointed at the given URL. Accept +either a string or a parsed URL tuple as returned by +\code{urlparse.urparse()}. Under Unix, interpret the BROWSER environment +variable, if it exists, as a colon-separated list of browser commands +to try; in each commasnd, the URL is substituted for \%s. By default, +the Unix version of this function tries to hand the URL to Mozilla, +then to a Netscape running on the current display, then to a new +instance of Netscape, then to lynx, then to w3m. The function returns +1 if the launch succeeds, 0 otherwise. +\end{funcdesc} + \begin{funcdesc}{quote}{string\optional{, safe}} Replace special characters in \var{string} using the \samp{\%xx} escape. Letters, digits, and the characters \character{_,.-} are never quoted. --- urllib.py 2000/06/10 08:39:03 1.1 +++ urllib.py 2000/06/10 08:39:30 @@ -973,6 +973,32 @@ return proxies +# Support for launching a browser + +if os.environ.has_key("BROWSER"): + _browsers = string.split(os.environ["BROWSER"], ":") +else: + _browsers = ["mozilla %s &", + "netscape -remote 'openURL(%s)'", + "netscape %s &", + "lynx %s &", + "w3m %s &"] + +def urlbrowse(url): + """Launch a browser, in background, pointed at the given URL. + Accept either a string or a parsed URL tuple. + Interpret the BROWSER environment variable, if it exists, + as a colon-separated list of browser commands to try. + """ + from urlparse import urlunparse + if type(url) == (): + url = urlunparse(url) + for browser in _browsers: + if not os.system('which 1>/dev/null 2>&1 '+string.split(browser)[0]): + if os.system((browser % url)) == 0: + return 1 + return 0 + # Test and time quote() and unquote() def test1(): import time End of diffs. -- Eric S. Raymond Still, if you will not fight for the right when you can easily win without bloodshed, if you will not fight when your victory will be sure and not so costly, you may come to the moment when you will have to fight with all the odds against you and only a precarious chance for survival. There may be a worse case. You may have to fight when there is no chance of victory, because it is better to perish than to live as slaves. --Winston Churchill From Moshe Zadka Sat Jun 10 10:30:51 2000 From: Moshe Zadka (Moshe Zadka) Date: Sat, 10 Jun 2000 12:30:51 +0300 (IDT) Subject: [Patches] Giving Python launch capav\bility In-Reply-To: <200006100849.EAA18388@snark.thyrsus.com> Message-ID: On Sat, 10 Jun 2000, Eric S. Raymond wrote: > Patch description: > > Add a small function to urllib that supports launching a browser on > a specified URL. Doc patch included because it's short and > explains the function in detail. I'm -1: this adds to urllib something that is platform dependant, and doesn't really belong there. I'm +1, though, on installing idle as a package by default. Then a simple import idle.BrowserControl would solve the problem. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From mal@lemburg.com Sat Jun 10 10:38:03 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sat, 10 Jun 2000 11:38:03 +0200 Subject: [Patches] Giving Python launch capav\bility References: Message-ID: <39420C7B.6740A640@lemburg.com> Moshe Zadka wrote: > > On Sat, 10 Jun 2000, Eric S. Raymond wrote: > > > Patch description: > > > > Add a small function to urllib that supports launching a browser on > > a specified URL. Doc patch included because it's short and > > explains the function in detail. > > I'm -1: this adds to urllib something that is platform dependant, and > doesn't really belong there. Dito. Why not add it to os.py (and add support for Win32 platforms) ? > I'm +1, though, on installing idle as a package by default. > > Then a simple > > import idle.BrowserControl > > would solve the problem. Not a bad idea, but will IDLE work as package ? (I see lots of relative imports in there.) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Moshe Zadka Sat Jun 10 12:15:43 2000 From: Moshe Zadka (Moshe Zadka) Date: Sat, 10 Jun 2000 14:15:43 +0300 (IDT) Subject: [Patches] Giving Python launch capav\bility In-Reply-To: <39420C7B.6740A640@lemburg.com> Message-ID: On Sat, 10 Jun 2000, M.-A. Lemburg wrote: > Not a bad idea, but will IDLE work as package ? (I see lots > of relative imports in there.) It works.... I know I worked a bit on relative data-file paths (maybe IDLE should grow to use the distutils capabilities for this?), and with previous versions of IDLE, it operated quite nicely as a package. I haven't worked with recent versions, but after a recent look through the CVS logs, there shouldn't be anything that stopped working. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From fdrake@beopen.com Sun Jun 11 04:06:24 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Sat, 10 Jun 2000 23:06:24 -0400 (EDT) Subject: [Patches] Giving Python launch capav\bility In-Reply-To: References: <200006100849.EAA18388@snark.thyrsus.com> Message-ID: <14659.560.735544.820308@cj42289-a.reston1.va.home.com> Moshe Zadka writes: > I'm -1: this adds to urllib something that is platform dependant, and > doesn't really belong there. > I'm +1, though, on installing idle as a package by default. > > Then a simple > > import idle.BrowserControl I'm biased, but agree with Moshe anyway. ;) -1 on hacking urllib, +1 on making idle a package in the standard library (or at least parts of it). Disclaimer: I wrote BrowserControl. ;) -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From peter@schneider-kamp.de Sun Jun 11 11:15:37 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Sun, 11 Jun 2000 12:15:37 +0200 Subject: [Patches] indexerror: better error messages Message-ID: <394366C9.D5A00FD1@stud.ntnu.no> This is a multi-part message in MIME format. --------------21F20B013F0333841F36363B Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit error messages like "list index out of range" are not very helpful. a discussion about better error messages on the python mailing list proposed to add information about the value of the index which caused the IndexError and about the valid range.a few examples: "abc"[3] IndexError: string index 3 out of range [0..2] u"guido"[-10] IndexError: unicode string index -10 out of range [-5..-1] [][7] IndexError: cannot get item from empty list The speed penalty in case of a caught exception is constant and imho negligibly. an extra function PyErr_SetFromRange is added to Python/errors.c for the sake of sanity (wanna see the first version? :]). patch attached as plaintext context diff -- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de --------------21F20B013F0333841F36363B Content-Type: text/plain; charset=us-ascii; name="indexerror-patch-4" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="indexerror-patch-4" diff -c -b --recursive python/dist/src/Include/pyerrors.h python-mod/dist/src/Include/pyerrors.h *** python/dist/src/Include/pyerrors.h Fri Mar 10 23:33:32 2000 --- python-mod/dist/src/Include/pyerrors.h Sun Jun 11 11:47:38 2000 *************** *** 95,100 **** --- 95,101 ---- extern DL_IMPORT(PyObject *) PyErr_NoMemory Py_PROTO((void)); extern DL_IMPORT(PyObject *) PyErr_SetFromErrno Py_PROTO((PyObject *)); extern DL_IMPORT(PyObject *) PyErr_SetFromErrnoWithFilename Py_PROTO((PyObject *, char *)); + extern DL_IMPORT(PyObject *) PyErr_SetFromRange Py_PROTO((const char *, int, int)); extern DL_IMPORT(PyObject *) PyErr_Format Py_PROTO((PyObject *, const char *, ...)); #ifdef MS_WINDOWS extern DL_IMPORT(PyObject *) PyErr_SetFromWindowsErrWithFilename(int, const char *); diff -c -b --recursive python/dist/src/Modules/arraymodule.c python-mod/dist/src/Modules/arraymodule.c *** python/dist/src/Modules/arraymodule.c Thu Jun 1 04:02:46 2000 --- python-mod/dist/src/Modules/arraymodule.c Sun Jun 11 11:47:38 2000 *************** *** 389,395 **** } ap = (arrayobject *)op; if (i < 0 || i >= ap->ob_size) { ! PyErr_SetString(PyExc_IndexError, "array index out of range"); return NULL; } return (*ap->ob_descr->getitem)(ap, i); --- 389,400 ---- } ap = (arrayobject *)op; if (i < 0 || i >= ap->ob_size) { ! if (ap->ob_size) { ! PyErr_SetFromRange("array",i,ap->ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty array"); ! } return NULL; } return (*ap->ob_descr->getitem)(ap, i); *************** *** 502,508 **** int i; { if (i < 0 || i >= a->ob_size) { ! PyErr_SetString(PyExc_IndexError, "array index out of range"); return NULL; } return getarrayitem((PyObject *)a, i); --- 507,518 ---- int i; { if (i < 0 || i >= a->ob_size) { ! if (a->ob_size) { ! PyErr_SetFromRange("array",i,a->ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty array"); ! } return NULL; } return getarrayitem((PyObject *)a, i); *************** *** 668,675 **** PyObject *v; { if (i < 0 || i >= a->ob_size) { PyErr_SetString(PyExc_IndexError, ! "array assignment index out of range"); return -1; } if (v == NULL) --- 678,689 ---- PyObject *v; { if (i < 0 || i >= a->ob_size) { + if (a->ob_size) { + PyErr_SetFromRange("array",i,a->ob_size); + } else { PyErr_SetString(PyExc_IndexError, ! "cannot set item in empty array"); ! } return -1; } if (v == NULL) diff -c -b --recursive python/dist/src/Modules/mmapmodule.c python-mod/dist/src/Modules/mmapmodule.c *** python/dist/src/Modules/mmapmodule.c Sat Jun 3 22:43:43 2000 --- python-mod/dist/src/Modules/mmapmodule.c Sun Jun 11 11:58:16 2000 *************** *** 547,553 **** { CHECK_VALID(NULL); if (i < 0 || i >= self->size) { ! PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } return PyString_FromStringAndSize(self->data + i, 1); --- 547,557 ---- { CHECK_VALID(NULL); if (i < 0 || i >= self->size) { ! if (self->size) ! PyErr_SetFromRange("mmap",i,self->size); ! else ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty mmap"); return NULL; } return PyString_FromStringAndSize(self->data + i, 1); *************** *** 621,628 **** return -1; } if ( PyString_Size(v) != (ihigh - ilow) ) { ! PyErr_SetString(PyExc_IndexError, ! "mmap slice assignment is wrong size"); return -1; } buf = PyString_AsString(v); --- 625,631 ---- return -1; } if ( PyString_Size(v) != (ihigh - ilow) ) { ! PyErr_Format(PyExc_IndexError,"mmap slice assignment must have size %d but has size %d",ihigh-ilow,PyString_Size(v)); return -1; } buf = PyString_AsString(v); *************** *** 640,651 **** CHECK_VALID(-1); if (i < 0 || i >= self->size) { ! PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } ! if (! (PyString_Check(v) && PyString_Size(v)==1) ) { PyErr_SetString(PyExc_IndexError, "mmap assignment must be single-character string"); return -1; } buf = PyString_AsString(v); --- 643,663 ---- CHECK_VALID(-1); if (i < 0 || i >= self->size) { ! if (self->size) ! PyErr_SetFromRange("mmap",i,self->size); ! else ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty mmap"); return -1; } ! if (! (PyString_Check(v)) ) { PyErr_SetString(PyExc_IndexError, "mmap assignment must be single-character string"); + return -1; + } + if ( PyString_Size(v) != 1) { + PyErr_Format(PyExc_IndexError, + "mmap assignment must have single-character string but has size string of size %d",PyString_Size(v)); return -1; } buf = PyString_AsString(v); diff -c -b --recursive python/dist/src/Objects/bufferobject.c python-mod/dist/src/Objects/bufferobject.c *** python/dist/src/Objects/bufferobject.c Thu May 4 01:44:34 2000 --- python-mod/dist/src/Objects/bufferobject.c Sun Jun 11 11:47:38 2000 *************** *** 400,406 **** { if ( idx < 0 || idx >= self->b_size ) { ! PyErr_SetString(PyExc_IndexError, "buffer index out of range"); return NULL; } return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1); --- 400,411 ---- { if ( idx < 0 || idx >= self->b_size ) { ! if (self->b_size) { ! PyErr_SetFromRange("buffer",idx,self->b_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty buffer"); ! } return NULL; } return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1); *************** *** 447,454 **** } if (idx < 0 || idx >= self->b_size) { PyErr_SetString(PyExc_IndexError, ! "buffer assignment index out of range"); return -1; } --- 452,463 ---- } if (idx < 0 || idx >= self->b_size) { + if (self->b_size) { + PyErr_SetFromRange("buffer",idx,self->b_size); + } else { PyErr_SetString(PyExc_IndexError, ! "cannot set item in empty buffer"); ! } return -1; } diff -c -b --recursive python/dist/src/Objects/listobject.c python-mod/dist/src/Objects/listobject.c *** python/dist/src/Objects/listobject.c Thu Jun 1 16:31:03 2000 --- python-mod/dist/src/Objects/listobject.c Sun Jun 11 11:47:38 2000 *************** *** 115,124 **** return NULL; } if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { ! if (indexerr == NULL) ! indexerr = PyString_FromString( ! "list index out of range"); PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; } return ((PyListObject *)op) -> ob_item[i]; --- 115,128 ---- return NULL; } if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { ! if (indexerr == NULL) { ! if (((PyListObject *)op) -> ob_size) { ! indexerr = PyErr_SetFromRange("list",i,((PyListObject *)op) -> ob_size); ! } else { ! indexerr = PyString_FromString("cannot get item from empty list"); PyErr_SetObject(PyExc_IndexError, indexerr); + } + } else PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; } return ((PyListObject *)op) -> ob_item[i]; *************** *** 139,146 **** } if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { Py_XDECREF(newitem); ! PyErr_SetString(PyExc_IndexError, ! "list assignment index out of range"); return -1; } p = ((PyListObject *)op) -> ob_item + i; --- 143,153 ---- } if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { Py_XDECREF(newitem); ! if (((PyListObject *)op) -> ob_size) { ! PyErr_SetFromRange("list",i,((PyListObject *)op) -> ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError,"cannot set item in empty list"); ! } return -1; } p = ((PyListObject *)op) -> ob_item + i; *************** *** 331,340 **** int i; { if (i < 0 || i >= a->ob_size) { ! if (indexerr == NULL) ! indexerr = PyString_FromString( ! "list index out of range"); PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; } Py_INCREF(a->ob_item[i]); --- 338,352 ---- int i; { if (i < 0 || i >= a->ob_size) { ! if (indexerr == NULL) { ! if (a->ob_size) { ! indexerr = PyErr_SetFromRange("list",i,a->ob_size); ! } else { ! indexerr = PyString_FromString("cannot get item from empty list"); PyErr_SetObject(PyExc_IndexError, indexerr); + + } + } else PyErr_SetObject(PyExc_IndexError, indexerr); return NULL; } Py_INCREF(a->ob_item[i]); *************** *** 551,558 **** { PyObject *old_value; if (i < 0 || i >= a->ob_size) { PyErr_SetString(PyExc_IndexError, ! "list assignment index out of range"); return -1; } if (v == NULL) --- 563,574 ---- { PyObject *old_value; if (i < 0 || i >= a->ob_size) { + if (a->ob_size) { + PyErr_SetFromRange("list",i,a->ob_size); + } else { PyErr_SetString(PyExc_IndexError, ! "cannot set item in empty list"); ! } return -1; } if (v == NULL) *************** *** 701,707 **** if (i < 0) i += self->ob_size; if (i < 0 || i >= self->ob_size) { ! PyErr_SetString(PyExc_IndexError, "pop index out of range"); return NULL; } v = self->ob_item[i]; --- 717,723 ---- if (i < 0) i += self->ob_size; if (i < 0 || i >= self->ob_size) { ! PyErr_SetFromRange("list",i,self->ob_size); return NULL; } v = self->ob_item[i]; diff -c -b --recursive python/dist/src/Objects/rangeobject.c python-mod/dist/src/Objects/rangeobject.c *** python/dist/src/Objects/rangeobject.c Thu May 4 01:44:35 2000 --- python-mod/dist/src/Objects/rangeobject.c Sun Jun 11 11:47:38 2000 *************** *** 70,77 **** int i; { if (i < 0 || i >= r->len * r->reps) { PyErr_SetString(PyExc_IndexError, ! "xrange object index out of range"); return NULL; } --- 70,80 ---- int i; { if (i < 0 || i >= r->len * r->reps) { + if (r->len * r->reps) + PyErr_SetFromRange("xrange",i,r->len * r->reps); + else PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty xrange"); return NULL; } diff -c -b --recursive python/dist/src/Objects/stringobject.c python-mod/dist/src/Objects/stringobject.c *** python/dist/src/Objects/stringobject.c Fri Jun 9 16:04:53 2000 --- python-mod/dist/src/Objects/stringobject.c Sun Jun 11 11:47:38 2000 *************** *** 414,420 **** int c; PyObject *v; if (i < 0 || i >= a->ob_size) { ! PyErr_SetString(PyExc_IndexError, "string index out of range"); return NULL; } c = a->ob_sval[i] & UCHAR_MAX; --- 414,425 ---- int c; PyObject *v; if (i < 0 || i >= a->ob_size) { ! if (a->ob_size) { ! PyErr_SetFromRange("string",i,a->ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty string"); ! } return NULL; } c = a->ob_sval[i] & UCHAR_MAX; diff -c -b --recursive python/dist/src/Objects/tupleobject.c python-mod/dist/src/Objects/tupleobject.c *** python/dist/src/Objects/tupleobject.c Thu Jun 1 05:12:13 2000 --- python-mod/dist/src/Objects/tupleobject.c Sun Jun 11 11:47:38 2000 *************** *** 139,145 **** return NULL; } if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { ! PyErr_SetString(PyExc_IndexError, "tuple index out of range"); return NULL; } return ((PyTupleObject *)op) -> ob_item[i]; --- 139,150 ---- return NULL; } if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { ! if (((PyListObject *)op) -> ob_size) { ! PyErr_SetFromRange("tuple",i,((PyListObject *)op) -> ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty tuple"); ! } return NULL; } return ((PyTupleObject *)op) -> ob_item[i]; *************** *** 160,167 **** } if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { Py_XDECREF(newitem); PyErr_SetString(PyExc_IndexError, ! "tuple assignment index out of range"); return -1; } p = ((PyTupleObject *)op) -> ob_item + i; --- 165,176 ---- } if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { Py_XDECREF(newitem); + if (((PyListObject *)op) -> ob_size) { + PyErr_SetFromRange("tuple",i,((PyListObject *)op) -> ob_size); + } else { PyErr_SetString(PyExc_IndexError, ! "cannot set item in empty tuple"); ! } return -1; } p = ((PyTupleObject *)op) -> ob_item + i; *************** *** 304,310 **** register int i; { if (i < 0 || i >= a->ob_size) { ! PyErr_SetString(PyExc_IndexError, "tuple index out of range"); return NULL; } Py_INCREF(a->ob_item[i]); --- 313,324 ---- register int i; { if (i < 0 || i >= a->ob_size) { ! if (a->ob_size) { ! PyErr_SetFromRange("tuple",i,a->ob_size); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty tuple"); ! } return NULL; } Py_INCREF(a->ob_item[i]); diff -c -b --recursive python/dist/src/Objects/unicodeobject.c python-mod/dist/src/Objects/unicodeobject.c *** python/dist/src/Objects/unicodeobject.c Sun Jun 11 11:23:16 2000 --- python-mod/dist/src/Objects/unicodeobject.c Sun Jun 11 11:55:27 2000 *************** *** 3222,3228 **** unicode_getitem(PyUnicodeObject *self, int index) { if (index < 0 || index >= self->length) { ! PyErr_SetString(PyExc_IndexError, "string index out of range"); return NULL; } --- 3222,3233 ---- unicode_getitem(PyUnicodeObject *self, int index) { if (index < 0 || index >= self->length) { ! if (self->length) { ! PyErr_SetFromRange("unicode string",index,self->length); ! } else { ! PyErr_SetString(PyExc_IndexError, ! "cannot get item from empty unicode string"); ! } return NULL; } diff -c -b --recursive python/dist/src/Python/ceval.c python-mod/dist/src/Python/ceval.c *** python/dist/src/Python/ceval.c Mon May 8 16:06:50 2000 --- python-mod/dist/src/Python/ceval.c Sun Jun 11 11:47:38 2000 *************** *** 858,865 **** i += PyList_GET_SIZE(v); if (i < 0 || i >= PyList_GET_SIZE(v)) { PyErr_SetString(PyExc_IndexError, ! "list index out of range"); x = NULL; } else { --- 858,869 ---- i += PyList_GET_SIZE(v); if (i < 0 || i >= PyList_GET_SIZE(v)) { + if (PyList_GET_SIZE(v)) { + PyErr_SetFromRange("list",i,PyList_GET_SIZE(v)); + } else { PyErr_SetString(PyExc_IndexError, ! "empty list cannot be subscripted"); ! } x = NULL; } else { diff -c -b --recursive python/dist/src/Python/errors.c python-mod/dist/src/Python/errors.c *** python/dist/src/Python/errors.c Tue May 2 21:27:51 2000 --- python-mod/dist/src/Python/errors.c Sun Jun 11 11:47:38 2000 *************** *** 402,407 **** --- 402,420 ---- } #endif /* MS_WINDOWS */ + PyObject * + PyErr_SetFromRange(name,index,max) + const char* name; + int index; + int max; + { + if (index < 0) + PyErr_Format(PyExc_IndexError,"%s index %d out of range [-%d..-1]",name,index-max,max); + else + PyErr_Format(PyExc_IndexError,"%s index %d out of range [0..%d]",name,index,max-1); + return PyThreadState_Get()->curexc_value; + } + void PyErr_BadInternalCall() { --------------21F20B013F0333841F36363B-- From Moshe Zadka Sun Jun 11 11:22:18 2000 From: Moshe Zadka (Moshe Zadka) Date: Sun, 11 Jun 2000 13:22:18 +0300 (IDT) Subject: [Patches] indexerror: better error messages In-Reply-To: <394366C9.D5A00FD1@stud.ntnu.no> Message-ID: On Sun, 11 Jun 2000, Peter Schneider-Kamp wrote: > error messages like "list index out of range" are not very > helpful. a discussion about better error messages on the > python mailing list proposed to add information about the > value of the index which caused the IndexError and about > the valid range.a few examples: > The speed penalty in case of a caught exception is constant > and imho negligibly. Did you check it? You're taking a formatting hit for every IndexError! That doesn't seem this negligible. Why not simply have IndexError with enough members for formatting, and do the formatting (including the intellegient about checking if the size is 0) inside IndexError's __str__? -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From peter@schneider-kamp.de Sun Jun 11 12:41:57 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Sun, 11 Jun 2000 13:41:57 +0200 Subject: [Patches] indexerror: better error messages References: Message-ID: <39437B05.F5565DEC@stud.ntnu.no> Moshe Zadka wrote: > > Did you check it? You're taking a formatting hit for every IndexError! No, I did not. Do you have some suggestions what kind of code I should profile for comparison? > That doesn't seem this negligible. Why not simply have IndexError > with enough members for formatting, and do the formatting (including > the intellegient about checking if the size is 0) inside IndexError's > __str__? That's how I started. I passed a tuple containing the offending index and the length of the structure to IndexError__init__ and reused it in IndexError__str__. Then I realized that for the error message to contain the type of the sequence I have to pass down that one, too. For the "intelligent" size == 0 checking I additionally needed the type of the operation (I prefer "cannot get item from empty list" to "cannot perform operation on empty sequence"). Passing all of this seemed not much better than the one formatting and the if-else construct. Another possibility I see is to pass down an error number to encode the operation and the sequence type. But I hesitate to add long rows of: #define indexerror_list_getitem 0 #define indexerror_list_setitem 1 ... #define indexerror_array_getitem 0 It would also take away some flexibility. If my self-written Python class wants to use this "intelligent" error processing I cannot give a correct error number. Passing down the object itself (to get type and size) does not help, too, because that would mean a lot of if (PyList_Check(obj)) ... else if (PyString_Check(obj)) ... The size members etc. are inconsistently named. I see 3 sensible possibilities at the moment (please point out further ones I missed, maybe there are some obvious ones): * keep the old error messages * do some of the processing at the error location * just pass down the size and index and be happy with "sequence index 7 out of range [0..3]" and ("cannot perform operation on empty sequence" or "sequence index 0 out of range [0..-1]") while 1: if feedback: break -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de From mal@lemburg.com Sun Jun 11 21:04:42 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sun, 11 Jun 2000 22:04:42 +0200 Subject: [Patches] indexerror: better error messages References: <394366C9.D5A00FD1@stud.ntnu.no> Message-ID: <3943F0DA.A2FE2C60@lemburg.com> > error messages like "list index out of range" are not very > helpful. a discussion about better error messages on the > python mailing list proposed to add information about the > value of the index which caused the IndexError and about > the valid range.a few examples: > > "abc"[3] > IndexError: string index 3 out of range [0..2] > > u"guido"[-10] > IndexError: unicode string index -10 out of range [-5..-1] > > [][7] > IndexError: cannot get item from empty list > > The speed penalty in case of a caught exception is constant > and imho negligibly. I'm -2 on this one: errors which are raised *very* often like IndexError and AttributeError should not do any performance relevant actions during the raise operation. Finding out the cause of an error is easy enough by simply looking at the traceback when the error is being printed. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gstein@lyra.org Sun Jun 11 21:38:44 2000 From: gstein@lyra.org (Greg Stein) Date: Sun, 11 Jun 2000 13:38:44 -0700 Subject: [Patches] indexerror: better error messages In-Reply-To: <3943F0DA.A2FE2C60@lemburg.com>; from mal@lemburg.com on Sun, Jun 11, 2000 at 10:04:42PM +0200 References: <394366C9.D5A00FD1@stud.ntnu.no> <3943F0DA.A2FE2C60@lemburg.com> Message-ID: <20000611133844.Q19484@lyra.org> On Sun, Jun 11, 2000 at 10:04:42PM +0200, M.-A. Lemburg wrote: > > error messages like "list index out of range" are not very > > helpful. a discussion about better error messages on the > > python mailing list proposed to add information about the > > value of the index which caused the IndexError and about > > the valid range.a few examples: > > > > "abc"[3] > > IndexError: string index 3 out of range [0..2] > > > > u"guido"[-10] > > IndexError: unicode string index -10 out of range [-5..-1] > > > > [][7] > > IndexError: cannot get item from empty list > > > > The speed penalty in case of a caught exception is constant > > and imho negligibly. > > I'm -2 on this one: errors which are raised *very* often > like IndexError and AttributeError should not do any > performance relevant actions during the raise operation. Agreed: at raise time, it should be *fast*. However, at *print* time, it can take a little longer. If Peter can make the raise fast, and defer the formatting time to the print, then this patch would be reasonable. Cheers, -g -- Greg Stein, http://www.lyra.org/ From thomas@xs4all.net Sun Jun 11 22:52:40 2000 From: thomas@xs4all.net (Thomas Wouters) Date: Sun, 11 Jun 2000 23:52:40 +0200 Subject: [Patches] [UPDATE] Revised openpty patch Message-ID: <20000611235240.J7766@xs4all.nl> --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii An updated version of my patch to add openpty() and forkpty() to the posix module. (See http://www.python.org/pipermail/patches/2000-June/000896.html) Diff does not include configure or config.h.in this time ;) But it does include a patch to pty.py, which attempts to use os.openpty() and falls back to the old methods. I've renamed most of the functions to emphasize the fact that they're supposed to be internal, but wasn't sure wether removing master_open() and slave_open() was going to break anything; I can imagine people using them, in lieu of any other semi-portable method of opening a pty pair. So I've added backwards-compatibility for those two functions. (os.open(os.ttyname(slave_fd)) works correctly even with Unix98 pty's) I've also added pty.openpty() as the proper way of getting a pseudo-terminal pair, also including fallback. Documentation for the new pty and os functions isn't included in the patch, but is being sent to python-docs. I've tested this code on Linux (with glibc-2.1), FreeBSD 4.0 and BSDI4.x, and made sure it compiled without (additional) errors on those three + Solaris 2.6 -- I couldn't test it on Solaris because Python fails to compile on our sole, aging Solaris machine. It has turned up one issue: though not documented as doing so, forkpty() sets the new process as session leader, causing the setsid() in pty.py to fail. I'm not sure wether to remove it or not, because that behaviour isn't documented :P I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! --FL5UXtIhxfXey3p5 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="openpty.diff" Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.124 diff -u -r1.124 configure.in --- configure.in 2000/05/26 12:22:54 1.124 +++ configure.in 2000/06/11 21:33:48 @@ -357,7 +357,7 @@ signal.h stdarg.h stddef.h stdlib.h thread.h unistd.h utime.h \ sys/audioio.h sys/file.h sys/lock.h \ sys/param.h sys/select.h sys/socket.h sys/time.h sys/times.h \ -sys/un.h sys/utsname.h sys/wait.h) +sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h) AC_HEADER_DIRENT # checks for typedefs @@ -769,6 +769,11 @@ sigaction siginterrupt sigrelse strftime strptime symlink sysconf \ tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \ truncate uname waitpid) + +# check for openpty and forkpty + +AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(util,openpty, [AC_DEFINE(HAVE_OPENPTY)] [LIBS="$LIBS -lutil"])) +AC_CHECK_FUNCS(forkpty,, AC_CHECK_LIB(util,forkpty, [AC_DEFINE(HAVE_FORKPTY)] [LIBS="$LIBS -lutil"])) # check for long file support functions AC_CHECK_FUNCS(fseek64 fseeko fstatvfs ftell64 ftello statvfs) Index: Lib/pty.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pty.py,v retrieving revision 1.3 diff -u -r1.3 pty.py --- Lib/pty.py 2000/02/04 15:10:34 1.3 +++ Lib/pty.py 2000/06/11 21:33:49 @@ -16,9 +16,37 @@ CHILD = 0 +def openpty(): + """openpty() -> (master_fd, slave_fd) + Open a pty master/slave pair, using os.openpty() if possible.""" + + try: + return os.openpty() + except (AttributeError, OSError): + pass + master_fd, slave_name = _open_terminal() + slave_fd = _slave_open(slave_name) + return master_fd, slave_fd + def master_open(): + """master_open() -> (master_fd, slave_name) + Open a pty master and return the fd, and the filename of the slave end. + Deprecated, use openpty() instead.""" + + try: + master_fd, slave_fd = os.openpty() + except (AttributeError, OSError): + pass + else: + slave_name = os.ttyname(slave_fd) + os.close(slave_fd) + return master_fd, slave_name + + return _open_terminal() + +def _open_terminal(): """Open pty master and return (master_fd, tty_name). - SGI and Linux/BSD version.""" + SGI and generic BSD version, for when openpty() fails.""" try: import sgi except ImportError: @@ -40,22 +68,35 @@ raise os.error, 'out of pty devices' def slave_open(tty_name): - """Open the pty slave and acquire the controlling terminal. - Return the file descriptor. Linux version.""" - # (Should be universal? --Guido) + """slave_open(tty_name) -> slave_fd + Open the pty slave and acquire the controlling terminal, returning + opened filedescriptor. + Deprecated, use openpty() instead.""" + return os.open(tty_name, FCNTL.O_RDWR) def fork(): - """Fork and make the child a session leader with a controlling terminal. - Return (pid, master_fd).""" - master_fd, tty_name = master_open() + """fork() -> (pid, master_fd) + Fork and make the child a session leader with a controlling terminal.""" + + try: + pid, fd = os.forkpty() + except (AttributeError, OSError): + pass + else: + if pid == CHILD: + try: + os.setsid() + except OSError: + # os.forkpty() already set us session leader + pass + return pid, fd + + master_fd, slave_fd = openpty() pid = os.fork() if pid == CHILD: # Establish a new session. os.setsid() - - # Acquire controlling terminal. - slave_fd = slave_open(tty_name) os.close(master_fd) # Slave becomes stdin/stdout/stderr of child. @@ -68,17 +109,17 @@ # Parent and child process. return pid, master_fd -def writen(fd, data): +def _writen(fd, data): """Write all the data to a descriptor.""" while data != '': n = os.write(fd, data) data = data[n:] -def read(fd): +def _read(fd): """Default read function.""" return os.read(fd, 1024) -def copy(master_fd, master_read=read, stdin_read=read): +def _copy(master_fd, master_read=_read, stdin_read=_read): """Parent copy loop. Copies pty master -> standard output (master_read) @@ -91,9 +132,9 @@ os.write(STDOUT_FILENO, data) if STDIN_FILENO in rfds: data = stdin_read(STDIN_FILENO) - writen(master_fd, data) + _writen(master_fd, data) -def spawn(argv, master_read=read, stdin_read=read): +def spawn(argv, master_read=_read, stdin_read=_read): """Create a spawned process.""" if type(argv) == type(''): argv = (argv,) @@ -103,6 +144,6 @@ mode = tty.tcgetattr(STDIN_FILENO) tty.setraw(STDIN_FILENO) try: - copy(master_fd, master_read, stdin_read) + _copy(master_fd, master_read, stdin_read) except: tty.tcsetattr(STDIN_FILENO, tty.TCSAFLUSH, mode) Index: Modules/posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.136 diff -u -r2.136 posixmodule.c --- Modules/posixmodule.c 2000/06/06 20:52:17 2.136 +++ Modules/posixmodule.c 2000/06/11 21:33:51 @@ -1731,6 +1731,64 @@ } #endif +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) +#ifdef HAVE_PTY_H +#include +#else +#ifdef HAVE_LIBUTIL_H +#include +#else +/* BSDI does not supply a prototype for the 'openpty' and 'forkpty' + functions, eventhough they are included in libutil. */ +#include +extern int openpty(int *, int *, char *, struct termios *, struct winsize *); +extern int forkpty(int *, char *, struct termios *, struct winsize *); +#endif /* HAVE_LIBUTIL_H */ +#endif /* HAVE_PTY_H */ +#endif /* defined(HAVE_OPENPTY) or defined(HAVE_FORKPTY) */ + +#ifdef HAVE_OPENPTY +static char posix_openpty__doc__[] = +"openpty() -> (master_fd, slave_fd)\n\ +Open a pseudo-terminal, returning open fd's for both master and slave end.\n"; + +static PyObject * +posix_openpty(self, args) + PyObject *self; + PyObject *args; +{ + int master_fd, slave_fd; + if (!PyArg_ParseTuple(args, ":openpty")) + return NULL; + if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) + return posix_error(); + return Py_BuildValue("(ii)", master_fd, slave_fd); +} +#endif + +#ifdef HAVE_FORKPTY +static char posix_forkpty__doc__[] = +"forkpty() -> (pid, master_fd)\n\ +Fork a new process with a new pseudo-terminal as controlling tty.\n\n\ +Like fork(), return 0 as pid to child process, and PID of child to parent.\n\ +To both, return fd of newly opened pseudo-terminal.\n"; + +static PyObject * +posix_forkpty(self, args) + PyObject *self; + PyObject *args; +{ + int master_fd, pid; + + if (!PyArg_ParseTuple(args, ":forkpty")) + return NULL; + pid = forkpty(&master_fd, NULL, NULL, NULL); + if (pid == -1) + return posix_error(); + PyOS_AfterFork(); + return Py_BuildValue("(ii)", pid, master_fd); +} +#endif #ifdef HAVE_GETEGID static char posix_getegid__doc__[] = @@ -4514,6 +4572,12 @@ #ifdef HAVE_FORK {"fork", posix_fork, METH_VARARGS, posix_fork__doc__}, #endif /* HAVE_FORK */ +#ifdef HAVE_OPENPTY + {"openpty", posix_openpty, METH_VARARGS, posix_openpty__doc__}, +#endif /* HAVE_OPENPTY */ +#ifdef HAVE_FORKPTY + {"forkpty", posix_forkpty, METH_VARARGS, posix_forkpty__doc__}, +#endif /* HAVE_FORKPTY */ #ifdef HAVE_GETEGID {"getegid", posix_getegid, METH_VARARGS, posix_getegid__doc__}, #endif /* HAVE_GETEGID */ --FL5UXtIhxfXey3p5-- From peter@schneider-kamp.de Sun Jun 11 23:11:53 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Mon, 12 Jun 2000 00:11:53 +0200 Subject: [Patches] indexerror: better error messages References: <394366C9.D5A00FD1@stud.ntnu.no> <3943F0DA.A2FE2C60@lemburg.com> <20000611133844.Q19484@lyra.org> Message-ID: <39440EA9.73C7DFA5@stud.ntnu.no> Greg Stein wrote: > > If Peter can make the raise fast, and defer the formatting time to the > print, then this patch would be reasonable. Okay. The traceback solution sounds good on first sight. I'll give it a try. But don't hold your breath yet ;-) Peter -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de From peter@schneider-kamp.de Mon Jun 12 09:38:22 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Mon, 12 Jun 2000 10:38:22 +0200 Subject: [Patches] UPDATE: pindent: eliminate "# end"-tags References: <3932E28B.A5B9075F@stud.ntnu.no> <200005301445.JAA05990@cj20424-a.reston1.va.home.com> Message-ID: <3944A17E.573B5C1A@stud.ntnu.no> Guido van Rossum wrote: > > Looks okay to me. > > --Guido van Rossum (home page: http://www.python.org/~guido/) I guess I can take that as +0, right? Does anybody feel like commenting on it or just checking it in? just-putting-my-open-patches-on-sourceforge-ly y'rs Peter -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de From peter@schneider-kamp.de Mon Jun 12 09:46:55 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Mon, 12 Jun 2000 10:46:55 +0200 Subject: [Patches] indexerror: better error messages References: <394366C9.D5A00FD1@stud.ntnu.no> <3943F0DA.A2FE2C60@lemburg.com> Message-ID: <3944A37F.7841BB59@stud.ntnu.no> "M.-A. Lemburg" wrote: > > Finding out the cause of an error is easy enough by > simply looking at the traceback when the error is being > printed. I suppose this can be done inside the IndexError__str__ method in Python/exceptions.c. But how do I access the traceback object to get the required information? I have looked closely at traceobject.c but didn't see anything that would help me. A short hint would be appreciated. not-goint-to-parse-the-line-of-code-ly y'rs Peter -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de From peter@schneider-kamp.de Mon Jun 12 12:45:32 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Mon, 12 Jun 2000 13:45:32 +0200 Subject: [Patches] UPDATE: array.{pop,extend} [array.{count,index,remove}] References: <3930E6D4.BD5628C7@stud.ntnu.no> <200005301525.KAA06217@cj20424-a.reston1.va.home.com> Message-ID: <3944CD5C.FF4A821C@stud.ntnu.no> This is a multi-part message in MIME format. --------------A1BB794F76124C6DB9BD056D Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Guido van Rossum wrote: > > My suggestion would be to add pop() and extend() but leave the slow > ones (count, index, remove) out. Now the patch adds pop() and extend(), the other three replace the non-working versions which somebody (Tim?) added at some time (long ago?), but are still #if 0..#endif'ed. Documentation and tests for pop() and extend() are also added. Nevertheless I don't see the harm of having those "slow" versions. If somebody really should need them, they are more convenient and probably also faster than equivalent Python code. Peter patch attached as plaintext context diff -- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de --------------A1BB794F76124C6DB9BD056D Content-Type: text/plain; charset=us-ascii; name="array.pop-extend.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="array.pop-extend.patch" diff -c -b --recursive python/dist/src/Doc/lib/libarray.tex python-mod/dist/src/Doc/lib/libarray.tex *** python/dist/src/Doc/lib/libarray.tex Mon Apr 3 22:13:52 2000 --- python-mod/dist/src/Doc/lib/libarray.tex Mon Jun 12 13:13:39 2000 *************** *** 83,88 **** --- 83,92 ---- data from a file written on a machine with a different byte order. \end{methoddesc} + \begin{methoddesc}[array]{extend}{a} + Append array items from \var{a} to the end of the array. + \end{methoddesc} + \begin{methoddesc}[array]{fromfile}{f, n} Read \var{n} items (as machine values) from the file object \var{f} and append them to the end of the array. If less than \var{n} items *************** *** 107,112 **** --- 111,122 ---- \begin{methoddesc}[array]{insert}{i, x} Insert a new item with value \var{x} in the array before position \var{i}. + \end{methoddesc} + + \begin{methoddesc}[array]{pop}{\optional{i}} + Removes the item with the index \var{i} from the array and returns + it. The optional argument defaults to \code{-1}, so that by default + the last item is removed and returned. \end{methoddesc} \begin{methoddesc}[array]{read}{f, n} diff -c -b --recursive python/dist/src/Doc/lib/libstdtypes.tex python-mod/dist/src/Doc/lib/libstdtypes.tex *** python/dist/src/Doc/lib/libstdtypes.tex Mon Apr 3 22:13:54 2000 --- python-mod/dist/src/Doc/lib/libstdtypes.tex Mon Jun 12 11:34:16 2000 *************** *** 506,513 **** \item[(3)] Raises \exception{ValueError} when \var{x} is not found in \var{s}. ! \item[(4)] The \method{pop()} method is experimental and not supported ! by other mutable sequence types than lists. The optional argument \var{i} defaults to \code{-1}, so that by default the last item is removed and returned. --- 506,513 ---- \item[(3)] Raises \exception{ValueError} when \var{x} is not found in \var{s}. ! \item[(4)] The \method{pop()} method is experimental and at the moment ! only supported by the list and array types. The optional argument \var{i} defaults to \code{-1}, so that by default the last item is removed and returned. diff -c -b --recursive python/dist/src/Lib/test/test_array.py python-mod/dist/src/Lib/test/test_array.py *** python/dist/src/Lib/test/test_array.py Thu Jul 16 17:31:43 1998 --- python-mod/dist/src/Lib/test/test_array.py Mon Jun 12 13:20:51 2000 *************** *** 67,72 **** --- 67,86 ---- a[1:-1] = a if a != array.array(type, "aabcdee"): raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` + if a.pop(0) != "a": + raise TestFailed, "array(%s) pop-test" % `type` + if a.pop(1) != "b": + raise TestFailed, "array(%s) pop-test" % `type` + a.extend(array.array(type, "xyz")) + if a != array.array(type, "acdeexyz"): + raise TestFailed, "array(%s) extend-test" % `type` + a.pop() + a.pop() + a.pop() + a.pop() + a.pop() + if a != array.array(type, "acd"): + raise TestFailed, "array(%s) pop-test" % `type` else: a = array.array(type, [1, 2, 3, 4, 5]) a[:-1] = a *************** *** 80,85 **** --- 94,113 ---- a[1:-1] = a if a != array.array(type, [1, 1, 2, 3, 4, 5, 5]): raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` + if a.pop(0) != 1: + raise TestFailed, "array(%s) pop-test" % `type` + if a.pop(1) != 2: + raise TestFailed, "array(%s) pop-test" % `type` + a.extend(array.array(type, [7, 8, 9])) + if a != array.array(type, [1, 3, 4, 5, 5, 7, 8, 9]): + raise TestFailed, "array(%s) extend-test" % `type` + a.pop() + a.pop() + a.pop() + a.pop() + a.pop() + if a != array.array(type, [1, 3, 4]): + raise TestFailed, "array(%s) pop-test" % `type` main() diff -c -b --recursive python/dist/src/Modules/arraymodule.c python-mod/dist/src/Modules/arraymodule.c *** python/dist/src/Modules/arraymodule.c Thu Jun 1 04:02:46 2000 --- python-mod/dist/src/Modules/arraymodule.c Mon Jun 12 13:17:35 2000 *************** *** 703,708 **** --- 703,785 ---- } static PyObject * + array_pop(self, args) + arrayobject *self; + PyObject *args; + { + int i = -1; + PyObject *v; + if (!PyArg_ParseTuple(args, "|i:pop", &i)) + return NULL; + if (self->ob_size == 0) { + /* Special-case most common failure cause */ + PyErr_SetString(PyExc_IndexError, "pop from empty array"); + return NULL; + } + if (i < 0) + i += self->ob_size; + if (i < 0 || i >= self->ob_size) { + PyErr_SetString(PyExc_IndexError, "pop index out of range"); + return NULL; + } + v = getarrayitem((PyObject *)self,i); + Py_INCREF(v); + if (array_ass_slice(self, i, i+1, (PyObject *)NULL) != 0) { + Py_DECREF(v); + return NULL; + } + return v; + } + + static char pop_doc [] = + "pop ([i])\n\ + \n\ + Return the i-th element and delete it from the array. i defaults to -1."; + + static PyObject * + array_extend(self, args) + arrayobject *self; + PyObject *args; + { + int size; + PyObject *bb; + arrayobject *np; + + if (!PyArg_ParseTuple(args, "O:extend", &bb)) + return NULL; + + if (!is_arrayobject(bb)) { + PyErr_Format(PyExc_TypeError, + "can only append array (not \"%.200s\") to array", + bb->ob_type->tp_name); + return NULL; + } + #define b ((arrayobject *)bb) + if (self->ob_descr != b->ob_descr) { + PyErr_BadArgument(); + return NULL; + } + size = self->ob_size + b->ob_size; + PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize); + if (self->ob_item == NULL) { + PyObject_Del(self); + return PyErr_NoMemory(); + } + memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize, + b->ob_item, b->ob_size*b->ob_descr->itemsize); + self->ob_size = size; + Py_INCREF(Py_None); + return Py_None; + #undef b + } + + static char extend_doc [] = + "extend(array)\n\ + \n\ + Append array items to the end of the array."; + + + static PyObject * array_insert(self, args) arrayobject *self; PyObject *args; *************** *** 850,900 **** \n\ Reverse the order of the items in the array."; ! /* The following routines were adapted from listobject.c but not converted. ! To make them work you will have to work! */ #if 0 static PyObject * ! array_index(self, args) arrayobject *self; PyObject *args; { int i; ! if (args == NULL) { ! PyErr_BadArgument(); return NULL; - } for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(self->ob_item[i], args) == 0) ! return PyInt_FromLong((long)i); ! /* XXX PyErr_Occurred */ ! } ! PyErr_SetString(PyExc_ValueError, "array.index(x): x not in array"); return NULL; } #endif #if 0 static PyObject * ! array_count(self, args) arrayobject *self; PyObject *args; { - int count = 0; int i; ! if (args == NULL) { ! PyErr_BadArgument(); return NULL; - } for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(self->ob_item[i], args) == 0) ! count++; ! /* XXX PyErr_Occurred */ } ! return PyInt_FromLong((long)count); } #endif #if 0 --- 927,988 ---- \n\ Reverse the order of the items in the array."; ! /* The following routines were adapted from listobject.c, but are not ! included because they are considered too slow. To use them you ! additionally have to uncomment the method hookups. */ #if 0 static PyObject * ! array_count(self, args) arrayobject *self; PyObject *args; { + int count = 0; int i; + PyObject *v; ! if (!PyArg_Parse(args, "O", &v)) return NULL; for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(getarrayitem((PyObject *)self,i), v) == 0) ! count++; ! if (PyErr_Occurred()) return NULL; + } + return PyInt_FromLong((long)count); } + + static char count_doc [] = + "count (x)\n\ + \n\ + Return number of occurences of x in the array."; #endif #if 0 static PyObject * ! array_index(self, args) arrayobject *self; PyObject *args; { int i; + PyObject *v; ! if (!PyArg_Parse(args, "O", &v)) return NULL; for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(getarrayitem((PyObject *)self,i), v) == 0) ! return PyInt_FromLong((long)i); ! if (PyErr_Occurred()) ! return NULL; } ! PyErr_SetString(PyExc_ValueError, "array.index(x): x not in list"); ! return NULL; } + + static char index_doc [] = + "index (x)\n\ + \n\ + Return index of first occurence of x in the array."; #endif #if 0 *************** *** 904,927 **** PyObject *args; { int i; ! if (args == NULL) { ! PyErr_BadArgument(); return NULL; - } for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(self->ob_item[i], args) == 0) { if (array_ass_slice(self, i, i+1, (PyObject *)NULL) != 0) return NULL; Py_INCREF(Py_None); return Py_None; } ! /* XXX PyErr_Occurred */ } ! PyErr_SetString(PyExc_ValueError, "array.remove(x): x not in array"); return NULL; } #endif static PyObject * --- 992,1020 ---- PyObject *args; { int i; + PyObject *v; ! if (!PyArg_Parse(args, "O", &v)) return NULL; for (i = 0; i < self->ob_size; i++) { ! if (PyObject_Compare(getarrayitem((PyObject *)self,i), v) == 0) { if (array_ass_slice(self, i, i+1, (PyObject *)NULL) != 0) return NULL; Py_INCREF(Py_None); return Py_None; } ! if (PyErr_Occurred()) ! return NULL; } ! PyErr_SetString(PyExc_ValueError, "array.remove(x): x not in list"); return NULL; } + + static char remove_doc [] = + "remove (x)\n\ + \n\ + Remove the first occurence of x in the array."; #endif static PyObject * *************** *** 1147,1162 **** {"buffer_info", (PyCFunction)array_buffer_info, 0, buffer_info_doc}, {"byteswap", (PyCFunction)array_byteswap, METH_VARARGS, byteswap_doc}, ! /* {"count", (method)array_count},*/ {"fromfile", (PyCFunction)array_fromfile, 0, fromfile_doc}, {"fromlist", (PyCFunction)array_fromlist, 0, fromlist_doc}, {"fromstring", (PyCFunction)array_fromstring, 0, fromstring_doc}, ! /* {"index", (method)array_index},*/ {"insert", (PyCFunction)array_insert, 0, insert_doc}, {"read", (PyCFunction)array_fromfile, 0, fromfile_doc}, ! /* {"remove", (method)array_remove},*/ {"reverse", (PyCFunction)array_reverse, 0, reverse_doc}, ! /* {"sort", (method)array_sort},*/ {"tofile", (PyCFunction)array_tofile, 0, tofile_doc}, {"tolist", (PyCFunction)array_tolist, 0, tolist_doc}, {"tostring", (PyCFunction)array_tostring, 0, tostring_doc}, --- 1240,1257 ---- {"buffer_info", (PyCFunction)array_buffer_info, 0, buffer_info_doc}, {"byteswap", (PyCFunction)array_byteswap, METH_VARARGS, byteswap_doc}, ! /* {"count", (PyCFunction)array_count, 0, count_doc},*/ ! {"extend", (PyCFunction)array_extend, 1, extend_doc}, {"fromfile", (PyCFunction)array_fromfile, 0, fromfile_doc}, {"fromlist", (PyCFunction)array_fromlist, 0, fromlist_doc}, {"fromstring", (PyCFunction)array_fromstring, 0, fromstring_doc}, ! /* {"index", (PyCFunction)array_index, 0, index_doc},*/ {"insert", (PyCFunction)array_insert, 0, insert_doc}, + {"pop", (PyCFunction)array_pop, 1, pop_doc}, {"read", (PyCFunction)array_fromfile, 0, fromfile_doc}, ! /* {"remove", (PyCFunction)array_remove, 0, remove_doc},*/ {"reverse", (PyCFunction)array_reverse, 0, reverse_doc}, ! /* {"sort", (PyCFunction)array_sort, 0, sort_doc},*/ {"tofile", (PyCFunction)array_tofile, 0, tofile_doc}, {"tolist", (PyCFunction)array_tolist, 0, tolist_doc}, {"tostring", (PyCFunction)array_tostring, 0, tostring_doc}, *************** *** 1432,1441 **** --- 1527,1538 ---- append() -- append a new item to the end of the array\n\ buffer_info() -- return information giving the current memory info\n\ byteswap() -- byteswap all the items of the array\n\ + extend() -- extend array by appending array elements\n\ fromfile() -- read items from a file object\n\ fromlist() -- append items from the list\n\ fromstring() -- append items from the string\n\ insert() -- insert a new item into the array at a provided position\n\ + pop() -- remove and return item (default last)\n\ read() -- DEPRECATED, use fromfile()\n\ reverse() -- reverse the order of the items in the array\n\ tofile() -- write all items to a file object\n\ --------------A1BB794F76124C6DB9BD056D-- From mal@lemburg.com Mon Jun 12 13:54:38 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Mon, 12 Jun 2000 14:54:38 +0200 Subject: [Patches] indexerror: better error messages References: <394366C9.D5A00FD1@stud.ntnu.no> <3943F0DA.A2FE2C60@lemburg.com> <3944A37F.7841BB59@stud.ntnu.no> Message-ID: <3944DD8E.C587B722@lemburg.com> Peter Schneider-Kamp wrote: > > "M.-A. Lemburg" wrote: > > > > Finding out the cause of an error is easy enough by > > simply looking at the traceback when the error is being > > printed. > > I suppose this can be done inside the IndexError__str__ > method in Python/exceptions.c. Right. > But how do I access the traceback object to get the > required information? I have looked closely at > traceobject.c but didn't see anything that would help me. > A short hint would be appreciated. First, get the current thread state via PyThreadState_Get() and then use ->curexc_traceback to find the information needed. Note that for errors raised from C functions you won't be able to use the traceback. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From tim_one@email.msn.com Mon Jun 12 18:29:56 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 12 Jun 2000 13:29:56 -0400 Subject: [Patches] UPDATE: array.{pop,extend} [array.{count,index,remove}] In-Reply-To: <3944CD5C.FF4A821C@stud.ntnu.no> Message-ID: <000801bfd493$d3d9a380$f5a0143f@tim> [Guido] > My suggestion would be to add pop() and extend() but leave the slow > ones (count, index, remove) out. [Peter Schneider-Kamp] > Now the patch adds pop() and extend(), the other three replace > the non-working versions which somebody (Tim?) added at some time > (long ago?), but are still #if 0..#endif'ed. 'Tweren't me -- AFAIK those stubs have been there forever. > Documentation and tests for pop() and extend() are also added. Good! > Nevertheless I don't see the harm of having those "slow" versions. > If somebody really should need them, they are more convenient and > probably also faster than equivalent Python code. I agree. Guido is concerned that he's going to get yelled at when people discover *how* slow they are (compared to lists), and I sympathize with that, but Guido has to get used to the idea that he'll soon have people to yell at in turn . Seriously, that we want (& may even have) a faster implementation "someday" isn't compelling reason to refuse to supply the *functionality* today. work-first-fast-later-ly y'rs - tim From dscherer@cmu.edu Mon Jun 12 18:57:43 2000 From: dscherer@cmu.edu (David Scherer) Date: Mon, 12 Jun 2000 13:57:43 -0400 Subject: [Patches] import floatdivision # 1/2==0.5 Message-ID: This is a multi-part message in MIME format. ------=_NextPart_000_0009_01BFD476.2E3025C0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit This patch provides a way to make 1/2==0.5 optional without introducing any backward incompatibilities. It provides a pseudomodule "floatdivision" that, when imported, changes the behavior of the importing script at compile time: import floatdivision print 3/4 # 0.75 This behavior is already available in my 1.5.2-based Python distribution for Windows (see http://sourceforge.net/projects/visualpython). I would like to see it generally available, particularly since I cannot easily provide a replacement Python interpreter to UNIX users. The attached patch is against the CVS 1.6 of this morning. I believe the changes are self-explanatory, but I will be happy to discuss them. In my original changes to 1.5.2, I implemented the BINARY_FRACTION opcode through a new PyNumber_Fraction API call, but I thought it best to keep this patch as simple as possible and let someone more familiar with the code base reorganize it if they choose. Optionally, the interpreter can be made to do floating-point division in interactive mode. The lines that do this are commented out in the patch: c->c_interactive++; + /* c->c_floatdivision++; */ + /* c->c_floatdivision--; */ c->c_interactive--; Alternatively, this could be left to environments such as IDLE. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Dave ------=_NextPart_000_0009_01BFD476.2E3025C0 Content-Type: application/octet-stream; name="floatdivision.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="floatdivision.patch" diff -c -r -x Entries* old\python/dist/src/Include/opcode.h = python/dist/src/Include/opcode.h *** old\python/dist/src/Include/opcode.h Tue Mar 28 23:10:02 2000 --- python/dist/src/Include/opcode.h Mon Jun 12 14:41:06 2000 *************** *** 76,81 **** --- 76,82 ---- #define BINARY_AND 64 #define BINARY_XOR 65 #define BINARY_OR 66 + #define BINARY_FRACTION 67 /* 3/4 =3D=3D 0.75 */ =20 =20 #define PRINT_EXPR 70 diff -c -r -x Entries* old\python/dist/src/Lib/dis.py = python/dist/src/Lib/dis.py *** old\python/dist/src/Lib/dis.py Thu Mar 30 14:02:10 2000 --- python/dist/src/Lib/dis.py Mon Jun 12 15:52:20 2000 *************** *** 186,191 **** --- 186,192 ---- def_op('BINARY_AND', 64) def_op('BINARY_XOR', 65) def_op('BINARY_OR', 66) + def_op('BINARY_FRACTION', 67) =20 def_op('PRINT_EXPR', 70) def_op('PRINT_ITEM', 71) diff -c -r -x Entries* old\python/dist/src/Python/ceval.c = python/dist/src/Python/ceval.c *** old\python/dist/src/Python/ceval.c Mon May 08 14:06:50 2000 --- python/dist/src/Python/ceval.c Mon Jun 12 14:52:02 2000 *************** *** 787,792 **** --- 787,816 ---- PUSH(x); if (x !=3D NULL) continue; break; +=20 + case BINARY_FRACTION: + w =3D POP(); + v =3D POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* 3/4 =3D=3D 0.75 */ + long vi, wi; + vi =3D PyInt_AS_LONG(v); + wi =3D PyInt_AS_LONG(w); + if (wi =3D=3D 0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "integer division"); + x=3DNULL; + } + else + x=3DPyFloat_FromDouble( (double)vi / (double)wi ); + } + else + x =3D PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x !=3D NULL) continue; + break; =09 case BINARY_MODULO: w =3D POP(); diff -c -r -x Entries* old\python/dist/src/Python/compile.c = python/dist/src/Python/compile.c *** old\python/dist/src/Python/compile.c Wed May 03 23:44:38 2000 --- python/dist/src/Python/compile.c Mon Jun 12 15:25:26 2000 *************** *** 329,334 **** --- 329,335 ---- #ifdef PRIVATE_NAME_MANGLING char *c_private; /* for private name mangling */ #endif + int c_floatdivision; /* generate BINARY_FRACTION; 3/4=3D=3D0.75 */ }; =20 =20 *************** *** 463,468 **** --- 464,470 ---- c->c_last_addr =3D 0; c->c_last_line =3D 0; c-> c_lnotab_next =3D 0; + c->c_floatdivision =3D 0; return 1; =09 fail: *************** *** 1482,1488 **** op =3D BINARY_MULTIPLY; break; case SLASH: ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; --- 1484,1493 ---- op =3D BINARY_MULTIPLY; break; case SLASH: ! if (c->c_floatdivision) ! op =3D BINARY_FRACTION; ! else ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; *************** *** 2179,2188 **** /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); } } } --- 2184,2200 ---- /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); !=20 ! if (NCH( CHILD(n,i) )=3D=3D1 &&=20 ! !strcmp("floatdivision", STR(CHILD(CHILD(n,i),0)))) ! { ! c->c_floatdivision++; ! } else { ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); ! } } } } *************** *** 3306,3311 **** --- 3318,3324 ---- case single_input: /* One interactive command */ /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ c->c_interactive++; + /* c->c_floatdivision++; */ n =3D CHILD(n, 0); if (TYPE(n) !=3D NEWLINE) com_node(c, n); *************** *** 3313,3318 **** --- 3326,3332 ---- com_push(c, 1); com_addbyte(c, RETURN_VALUE); com_pop(c, 1); + /* c->c_floatdivision--; */ c->c_interactive--; break; =09 *************** *** 3482,3487 **** --- 3496,3503 ---- else sc.c_private =3D NULL; #endif + if (base) + sc.c_floatdivision =3D base->c_floatdivision; compile_node(&sc, n); com_done(&sc); if ((TYPE(n) =3D=3D funcdef || TYPE(n) =3D=3D lambdef) && sc.c_errors = =3D=3D 0) { ------=_NextPart_000_0009_01BFD476.2E3025C0-- From peter@schneider-kamp.de Mon Jun 12 19:22:43 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Mon, 12 Jun 2000 20:22:43 +0200 Subject: [Patches] UPDATE: array.{pop,extend} [array.{count,index,remove}] References: <000801bfd493$d3d9a380$f5a0143f@tim> Message-ID: <39452A73.9374C69D@stud.ntnu.no> Tim Peters wrote: > > 'Tweren't me -- AFAIK those stubs have been there forever. =8-] Well, there IS your name in the todo list. BTW: Is there a more recent list of things that need to be done? Everything but float arithmetics and error handling would be fine to me... > Seriously, that we want (& may even have) a faster implementation "someday" > isn't compelling reason to refuse to supply the *functionality* today. I think so, too. Well, if this patch is checked in and Guido changes his mind it's just 6 pragmas and 4 comments to delete. [+ some doc changes and added tests which I still have around] but-then-who-uses-index-count-remove-on-arrays--ly y'rs Peter -- Peter Schneider-Kamp ++47-7388-7331 Herman Krags veg 51-11 mailto:peter@schneider-kamp.de N-7050 Trondheim http://schneider-kamp.de From dscherer@cmu.edu Mon Jun 12 21:12:01 2000 From: dscherer@cmu.edu (David Scherer) Date: Mon, 12 Jun 2000 16:12:01 -0400 Subject: [Patches] Re: import floatdivision # 1/2==0.5 Message-ID: This is a multi-part message in MIME format. ------=_NextPart_000_0015_01BFD488.F0E76300 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit In case anyone's mailer had as much difficulty with the MIME attachment in my original post as the pipermail archives did, the patch is also available from http://visualpython.sourceforge.net/floatdivision.patch Dave ------=_NextPart_000_0015_01BFD488.F0E76300 Content-Type: application/octet-stream; name="floatdivision.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="floatdivision.patch" diff -c -r -x Entries* old\python/dist/src/Include/opcode.h = python/dist/src/Include/opcode.h *** old\python/dist/src/Include/opcode.h Tue Mar 28 23:10:02 2000 --- python/dist/src/Include/opcode.h Mon Jun 12 14:41:06 2000 *************** *** 76,81 **** --- 76,82 ---- #define BINARY_AND 64 #define BINARY_XOR 65 #define BINARY_OR 66 + #define BINARY_FRACTION 67 /* 3/4 =3D=3D 0.75 */ =20 =20 #define PRINT_EXPR 70 diff -c -r -x Entries* old\python/dist/src/Lib/dis.py = python/dist/src/Lib/dis.py *** old\python/dist/src/Lib/dis.py Thu Mar 30 14:02:10 2000 --- python/dist/src/Lib/dis.py Mon Jun 12 15:52:20 2000 *************** *** 186,191 **** --- 186,192 ---- def_op('BINARY_AND', 64) def_op('BINARY_XOR', 65) def_op('BINARY_OR', 66) + def_op('BINARY_FRACTION', 67) =20 def_op('PRINT_EXPR', 70) def_op('PRINT_ITEM', 71) diff -c -r -x Entries* old\python/dist/src/Python/ceval.c = python/dist/src/Python/ceval.c *** old\python/dist/src/Python/ceval.c Mon May 08 14:06:50 2000 --- python/dist/src/Python/ceval.c Mon Jun 12 14:52:02 2000 *************** *** 787,792 **** --- 787,816 ---- PUSH(x); if (x !=3D NULL) continue; break; +=20 + case BINARY_FRACTION: + w =3D POP(); + v =3D POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* 3/4 =3D=3D 0.75 */ + long vi, wi; + vi =3D PyInt_AS_LONG(v); + wi =3D PyInt_AS_LONG(w); + if (wi =3D=3D 0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "integer division"); + x=3DNULL; + } + else + x=3DPyFloat_FromDouble( (double)vi / (double)wi ); + } + else + x =3D PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x !=3D NULL) continue; + break; =09 case BINARY_MODULO: w =3D POP(); diff -c -r -x Entries* old\python/dist/src/Python/compile.c = python/dist/src/Python/compile.c *** old\python/dist/src/Python/compile.c Wed May 03 23:44:38 2000 --- python/dist/src/Python/compile.c Mon Jun 12 15:25:26 2000 *************** *** 329,334 **** --- 329,335 ---- #ifdef PRIVATE_NAME_MANGLING char *c_private; /* for private name mangling */ #endif + int c_floatdivision; /* generate BINARY_FRACTION; 3/4=3D=3D0.75 */ }; =20 =20 *************** *** 463,468 **** --- 464,470 ---- c->c_last_addr =3D 0; c->c_last_line =3D 0; c-> c_lnotab_next =3D 0; + c->c_floatdivision =3D 0; return 1; =09 fail: *************** *** 1482,1488 **** op =3D BINARY_MULTIPLY; break; case SLASH: ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; --- 1484,1493 ---- op =3D BINARY_MULTIPLY; break; case SLASH: ! if (c->c_floatdivision) ! op =3D BINARY_FRACTION; ! else ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; *************** *** 2179,2188 **** /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); } } } --- 2184,2200 ---- /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); !=20 ! if (NCH( CHILD(n,i) )=3D=3D1 &&=20 ! !strcmp("floatdivision", STR(CHILD(CHILD(n,i),0)))) ! { ! c->c_floatdivision++; ! } else { ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); ! } } } } *************** *** 3306,3311 **** --- 3318,3324 ---- case single_input: /* One interactive command */ /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ c->c_interactive++; + /* c->c_floatdivision++; */ n =3D CHILD(n, 0); if (TYPE(n) !=3D NEWLINE) com_node(c, n); *************** *** 3313,3318 **** --- 3326,3332 ---- com_push(c, 1); com_addbyte(c, RETURN_VALUE); com_pop(c, 1); + /* c->c_floatdivision--; */ c->c_interactive--; break; =09 *************** *** 3482,3487 **** --- 3496,3503 ---- else sc.c_private =3D NULL; #endif + if (base) + sc.c_floatdivision =3D base->c_floatdivision; compile_node(&sc, n); com_done(&sc); if ((TYPE(n) =3D=3D funcdef || TYPE(n) =3D=3D lambdef) && sc.c_errors = =3D=3D 0) { ------=_NextPart_000_0015_01BFD488.F0E76300-- From gstein@lyra.org Mon Jun 12 21:20:15 2000 From: gstein@lyra.org (Greg Stein) Date: Mon, 12 Jun 2000 13:20:15 -0700 Subject: [Patches] Re: import floatdivision # 1/2==0.5 In-Reply-To: ; from dscherer@cmu.edu on Mon, Jun 12, 2000 at 04:12:01PM -0400 References: Message-ID: <20000612132015.O19484@lyra.org> On Mon, Jun 12, 2000 at 04:12:01PM -0400, David Scherer wrote: > In case anyone's mailer had as much difficulty with the MIME attachment in > my original post as the pipermail archives did, the patch is also available > from > > http://visualpython.sourceforge.net/floatdivision.patch The problem is that you are posting them with the "application/octet-stream" MIME type. Either insert the patch right into the body of your message, or ensure that it is attached as text/plain. To get text/plain, you could rename your patch file to end with ".txt"; your Outlook mailer doesn't recognize the ".patch" extension, so it uses application/octet-stream. Cheers, -g -- Greg Stein, http://www.lyra.org/ From dscherer@cmu.edu Mon Jun 12 22:01:13 2000 From: dscherer@cmu.edu (David Scherer) Date: Mon, 12 Jun 2000 17:01:13 -0400 Subject: [Patches] Re: import floatdivision # 1/2==0.5 Message-ID: This is a multi-part message in MIME format. ------=_NextPart_000_002B_01BFD48F.D0AD66A0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit > The problem is that you are posting them with the > "application/octet-stream" MIME type. :( Here's a third try. Still-using-the-mouse-as-a-foot-pedal-ly yours, Dave ------=_NextPart_000_002B_01BFD48F.D0AD66A0 Content-Type: text/plain; name="floatdivision.patch.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="floatdivision.patch.txt" This patch provides a way to make 1/2=3D=3D0.5 optional without introducing any backward incompatibilities. It provides a pseudomodule "floatdivision" that, when imported, changes the behavior of the importing script at compile time: import floatdivision print 3/4 # 0.75 I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Dave diff -c -r -x Entries* old\python/dist/src/Include/opcode.h = python/dist/src/Include/opcode.h *** old\python/dist/src/Include/opcode.h Tue Mar 28 23:10:02 2000 --- python/dist/src/Include/opcode.h Mon Jun 12 14:41:06 2000 *************** *** 76,81 **** --- 76,82 ---- #define BINARY_AND 64 #define BINARY_XOR 65 #define BINARY_OR 66 + #define BINARY_FRACTION 67 /* 3/4 =3D=3D 0.75 */ =20 =20 #define PRINT_EXPR 70 diff -c -r -x Entries* old\python/dist/src/Lib/dis.py = python/dist/src/Lib/dis.py *** old\python/dist/src/Lib/dis.py Thu Mar 30 14:02:10 2000 --- python/dist/src/Lib/dis.py Mon Jun 12 15:52:20 2000 *************** *** 186,191 **** --- 186,192 ---- def_op('BINARY_AND', 64) def_op('BINARY_XOR', 65) def_op('BINARY_OR', 66) + def_op('BINARY_FRACTION', 67) =20 def_op('PRINT_EXPR', 70) def_op('PRINT_ITEM', 71) diff -c -r -x Entries* old\python/dist/src/Python/ceval.c = python/dist/src/Python/ceval.c *** old\python/dist/src/Python/ceval.c Mon May 08 14:06:50 2000 --- python/dist/src/Python/ceval.c Mon Jun 12 14:52:02 2000 *************** *** 787,792 **** --- 787,816 ---- PUSH(x); if (x !=3D NULL) continue; break; +=20 + case BINARY_FRACTION: + w =3D POP(); + v =3D POP(); + if (PyInt_Check(v) && PyInt_Check(w)) { + /* 3/4 =3D=3D 0.75 */ + long vi, wi; + vi =3D PyInt_AS_LONG(v); + wi =3D PyInt_AS_LONG(w); + if (wi =3D=3D 0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "integer division"); + x=3DNULL; + } + else + x=3DPyFloat_FromDouble( (double)vi / (double)wi ); + } + else + x =3D PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + PUSH(x); + if (x !=3D NULL) continue; + break; =09 case BINARY_MODULO: w =3D POP(); diff -c -r -x Entries* old\python/dist/src/Python/compile.c = python/dist/src/Python/compile.c *** old\python/dist/src/Python/compile.c Wed May 03 23:44:38 2000 --- python/dist/src/Python/compile.c Mon Jun 12 15:25:26 2000 *************** *** 329,334 **** --- 329,335 ---- #ifdef PRIVATE_NAME_MANGLING char *c_private; /* for private name mangling */ #endif + int c_floatdivision; /* generate BINARY_FRACTION; 3/4=3D=3D0.75 */ }; =20 =20 *************** *** 463,468 **** --- 464,470 ---- c->c_last_addr =3D 0; c->c_last_line =3D 0; c-> c_lnotab_next =3D 0; + c->c_floatdivision =3D 0; return 1; =09 fail: *************** *** 1482,1488 **** op =3D BINARY_MULTIPLY; break; case SLASH: ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; --- 1484,1493 ---- op =3D BINARY_MULTIPLY; break; case SLASH: ! if (c->c_floatdivision) ! op =3D BINARY_FRACTION; ! else ! op =3D BINARY_DIVIDE; break; case PERCENT: op =3D BINARY_MODULO; *************** *** 2179,2188 **** /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); } } } --- 2184,2200 ---- /* 'import' ... */ for (i =3D 1; i < NCH(n); i +=3D 2) { REQ(CHILD(n, i), dotted_name); !=20 ! if (NCH( CHILD(n,i) )=3D=3D1 &&=20 ! !strcmp("floatdivision", STR(CHILD(CHILD(n,i),0)))) ! { ! c->c_floatdivision++; ! } else { ! com_addopname(c, IMPORT_NAME, CHILD(n, i)); ! com_push(c, 1); ! com_addopname(c, STORE_NAME, CHILD(CHILD(n, i), 0)); ! com_pop(c, 1); ! } } } } *************** *** 3306,3311 **** --- 3318,3324 ---- case single_input: /* One interactive command */ /* NEWLINE | simple_stmt | compound_stmt NEWLINE */ c->c_interactive++; + /* c->c_floatdivision++; */ n =3D CHILD(n, 0); if (TYPE(n) !=3D NEWLINE) com_node(c, n); *************** *** 3313,3318 **** --- 3326,3332 ---- com_push(c, 1); com_addbyte(c, RETURN_VALUE); com_pop(c, 1); + /* c->c_floatdivision--; */ c->c_interactive--; break; =09 *************** *** 3482,3487 **** --- 3496,3503 ---- else sc.c_private =3D NULL; #endif + if (base) + sc.c_floatdivision =3D base->c_floatdivision; compile_node(&sc, n); com_done(&sc); if ((TYPE(n) =3D=3D funcdef || TYPE(n) =3D=3D lambdef) && sc.c_errors = =3D=3D 0) { ------=_NextPart_000_002B_01BFD48F.D0AD66A0-- From tim_one@email.msn.com Tue Jun 13 02:58:14 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 12 Jun 2000 21:58:14 -0400 Subject: [Patches] UPDATE: array.{pop,extend} [array.{count,index,remove}] In-Reply-To: <39452A73.9374C69D@stud.ntnu.no> Message-ID: <000301bfd4da$d6087220$de2d153f@tim> [Peter Schneider-Kamp] > ... BTW: Is there a more recent list of things that need to be done? > Everything but float arithmetics and error handling would be fine to me... Python development is in a state of not-quite-controlled chaos at the moment. Everything from bug list to ToDo list needs a major overhaul. > ... Well, if this patch is checked in and Guido changes his mind it's > just 6 pragmas and 4 comments to delete. [+ some doc changes and > added tests which I still have around] I won't be any help this week -- in the middle of moving to VA, and while I managed to get a SourceForge CVS mirror on the laptop I bought for the trip, I still haven't figured out what I need to do to actually check semething in (& out of time for putzing around with that). > but-then-who-uses-index-count-remove-on-arrays--ly y'rs I would. efficiency-doesn't-matter-most-of-the-time-ly y'rs - tim From Moshe Zadka Tue Jun 13 05:29:31 2000 From: Moshe Zadka (Moshe Zadka) Date: Tue, 13 Jun 2000 07:29:31 +0300 (IDT) Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: Message-ID: On Mon, 12 Jun 2000, David Scherer wrote: > This patch provides a way to make 1/2==0.5 optional without introducing any > backward incompatibilities. It provides a pseudomodule "floatdivision" > that, when imported, changes the behavior of the importing script at compile > time: > > import floatdivision > print 3/4 # 0.75 -1 on that. I don't like language to be dependant on modules: no "library" can import this module, because it might break other code. On the other hand, no "application" can import this module, because it might break library code. Plus a general -1 on thrusting floating point in innocent people's faces. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From gstein@lyra.org Tue Jun 13 08:47:34 2000 From: gstein@lyra.org (Greg Stein) Date: Tue, 13 Jun 2000 00:47:34 -0700 Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: ; from moshez@math.huji.ac.il on Tue, Jun 13, 2000 at 07:29:31AM +0300 References: Message-ID: <20000613004734.N19484@lyra.org> On Tue, Jun 13, 2000 at 07:29:31AM +0300, Moshe Zadka wrote: > On Mon, 12 Jun 2000, David Scherer wrote: > > > This patch provides a way to make 1/2==0.5 optional without introducing any > > backward incompatibilities. It provides a pseudomodule "floatdivision" > > that, when imported, changes the behavior of the importing script at compile > > time: > > > > import floatdivision > > print 3/4 # 0.75 > > -1 on that. I don't like language to be dependant on modules: no "library" > can import this module, because it might break other code. On the other > hand, no "application" can import this module, because it might break > library code. Plus a general -1 on thrusting floating point in innocent > people's faces. Careful with your impressions there... :-) There isn't a module, and your statement of its scope is incorrect. The patch is actually much more subtle. The "import floatdivision" is not really an import, and it doesn't affect anything outside of the "compound_stmt" that it occurs in (and the sub-statements). Effectively, the flag is scoped. def foo(): import floatdivision print 3/4 foo() print 3/4 The answer is 0.75 and 0. Pretty neat, huh? What happens is when the *compiler* sees "import floatdivision", it enables a flag. All further divisions in that compilation unit (and sub-units) use a new opcode for fractional division. Any other compile that doesn't have a similar import will insert the regular division bytecode. While this is a really slick way to accomplish this, I'm not all that comfortable with the "magic" that makes it work. Cheers, -g -- Greg Stein, http://www.lyra.org/ From mal@lemburg.com Tue Jun 13 09:19:54 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 13 Jun 2000 10:19:54 +0200 Subject: [Patches] import floatdivision # 1/2==0.5 References: Message-ID: <3945EEAA.C07E3C39@lemburg.com> Moshe Zadka wrote: > > On Mon, 12 Jun 2000, David Scherer wrote: > > > This patch provides a way to make 1/2==0.5 optional without introducing any > > backward incompatibilities. It provides a pseudomodule "floatdivision" > > that, when imported, changes the behavior of the importing script at compile > > time: > > > > import floatdivision > > print 3/4 # 0.75 > > -1 on that. I don't like language to be dependant on modules: no "library" > can import this module, because it might break other code. On the other > hand, no "application" can import this module, because it might break > library code. Plus a general -1 on thrusting floating point in innocent > people's faces. -1 from here too for much the same reasons. While introducing some kind of float division is probably a good idea for CP4E, I wouldn't like to have to scan 100k LOCs just to figure out which of them rely on 5/2 returning 2 instead of 2.5. Some time ago there was a discussion about introducing 5//2 to give 2.5 (or was it the other way around ?). Note that writing 3/4. will solve the problem without any new language features. For variable arguments you can write a/float(b) which is pretty nice to read too. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gstein@lyra.org Tue Jun 13 11:34:47 2000 From: gstein@lyra.org (Greg Stein) Date: Tue, 13 Jun 2000 03:34:47 -0700 Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: <3945EEAA.C07E3C39@lemburg.com>; from mal@lemburg.com on Tue, Jun 13, 2000 at 10:19:54AM +0200 References: <3945EEAA.C07E3C39@lemburg.com> Message-ID: <20000613033447.V19484@lyra.org> On Tue, Jun 13, 2000 at 10:19:54AM +0200, M.-A. Lemburg wrote: > Moshe Zadka wrote: > > > > On Mon, 12 Jun 2000, David Scherer wrote: > > > > > This patch provides a way to make 1/2==0.5 optional without introducing any > > > backward incompatibilities. It provides a pseudomodule "floatdivision" > > > that, when imported, changes the behavior of the importing script at compile > > > time: > > > > > > import floatdivision > > > print 3/4 # 0.75 > > > > -1 on that. I don't like language to be dependant on modules: no "library" > > can import this module, because it might break other code. On the other > > hand, no "application" can import this module, because it might break > > library code. Plus a general -1 on thrusting floating point in innocent > > people's faces. > > -1 from here too for much the same reasons. > > While introducing some kind of float division is probably a good > idea for CP4E, I wouldn't like to have to scan 100k LOCs just to > figure out which of them rely on 5/2 returning 2 instead of 2.5. Some > time ago there was a discussion about introducing 5//2 to > give 2.5 (or was it the other way around ?). > > Note that writing 3/4. will solve the problem without any > new language features. For variable arguments you can write > a/float(b) which is pretty nice to read too. Um... guys? David's patch uses lexical scoping to determine where the "/" operator does a float division. There isn't any cross-module or application-level problems. If a module is designed to use float division, then it includes the thing at the top. If just a single function wants it, then the "import" (which it really isn't) occurs in the function body. Want it for a class? Then do the import in the classdef portion, before the method definitions. Go read the patch :-) Cheers, -g -- Greg Stein, http://www.lyra.org/ From mal@lemburg.com Tue Jun 13 11:54:34 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 13 Jun 2000 12:54:34 +0200 Subject: [Patches] import floatdivision # 1/2==0.5 References: <3945EEAA.C07E3C39@lemburg.com> <20000613033447.V19484@lyra.org> Message-ID: <394612EA.7024940B@lemburg.com> Greg Stein wrote: > > On Tue, Jun 13, 2000 at 10:19:54AM +0200, M.-A. Lemburg wrote: > > Moshe Zadka wrote: > > > > > > On Mon, 12 Jun 2000, David Scherer wrote: > > > > > > > This patch provides a way to make 1/2==0.5 optional without introducing any > > > > backward incompatibilities. It provides a pseudomodule "floatdivision" > > > > that, when imported, changes the behavior of the importing script at compile > > > > time: > > > > > > > > import floatdivision > > > > print 3/4 # 0.75 > > > > > > -1 on that. I don't like language to be dependant on modules: no "library" > > > can import this module, because it might break other code. On the other > > > hand, no "application" can import this module, because it might break > > > library code. Plus a general -1 on thrusting floating point in innocent > > > people's faces. > > > > -1 from here too for much the same reasons. > > > > While introducing some kind of float division is probably a good > > idea for CP4E, I wouldn't like to have to scan 100k LOCs just to > > figure out which of them rely on 5/2 returning 2 instead of 2.5. Some > > time ago there was a discussion about introducing 5//2 to > > give 2.5 (or was it the other way around ?). > > > > Note that writing 3/4. will solve the problem without any > > new language features. For variable arguments you can write > > a/float(b) which is pretty nice to read too. > > Um... guys? David's patch uses lexical scoping to determine where the "/" > operator does a float division. There isn't any cross-module or > application-level problems. > > If a module is designed to use float division, then it includes the thing at > the top. If just a single function wants it, then the "import" (which it > really isn't) occurs in the function body. Want it for a class? Then do the > import in the classdef portion, before the method definitions. > > Go read the patch :-) Wasn't inlined by my mailer and I was too lazy to save it first :-) Still, I'd rather like to see some kind of pragma keyword for these kind of semantic changes... I have to admit that the hack is a cool one though -- perhaps we could use something similar for the source code encoding stuff ?! I'm still -1 on changing semantics/syntax via imports; +1 on doing so via pragma or some_other_hairy_keyword_to_scare_away_newbies ;-) Seriously, neither import nor pragma will help newbies make use of '·/·' ::= '·/float(·)'. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From dscherer@cmu.edu Tue Jun 13 14:02:00 2000 From: dscherer@cmu.edu (David Scherer) Date: Tue, 13 Jun 2000 09:02:00 -0400 Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: <394612EA.7024940B@lemburg.com> Message-ID: [Greg] >> If a module is designed to use float division, then it includes >> the thing at the top. If just a single function wants it, then >> the "import" (which it really isn't) occurs in the function body. >> Want it for a class? Then do the import in the classdef portion, >> before the method definitions. Correct. [MAL] > Still, I'd rather like to see some kind of pragma keyword > for these kind of semantic changes... Some background might be appropriate here. I am working with some professors who write physics textbooks. For a few years, they have been teaching all of their (non-CS) students to write graphical simulations, using an obscure language called cT. This is a real "CP4E" environment: we have two 50-minute class periods to teach graphics programming to nonprogrammers. Beginning in September, we will be switching to Python and a 3D graphics library I've written for Python (http://sourceforge.net/projects/visualpython) We need floating point division. Because we are trying to make our environment available on UNIX, we want it to be part of standard Python in some form. My first suggestion (made to idle-dev and discussed briefly on python-dev) was to make 3/4==0.75 the default, and provide backward compatibility with the 'global' keyword. The ha.. er, implementation :) works exactly the same, and is also lexically scoped. global olddivision # does nothing on Python 1.5.2 print 3/4 # 0 This is obviously a much bigger change than the "import", since it changes the default behavior of the language. "import floatdivision" is intended as a compromise: it permits us to experiment without inconveniencing anyone. There are a variety of other possibilities, from file extensions to new keywords. > Seriously, neither import nor pragma will help newbies > make use of '·/·' ::= '·/float(·)'. We disagree. At worst, we can simply tell students up front that they need to type "import floatdivision" at the beginning of every program, because otherwise 3/2 is one, and that leads to hard-to-find bugs. I don't think it's a difficult habit to learn. Programming environments such as IDLE could be configured to insert "import floatdivision" at the top of a new file, leaving it up to the experienced programmer to remove it. More specialized environments could even change the behavior silently. The point is that having the flag in the language gives 'CP4E' researchers room to experiment, even on platforms like Linux where the interpreter is a system resource and can't be replaced. Dave From mal@lemburg.com Tue Jun 13 14:24:09 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 13 Jun 2000 15:24:09 +0200 Subject: [Patches] import floatdivision # 1/2==0.5 References: Message-ID: <394635F9.CB16C4D9@lemburg.com> David Scherer wrote: > > [Greg] > >> If a module is designed to use float division, then it includes > >> the thing at the top. If just a single function wants it, then > >> the "import" (which it really isn't) occurs in the function body. > >> Want it for a class? Then do the import in the classdef portion, > >> before the method definitions. > > Correct. > > [MAL] > > Still, I'd rather like to see some kind of pragma keyword > > for these kind of semantic changes... > > Some background might be appropriate here. I am working with some > professors who write physics textbooks. For a few years, they have been > teaching all of their (non-CS) students to write graphical simulations, > using an obscure language called cT. This is a real "CP4E" environment: we > have two 50-minute class periods to teach graphics programming to > nonprogrammers. Beginning in September, we will be switching to Python and > a 3D graphics library I've written for Python > (http://sourceforge.net/projects/visualpython) > > We need floating point division. Because we are trying to make our > environment available on UNIX, we want it to be part of standard Python in > some form. > > My first suggestion (made to idle-dev and discussed briefly on python-dev) > was to make 3/4==0.75 the default, and provide backward compatibility with > the 'global' keyword. The ha.. er, implementation :) works exactly the > same, and is also lexically scoped. > > global olddivision # does nothing on Python 1.5.2 > print 3/4 # 0 > > This is obviously a much bigger change than the "import", since it changes > the default behavior of the language. "import floatdivision" is intended as > a compromise: it permits us to experiment without inconveniencing anyone. > There are a variety of other possibilities, from file extensions to new > keywords. I like your lexically scoped fix (changing / to globally mean float division would break huge amounts of code and be very hard to track down)... not sure what Guido thinks about this, though. What I don't like is the misuse of 'import' to trigger the change. IMHO, it would be worthwhile designing a general solution to this problem, which also allows setting values. The background here: we will be moving towards different source encodings in 1.7 and there'll be a need to define the encoding somewhere in the code for the compiler to use. Some kind of 'pragma encoding:latin-1' would be needed -- much like your 'pragma division:coerce-to-float'. It's a new keyword, but a potentially useful one :-) > > Seriously, neither import nor pragma will help newbies > > make use of '·/·' ::= '·/float(·)'. > > We disagree. At worst, we can simply tell students up front that they need > to type "import floatdivision" at the beginning of every program, because > otherwise 3/2 is one, and that leads to hard-to-find bugs. I don't think > it's a difficult habit to learn. The other around is neither ;-) (Note that in C/C++ 3/2 also gives 1. Don't know about Java, but it's probably the same there too.) > Programming environments such as IDLE could be configured to insert "import > floatdivision" at the top of a new file, leaving it up to the experienced > programmer to remove it. More specialized environments could even change > the behavior silently. The point is that having the flag in the language > gives 'CP4E' researchers room to experiment, even on platforms like Linux > where the interpreter is a system resource and can't be replaced. Agreed. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From jim@interet.com Tue Jun 13 14:28:17 2000 From: jim@interet.com (James C. Ahlstrom) Date: Tue, 13 Jun 2000 09:28:17 -0400 Subject: [Patches] Buglet in zipfile.py Message-ID: <394636F1.2F048A8A@interet.com> Thanks to Hubert Hoegl for finding this bug: JimA *** zipfile.py Fri Mar 31 12:30:02 2000 --- O:/ftp/pub/zipfile.py Mon May 22 09:36:22 2000 *************** *** 166,172 **** x.volume, x.internal_attr, x.external_attr = centdir[15:18] # Convert date/time code to (year, month, day, hour, min, sec) x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F, ! t>>11, (t>>5)&0x3F, t&0x1F * 2 ) self.filelist.append(x) self.NameToInfo[x.filename] = x if self.debug > 2: --- 166,172 ---- x.volume, x.internal_attr, x.external_attr = centdir[15:18] # Convert date/time code to (year, month, day, hour, min, sec) x.date_time = ( (d>>9)+1980, (d>>5)&0xF, d&0x1F, ! t>>11, (t>>5)&0x3F, (t&0x1F) * 2 ) self.filelist.append(x) self.NameToInfo[x.filename] = x if self.debug > 2: From skip@mojam.com (Skip Montanaro) Tue Jun 13 15:23:59 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Tue, 13 Jun 2000 09:23:59 -0500 (CDT) Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: References: <394612EA.7024940B@lemburg.com> Message-ID: <14662.17407.703078.679110@beluga.mojam.com> >> Seriously, neither import nor pragma will help newbies make use = of >> '=B7/=B7' ::=3D '=B7/float(=B7)'. Dave> We disagree. At worst, we can simply tell students up front = that Dave> they need to type "import floatdivision" at the beginning of = every Dave> program, because otherwise 3/2 is one, and that leads to Dave> hard-to-find bugs. I don't think it's a difficult habit to l= earn. Dave, My anecdotal experience reading the python-bugs list for awhile is that= people are thrown for a loop much more often by the imprecision of floa= ting point arithmetic than they are by the truncating properties of integer division. I believe the number one "bug report" category on that list = reads something like "Python doesn't compare floating point numbers correctly= ", followed by a brief treatise by Tim Peters on the properties of floatin= g point arithmetic. I don't believe I've ever seen a "bug report" that suggests there is something wrong with Python's division operation beca= use 3/2 =3D=3D 1 or 2/3 =3D=3D 0. I will add my vote against the specific patch (I can't recall what the various values mean - I think the concept is okay but not the mechanism= ). While I understand the desire to allow floating point results from inte= ger division in some contexts and have seen enough traffic on the Python li= sts over the years to believe there is a need for it, I think that coopting= the import statement is not the correct way to reach that goal. It will al= most certainly not pass muster with Guido, which (presuming you adopt this c= hange in your department) will leave you always having to patch Python distributions and build those (like Windows) that are commonly distribu= ted in binary form. What will happen if/when your BINARY_FRACTION opcode g= ets used for something else in the 1.7 release? Then all your pyc files wi= ll be broken, perhaps in very subtle ways... Also, while the patch provides a scoped solution, within a specific sco= pe there is no way to undo it (I suppose you could also recognize "import intdivision"). What if, after executing "import floatdivision" you wan= ted integer division later on (say, during some loop arithmetic)? Your pat= ch doesn't allow that behavior. Not being a numerical person, I would fin= d it very odd to have to deal with floating point results in loop variables.= Wouldn't happen a lot, but I'd have to scratch my head whenever it did.= My recommendation is that for the time being just put up with Marc-Andr= e's 3/4. and a/float(b) suggestions. They will always work, and they make = the programmer's intent clear. tim-will-correct-me-if-i'm-wrong-ly y'rs, --=20 Skip Montanaro, skip@mojam.com, http://www.mojam.com/, http://www.musi-= cal.com/ On June 24th at 8AM, live your life for an hour as Ricky Byrdsong alway= s lived his - run/walk in the Ricky Byrdsong Memorial 5K or just make a donatio= n: https://www.SignmeupSports.com/Events/Index_Events.asp?EventID=3D13= 95 From dscherer@cmu.edu Tue Jun 13 16:45:22 2000 From: dscherer@cmu.edu (David Scherer) Date: Tue, 13 Jun 2000 11:45:22 -0400 Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: <14662.17407.703078.679110@beluga.mojam.com> Message-ID: Skip writes: > I believe the number one "bug report" category on that list reads > something like "Python doesn't compare floating point numbers correctly", > followed by a brief treatise by Tim Peters on the properties of floating > point arithmetic. I don't believe I've ever seen a "bug report" that > suggests there is something wrong with Python's division operation because > 3/2 == 1 or 2/3 == 0. Truncating integer division doesn't do anything to ameliorate the problems with floating point. The properties which fail to hold for floats also fail to hold when 1/2 = 0. I suggest that people who are posting bugs to the bug list are a totally different population than we are targeting. Most people have never heard of truncating division - it really exists only in the programming world. Randy Pausch's research, and our own limited experience, strongly suggest that this is a serious problem. > It will almost certainly not pass muster with Guido Well, he called my previous proposal "kind of cute" and even "a fine starting point" :) http://www.python.org/pipermail/python-dev/2000-April/004761.html > will leave you always having to patch Python > distributions and build those (like Windows) that are commonly distributed > in binary form. What will happen if/when your BINARY_FRACTION opcode gets > used for something else in the 1.7 release? Then all your pyc > files will be broken, perhaps in very subtle ways... We are already committed to providing our own installer on Windows and Macintosh, because we need to give students a single download. The big problem is on Linux, where the Python interpreter is often critical to the OS. We also want something integrated with standard Python because we hope that some of our students will go on to do things other than physics with Python. Any of the following approaches would work for us, in roughly decreasing order of preference: 1. global olddivision (default to 1/2 = 0.5) 2. pragma floatdivision (same as import, but a new keyword) 3. import floatdivision 4. file extension (but this is very fragile) 5. BINARY_FRACTION opcode only (We do custom compilation in IDLE) I chose to submit a patch for (3) because it involves no inconvenience to others, and leaves the possibility of an even better solution open. > Also, while the patch provides a scoped solution, within a specific scope > there is no way to undo it (I suppose you could also recognize "import > intdivision"). What if, after executing "import floatdivision" you wanted > integer division later on (say, during some loop arithmetic)? Your patch > doesn't allow that behavior. We do not intend to make use of scoped changes at all, though others may. This is a way of making a language change available to us, without forcing it on others or breaking library modules. Changing the semantics of / constantly would be hideous programming practice. A purist would argue that there is no such thing as integer division. Personally, I think int(a/b) is an acceptable way to spell "divide a by b and truncate" for now, and I would strongly suggest adding "div" and "mod" operators in the future. Dave From skip@mojam.com (Skip Montanaro) Tue Jun 13 17:34:24 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Tue, 13 Jun 2000 11:34:24 -0500 (CDT) Subject: [Patches] import floatdivision # 1/2==0.5 In-Reply-To: References: <14662.17407.703078.679110@beluga.mojam.com> Message-ID: <14662.25232.391553.978516@beluga.mojam.com> >> It will almost certainly not pass muster with Guido Dave> Well, he called my previous proposal "kind of cute" and even "a Dave> fine starting point" :) Yes, it's a good starting point. Marc-Andre mentioned a "pragma" keyword, which would be a useful addition for other things. My complaint is basically that coopting import's semantics is wrong. Given that Guido thinks your proposal is a good place to start, I still think the best short-term approach is to teach your users about explicitly using floating point numbers in division where they want floating point results. (Short-term might be < six months. Once 1.6 is out, we can hash out possible syntax and experiment with implementations.) Dave> I chose to submit a patch for (3) because it involves no Dave> inconvenience to others, and leaves the possibility of an even Dave> better solution open. Well, sort of. If it was adopted, it would get used. Taking stuff out of the language is much harder than putting stuff into the language. If you adopt "import floatdivision" today, then later implement a more universally accepted pagma keyword, you'll be stuck with a wart on import's semantics for a couple revisions anyway, since it takes time to deprecate existing semantics. While it might be convenient for you and others today, I suspect you'll find it inconvenient later if you have to modify your code to work with a different implementation. >> Also, while the patch provides a scoped solution, within a specific >> scope there is no way to undo it (I suppose you could also recognize >> "import intdivision"). What if, after executing "import >> floatdivision" you wanted integer division later on (say, during some >> loop arithmetic)? Your patch doesn't allow that behavior. Dave> We do not intend to make use of scoped changes at all, though Dave> others may. This is a way of making a language change available Dave> to us, without forcing it on others or breaking library modules. Dave> Changing the semantics of / constantly would be hideous Dave> programming practice. That your proposal restricts the change to the current scope is a good thing, but immaterial to my argument. My point was that once your semantic change is enabled, you can't disable it until you happen to pop out to a wider scope. If you want to return floating point results for numeric purposes, integer division (whose properties are very useful for loop control), will be imprecise and can lead to subtle bugs which can be just as hard to detect as the truncating effects of integer division. -- Skip Montanaro, skip@mojam.com, http://www.mojam.com/, http://www.musi-cal.com/ On June 24th at 8AM, live your life for an hour as Ricky Byrdsong always lived his - run/walk in the Ricky Byrdsong Memorial 5K or just make a donation: https://www.SignmeupSports.com/Events/Index_Events.asp?EventID=1395 From fdrake@beopen.com Tue Jun 13 19:49:41 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 13 Jun 2000 14:49:41 -0400 (EDT) Subject: [Patches] Buglet in zipfile.py In-Reply-To: <394636F1.2F048A8A@interet.com> References: <394636F1.2F048A8A@interet.com> Message-ID: <14662.33349.689309.218335@cj42289-a.reston1.va.home.com> James C. Ahlstrom writes: > Thanks to Hubert Hoegl for finding this bug: Thanks; I've checked in the patch. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From R.Liebscher@gmx.de Wed Jun 14 12:41:24 2000 From: R.Liebscher@gmx.de (Rene Liebscher) Date: Wed, 14 Jun 2000 13:41:24 +0200 Subject: [Patches] Extension building on Win32 using Gnu C References: <20000607102724.E5559@ludwig.cnri.reston.va.us> Message-ID: <39476F64.A08FA321@gmx.de> This is a multi-part message in MIME format. --------------149A4E4C425D8C885F0B8B92 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Greg Ward wrote: > > > --- python.patched/dist/src/Include/object.h Tue May 30 10:34:33 2000 > [...] > > --- 107,120 ---- > > PyObject_HEAD \ > > int ob_size; /* Number of items in variable part */ > > > > ! typedef DL_CLASSIMPORT_BEG struct _object { > > PyObject_HEAD > > ! } DL_CLASSIMPORT_END PyObject; > > > > > > + typedef DL_CLASSIMPORT_BEG struct { > > + PyObject_VAR_HEAD > > + } DL_CLASSIMPORT_END PyVarObject; > > This strikes me as really weird style. Do those macros really *have* to > be wormed into the typedefs in that way? Isn't there a cleaner way to > do it? The Gnu-C compilers need these imports, there are two ways to do so struct name { ... } __declspec(dllimport); or struct __declspec(dllimport) name { ... }; Read also http://gcc.gnu.org/onlinedocs/gcc_4.html#SEC95 (paragraphs 3 and 4) __declspec is another name for __attribute They don't mention dllimport and types in the same context, I don't know why. (However, MS Visual C++ uses the same import statements for imports of classes from dll's. egcs 1.1.x uses __declspec() in MS compatible way.) In typedefs you could have unnamed structs, so I prefer the second. Even if it seems to work to have such a definition: typedef struct __declspec(import) { ... } name; If you don't have these imports in C-mode you get warnings and in C++ mode the compiler chrashs. Perhaps it would be useful to reduce it to a "#define DL_IMPORT_TYPE __decspec(dllimport)" instead of these two. (The attached patch realizes this idea, if you don't like the name replace it directly in the patch file.) ( I found this DL_CLASSIMPORT stuff (the only part of the patch I didn't found for myself) at the following website http://starship.python.net/crew/kernr/mingw32/Notes.html and I took it almost unchanged.) > And do these macros have to be used in extensions as well? Eg. if foo.c > supplies an extension foo, so is compiled/linked to foo.pyd (a DLL in > disguise), do I have to scatter foo.c with DL_CLASSIMPORT_{BEG,END} tags > to make it compile with Cygwin? No, you only need it, if these types are used in the interface of a dll you want to use (in this case you want to use python??.dll or should I better say, link against its import library libpython??.a ) (You probably had to use it in your file foo.h if you want let other people use your extension dll on a direct way. Which also means these people would need to link their modules against your dll.) kind regards Rene Liebscher --------------149A4E4C425D8C885F0B8B92 Content-Type: text/plain; charset=us-ascii; name="python_new.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="python_new.patch" diff -BcrN --minimal python/dist/src/Include/Python.h python.patched/dist/src/Include/Python.h *** python/dist/src/Include/Python.h Sun May 28 22:29:48 2000 --- python.patched/dist/src/Include/Python.h Wed Jun 14 12:45:18 2000 *************** *** 46,51 **** --- 46,59 ---- #define DL_EXPORT(RTYPE) RTYPE #endif + /* The next is used by the Gnu C-compilers on Win32, for all others + it will be defined as empty */ + /* Definition of every type, variables of which may be imported from DLL, + must be imported too */ + #ifndef DL_IMPORT_TYPE + #define DL_IMPORT_TYPE + #endif + #ifdef SYMANTEC__CFM68K__ #define UsingSharedLibs #endif diff -BcrN --minimal python/dist/src/Include/object.h python.patched/dist/src/Include/object.h *** python/dist/src/Include/object.h Mon Apr 24 17:40:45 2000 --- python.patched/dist/src/Include/object.h Wed Jun 14 12:45:18 2000 *************** *** 109,120 **** typedef struct _object { PyObject_HEAD ! } PyObject; typedef struct { PyObject_VAR_HEAD - } PyVarObject; /* Type objects contain a string containing the type name (to help somewhat --- 109,120 ---- typedef struct _object { PyObject_HEAD ! } DL_IMPORT_TYPE PyObject; typedef struct { PyObject_VAR_HEAD + } DL_IMPORT_TYPE PyVarObject; /* Type objects contain a string containing the type name (to help somewhat *************** *** 170,176 **** unaryfunc nb_float; unaryfunc nb_oct; unaryfunc nb_hex; ! } PyNumberMethods; typedef struct { inquiry sq_length; --- 170,176 ---- unaryfunc nb_float; unaryfunc nb_oct; unaryfunc nb_hex; ! } DL_IMPORT_TYPE PyNumberMethods; typedef struct { inquiry sq_length; *************** *** 181,200 **** intobjargproc sq_ass_item; intintobjargproc sq_ass_slice; objobjproc sq_contains; ! } PySequenceMethods; typedef struct { inquiry mp_length; binaryfunc mp_subscript; objobjargproc mp_ass_subscript; ! } PyMappingMethods; typedef struct { getreadbufferproc bf_getreadbuffer; getwritebufferproc bf_getwritebuffer; getsegcountproc bf_getsegcount; getcharbufferproc bf_getcharbuffer; ! } PyBufferProcs; typedef void (*destructor) Py_PROTO((PyObject *)); --- 181,200 ---- intobjargproc sq_ass_item; intintobjargproc sq_ass_slice; objobjproc sq_contains; ! } DL_IMPORT_TYPE PySequenceMethods; typedef struct { inquiry mp_length; binaryfunc mp_subscript; objobjargproc mp_ass_subscript; ! } DL_IMPORT_TYPE PyMappingMethods; typedef struct { getreadbufferproc bf_getreadbuffer; getwritebufferproc bf_getwritebuffer; getsegcountproc bf_getsegcount; getcharbufferproc bf_getcharbuffer; ! } DL_IMPORT_TYPE PyBufferProcs; typedef void (*destructor) Py_PROTO((PyObject *)); *************** *** 256,262 **** int tp_maxalloc; struct _typeobject *tp_next; #endif ! } PyTypeObject; extern DL_IMPORT(PyTypeObject) PyType_Type; /* The type of type objects */ --- 256,262 ---- int tp_maxalloc; struct _typeobject *tp_next; #endif ! } DL_IMPORT_TYPE PyTypeObject; extern DL_IMPORT(PyTypeObject) PyType_Type; /* The type of type objects */ diff -BcrN --minimal python/dist/src/PC/config.h python.patched/dist/src/PC/config.h *** python/dist/src/PC/config.h Wed May 10 15:25:32 2000 --- python.patched/dist/src/PC/config.h Wed Jun 14 12:45:18 2000 *************** *** 42,47 **** --- 42,78 ---- #define PREFIX "" #define EXEC_PREFIX "" + /* egcs/gnu-win32 defines __GNUC__ and _WIN32 */ + + #if defined(__GNUC__) && defined(_WIN32) + #define NT /* NT is obsolete - please use MS_WIN32 instead */ + #define MS_WIN32 + #define MS_WINDOWS + #define HAVE_CLOCK + #define HAVE_STRFTIME + #define HAVE_STRERROR + #define NT_THREADS + #define WITH_THREAD + #define WORD_BIT 32 + #define HAVE_LONG_LONG 1 + #define LONG_LONG long long + #define PYTHONPATH ".\\DLLs;.\\lib;.\\lib\\plat-win;.\\lib\\lib-tk" + + #ifndef MS_NO_COREDLL + #define MS_COREDLL /* Python core is in a DLL */ + #ifndef USE_DL_EXPORT + #define USE_DL_IMPORT + #endif /* !USE_DL_EXPORT */ + #endif /* !MS_NO_COREDLL */ + + #ifdef USE_DL_IMPORT + #define DL_IMPORT(sym) __declspec(dllimport) sym + /* Definition of every type, variables of which may be imported from DLL, + must be imported too */ + #define DL_IMPORT_TYPE __declspec(dllimport) + #endif /* USE_DL_IMPORT */ + #endif /* (defined(__GNUC__) && defined(_WIN32)) */ + /* Microsoft C defines _MSC_VER */ #ifdef _MSC_VER --------------149A4E4C425D8C885F0B8B92-- From nascheme@enme.ucalgary.ca Wed Jun 14 19:38:18 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 14 Jun 2000 12:38:18 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) Message-ID: <20000614123818.A8975@acs.ucalgary.ca> --4Ckj6UjgE2iN1+kY Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This patch adds the type methods recurse and clear necessary for my GC patch. It is straightforward so hopefully it can be applied right away. Neil --4Ckj6UjgE2iN1+kY Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="recurse.diff" Index: 0.9/Include/object.h *** 0.9/Include/object.h Tue, 25 Apr 2000 17:33:19 -0600 nas (python/o/18_object.h 1.1 644) --- 0.9(w)/Include/object.h Wed, 14 Jun 2000 12:26:41 -0600 nas (python/o/18_object.h 1.1 644) *************** *** 145,150 **** --- 145,152 ---- typedef int (*getsegcountproc) Py_PROTO((PyObject *, int *)); typedef int (*getcharbufferproc) Py_PROTO((PyObject *, int, const char **)); typedef int (*objobjproc) Py_PROTO((PyObject *, PyObject *)); + typedef int (*visitproc) Py_PROTO((PyObject *, void *)); + typedef int (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); typedef struct { binaryfunc nb_add; *************** *** 243,251 **** char *tp_doc; /* Documentation string */ /* More spares */ - long tp_xxx5; - long tp_xxx6; long tp_xxx7; long tp_xxx8; --- 245,257 ---- char *tp_doc; /* Documentation string */ + /* call function for all accessible objects */ + recurseproc tp_recurse; + + /* delete references to contained objects */ + inquiry tp_clear; + /* More spares */ long tp_xxx7; long tp_xxx8; Index: 0.9/Objects/classobject.c *** 0.9/Objects/classobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/16_classobjec 1.1.2.2 644) --- 0.9(w)/Objects/classobject.c Wed, 14 Jun 2000 12:27:59 -0600 nas (python/E/16_classobjec 1.1.2.2 644) *************** *** 387,392 **** --- 387,404 ---- return res; } + static int + class_recurse(PyClassObject *o, visitproc visit, void *closure) + { + if (o->cl_bases) visit(o->cl_bases, closure); + if (o->cl_dict) visit(o->cl_dict, closure); + if (o->cl_name) visit(o->cl_name, closure); + if (o->cl_getattr) visit(o->cl_getattr, closure); + if (o->cl_setattr) visit(o->cl_setattr, closure); + if (o->cl_delattr) visit(o->cl_delattr, closure); + return 1; + } + PyTypeObject PyClass_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, *************** *** 407,412 **** --- 419,428 ---- (reprfunc)class_str, /*tp_str*/ (getattrofunc)class_getattr, /*tp_getattro*/ (setattrofunc)class_setattr, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)class_recurse, /* tp_recurse */ }; int *************** *** 849,854 **** --- 865,878 ---- return outcome; } + static int + instance_recurse(PyInstanceObject *o, visitproc visit, void *closure) + { + if (o->in_class) visit((PyObject *)(o->in_class), closure); + if (o->in_dict) visit(o->in_dict, closure); + return 1; + } + static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; static int *************** *** 1472,1478 **** (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags */ }; --- 1496,1504 ---- (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ ! 0, /* tp_doc */ ! (recurseproc)instance_recurse, /* tp_recurse */ }; *************** *** 1662,1667 **** --- 1688,1702 ---- return x ^ y; } + static int + instancemethod_recurse(PyMethodObject *im, visitproc visit, void *closure) + { + if (im->im_func) visit(im->im_func, closure); + if (im->im_self) visit(im->im_self, closure); + if (im->im_class) visit(im->im_class, closure); + return 1; + } + PyTypeObject PyMethod_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, *************** *** 1682,1687 **** --- 1717,1726 ---- 0, /*tp_str*/ (getattrofunc)instancemethod_getattr, /*tp_getattro*/ 0, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)instancemethod_recurse, /* tp_recurse */ }; /* Clear out the free list */ Index: 0.9/Objects/dictobject.c *** 0.9/Objects/dictobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/19_dictobject 1.1.2.1 644) --- 0.9(w)/Objects/dictobject.c Wed, 14 Jun 2000 12:28:08 -0600 nas (python/E/19_dictobject 1.1.2.1 644) *************** *** 1038,1043 **** --- 1038,1068 ---- return Py_None; } + static int + dict_recurse(PyObject *op, visitproc visit, void *closure) + { + int i = 0; + PyObject *pk; + PyObject *pv; + + while (PyDict_Next(op, &i, &pk, &pv)) { + if (!visit(pk, closure)) { + return 0; + } + if (!visit(pv, closure)) { + return 0; + } + } + return 1; + } + + static int + dict_tp_clear(PyObject *op) + { + PyDict_Clear(op); + return 0; + } + static PyMethodDef mapp_methods[] = { {"has_key", (PyCFunction)dict_has_key, METH_VARARGS}, {"keys", (PyCFunction)dict_keys}, *************** *** 1073,1078 **** --- 1098,1113 ---- 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ &dict_as_mapping, /*tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)dict_recurse, /* tp_recurse */ + (inquiry)dict_tp_clear, /* tp_clear */ }; /* For backward compatibility with old dictionary interface */ Index: 0.9/Objects/funcobject.c *** 0.9/Objects/funcobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/23_funcobject 1.1.2.2 644) --- 0.9(w)/Objects/funcobject.c Wed, 14 Jun 2000 12:28:19 -0600 nas (python/E/23_funcobject 1.1.2.2 644) *************** *** 239,244 **** --- 239,255 ---- return h; } + static int + func_recurse(PyFunctionObject *f, visitproc visit, void *closure) + { + if (f->func_code) visit(f->func_code, closure); + if (f->func_globals) visit(f->func_globals, closure); + if (f->func_defaults) visit(f->func_defaults, closure); + if (f->func_doc) visit(f->func_doc, closure); + if (f->func_name) visit(f->func_name, closure); + return 1; + } + PyTypeObject PyFunction_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, *************** *** 255,258 **** --- 266,277 ---- 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)func_hash, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /* tp_doc */ + (recurseproc)func_recurse, /* tp_recurse */ }; Index: 0.9/Objects/listobject.c *** 0.9/Objects/listobject.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/25_listobject 1.1.2.3 644) --- 0.9(w)/Objects/listobject.c Wed, 14 Jun 2000 12:28:32 -0600 nas (python/E/25_listobject 1.1.2.3 644) *************** *** 1423,1428 **** --- 1423,1449 ---- return NULL; } + static int + list_recurse(PyListObject *o, visitproc visit, void *closure) + { + int i; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL && !visit(x, closure)) + return 0; + } + return 1; + } + + static int + list_clear(PyListObject *lp) + { + (void) PyList_SetSlice((PyObject *)lp, 0, lp->ob_size, 0); + return 0; + } + static char append_doc[] = "L.append(object) -- append object to end"; static char extend_doc[] = *************** *** 1489,1494 **** --- 1510,1525 ---- 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)list_recurse, /* tp_recurse */ + (inquiry)list_clear, /* tp_clear */ }; *************** *** 1557,1561 **** --- 1588,1601 ---- 0, /*tp_as_number*/ &immutable_list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)list_recurse, /* tp_recurse */ }; Index: 0.9/Objects/tupleobject.c *** 0.9/Objects/tupleobject.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/33_tupleobjec 1.1.2.3 644) --- 0.9(w)/Objects/tupleobject.c Wed, 14 Jun 2000 12:28:40 -0600 nas (python/E/33_tupleobjec 1.1.2.3 644) *************** *** 420,425 **** --- 420,439 ---- return (PyObject *) np; } + static int + tuplerecurse(PyTupleObject *o, visitproc visit, void *closure) + { + int i; + PyObject *x; + + for (i = o->ob_size; --i >= 0; ) { + x = o->ob_item[i]; + if (x != NULL && !visit(x, closure)) + return 0; + } + return 1; + } + static PySequenceMethods tuple_as_sequence = { (inquiry)tuplelength, /*sq_length*/ (binaryfunc)tupleconcat, /*sq_concat*/ *************** *** 447,452 **** --- 461,474 ---- &tuple_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)tuplehash, /*tp_hash*/ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + (recurseproc)tuplerecurse, /* tp_recurse */ }; /* The following function breaks the notion that tuples are immutable: --4Ckj6UjgE2iN1+kY-- From nascheme@enme.ucalgary.ca Wed Jun 14 20:15:07 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 14 Jun 2000 13:15:07 -0600 Subject: [Patches] GC infrastructure patch 2 (type changes) Message-ID: <20000614131507.A16847@acs.ucalgary.ca> --VbJkn9YxBvnuCH5J Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This patch modifies the type structures of objects that participate in GC. The object's tp_basicsize is increased when GC is enabled. GC information is prefixed to the object to maintain binary compatibility. GC objects also define the tp_flag Py_TPFLAGS_GC. Can someone think of a better alternative for the name WITH_CYCLE_GC? I don't like it. Neil --VbJkn9YxBvnuCH5J Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="type.diff" Index: recurse.1/Include/object.h *** recurse.1/Include/object.h Wed, 14 Jun 2000 12:32:15 -0600 nas (python/o/18_object.h 1.1.2.1 644) --- recurse.1(w)/Include/object.h Wed, 14 Jun 2000 12:46:50 -0600 nas (python/o/18_object.h 1.1.2.1 644) *************** *** 325,330 **** --- 325,337 ---- /* PySequenceMethods contains sq_contains */ #define Py_TPFLAGS_HAVE_SEQUENCE_IN (1L<<1) + /* Objects which participate in garbage collection (see objimp.h) */ + #ifdef WITH_CYCLE_GC + #define Py_TPFLAGS_GC (1L<<2) + #else + #define Py_TPFLAGS_GC 0 + #endif + #define Py_TPFLAGS_DEFAULT (Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_SEQUENCE_IN) Index: recurse.1/Include/objimpl.h *** recurse.1/Include/objimpl.h Mon, 08 May 2000 12:24:03 -0600 nas (python/o/19_objimpl.h 1.1.2.1 644) --- recurse.1(w)/Include/objimpl.h Wed, 14 Jun 2000 12:47:39 -0600 nas (python/o/19_objimpl.h 1.1.2.1 644) *************** *** 234,239 **** --- 234,245 ---- the 1st step is performed automatically for you, so in a C++ class constructor you would start directly with PyObject_Init/InitVar. */ + + + #ifndef WITH_CYCLE_GC + #define PyGC_INFO_SIZE 0 + #endif + #ifdef __cplusplus } #endif Index: recurse.1/Objects/classobject.c *** recurse.1/Objects/classobject.c Wed, 14 Jun 2000 12:32:15 -0600 nas (python/E/16_classobjec 1.1.2.2.1.1 644) --- recurse.1(w)/Objects/classobject.c Wed, 14 Jun 2000 12:46:30 -0600 nas (python/E/16_classobjec 1.1.2.2.1.1 644) *************** *** 403,409 **** PyObject_HEAD_INIT(&PyType_Type) 0, "class", ! sizeof(PyClassObject), 0, (destructor)class_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ --- 403,409 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "class", ! sizeof(PyClassObject) + PyGC_INFO_SIZE, 0, (destructor)class_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ *************** *** 420,426 **** (getattrofunc)class_getattr, /*tp_getattro*/ (setattrofunc)class_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)class_recurse, /* tp_recurse */ }; --- 420,426 ---- (getattrofunc)class_getattr, /*tp_getattro*/ (setattrofunc)class_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)class_recurse, /* tp_recurse */ }; *************** *** 1479,1485 **** PyObject_HEAD_INIT(&PyType_Type) 0, "instance", ! sizeof(PyInstanceObject), 0, (destructor)instance_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ --- 1479,1485 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "instance", ! sizeof(PyInstanceObject) + PyGC_INFO_SIZE, 0, (destructor)instance_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ *************** *** 1496,1502 **** (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)instance_recurse, /* tp_recurse */ }; --- 1496,1502 ---- (getattrofunc)instance_getattr, /*tp_getattro*/ (setattrofunc)instance_setattr, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)instance_recurse, /* tp_recurse */ }; *************** *** 1701,1707 **** PyObject_HEAD_INIT(&PyType_Type) 0, "instance method", ! sizeof(PyMethodObject), 0, (destructor)instancemethod_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ --- 1701,1707 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "instance method", ! sizeof(PyMethodObject) + PyGC_INFO_SIZE, 0, (destructor)instancemethod_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ *************** *** 1718,1724 **** (getattrofunc)instancemethod_getattr, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)instancemethod_recurse, /* tp_recurse */ }; --- 1718,1724 ---- (getattrofunc)instancemethod_getattr, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)instancemethod_recurse, /* tp_recurse */ }; Index: recurse.1/Objects/dictobject.c *** recurse.1/Objects/dictobject.c Wed, 14 Jun 2000 12:32:15 -0600 nas (python/E/19_dictobject 1.1.2.1.1.1 644) --- recurse.1(w)/Objects/dictobject.c Wed, 14 Jun 2000 12:46:30 -0600 nas (python/E/19_dictobject 1.1.2.1.1.1 644) *************** *** 1087,1093 **** PyObject_HEAD_INIT(&PyType_Type) 0, "dictionary", ! sizeof(dictobject), 0, (destructor)dict_dealloc, /*tp_dealloc*/ (printfunc)dict_print, /*tp_print*/ --- 1087,1093 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "dictionary", ! sizeof(dictobject) + PyGC_INFO_SIZE, 0, (destructor)dict_dealloc, /*tp_dealloc*/ (printfunc)dict_print, /*tp_print*/ *************** *** 1104,1110 **** 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)dict_recurse, /* tp_recurse */ (inquiry)dict_tp_clear, /* tp_clear */ --- 1104,1110 ---- 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)dict_recurse, /* tp_recurse */ (inquiry)dict_tp_clear, /* tp_clear */ Index: recurse.1/Objects/funcobject.c *** recurse.1/Objects/funcobject.c Wed, 14 Jun 2000 12:32:15 -0600 nas (python/E/23_funcobject 1.1.2.2.1.1 644) --- recurse.1(w)/Objects/funcobject.c Wed, 14 Jun 2000 12:46:30 -0600 nas (python/E/23_funcobject 1.1.2.2.1.1 644) *************** *** 254,260 **** PyObject_HEAD_INIT(&PyType_Type) 0, "function", ! sizeof(PyFunctionObject), 0, (destructor)func_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ --- 254,260 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "function", ! sizeof(PyFunctionObject) + PyGC_INFO_SIZE, 0, (destructor)func_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ *************** *** 271,277 **** 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)func_recurse, /* tp_recurse */ }; --- 271,277 ---- 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ 0, /* tp_doc */ (recurseproc)func_recurse, /* tp_recurse */ }; Index: recurse.1/Objects/listobject.c *** recurse.1/Objects/listobject.c Wed, 14 Jun 2000 12:32:15 -0600 nas (python/E/25_listobject 1.1.2.3.1.1 644) --- recurse.1(w)/Objects/listobject.c Wed, 14 Jun 2000 13:01:53 -0600 nas (python/E/25_listobject 1.1.2.3.1.1 644) *************** *** 71,77 **** return PyErr_NoMemory(); } /* PyObject_NewVar is inlined */ ! op = (PyListObject *) PyObject_MALLOC(sizeof(PyListObject)); if (op == NULL) { return PyErr_NoMemory(); } --- 71,78 ---- return PyErr_NoMemory(); } /* PyObject_NewVar is inlined */ ! op = (PyListObject *) PyObject_MALLOC(sizeof(PyListObject) ! + PyGC_INFO_SIZE); if (op == NULL) { return PyErr_NoMemory(); } *************** *** 1499,1505 **** PyObject_HEAD_INIT(&PyType_Type) 0, "list", ! sizeof(PyListObject), 0, (destructor)list_dealloc, /*tp_dealloc*/ (printfunc)list_print, /*tp_print*/ --- 1500,1506 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "list", ! sizeof(PyListObject) + PyGC_INFO_SIZE, 0, (destructor)list_dealloc, /*tp_dealloc*/ (printfunc)list_print, /*tp_print*/ *************** *** 1516,1522 **** 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ (recurseproc)list_recurse, /* tp_recurse */ (inquiry)list_clear, /* tp_clear */ --- 1517,1523 ---- 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */ 0, /* tp_doc */ (recurseproc)list_recurse, /* tp_recurse */ (inquiry)list_clear, /* tp_clear */ *************** *** 1577,1583 **** PyObject_HEAD_INIT(&PyType_Type) 0, "list (immutable, during sort)", ! sizeof(PyListObject), 0, 0, /*tp_dealloc*/ /* Cannot happen */ (printfunc)list_print, /*tp_print*/ --- 1578,1584 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "list (immutable, during sort)", ! sizeof(PyListObject) + PyGC_INFO_SIZE, 0, 0, /*tp_dealloc*/ /* Cannot happen */ (printfunc)list_print, /*tp_print*/ *************** *** 1594,1600 **** 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ (recurseproc)list_recurse, /* tp_recurse */ }; --- 1595,1601 ---- 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */ 0, /* tp_doc */ (recurseproc)list_recurse, /* tp_recurse */ }; Index: recurse.1/Objects/tupleobject.c *** recurse.1/Objects/tupleobject.c Wed, 14 Jun 2000 12:32:15 -0600 nas (python/E/33_tupleobjec 1.1.2.3.1.1 644) --- recurse.1(w)/Objects/tupleobject.c Wed, 14 Jun 2000 13:13:03 -0600 nas (python/E/33_tupleobjec 1.1.2.3.1.1 644) *************** *** 93,99 **** int nbytes = size * sizeof(PyObject *); /* Check for overflow */ if (nbytes / sizeof(PyObject *) != (size_t)size || ! (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *)) <= 0) { return PyErr_NoMemory(); --- 93,100 ---- int nbytes = size * sizeof(PyObject *); /* Check for overflow */ if (nbytes / sizeof(PyObject *) != (size_t)size || ! (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *) ! + PyGC_INFO_SIZE) <= 0) { return PyErr_NoMemory(); *************** *** 449,455 **** PyObject_HEAD_INIT(&PyType_Type) 0, "tuple", ! sizeof(PyTupleObject) - sizeof(PyObject *), sizeof(PyObject *), (destructor)tupledealloc, /*tp_dealloc*/ (printfunc)tupleprint, /*tp_print*/ --- 450,456 ---- PyObject_HEAD_INIT(&PyType_Type) 0, "tuple", ! sizeof(PyTupleObject) - sizeof(PyObject *) + PyGC_INFO_SIZE, sizeof(PyObject *), (destructor)tupledealloc, /*tp_dealloc*/ (printfunc)tupleprint, /*tp_print*/ *************** *** 466,472 **** 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ (recurseproc)tuplerecurse, /* tp_recurse */ }; --- 467,473 ---- 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /* tp_flags */ 0, /* tp_doc */ (recurseproc)tuplerecurse, /* tp_recurse */ }; *************** *** 554,561 **** #endif { sv = (PyTupleObject *) ! PyObject_REALLOC((char *)v, ! sizeof(PyTupleObject) + newsize * sizeof(PyObject *)); *pv = (PyObject *) sv; if (sv == NULL) { PyObject_DEL(v); --- 555,563 ---- #endif { sv = (PyTupleObject *) ! PyObject_REALLOC((char *)v, sizeof(PyTupleObject) ! + PyGC_INFO_SIZE ! + newsize * sizeof(PyObject *)); *pv = (PyObject *) sv; if (sv == NULL) { PyObject_DEL(v); --VbJkn9YxBvnuCH5J-- From nascheme@enme.ucalgary.ca Wed Jun 14 20:39:00 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 14 Jun 2000 13:39:00 -0600 Subject: [Patches] GC patch 3 (GC disabled) Message-ID: <20000614133900.A22867@acs.ucalgary.ca> --ZGiS0Q5IWpPtfppv Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This patch adds all the changes for when WITH_CYCLE_GC is undefined (ie. GC is disabled). This patch does not modify any behavior (its just macros). Neil --ZGiS0Q5IWpPtfppv Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="nogc.diff" Index: type.1/Include/objimpl.h *** type.1/Include/objimpl.h Wed, 14 Jun 2000 13:16:32 -0600 nas (python/o/19_objimpl.h 1.1.2.1.1.1 644) --- type.1(w)/Include/objimpl.h Wed, 14 Jun 2000 13:29:58 -0600 nas (python/o/19_objimpl.h 1.1.2.1.1.1 644) *************** *** 234,243 **** --- 234,261 ---- the 1st step is performed automatically for you, so in a C++ class constructor you would start directly with PyObject_Init/InitVar. */ + /* + * Garbage Collection Support + * ========================== + */ + /* To make a new object participate in garbage collection use + PyObject_{New, VarNew, Del} to manage the memory. Set the type flag + Py_TPFLAGS_GC and define the type method tp_recurse. You should also + add the method tp_clear if your object is mutable. Include + PyGC_INFO_SIZE in the calculation of tp_basicsize. Call + PyObject_GC_Init after the pointers followed by tp_recurse become + valid (usually just before returning the object from the allocation + method. Call PyObject_GC_Fini before those pointers become invalid + (usually at the top of the deallocation method). */ #ifndef WITH_CYCLE_GC + #define PyGC_INFO_SIZE 0 + #define PyObject_GC_DEL PyObject_DEL + #define PyObject_GC_Init(op) + #define PyObject_GC_Fini(op) + #endif #ifdef __cplusplus Index: type.1/Modules/cPickle.c *** type.1/Modules/cPickle.c Mon, 05 Jun 2000 00:51:28 -0600 nas (python/C/27_cPickle.c 1.1.2.2 644) --- type.1(w)/Modules/cPickle.c Wed, 14 Jun 2000 13:18:46 -0600 nas (python/C/27_cPickle.c 1.1.2.2 644) *************** *** 2893,2899 **** Py_DECREF(inst); goto err; } ! return (PyObject *)inst; } Py_DECREF(__getinitargs__); --- 2893,2899 ---- Py_DECREF(inst); goto err; } ! PyObject_GC_Init((PyObject *)inst); return (PyObject *)inst; } Py_DECREF(__getinitargs__); Index: type.1/Modules/newmodule.c *** type.1/Modules/newmodule.c Mon, 08 May 2000 12:24:03 -0600 nas (python/D/13_newmodule. 1.1.2.1 644) --- type.1(w)/Modules/newmodule.c Wed, 14 Jun 2000 13:18:46 -0600 nas (python/D/13_newmodule. 1.1.2.1 644) *************** *** 56,61 **** --- 56,62 ---- Py_INCREF(dict); inst->in_class = (PyClassObject *)klass; inst->in_dict = dict; + PyObject_GC_Init((PyObject *)inst); return (PyObject *)inst; } Index: type.1/Objects/classobject.c *** type.1/Objects/classobject.c Wed, 14 Jun 2000 13:16:32 -0600 nas (python/E/16_classobjec 1.1.2.2.1.2 644) --- type.1(w)/Objects/classobject.c Wed, 14 Jun 2000 13:33:31 -0600 nas (python/E/16_classobjec 1.1.2.2.1.2 644) *************** *** 132,137 **** --- 132,138 ---- Py_XINCREF(op->cl_getattr); Py_XINCREF(op->cl_setattr); Py_XINCREF(op->cl_delattr); + PyObject_GC_Init((PyObject *)op); return (PyObject *) op; } *************** *** 141,153 **** class_dealloc(op) PyClassObject *op; { Py_DECREF(op->cl_bases); Py_DECREF(op->cl_dict); Py_XDECREF(op->cl_name); Py_XDECREF(op->cl_getattr); Py_XDECREF(op->cl_setattr); Py_XDECREF(op->cl_delattr); ! PyObject_DEL(op); } static PyObject * --- 142,155 ---- class_dealloc(op) PyClassObject *op; { + PyObject_GC_Fini((PyObject *)op); Py_DECREF(op->cl_bases); Py_DECREF(op->cl_dict); Py_XDECREF(op->cl_name); Py_XDECREF(op->cl_getattr); Py_XDECREF(op->cl_setattr); Py_XDECREF(op->cl_delattr); ! PyObject_GC_DEL(op); } static PyObject * *************** *** 467,472 **** --- 469,475 ---- Py_INCREF(class); inst->in_class = (PyClassObject *)class; inst->in_dict = PyDict_New(); + PyObject_GC_Init((PyObject *)inst); if (inst->in_dict == NULL) { Py_DECREF(inst); return NULL; *************** *** 514,524 **** PyObject *error_type, *error_value, *error_traceback; PyObject *del; static PyObject *delstr; /* Call the __del__ method if it exists. First temporarily revive the object and save the current exception, if any. */ #ifdef Py_TRACE_REFS /* much too complicated if Py_TRACE_REFS defined */ - extern long _Py_RefTotal; inst->ob_type = &PyInstance_Type; _Py_NewReference((PyObject *)inst); _Py_RefTotal--; /* compensate for increment in NEWREF */ --- 517,528 ---- PyObject *error_type, *error_value, *error_traceback; PyObject *del; static PyObject *delstr; + extern long _Py_RefTotal; + PyObject_GC_Fini((PyObject *)inst); /* Call the __del__ method if it exists. First temporarily revive the object and save the current exception, if any. */ #ifdef Py_TRACE_REFS /* much too complicated if Py_TRACE_REFS defined */ inst->ob_type = &PyInstance_Type; _Py_NewReference((PyObject *)inst); _Py_RefTotal--; /* compensate for increment in NEWREF */ *************** *** 566,571 **** --- 570,576 ---- #ifdef COUNT_ALLOCS inst->ob_type->tp_free--; #endif + PyObject_GC_Init((PyObject *)inst); return; /* __del__ added a reference; don't delete now */ } #ifdef Py_TRACE_REFS *************** *** 577,583 **** #endif /* Py_TRACE_REFS */ Py_DECREF(inst->in_class); Py_XDECREF(inst->in_dict); ! PyObject_DEL(inst); } static PyObject * --- 582,588 ---- #endif /* Py_TRACE_REFS */ Py_DECREF(inst->in_class); Py_XDECREF(inst->in_dict); ! PyObject_GC_DEL(inst); } static PyObject * *************** *** 1537,1542 **** --- 1542,1548 ---- im->im_self = self; Py_INCREF(class); im->im_class = class; + PyObject_GC_Init((PyObject *)im); return (PyObject *)im; } *************** *** 1612,1617 **** --- 1618,1624 ---- instancemethod_dealloc(im) register PyMethodObject *im; { + PyObject_GC_Fini((PyObject *)im); Py_DECREF(im->im_func); Py_XDECREF(im->im_self); Py_DECREF(im->im_class); Index: type.1/Objects/dictobject.c *** type.1/Objects/dictobject.c Wed, 14 Jun 2000 13:16:32 -0600 nas (python/E/19_dictobject 1.1.2.1.1.2 644) --- type.1(w)/Objects/dictobject.c Wed, 14 Jun 2000 13:18:46 -0600 nas (python/E/19_dictobject 1.1.2.1.1.2 644) *************** *** 129,134 **** --- 129,135 ---- mp->ma_table = NULL; mp->ma_fill = 0; mp->ma_used = 0; + PyObject_GC_Init((PyObject *)mp); return (PyObject *)mp; } *************** *** 481,486 **** --- 482,488 ---- register int i; register dictentry *ep; Py_TRASHCAN_SAFE_BEGIN(mp) + PyObject_GC_Fini((PyObject *)mp); for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) { if (ep->me_key != NULL) { Py_DECREF(ep->me_key); *************** *** 491,497 **** } if (mp->ma_table != NULL) PyMem_DEL(mp->ma_table); ! PyObject_DEL(mp); Py_TRASHCAN_SAFE_END(mp) } --- 493,499 ---- } if (mp->ma_table != NULL) PyMem_DEL(mp->ma_table); ! PyObject_GC_DEL(mp); Py_TRASHCAN_SAFE_END(mp) } Index: type.1/Objects/funcobject.c *** type.1/Objects/funcobject.c Wed, 14 Jun 2000 13:16:32 -0600 nas (python/E/23_funcobject 1.1.2.2.1.2 644) --- type.1(w)/Objects/funcobject.c Wed, 14 Jun 2000 13:18:46 -0600 nas (python/E/23_funcobject 1.1.2.2.1.2 644) *************** *** 63,68 **** --- 63,69 ---- Py_INCREF(doc); op->func_doc = doc; } + PyObject_GC_Init((PyObject *)op); return (PyObject *)op; } *************** *** 186,197 **** func_dealloc(op) PyFunctionObject *op; { Py_DECREF(op->func_code); Py_DECREF(op->func_globals); Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc); ! PyObject_DEL(op); } static PyObject* --- 187,199 ---- func_dealloc(op) PyFunctionObject *op; { + PyObject_GC_Fini((PyObject *)op); Py_DECREF(op->func_code); Py_DECREF(op->func_globals); Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc); ! PyObject_GC_DEL(op); } static PyObject* Index: type.1/Objects/listobject.c *** type.1/Objects/listobject.c Wed, 14 Jun 2000 13:16:32 -0600 nas (python/E/25_listobject 1.1.2.3.1.2 644) --- type.1(w)/Objects/listobject.c Wed, 14 Jun 2000 13:21:44 -0600 nas (python/E/25_listobject 1.1.2.3.1.2 644) *************** *** 89,94 **** --- 89,95 ---- PyObject_INIT_VAR(op, &PyList_Type, size); for (i = 0; i < size; i++) op->ob_item[i] = NULL; + PyObject_GC_Init((PyObject *)op); return (PyObject *) op; } *************** *** 216,221 **** --- 217,223 ---- { int i; Py_TRASHCAN_SAFE_BEGIN(op) + PyObject_GC_Fini((PyObject *)op); if (op->ob_item != NULL) { /* Do it backwards, for Christian Tismer. There's a simple test case where somehow this reduces *************** *** 227,233 **** } PyMem_FREE(op->ob_item); } ! PyObject_DEL(op); Py_TRASHCAN_SAFE_END(op) } --- 229,235 ---- } PyMem_FREE(op->ob_item); } ! PyObject_GC_DEL(op); Py_TRASHCAN_SAFE_END(op) } Index: type.1/Objects/tupleobject.c *** type.1/Objects/tupleobject.c Wed, 14 Jun 2000 13:16:32 -0600 nas (python/E/33_tupleobjec 1.1.2.3.1.2 644) --- type.1(w)/Objects/tupleobject.c Wed, 14 Jun 2000 13:22:30 -0600 nas (python/E/33_tupleobjec 1.1.2.3.1.2 644) *************** *** 103,109 **** op = (PyTupleObject *) PyObject_MALLOC(nbytes); if (op == NULL) return PyErr_NoMemory(); - PyObject_INIT_VAR(op, &PyTuple_Type, size); } for (i = 0; i < size; i++) --- 103,108 ---- *************** *** 115,120 **** --- 114,120 ---- Py_INCREF(op); /* extra INCREF so that this is never freed */ } #endif + PyObject_GC_Init((PyObject *)op); return (PyObject *) op; } *************** *** 181,186 **** --- 181,187 ---- register int i; register int len = op->ob_size; Py_TRASHCAN_SAFE_BEGIN(op) + PyObject_GC_Fini((PyObject *)op); if (len > 0) { i = len; while (--i >= 0) *************** *** 194,200 **** } #endif } ! PyObject_DEL(op); done: Py_TRASHCAN_SAFE_END(op) } --- 195,201 ---- } #endif } ! PyObject_GC_DEL(op); done: Py_TRASHCAN_SAFE_END(op) } *************** *** 560,566 **** + newsize * sizeof(PyObject *)); *pv = (PyObject *) sv; if (sv == NULL) { ! PyObject_DEL(v); PyErr_NoMemory(); return -1; } --- 561,568 ---- + newsize * sizeof(PyObject *)); *pv = (PyObject *) sv; if (sv == NULL) { ! PyObject_GC_Init((PyObject *)v); ! PyObject_GC_DEL(v); PyErr_NoMemory(); return -1; } *************** *** 575,580 **** --- 577,583 ---- sv->ob_item[i - sizediff] = NULL; } } + PyObject_GC_Init((PyObject *)sv); sv->ob_size = newsize; return 0; } *************** *** 595,601 **** while (p) { q = p; p = (PyTupleObject *)(p->ob_item[0]); ! PyObject_DEL(q); } } #endif --- 598,604 ---- while (p) { q = p; p = (PyTupleObject *)(p->ob_item[0]); ! PyObject_GC_DEL(q); } } #endif --ZGiS0Q5IWpPtfppv-- From nascheme@enme.ucalgary.ca Wed Jun 14 21:24:10 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 14 Jun 2000 14:24:10 -0600 Subject: [Patches] GC patch 4 (gc enabled) Message-ID: <20000614142410.A25920@acs.ucalgary.ca> --vtzGhvizbBRQ85DL Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This final GC patch adds the changes necessary for enabled GC. I expect this patch to be the most controversial. However, all the changes to the interpreter are surrounded by ifdefs (except for a PyObject_GC_DEL change that I missed). The only new ABIs introduced are _PyGC_Insert and _PyGC_Remove. Extension modules compiled with GC enabled will need these functions (even if they don't do anything). New APIs were introduced in the last patches. I am abusing Setup.thread to automaticly include the gc module when GC is enabled. Perhaps the gc module should go somewhere else. Neil --vtzGhvizbBRQ85DL Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="gc.diff" Index: nogc.1/config.h.in *** nogc.1/config.h.in Mon, 05 Jun 2000 00:51:28 -0600 nas (python/3_config.h.i 1.1.2.2 644) --- gc.14(w)/config.h.in Wed, 14 Jun 2000 11:43:34 -0600 nas (python/3_config.h.i 1.1.2.3 644) *************** *** 210,215 **** --- 210,218 ---- (shared library plus accessory files). */ #undef WITH_NEXT_FRAMEWORK + /* Define if you want cycle garbage collection */ + #undef WITH_CYCLE_GC + /* The number of bytes in an off_t. */ #undef SIZEOF_OFF_T Index: nogc.1/configure.in *** nogc.1/configure.in Mon, 05 Jun 2000 00:51:28 -0600 nas (python/5_configure. 1.1.2.2 644) --- gc.14(w)/configure.in Wed, 14 Jun 2000 11:43:34 -0600 nas (python/5_configure. 1.1.2.3 644) *************** *** 1083,1088 **** --- 1083,1099 ---- fi], [AC_MSG_RESULT(no)]) + # Check for GC support + AC_SUBST(USE_GC_MODULE) + USE_GC_MODULE="#" + AC_MSG_CHECKING(for --with-cycle-gc) + AC_ARG_WITH(cycle-gc, [--with-cycle-gc enable garbage collection], [ + AC_MSG_RESULT($withval) + AC_DEFINE(WITH_CYCLE_GC) + USE_GC_MODULE= + ], + AC_MSG_RESULT(no)) + # THIS MUST BE LAST, IT CAN BREAK OTHER TESTS! # Add sys/socket.h to confdefs.h cat >> confdefs.h <<\EOF Index: nogc.1/Include/objimpl.h *** nogc.1/Include/objimpl.h Wed, 14 Jun 2000 13:39:10 -0600 nas (python/o/19_objimpl.h 1.1.2.1.1.2 644) --- gc.14(w)/Include/objimpl.h Wed, 14 Jun 2000 14:06:01 -0600 nas (python/o/19_objimpl.h 1.1.2.4 644) *************** *** 256,262 **** #define PyObject_GC_Init(op) #define PyObject_GC_Fini(op) ! #endif #ifdef __cplusplus } --- 256,300 ---- #define PyObject_GC_Init(op) #define PyObject_GC_Fini(op) ! #else ! ! /* Add the object into the container set */ ! extern DL_IMPORT(void) _PyGC_Insert Py_PROTO((PyObject *)); ! ! /* Remove the object from the container set */ ! extern DL_IMPORT(void) _PyGC_Remove Py_PROTO((PyObject *)); ! ! #define PyObject_GC_Init(op) _PyGC_Insert(op) ! #define PyObject_GC_Fini(op) _PyGC_Remove(op) ! ! /* Structure *prefixed* to container objects participating in GC */ ! typedef struct _gcinfo { ! struct _gcinfo *gc_next; ! struct _gcinfo *gc_prev; ! int gc_refs; ! } PyGCInfo; ! ! #define PyGC_INFO_SIZE sizeof(PyGCInfo) ! ! /* Test if a type has GC info */ ! #define PyGC_TYPE_HAS_INFO(t) PyType_HasFeature((t), Py_TPFLAGS_GC) ! ! /* Test if an object has GC info */ ! #define PyGC_HAS_INFO(o) PyGC_TYPE_HAS_INFO((o)->ob_type) ! ! /* Get an object's GC info -- NULL if the object has none */ ! #define PyGC_INFO(o) (PyGC_HAS_INFO(o) ? ((PyGCInfo *)(o)-1) : NULL) ! ! /* Unsafe version of PyGC_INFO() -- only call if PyGC_HAS_INFO(p) is true */ ! #define PyGC_INFO_UNSAFE(o) ((PyGCInfo *)(o)-1) ! ! /* Get the object given the PyGCInfo */ ! #define PyGC_OBJ(g) ((PyObject *)((g)+1)) ! ! /* Interpreter macro, use PyObject_Del for extension types. */ ! #define PyObject_GC_DEL(op) PyObject_FREE(PyGC_INFO(op)) ! ! #endif /* WITH_CYCLE_GC */ #ifdef __cplusplus } Index: nogc.1/Modules/Setup.thread.in *** nogc.1/Modules/Setup.thread.in Tue, 25 Apr 2000 17:33:19 -0600 nas (python/C/19_Setup.thre 1.1 644) --- gc.14(w)/Modules/Setup.thread.in Wed, 14 Jun 2000 11:43:34 -0600 nas (python/C/19_Setup.thre 1.2 644) *************** *** 9,11 **** --- 9,14 ---- # support threads. @USE_THREAD_MODULE@thread threadmodule.c + + # Garbage collection enabled with --with-cycle-gc + @USE_GC_MODULE@gc gcmodule.c Index: nogc.1/Objects/classobject.c *** nogc.1/Objects/classobject.c Wed, 14 Jun 2000 13:39:10 -0600 nas (python/E/16_classobjec 1.1.2.2.1.3 644) --- gc.14(w)/Objects/classobject.c Wed, 14 Jun 2000 13:44:26 -0600 nas (python/E/16_classobjec 1.1.2.6 644) *************** *** 578,584 **** --- 578,586 ---- inst->ob_type->tp_free--; /* compensate for increment in UNREF */ #endif _Py_ForgetReference((PyObject *)inst); + #ifndef WITH_CYCLE_GC inst->ob_type = NULL; + #endif #endif /* Py_TRACE_REFS */ Py_DECREF(inst->in_class); Py_XDECREF(inst->in_dict); *************** *** 1738,1743 **** while (free_list) { PyMethodObject *im = free_list; free_list = (PyMethodObject *)(im->im_self); ! PyObject_DEL(im); } } --- 1740,1745 ---- while (free_list) { PyMethodObject *im = free_list; free_list = (PyMethodObject *)(im->im_self); ! PyObject_GC_DEL(im); } } Index: nogc.1/Objects/listobject.c *** nogc.1/Objects/listobject.c Wed, 14 Jun 2000 13:39:10 -0600 nas (python/E/25_listobject 1.1.2.3.1.3 644) --- gc.14(w)/Objects/listobject.c Wed, 14 Jun 2000 11:43:34 -0600 nas (python/E/25_listobject 1.1.2.5 644) *************** *** 76,81 **** --- 76,84 ---- if (op == NULL) { return PyErr_NoMemory(); } + #ifdef WITH_CYCLE_GC + op = (PyListObject *) PyGC_OBJ((PyGCInfo *)op); + #endif if (size <= 0) { op->ob_item = NULL; } Index: nogc.1/Objects/object.c *** nogc.1/Objects/object.c Wed, 14 Jun 2000 12:25:30 -0600 nas (python/E/29_object.c 1.1.1.1.1.1 644) --- gc.14(w)/Objects/object.c Wed, 14 Jun 2000 12:33:09 -0600 nas (python/E/29_object.c 1.1.1.1.1.1 644) *************** *** 122,127 **** --- 122,131 ---- "NULL object passed to PyObject_Init"); return op; } + #ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) + op = (PyObject *) PyGC_OBJ((PyGCInfo *)op); + #endif /* Any changes should be reflected in PyObject_INIT (objimpl.h) */ op->ob_type = tp; _Py_NewReference(op); *************** *** 139,144 **** --- 143,152 ---- "NULL object passed to PyObject_InitVar"); return op; } + #ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) + op = (PyVarObject *) PyGC_OBJ((PyGCInfo *)op); + #endif /* Any changes should be reflected in PyObject_INIT_VAR */ op->ob_size = size; op->ob_type = tp; *************** *** 154,159 **** --- 162,171 ---- op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); if (op == NULL) return PyErr_NoMemory(); + #ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) + op = (PyObject *) PyGC_OBJ((PyGCInfo *)op); + #endif return PyObject_INIT(op, tp); } *************** *** 166,171 **** --- 178,187 ---- op = (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE(tp, size)); if (op == NULL) return (PyVarObject *)PyErr_NoMemory(); + #ifdef WITH_CYCLE_GC + if (PyGC_TYPE_HAS_INFO(tp)) + op = (PyVarObject *) PyGC_OBJ((PyGCInfo *)op); + #endif return PyObject_INIT_VAR(op, tp, size); } *************** *** 173,181 **** _PyObject_Del(op) PyObject *op; { ! PyObject_FREE(op); } int PyObject_Print(op, fp, flags) PyObject *op; --- 189,211 ---- _PyObject_Del(op) PyObject *op; { ! #ifdef WITH_CYCLE_GC ! if (PyGC_TYPE_HAS_INFO(op->ob_type)) { ! PyGCInfo *g = PyGC_INFO(op); ! PyObject_FREE(g); ! } else ! #endif ! { ! PyObject_FREE(op); ! } } + #ifndef WITH_CYCLE_GC + /* extension modules might need these */ + void _PyGC_Insert(PyObject *op) { } + void _PyGC_Remove(PyObject *op) { } + #endif + int PyObject_Print(op, fp, flags) PyObject *op; *************** *** 846,853 **** --- 876,885 ---- { destructor dealloc = op->ob_type->tp_dealloc; _Py_ForgetReference(op); + #ifndef WITH_CYCLE_GC if (_PyTrash_delete_nesting < PyTrash_UNWIND_LEVEL-1) op->ob_type = NULL; + #endif (*dealloc)(op); } Index: nogc.1/Objects/tupleobject.c *** nogc.1/Objects/tupleobject.c Wed, 14 Jun 2000 13:39:10 -0600 nas (python/E/33_tupleobjec 1.1.2.3.1.3 644) --- gc.14(w)/Objects/tupleobject.c Wed, 14 Jun 2000 13:48:47 -0600 nas (python/E/33_tupleobjec 1.1.2.5 644) *************** *** 103,108 **** --- 103,111 ---- op = (PyTupleObject *) PyObject_MALLOC(nbytes); if (op == NULL) return PyErr_NoMemory(); + #ifdef WITH_CYCLE_GC + op = (PyTupleObject *) PyGC_OBJ((PyGCInfo *)op); + #endif PyObject_INIT_VAR(op, &PyTuple_Type, size); } for (i = 0; i < size; i++) *************** *** 555,564 **** --- 558,581 ---- } else #endif { + #ifdef WITH_CYCLE_GC + PyGCInfo *g = PyGC_INFO((PyObject *)v); + PyObject_GC_Fini((PyObject *)v); + sv = (PyTupleObject *) + PyObject_REALLOC((char *)g, sizeof(PyTupleObject) + + PyGC_INFO_SIZE + + newsize * sizeof(PyObject *)); + if (g == NULL) { + sv = NULL; + } else { + sv = (PyTupleObject *)PyGC_OBJ(g); + } + #else sv = (PyTupleObject *) PyObject_REALLOC((char *)v, sizeof(PyTupleObject) + PyGC_INFO_SIZE + newsize * sizeof(PyObject *)); + #endif *pv = (PyObject *) sv; if (sv == NULL) { PyObject_GC_Init((PyObject *)v); Index: nogc.1/PC/config.c *** nogc.1/PC/config.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/39_config.c 1.1.2.1 644) --- gc.14(w)/PC/config.c Wed, 14 Jun 2000 11:43:34 -0600 nas (python/E/39_config.c 1.1.2.2 644) *************** *** 43,48 **** --- 43,51 ---- #endif extern void initcmath(); extern void initerrno(); + #ifdef WITH_CYCLE_GC + extern void initgc(); + #endif #ifndef MS_WIN64 extern void initimageop(); #endif *************** *** 89,94 **** --- 92,100 ---- #endif {"cmath", initcmath}, {"errno", initerrno}, + #ifdef WITH_CYCLE_GC + {"gc", initgc}, + #endif #ifndef MS_WIN64 {"imageop", initimageop}, #endif Index: nogc.1/PC/config.h *** nogc.1/PC/config.h Mon, 05 Jun 2000 00:51:28 -0600 nas (python/E/40_config.h 1.1.2.2 644) --- gc.14(w)/PC/config.h Wed, 14 Jun 2000 13:50:56 -0600 nas (python/E/40_config.h 1.1.2.3 644) *************** *** 421,426 **** --- 421,429 ---- /* Define if you want to use the GNU readline library */ /* #define WITH_READLINE 1 */ + /* Define if you want cycle garbage collection */ + /* #define WITH_CYCLE_GC 1 */ + /* Define if you have clock. */ /* #define HAVE_CLOCK */ Index: nogc.1/PCbuild/python16.dsp *** nogc.1/PCbuild/python16.dsp Wed, 07 Jun 2000 13:08:39 -0600 nas (python/G/1_python16.d 1.1.1.1.1.1 644) --- gc.14(w)/PCbuild/python16.dsp Wed, 14 Jun 2000 11:43:34 -0600 nas (python/G/1_python16.d 1.1.1.1.1.2 644) *************** *** 660,665 **** --- 660,680 ---- # End Source File # Begin Source File + SOURCE=..\Modules\gcmodule.c + + !IF "$(CFG)" == "python16 - Win32 Release" + + !ELSEIF "$(CFG)" == "python16 - Win32 Debug" + + !ELSEIF "$(CFG)" == "python16 - Win32 Alpha Debug" + + !ELSEIF "$(CFG)" == "python16 - Win32 Alpha Release" + + !ENDIF + + # End Source File + # Begin Source File + SOURCE=..\Python\getargs.c !IF "$(CFG)" == "python16 - Win32 Release" Index: nogc.1/Modules/gcmodule.c *** nogc.1/Modules/gcmodule.c Wed, 14 Jun 2000 14:06:03 -0600 nas () --- gc.14(w)/Modules/gcmodule.c Wed, 14 Jun 2000 14:01:04 -0600 nas (python/M/10_gcmodule.c 1.6 644) *************** *** 0 **** --- 1,675 ---- + /* + + Reference Cycle Garbage Collection + ================================== + + Neil Schemenauer + + Based on a post on the python-dev list. Ideas from Guido van Rossum, + Eric Tiedemann, and various others. + + http://www.enme.calgary.ca/~nascheme/python/gc.html + http://www.python.org/pipermail/python-dev/2000-March/003869.html + http://www.python.org/pipermail/python-dev/2000-March/004010.html + http://www.python.org/pipermail/python-dev/2000-March/004022.html + + For a highlevel view of the collection process, read the collect + function. + + TODO: + use a different interface for set_debug() (keywords)? + tune parameters + + */ + + + #include "Python.h" + + #ifdef WITH_CYCLE_GC + + /* magic gc_refs value */ + #define GC_MOVED -1 + + /*** Global GC state ***/ + + /* linked lists of container objects */ + static PyGCInfo generation0 = {&generation0, &generation0, 0}; + static PyGCInfo generation1 = {&generation1, &generation1, 0}; + static PyGCInfo generation2 = {&generation2, &generation2, 0}; + static int generation = 0; /* current generation being collected */ + + /* collection frequencies, XXX tune these */ + static int threshold0 = 100; /* net new containers before collection */ + static int threshold1 = 10; /* generation0 collections before collecting 1 */ + static int threshold2 = 10; /* generation1 collections before collecting 2 */ + + /* net new objects allocated since last collection */ + static int allocated; + + /* set for debugging information */ + #define DEBUG_STATS (1<<0) /* print collection statistics */ + #define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ + #define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */ + #define DEBUG_INSTANCES (1<<3) /* print instances */ + #define DEBUG_OBJECTS (1<<4) /* print other objects */ + #define DEBUG_LEAK DEBUG_COLLECTABLE | \ + DEBUG_UNCOLLECTABLE | \ + DEBUG_INSTANCES | \ + DEBUG_OBJECTS + static int debug; + + /* list of uncollectable objects */ + static PyObject *garbage; + + + /*** list functions ***/ + + static void + gc_list_init(PyGCInfo *list) + { + list->gc_prev = list; + list->gc_next = list; + } + + static void + gc_list_append(PyGCInfo *node, PyGCInfo *list) + { + node->gc_next = list; + node->gc_prev = list->gc_prev; + node->gc_prev->gc_next = node; + list->gc_prev = node; + } + + static void + gc_list_remove(PyGCInfo *node) + { + node->gc_prev->gc_next = node->gc_next; + node->gc_next->gc_prev = node->gc_prev; + #ifdef Py_DEBUG + node->gc_prev = NULL; + node->gc_next = NULL; + #endif + } + + static void + gc_list_move(PyGCInfo *from, PyGCInfo *to) + { + if (from->gc_next == from) { + /* empty from list */ + gc_list_init(to); + } else { + to->gc_next = from->gc_next; + to->gc_next->gc_prev = to; + to->gc_prev = from->gc_prev; + to->gc_prev->gc_next = to; + } + gc_list_init(from); + } + + /* append a list onto another list, from becomes an empty list */ + static void + gc_list_merge(PyGCInfo *from, PyGCInfo *to) + { + PyGCInfo *tail; + if (from->gc_next != from) { + tail = to->gc_prev; + tail->gc_next = from->gc_next; + tail->gc_next->gc_prev = tail; + to->gc_prev = from->gc_prev; + to->gc_prev->gc_next = to; + } + gc_list_init(from); + } + + static long + gc_list_size(PyGCInfo *list) + { + PyGCInfo *gc; + long n = 0; + for (gc = list->gc_next; gc != list; gc = gc->gc_next) { + n++; + } + return n; + } + + /*** end of list stuff ***/ + + + /* Set all gc_refs = ob_refcnt */ + static void + update_refs(PyGCInfo *containers) + { + PyGCInfo *gc = containers->gc_next; + for (; gc != containers; gc=gc->gc_next) { + gc->gc_refs = PyGC_OBJ(gc)->ob_refcnt; + } + } + + static int + visit_decref(PyObject *op, void *data) + { + if (op && PyGC_HAS_INFO(op)) { + PyGC_INFO_UNSAFE(op)->gc_refs--; + } + return 1; + } + + /* Subtract internal references from gc_refs */ + static void + subtract_refs(PyGCInfo *containers) + { + recurseproc recurse; + PyGCInfo *gc = containers->gc_next; + for (; gc != containers; gc=gc->gc_next) { + recurse = PyGC_OBJ(gc)->ob_type->tp_recurse; + (void) recurse(PyGC_OBJ(gc), + (visitproc)visit_decref, + NULL); + } + } + + /* Append objects with gc_refs > 0 to roots list */ + static void + move_roots(PyGCInfo *containers, PyGCInfo *roots) + { + PyGCInfo *next; + PyGCInfo *gc = containers->gc_next; + while (gc != containers) { + next = gc->gc_next; + if (gc->gc_refs > 0) { + gc_list_remove(gc); + gc_list_append(gc, roots); + gc->gc_refs = GC_MOVED; + } + gc = next; + } + } + + static int + visit_reachable(PyObject *op, PyGCInfo *roots) + { + PyGCInfo *gc = PyGC_INFO(op); + if (gc && gc->gc_refs != GC_MOVED) { + gc_list_remove(gc); + gc_list_append(gc, roots); + gc->gc_refs = GC_MOVED; + } + return 1; + } + + /* Move objects referenced from reachable to reachable set. */ + static void + move_root_reachable(PyGCInfo *reachable) + { + recurseproc recurse; + PyGCInfo *gc = reachable->gc_next; + for (; gc != reachable; gc=gc->gc_next) { + /* careful, reachable list is growing here */ + PyObject *op = PyGC_OBJ(gc); + recurse = op->ob_type->tp_recurse; + (void) recurse(op, + (visitproc)visit_reachable, + (void *)reachable); + } + } + + /* move all objects with finalizers (instances with __del__) */ + static void + move_finalizers(PyGCInfo *unreachable, PyGCInfo *finalizers) + { + PyGCInfo *next; + PyGCInfo *gc = unreachable->gc_next; + static PyObject *delstr; + if (delstr == NULL) { + delstr = PyString_InternFromString("__del__"); + } + for (; gc != unreachable; gc=next) { + PyObject *op = PyGC_OBJ(gc); + next = gc->gc_next; + if (PyInstance_Check(op) && PyObject_HasAttr(op, delstr)) { + gc_list_remove(gc); + gc_list_append(gc, finalizers); + } + } + } + + + /* called by tp_recurse */ + static int + visit_finalizer_reachable(PyObject *op, PyGCInfo *finalizers) + { + PyGCInfo *gc = PyGC_INFO(op); + if (gc && gc->gc_refs != GC_MOVED) { + gc_list_remove(gc); + gc_list_append(gc, finalizers); + gc->gc_refs = GC_MOVED; + } + return 1; + } + + /* Move objects referenced from roots to roots */ + static void + move_finalizer_reachable(PyGCInfo *finalizers) + { + recurseproc recurse; + PyGCInfo *gc = finalizers->gc_next; + for (; gc != finalizers; gc=gc->gc_next) { + /* careful, finalizers list is growing here */ + recurse = PyGC_OBJ(gc)->ob_type->tp_recurse; + (void) recurse(PyGC_OBJ(gc), + (visitproc)visit_finalizer_reachable, + (void *)finalizers); + } + } + + static void + debug_instance(PyObject *output, char *msg, PyInstanceObject *inst) + { + char buf[200]; + char *cname; + /* be careful not to create new dictionaries */ + PyObject *classname = inst->in_class->cl_name; + if (classname != NULL && PyString_Check(classname)) + cname = PyString_AsString(classname); + else + cname = "?"; + sprintf(buf, "gc: %s<%.100s instance at %lx>\n", + msg, cname, (long)inst); + PyFile_WriteString(buf, output); + } + + static void + debug_cycle(PyObject *output, char *msg, PyObject *op) + { + if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { + debug_instance(output, msg, (PyInstanceObject *)op); + } else if (debug & DEBUG_OBJECTS) { + char buf[200]; + sprintf(buf, "gc: %s<%s 0x%x>\n", + msg, + op->ob_type->tp_name, + (long)op); + PyFile_WriteString(buf, output); + } + } + + /* Handle uncollectable garbage (cycles with finalizers). */ + static void + handle_finalizers(PyGCInfo *finalizers, PyGCInfo *old) + { + PyGCInfo *gc; + if (garbage == NULL) { + garbage = PyList_New(0); + } + for (gc = finalizers->gc_next; gc != finalizers; + gc = finalizers->gc_next) { + PyObject *op = PyGC_OBJ(gc); + /* Add all instances to a Python accessible list of garbage */ + if (PyInstance_Check(op)) { + PyList_Append(garbage, op); + } + /* We assume that all objects in finalizers are reachable from + * instances. Once we add the instances to the garbage list + * everything is reachable from Python again. */ + gc_list_remove(gc); + gc_list_append(gc, old); + } + } + + /* Break reference cycles by clearing the containers involved. This is + * tricky business as the lists can be changing and we don't know which + * objects may be freed. It is possible I screwed something up here. */ + static void + delete_garbage(PyGCInfo *unreachable, PyGCInfo *old) + { + inquiry clear; + + while (unreachable->gc_next != unreachable) { + PyGCInfo *gc = unreachable->gc_next; + PyObject *op = PyGC_OBJ(gc); + /* + PyList_Append(garbage, op); + */ + if ((clear = op->ob_type->tp_clear) != NULL) { + Py_INCREF(op); + clear((PyObject *)op); + Py_DECREF(op); + } + /* only try to call tp_clear once for each object */ + if (unreachable->gc_next == gc) { + /* still alive, move it, it may die later */ + gc_list_remove(gc); + gc_list_append(gc, old); + } + } + } + + /* This is the main function. Read this to understand how the + * collection process works. */ + static long + collect(PyGCInfo *young, PyGCInfo *old) + { + long n = 0; + long m = 0; + PyGCInfo reachable; + PyGCInfo unreachable; + PyGCInfo finalizers; + PyGCInfo *gc; + PyObject *output = NULL; + + if (debug) { + output = PySys_GetObject("stderr"); + } + if (debug & DEBUG_STATS) { + char buf[100]; + sprintf(buf, "gc: collecting generation %d...\n", generation); + PyFile_WriteString(buf,output); + sprintf(buf, "gc: objects in each generation: %d %d %d\n", + gc_list_size(&generation0), + gc_list_size(&generation1), + gc_list_size(&generation2)); + PyFile_WriteString(buf,output); + } + + /* Using ob_refcnt and gc_refs, calculate which objects in the + * container set are reachable from outside the set (ie. have a + * refcount greater than 0 when all the references within the + * set are taken into account */ + update_refs(young); + subtract_refs(young); + + /* Move everything reachable from outside the set into the + * reachable set (ie. gc_refs > 0). Next, move everything + * reachable from objects in the reachable set. */ + gc_list_init(&reachable); + move_roots(young, &reachable); + move_root_reachable(&reachable); + + /* move unreachable objects to a temporary list, new objects can be + * allocated after this point */ + gc_list_init(&unreachable); + gc_list_move(young, &unreachable); + + /* move reachable objects to next generation */ + gc_list_merge(&reachable, old); + + /* Move objects reachable from finalizers, we can't safely delete + * them. Python programmers should take care not to create such + * things. For Python finalizers means instance objects with + * __del__ methods. */ + gc_list_init(&finalizers); + move_finalizers(&unreachable, &finalizers); + move_finalizer_reachable(&finalizers); + + /* Collect statistics on collectable objects found and print + * debugging information. */ + for (gc = unreachable.gc_next; gc != &unreachable; + gc = gc->gc_next) { + m++; + if (output != NULL && (debug & DEBUG_COLLECTABLE)) { + debug_cycle(output, "collectable ", PyGC_OBJ(gc)); + } + } + /* call tp_clear on objects in the collectable set. This will cause + * the reference cycles to be broken. It may also cause some objects in + * finalizers to be freed */ + delete_garbage(&unreachable, old); + + /* Collect statistics on uncollectable objects found and print + * debugging information. */ + for (gc = finalizers.gc_next; gc != &finalizers; + gc = gc->gc_next) { + n++; + if (output != NULL && (debug & DEBUG_UNCOLLECTABLE)) { + debug_cycle(output, "uncollectable ", PyGC_OBJ(gc)); + } + } + if (output != NULL && (debug & DEBUG_STATS)) { + if (m == 0 && n == 0) { + PyFile_WriteString("gc: done.\n", output); + } else { + char buf[200]; + sprintf(buf, + "gc: done, %d unreachable, %d uncollectable.\n", + n+m, n); + PyFile_WriteString(buf, output); + } + } + + /* Append instances in the uncollectable set to a Python + * reachable list of garbage. The programmer has to deal with + * this if they insist on creating this type of structure. */ + handle_finalizers(&finalizers, old); + + allocated = 0; + PyErr_Clear(); /* in case writing to sys.stderr failed */ + return n+m; + } + + static long + collect_generations(void) + { + static long collections0 = 0; + static long collections1 = 0; + long n; + + + if (collections1 > threshold2) { + generation = 2; + gc_list_merge(&generation0, &generation2); + gc_list_merge(&generation1, &generation2); + if (generation2.gc_next != &generation2) { + n = collect(&generation2, &generation2); + } + collections1 = 0; + } else if (collections0 > threshold1) { + generation = 1; + collections1++; + gc_list_merge(&generation0, &generation1); + if (generation1.gc_next != &generation1) { + n = collect(&generation1, &generation2); + } + collections0 = 0; + } else { + generation = 0; + collections0++; + if (generation0.gc_next != &generation0) { + n = collect(&generation0, &generation1); + } + } + return n; + } + + void + _PyGC_Insert(PyObject *op) + { + /* collection lock since collecting may cause allocations */ + static int collecting = 0; + + #ifdef Py_DEBUG + if (!PyGC_HAS_INFO(op)) { + abort(); + } + #endif + if (threshold0 && allocated > threshold0 && !collecting) { + collecting++; + collect_generations(); + collecting--; + } + allocated++; + gc_list_append(PyGC_INFO(op), &generation0); + } + + void + _PyGC_Remove(PyObject *op) + { + PyGCInfo *g = PyGC_INFO(op); + #ifdef Py_DEBUG + if (!PyGC_HAS_INFO(op)) { + abort(); + } + #endif + gc_list_remove(g); + if (allocated > 0) { + allocated--; + } + } + + + static char collect__doc__[] = + "collect() -> n\n" + "\n" + "Run a full collection. The number of unreachable objects is returned.\n" + ; + + static PyObject * + Py_collect(self, args) + PyObject *self; + PyObject *args; + { + long n; + + if(!PyArg_ParseTuple(args, "")) /* check no args */ + return NULL; + + generation = 2; + gc_list_merge(&generation0, &generation2); + gc_list_merge(&generation1, &generation2); + n = collect(&generation2, &generation2); + + return Py_BuildValue("i", n); + } + + static char set_debug__doc__[] = + "set_debug(flags) -> None\n" + "\n" + "Set the garbage collection debugging flags. Debugging information is\n" + "written to sys.stderr.\n" + "\n" + "flags is an integer and can have the following bits turned on:\n" + "\n" + " DEBUG_STATS - Print statistics during collection.\n" + " DEBUG_COLLECTABLE - Print collectable objects found.\n" + " DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n" + " DEBUG_INSTANCES - Print instance objects.\n" + " DEBUG_OBJECTS - Print objects other than instances.\n" + " DEBUG_LEAK - Debug leaking programs (everything but STATS).\n" + ; + + static PyObject * + Py_set_debug(self, args) + PyObject *self; + PyObject *args; + { + if (!PyArg_ParseTuple(args, "l", &debug)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + static char get_debug__doc__[] = + "get_debug() -> flags\n" + "\n" + "Get the garbage collection debugging flags.\n" + ; + + static PyObject * + Py_get_debug(self, args) + PyObject *self; + PyObject *args; + { + if(!PyArg_ParseTuple(args, "")) /* no args */ + return NULL; + + return Py_BuildValue("i", debug); + } + + static char set_thresh__doc__[] = + "set_threshold(threshold0, [threhold1, threshold2]) -> None\n" + "\n" + "Sets the collection thresholds. Setting threshold0 to zero disables\n" + "collection.\n" + ; + + static PyObject * + Py_set_thresh(self, args) + PyObject *self; + PyObject *args; + { + if (!PyArg_ParseTuple(args, "i|ii", &threshold0, + &threshold1, &threshold2)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + static char get_thresh__doc__[] = + "get_threshold() -> (threshold0, threshold1, threshold2)\n" + "\n" + "Return the current collection thresholds\n" + ; + + static PyObject * + Py_get_thresh(self, args) + PyObject *self; + PyObject *args; + { + if(!PyArg_ParseTuple(args, "")) /* no args */ + return NULL; + + return Py_BuildValue("(iii)", threshold0, threshold1, threshold2); + } + + + static char gc__doc__ [] = + "This module provides access to the garbage collector for reference cycles.\n" + "\n" + "collect() -- Do a full collection right now.\n" + "set_debug() -- Set debugging flags.\n" + "get_debug() -- Get debugging flags.\n" + "set_threshold() -- Set the collection thresholds.\n" + "get_threshold() -- Return the current the collection thresholds.\n" + ; + + static PyMethodDef GcMethods[] = { + {"set_debug", Py_set_debug, METH_VARARGS, set_debug__doc__}, + {"get_debug", Py_get_debug, METH_VARARGS, get_debug__doc__}, + {"set_threshold", Py_set_thresh, METH_VARARGS, set_thresh__doc__}, + {"get_threshold", Py_get_thresh, METH_VARARGS, get_thresh__doc__}, + {"collect", Py_collect, METH_VARARGS, collect__doc__}, + {NULL, NULL} /* Sentinel */ + }; + + void + initgc(void) + { + PyObject *m; + PyObject *d; + + m = Py_InitModule4("gc", + GcMethods, + gc__doc__, + NULL, + PYTHON_API_VERSION); + d = PyModule_GetDict(m); + if (garbage == NULL) { + garbage = PyList_New(0); + } + PyDict_SetItemString(d, "garbage", garbage); + PyDict_SetItemString(d, "DEBUG_STATS", + PyInt_FromLong(DEBUG_STATS)); + PyDict_SetItemString(d, "DEBUG_COLLECTABLE", + PyInt_FromLong(DEBUG_COLLECTABLE)); + PyDict_SetItemString(d, "DEBUG_UNCOLLECTABLE", + PyInt_FromLong(DEBUG_UNCOLLECTABLE)); + PyDict_SetItemString(d, "DEBUG_INSTANCES", + PyInt_FromLong(DEBUG_INSTANCES)); + PyDict_SetItemString(d, "DEBUG_OBJECTS", + PyInt_FromLong(DEBUG_OBJECTS)); + PyDict_SetItemString(d, "DEBUG_LEAK", + PyInt_FromLong(DEBUG_LEAK)); + } + + #endif /* WITH_CYCLE_GC */ Index: nogc.1/Lib/test/test_gc.py *** nogc.1/Lib/test/test_gc.py Wed, 14 Jun 2000 14:06:03 -0600 nas () --- gc.14(w)/Lib/test/test_gc.py Wed, 14 Jun 2000 11:43:34 -0600 nas (python/M/12_test_gc.py 1.2 644) *************** *** 0 **** --- 1,100 ---- + import gc + + def test_list(): + l = [] + l.append(l) + print 'list 0x%x' % id(l) + gc.collect() + del l + assert gc.collect() == 1 + + def test_dict(): + d = {} + d[1] = d + print 'dict 0x%x' % id(d) + gc.collect() + del d + assert gc.collect() == 1 + + def test_tuple(): + l = [] + t = (l,) + l.append(t) + print 'list 0x%x' % id(l) + print 'tuple 0x%x' % id(t) + gc.collect() + del t + del l + assert gc.collect() == 2 + + def test_class(): + class A: + pass + A.a = A + print 'class 0x%x' % id(A) + gc.collect() + del A + assert gc.collect() > 0 + + def test_instance(): + class A: + pass + a = A() + a.a = a + print repr(a) + gc.collect() + del a + assert gc.collect() > 0 + + def test_method(): + class A: + def __init__(self): + self.init = self.__init__ + a = A() + gc.collect() + del a + assert gc.collect() > 0 + + def test_finalizer(): + class A: + def __del__(self): pass + class B: + pass + a = A() + a.a = a + id_a = id(a) + b = B() + b.b = b + print 'a', repr(a) + print 'b', repr(b) + gc.collect() + gc.garbage[:] = [] + del a + del b + assert gc.collect() > 0 + assert id(gc.garbage[0]) == id_a + + def test_function(): + d = {} + exec("def f(): pass\n") in d + print 'dict 0x%x' % id(d) + print 'func 0x%x' % id(d['f']) + gc.collect() + del d + assert gc.collect() == 2 + + + def test_all(): + debug = gc.get_debug() + gc.set_debug(gc.DEBUG_LEAK | gc.DEBUG_STATS) + test_list() + test_dict() + test_tuple() + test_class() + test_instance() + test_method() + test_finalizer() + test_function() + gc.set_debug(debug) + + test_all() --vtzGhvizbBRQ85DL-- From gstein@lyra.org Wed Jun 14 22:46:54 2000 From: gstein@lyra.org (Greg Stein) Date: Wed, 14 Jun 2000 14:46:54 -0700 Subject: [Patches] Hi, its for you ! In-Reply-To: <07332810764701623@d203.p6.col.ru>; from prettylady@freemail.ru on Wed, Jun 14, 2000 at 09:34:03PM +0000 References: <07332810764701623@d203.p6.col.ru> Message-ID: <20000614144654.C28280@lyra.org> Dang. Why didn't they include their patch? It sounds like it would be a wonderful improvement for Python to include this stuff. *snicker* On Wed, Jun 14, 2000 at 09:34:03PM +0000, prettylady@freemail.ru wrote: > Hi! We are Russian girls - Natali, Alla, Vika. We would like to > correspond with you. Visit our site and see our photos. > http://www.russiangirls.narod.ru/ > With interest, Natali,Alla, Vika. > > > P.S. (This is not spam. You can unsubscribe at any time by sending an email to > prettylady@freemail.ru > with the subject UNSUBSCRIBE.) > > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches -- Greg Stein, http://www.lyra.org/ From fdrake@beopen.com Wed Jun 14 22:49:53 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Wed, 14 Jun 2000 17:49:53 -0400 (EDT) Subject: [Patches] Hi, its for you ! In-Reply-To: <20000614144654.C28280@lyra.org> References: <07332810764701623@d203.p6.col.ru> <20000614144654.C28280@lyra.org> Message-ID: <14663.65025.774871.533702@cj42289-a.reston1.va.home.com> Greg Stein writes: > Dang. Why didn't they include their patch? It sounds like it would be a > wonderful improvement for Python to include this stuff. It would surely increase the download count! But the download size would go up; ready to subsidize the mass storage industry? :) -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From paul@commerceflow.com Thu Jun 15 00:52:02 2000 From: paul@commerceflow.com (Paul Schreiber) Date: Wed, 14 Jun 2000 16:52:02 -0700 Subject: [Patches] urllib.py patch Message-ID: <39481AA2.C7B29EEA@commerceflow.com> This is a multi-part message in MIME format. --------------3EE36A3787159ED881FD3EC3 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch description ----------------- This addresses four issues: (1) usernames and passwords in urls with special characters are now decoded properly. i.e. http://foo%2C:bar@www.whatever.com/ (2) Basic Auth support has been added to HTTPS, like it was in HTTP. (3) Version 1.92 sent the POSTed data, but did not deal with errors (HTTP responses other than 200) properly. HTTPS now behaves the same way HTTP does. (4) made URL-checking beahve the same way with HTTPS as it does with HTTP (changed == to !=). Paul Schreiber --------------3EE36A3787159ED881FD3EC3 Content-Type: text/plain; charset=us-ascii; name="urllib-diff-2" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="urllib-diff-2" *** urllib.old Tue Jun 13 18:27:02 2000 --- urllib.py Tue Jun 13 18:33:27 2000 *************** *** 302,316 **** def open_https(self, url, data=None): """Use HTTPS protocol.""" import httplib if type(url) is type(""): host, selector = splithost(url) ! user_passwd, host = splituser(host) else: host, selector = url urltype, rest = splittype(selector) ! if string.lower(urltype) == 'https': realhost, rest = splithost(rest) ! user_passwd, realhost = splituser(realhost) if user_passwd: selector = "%s://%s%s" % (urltype, realhost, rest) #print "proxy via https:", host, selector --- 302,325 ---- def open_https(self, url, data=None): """Use HTTPS protocol.""" import httplib + user_passwd = None if type(url) is type(""): host, selector = splithost(url) ! if host: ! user_passwd, host = splituser(host) ! host = unquote(host) ! realhost = host else: host, selector = url urltype, rest = splittype(selector) ! url = rest ! user_passwd = None ! if string.lower(urltype) != 'https': ! realhost = None ! else: realhost, rest = splithost(rest) ! if realhost: ! user_passwd, realhost = splituser(realhost) if user_passwd: selector = "%s://%s%s" % (urltype, realhost, rest) #print "proxy via https:", host, selector *************** *** 331,336 **** --- 340,346 ---- else: h.putrequest('GET', selector) if auth: h.putheader('Authorization: Basic %s' % auth) + if realhost: h.putheader('Host', realhost) for args in self.addheaders: apply(h.putheader, args) h.endheaders() if data is not None: *************** *** 340,347 **** if errcode == 200: return addinfourl(fp, headers, url) else: ! return self.http_error(url, fp, errcode, errmsg, headers) ! def open_gopher(self, url): """Use Gopher protocol.""" import gopherlib --- 350,360 ---- if errcode == 200: return addinfourl(fp, headers, url) else: ! if data is None: ! return self.http_error(url, fp, errcode, errmsg, headers) ! else: ! return self.http_error(url, fp, errcode, errmsg, headers, data) ! def open_gopher(self, url): """Use Gopher protocol.""" import gopherlib *************** *** 872,878 **** _userprog = re.compile('^([^@]*)@(.*)$') match = _userprog.match(host) ! if match: return match.group(1, 2) return None, host _passwdprog = None --- 885,891 ---- _userprog = re.compile('^([^@]*)@(.*)$') match = _userprog.match(host) ! if match: return map(unquote, match.group(1, 2)) return None, host _passwdprog = None --------------3EE36A3787159ED881FD3EC3-- From Moshe Zadka Thu Jun 15 03:57:39 2000 From: Moshe Zadka (Moshe Zadka) Date: Thu, 15 Jun 2000 05:57:39 +0300 (IDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <20000614123818.A8975@acs.ucalgary.ca> Message-ID: On Wed, 14 Jun 2000, Neil Schemenauer wrote: > This patch adds the type methods recurse and clear necessary for > my GC patch. It is straightforward so hopefully it can be > applied right away. a) As spammy as it sounds, you probably want to send this patch again with the legal mumbo-jumbo... b) +0.5, because you are eating into 2 spare slots. Couldn't you just waste one, and have it point into a structure with those two functions? I'd certainly be +1 on that. -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From Moshe Zadka Thu Jun 15 04:05:48 2000 From: Moshe Zadka (Moshe Zadka) Date: Thu, 15 Jun 2000 06:05:48 +0300 (IDT) Subject: [Patches] GC infrastructure patch 2 (type changes) In-Reply-To: <20000614131507.A16847@acs.ucalgary.ca> Message-ID: On Wed, 14 Jun 2000, Neil Schemenauer wrote: > This patch modifies the type structures of objects that > participate in GC. The object's tp_basicsize is increased when > GC is enabled. GC information is prefixed to the object to > maintain binary compatibility. GC objects also define the > tp_flag Py_TPFLAGS_GC. a) See my other a) b) in + /* Objects which participate in garbage collection (see objimp.h) */ + #ifdef WITH_CYCLE_GC + #define Py_TPFLAGS_GC (1L<<2) + #else + #define Py_TPFLAGS_GC 0 + #endif What's wrong with defining Py_TPFLAGS_GC unconditionally? c) You seem to be adding GC information to an awful lot of objects. How much of this can be thrown out without affecting GC greatly? Cool, anyway! -- Moshe Zadka http://www.oreilly.com/news/prescod_0300.html http://www.linux.org.il -- we put the penguin in .com From mal@lemburg.com Thu Jun 15 09:39:24 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Thu, 15 Jun 2000 10:39:24 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: Message-ID: <3948963C.7BC06AF9@lemburg.com> Moshe Zadka wrote: > > On Wed, 14 Jun 2000, Neil Schemenauer wrote: > > > This patch adds the type methods recurse and clear necessary for > > my GC patch. It is straightforward so hopefully it can be > > applied right away. > > a) As spammy as it sounds, you probably want to send this patch again with > the legal mumbo-jumbo... > > b) +0.5, because you are eating into 2 spare slots. Couldn't you just > waste one, and have it point into a structure with those two functions? > I'd certainly be +1 on that. I don't see much of a problem here. IIRC Guido wasn't too happy with the current implementation of protocols (via pointers to structs), so Neil's approach is in line with the "new" strategy to include all slots at top-level. BTW, type objects don't cost anything (there's only one per object type, not one per object), so there really isn't all that much to bother about. The patch set looks ok to me... at least as far as I understand it. I'm certainly +1 on the strategy which is used. Some questions: * what's the impact of having GC enabled for the class of well bahaved programs (those which do not create cyclic garbage) ? * would it be possible to disable automatic collection and implement a custom collection invocation scheme ? * what would an extension type have to do/implement to participate in GC ? * would an extension compiled with GC still work together with an interpreter which is not (and vice-versa) ? [This one is of particular importance to me for obvious reasons.] -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From thomas@xs4all.net Thu Jun 15 13:45:23 2000 From: thomas@xs4all.net (Thomas Wouters) Date: Thu, 15 Jun 2000 14:45:23 +0200 Subject: [Patches] sq_contains support for listobject and rangeobject Message-ID: <20000615144523.E26436@xs4all.nl> --VS++wcV0S1rZb1Fb Content-Type: text/plain; charset=us-ascii The following patch adds 'sq_contains' support to rangeobject, and enables the already-written support for sq_contains in listobject and tupleobject. The rangeobject 'contains' code should be a bit more efficient than the current default 'in' implementation ;-) It might not get used much, but it's not that much to add. listobject.c and tupleobject.c already had code for sq_contains, and the proper struct member was set, but the PyType structure was not extended to include tp_flags, so the object-specific code was not getting called (Go ahead, test it ;-). I also did this for the immutable_list_type in listobject.c, eventhough it is probably never used. Symmetry and all that. The patch is so small I thought it would be OK to submit these three patches in one posting, with one attachement ;P I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -ly y'rs, -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! --VS++wcV0S1rZb1Fb Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="contains.diff" Index: Objects/listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.71 diff -u -r2.71 listobject.c --- Objects/listobject.c 2000/06/01 14:31:03 2.71 +++ Objects/listobject.c 2000/06/15 12:41:53 @@ -1489,6 +1490,13 @@ 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; @@ -1540,6 +1548,7 @@ (intintargfunc)list_slice, /*sq_slice*/ (intobjargproc)immutable_list_ass, /*sq_ass_item*/ (intintobjargproc)immutable_list_ass, /*sq_ass_slice*/ + (objobjproc)list_contains, /*sq_contains*/ }; static PyTypeObject immutable_list_type = { @@ -1557,5 +1566,12 @@ 0, /*tp_as_number*/ &immutable_list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; Index: Objects/rangeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/rangeobject.c,v retrieving revision 2.12 diff -u -r2.12 rangeobject.c --- Objects/rangeobject.c 2000/05/03 23:44:35 2.12 +++ Objects/rangeobject.c 2000/06/15 12:41:53 @@ -237,6 +237,23 @@ return Py_FindMethod(range_methods, (PyObject *) r, name); } +static int +range_contains(r, obj) + rangeobject * r; + PyObject * obj; +{ + long num = PyInt_AsLong(obj); + + if (num < 0 && PyErr_Occurred()) + return -1; + + if (num < r->start || (num - r->start) % r->step) + return 0; + if (num > (r->start + (r->len * r->step))) + return 0; + return 1; +} + static PySequenceMethods range_as_sequence = { (inquiry)range_length, /*sq_length*/ (binaryfunc)range_concat, /*sq_concat*/ @@ -245,6 +262,7 @@ (intintargfunc)range_slice, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ + (objobjproc)range_contains, /*sq_contains*/ }; PyTypeObject PyRange_Type = { @@ -262,4 +280,12 @@ 0, /*tp_as_number*/ &range_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; +c \ No newline at end of file Index: Objects/tupleobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/tupleobject.c,v retrieving revision 2.34 diff -u -r2.34 tupleobject.c --- Objects/tupleobject.c 2000/06/01 03:12:13 2.34 +++ Objects/tupleobject.c 2000/06/15 12:41:54 @@ -447,6 +447,12 @@ &tuple_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)tuplehash, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; /* The following function breaks the notion that tuples are immutable: --VS++wcV0S1rZb1Fb-- From thomas@xs4all.net Thu Jun 15 14:39:13 2000 From: thomas@xs4all.net (Thomas Wouters) Date: Thu, 15 Jun 2000 15:39:13 +0200 Subject: [Patches] Re: sq_contains support for listobject and rangeobject In-Reply-To: <20000615144523.E26436@xs4all.nl>; from thomas@xs4all.net on Thu, Jun 15, 2000 at 02:45:23PM +0200 References: <20000615144523.E26436@xs4all.nl> Message-ID: <20000615153913.H26436@xs4all.nl> --LyciRD1jyfeSSjG0 Content-Type: text/plain; charset=us-ascii On Thu, Jun 15, 2000 at 02:45:23PM +0200, Thomas Wouters wrote: > The following patch adds 'sq_contains' support to rangeobject, and enables > the already-written support for sq_contains in listobject and tupleobject. > The rangeobject 'contains' code should be a bit more efficient than the > current default 'in' implementation ;-) It might not get used much, but it's > not that much to add. > > listobject.c and tupleobject.c already had code for sq_contains, and the > proper struct member was set, but the PyType structure was not extended to > include tp_flags, so the object-specific code was not getting called (Go > ahead, test it ;-). I also did this for the immutable_list_type in > listobject.c, eventhough it is probably never used. Symmetry and all that. > > The patch is so small I thought it would be OK to submit these three patches > in one posting, with one attachement ;P Unfortunately, it contained a typo. The attached version works ;-P I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -ly y'rs, -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! --LyciRD1jyfeSSjG0 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="contains.diff" Index: Objects/listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.71 diff -u -r2.71 listobject.c --- Objects/listobject.c 2000/06/01 14:31:03 2.71 +++ Objects/listobject.c 2000/06/15 13:36:14 @@ -1489,6 +1490,13 @@ 0, /*tp_as_number*/ &list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; @@ -1540,6 +1548,7 @@ (intintargfunc)list_slice, /*sq_slice*/ (intobjargproc)immutable_list_ass, /*sq_ass_item*/ (intintobjargproc)immutable_list_ass, /*sq_ass_slice*/ + (objobjproc)list_contains, /*sq_contains*/ }; static PyTypeObject immutable_list_type = { @@ -1557,5 +1566,12 @@ 0, /*tp_as_number*/ &immutable_list_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; Index: Objects/rangeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/rangeobject.c,v retrieving revision 2.12 diff -u -r2.12 rangeobject.c --- Objects/rangeobject.c 2000/05/03 23:44:35 2.12 +++ Objects/rangeobject.c 2000/06/15 13:36:14 @@ -237,6 +237,23 @@ return Py_FindMethod(range_methods, (PyObject *) r, name); } +static int +range_contains(r, obj) + rangeobject * r; + PyObject * obj; +{ + long num = PyInt_AsLong(obj); + + if (num < 0 && PyErr_Occurred()) + return -1; + + if (num < r->start || (num - r->start) % r->step) + return 0; + if (num > (r->start + (r->len * r->step))) + return 0; + return 1; +} + static PySequenceMethods range_as_sequence = { (inquiry)range_length, /*sq_length*/ (binaryfunc)range_concat, /*sq_concat*/ @@ -245,6 +262,7 @@ (intintargfunc)range_slice, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ + (objobjproc)range_contains, /*sq_contains*/ }; PyTypeObject PyRange_Type = { @@ -262,4 +280,11 @@ 0, /*tp_as_number*/ &range_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; Index: Objects/tupleobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/tupleobject.c,v retrieving revision 2.34 diff -u -r2.34 tupleobject.c --- Objects/tupleobject.c 2000/06/01 03:12:13 2.34 +++ Objects/tupleobject.c 2000/06/15 13:36:14 @@ -447,6 +447,12 @@ &tuple_as_sequence, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)tuplehash, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ }; /* The following function breaks the notion that tuples are immutable: --LyciRD1jyfeSSjG0-- From fdrake@beopen.com Thu Jun 15 15:50:43 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Thu, 15 Jun 2000 10:50:43 -0400 (EDT) Subject: [Patches] Re: sq_contains support for listobject and rangeobject In-Reply-To: <20000615153913.H26436@xs4all.nl> References: <20000615144523.E26436@xs4all.nl> <20000615153913.H26436@xs4all.nl> Message-ID: <14664.60739.481084.205861@cj42289-a.reston1.va.home.com> Thomas Wouters writes: > Unfortunately, it contained a typo. The attached version works ;-P Thomas, Thanks! I've checked this in. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From jeremy@beopen.com Thu Jun 15 17:20:25 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Thu, 15 Jun 2000 12:20:25 -0400 (EDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: References: <20000614123818.A8975@acs.ucalgary.ca> Message-ID: <14665.585.98693.352141@localhost.localdomain> >>>>> "MZ" == Moshe Zadka writes: MZ> On Wed, 14 Jun 2000, Neil Schemenauer wrote: >> This patch adds the type methods recurse and clear necessary for >> my GC patch. It is straightforward so hopefully it can be >> applied right away. MZ> a) As spammy as it sounds, you probably want to send this patch MZ> again with the legal mumbo-jumbo... I think we can handle this some way other than including the boilerplate in a new set of patches. Let's not worry about it for now; we do have the disclaimer for previous versions of the patches. Jeremy From nascheme@enme.ucalgary.ca Thu Jun 15 19:39:45 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Thu, 15 Jun 2000 12:39:45 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: ; from moshez@math.huji.ac.il on Thu, Jun 15, 2000 at 05:57:39AM +0300 References: <20000614123818.A8975@acs.ucalgary.ca> Message-ID: <20000615123944.A9717@acs.ucalgary.ca> On Thu, Jun 15, 2000 at 05:57:39AM +0300, Moshe Zadka wrote: > a) As spammy as it sounds, you probably want to send this patch > again with the legal mumbo-jumbo... CNRI has my wet signature. I don't think the legal is required. Neil -- 145 = 1! + 4! + 5! From nascheme@enme.ucalgary.ca Thu Jun 15 19:49:06 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Thu, 15 Jun 2000 12:49:06 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <3948963C.7BC06AF9@lemburg.com>; from mal@lemburg.com on Thu, Jun 15, 2000 at 10:39:24AM +0200 References: <3948963C.7BC06AF9@lemburg.com> Message-ID: <20000615124906.B9717@acs.ucalgary.ca> On Thu, Jun 15, 2000 at 10:39:24AM +0200, M.-A. Lemburg wrote: > Some questions: > > * what's the impact of having GC enabled for the class of > well bahaved programs (those which do not create cyclic > garbage) ? There is the memory overhead of the PyGCInfo struct that is prefixed to all objects with the GC type flag set (~ 3 words). By default, the collector runs after X net new object allocations (this can be tuned or turned off). Because of the generational collection, the collector usually only looks at a few objects when it runs. There is also some overhead inserting and removing GC objects into the linked list of all GC objects. > * would it be possible to disable automatic collection and > implement a custom collection invocation scheme ? It is possible to disable it (gc.set_threshold(0)). I'm not sure what you mean by custom scheme. You can call gc.collect() explicitly if thats what you mean. > * what would an extension type have to do/implement to > participate in GC ? This is documented in objimp.h: /* To make a new object participate in garbage collection use PyObject_{New, VarNew, Del} to manage the memory. Set the type flag Py_TPFLAGS_GC and define the type method tp_recurse. You should also add the method tp_clear if your object is mutable. Include PyGC_INFO_SIZE in the calculation of tp_basicsize. Call PyObject_GC_Init after the pointers followed by tp_recurse become valid (usually just before returning the object from the allocation method. Call PyObject_GC_Fini before those pointers become invalid (usually at the top of the deallocation method). */ > * would an extension compiled with GC still work together > with an interpreter which is not (and vice-versa) ? Yes. An extension compiled with GC enabled will work with a non-GC interpreter and the other way around. For an extension type to participate in GC it must be compiled with GC enabled and be used with a GC interpreter. -- Evolution of Language Through The Ages: 6000 B.C.: ungh. grrf. booga. 2000 A.D.: grep. awk. sed. From nascheme@enme.ucalgary.ca Thu Jun 15 19:53:46 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Thu, 15 Jun 2000 12:53:46 -0600 Subject: [Patches] GC infrastructure patch 2 (type changes) In-Reply-To: ; from moshez@math.huji.ac.il on Thu, Jun 15, 2000 at 06:05:48AM +0300 References: <20000614131507.A16847@acs.ucalgary.ca> Message-ID: <20000615125346.C9717@acs.ucalgary.ca> On Thu, Jun 15, 2000 at 06:05:48AM +0300, Moshe Zadka wrote: > + /* Objects which participate in garbage collection (see objimp.h) */ > + #ifdef WITH_CYCLE_GC > + #define Py_TPFLAGS_GC (1L<<2) > + #else > + #define Py_TPFLAGS_GC 0 > + #endif > > What's wrong with defining Py_TPFLAGS_GC unconditionally? Things are done this way so that extension types compiled with GC disabled will work with a GC enabled interpreter. > c) You seem to be adding GC information to an awful lot of objects. > How much of this can be thrown out without affecting GC greatly? I don't think I can answer that without more Real World(tm) testing. I thought that method objects were not important until I added GC support for them. Reference cycles can show up in surprising places. Just ask Tim Peters. :) Neil -- "Simplicity does not precede complexity, but follows it." -- Alan Perlis From mal@lemburg.com Thu Jun 15 22:50:00 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Thu, 15 Jun 2000 23:50:00 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: <3948963C.7BC06AF9@lemburg.com> <20000615124906.B9717@acs.ucalgary.ca> Message-ID: <39494F88.DC7DA824@lemburg.com> Neil Schemenauer wrote: > > On Thu, Jun 15, 2000 at 10:39:24AM +0200, M.-A. Lemburg wrote: > > Some questions: > > > > * what's the impact of having GC enabled for the class of > > well bahaved programs (those which do not create cyclic > > garbage) ? > > There is the memory overhead of the PyGCInfo struct that is > prefixed to all objects with the GC type flag set (~ 3 words). > By default, the collector runs after X net new object allocations > (this can be tuned or turned off). Because of the generational > collection, the collector usually only looks at a few objects > when it runs. There is also some overhead inserting and removing > GC objects into the linked list of all GC objects. Hmm, I guess we'd need to add some more free lists for small containers then... tuples already have such a list, adding something similar to lists and dictionaries would probably be worthwhile too, both to reduce GC overhead and to boost performance (small lists and dicts being are created/deleted quite often). I have a patch for dicts... anybody have something similar for lists ? I also have a free list implementation for Python instances (which also keeps the instance dicts allocated), BTW. Any interest in this ? > > * would it be possible to disable automatic collection and > > implement a custom collection invocation scheme ? > > It is possible to disable it (gc.set_threshold(0)). I'm not sure > what you mean by custom scheme. You can call gc.collect() > explicitly if thats what you mean. Right, that's what I meant. I would like to implement a different scheme in a server I run in my app: it would run the GC collector after having completed processing a request while waiting for the next request, rather than during a request. > > * what would an extension type have to do/implement to > > participate in GC ? > > This is documented in objimp.h: > > /* To make a new object participate in garbage collection use > PyObject_{New, VarNew, Del} to manage the memory. Set the type flag > Py_TPFLAGS_GC and define the type method tp_recurse. You should also > add the method tp_clear if your object is mutable. Include > PyGC_INFO_SIZE in the calculation of tp_basicsize. Call > PyObject_GC_Init after the pointers followed by tp_recurse become > valid (usually just before returning the object from the allocation > method. Call PyObject_GC_Fini before those pointers become invalid > (usually at the top of the deallocation method). */ That seems easy enough ;-) > > * would an extension compiled with GC still work together > > with an interpreter which is not (and vice-versa) ? > > Yes. An extension compiled with GC enabled will work with a > non-GC interpreter and the other way around. For an extension > type to participate in GC it must be compiled with GC enabled and > be used with a GC interpreter. Great :-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From nascheme@enme.ucalgary.ca Thu Jun 15 23:10:39 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Thu, 15 Jun 2000 16:10:39 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <39494F88.DC7DA824@lemburg.com>; from mal@lemburg.com on Thu, Jun 15, 2000 at 11:50:00PM +0200 References: <3948963C.7BC06AF9@lemburg.com> <20000615124906.B9717@acs.ucalgary.ca> <39494F88.DC7DA824@lemburg.com> Message-ID: <20000615161039.A11507@acs.ucalgary.ca> On Thu, Jun 15, 2000 at 11:50:00PM +0200, M.-A. Lemburg wrote: > Hmm, I guess we'd need to add some more free lists for > small containers then... I don't think this will help the GC too much. Currently I remove tuples from the GC set when they are placed on the free list. My thinking was that setting the pointers to NULL would be more expensive than removing the object from the set. Another advantage is that the collector doesn't have to look at objects on the free list. However, more free lists might help offset the cost of the GC. Neil From mal@lemburg.com Fri Jun 16 09:09:01 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 16 Jun 2000 10:09:01 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: <3948963C.7BC06AF9@lemburg.com> <20000615124906.B9717@acs.ucalgary.ca> <39494F88.DC7DA824@lemburg.com> <20000615161039.A11507@acs.ucalgary.ca> Message-ID: <3949E09D.94726BA1@lemburg.com> Neil Schemenauer wrote: > > On Thu, Jun 15, 2000 at 11:50:00PM +0200, M.-A. Lemburg wrote: > > Hmm, I guess we'd need to add some more free lists for > > small containers then... > > I don't think this will help the GC too much. Currently I remove > tuples from the GC set when they are placed on the free list. My > thinking was that setting the pointers to NULL would be more > expensive than removing the object from the set. Another > advantage is that the collector doesn't have to look at objects > on the free list. However, more free lists might help offset the > cost of the GC. Uhm, I was referring to the memory costs of those 3 additional words needed for every GC aware object, not so much the performance costs. You usually have many small containers and a few big ones. For the big ones those extra words don't matter much, but for the small ones the increase in size may well be noticable, e.g. say you store a database table in a list of small lists. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gstein@lyra.org Fri Jun 16 10:59:27 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 16 Jun 2000 02:59:27 -0700 Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: <39476F64.A08FA321@gmx.de>; from R.Liebscher@gmx.de on Wed, Jun 14, 2000 at 01:41:24PM +0200 References: <20000607102724.E5559@ludwig.cnri.reston.va.us> <39476F64.A08FA321@gmx.de> Message-ID: <20000616025927.Q29590@lyra.org> On Wed, Jun 14, 2000 at 01:41:24PM +0200, Rene Liebscher wrote: > Greg Ward wrote: > > > --- python.patched/dist/src/Include/object.h Tue May 30 10:34:33 2000 > > [...] > > > --- 107,120 ---- > > > PyObject_HEAD \ > > > int ob_size; /* Number of items in variable part */ > > > > > > ! typedef DL_CLASSIMPORT_BEG struct _object { > > > PyObject_HEAD > > > ! } DL_CLASSIMPORT_END PyObject; > > > > > > > > > + typedef DL_CLASSIMPORT_BEG struct { > > > + PyObject_VAR_HEAD > > > + } DL_CLASSIMPORT_END PyVarObject; > > > > This strikes me as really weird style. Do those macros really *have* to > > be wormed into the typedefs in that way? Isn't there a cleaner way to > > do it? > > The Gnu-C compilers need these imports, there are two ways to do so > > struct name { ... } __declspec(dllimport); > > or > > struct __declspec(dllimport) name { ... }; > > Read also > http://gcc.gnu.org/onlinedocs/gcc_4.html#SEC95 (paragraphs 3 and 4) > __declspec is another name for __attribute > They don't mention dllimport and types in the same context, I don't know > why. Maybe because it doesn't apply? I have never seen *linkage* information applied to a typedef. That just doesn't make sense. > (However, MS Visual C++ uses the same import statements for imports of > classes from dll's. egcs 1.1.x uses __declspec() in MS compatible way.) Importing classes is different than importing typedefs. A class usually has some associated data, which needs to have linkage information associated with it. > In typedefs you could have unnamed structs, so I prefer the second. > Even if it seems to work to have such a definition: > typedef struct __declspec(import) { ... } name; > > If you don't have these imports in C-mode you get warnings and in C++ > mode the compiler chrashs. Can you post the warnings that you're receiving? I gotta believe there is something else going on. Cheers, -g -- Greg Stein, http://www.lyra.org/ From gstein@lyra.org Fri Jun 16 11:44:43 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 16 Jun 2000 03:44:43 -0700 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: ; from moshez@math.huji.ac.il on Thu, Jun 15, 2000 at 05:57:39AM +0300 References: <20000614123818.A8975@acs.ucalgary.ca> Message-ID: <20000616034442.T29590@lyra.org> On Thu, Jun 15, 2000 at 05:57:39AM +0300, Moshe Zadka wrote: > On Wed, 14 Jun 2000, Neil Schemenauer wrote: > > > This patch adds the type methods recurse and clear necessary for > > my GC patch. It is straightforward so hopefully it can be > > applied right away. > > a) As spammy as it sounds, you probably want to send this patch again with > the legal mumbo-jumbo... > > b) +0.5, because you are eating into 2 spare slots. Couldn't you just > waste one, and have it point into a structure with those two functions? > I'd certainly be +1 on that. IMO, the two slots are much clearer. I don't think that we want to start grouping this stuff up, just to combine a couple slots. It isn't like we are proposing any other use for those slots right now. +1 on Patch 1 Cheers, -g -- Greg Stein, http://www.lyra.org/ From gstein@lyra.org Fri Jun 16 11:56:29 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 16 Jun 2000 03:56:29 -0700 Subject: [Patches] GC infrastructure patch 2 (type changes) In-Reply-To: ; from moshez@math.huji.ac.il on Thu, Jun 15, 2000 at 06:05:48AM +0300 References: <20000614131507.A16847@acs.ucalgary.ca> Message-ID: <20000616035629.U29590@lyra.org> On Thu, Jun 15, 2000 at 06:05:48AM +0300, Moshe Zadka wrote: > On Wed, 14 Jun 2000, Neil Schemenauer wrote: > > > This patch modifies the type structures of objects that > > participate in GC. The object's tp_basicsize is increased when > > GC is enabled. GC information is prefixed to the object to > > maintain binary compatibility. GC objects also define the > > tp_flag Py_TPFLAGS_GC. > > a) See my other a) > > b) in > > + /* Objects which participate in garbage collection (see objimp.h) */ > + #ifdef WITH_CYCLE_GC > + #define Py_TPFLAGS_GC (1L<<2) > + #else > + #define Py_TPFLAGS_GC 0 > + #endif > > What's wrong with defining Py_TPFLAGS_GC unconditionally? Agreed, here. This is similar to the slots thing. Define it unconditionally. It isn't like ANY other extension can ever use that flag bit for anything else. That bit, from here on, means "GC". Not sure on the overall patch. It would be much nicer to simply include the GC fields into the object. Essentially, have something like this: typedef struct { PyObject_VAR_HEAD_GC PyObject **ob_item; } PyListObject; #define PyObject_VAR_HEAD_GC \ PyObject_HEAD_GC \ int ob_size; #define PyObject_HEAD_GC \ my_three_items PyObject_HEAD In the allocation of these, just do: ptr = (PyListObject *)some_kinda_alloc(...) ob = (PyObject *)&ptr->refcnt; Of course, ob+sizeof(PyListObject) doesn't really point to just after the structure. Not sure if that is good or bad. Hmm. Probably bad. Never mind the above suggestion... :-) [ but left as a possible stimulus for others ] Cheers, -g -- Greg Stein, http://www.lyra.org/ From R.Liebscher@gmx.de Fri Jun 16 17:01:15 2000 From: R.Liebscher@gmx.de (Rene Liebscher) Date: Fri, 16 Jun 2000 18:01:15 +0200 Subject: [Patches] Extension building on Win32 using Gnu C References: <20000607102724.E5559@ludwig.cnri.reston.va.us> <39476F64.A08FA321@gmx.de> <20000616025927.Q29590@lyra.org> Message-ID: <394A4F4B.1A048917@gmx.de> > > The Gnu-C compilers need these imports, there are two ways to do so > > > > struct name { ... } __declspec(dllimport); > > or > > struct __declspec(dllimport) name { ... }; > > > > Read also > > http://gcc.gnu.org/onlinedocs/gcc_4.html#SEC95 (paragraphs 3 and 4) > > __declspec is another name for __attribute > > They don't mention dllimport and types in the same context, I don't know > > why. > > Maybe because it doesn't apply? > > I have never seen *linkage* information applied to a typedef. That just > doesn't make sense. It isn't the typedef, it is about the struct (but it looks like the typedef because all structs are defined in typedefs) If if doesn't apply, why crashs C++ if I don't have in there? (I tried it several times, and checked different positions for this dllimport. I'm sure it belongs to this struct.) > > (However, MS Visual C++ uses the same import statements for imports of > > classes from dll's. egcs 1.1.x uses __declspec() in MS compatible way.) > > Importing classes is different than importing typedefs. A class usually has > some associated data, which needs to have linkage information associated > with it. At least on C++ classes and struct are the same (except struct data are public by default.) > > If you don't have these imports in C-mode you get warnings and in C++ > > mode the compiler chrashs. > > Can you post the warnings that you're receiving? I gotta believe there is > something else going on. Currently I don't have access to my Windows machine, so you have to wait some days for a complete list of warnings. But I remember some things. (All in C mode) Py_INCREF(Py_None); return Py_None; => ( pointer lacks cast ?, I don't remember which line it was.) ---Python's object.h----------------------- #define Py_INCREF(op) ((op)->ob_refcnt++) extern DL_IMPORT(PyObject) _Py_NoneStruct; /* Don't use this directly */ #define Py_None (&_Py_NoneStruct) ---------------------------- You access here > some associated data, which needs to have linkage information associated > with it. ?????????? (Your own words, could it be you know what's wrong and don't know that you know it.) Also if you use type checks. => ( incompatible pointer type ? ) -----object.h-------------------- extern DL_IMPORT(PyTypeObject) PyType_Type; /* The type of type objects */ #define PyType_Check(op) ((op)->ob_type == &PyType_Type) --------------------------------- Maybe I mixed up the warning messages, but I think you can see the point. kind regards Rene Liebscher From nascheme@enme.ucalgary.ca Fri Jun 16 19:20:16 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Fri, 16 Jun 2000 12:20:16 -0600 Subject: [Patches] GC infrastructure patch 2 (type changes) In-Reply-To: <20000616035629.U29590@lyra.org>; from gstein@lyra.org on Fri, Jun 16, 2000 at 03:56:29AM -0700 References: <20000614131507.A16847@acs.ucalgary.ca> <20000616035629.U29590@lyra.org> Message-ID: <20000616122016.A20519@acs.ucalgary.ca> On Fri, Jun 16, 2000 at 03:56:29AM -0700, Greg Stein wrote: > On Thu, Jun 15, 2000 at 06:05:48AM +0300, Moshe Zadka wrote: > > What's wrong with defining Py_TPFLAGS_GC unconditionally? > > Agreed, here. This is similar to the slots thing. Define it > unconditionally. It isn't like ANY other extension can ever use > that flag bit for anything else. That bit, from here on, means > "GC". As I mentioned in another email, this is done so that extensions compiled with WITH_CYCLE_GC undefined will work with a GC enabled interpreter. The bit always means GC. When it is set it means that the object supports GC. Does that make sense? Neil From nascheme@enme.ucalgary.ca Fri Jun 16 19:22:04 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Fri, 16 Jun 2000 12:22:04 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <3949E09D.94726BA1@lemburg.com>; from mal@lemburg.com on Fri, Jun 16, 2000 at 10:09:01AM +0200 References: <3948963C.7BC06AF9@lemburg.com> <20000615124906.B9717@acs.ucalgary.ca> <39494F88.DC7DA824@lemburg.com> <20000615161039.A11507@acs.ucalgary.ca> <3949E09D.94726BA1@lemburg.com> Message-ID: <20000616122204.B20519@acs.ucalgary.ca> On Fri, Jun 16, 2000 at 10:09:01AM +0200, M.-A. Lemburg wrote: > Uhm, I was referring to the memory costs of those 3 additional > words needed for every GC aware object, not so much the > performance costs. Hmm, I'm not following you here. How does using the free lists save the 3 words of memory? Neil -- "Simplicity does not precede complexity, but follows it." -- Alan Perlis From mal@lemburg.com Fri Jun 16 19:50:57 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 16 Jun 2000 20:50:57 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: <3948963C.7BC06AF9@lemburg.com> <20000615124906.B9717@acs.ucalgary.ca> <39494F88.DC7DA824@lemburg.com> <20000615161039.A11507@acs.ucalgary.ca> <3949E09D.94726BA1@lemburg.com> <20000616122204.B20519@acs.ucalgary.ca> Message-ID: <394A7711.5C2DBD02@lemburg.com> Neil Schemenauer wrote: > > On Fri, Jun 16, 2000 at 10:09:01AM +0200, M.-A. Lemburg wrote: > > Uhm, I was referring to the memory costs of those 3 additional > > words needed for every GC aware object, not so much the > > performance costs. > > Hmm, I'm not following you here. How does using the free lists > save the 3 words of memory? Good question... I don't know what made me think that they would save memory -- should drink more coffee before posting ;-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gstein@lyra.org Fri Jun 16 22:25:52 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 16 Jun 2000 14:25:52 -0700 Subject: [Patches] GC infrastructure patch 2 (type changes) In-Reply-To: <20000616122016.A20519@acs.ucalgary.ca>; from nascheme@enme.ucalgary.ca on Fri, Jun 16, 2000 at 12:20:16PM -0600 References: <20000614131507.A16847@acs.ucalgary.ca> <20000616035629.U29590@lyra.org> <20000616122016.A20519@acs.ucalgary.ca> Message-ID: <20000616142552.L29590@lyra.org> On Fri, Jun 16, 2000 at 12:20:16PM -0600, Neil Schemenauer wrote: > On Fri, Jun 16, 2000 at 03:56:29AM -0700, Greg Stein wrote: > > On Thu, Jun 15, 2000 at 06:05:48AM +0300, Moshe Zadka wrote: > > > What's wrong with defining Py_TPFLAGS_GC unconditionally? > > > > Agreed, here. This is similar to the slots thing. Define it > > unconditionally. It isn't like ANY other extension can ever use > > that flag bit for anything else. That bit, from here on, means > > "GC". > > As I mentioned in another email, this is done so that extensions > compiled with WITH_CYCLE_GC undefined will work with a GC enabled > interpreter. The bit always means GC. When it is set it means > that the object supports GC. Does that make sense? Good point. Please insert comments to that effect so that somebody doesn't go and tweak that definition in the future :-) Cheers, -g -- Greg Stein, http://www.lyra.org/ From jeremy@beopen.com Fri Jun 16 23:35:43 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Fri, 16 Jun 2000 18:35:43 -0400 (EDT) Subject: [Patches] patch for core dump in parser Message-ID: <14666.43967.343472.186781@localhost.localdomain> This patch fixes a bug report on the python list today. http://www.python.org/pipermail/python-list/2000-June/061698.html Brief summary: eval("2+2+" * 8192 + "2") The patch mucks with the parser code, which I've never looked at seriously before. The basic idea is to catch the error -- an overflow of the short used to count the number of children and cause a new parser error to be returned, E_OVERFLOW. Python turns that errorcode into the SyntaxError "expression too long." Note that I've changed the signature of PyNode_AddChild. It used to return a node * or NULL. Callers only checked for NULL, so the change seems safe. Jeremy Index: Include/errcode.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/errcode.h,v retrieving revision 2.8 diff -c -r2.8 errcode.h *** Include/errcode.h 1998/04/09 21:37:20 2.8 --- Include/errcode.h 2000/06/16 22:19:53 *************** *** 52,57 **** --- 52,58 ---- #define E_DONE 16 /* Parsing complete */ #define E_ERROR 17 /* Execution error */ #define E_INDENT 18 /* Invalid indentation detected */ + #define E_OVERFLOW 19 /* Node had too many children */ #ifdef __cplusplus } Index: Include/node.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/node.h,v retrieving revision 2.12 diff -c -r2.12 node.h *** Include/node.h 1998/12/04 18:48:11 2.12 --- Include/node.h 2000/06/16 22:19:53 *************** *** 46,52 **** } node; extern DL_IMPORT(node *) PyNode_New Py_PROTO((int type)); ! extern DL_IMPORT(node *) PyNode_AddChild Py_PROTO((node *n, int type, char *str, int lineno)); extern DL_IMPORT(void) PyNode_Free Py_PROTO((node *n)); /* Node access functions */ --- 46,52 ---- } node; extern DL_IMPORT(node *) PyNode_New Py_PROTO((int type)); ! extern DL_IMPORT(int) PyNode_AddChild Py_PROTO((node *n, int type, char *str, int lineno)); extern DL_IMPORT(void) PyNode_Free Py_PROTO((node *n)); /* Node access functions */ Index: Parser/node.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Parser/node.c,v retrieving revision 2.7 diff -c -r2.7 node.c *** Parser/node.c 1997/04/29 21:02:42 2.7 --- Parser/node.c 2000/06/16 22:19:53 *************** *** 33,38 **** --- 33,39 ---- #include "pgenheaders.h" #include "node.h" + #include "errcode.h" node * PyNode_New(type) *************** *** 52,58 **** #define XXX 3 /* Node alignment factor to speed up realloc */ #define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX) ! node * PyNode_AddChild(n1, type, str, lineno) register node *n1; int type; --- 53,59 ---- #define XXX 3 /* Node alignment factor to speed up realloc */ #define XXXROUNDUP(n) ((n) == 1 ? 1 : ((n) + XXX - 1) / XXX * XXX) ! int PyNode_AddChild(n1, type, str, lineno) register node *n1; int type; *************** *** 62,73 **** register int nch = n1->n_nchildren; register int nch1 = nch+1; register node *n; if (XXXROUNDUP(nch) < nch1) { n = n1->n_child; nch1 = XXXROUNDUP(nch1); PyMem_RESIZE(n, node, nch1); if (n == NULL) ! return NULL; n1->n_child = n; } n = &n1->n_child[n1->n_nchildren++]; --- 63,76 ---- register int nch = n1->n_nchildren; register int nch1 = nch+1; register node *n; + if (nch == 32767) + return E_OVERFLOW; if (XXXROUNDUP(nch) < nch1) { n = n1->n_child; nch1 = XXXROUNDUP(nch1); PyMem_RESIZE(n, node, nch1); if (n == NULL) ! return E_NOMEM; n1->n_child = n; } n = &n1->n_child[n1->n_nchildren++]; *************** *** 76,82 **** n->n_lineno = lineno; n->n_nchildren = 0; n->n_child = NULL; ! return n; } /* Forward */ --- 79,85 ---- n->n_lineno = lineno; n->n_nchildren = 0; n->n_child = NULL; ! return 0; } /* Forward */ Index: Parser/parser.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Parser/parser.c,v retrieving revision 2.10 diff -c -r2.10 parser.c *** Parser/parser.c 1997/04/29 21:02:45 2.10 --- Parser/parser.c 2000/06/16 22:19:54 *************** *** 153,163 **** int newstate; int lineno; { assert(!s_empty(s)); ! if (PyNode_AddChild(s->s_top->s_parent, type, str, lineno) == NULL) { ! fprintf(stderr, "shift: no mem in addchild\n"); ! return -1; ! } s->s_top->s_state = newstate; return 0; } --- 153,163 ---- int newstate; int lineno; { + int err; assert(!s_empty(s)); ! err = PyNode_AddChild(s->s_top->s_parent, type, str, lineno); ! if (err) ! return err; s->s_top->s_state = newstate; return 0; } *************** *** 172,184 **** int newstate; int lineno; { register node *n; n = s->s_top->s_parent; assert(!s_empty(s)); ! if (PyNode_AddChild(n, type, (char *)NULL, lineno) == NULL) { ! fprintf(stderr, "push: no mem in addchild\n"); ! return -1; ! } s->s_top->s_state = newstate; return s_push(s, d, CHILD(n, NCH(n)-1)); } --- 172,184 ---- int newstate; int lineno; { + int err; register node *n; n = s->s_top->s_parent; assert(!s_empty(s)); ! err = PyNode_AddChild(n, type, (char *)NULL, lineno); ! if (err) ! return err; s->s_top->s_state = newstate; return s_push(s, d, CHILD(n, NCH(n)-1)); } *************** *** 233,238 **** --- 233,239 ---- int lineno; { register int ilabel; + int err; D(printf("Token %s/'%s' ... ", _PyParser_TokenNames[type], str)); *************** *** 260,279 **** int arrow = x & ((1<<7)-1); dfa *d1 = PyGrammar_FindDFA( ps->p_grammar, nt); ! if (push(&ps->p_stack, nt, d1, ! arrow, lineno) < 0) { D(printf(" MemError: push\n")); ! return E_NOMEM; } D(printf(" Push ...\n")); continue; } /* Shift the token */ ! if (shift(&ps->p_stack, type, str, ! x, lineno) < 0) { D(printf(" MemError: shift.\n")); ! return E_NOMEM; } D(printf(" Shift.\n")); /* Pop while we are in an accept-only state */ --- 261,280 ---- int arrow = x & ((1<<7)-1); dfa *d1 = PyGrammar_FindDFA( ps->p_grammar, nt); ! if ((err = push(&ps->p_stack, nt, d1, ! arrow, lineno)) > 0) { D(printf(" MemError: push\n")); ! return err; } D(printf(" Push ...\n")); continue; } /* Shift the token */ ! if ((err = shift(&ps->p_stack, type, str, ! x, lineno)) > 0) { D(printf(" MemError: shift.\n")); ! return err; } D(printf(" Shift.\n")); /* Pop while we are in an accept-only state */ Index: Python/pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.97 diff -c -r2.97 pythonrun.c *** Python/pythonrun.c 2000/05/25 23:09:49 2.97 --- Python/pythonrun.c 2000/06/16 22:19:56 *************** *** 1033,1038 **** --- 1033,1041 ---- case E_INDENT: msg = "inconsistent use of tabs and spaces in indentation"; break; + case E_OVERFLOW: + msg = "expression too long"; + break; default: fprintf(stderr, "error=%d\n", err->error); msg = "unknown parsing error"; From mhammond@skippinet.com.au Fri Jun 16 23:47:20 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Sat, 17 Jun 2000 08:47:20 +1000 Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: <394A4F4B.1A048917@gmx.de> Message-ID: > If if doesn't apply, why crashs C++ if I don't have in there? Who knows? Why does it work for MSVC? > But I remember some things. (All in C mode) > > Py_INCREF(Py_None); > return Py_None; > => ( pointer lacks cast ?, I don't remember which line it was.) This is wierd. What is the sig of the function this appeared in? > ---Python's object.h----------------------- > #define Py_INCREF(op) ((op)->ob_refcnt++) > extern DL_IMPORT(PyObject) _Py_NoneStruct; /* Don't use this directly */ > #define Py_None (&_Py_NoneStruct) > ---------------------------- > You access here > > some associated data, which needs to have linkage information > associated > > with it. > ?????????? (Your own words, could it be you know what's wrong and don't > know > that you know it.) This isnt any clearer. In these cases, you are looking at an _instance_ of the struct. There is still no need I can see for the struct definition to be exported - that is a compile time issue. The _instance_ of the struct (eg, in the example above, the specific _Py_NoneStruct instance of the struct) is what the imports are needed for. > Also if you use type checks. > => ( incompatible pointer type ? ) You are going to need to be exact here. This doesnt help at all. > Maybe I mixed up the warning messages, but I think you can see the > point. Afraid not :-( Mark. From gstein@lyra.org Sat Jun 17 01:19:48 2000 From: gstein@lyra.org (Greg Stein) Date: Fri, 16 Jun 2000 17:19:48 -0700 Subject: [Patches] patch for core dump in parser In-Reply-To: <14666.43967.343472.186781@localhost.localdomain>; from jeremy@beopen.com on Fri, Jun 16, 2000 at 06:35:43PM -0400 References: <14666.43967.343472.186781@localhost.localdomain> Message-ID: <20000616171948.R29590@lyra.org> On Fri, Jun 16, 2000 at 06:35:43PM -0400, Jeremy Hylton wrote: >... > --- 63,76 ---- > register int nch = n1->n_nchildren; > register int nch1 = nch+1; > register node *n; > + if (nch == 32767) > + return E_OVERFLOW; I would highly recommend that you make that "nch >= 32767" rather than a precise test. For some reason, if nch pops suddenly up to 32768, then you're SOL. (maybe the current code increments one at a time, and you will always catch the 32767, but the test seems a bit fragile over the long haul) Cheers, -g -- Greg Stein, http://www.lyra.org/ From lorenzo@sancho.ccd.uniroma2.it Sat Jun 17 15:29:14 2000 From: lorenzo@sancho.ccd.uniroma2.it (Lorenzo M. Catucci) Date: Sat, 17 Jun 2000 16:29:14 +0200 (CEST) Subject: [Patches] Almost insignificant patch for mmapmodule Message-ID: While compiling mmapfile for 1.5.2, I happened to go looking the sources, and find the stub for the case when mremap is unusable. After looking around and convincing myself under linux mremap should be available to the user, I discovered the symbol is only defined when _GNU_SOURCE is defined; therefore, here is the change: if we are compiling for linux, define _GNU_SOURCE before including mman.h, and all is done. It seems the disclaimer is a bit too much for a one liner, but it's here appended to the patch. Yours, lorenzo *** Python-1.6a2.orig/Modules/mmapmodule.c=09Thu Jun 15 15:50:46 2000 --- Python-1.6a2/Modules/mmapmodule.c=09Thu Jun 15 15:53:45 2000 *************** *** 27,32 **** --- 27,35 ---- #endif =20 #ifdef UNIX + #ifdef __linux__ + #define _GNU_SOURCE /* So we can get MREMAP_MAYMOVE defined */ + #endif #include #include #endif And now the Contribution disclaimer...=20 I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. +-------------------------+----------------------------------------------+ | Lorenzo M. Catucci | Centro di Calcolo e Documentazione | | catucci@ccd.uniroma2.it | Universit=E0 degli Studi di Roma "Tor Vergata" = | | | Via O. Raimondo 18 ** I-00173 ROMA ** ITALY | | Tel. +39 06 7259 2255 | Fax. +39 06 7259 2125 | +-------------------------+----------------------------------------------+ From Vladimir.Marangozov@inrialpes.fr Sat Jun 17 20:58:48 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Sat, 17 Jun 2000 21:58:48 +0200 (CEST) Subject: [Patches] _PyUnicode_New Message-ID: <200006171958.VAA01063@python.inrialpes.fr> This patch fixes an optimisation mystery in _PyUnicodeNew causing segfaults on AIX when the interpreter is compiled with -O. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 -- Disclaimer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -------------------------------[ cut here ]--------------------------- *** unicodeobject.c-orig Sat Jun 17 21:36:34 2000 --- unicodeobject.c Sat Jun 17 21:37:19 2000 *************** *** 213,221 **** /* Unicode freelist & memory allocation */ if (unicode_freelist) { unicode = unicode_freelist; ! unicode_freelist = *(PyUnicodeObject **)unicode_freelist; unicode_freelist_size--; - PyObject_INIT(unicode, &PyUnicode_Type); if (unicode->str) { /* Keep-Alive optimization: we only upsize the buffer, never downsize it. */ --- 213,220 ---- /* Unicode freelist & memory allocation */ if (unicode_freelist) { unicode = unicode_freelist; ! unicode_freelist = *(PyUnicodeObject **)unicode; unicode_freelist_size--; if (unicode->str) { /* Keep-Alive optimization: we only upsize the buffer, never downsize it. */ *************** *** 225,232 **** goto onError; } } ! else unicode->str = PyMem_NEW(Py_UNICODE, length + 1); } else { unicode = PyObject_NEW(PyUnicodeObject, &PyUnicode_Type); --- 224,233 ---- goto onError; } } ! else { unicode->str = PyMem_NEW(Py_UNICODE, length + 1); + } + PyObject_INIT(unicode, &PyUnicode_Type); } else { unicode = PyObject_NEW(PyUnicodeObject, &PyUnicode_Type); From Vladimir.Marangozov@inrialpes.fr Sat Jun 17 23:26:29 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Sun, 18 Jun 2000 00:26:29 +0200 (CEST) Subject: [Patches] getargs.c Message-ID: <200006172226.AAA01568@python.inrialpes.fr> This patch fixes a problem on AIX with the signed int case code in getargs.c, after Trent Mick's intervention about MIN/MAX overflow checks. The AIX compiler/optimizer generates bogus code with the default flags "-g -O" causing test_builtin to fail: int("10", 16) <> 16L. Hopefully, swapping the two checks in the signed int code makes the problem go away. Also, make the error messages fit in 80 char lines. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 -- Disclaimer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -------------------------------[ cut here ]--------------------------- *** getargs.c-orig Sat Jun 17 23:12:18 2000 --- getargs.c Sat Jun 17 23:59:07 2000 *************** *** 473,484 **** return "integer"; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, ! "unsigned byte integer is less than minimum"); return "integer"; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, ! "unsigned byte integer is greater than maximum"); return "integer"; } else --- 473,484 ---- return "integer"; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, ! "unsigned byte integer is less than minimum"); return "integer"; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, ! "unsigned byte integer is greater than maximum"); return "integer"; } else *************** *** 494,505 **** return "integer"; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "signed short integer is less than minimum"); return "integer"; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "signed short integer is greater than maximum"); return "integer"; } else --- 494,505 ---- return "integer"; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "signed short integer is less than minimum"); return "integer"; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "signed short integer is greater than maximum"); return "integer"; } else *************** *** 513,526 **** long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; ! else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "signed integer is less than minimum"); return "integer"; } ! else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "signed integer is greater than maximum"); return "integer"; } else --- 513,526 ---- long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; ! else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "signed integer is greater than maximum"); return "integer"; } ! else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "signed integer is less than minimum"); return "integer"; } else From trentm@activestate.com Sun Jun 18 00:13:17 2000 From: trentm@activestate.com (Trent Mick) Date: Sat, 17 Jun 2000 16:13:17 -0700 Subject: [Patches] getargs.c In-Reply-To: <200006172226.AAA01568@python.inrialpes.fr> References: <200006172226.AAA01568@python.inrialpes.fr> Message-ID: <20000617161317.B19446@activestate.com> On Sun, Jun 18, 2000 at 12:26:29AM +0200, Vladimir Marangozov wrote: > > This patch fixes a problem on AIX with the signed int case code in getargs.c, > after Trent Mick's intervention about MIN/MAX overflow checks. The AIX > compiler/optimizer generates bogus code with the default flags "-g -O" > causing test_builtin to fail: int("10", 16) <> 16L. > Hopefully, swapping > the two checks in the signed int code makes the problem go away. > Does it? Otherwise, I can't see how the patch will cause any issues elsewhere. So, seems okay. Trent -- Trent Mick trentm@activestate.com From Vladimir.Marangozov@inrialpes.fr Sun Jun 18 00:37:35 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Sun, 18 Jun 2000 01:37:35 +0200 (CEST) Subject: [Patches] getargs.c In-Reply-To: <20000617161317.B19446@activestate.com> from "Trent Mick" at Jun 17, 2000 04:13:17 PM Message-ID: <200006172337.BAA01718@python.inrialpes.fr> Trent Mick wrote: > > On Sun, Jun 18, 2000 at 12:26:29AM +0200, Vladimir Marangozov wrote: > > > > This patch fixes a problem on AIX with the signed int case code in getargs.c , > > after Trent Mick's intervention about MIN/MAX overflow checks. The AIX > > compiler/optimizer generates bogus code with the default flags "-g -O" > > causing test_builtin to fail: int("10", 16) <> 16L. > > > Hopefully, swapping > > the two checks in the signed int code makes the problem go away. > > > Does it? Yes, it does. Without optimization, everything was okay, with -O it crashed. This is the second time that swapping statemets in the code alleviates bugs in some (old) AIX optimizers. People reported that more recent versions of the compiler don't show such misbehaviors, but apparently I happen to use a "buggy" one. Although my system is quite old, I'm not in a hurry to upgrade as there may be thousands of people like me... So, as far as such patches don't hurt the semantics of the code, they are fine. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From john@list.org Sun Jun 18 01:32:04 2000 From: john@list.org (John Viega) Date: Sat, 17 Jun 2000 20:32:04 -0400 Subject: [Patches] Unix Mailboxes don't work quite right. Message-ID: <394C1884.CB659557@list.org> The method "_isrealfromline" in mailbox.UnixMailbox doesn't handle some real email messages. I've noticed this by comparing Python's notion of a Mailbox with that of real mailers. In this particular case, one of my real mailboxes has several messages without a time zone offset included, and Python doesn't treat those from lines as the start of a message. I've looked around, and it seems that real mailers seem to treat any sequence of "\nFrom " as a from line. With that in mind, I'd suggest the following changes: Delete lines 104-113. Change "_isrealfromline" to: def _isrealfromline(self, line): return 1 If people want the original behavior for whatever reason, they can override it, but this change would make Python much more compatible with mailers, etc. John From trentm@activestate.com Sun Jun 18 04:24:59 2000 From: trentm@activestate.com (Trent Mick) Date: Sat, 17 Jun 2000 20:24:59 -0700 Subject: [Patches] getargs.c In-Reply-To: <200006172337.BAA01718@python.inrialpes.fr> References: <20000617161317.B19446@activestate.com> <200006172337.BAA01718@python.inrialpes.fr> Message-ID: <20000617202459.B20019@activestate.com> On Sun, Jun 18, 2000 at 01:37:35AM +0200, Vladimir Marangozov wrote: > > So, as far as > such patches don't hurt the semantics of the code, they are fine. > Seconded. +1 Plus you are fixing my poor formatting. That is always good for me. :) Cheers, Trent -- Trent Mick trentm@activestate.com From guido@python.org Sun Jun 18 06:00:57 2000 From: guido@python.org (Guido van Rossum) Date: Sun, 18 Jun 2000 00:00:57 -0500 Subject: [Patches] "David J. MacKenzie": Python 1.5.2 BSD/OS support for dynamic modules Message-ID: <200006180500.AAA09887@cj20424-a.reston1.va.home.com> ------- Forwarded Message Date: Sun, 11 Jun 2000 03:54:31 -0400 From: "David J. MacKenzie" To: support@BSDI.COM, guido@python.org cc: djm@eng.us.uu.net, engprodstaff@eng.us.uu.net Subject: Python 1.5.2 BSD/OS support for dynamic modules This patch adds support for dynamically loaded modules (via the *shared* magic token in Modules/Setup.in) on BSDI BSD/OS 4.0.1 to Python 1.5.2. I think the dynamic library support in BSD/OS 4.1 is the same, so this patch should work there too. Run autoconf after applying, of course. Index: configure.in - --- configure.in 2000/02/17 14:48:49 1.1 +++ configure.in 2000/06/11 07:42:52 1.2 @@ -467,7 +467,7 @@ fi ;; Linux*) LDSHARED="gcc -shared";; dgux*) LDSHARED="ld -G";; - - FreeBSD*/3*) LDSHARED="gcc -shared";; + FreeBSD*/3*|BSD/OS/4*) LDSHARED="gcc -shared";; FreeBSD*|OpenBSD*) LDSHARED="ld -Bshareable";; NetBSD*) if [[ "`$CC -dM -E - This is a multi-part message in MIME format. --------------2F1517A45791ABCEA5F35B38 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit handle_special is not being called in xmllib, in spite of the documentation stating otherwise. This patch adds parser_special, a dummy handle_special, and modifies goahead, as well as add a few directly related globals. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. - Burton Radons (loth@pacificcoast.net) --------------2F1517A45791ABCEA5F35B38 Content-Type: text/plain; charset=us-ascii; name="xmllib.py.diff" Content-Disposition: inline; filename="xmllib.py.diff" Content-Transfer-Encoding: 7bit *** xmllib.py~ Sun Jun 18 01:36:47 2000 --- xmllib.py Sun Jun 18 01:15:12 2000 *************** *** 37,42 **** --- 37,44 ---- endbracket = re.compile(_opS + '>') endbracketfind = re.compile('(?:[^>\'"]|'+_QStr+')*>') tagfind = re.compile(_Name) + specialopen = re.compile('') cdataopen = re.compile(r'') # this matches one of the following: *************** *** 280,285 **** --- 282,293 ---- self.lineno = self.lineno + string.count(rawdata[i:i], '\n') i = k continue + if specialopen.match(rawdata, i): + k = self.parse_special(i) + if k < 0: break + self.lineno = self.lineno + string.count(rawdata[i:i], '\n') + i = k + continue res = xmldecl.match(rawdata, i) if res: if not self.__at_start: *************** *** 476,481 **** --- 484,503 ---- self.handle_cdata(rawdata[i+9:res.start(0)]) return res.end(0) + # Internal -- handle tag, return length or -1 if not terminated + def parse_special(self, i): + rawdata = self.rawdata + if rawdata[i:i+2] <> ' Message-ID: <394CA06C.32163BD8@lemburg.com> John Viega wrote: > > The method "_isrealfromline" in mailbox.UnixMailbox doesn't handle some > real email messages. I've noticed this by comparing Python's notion of > a Mailbox with that of real mailers. In this particular case, one of my > real mailboxes has several messages without a time zone offset included, > and Python doesn't treat those from lines as the start of a message. Those messages are likely to be spam :-) > > I've looked around, and it seems that real mailers seem to treat any > sequence of "\nFrom " as a from line. > > With that in mind, I'd suggest the following changes: > > Delete lines 104-113. > Change "_isrealfromline" to: > > def _isrealfromline(self, line): return 1 > > If people want the original behavior for whatever reason, they can > override it, but this change would make Python much more compatible with > mailers, etc. Why not fix the RE to also match the messages you are seeing your mail box file instead of removing the check completely ? -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Fredrik Lundh" <394CA06C.32163BD8@lemburg.com> Message-ID: <00aa01bfd913$d22c7c40$f2a6b5d4@hagrid> MAL wrote: > > If people want the original behavior for whatever reason, they can > > override it, but this change would make Python much more compatible = with > > mailers, etc. >=20 > Why not fix the RE to also match the messages you are seeing=20 > your mail box file instead of removing the check completely ? maybe because it doesn't really make much sense to look for either "From ", or "From " followed by something else? also see: http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.htm= l Essentially the only safe way to parse that file format is to = consider all lines which begin with the characters "From '' (From-space), = which are preceded by a blank line or beginning-of-file, to be the = division between messages. /.../ Some people will tell you that you should do stricter parsing on = those lines: check for user names and dates and so on. They are wrong. From mal@lemburg.com Sun Jun 18 12:27:42 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sun, 18 Jun 2000 13:27:42 +0200 Subject: [Patches] Unix Mailboxes don't work quite right. References: <394C1884.CB659557@list.org> <394CA06C.32163BD8@lemburg.com> <00aa01bfd913$d22c7c40$f2a6b5d4@hagrid> Message-ID: <394CB22E.C6E8B76@lemburg.com> Fredrik Lundh wrote: > > MAL wrote: > > > If people want the original behavior for whatever reason, they can > > > override it, but this change would make Python much more compatible with > > > mailers, etc. > > > > Why not fix the RE to also match the messages you are seeing > > your mail box file instead of removing the check completely ? > > maybe because it doesn't really make much sense to look for either > "From ", or "From " followed by something else? Huh ? I meant changing the RE to accept more date formats... > also see: > > http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html > > Essentially the only safe way to parse that file format is to consider > all lines which begin with the characters "From '' (From-space), which > are preceded by a blank line or beginning-of-file, to be the division > between messages. /.../ > > Some people will tell you that you should do stricter parsing on those > lines: check for user names and dates and so on. They are wrong. Hmm, that's a rather strong opinion... but the guy in question should know, so I'll change my -1 to +1 :-) PS: Didn't know there was a whole newsgroup devoted to mail headers. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Fredrik Lundh" This is a multi-part message in MIME format. ------=_NextPart_000_0024_01BFD936.405A8A00 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable [as discussed on python-dev] this patch introduces PySequence_Fast and PySequence_Fast_GET_ITEM, and modifies the list.extend method to accept any kind of sequence. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. ------=_NextPart_000_0024_01BFD936.405A8A00 Content-Type: text/plain; name="extend-patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="extend-patch.txt" Index: Include/abstract.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/abstract.h,v retrieving revision 2.17 diff -u -r2.17 abstract.h --- Include/abstract.h 2000/03/10 22:35:06 2.17 +++ Include/abstract.h 2000/06/18 12:54:02 @@ -731,7 +731,6 @@ /* Return the ith element of o, or NULL on failure. This is the equivalent of the Python expression: o[i]. - */ DL_IMPORT(PyObject *) PySequence_GetSlice Py_PROTO((PyObject *o, int i1, int i2)); @@ -783,11 +782,31 @@ This is equivalent to the Python expression: tuple(o) */ + DL_IMPORT(PyObject *) PySequence_List Py_PROTO((PyObject *o)); /* Returns the sequence, o, as a list on success, and NULL on failure. This is equivalent to the Python expression: list(o) + */ + + DL_IMPORT(PyObject *) PySequence_Fast Py_PROTO((PyObject *o, const char* m)); + + /* + Returns the sequence, o, as a tuple, unless it's already a + tuple or list. Use PySequence_Fast_GET_ITEM to access the + members of this list. + + Returns NULL on failure. If the object is not a sequence, + raises a TypeError exception with m as the message text. + */ + +#define PySequence_Fast_GET_ITEM(o, i)\ + (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) + + /* + Return the ith element of o, assuming that o was returned by + PySequence_Fast, and that i is within bounds. */ DL_IMPORT(int) PySequence_Count Py_PROTO((PyObject *o, PyObject *value)); Index: Objects/abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.34 diff -u -r2.34 abstract.c --- Objects/abstract.c 2000/04/05 20:11:20 2.34 +++ Objects/abstract.c 2000/06/18 12:54:12 @@ -1207,6 +1207,26 @@ return type_error("list() argument must be a sequence"); } +PyObject * +PySequence_Fast(v, m) + PyObject *v; + const char* m; +{ + if (v == NULL) + return null_error(); + + if (PyList_Check(v) || PyTuple_Check(v)) { + Py_INCREF(v); + return v; + } + + v = PySequence_Tuple(v); + if (v == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) + return type_error(m); + + return v; +} + int PySequence_Count(s, o) PyObject *s; Index: Objects/listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.72 diff -u -r2.72 listobject.c --- Objects/listobject.c 2000/06/15 14:50:20 2.72 +++ Objects/listobject.c 2000/06/18 12:54:18 @@ -627,16 +627,14 @@ if (!PyArg_ParseTuple(args, "O:extend", &b)) return NULL; - if (!PyList_Check(b)) { - PyErr_SetString(PyExc_TypeError, - "list.extend() argument must be a list"); + b = PySequence_Fast(b, "list.extend() argument must be a sequence"); + if (!b) return NULL; - } - if (PyList_GET_SIZE(b) == 0) { + + if (PyObject_Length(b) == 0) /* short circuit when b is empty */ - Py_INCREF(Py_None); - return Py_None; - } + goto ok; + if (self == (PyListObject*)b) { /* as in list_ass_slice() we must special case the * situation: a.extend(a) @@ -644,6 +642,7 @@ * XXX: I think this way ought to be faster than using * list_slice() the way list_ass_slice() does. */ + Py_DECREF(b); b = PyList_New(selflen); if (!b) return NULL; @@ -653,33 +652,29 @@ PyList_SET_ITEM(b, i, o); } } - else - /* we want b to have the same refcount semantics for the - * Py_XDECREF() in the finally clause regardless of which - * branch in the above conditional we took. - */ - Py_INCREF(b); + + blen = PyObject_Length(b); - blen = PyList_GET_SIZE(b); /* resize a using idiom */ items = self->ob_item; NRESIZE(items, PyObject*, selflen + blen); - if (items == NULL ) { + if (items == NULL) { PyErr_NoMemory(); - goto finally; + goto failed; } self->ob_item = items; - /* populate the end self with b's items */ + /* populate the end of self with b's items */ for (i = 0; i < blen; i++) { - PyObject *o = PyList_GET_ITEM(b, i); + PyObject *o = PySequence_Fast_GET_ITEM(b, i); Py_INCREF(o); PyList_SET_ITEM(self, self->ob_size++, o); } + ok: res = Py_None; Py_INCREF(res); - finally: - Py_XDECREF(b); + failed: + Py_DECREF(b); return res; } ------=_NextPart_000_0024_01BFD936.405A8A00-- From Fredrik Lundh" Message-ID: <007f01bfd935$fa454140$f2a6b5d4@hagrid> This is a multi-part message in MIME format. ------=_NextPart_000_0079_01BFD946.AE0EB200 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable [as discussed on python-dev] this patch adds a fast _flatten function to the _tkinter module, and imports it from Tkinter.py (if available). this speeds up canvas operations like create_line and create_polygon. for example, a create_line with 5000 vertices runs about 50 times faster with this patch in place. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. ------=_NextPart_000_0079_01BFD946.AE0EB200 Content-Type: text/plain; name="tkinter-patch.txt" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="tkinter-patch.txt" Index: Modules/_tkinter.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvsroot/python/python/dist/src/Modules/_tkinter.c,v retrieving revision 1.99 diff -u -r1.99 _tkinter.c --- Modules/_tkinter.c 2000/05/04 15:55:17 1.99 +++ Modules/_tkinter.c 2000/06/18 14:36:36 @@ -1978,6 +1982,105 @@ =0C /**** Tkinter Module ****/ =20 +typedef struct { + PyObject* tuple; + int size; /* current size */ + int maxsize; /* allocated size */ +} FlattenContext; + +static int +_bump(FlattenContext* context, int size) +{ + /* expand tuple to hold (at least) size new items. return true if + successful, false if an exception was raised*/ + + int maxsize =3D context->maxsize * 2; + + if (maxsize < context->size + size) + maxsize =3D context->size + size; + + context->maxsize =3D maxsize; + + return _PyTuple_Resize(&context->tuple, maxsize, 0) >=3D 0; +} + +static int +_flatten1(FlattenContext* context, PyObject* item) +{ + /* add tuple or list to argument tuple (recursively) */ + + int i, size; + + if (PyList_Check(item)) { + size =3D PyList_GET_SIZE(item); + /* preallocate (assume no nesting) */ + if (context->size + size > context->maxsize && !_bump(context, size)) + return 0; + /* copy items to output tuple */ + for (i =3D 0; i < size; i++) { + PyObject *o =3D PyList_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o)) + return 0; + } else if (o !=3D Py_None) { + if (context->size + 1 > context->maxsize && !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, context->size++, o); + } + } + } else if (PyTuple_Check(item)) { + /* same, for tuples */ + size =3D PyTuple_GET_SIZE(item); + if (context->size + size > context->maxsize && !_bump(context, size)) + return 0; + for (i =3D 0; i < size; i++) { + PyObject *o =3D PyTuple_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o)) + return 0; + } else if (o !=3D Py_None) { + if (context->size + 1 > context->maxsize && !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, context->size++, o); + } + } + } else { + PyErr_SetString(PyExc_TypeError, "argument must be sequence"); + return 0; + } + return 1; +} + +static PyObject * +Tkinter_Flatten(PyObject* self, PyObject* args) +{ + FlattenContext context; + PyObject* item; + + if (!PyArg_ParseTuple(args, "O:_flatten", &item)) + return NULL; + + context.maxsize =3D PySequence_Length(item); + if (context.maxsize <=3D 0) + return PyTuple_New(0); +=09 + context.tuple =3D PyTuple_New(context.maxsize); + if (!context.tuple) + return NULL; +=09 + context.size =3D 0; + + if (!_flatten1(&context, item)) + return NULL; + + if (_PyTuple_Resize(&context.tuple, context.size, 0)) + return NULL; + + return context.tuple; +} + static PyObject * Tkinter_Create(self, args) PyObject *self; @@ -2006,6 +2109,7 @@ =20 static PyMethodDef moduleMethods[] =3D { + {"_flatten", Tkinter_Flatten, 1}, {"create", Tkinter_Create, 1}, #ifdef HAVE_CREATEFILEHANDLER {"createfilehandler", Tkapp_CreateFileHandler, 1}, Index: Lib/lib-tk/Tkinter.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D RCS file: /cvsroot/python/python/dist/src/Lib/lib-tk/Tkinter.py,v retrieving revision 1.137 diff -u -r1.137 Tkinter.py --- Lib/lib-tk/Tkinter.py 2000/03/30 23:19:44 1.137 +++ Lib/lib-tk/Tkinter.py 2000/06/18 14:36:43 @@ -39,6 +39,9 @@ res =3D res + (item,) return res =20 +try: _flatten =3D _tkinter._flatten +except AttributeError: pass + def _cnfmerge(cnfs): if type(cnfs) is DictionaryType: return cnfs @@ -54,6 +57,9 @@ for k, v in c.items(): cnf[k] =3D v return cnf + +try: _cnfmerge =3D _tkinter._cnfmerge +except AttributeError: pass =20 class Event: pass ------=_NextPart_000_0079_01BFD946.AE0EB200-- From akuchlin@mems-exchange.org Sun Jun 18 16:00:55 2000 From: akuchlin@mems-exchange.org (Andrew Kuchling) Date: Sun, 18 Jun 2000 11:00:55 -0400 Subject: [Patches] Re: Python 1.5.2 BSD/OS support for dynamic modules In-Reply-To: <200006180500.AAA09887@cj20424-a.reston1.va.home.com>; from guido@python.org on Sun, Jun 18, 2000 at 12:00:57AM -0500 References: <200006180500.AAA09887@cj20424-a.reston1.va.home.com> Message-ID: <20000618110055.A14097@newcnri.cnri.reston.va.us> On Sun, Jun 18, 2000 at 12:00:57AM -0500, Guido van Rossum wrote: >This patch adds support for dynamically loaded modules Something similar to this patch has already been applied to 1.6. From cvs log configure.in: revision 1.107 date: 1999/10/05 21:59:33; author: guido; state: Exp; lines: +3 -1 Dynamic linking support for BSD/OS 4.x as suggested by Vivek Khera One actual difference between the two... Mackenzie's patch has: >@@ -512,6 +512,7 @@ > hp*|HP*) > LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; > FreeBSD/3*) LINKFORSHARED="-Xlinker -export-dynamic";; >+ BSD/OS/4*) LINKFORSHARED="-rdynamic";; > Linux*) LINKFORSHARED="-Xlinker -export-dynamic";; > # -u libsys_s pulls in all symbols in libsys > next/2*|next/3*) LINKFORSHARED="-u libsys_s";; The configure.in currently sets it to -Xlinker -export-dynamic, just like all the other GCC platforms. By symmetry arguments, probably configure.in is right. --amk From viega@list.org Sun Jun 18 17:49:14 2000 From: viega@list.org (John Viega) Date: Sun, 18 Jun 2000 09:49:14 -0700 Subject: [Patches] Unix Mailboxes don't work quite right. In-Reply-To: <394CA06C.32163BD8@lemburg.com>; from M.-A. Lemburg on Sun, Jun 18, 2000 at 12:11:56PM +0200 References: <394C1884.CB659557@list.org> <394CA06C.32163BD8@lemburg.com> Message-ID: <20000618094914.A9011@viega.org> On Sun, Jun 18, 2000 at 12:11:56PM +0200, M.-A. Lemburg wrote: > John Viega wrote: > > > > The method "_isrealfromline" in mailbox.UnixMailbox doesn't handle some > > real email messages. I've noticed this by comparing Python's notion of > > a Mailbox with that of real mailers. In this particular case, one of my > > real mailboxes has several messages without a time zone offset included, > > and Python doesn't treat those from lines as the start of a message. > > Those messages are likely to be spam :-) They're not. It was an outgoing mailbox, and apparently it depends on which mailer I used to send a message. > Why not fix the RE to also match the messages you are seeing > your mail box file instead of removing the check completely ? Because every sequence of "\nFrom " starts a new message as far as every mailer I've ever seen is concerned. If a line of text actually started with "From", then it is supposed to be escaped with a ">" so as to avoid confusing it with a from line. John From guido@python.org Sun Jun 18 21:26:20 2000 From: guido@python.org (Guido van Rossum) Date: Sun, 18 Jun 2000 15:26:20 -0500 Subject: [Patches] Unix Mailboxes don't work quite right. In-Reply-To: Your message of "Sun, 18 Jun 2000 09:49:14 MST." <20000618094914.A9011@viega.org> References: <394C1884.CB659557@list.org> <394CA06C.32163BD8@lemburg.com> <20000618094914.A9011@viega.org> Message-ID: <200006182026.PAA01067@cj20424-a.reston1.va.home.com> > Because every sequence of "\nFrom " starts a new message as far as > every mailer I've ever seen is concerned. If a line of text actually > started with "From", then it is supposed to be escaped with a ">" so > as to avoid confusing it with a from line. That's "\n\nFrom ", actually, and "From " at the start of the file also counts. In the past I've seen mailers that only added the ">" to From lines that looked somewhat like dates, and this is probably why I put that regular expression in there. But I agree with the quoted Mozilla guideline that therein lies madness. That's a +999 for the patch, I guess. :-) --Guido van Rossum (home page: http://www.python.org/~guido/) From mwh21@cam.ac.uk Mon Jun 19 01:20:50 2000 From: mwh21@cam.ac.uk (Michael Hudson) Date: Mon, 19 Jun 2000 01:20:50 +0100 (BST) Subject: [Patches] protection for marshalling recursive data structures Message-ID: As I really do not have anything better to do at the moment, I've written a patch to Python/marshal.c that prevents Python dumping core when trying to marshal stack bustingly deep (or recursive) data structure. It just throws an exception; even slightly clever handling of recursive data is what pickle is for... Index: marshal.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/marshal.c,v retrieving revision 1.47 diff -u -r1.47 marshal.c --- marshal.c 2000/05/03 23:44:39 1.47 +++ marshal.c 2000/06/19 00:18:44 @@ -58,6 +58,7 @@ typedef struct { FILE *fp; int error; + int depth; /* If fp == NULL, the following are valid: */ PyObject *str; char *ptr; @@ -144,8 +145,13 @@ { int i, n; PyBufferProcs *pb; + + p->depth++; - if (v == NULL) { + if (p->depth > 5000) { + p->error = 2; + } + else if (v == NULL) { w_byte(TYPE_NULL, p); } else if (v == Py_None) { @@ -301,6 +307,7 @@ WFILE wf; wf.fp = fp; wf.error = 0; + wf.depth = 0; w_long(x, &wf); } @@ -690,6 +697,7 @@ wf.ptr = PyString_AS_STRING((PyStringObject *)wf.str); wf.end = wf.ptr + PyString_Size(wf.str); wf.error = 0; + wf.depth = 0; w_object(x, &wf); if (wf.str != NULL) _PyString_Resize(&wf.str, @@ -697,7 +705,9 @@ PyString_AS_STRING((PyStringObject *)wf.str))); if (wf.error) { Py_XDECREF(wf.str); - PyErr_SetString(PyExc_ValueError, "unmarshallable object"); + PyErr_SetString(PyExc_ValueError, + (wf.error==1)?"unmarshallable object" + :"object too deeply nested to marshal"); return NULL; } return wf.str; @@ -724,9 +734,12 @@ wf.str = NULL; wf.ptr = wf.end = NULL; wf.error = 0; + wf.depth = 0; w_object(x, &wf); if (wf.error) { - PyErr_SetString(PyExc_ValueError, "unmarshallable object"); + PyErr_SetString(PyExc_ValueError, + (wf.error==1)?"unmarshallable object" + :"object too deeply nested to marshal"); return NULL; } Py_INCREF(Py_None); On my machine, it seems an unpatched marshal blows up at a depth of about 13000, so I hope 5000 is OK almost everywhere. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Cheers, M. From R.Liebscher@gmx.de Mon Jun 19 11:40:54 2000 From: R.Liebscher@gmx.de (Rene Liebscher) Date: Mon, 19 Jun 2000 12:40:54 +0200 Subject: [Patches] Extension building on Win32 using Gnu C References: Message-ID: <394DF8B6.8874A234@gmx.de> Good news, I tried last weekend an up-to-date version of gcc (2.95.2) and it works now without these struct-imports. I used before an older version (2.91.57) which I got from ftp://go.cygnus.com/pub/sourceware.cygnus.com/cygwin/latest/ but this is quite old (Dec 1998). (Some months ago this site was mentioned on cygnus website as the directory containing the latest release of cygwin.) So,it was a bug in the compiler. I found in its mailing list a bug report concerning this bug. http://sourceware.cygnus.com/ml/cygwin/1999-02/msg00484.html Using an up-to-date compiler we don't have these problems anymore. I think we should warn the user if he is using such a older,buggy compiler. In config.h's GNUC section we could insert something like that: #if (__GNUC__==2) && (__GNUC_MINOR__<=91) #warning "Please use an up-to-date version of gcc" #endif (All what you need to make python gnu-c compatible is this section in its config.h file. The rest was a "bug workaround".) kind regards Rene Liebscher PS: ++++++++++++++++++++++++++ For those of you who are still interested what the problem was, here the complete description. * C mode Using of ob_type member of struct _typeobject gives you an warning : Most type checks are macros ! ( arg is of type PyObject* ) PyCObject_Check(arg) ==> warning: comparison of distinct pointer types lacks a cast not only for this, also for PyTuple_Check(arg) ... but not for PyCallable_Check(arg) this is realized as external funtion, not as macro Also if you initialize you own types. /* module initialization */ void initfoo(){ Foo_Type.ob_type = &PyType_Type; /* this is a workaround for MSVC and other Windows compilers */ ==> warning: assignment from incompatible pointer type ... } These two can be avoided by importing struct _typeobject. Another warning you get if you use dll-imported data in return statements: PyObject* f(...) { ... Py_INCREF(Py_None); return Py_None; ==> warning: return from incompatible pointer type } If you import PyObject this warning also disappears. * C++ mode Compiler crashs: [main] C:\CYGNUS\CYGWIN-B20\H-I586-CYGWIN32\LIB\GCC-LIB\I586-CYGWIN32\EGCS-2.91.57\CC1PLUS.EXE 1006 (0) handle_exceptions: Exception: STATUS_ACCESS_VIOLATION [main] CC1PLUS 1006 (0) handle_exceptions: Dumping stack trace to CC1PLUS.EXE.core content of CC1PLUS.EXE.core: [main] CC1PLUS 1006 (0) exception: trapped! [main] CC1PLUS 1006 (0) exception: code 0xC0000005 at 0x43929C [main] CC1PLUS 1006 (0) exception: ax 0x0 bx 0x0 cx 0x270F1BC dx 0x48 [main] CC1PLUS 1006 (0) exception: si 0x270F1BC di 0x2792238 bp 0x270F12C sp 0x270F124 [main] CC1PLUS 1006 (0) exception: exception is: STATUS_ACCESS_VIOLATION [main] CC1PLUS 1006 (0) stack: Stack trace: [main] CC1PLUS 1006 (0) stack: frame 0: sp = 0x270EF20, pc = 0x6100A2C3 ... [main] CC1PLUS 1006 (0) stack: frame 15: sp = 0x270FB68, pc = 0x48FB85 [main] CC1PLUS 1006 (0) stack: End of stack trace (more stack frames may be present) +++++++++++++++++++++++++++++++++ From fdrake@beopen.com Mon Jun 19 14:25:54 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Mon, 19 Jun 2000 09:25:54 -0400 (EDT) Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: <394DF8B6.8874A234@gmx.de> References: <394DF8B6.8874A234@gmx.de> Message-ID: <14670.8034.259577.659664@cj42289-a.reston1.va.home.com> Rene Liebscher writes: > Using an up-to-date compiler we don't have these problems anymore. > I think we should warn the user if he is using such a older,buggy > compiler. In config.h's GNUC section we could insert something > like that: > > #if (__GNUC__==2) && (__GNUC_MINOR__<=91) > #warning "Please use an up-to-date version of gcc" > #endif Were older versions of the compiler broken as well? Do you know if this problem was shared by all versions <= 2.91.*? I'd hate to exclude too many versions of the compiler, but I don't know how common older versions are. I have little idea how often people using the GCC ports to Windows are willing to upgrade their compiler; if they commonly stay up to date this might be the best approach. Should the #warning be made into a #error? Thanks! -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From dan@cgsoftware.com Mon Jun 19 14:30:50 2000 From: dan@cgsoftware.com (Daniel Berlin) Date: Mon, 19 Jun 2000 06:30:50 -0700 (PDT) Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: <14670.8034.259577.659664@cj42289-a.reston1.va.home.com> Message-ID: > > Were older versions of the compiler broken as well? Most likely. > Do you know if > this problem was shared by all versions <= 2.91.*? The only version <= 2.91 that might have a chance at not being buggy would be 2.8.1, but nobody uses it. > I'd hate to > exclude too many versions of the compiler, but I don't know how common > older versions are. These days, the earliest you'll see is 2.91.66, which corresponds to egcs 1.1. > I have little idea how often people using the GCC > ports to Windows are willing to upgrade their compiler; if they > commonly stay up to date this might be the best approach. People who are concerned about stability tend to stay one major release behind, mainly because before EGCS became the official GCC, major releases often had very annoying bugs. > Should the #warning be made into a #error? > Thanks! > > > -Fred > > -- > Fred L. Drake, Jr. > BeOpen PythonLabs Team Member > > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches > From fdrake@beopen.com Mon Jun 19 14:38:39 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Mon, 19 Jun 2000 09:38:39 -0400 (EDT) Subject: [Patches] Extension building on Win32 using Gnu C In-Reply-To: References: <14670.8034.259577.659664@cj42289-a.reston1.va.home.com> Message-ID: <14670.8799.164083.353719@cj42289-a.reston1.va.home.com> Daniel Berlin writes: > People who are concerned about stability tend to stay one major > release behind, mainly because before EGCS became the official GCC, major > releases often had very annoying bugs. Sounds like this is safe to accept; I'll check it in momentarily. Thanks! -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From skip@mojam.com (Skip Montanaro) Mon Jun 19 16:43:13 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Mon, 19 Jun 2000 10:43:13 -0500 Subject: [Patches] list comprehensions Message-ID: <200006191543.KAA23239@beluga.mojam.com> In python-dev Guido wrote: me> I thought I submitted a 1.6-compatible update of Greg Ewing's mods me> awhile ago. Should I resubmit? To the patches list? guido> It's rather late in the release cycle -- I'm trying to get alpha guido> 3 released, and i'm still 1400 messages behind on my email. guido> But submitting a patch might be a good idea anyway so we won't guido> forget about it (and maybe it's of such baffling simplicity that guido> it'll charm its way past the guards :-). Just so it doesn't get forgotten, the appended patch adds list comprehensions to Python as developed by Greg Ewing (greg@cosc.canterbury.ac.nz). I only tweaked Greg's original changes to work with 1.6. That said, you should probably get a disclaimer from Greg as well. The patch includes mods to test_grammar.py which pass, though at this point there are no documentation updates. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Skip Montanaro, skip@mojam.com, http://www.mojam.com/, http://www.musi-cal.com/ On June 24th at 8AM, live your life for an hour as Ricky Byrdsong always lived his - run/walk in the Ricky Byrdsong Memorial 5K or just make a donation: https://www.SignmeupSports.com/Events/Index_Events.asp?EventID=1395 Index: Grammar/Grammar =================================================================== RCS file: /cvsroot/python/python/dist/src/Grammar/Grammar,v retrieving revision 1.35 diff -a -u -r1.35 Grammar --- Grammar/Grammar 2000/03/28 23:49:00 1.35 +++ Grammar/Grammar 2000/06/19 15:03:26 @@ -74,7 +74,7 @@ term: factor (('*'|'/'|'%') factor)* factor: ('+'|'-'|'~') factor | power power: atom trailer* ('**' factor)* -atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+ +atom: '(' [testlist] ')' | '[' [testlist [list_iter]] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+ lambdef: 'lambda' [varargslist] ':' test trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] @@ -88,3 +88,9 @@ arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) argument: [test '='] test # Really [keyword '='] test + +# +list_iter: list_for | list_if +list_for: 'for' exprlist 'in' testlist [list_iter] +list_if: 'if' test [list_iter] +# Index: Include/graminit.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/graminit.h,v retrieving revision 2.13 diff -a -u -r2.13 graminit.h --- Include/graminit.h 1997/04/02 05:23:10 2.13 +++ Include/graminit.h 2000/06/19 15:03:26 @@ -55,3 +55,6 @@ #define classdef 310 #define arglist 311 #define argument 312 +#define list_iter 313 +#define list_for 314 +#define list_if 315 Index: Lib/test/test_grammar.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_grammar.py,v retrieving revision 1.13 diff -a -u -r1.13 test_grammar.py --- Lib/test/test_grammar.py 2000/03/28 23:51:13 1.13 +++ Lib/test/test_grammar.py 2000/06/19 15:03:26 @@ -542,3 +542,38 @@ def meth1(self): pass def meth2(self, arg): pass def meth3(self, a1, a2): pass + +### list comprehensions... +nums = [1, 2, 3, 4, 5] +strs = ["Apple", "Banana", "Coconut"] +spcs = [" Apple", " Banana ", "Coco nut "] + +print [s.strip() for s in spcs] +print [3 * x for x in nums] +print [x for x in nums if x > 2] +print [i, s for i in nums for s in strs] +print [i, s for i in nums for s in [f for f in strs if "n" in f]] + +suppliers = [ + (1, "Boeing"), + (2, "Ford"), + (3, "Macdonalds") +] + +parts = [ + (10, "Airliner"), + (20, "Engine"), + (30, "Cheeseburger") +] + +suppart = [ + (1, 10), (1, 20), (2, 20), (3, 30) +] + +print [ + (sname, pname) + for (sno, sname) in suppliers + for (pno, pname) in parts + for (sp_sno, sp_pno) in suppart + if sno == sp_sno and pno == sp_pno +] Index: Lib/test/output/test_grammar =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/output/test_grammar,v retrieving revision 1.3 diff -a -u -r1.3 test_grammar --- Lib/test/output/test_grammar 2000/03/28 23:53:22 1.3 +++ Lib/test/output/test_grammar 2000/06/19 15:03:26 @@ -45,3 +45,9 @@ atoms classdef +['Apple', 'Banana', 'Coco nut'] +[3, 6, 9, 12, 15] +[3, 4, 5] +[(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')] +[(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), (5, 'Banana'), (5, 'Coconut')] +[('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), ('Macdonalds', 'Cheeseburger')] Index: Python/compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.108 diff -a -u -r2.108 compile.c --- Python/compile.c 2000/05/03 23:44:38 2.108 +++ Python/compile.c 2000/06/19 15:03:27 @@ -329,6 +329,7 @@ #ifdef PRIVATE_NAME_MANGLING char *c_private; /* for private name mangling */ #endif + int c_tmpname; /* temp local name counter */ /*LISTCOMP*/ }; @@ -412,6 +413,16 @@ static void com_list Py_PROTO((struct compiling *, node *, int)); static int com_argdefs Py_PROTO((struct compiling *, node *)); static int com_newlocal Py_PROTO((struct compiling *, char *)); +/**/ +static void com_list_for Py_PROTO((struct compiling *, + node *, node *, char *)); +static void com_list_if Py_PROTO((struct compiling *, + node *, node *, char *)); +static void com_list_iter Py_PROTO((struct compiling *, + node *, int, node *, char *)); +static void com_list_comprehension Py_PROTO((struct compiling *, node *)); +static void com_assign Py_PROTO((struct compiling *, node *, int)); +/**/ static PyCodeObject *icompile Py_PROTO((struct _node *, struct compiling *)); static PyCodeObject *jcompile Py_PROTO((struct _node *, char *, struct compiling *)); @@ -463,6 +474,7 @@ c->c_last_addr = 0; c->c_last_line = 0; c-> c_lnotab_next = 0; + c->c_tmpname = 0; return 1; fail: @@ -1025,6 +1037,121 @@ return NULL; } +/**/ + +static void +com_list_for(c, n, e, t) +struct compiling *c; +node *n, *e; +char *t; +{ + PyObject *v; + int anchor = 0; + int save_begin = c->c_begin; + + /*com_addfwref(c, SETUP_LOOP, &break_anchor);*/ + /*block_push(c, SETUP_LOOP);*/ + /* list_iter: for v in expr [list_iter] */ + com_node(c, CHILD(n, 3)); /* expr */ + v = PyInt_FromLong(0L); + if (v == NULL) + c->c_errors++; + com_addoparg(c, LOAD_CONST, com_addconst(c, v)); + com_push(c, 1); + Py_XDECREF(v); + c->c_begin = c->c_nexti; + com_addoparg(c, SET_LINENO, n->n_lineno); + com_addfwref(c, FOR_LOOP, &anchor); + com_push(c, 1); + com_assign(c, CHILD(n, 1), OP_ASSIGN); + c->c_loops++; + com_list_iter(c, n, 4, e, t); + c->c_loops--; + com_addoparg(c, JUMP_ABSOLUTE, c->c_begin); + c->c_begin = save_begin; + com_backpatch(c, anchor); + com_pop(c, 2); /* FOR_LOOP has popped these */ + /*com_addbyte(c, POP_BLOCK);*/ + /*block_pop(c, SETUP_LOOP);*/ + /*com_backpatch(c, break_anchor);*/ +} + +static void +com_list_if(c, n, e, t) +struct compiling *c; +node *n, *e; +char *t; +{ + int anchor = 0; + int a = 0; + /* list_iter: 'if' test [list_iter] */ + com_addoparg(c, SET_LINENO, n->n_lineno); + com_node(c, CHILD(n, 1)); + com_addfwref(c, JUMP_IF_FALSE, &a); + com_addbyte(c, POP_TOP); + com_pop(c, 1); + com_list_iter(c, n, 2, e, t); + com_addfwref(c, JUMP_FORWARD, &anchor); + com_backpatch(c, a); + /* We jump here with an extra entry which we now pop */ + com_addbyte(c, POP_TOP); + com_backpatch(c, anchor); +} + +static void +com_list_iter(c, p, i, e, t) +struct compiling *c; +node *p; /* parent of list_iter node */ +int i; /* child no. in p of list_iter node */ +node *e; /* element expression */ +char *t; /* name of result list temp local */ +{ + if (i < NCH(p)) { + node *n = CHILD(p, i); + n = CHILD(n, 0); + switch (TYPE(n)) { + case list_for: + com_list_for(c, n, e, t); + break; + case list_if: + com_list_if(c, n, e, t); + break; + default: + com_error(c, PyExc_SystemError, "invalid list_iter node type"); + } + } + else { + com_addopnamestr(c, LOAD_NAME, t); + com_push(c, 1); + com_addopnamestr(c, LOAD_ATTR, "append"); + com_node(c, e); + com_addoparg(c, CALL_FUNCTION, 1); + com_addbyte(c, POP_TOP); + com_pop(c, 2); + } +} + +static void +com_list_comprehension(c, n) +struct compiling *c; +node *n; +{ + /* atom: '[' test list_iter ']' */ + char tmpname[8]; + sprintf(tmpname, "%d", ++c->c_tmpname); + com_addoparg(c, BUILD_LIST, 0); + com_push(c, 1); + com_addopnamestr(c, STORE_NAME, tmpname); + com_pop(c, 1); + com_list_iter(c, n, 2, CHILD(n, 1), tmpname); + com_addopnamestr(c, LOAD_NAME, tmpname); + com_push(c, 1); + com_addopnamestr(c, DELETE_NAME, tmpname); + --c->c_tmpname; +} + +/**/ + static void com_list_constructor(c, n) struct compiling *c; @@ -1037,7 +1164,7 @@ /* exprlist: expr (',' expr)* [',']; likewise for testlist */ len = (NCH(n) + 1) / 2; for (i = 0; i < NCH(n); i += 2) - com_node(c, CHILD(n, i)); + com_node(c, CHILD(n, i)); com_addoparg(c, BUILD_LIST, len); com_pop(c, len-1); } @@ -1086,8 +1213,10 @@ com_addoparg(c, BUILD_LIST, 0); com_push(c, 1); } - else + else if (TYPE(CHILD(n, 2)) == RSQB) /*LISTCOMP*/ com_list_constructor(c, CHILD(n, 1)); + else /*LISTCOMP*/ + com_list_comprehension(c, n); /*LISTCOMP*/ break; case LBRACE: /* '{' [dictmaker] '}' */ com_addoparg(c, BUILD_MAP, 0); Index: Python/graminit.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/graminit.c,v retrieving revision 2.23 diff -a -u -r2.23 graminit.c --- Python/graminit.c 2000/03/28 23:49:17 2.23 +++ Python/graminit.c 2000/06/19 15:03:27 @@ -896,11 +896,11 @@ static arc arcs_45_0[7] = { {16, 1}, {109, 2}, - {111, 3}, - {114, 4}, + {112, 3}, + {115, 4}, {12, 5}, - {115, 5}, - {116, 6}, + {116, 5}, + {117, 6}, }; static arc arcs_45_1[2] = { {9, 7}, @@ -908,11 +908,11 @@ }; static arc arcs_45_2[2] = { {9, 8}, - {110, 5}, + {111, 5}, }; static arc arcs_45_3[2] = { - {112, 9}, - {113, 5}, + {113, 9}, + {114, 5}, }; static arc arcs_45_4[1] = { {9, 10}, @@ -921,22 +921,26 @@ {0, 5}, }; static arc arcs_45_6[2] = { - {116, 6}, + {117, 6}, {0, 6}, }; static arc arcs_45_7[1] = { {18, 5}, }; -static arc arcs_45_8[1] = { - {110, 5}, +static arc arcs_45_8[2] = { + {110, 11}, + {111, 5}, }; static arc arcs_45_9[1] = { - {113, 5}, + {114, 5}, }; static arc arcs_45_10[1] = { - {114, 5}, + {115, 5}, }; -static state states_45[11] = { +static arc arcs_45_11[1] = { + {111, 5}, +}; +static state states_45[12] = { {7, arcs_45_0}, {2, arcs_45_1}, {2, arcs_45_2}, @@ -945,12 +949,13 @@ {1, arcs_45_5}, {2, arcs_45_6}, {1, arcs_45_7}, - {1, arcs_45_8}, + {2, arcs_45_8}, {1, arcs_45_9}, {1, arcs_45_10}, + {1, arcs_45_11}, }; static arc arcs_46_0[1] = { - {117, 1}, + {118, 1}, }; static arc arcs_46_1[2] = { {17, 2}, @@ -978,11 +983,11 @@ {52, 3}, }; static arc arcs_47_1[2] = { - {118, 4}, + {119, 4}, {18, 5}, }; static arc arcs_47_2[1] = { - {119, 6}, + {120, 6}, }; static arc arcs_47_3[1] = { {12, 5}, @@ -994,7 +999,7 @@ {0, 5}, }; static arc arcs_47_6[1] = { - {110, 5}, + {111, 5}, }; static state states_47[7] = { {3, arcs_47_0}, @@ -1006,14 +1011,14 @@ {1, arcs_47_6}, }; static arc arcs_48_0[1] = { - {120, 1}, + {121, 1}, }; static arc arcs_48_1[2] = { {22, 2}, {0, 1}, }; static arc arcs_48_2[2] = { - {120, 1}, + {121, 1}, {0, 2}, }; static state states_48[3] = { @@ -1035,14 +1040,14 @@ }; static arc arcs_49_3[3] = { {21, 5}, - {121, 6}, + {122, 6}, {0, 3}, }; static arc arcs_49_4[1] = { {52, 6}, }; static arc arcs_49_5[2] = { - {121, 6}, + {122, 6}, {0, 5}, }; static arc arcs_49_6[1] = { @@ -1129,7 +1134,7 @@ {2, arcs_53_4}, }; static arc arcs_54_0[1] = { - {122, 1}, + {123, 1}, }; static arc arcs_54_1[1] = { {12, 2}, @@ -1164,7 +1169,7 @@ {1, arcs_54_7}, }; static arc arcs_55_0[3] = { - {123, 1}, + {124, 1}, {23, 2}, {24, 3}, }; @@ -1179,7 +1184,7 @@ {21, 6}, }; static arc arcs_55_4[4] = { - {123, 1}, + {124, 1}, {23, 2}, {24, 3}, {0, 4}, @@ -1222,14 +1227,71 @@ {2, arcs_56_1}, {1, arcs_56_2}, {1, arcs_56_3}, +}; +static arc arcs_57_0[2] = { + {125, 1}, + {126, 1}, +}; +static arc arcs_57_1[1] = { + {0, 1}, +}; +static state states_57[2] = { + {2, arcs_57_0}, + {1, arcs_57_1}, +}; +static arc arcs_58_0[1] = { + {67, 1}, +}; +static arc arcs_58_1[1] = { + {39, 2}, }; -static dfa dfas[57] = { +static arc arcs_58_2[1] = { + {56, 3}, +}; +static arc arcs_58_3[1] = { + {9, 4}, +}; +static arc arcs_58_4[2] = { + {110, 5}, + {0, 4}, +}; +static arc arcs_58_5[1] = { + {0, 5}, +}; +static state states_58[6] = { + {1, arcs_58_0}, + {1, arcs_58_1}, + {1, arcs_58_2}, + {1, arcs_58_3}, + {2, arcs_58_4}, + {1, arcs_58_5}, +}; +static arc arcs_59_0[1] = { + {63, 1}, +}; +static arc arcs_59_1[1] = { + {21, 2}, +}; +static arc arcs_59_2[2] = { + {110, 3}, + {0, 2}, +}; +static arc arcs_59_3[1] = { + {0, 3}, +}; +static state states_59[4] = { + {1, arcs_59_0}, + {1, arcs_59_1}, + {2, arcs_59_2}, + {1, arcs_59_3}, +}; +static dfa dfas[60] = { {256, "single_input", 0, 3, states_0, - "\004\030\001\000\140\341\153\202\034\200\000\000\060\242\074\004"}, + "\004\030\001\000\140\341\153\202\034\200\000\000\060\042\171\010"}, {257, "file_input", 0, 2, states_1, - "\204\030\001\000\140\341\153\202\034\200\000\000\060\242\074\004"}, + "\204\030\001\000\140\341\153\202\034\200\000\000\060\042\171\010"}, {258, "eval_input", 0, 3, states_2, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, {259, "funcdef", 0, 6, states_3, "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {260, "parameters", 0, 4, states_4, @@ -1241,13 +1303,13 @@ {263, "fplist", 0, 3, states_7, "\000\020\001\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {264, "stmt", 0, 2, states_8, - "\000\030\001\000\140\341\153\202\034\200\000\000\060\242\074\004"}, + "\000\030\001\000\140\341\153\202\034\200\000\000\060\042\171\010"}, {265, "simple_stmt", 0, 4, states_9, - "\000\020\001\000\140\341\153\002\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\140\341\153\002\000\200\000\000\060\042\171\000"}, {266, "small_stmt", 0, 2, states_10, - "\000\020\001\000\140\341\153\002\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\140\341\153\002\000\200\000\000\060\042\171\000"}, {267, "expr_stmt", 0, 2, states_11, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, {268, "print_stmt", 0, 3, states_12, "\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000"}, {269, "del_stmt", 0, 3, states_13, @@ -1275,7 +1337,7 @@ {280, "assert_stmt", 0, 5, states_24, "\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"}, {281, "compound_stmt", 0, 2, states_25, - "\000\010\000\000\000\000\000\200\034\000\000\000\000\000\000\004"}, + "\000\010\000\000\000\000\000\200\034\000\000\000\000\000\000\010"}, {282, "if_stmt", 0, 8, states_26, "\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000"}, {283, "while_stmt", 0, 8, states_27, @@ -1287,59 +1349,65 @@ {286, "except_clause", 0, 5, states_30, "\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000"}, {287, "suite", 0, 5, states_31, - "\004\020\001\000\140\341\153\002\000\200\000\000\060\242\074\000"}, + "\004\020\001\000\140\341\153\002\000\200\000\000\060\042\171\000"}, {288, "test", 0, 4, states_32, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, {289, "and_test", 0, 2, states_33, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\071\000"}, {290, "not_test", 0, 3, states_34, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\071\000"}, {291, "comparison", 0, 2, states_35, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {292, "comp_op", 0, 4, states_36, "\000\000\000\000\000\000\000\001\000\200\374\003\000\000\000\000"}, {293, "expr", 0, 2, states_37, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {294, "xor_expr", 0, 2, states_38, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {295, "and_expr", 0, 2, states_39, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {296, "shift_expr", 0, 2, states_40, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {297, "arith_expr", 0, 2, states_41, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {298, "term", 0, 2, states_42, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {299, "factor", 0, 3, states_43, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {300, "power", 0, 4, states_44, - "\000\020\001\000\000\000\000\000\000\000\000\000\000\240\034\000"}, - {301, "atom", 0, 11, states_45, - "\000\020\001\000\000\000\000\000\000\000\000\000\000\240\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\000\040\071\000"}, + {301, "atom", 0, 12, states_45, + "\000\020\001\000\000\000\000\000\000\000\000\000\000\040\071\000"}, {302, "lambdef", 0, 5, states_46, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\040\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\100\000"}, {303, "trailer", 0, 7, states_47, "\000\000\001\000\000\000\020\000\000\000\000\000\000\040\000\000"}, {304, "subscriptlist", 0, 3, states_48, - "\000\120\001\000\000\000\020\000\000\200\000\000\060\242\074\000"}, + "\000\120\001\000\000\000\020\000\000\200\000\000\060\042\171\000"}, {305, "subscript", 0, 7, states_49, - "\000\120\001\000\000\000\020\000\000\200\000\000\060\242\074\000"}, + "\000\120\001\000\000\000\020\000\000\200\000\000\060\042\171\000"}, {306, "sliceop", 0, 3, states_50, "\000\100\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {307, "exprlist", 0, 3, states_51, - "\000\020\001\000\000\000\000\000\000\000\000\000\060\242\034\000"}, + "\000\020\001\000\000\000\000\000\000\000\000\000\060\042\071\000"}, {308, "testlist", 0, 3, states_52, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, {309, "dictmaker", 0, 5, states_53, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, {310, "classdef", 0, 8, states_54, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\004"}, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\010"}, {311, "arglist", 0, 8, states_55, - "\000\020\201\001\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\201\001\000\000\000\000\000\200\000\000\060\042\171\000"}, {312, "argument", 0, 4, states_56, - "\000\020\001\000\000\000\000\000\000\200\000\000\060\242\074\000"}, + "\000\020\001\000\000\000\000\000\000\200\000\000\060\042\171\000"}, + {313, "list_iter", 0, 2, states_57, + "\000\000\000\000\000\000\000\200\010\000\000\000\000\000\000\000"}, + {314, "list_for", 0, 6, states_58, + "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000"}, + {315, "list_if", 0, 4, states_59, + "\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000"}, }; -static label labels[124] = { +static label labels[127] = { {0, "EMPTY"}, {256, 0}, {4, 0}, @@ -1450,6 +1518,7 @@ {301, 0}, {303, 0}, {9, 0}, + {313, 0}, {10, 0}, {26, 0}, {309, 0}, @@ -1464,10 +1533,12 @@ {306, 0}, {1, "class"}, {312, 0}, + {314, 0}, + {315, 0}, }; grammar _PyParser_Grammar = { - 57, + 60, dfas, - {124, labels}, + {127, labels}, 256 }; From DavidA@ActiveState.com Mon Jun 19 18:44:41 2000 From: DavidA@ActiveState.com (David Ascher) Date: Mon, 19 Jun 2000 10:44:41 -0700 Subject: [Patches] list comprehensions In-Reply-To: <200006191543.KAA23239@beluga.mojam.com> Message-ID: > the appended patch adds list > comprehensions to Python as developed by Greg Ewing > (greg@cosc.canterbury.ac.nz). A patch to the doc would also be good -- I forget what the exact semantics are. --david From skip@mojam.com (Skip Montanaro) Mon Jun 19 22:01:55 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Mon, 19 Jun 2000 16:01:55 -0500 (CDT) Subject: [Patches] list comprehensions In-Reply-To: References: <200006191543.KAA23239@beluga.mojam.com> Message-ID: <14670.35395.211197.346834@beluga.mojam.com> >> [list comprehensions] David> A patch to the doc would also be good -- I forget what the exact David> semantics are. Yeah, I realize that. I'll try and work something into the reference and tutorial manuals. I wanted to get them into the queue. Skip From djm@web.us.uu.net Tue Jun 20 08:55:14 2000 From: djm@web.us.uu.net (David J. MacKenzie) Date: Tue, 20 Jun 2000 03:55:14 -0400 Subject: [Patches] Re: Python 1.5.2 BSD/OS support for dynamic modules In-Reply-To: Message from Andrew Kuchling of "Sun, 18 Jun 2000 11:00:55 EDT." <20000618110055.A14097@newcnri.cnri.reston.va.us> Message-ID: > Something similar to this patch has already been applied to 1.6. > >From cvs log configure.in: > revision 1.107 > date: 1999/10/05 21:59:33; author: guido; state: Exp; lines: +3 -1 > Dynamic linking support for BSD/OS 4.x as suggested by Vivek Khera > > One actual difference between the two... Mackenzie's patch has: > > >@@ -512,6 +512,7 @@ > > hp*|HP*) > > LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; > > FreeBSD/3*) LINKFORSHARED="-Xlinker -export-dynamic";; > >+ BSD/OS/4*) LINKFORSHARED="-rdynamic";; > > Linux*) LINKFORSHARED="-Xlinker -export-dynamic";; > > # -u libsys_s pulls in all symbols in libsys > > next/2*|next/3*) LINKFORSHARED="-u libsys_s";; > > The configure.in currently sets it to -Xlinker -export-dynamic, just > like all the other GCC platforms. By symmetry arguments, probably > configure.in is right. Both ways appear to work. I got the -rdynamic from libtool's BSD/OS configuration in ltconfig.in. From Fredrik Lundh" <20000618152020.B14713@newcnri.cnri.reston.va.us> <008301bfd96e$0bd98d20$f2a6b5d4@hagrid> <394D43B0.8CC7070@lemburg.com> <003101bfdaa0$693b4de0$0900a8c0@SPIFF> <20000620095309.A3039@amarok.cnri.reston.va.us> Message-ID: <007701bfdacc$0d2e87c0$f2a6b5d4@hagrid> This is a multi-part message in MIME format. ------=_NextPart_000_0071_01BFDADC.B3488D80 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable [as discussed on python-dev] amk wrote: > On Tue, Jun 20, 2000 at 12:15:01PM +0200, Fredrik Lundh wrote: > >for the record, my little benchmark now runs about five > >times faster than before -- which means that 16-bit find > >is now ~30% faster than 8-bit find (barry? ;-) >=20 > Speculation: the code in stringobject.c looks like this: > for (; i <=3D last; ++i) > if (s[i] =3D=3D sub[0] && > (n =3D=3D 1 || memcmp(&s[i+1], &sub[1], = n-1) =3D=3D 0)) > return (long)i; > =20 > It checks the first character, and then does the memcmp() skipping the > first character, or succeeds if the substring length is 1; the Unicode > find is simpler, just doing the full memcmp. I wonder if the extra n > =3D=3D 1 and i+1, n-1 arithmetic costs more than it saves? at least on my box (win95, msvc 5)... after simplifying the code, string.find is now faster than sre.search. it's still 15% slower than the 16-bit string find, but I don't have time to dig into that right now... patches are included. =20 I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. ------=_NextPart_000_0071_01BFDADC.B3488D80 Content-Type: text/plain; name="string-patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="string-patch.txt" Index: Objects/stringobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v retrieving revision 2.68 diff -u -r2.68 stringobject.c --- Objects/stringobject.c 2000/06/14 09:18:09 2.68 +++ Objects/stringobject.c 2000/06/20 15:07:51 @@ -651,7 +651,7 @@ i = j = 0; while (i+n <= len) { - if (s[i] == sub[0] && (n == 1 || memcmp(s+i, sub, n) == 0)) { + if (s[i] == sub[0] && memcmp(s+i, sub, n) == 0) { if (maxsplit-- <= 0) break; item = PyString_FromStringAndSize(s+j, (int)(i-j)); @@ -852,8 +852,7 @@ return (long)i; last -= n; for (; i <= last; ++i) - if (s[i] == sub[0] && - (n == 1 || memcmp(&s[i+1], &sub[1], n-1) == 0)) + if (s[i] == sub[0] && memcmp(s+i, sub, n) == 0) return (long)i; } else { @@ -862,8 +861,7 @@ if (n == 0 && i <= last) return (long)last; for (j = last-n; j >= i; --j) - if (s[j] == sub[0] && - (n == 1 || memcmp(&s[j+1], &sub[1], n-1) == 0)) + if (s[j] == sub[0] && memcmp(s+j, sub, n) == 0) return (long)j; } @@ -1415,9 +1413,7 @@ len -= pat_len; for (ii = 0; ii <= len; ii++) { - if (mem[ii] == pat[0] && - (pat_len == 1 || - memcmp(&mem[ii+1], &pat[1], pat_len-1) == 0)) { + if (mem[ii] == pat[0] && memcmp(mem+ii, pat, pat_len) == 0) { return ii; } } ------=_NextPart_000_0071_01BFDADC.B3488D80-- From fdrake@beopen.com Tue Jun 20 16:47:35 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 20 Jun 2000 11:47:35 -0400 (EDT) Subject: [Patches] Re: [Python-Dev] faster 8-bit find/split (was: talking about performance...) In-Reply-To: <007701bfdacc$0d2e87c0$f2a6b5d4@hagrid> References: <005401bfd958$5c0d7b00$f2a6b5d4@hagrid> <20000618152020.B14713@newcnri.cnri.reston.va.us> <008301bfd96e$0bd98d20$f2a6b5d4@hagrid> <394D43B0.8CC7070@lemburg.com> <003101bfdaa0$693b4de0$0900a8c0@SPIFF> <20000620095309.A3039@amarok.cnri.reston.va.us> <007701bfdacc$0d2e87c0$f2a6b5d4@hagrid> Message-ID: <14671.37399.809253.945519@cj42289-a.reston1.va.home.com> Fredrik Lundh writes: > patches are included. Now checked in, thanks! -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From Pekka.Pessi@nokia.com Tue Jun 20 18:45:06 2000 From: Pekka.Pessi@nokia.com (Pekka Pessi) Date: Tue, 20 Jun 2000 20:45:06 +0300 (EEST) Subject: [Patches] Adding sip to urlparse Message-ID: <14671.44450.197852.869640@rama.research.nokia.com> --3cTL+Wu/Kg Content-Type: text/plain; charset=us-ascii Content-Description: message body text Content-Transfer-Encoding: 7bit *** urlparse.py Fri Apr 14 17:02:31 2000 --- urlparse2.py Tue Jun 20 20:43:02 2000 *************** *** 17,30 **** 'https', 'shttp', 'snews', 'prospero', ''] non_hierarchical = ['gopher', 'hdl', 'mailto', 'news', 'telnet', 'wais', ! 'snews', ] uses_params = ['ftp', 'hdl', 'prospero', 'http', ! 'https', 'shttp', ''] uses_query = ['http', 'wais', 'https', 'shttp', ! 'gopher', ''] uses_fragment = ['ftp', 'hdl', 'http', 'gopher', 'news', 'nntp', 'wais', 'https', 'shttp', 'snews', --- 17,30 ---- 'https', 'shttp', 'snews', 'prospero', ''] non_hierarchical = ['gopher', 'hdl', 'mailto', 'news', 'telnet', 'wais', ! 'snews', 'sip' ] uses_params = ['ftp', 'hdl', 'prospero', 'http', ! 'https', 'shttp', 'sip', ''] uses_query = ['http', 'wais', 'https', 'shttp', ! 'gopher', 'sip', ''] uses_fragment = ['ftp', 'hdl', 'http', 'gopher', 'news', 'nntp', 'wais', 'https', 'shttp', 'snews', --3cTL+Wu/Kg Content-Type: text/plain Content-Disposition: inline; filename="stddisclaimer.py" Content-Transfer-Encoding: 7bit I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. --3cTL+Wu/Kg-- From fdrake@beopen.com Tue Jun 20 19:06:29 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 20 Jun 2000 14:06:29 -0400 (EDT) Subject: [Patches] Adding sip to urlparse In-Reply-To: <14671.44450.197852.869640@rama.research.nokia.com> References: <14671.44450.197852.869640@rama.research.nokia.com> Message-ID: <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> What is "sip"? Is it defined by an RFC (which?), or Internet Draft (which? what's the expected activity?). I don't mean to imply that it shouldn't be included, I'm just not aware of what it is or what it's used for. Thanks! -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From Fredrik Lundh" <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> Message-ID: <002c01bfdae3$e4b71ba0$f2a6b5d4@hagrid> fred wrote: > What is "sip"? Is it defined by an RFC (which?), or Internet Draft > (which? what's the expected activity?). > I don't mean to imply that it shouldn't be included, I'm just not > aware of what it is or what it's used for. http://www.faqs.org/rfcs/rfc2543.html From fdrake@beopen.com Tue Jun 20 19:26:46 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 20 Jun 2000 14:26:46 -0400 (EDT) Subject: [Patches] Adding sip to urlparse In-Reply-To: <002c01bfdae3$e4b71ba0$f2a6b5d4@hagrid> References: <14671.44450.197852.869640@rama.research.nokia.com> <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> <002c01bfdae3$e4b71ba0$f2a6b5d4@hagrid> Message-ID: <14671.46950.876043.388001@cj42289-a.reston1.va.home.com> Fredrik Lundh writes: > http://www.faqs.org/rfcs/rfc2543.html Thanks! I'll add this. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From fdrake@beopen.com Tue Jun 20 19:28:28 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 20 Jun 2000 14:28:28 -0400 (EDT) Subject: [Patches] Adding sip to urlparse In-Reply-To: <14671.44450.197852.869640@rama.research.nokia.com> References: <14671.44450.197852.869640@rama.research.nokia.com> Message-ID: <14671.47052.125001.872845@cj42289-a.reston1.va.home.com> Pekka, Thanks! I'll have this checked in momentarily. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From jeremy@beopen.com Tue Jun 20 22:52:51 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Tue, 20 Jun 2000 17:52:51 -0400 (EDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <20000614123818.A8975@acs.ucalgary.ca> References: <20000614123818.A8975@acs.ucalgary.ca> Message-ID: <14671.59315.722952.141655@localhost.localdomain> Neil, This patch defines the recurse function as typedef int (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); What is the return value for? A number of the recurse functions return 1 unless a call to visit fails. Some return 1 even if a visit call returns 0. All of the visit functions in patch4 return 1. It seems like it would make more sense to make it typedef void (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); Or to define the return values and be consistent about checking error returns. Jeremy From nascheme@enme.ucalgary.ca Tue Jun 20 23:03:37 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Tue, 20 Jun 2000 16:03:37 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <14671.59315.722952.141655@localhost.localdomain>; from jeremy@beopen.com on Tue, Jun 20, 2000 at 05:52:51PM -0400 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> Message-ID: <20000620160337.A15169@acs.ucalgary.ca> On Tue, Jun 20, 2000 at 05:52:51PM -0400, Jeremy Hylton wrote: > This patch defines the recurse function as > typedef int (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); > > What is the return value for? The GC doesn't need it but I thought it might be useful in the future. > A number of the recurse functions return 1 unless a call to > visit fails. Some return 1 even if a visit call returns 0. Oops, those should be fixed. tp_recurse should return 0 if any called visit function does (ie. it fails). The GC visit functions all return success (ie. 1). > It seems like it would make more sense to make it > typedef void (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); > > Or to define the return values and be consistent about checking error > returns. Can anyone think of a use for the return value? I guess it could be added back if someone found a use of it. Neil From mal@lemburg.com Wed Jun 21 08:24:19 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Wed, 21 Jun 2000 09:24:19 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> Message-ID: <39506DA3.8DC013A@lemburg.com> Neil Schemenauer wrote: > > On Tue, Jun 20, 2000 at 05:52:51PM -0400, Jeremy Hylton wrote: > > This patch defines the recurse function as > > typedef int (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); > > > > What is the return value for? > > The GC doesn't need it but I thought it might be useful in the > future. > > > A number of the recurse functions return 1 unless a call to > > visit fails. Some return 1 even if a visit call returns 0. > > Oops, those should be fixed. tp_recurse should return 0 if any > called visit function does (ie. it fails). The GC visit > functions all return success (ie. 1). > > > It seems like it would make more sense to make it > > typedef void (*recurseproc) Py_PROTO((PyObject *, visitproc, void *)); > > > > Or to define the return values and be consistent about checking error > > returns. > > Can anyone think of a use for the return value? I guess it could > be added back if someone found a use of it. ... how about -1 for errors and 0 for normal operation. If you don't provide a way to report errors then cleanup actions won't be able to terminate prematurely. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Fredrik Lundh" Message-ID: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> This is a multi-part message in MIME format. ------=_NextPart_000_008A_01BFDB68.D16C9860 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable more warnings: ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' undefined; = assuming extern returning int the attached patch adds this function to the pythonrun.h header file. I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. ------=_NextPart_000_008A_01BFDB68.D16C9860 Content-Type: text/plain; name="pythonrun-patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="pythonrun-patch.txt" Index: Include/pythonrun.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pythonrun.h,v retrieving revision 2.27 diff -u -r2.27 pythonrun.h --- Include/pythonrun.h 2000/05/25 23:05:36 2.27 +++ Include/pythonrun.h 2000/06/21 08:04:54 @@ -94,6 +94,7 @@ /* Various internal finalizers */ DL_IMPORT(void) fini_exceptions Py_PROTO((void)); +DL_IMPORT(void) _PyImport_Fini Py_PROTO((void)); DL_IMPORT(void) PyMethod_Fini Py_PROTO((void)); DL_IMPORT(void) PyFrame_Fini Py_PROTO((void)); DL_IMPORT(void) PyCFunction_Fini Py_PROTO((void)); ------=_NextPart_000_008A_01BFDB68.D16C9860-- From Pekka.Pessi@nokia.com Wed Jun 21 10:59:32 2000 From: Pekka.Pessi@nokia.com (Pekka Pessi) Date: Wed, 21 Jun 2000 12:59:32 +0300 (EEST) Subject: [Patches] Adding sip to urlparse In-Reply-To: <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> References: <14671.44450.197852.869640@rama.research.nokia.com> <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> Message-ID: <14672.37380.341806.853358@rama.research.nokia.com> Fred L. Drake, Jr. writes: > What is "sip"? Is it defined by an RFC (which?), or Internet Draft >(which? what's the expected activity?). Sorry, I foolishly assumed that everyone knew SIP. ;) It is defined in RFC 2453. >aware of what it is or what it's used for. Session Initiation Protocol, aka Internet phone. Pekka From jeremy@beopen.com Wed Jun 21 15:16:11 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Wed, 21 Jun 2000 10:16:11 -0400 (EDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <39506DA3.8DC013A@lemburg.com> References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> Message-ID: <14672.52779.171329.428895@localhost.localdomain> >>>>> "MAL" == M -A Lemburg writes: MAL> Neil Schemenauer wrote: [...] >> Can anyone think of a use for the return value? I guess it could >> be added back if someone found a use of it. MAL> ... how about -1 for errors and 0 for normal operation. If you MAL> don't provide a way to report errors then cleanup actions won't MAL> be able to terminate prematurely. I'm still not convinced that a return value is useful. Here's an example of a function that uses the recurse code and visit code. Note that in the first function the return value is explicitly cast to void. It seems that it we were going to be careful about adding return values, we would need to put some error checking here and explicitly deal with the error return. static void move_root_reachable(PyGCInfo *reachable) { recurseproc recurse; PyGCInfo *gc = reachable->gc_next; for (; gc != reachable; gc=gc->gc_next) { /* careful, reachable list is growing here */ PyObject *op = PyGC_OBJ(gc); recurse = op->ob_type->tp_recurse; (void) recurse(op, (visitproc)visit_reachable, (void *)reachable); } } static int visit_reachable(PyObject *op, PyGCInfo *roots) { PyGCInfo *gc = PyGC_INFO(op); if (gc && gc->gc_refs != GC_MOVED) { gc_list_remove(gc); gc_list_append(gc, roots); gc->gc_refs = GC_MOVED; } return 1; } The recurse function called in the 1st function above will return an error only if the visit function returns an error. The visit function never returns an error. (In fact, none of the visit functions return an error.) On the one hand, it seems appropriate to by careful about error checking. Each function could return -1 for error and 0 for success (or use some other convention), but then all of the code ought to check the return values and do something appropriate when an error is returned. On the other hand, none of the code that is currently implemented looks like it could return an error. The visit_reachable function above is just doing a bunch of pointer operations. The gc_list_ functions do a few pointer assignments and have no return value. If there is going to be a problem, it seems it would be caused by corruption of a PyObject caused by an error elsewhere (perhaps an extension). Better error checking -- just sanity checks -- in the GC code might be helpful, along with a mechanism to print out errors or exceptions that get raised during the traversal. So, concretely I see two courses of action: 1. Change the class and function recurse functions to check the return value of the visit calls they make and return an error if visit returns an error. Then change all the places that call the recurse functions to report an error if the recurse function reports an error. (Not sure how to report the error.) 2. Change the visit and recurse functions to have no return value (void) and worry about error checking later. Jeremy From fdrake@beopen.com Wed Jun 21 14:12:06 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Wed, 21 Jun 2000 09:12:06 -0400 (EDT) Subject: [Patches] Adding sip to urlparse In-Reply-To: <14672.37380.341806.853358@rama.research.nokia.com> References: <14671.44450.197852.869640@rama.research.nokia.com> <14671.45733.968387.361146@cj42289-a.reston1.va.home.com> <14672.37380.341806.853358@rama.research.nokia.com> Message-ID: <14672.48934.474311.436098@cj42289-a.reston1.va.home.com> Pekka Pessi writes: > >aware of what it is or what it's used for. > > Session Initiation Protocol, aka Internet phone. Ah, IP telephony -- no wonder I never heard of it! I can scarcely imagine using the analog variety, much less hooking up a microphone to my computer! Well, it's in, since others probably don't feel as I do about voice communications. ;) -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From sjoerd@oratrix.nl Wed Jun 21 16:28:27 2000 From: sjoerd@oratrix.nl (Sjoerd Mullender) Date: Wed, 21 Jun 2000 17:28:27 +0200 Subject: [Patches] 2 fixes to xmllib Message-ID: <20000621152828.37C56301CE3@bireme.oratrix.nl> These two fixes were approved by me. Peter Kropf: There's a problem with the xmllib module when used with JPython. Specifically, the JPython re module has trouble with the () characters in strings passed into re.compile. Spiros Papadimitriou: I just downloaded xmllib.py ver. 0.3 from python.org and there seems to be a slight typo: Line 654 ("tag = self.stack[-1][0]" in parse_endtag), is indented one level more than it should be. I just thought I'd let you know... Index: xmllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xmllib.py,v retrieving revision 1.17 diff -u -r1.17 xmllib.py --- xmllib.py 2000/02/04 15:39:30 1.17 +++ xmllib.py 2000/06/21 15:22:26 @@ -27,7 +27,7 @@ attrfind = re.compile( _S + '(?P' + _Name + ')' '(' + _opS + '=' + _opS + - '(?P'+_QStr+'|[-a-zA-Z0-9.:+*%?!()_#=~]+))?') + '(?P'+_QStr+'|[-a-zA-Z0-9.:+*%?!\(\)_#=~]+))?') starttagopen = re.compile('<' + _Name) starttagend = re.compile(_opS + '(?P/?)>') starttagmatch = re.compile('<(?P'+_Name+')' @@ -43,8 +43,8 @@ # SYSTEM SystemLiteral # PUBLIC PubidLiteral SystemLiteral _SystemLiteral = '(?P<%s>'+_QStr+')' -_PublicLiteral = '(?P<%s>"[-\'()+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*"|' \ - "'[-()+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*')" +_PublicLiteral = '(?P<%s>"[-\'\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*"|' \ + "'[-\(\)+,./:=?;!*#@$_%% \n\ra-zA-Z0-9]*')" _ExternalId = '(?:SYSTEM|' \ 'PUBLIC'+_S+_PublicLiteral%'pubid'+ \ ')'+_S+_SystemLiteral%'syslit' @@ -652,7 +652,7 @@ return i+1 if not self.__accept_missing_endtag_name: self.syntax_error('no name specified in end tag') - tag = self.stack[-1][0] + tag = self.stack[-1][0] k = i+2 else: tag = res.group(0) I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Sjoerd Mullender From jeremy@beopen.com Wed Jun 21 18:26:21 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Wed, 21 Jun 2000 13:26:21 -0400 (EDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <20000621112223.A22179@acs.ucalgary.ca> References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> <14672.52779.171329.428895@localhost.localdomain> <20000621112223.A22179@acs.ucalgary.ca> Message-ID: <14672.64189.463518.718085@localhost.localdomain> >>>>> "NS" == Neil Schemenauer writes: NS> On Wed, Jun 21, 2000 at 10:16:11AM -0400, Jeremy Hylton wrote: >> I'm still not convinced that a return value is useful. Here's an >> example of a function that uses the recurse code and visit code. NS> Hmm, I guess my last message wasn't too clear. The GC code does NS> not use the return value. tp_recurse takes a function pointer NS> as an argument. visitproc could possibly return a non-zero NS> status code but all the visitprocs in the GC return success. NS> If, in the future, someone else finds a use for tp_recurse they NS> may wish to return a status value from their visitproc. NS> I have been a little sloppy with the return values since the GC NS> didn't need them. My fault. For optimal flexibility if NS> visitproc returns a non-zero value the tp_recurse functions NS> should return it instead of 1. How about zero for failure? The the recurse function returns one unless the visit function returns zero. Then we define the recurse/visit protocol so that the caller of the recurse function can ignore the error code only if it can guarantee that the visit function will never return an error. If there are no objections, I'll make the changes and check in patch1. Jeremy From nascheme@enme.ucalgary.ca Wed Jun 21 18:35:33 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 11:35:33 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <14672.64189.463518.718085@localhost.localdomain>; from jeremy@beopen.com on Wed, Jun 21, 2000 at 01:26:21PM -0400 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> <14672.52779.171329.428895@localhost.localdomain> <20000621112223.A22179@acs.ucalgary.ca> <14672.64189.463518.718085@localhost.localdomain> Message-ID: <20000621113533.D22179@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 01:26:21PM -0400, Jeremy Hylton wrote: > How about zero for failure? The the recurse function returns one > unless the visit function returns zero. Zero for success is more flexible but perhaps more confusing. I don't care either way (or even if you change everything to void). The GC doesn't need it. :) Neil -- "Its a trick; get an axe." -- Ash, Evil Dead II From tim_one@email.msn.com Wed Jun 21 18:45:36 2000 From: tim_one@email.msn.com (Tim Peters) Date: Wed, 21 Jun 2000 13:45:36 -0400 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: [posted & mailed] [Fredrik Lundh] > more warnings: > > ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' > undefined; assuming extern returning int > > the attached patch adds this function to the pythonrun.h > header file. +1 from me, but I see Trent Mick contributed an identical patch almost a month ago: http://www.python.org/pipermail/patches/2000-May/000769.html + Is there any way to search the patches archive directly (only way I know is to go to the main python.org search page, and check the "SIG archives" box, and that too often turns up way too many irrelevant hits from archives other than patches)? + Directed mostly to my PythonLabs co-conspirators: what can we do to clean up the patches mess? I'm scanning the archives, and have no idea what has & hasn't been checked in, or, when I do , no idea which of the unchecked-in patches should be checked in. Before Guido's honeymoon there was talk of assigning areas of responsibility, and I don't see any other way to make progress: someone has to own the problems. Implying we also need to assign an owner to each patch that comes in. + This mailing list doesn't work. At least the SourceForge patch manager has an "assigned to" slot, a per-patch discussion history, and a status classification (open, accepted, etc). I'm sure it sucks in ways I don't know about yet (I do know that the interface is s-l-o-w), but better the devil you don't know ... From jeremy@beopen.com Wed Jun 21 18:51:26 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Wed, 21 Jun 2000 13:51:26 -0400 (EDT) Subject: [Patches] Warnings in pythonrun.c In-Reply-To: References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: <14673.158.183876.75480@localhost.localdomain> >>>>> "TP" == Tim Peters writes: TP> + This mailing list doesn't work. At least the SourceForge TP> patch manager has an "assigned to" slot, a per-patch discussion TP> history, and a status classification (open, accepted, etc). I'm TP> sure it sucks in ways I don't know about yet (I do know that the TP> interface is s-l-o-w), but better the devil you don't know ... One possibility that I thought we should look at is using Ping's Roundup system layered on top of the current mailing list. I meant to look at the current code and see if it would work, but never found the time. I agree that it's a complete mess, though. Jeremy From bwarsaw@python.org Wed Jun 21 18:59:36 2000 From: bwarsaw@python.org (Barry A. Warsaw) Date: Wed, 21 Jun 2000 13:59:36 -0400 (EDT) Subject: [Patches] Warnings in pythonrun.c References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: <14673.648.837378.898019@anthem.concentric.net> >>>>> "TP" == Tim Peters writes: TP> + Is there any way to search the patches archive directly No. TP> (only way I know is to go to the main python.org search page, TP> and check the "SIG archives" box, and that too often turns up TP> way too many irrelevant hits from archives other than TP> patches)? Sadly, that's the way to do it. You could try narrowing it down by including the word `patches' though. TP> + Directed mostly to my PythonLabs co-conspirators: what can TP> we do to clean up the patches mess? I'm scanning the TP> archives, and have no idea what has & hasn't been checked in, TP> or, when I do , no idea which of the unchecked-in TP> patches should be checked in. Before Guido's honeymoon there TP> was talk of assigning areas of responsibility, and I don't see TP> any other way to make progress: someone has to own the TP> problems. Implying we also need to assign an owner to each TP> patch that comes in. TP> + This mailing list doesn't work. At least the SourceForge TP> patch manager has an "assigned to" slot, a per-patch TP> discussion history, and a status classification (open, TP> accepted, etc). I'm sure it sucks in ways I don't know about TP> yet (I do know that the interface is s-l-o-w), but better the TP> devil you don't know ... I think we have to start using the patch manager. If it sucks we'll either submit requests to the SF folks or expend some effort on checking out Roundup. -Barry From fdrake@beopen.com Wed Jun 21 19:29:30 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Wed, 21 Jun 2000 14:29:30 -0400 (EDT) Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <14673.648.837378.898019@anthem.concentric.net> References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> <14673.648.837378.898019@anthem.concentric.net> Message-ID: <14673.2442.117766.369951@cj42289-a.reston1.va.home.com> Barry A. Warsaw writes: > I think we have to start using the patch manager. If it sucks we'll > either submit requests to the SF folks or expend some effort on > checking out Roundup. Another possibility is just fixing SourceForge; I don't know how hard that would be. Roundup is probably easier since it's already in Python, but using SourceForge means we don't have to run the service and more people benefit from the effort. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From bwarsaw@python.org Wed Jun 21 19:37:46 2000 From: bwarsaw@python.org (bwarsaw@python.org) Date: Wed, 21 Jun 2000 14:37:46 -0400 (EDT) Subject: [Patches] Warnings in pythonrun.c References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> <14673.648.837378.898019@anthem.concentric.net> <14673.2442.117766.369951@cj42289-a.reston1.va.home.com> Message-ID: <14673.2938.249023.109867@anthem.concentric.net> >>>>> "Fred" == Fred L Drake, Jr writes: Fred> Another possibility is just fixing SourceForge; I don't Fred> know how hard that would be. Roundup is probably easier Fred> since it's already in Python, but using SourceForge means we Fred> don't have to run the service and more people benefit from Fred> the effort. A good idea since we (BeOpen) eventually want to run our own SF clone. From tim_one@email.msn.com Wed Jun 21 21:00:26 2000 From: tim_one@email.msn.com (Tim Peters) Date: Wed, 21 Jun 2000 16:00:26 -0400 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <200006212053.PAA01995@cj20424-a.reston1.va.home.com> Message-ID: >> + This mailing list doesn't work. > In more ways than once. I haven't received anything through the > patches mailing list all afternoon. (I'm getting this thread because > it's cc'ed to pythonlabs-info.) Barry is looking into it -- maybe a > reboot of dinsdale is in order (we had memory problems due to the > Ultraseek daemon -- it's not clear that the new Mailman is suspect). I'll add that I have not gotten back an echo from anything I've mailed to python-list or to python-help today either: whatever the problem, it's widespread. python-list is also spitting out many copies of several msgs. From guido@python.org Wed Jun 21 21:53:21 2000 From: guido@python.org (Guido van Rossum) Date: Wed, 21 Jun 2000 15:53:21 -0500 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: Your message of "Wed, 21 Jun 2000 13:45:36 -0400." References: Message-ID: <200006212053.PAA01995@cj20424-a.reston1.va.home.com> > + This mailing list doesn't work. In more ways than once. I haven't received anything through the patches mailing list all afternoon. (I'm getting this thread because it's cc'ed to pythonlabs-info.) Barry is looking into it -- maybe a reboot of dinsdale is in order (we had memory problems due to the Ultraseek daemon -- it's not clear that the new Mailman is suspect). --Guido van Rossum (home page: http://www.python.org/~guido/) From nascheme@enme.ucalgary.ca Wed Jun 21 18:22:23 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 11:22:23 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <14672.52779.171329.428895@localhost.localdomain>; from jeremy@beopen.com on Wed, Jun 21, 2000 at 10:16:11AM -0400 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> <14672.52779.171329.428895@localhost.localdomain> Message-ID: <20000621112223.A22179@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 10:16:11AM -0400, Jeremy Hylton wrote: > I'm still not convinced that a return value is useful. Here's an > example of a function that uses the recurse code and visit code. Hmm, I guess my last message wasn't too clear. The GC code does not use the return value. tp_recurse takes a function pointer as an argument. visitproc could possibly return a non-zero status code but all the visitprocs in the GC return success. If, in the future, someone else finds a use for tp_recurse they may wish to return a status value from their visitproc. I have been a little sloppy with the return values since the GC didn't need them. My fault. For optimal flexibility if visitproc returns a non-zero value the tp_recurse functions should return it instead of 1. Neil -- "I can't believe I put pants on for this." --Homer Simpson From nascheme@enme.ucalgary.ca Wed Jun 21 18:29:47 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 11:29:47 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <39506DA3.8DC013A@lemburg.com>; from mal@lemburg.com on Wed, Jun 21, 2000 at 09:24:19AM +0200 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> Message-ID: <20000621112947.C22179@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 09:24:19AM +0200, M.-A. Lemburg wrote: > ... how about -1 for errors and 0 for normal operation. 0 for success and non-zero for failure would be most flexible. The recurse functions should return this value as well. Neil From wolfgang.grafen@marconicomms.com Wed Jun 21 19:19:47 2000 From: wolfgang.grafen@marconicomms.com (Wolfgang Grafen) Date: Wed, 21 Jun 2000 20:19:47 +0200 Subject: [Patches] patch for gzip 1.18, readsize argument in read and readline method, optional strip_cr argument Message-ID: <39510743.6AF5B074@marconicomms.com> This is a multi-part message in MIME format. --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Standard disclaimer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Improvements to gzip 1.18: - readline accepts readsize argument - readlines accepts readsize argument - readlines accepts optional 'strip_cr' arguments, which is often convenient for me and also speeds up the routine :) def readline(self,readsize=100): def readlines(self, readsize=0,strip_cr=0) As I was not sure whether I generated the difffile as expected I also added the source. Especially I am wondering how you could find out if I create the diff with eg. v1.17 or before. As it is my first time to contribute, please give me a short notice whether it is good like this or what I can do better. I suggest you prepare a standard formular which might help. Regards Wolfgang --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii; name="gzip.py" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gzip.py" """Functions that read and write gzipped files. The user of the file doesn't have to worry about the compression, but random access is not allowed.""" # based on Andrew Kuchling's minigzip.py distributed with the zlib module import time import string import zlib import struct import __builtin__ FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 READ, WRITE = 1, 2 def write32(output, value): output.write(struct.pack("' def _init_write(self, filename): if filename[-3:] != '.gz': filename = filename + '.gz' self.filename = filename self.crc = zlib.crc32("") self.size = 0 self.writebuf = [] self.bufsize = 0 def _write_gzip_header(self): self.fileobj.write('\037\213') # magic header self.fileobj.write('\010') # compression method fname = self.filename[:-3] flags = 0 if fname: flags = FNAME self.fileobj.write(chr(flags)) write32u(self.fileobj, long(time.time())) self.fileobj.write('\002') self.fileobj.write('\377') if fname: self.fileobj.write(fname + '\000') def _init_read(self): self.crc = zlib.crc32("") self.size = 0 def _read_gzip_header(self): magic = self.fileobj.read(2) if magic != '\037\213': raise IOError, 'Not a gzipped file' method = ord( self.fileobj.read(1) ) if method != 8: raise IOError, 'Unknown compression method' flag = ord( self.fileobj.read(1) ) # modtime = self.fileobj.read(4) # extraflag = self.fileobj.read(1) # os = self.fileobj.read(1) self.fileobj.read(6) if flag & FEXTRA: # Read & discard the extra field, if present xlen=ord(self.fileobj.read(1)) xlen=xlen+256*ord(self.fileobj.read(1)) self.fileobj.read(xlen) if flag & FNAME: # Read and discard a null-terminated string containing the filename while (1): s=self.fileobj.read(1) if not s or s=='\000': break if flag & FCOMMENT: # Read and discard a null-terminated string containing a comment while (1): s=self.fileobj.read(1) if not s or s=='\000': break if flag & FHCRC: self.fileobj.read(2) # Read & discard the 16-bit header CRC def write(self,data): if self.fileobj is None: raise ValueError, "write() on closed GzipFile object" if len(data) > 0: self.size = self.size + len(data) self.crc = zlib.crc32(data, self.crc) self.fileobj.write( self.compress.compress(data) ) def writelines(self,lines): self.write(string.join(lines)) def read(self, size=-1): if self.extrasize <= 0 and self.fileobj is None: return '' readsize = 1024 if size < 0: # get the whole thing try: while 1: self._read(readsize) readsize = readsize * 2 except EOFError: size = self.extrasize else: # just get some more of it try: while size > self.extrasize: self._read(readsize) readsize = readsize * 2 except EOFError: if size > self.extrasize: size = self.extrasize chunk = self.extrabuf[:size] self.extrabuf = self.extrabuf[size:] self.extrasize = self.extrasize - size return chunk def _unread(self, buf): self.extrabuf = buf + self.extrabuf self.extrasize = len(buf) + self.extrasize def _read(self, size=1024): if self.fileobj is None: raise EOFError, "Reached EOF" if self._new_member: # If the _new_member flag is set, we have to # # First, check if we're at the end of the file; # if so, it's time to stop; no more members to read. pos = self.fileobj.tell() # Save current position self.fileobj.seek(0, 2) # Seek to end of file if pos == self.fileobj.tell(): self.fileobj = None raise EOFError, "Reached EOF" else: self.fileobj.seek( pos ) # Return to original position self._init_read() self._read_gzip_header() self.decompress = zlib.decompressobj(-zlib.MAX_WBITS) self._new_member = 0 # Read a chunk of data from the file buf = self.fileobj.read(size) # If the EOF has been reached, flush the decompression object # and mark this object as finished. if buf == "": uncompress = self.decompress.flush() self._read_eof() self.fileobj = None self._add_read_data( uncompress ) raise EOFError, 'Reached EOF' uncompress = self.decompress.decompress(buf) self._add_read_data( uncompress ) if self.decompress.unused_data != "": # Ending case: we've come to the end of a member in the file, # so seek back to the start of the unused data, finish up # this member, and read a new gzip header. # (The number of bytes to seek back is the length of the unused # data, minus 8 because _read_eof() will rewind a further 8 bytes) self.fileobj.seek( -len(self.decompress.unused_data)+8, 1) # Check the CRC and file size, and set the flag so we read # a new member on the next call self._read_eof() self._new_member = 1 def _add_read_data(self, data): self.crc = zlib.crc32(data, self.crc) self.extrabuf = self.extrabuf + data self.extrasize = self.extrasize + len(data) self.size = self.size + len(data) def _read_eof(self): # We've read to the end of the file, so we have to rewind in order # to reread the 8 bytes containing the CRC and the file size. # We check the that the computed CRC and size of the # uncompressed data matches the stored values. self.fileobj.seek(-8, 1) crc32 = read32(self.fileobj) isize = read32(self.fileobj) if crc32%0x100000000L != self.crc%0x100000000L: raise ValueError, "CRC check failed" elif isize != self.size: raise ValueError, "Incorrect length of data produced" def close(self): if self.mode == WRITE: self.fileobj.write(self.compress.flush()) write32(self.fileobj, self.crc) write32(self.fileobj, self.size) self.fileobj = None elif self.mode == READ: self.fileobj = None if self.myfileobj: self.myfileobj.close() self.myfileobj = None def __del__(self): try: if (self.myfileobj is None and self.fileobj is None): return except AttributeError: return self.close() def flush(self): self.fileobj.flush() def seek(self): raise IOError, 'Random access not allowed in gzip files' def tell(self): raise IOError, 'I won\'t tell() you for gzip files' def isatty(self): return 0 def readline(self,readsize=100): bufs = [] while 1: c = self.read(readsize) i = string.find(c, '\n') if i >= 0 or c == '': bufs.append(c[:i+1]) self._unread(c[i+1:]) return string.join(bufs, '') bufs.append(c) readsize = readsize * 2 def readlines(self, readsize=0,strip_cr=0): bufs = [] if readsize: while 1: c = self.read(readsize) i = string.rfind(c, '\n') if i >= 0 or c == '': bufs.append(c[:i+1]) self._unread(c[i+1:]) lines = string.split(string.join(bufs, ''),'\n') break; bufs.append(c) else: buf = self.read() lines = string.split(buf, '\n') if not strip_cr: for i in range(len(lines)-1): lines[i] = lines[i] + '\n' if lines and not lines[-1]: del lines[-1] return lines def writelines(self, L): for line in L: self.write(line) def _test(): # Act like gzip; with -d, act like gunzip. # The input file is not deleted, however, nor are any other gzip # options or features supported. import sys args = sys.argv[1:] decompress = args and args[0] == "-d" if decompress: args = args[1:] if not args: args = ["-"] for arg in args: if decompress: if arg == "-": f = GzipFile(filename="", mode="rb", fileobj=sys.stdin) g = sys.stdout else: if arg[-3:] != ".gz": print "filename doesn't end in .gz:", `arg` continue f = open(arg, "rb") g = __builtin__.open(arg[:-3], "wb") else: if arg == "-": f = sys.stdin g = GzipFile(filename="", mode="wb", fileobj=sys.stdout) else: f = __builtin__.open(arg, "rb") g = open(arg + ".gz", "wb") while 1: chunk = f.read(1024) if not chunk: break g.write(chunk) if g is not sys.stdout: g.close() if f is not sys.stdin: f.close() if __name__ == '__main__': _test() --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii; name="gzip.dif" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gzip.dif" 276c276 < def readline(self): --- > def readline(self,readsize=100): 278d277 < readsize = 100 289,293c288,305 < def readlines(self, ignored=None): < buf = self.read() < lines = string.split(buf, '\n') < for i in range(len(lines)-1): < lines[i] = lines[i] + '\n' --- > def readlines(self, readsize=0,strip_cr=0): > bufs = [] > if readsize: > while 1: > c = self.read(readsize) > i = string.rfind(c, '\n') > if i >= 0 or c == '': > bufs.append(c[:i+1]) > self._unread(c[i+1:]) > lines = string.split(string.join(bufs, ''),'\n') > break; > bufs.append(c) > else: > buf = self.read() > lines = string.split(buf, '\n') > if not strip_cr: > for i in range(len(lines)-1): > lines[i] = lines[i] + '\n' 295c307 < del lines[-1] --- > del lines[-1] --------------21881AE314EA3876A9AB0357-- From jeaton@hostway.net Wed Jun 21 20:26:43 2000 From: jeaton@hostway.net (Joe Eaton) Date: Wed, 21 Jun 2000 14:26:43 -0500 Subject: [Patches] Update bug in dumbdbm.py Message-ID: <395116F3.94CAE60B@hostway.net> I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Hello Patch folks: There is a silly bug in the fall-back dumbdbm.py database package in the Python 1.5.2 standard distro. This bug causes any changes to an existing item to generate a new key, even when the key already exists. After many updates, the .dir file used by dumbdbm grows to a huge size, and can cause filesystem problems. Here is a simple .py script to give an example: #!/usr/bin/env python import shelve S=shelve.open('Test') for i in range (2000): S['1'] = `i` This simply replaces the item '1' 2000 times. A look at the file Test.dir will show 2000 copies of the line '1' (0, 4) when just 1 is needed! The patch for this is: *** dumbdbm.py Wed Jun 21 13:07:12 2000 --- /usr/local/python1.5/lib/python1.5/dumbdbm.py Sun Jan 16 21:01:05 2000 *************** *** 120,125 **** --- 120,126 ---- else: pos, siz = self._addval(val) self._index[key] = pos, siz - self._addkey(key, (pos, siz)) def __delitem__(self, key): del self._index[key] simply remove the _addkey call to prevent extraneous keys from popping in. Should save diskspace for alot of people! Joe From trentm@activestate.com Wed Jun 21 20:25:18 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 21 Jun 2000 12:25:18 -0700 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: <20000621122518.B28236@activestate.com> On Wed, Jun 21, 2000 at 10:09:42AM +0200, Fredrik Lundh wrote: > more warnings: > > ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' undefined; assuming > extern returning int > > the attached patch adds this function to the pythonrun.h > header file. > The appropriate place for this is in Include/import.h. Description This patch cleans up a compilation warning. _PyImport_Fini() is meant to be exported by import.c but is not mentioned in Include/import.h. (it is called in Python/pythonrun.c). Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Include/import.h Thu Jun 1 00:13:37 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Include/import.h Wed May 31 23:54:13 2000 *************** *** 53,58 **** --- 53,59 ---- extern DL_IMPORT(PyObject *)_PyImport_FindExtension Py_PROTO((char *, char *)); extern DL_IMPORT(PyObject *)_PyImport_FixupExtension Py_PROTO((char *, char *)); + extern DL_IMPORT(void) _PyImport_Fini Py_PROTO((void)); struct _inittab { char *name; -- Trent Mick trentm@activestate.com From bwarsaw@python.org Wed Jun 21 21:06:45 2000 From: bwarsaw@python.org (Barry A. Warsaw) Date: Wed, 21 Jun 2000 16:06:45 -0400 (EDT) Subject: [Patches] Warnings in pythonrun.c References: <200006212053.PAA01995@cj20424-a.reston1.va.home.com> Message-ID: <14673.8277.348126.854652@anthem.concentric.net> >>>>> "GvR" == Guido van Rossum writes: >> + This mailing list doesn't work. GvR> In more ways than once. I haven't received anything through GvR> the patches mailing list all afternoon. (I'm getting this GvR> thread because it's cc'ed to pythonlabs-info.) Barry is GvR> looking into it -- maybe a reboot of dinsdale is in order (we GvR> had memory problems due to the Ultraseek daemon -- it's not GvR> clear that the new Mailman is suspect). Basically the Ultraseek daemon had consumed all available memory so Mailman couldn't make any progress on the messages sitting in its queue. We've now shut down Ultraseek and I'm running the qrunner manually so hopefully we start seeing the message queue get cleared. I'll be watching it closely over the next hour or so, and I'm going to work with the CNRI IT folks on a more long term solution (involving moving those services to different machines and making sure they aren't memory starved). -Barry From akuchlin@mems-exchange.org Wed Jun 21 21:27:31 2000 From: akuchlin@mems-exchange.org (Andrew M. Kuchling) Date: Wed, 21 Jun 2000 16:27:31 -0400 Subject: [Patches] Patch management (was: Warnings in pythonrun.c) In-Reply-To: <14673.158.183876.75480@localhost.localdomain>; from jeremy@beopen.com on Wed, Jun 21, 2000 at 01:51:26PM -0400 References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> <14673.158.183876.75480@localhost.localdomain> Message-ID: <20000621162731.B3918@amarok.cnri.reston.va.us> On Wed, Jun 21, 2000 at 01:51:26PM -0400, Jeremy Hylton wrote: >>>>>> "TP" == Tim Peters writes: > TP> + This mailing list doesn't work. At least the SourceForge >I agree that it's a complete mess, though. While you're all admiring the difficulty of the problem, how about actually checking in the pythonrun.c patch, assuming it's reasonable? Frankly, I don't think the current mailing list is broken, *as long as patches are handled with reasonable speed* so that the backlog doesn't build up. That hasn't been done, and I don't understand why. Obviously the CNRI->BeOpen transaction resulted in some downtime for everyone, but now it's a month later and there's still stagnation. Why aren't incoming patches being handled now? It's not like there are very many patches per day; an hour or two should suffice to keep the queue from growing. At this point, the best fix is to do two things: 1) Someone downloads the mbox archives of the patches list, and goes through all the past patches: apply them, discard them, send them back for revision. 2) Commit to handling new patches that arrive, and either apply/discard/revise them. Worrying about patch management mechanism, while more patches pile up and are ignored in the meantime, is not going to help and will just results in continued stagnation. -- A.M. Kuchling http://starship.python.net/crew/amk/ I couldn't think of one clever way to stop this guy, so I just trusted to mindless violence. -- Cliff Steele in DOOM PATROL #21 From mal@lemburg.com Wed Jun 21 22:26:19 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Wed, 21 Jun 2000 23:26:19 +0200 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> <14672.52779.171329.428895@localhost.localdomain> <20000621112223.A22179@acs.ucalgary.ca> <14672.64189.463518.718085@localhost.localdomain> <20000621113533.D22179@acs.ucalgary.ca> Message-ID: <395132FB.9079D0F0@lemburg.com> Neil Schemenauer wrote: > > On Wed, Jun 21, 2000 at 01:26:21PM -0400, Jeremy Hylton wrote: > > How about zero for failure? The the recurse function returns one > > unless the visit function returns zero. > > Zero for success is more flexible but perhaps more confusing. I > don't care either way (or even if you change everything to void). > The GC doesn't need it. :) It's common usage in CPython to return non-zero values to point to error conditions and a zero return to mean "ok". Why invent some new semantics here ? -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From nascheme@enme.ucalgary.ca Wed Jun 21 18:22:23 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 11:22:23 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <14672.52779.171329.428895@localhost.localdomain>; from jeremy@beopen.com on Wed, Jun 21, 2000 at 10:16:11AM -0400 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> <14672.52779.171329.428895@localhost.localdomain> Message-ID: <20000621112223.A22179@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 10:16:11AM -0400, Jeremy Hylton wrote: > I'm still not convinced that a return value is useful. Here's an > example of a function that uses the recurse code and visit code. Hmm, I guess my last message wasn't too clear. The GC code does not use the return value. tp_recurse takes a function pointer as an argument. visitproc could possibly return a non-zero status code but all the visitprocs in the GC return success. If, in the future, someone else finds a use for tp_recurse they may wish to return a status value from their visitproc. I have been a little sloppy with the return values since the GC didn't need them. My fault. For optimal flexibility if visitproc returns a non-zero value the tp_recurse functions should return it instead of 1. Neil -- "I can't believe I put pants on for this." --Homer Simpson From nascheme@enme.ucalgary.ca Wed Jun 21 18:29:47 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 11:29:47 -0600 Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <39506DA3.8DC013A@lemburg.com>; from mal@lemburg.com on Wed, Jun 21, 2000 at 09:24:19AM +0200 References: <20000614123818.A8975@acs.ucalgary.ca> <14671.59315.722952.141655@localhost.localdomain> <20000620160337.A15169@acs.ucalgary.ca> <39506DA3.8DC013A@lemburg.com> Message-ID: <20000621112947.C22179@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 09:24:19AM +0200, M.-A. Lemburg wrote: > ... how about -1 for errors and 0 for normal operation. 0 for success and non-zero for failure would be most flexible. The recurse functions should return this value as well. Neil From trentm@activestate.com Wed Jun 21 23:50:53 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 21 Jun 2000 15:50:53 -0700 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: <20000621155053.A29956@activestate.com> On Wed, Jun 21, 2000 at 01:45:36PM -0400, Tim Peters wrote: > [posted & mailed] > > [Fredrik Lundh] > > more warnings: > > > > ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' > > undefined; assuming extern returning int > > > > the attached patch adds this function to the pythonrun.h > > header file. > > +1 from me, but I see Trent Mick contributed an identical patch almost a > month ago: > > http://www.python.org/pipermail/patches/2000-May/000769.html ALmost identical except that the change was in import.h, where I think it should be. I answered this post earlier today but I don't think my message got through. Barry: I got a wierd message from mailman a while back complaining about a couple of emails that I sent accidentally as bcc. It seemed to say that I was being suspended from the list or something. Is this the case? Is that why my message has not gotten through? > + This mailing list doesn't work. At least the SourceForge patch manager > has an "assigned to" slot, a per-patch discussion history, and a status > classification (open, accepted, etc). I'm sure it sucks in ways I don't > know about yet (I do know that the interface is s-l-o-w), but better the > devil you don't know ... My patches are up at SourceForge. I think that the SourceForge patch manager will work okay and that we should try to give it a run. However, from what little I have lloked at it and at Roundup I am fond of the idea of using roundup. The email based interface that AFAIK it is based on seems to me more handy than the web only submission process on SourceForge. Trent -- Trent Mick trentm@activestate.com From nascheme@enme.ucalgary.ca Thu Jun 22 01:24:23 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 21 Jun 2000 18:24:23 -0600 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <14673.158.183876.75480@localhost.localdomain>; from jeremy@beopen.com on Wed, Jun 21, 2000 at 01:51:26PM -0400 References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> <14673.158.183876.75480@localhost.localdomain> Message-ID: <20000621182423.A25879@acs.ucalgary.ca> On Wed, Jun 21, 2000 at 01:51:26PM -0400, Jeremy Hylton wrote: > One possibility that I thought we should look at is using Ping's > Roundup system layered on top of the current mailing list. I second the vote for Roundup (although my vote probably isn't worth much :). It is a very interesting system. The ideas are the cool part, the implementation should be quite simple. If something is wrong with Ping's code it should be easy to fix. Neil -- 145 = 1! + 4! + 5! From mhammond@skippinet.com.au Thu Jun 22 01:38:26 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Thu, 22 Jun 2000 10:38:26 +1000 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: Message-ID: > + Directed mostly to my PythonLabs co-conspirators: Ha - You know you need to do better than that to shut the rest of us up! > Before Guido's honeymoon there > was talk of assigning areas of responsibility, and I don't see > any other way to make progress: someone has to own the problems. I think this could be part of the “price” you pay for checkin privileges - some nominated triage person may assign patches to you, and you need to keep your credibility and checkin privileges by shepherding the patch to a successful, reasonable conclusion (with the assistance of the patches or py-dev mailing list when you feel you need it). This could help remove any percieved “status” such privileges provide, by demonstrating that they actually _do_ cost! Mark. From wolfgang.grafen@marconicomms.com Wed Jun 21 19:19:47 2000 From: wolfgang.grafen@marconicomms.com (Wolfgang Grafen) Date: Wed, 21 Jun 2000 20:19:47 +0200 Subject: [Patches] patch for gzip 1.18, readsize argument in read and readline method, optional strip_cr argument Message-ID: <39510743.6AF5B074@marconicomms.com> This is a multi-part message in MIME format. --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Standard disclaimer: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Improvements to gzip 1.18: - readline accepts readsize argument - readlines accepts readsize argument - readlines accepts optional 'strip_cr' arguments, which is often convenient for me and also speeds up the routine :) def readline(self,readsize=100): def readlines(self, readsize=0,strip_cr=0) As I was not sure whether I generated the difffile as expected I also added the source. Especially I am wondering how you could find out if I create the diff with eg. v1.17 or before. As it is my first time to contribute, please give me a short notice whether it is good like this or what I can do better. I suggest you prepare a standard formular which might help. Regards Wolfgang --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii; name="gzip.py" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gzip.py" """Functions that read and write gzipped files. The user of the file doesn't have to worry about the compression, but random access is not allowed.""" # based on Andrew Kuchling's minigzip.py distributed with the zlib module import time import string import zlib import struct import __builtin__ FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16 READ, WRITE = 1, 2 def write32(output, value): output.write(struct.pack("' def _init_write(self, filename): if filename[-3:] != '.gz': filename = filename + '.gz' self.filename = filename self.crc = zlib.crc32("") self.size = 0 self.writebuf = [] self.bufsize = 0 def _write_gzip_header(self): self.fileobj.write('\037\213') # magic header self.fileobj.write('\010') # compression method fname = self.filename[:-3] flags = 0 if fname: flags = FNAME self.fileobj.write(chr(flags)) write32u(self.fileobj, long(time.time())) self.fileobj.write('\002') self.fileobj.write('\377') if fname: self.fileobj.write(fname + '\000') def _init_read(self): self.crc = zlib.crc32("") self.size = 0 def _read_gzip_header(self): magic = self.fileobj.read(2) if magic != '\037\213': raise IOError, 'Not a gzipped file' method = ord( self.fileobj.read(1) ) if method != 8: raise IOError, 'Unknown compression method' flag = ord( self.fileobj.read(1) ) # modtime = self.fileobj.read(4) # extraflag = self.fileobj.read(1) # os = self.fileobj.read(1) self.fileobj.read(6) if flag & FEXTRA: # Read & discard the extra field, if present xlen=ord(self.fileobj.read(1)) xlen=xlen+256*ord(self.fileobj.read(1)) self.fileobj.read(xlen) if flag & FNAME: # Read and discard a null-terminated string containing the filename while (1): s=self.fileobj.read(1) if not s or s=='\000': break if flag & FCOMMENT: # Read and discard a null-terminated string containing a comment while (1): s=self.fileobj.read(1) if not s or s=='\000': break if flag & FHCRC: self.fileobj.read(2) # Read & discard the 16-bit header CRC def write(self,data): if self.fileobj is None: raise ValueError, "write() on closed GzipFile object" if len(data) > 0: self.size = self.size + len(data) self.crc = zlib.crc32(data, self.crc) self.fileobj.write( self.compress.compress(data) ) def writelines(self,lines): self.write(string.join(lines)) def read(self, size=-1): if self.extrasize <= 0 and self.fileobj is None: return '' readsize = 1024 if size < 0: # get the whole thing try: while 1: self._read(readsize) readsize = readsize * 2 except EOFError: size = self.extrasize else: # just get some more of it try: while size > self.extrasize: self._read(readsize) readsize = readsize * 2 except EOFError: if size > self.extrasize: size = self.extrasize chunk = self.extrabuf[:size] self.extrabuf = self.extrabuf[size:] self.extrasize = self.extrasize - size return chunk def _unread(self, buf): self.extrabuf = buf + self.extrabuf self.extrasize = len(buf) + self.extrasize def _read(self, size=1024): if self.fileobj is None: raise EOFError, "Reached EOF" if self._new_member: # If the _new_member flag is set, we have to # # First, check if we're at the end of the file; # if so, it's time to stop; no more members to read. pos = self.fileobj.tell() # Save current position self.fileobj.seek(0, 2) # Seek to end of file if pos == self.fileobj.tell(): self.fileobj = None raise EOFError, "Reached EOF" else: self.fileobj.seek( pos ) # Return to original position self._init_read() self._read_gzip_header() self.decompress = zlib.decompressobj(-zlib.MAX_WBITS) self._new_member = 0 # Read a chunk of data from the file buf = self.fileobj.read(size) # If the EOF has been reached, flush the decompression object # and mark this object as finished. if buf == "": uncompress = self.decompress.flush() self._read_eof() self.fileobj = None self._add_read_data( uncompress ) raise EOFError, 'Reached EOF' uncompress = self.decompress.decompress(buf) self._add_read_data( uncompress ) if self.decompress.unused_data != "": # Ending case: we've come to the end of a member in the file, # so seek back to the start of the unused data, finish up # this member, and read a new gzip header. # (The number of bytes to seek back is the length of the unused # data, minus 8 because _read_eof() will rewind a further 8 bytes) self.fileobj.seek( -len(self.decompress.unused_data)+8, 1) # Check the CRC and file size, and set the flag so we read # a new member on the next call self._read_eof() self._new_member = 1 def _add_read_data(self, data): self.crc = zlib.crc32(data, self.crc) self.extrabuf = self.extrabuf + data self.extrasize = self.extrasize + len(data) self.size = self.size + len(data) def _read_eof(self): # We've read to the end of the file, so we have to rewind in order # to reread the 8 bytes containing the CRC and the file size. # We check the that the computed CRC and size of the # uncompressed data matches the stored values. self.fileobj.seek(-8, 1) crc32 = read32(self.fileobj) isize = read32(self.fileobj) if crc32%0x100000000L != self.crc%0x100000000L: raise ValueError, "CRC check failed" elif isize != self.size: raise ValueError, "Incorrect length of data produced" def close(self): if self.mode == WRITE: self.fileobj.write(self.compress.flush()) write32(self.fileobj, self.crc) write32(self.fileobj, self.size) self.fileobj = None elif self.mode == READ: self.fileobj = None if self.myfileobj: self.myfileobj.close() self.myfileobj = None def __del__(self): try: if (self.myfileobj is None and self.fileobj is None): return except AttributeError: return self.close() def flush(self): self.fileobj.flush() def seek(self): raise IOError, 'Random access not allowed in gzip files' def tell(self): raise IOError, 'I won\'t tell() you for gzip files' def isatty(self): return 0 def readline(self,readsize=100): bufs = [] while 1: c = self.read(readsize) i = string.find(c, '\n') if i >= 0 or c == '': bufs.append(c[:i+1]) self._unread(c[i+1:]) return string.join(bufs, '') bufs.append(c) readsize = readsize * 2 def readlines(self, readsize=0,strip_cr=0): bufs = [] if readsize: while 1: c = self.read(readsize) i = string.rfind(c, '\n') if i >= 0 or c == '': bufs.append(c[:i+1]) self._unread(c[i+1:]) lines = string.split(string.join(bufs, ''),'\n') break; bufs.append(c) else: buf = self.read() lines = string.split(buf, '\n') if not strip_cr: for i in range(len(lines)-1): lines[i] = lines[i] + '\n' if lines and not lines[-1]: del lines[-1] return lines def writelines(self, L): for line in L: self.write(line) def _test(): # Act like gzip; with -d, act like gunzip. # The input file is not deleted, however, nor are any other gzip # options or features supported. import sys args = sys.argv[1:] decompress = args and args[0] == "-d" if decompress: args = args[1:] if not args: args = ["-"] for arg in args: if decompress: if arg == "-": f = GzipFile(filename="", mode="rb", fileobj=sys.stdin) g = sys.stdout else: if arg[-3:] != ".gz": print "filename doesn't end in .gz:", `arg` continue f = open(arg, "rb") g = __builtin__.open(arg[:-3], "wb") else: if arg == "-": f = sys.stdin g = GzipFile(filename="", mode="wb", fileobj=sys.stdout) else: f = __builtin__.open(arg, "rb") g = open(arg + ".gz", "wb") while 1: chunk = f.read(1024) if not chunk: break g.write(chunk) if g is not sys.stdout: g.close() if f is not sys.stdin: f.close() if __name__ == '__main__': _test() --------------21881AE314EA3876A9AB0357 Content-Type: text/plain; charset=us-ascii; name="gzip.dif" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="gzip.dif" 276c276 < def readline(self): --- > def readline(self,readsize=100): 278d277 < readsize = 100 289,293c288,305 < def readlines(self, ignored=None): < buf = self.read() < lines = string.split(buf, '\n') < for i in range(len(lines)-1): < lines[i] = lines[i] + '\n' --- > def readlines(self, readsize=0,strip_cr=0): > bufs = [] > if readsize: > while 1: > c = self.read(readsize) > i = string.rfind(c, '\n') > if i >= 0 or c == '': > bufs.append(c[:i+1]) > self._unread(c[i+1:]) > lines = string.split(string.join(bufs, ''),'\n') > break; > bufs.append(c) > else: > buf = self.read() > lines = string.split(buf, '\n') > if not strip_cr: > for i in range(len(lines)-1): > lines[i] = lines[i] + '\n' 295c307 < del lines[-1] --- > del lines[-1] --------------21881AE314EA3876A9AB0357-- From trentm@activestate.com Wed Jun 21 20:25:18 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 21 Jun 2000 12:25:18 -0700 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> References: <008c01bfdb58$103e8140$f2a6b5d4@hagrid> Message-ID: <20000621122518.B28236@activestate.com> On Wed, Jun 21, 2000 at 10:09:42AM +0200, Fredrik Lundh wrote: > more warnings: > > ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' undefined; assuming > extern returning int > > the attached patch adds this function to the pythonrun.h > header file. > The appropriate place for this is in Include/import.h. Description This patch cleans up a compilation warning. _PyImport_Fini() is meant to be exported by import.c but is not mentioned in Include/import.h. (it is called in Python/pythonrun.c). Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Patch: *** /home/trentm/main/contrib/python/dist/src/Include/import.h Thu Jun 1 00:13:37 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Include/import.h Wed May 31 23:54:13 2000 *************** *** 53,58 **** --- 53,59 ---- extern DL_IMPORT(PyObject *)_PyImport_FindExtension Py_PROTO((char *, char *)); extern DL_IMPORT(PyObject *)_PyImport_FixupExtension Py_PROTO((char *, char *)); + extern DL_IMPORT(void) _PyImport_Fini Py_PROTO((void)); struct _inittab { char *name; -- Trent Mick trentm@activestate.com From jeaton@hostway.net Wed Jun 21 20:26:43 2000 From: jeaton@hostway.net (Joe Eaton) Date: Wed, 21 Jun 2000 14:26:43 -0500 Subject: [Patches] Update bug in dumbdbm.py Message-ID: <395116F3.94CAE60B@hostway.net> I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. Hello Patch folks: There is a silly bug in the fall-back dumbdbm.py database package in the Python 1.5.2 standard distro. This bug causes any changes to an existing item to generate a new key, even when the key already exists. After many updates, the .dir file used by dumbdbm grows to a huge size, and can cause filesystem problems. Here is a simple .py script to give an example: #!/usr/bin/env python import shelve S=shelve.open('Test') for i in range (2000): S['1'] = `i` This simply replaces the item '1' 2000 times. A look at the file Test.dir will show 2000 copies of the line '1' (0, 4) when just 1 is needed! The patch for this is: *** dumbdbm.py Wed Jun 21 13:07:12 2000 --- /usr/local/python1.5/lib/python1.5/dumbdbm.py Sun Jan 16 21:01:05 2000 *************** *** 120,125 **** --- 120,126 ---- else: pos, siz = self._addval(val) self._index[key] = pos, siz - self._addkey(key, (pos, siz)) def __delitem__(self, key): del self._index[key] simply remove the _addkey call to prevent extraneous keys from popping in. Should save diskspace for alot of people! Joe From jeremy@beopen.com Thu Jun 22 13:29:39 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Thu, 22 Jun 2000 08:29:39 -0400 (EDT) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <200006220754.JAA05584@python.inrialpes.fr> References: <14672.64189.463518.718085@localhost.localdomain> <200006220754.JAA05584@python.inrialpes.fr> Message-ID: <14674.1715.828180.733908@localhost.localdomain> >>>>> "VM" == Vladimir Marangozov writes: VM> Jeremy Hylton wrote: >> If there are no objections, I'll make the changes and check in >> patch1. VM> No objections for patch1 from me. Let's go for it. The patch is ready to go, with a few changes to make error reporting consistent (both internally and with the rest of the Python API). I would have checked it in yesterday, but my ISP is having some kind of routing trouble and I can't reach the Python CVS server at Sourceforge. Sheesh! You'll know when the problem is fixed :-). Jeremy From Vladimir.Marangozov@inrialpes.fr Thu Jun 22 08:54:41 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Thu, 22 Jun 2000 09:54:41 +0200 (CEST) Subject: [Patches] GC infrastructure patch 1 (tp_recurse, tp_clear) In-Reply-To: <14672.64189.463518.718085@localhost.localdomain> from "Jeremy Hylton" at Jun 21, 2000 01:26:21 PM Message-ID: <200006220754.JAA05584@python.inrialpes.fr> Jeremy Hylton wrote: > > If there are no objections, I'll make the changes and check in > patch1. No objections for patch1 from me. Let's go for it. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From guido@python.org Thu Jun 22 15:46:41 2000 From: guido@python.org (Guido van Rossum) Date: Thu, 22 Jun 2000 09:46:41 -0500 Subject: [Patches] this is a test Message-ID: <200006221446.JAA01040@cj20424-a.reston1.va.home.com> please ignore -- thank you! From fredrik@pythonware.com Thu Jun 22 16:19:16 2000 From: fredrik@pythonware.com (Fredrik Lundh) Date: Thu, 22 Jun 2000 17:19:16 +0200 Subject: [Patches] Warnings in pythonrun.c Message-ID: <006001bfdc5d$3ea12280$0900a8c0@SPIFF> On Wed, Jun 21, 2000 at 10:09:42AM +0200, Fredrik Lundh wrote: > > more warnings: > > > > ..\Python\pythonrun.c(233) : warning C4013: '_PyImport_Fini' undefined; assuming > > extern returning int > > > > the attached patch adds this function to the pythonrun.h > > header file. > > The appropriate place for this is in Include/import.h. "appropriate" ? if you'd bothered to look in Include/pythonrun.h, you'd found that _PyImport_Init was defined in that file, together with a whole bunch of other internal initializations and finalizations. if you'd bothered to look in the CVS history, you'd found that _PyImport_Fini *was* declared in pythonrun.h, before someone accidentally removed it a few weeks ago. if you're gonna move declarations around, it's probably more appropriate to move all of them to more appropriate places, don't you think? From trentm@activestate.com Thu Jun 22 18:45:40 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 22 Jun 2000 10:45:40 -0700 Subject: [Patches] Warnings in pythonrun.c In-Reply-To: <006001bfdc5d$3ea12280$0900a8c0@SPIFF> References: <006001bfdc5d$3ea12280$0900a8c0@SPIFF> Message-ID: <20000622104540.A9016@activestate.com> On Thu, Jun 22, 2000 at 05:19:16PM +0200, Fredrik Lundh wrote: > > > > The appropriate place for this is in Include/import.h. I apologize if I offended. I thought that the implied "I think" was understood. > > "appropriate" ? > > if you'd bothered to look in Include/pythonrun.h, you'd found > that _PyImport_Init was defined in that file, together with a > whole bunch of other internal initializations and finalizations. > > if you'd bothered to look in the CVS history, you'd found that > _PyImport_Fini *was* declared in pythonrun.h, before someone > accidentally removed it a few weeks ago. > I suppose that I thought the best place for _PyImport_Anything was the import.h|c files. That is how I would have built the system. However, you are right, I did not note the convention of placing the Init/Fini declarations in pythonrun.h. I will then second Tim's +1 to your patch. This is what peer review is for. Trent -- Trent Mick trentm@activestate.com From gisle@ActiveState.com Thu Jun 22 20:39:12 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 22 Jun 2000 19:39:12 -0000 Subject: [Patches] A little optimization in PyObject_Cmp() Message-ID: <20000622193912.27481.qmail@eik.g.aas.no> Avoid calling PyErr_Occurred() all the time... Index: Objects/abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.35 diff -u -p -u -r2.35 abstract.c --- Objects/abstract.c 2000/06/18 18:43:14 2.35 +++ Objects/abstract.c 2000/06/22 19:27:42 @@ -68,7 +68,7 @@ PyObject_Cmp(o1, o2, result) return -1; } r = PyObject_Compare(o1, o2); - if (PyErr_Occurred()) + if (r == -1 && PyErr_Occurred()) return -1; *result = r; return 0; From gisle@ActiveState.com Thu Jun 22 20:36:10 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 22 Jun 2000 19:36:10 -0000 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names Message-ID: <20000622193610.27452.qmail@eik.g.aas.no> While developing a perl interface to python I discovered that PyObject_(Has|Get|Set)Attr core dumps if given non-string names. This patch ought to fix it. If you actually wanted the object passed to v->ob_type->tp_setattro to be interned if it was a string, then a little additional tweak is needed for the PyObject_SetAttr(). Regards, Gisle Aas Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.71 diff -u -p -u -r2.71 object.c --- Objects/object.c 2000/06/09 16:20:39 2.71 +++ Objects/object.c 2000/06/22 19:27:51 @@ -600,8 +600,12 @@ PyObject_GetAttr(v, name) { if (v->ob_type->tp_getattro != NULL) return (*v->ob_type->tp_getattro)(v, name); - else + else if (PyString_Check(name)) return PyObject_GetAttrString(v, PyString_AsString(name)); + else { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + } } int @@ -626,12 +630,18 @@ PyObject_SetAttr(v, name, value) { int err; Py_INCREF(name); - PyString_InternInPlace(&name); if (v->ob_type->tp_setattro != NULL) err = (*v->ob_type->tp_setattro)(v, name, value); - else + else if (PyString_Check(name)) { + PyString_InternInPlace(&name); err = PyObject_SetAttrString( v, PyString_AsString(name), value); + } + else { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + err = -1; + } Py_DECREF(name); return err; } From mal@lemburg.com Thu Jun 22 21:10:56 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Thu, 22 Jun 2000 22:10:56 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names References: <20000622193610.27452.qmail@eik.g.aas.no> Message-ID: <395272D0.B82A0353@lemburg.com> Gisle Aas wrote: > > While developing a perl interface to python I discovered that > PyObject_(Has|Get|Set)Attr core dumps if given non-string names. > > This patch ought to fix it. If you actually wanted the object passed > to v->ob_type->tp_setattro to be interned if it was a string, then a > little additional tweak is needed for the PyObject_SetAttr(). > > Regards, > Gisle Aas > > Index: Objects/object.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v > retrieving revision 2.71 > diff -u -p -u -r2.71 object.c > --- Objects/object.c 2000/06/09 16:20:39 2.71 > +++ Objects/object.c 2000/06/22 19:27:51 > @@ -600,8 +600,12 @@ PyObject_GetAttr(v, name) > { > if (v->ob_type->tp_getattro != NULL) > return (*v->ob_type->tp_getattro)(v, name); > - else > + else if (PyString_Check(name)) > return PyObject_GetAttrString(v, PyString_AsString(name)); > + else { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + } > } Hmm, I think it would be more generic to add a NULL check to PyObject_GetAttrString() (PyString_AsString() returns NULL in case name is not a string object). > int > @@ -626,12 +630,18 @@ PyObject_SetAttr(v, name, value) > { > int err; > Py_INCREF(name); > - PyString_InternInPlace(&name); > if (v->ob_type->tp_setattro != NULL) > err = (*v->ob_type->tp_setattro)(v, name, value); > - else > + else if (PyString_Check(name)) { > + PyString_InternInPlace(&name); > err = PyObject_SetAttrString( > v, PyString_AsString(name), value); > + } > + else { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + err = -1; > + } Here, I think you ought to move the string test just before the interning call. > Py_DECREF(name); > return err; > } > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From mal@lemburg.com Thu Jun 22 21:12:29 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Thu, 22 Jun 2000 22:12:29 +0200 Subject: [Patches] A little optimization in PyObject_Cmp() References: <20000622193912.27481.qmail@eik.g.aas.no> Message-ID: <3952732D.9F17D4A5@lemburg.com> Gisle Aas wrote: > > Avoid calling PyErr_Occurred() all the time... > > Index: Objects/abstract.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v > retrieving revision 2.35 > diff -u -p -u -r2.35 abstract.c > --- Objects/abstract.c 2000/06/18 18:43:14 2.35 > +++ Objects/abstract.c 2000/06/22 19:27:42 > @@ -68,7 +68,7 @@ PyObject_Cmp(o1, o2, result) > return -1; > } > r = PyObject_Compare(o1, o2); > - if (PyErr_Occurred()) > + if (r == -1 && PyErr_Occurred()) Is this documented ? I mean: will all implementations return -1 in the error case ? (I think this is the case for the core interpreter, but what about extensions ?) > return -1; > *result = r; > return 0; > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gisle@ActiveState.com Thu Jun 22 21:23:49 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 22 Jun 2000 22:23:49 +0200 Subject: [Patches] A little optimization in PyObject_Cmp() In-Reply-To: "M.-A. Lemburg"'s message of "Thu, 22 Jun 2000 22:12:29 +0200" References: <20000622193912.27481.qmail@eik.g.aas.no> <3952732D.9F17D4A5@lemburg.com> Message-ID: "M.-A. Lemburg" writes: > Gisle Aas wrote: > > > > Avoid calling PyErr_Occurred() all the time... > > > > Index: Objects/abstract.c > > =================================================================== > > RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v > > retrieving revision 2.35 > > diff -u -p -u -r2.35 abstract.c > > --- Objects/abstract.c 2000/06/18 18:43:14 2.35 > > +++ Objects/abstract.c 2000/06/22 19:27:42 > > @@ -68,7 +68,7 @@ PyObject_Cmp(o1, o2, result) > > return -1; > > } > > r = PyObject_Compare(o1, o2); > > - if (PyErr_Occurred()) > > + if (r == -1 && PyErr_Occurred()) > > Is this documented ? I mean: will all implementations return > -1 in the error case ? > > (I think this is the case for the core interpreter, but > what about extensions ?) I have now reread what the API docs says about PyObject_Compare(), so please just forget this one. Regards, Gisle From gisle@ActiveState.com Thu Jun 22 21:38:58 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 22 Jun 2000 22:38:58 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names In-Reply-To: "M.-A. Lemburg"'s message of "Thu, 22 Jun 2000 22:10:56 +0200" References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> Message-ID: "M.-A. Lemburg" writes: > > Index: Objects/object.c > > =================================================================== > > RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v > > retrieving revision 2.71 > > diff -u -p -u -r2.71 object.c > > --- Objects/object.c 2000/06/09 16:20:39 2.71 > > +++ Objects/object.c 2000/06/22 19:27:51 > > @@ -600,8 +600,12 @@ PyObject_GetAttr(v, name) > > { > > if (v->ob_type->tp_getattro != NULL) > > return (*v->ob_type->tp_getattro)(v, name); > > - else > > + else if (PyString_Check(name)) > > return PyObject_GetAttrString(v, PyString_AsString(name)); > > + else { > > + PyErr_SetString(PyExc_TypeError, > > + "attribute name must be string"); > > + } > > } > > Hmm, I think it would be more generic to add a NULL > check to PyObject_GetAttrString() (PyString_AsString() returns > NULL in case name is not a string object). Ok. But it also set up the exception to be BadInternalCall() which does not feel right :-) I also forgot to "return NULL" here. > > int > > @@ -626,12 +630,18 @@ PyObject_SetAttr(v, name, value) > > { > > int err; > > Py_INCREF(name); > > - PyString_InternInPlace(&name); > > if (v->ob_type->tp_setattro != NULL) > > err = (*v->ob_type->tp_setattro)(v, name, value); > > - else > > + else if (PyString_Check(name)) { > > + PyString_InternInPlace(&name); > > err = PyObject_SetAttrString( > > v, PyString_AsString(name), value); > > + } > > + else { > > + PyErr_SetString(PyExc_TypeError, > > + "attribute name must be string"); > > + err = -1; > > + } > > Here, I think you ought to move the string test just before > the interning call. But you still want to be able to pass non-string objects to v->ob_type->tp_setattro I guess. Anyway, an alternative patch is included here. Thanks for the quick feedback! Regards, Gisle Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.71 diff -u -p -u -r2.71 object.c --- Objects/object.c 2000/06/09 16:20:39 2.71 +++ Objects/object.c 2000/06/22 20:37:21 @@ -598,10 +598,17 @@ PyObject_GetAttr(v, name) PyObject *v; PyObject *name; { + char *name_str; if (v->ob_type->tp_getattro != NULL) return (*v->ob_type->tp_getattro)(v, name); - else - return PyObject_GetAttrString(v, PyString_AsString(name)); + + name_str = PyString_AsString(name); + if (name_str == NULL) { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + return NULL; + } + return PyObject_GetAttrString(v, name_str); } int @@ -625,13 +632,23 @@ PyObject_SetAttr(v, name, value) PyObject *value; { int err; + int name_is_string = 0; Py_INCREF(name); - PyString_InternInPlace(&name); + if (PyString_Check(name)) { + PyString_InternInPlace(&name); + name_is_string = 1; + } if (v->ob_type->tp_setattro != NULL) err = (*v->ob_type->tp_setattro)(v, name, value); - else + else if (name_is_string) { err = PyObject_SetAttrString( v, PyString_AsString(name), value); + } + else { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + err = -1; + } Py_DECREF(name); return err; } I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. From mhammond@skippinet.com.au Thu Jun 22 23:36:35 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 23 Jun 2000 08:36:35 +1000 Subject: [Patches] A little optimization in PyObject_Cmp() In-Reply-To: <3952732D.9F17D4A5@lemburg.com> Message-ID: > Is this documented ? I mean: will all implementations return > -1 in the error case ? If it isnt, it should be. Im +1 on this, assuming there is a _reason_ for it - ie, that some profiling shows this a hot-spot improved with the patch. If is just a "for-the-sake-of-it", Im -1 simply due to the KISS principal. If-it-aint-broke-dont-fix-it-ly, Mark. From mhammond@skippinet.com.au Thu Jun 22 23:38:40 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 23 Jun 2000 08:38:40 +1000 Subject: [Patches] A little optimization in PyObject_Cmp() In-Reply-To: Message-ID: > I have now reread what the API docs says about PyObject_Compare(), so > please just forget this one. Doh - I definately should have known better :-( Oh well, I can put it down to the first 1/2 hour of my day. Hrm - I need a new rule - as well as "dont post patches until 24 hours after making them", I need to add "dont send mail before the first coffee is at least 1/2 way down" :-) Mark. From tim_one@email.msn.com Fri Jun 23 02:38:43 2000 From: tim_one@email.msn.com (Tim Peters) Date: Thu, 22 Jun 2000 21:38:43 -0400 Subject: [Patches] Patch management (was: Warnings in pythonrun.c) In-Reply-To: <20000621162731.B3918@amarok.cnri.reston.va.us> Message-ID: [Andrew M. Kuchling] > While you're all admiring the difficulty of the problem, how about > actually checking in the pythonrun.c patch, assuming it's reasonable? I can't yet. Be my guest! > > > Frankly, I don't think the current mailing list is broken, *as long as > patches are handled with reasonable speed* so that the backlog doesn't > build up. Andrew, this is saying that if it didn't display all the symptoms of illness, it wouldn't be sick. The consistent (this started long before Guido's honeymoon!) lack of timely action here *is* the brokenness. > That hasn't been done, and I don't understand why. Why didn't you check in the pythonrun.c patch? Multiply by 10 people and 100 patches. There are no mechanisms in a mailing list for assigning, recording or checking responsibility, neither for recording or querying disposition status. Nobody owns any part of the problem now, and it's extraordinarly difficult to determine the status of any particular patch you may be interested in via this mish-mash of archived all-topic email scattered across patches and python-dev. Prior to this mailing list, Guido owned every problem and the database was in his head. I think it's the lack of the "owned" and "database" parts we're suffering from here, not especially the lack of the "Guido" part. SourceForge provides rudimentary mechanisms for both of the former; a Python replacement for Guido is one of BeOpen's highest secret priorities . > ... > Worrying about patch management mechanism, while more patches pile up > and are ignored in the meantime, is not going to help and will just > results in continued stagnation. At an all-hands PythonLabs group mtg today, it was decided to move patch activity to SourceForge and kill the patches list. I'll send more about that later. There is absolutely nothing new stopping checkins while the move to the SourceForge patch manager is in progress, so if the patches continue to pile up it's certainly not the move's fault. If the pythonrun.c patch is still sitting untouched after the move, I'll assign it to you <0.7 wink>. the-only-one-working-on-the-move-is-me-and-i-haven't-done-a-checkin- yet-anyway-ly y'rs - tim From trentm@activestate.com Fri Jun 23 03:36:34 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 22 Jun 2000 19:36:34 -0700 Subject: [Patches] clean up warnings in Win32 build of mmapmodule.c Message-ID: <20000622193634.A17914@activestate.com> Discussion: Fix a few warnings in the Win32 build of mmapmodule.c. The warnings were about comparison of singed (int) and unsigned (size_t) values. This was patched by casting every int to size_t for comparison. This is safe because every cast is preceded with a check guaranteeing that the int is positive. Patch: Index: Modules/mmapmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/mmapmodule.c,v retrieving revision 2.15 diff -c -r2.15 mmapmodule.c *** Modules/mmapmodule.c 2000/06/18 19:06:49 2.15 --- Modules/mmapmodule.c 2000/06/23 02:33:34 *************** *** 568,574 **** int i; { CHECK_VALID(NULL); ! if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } --- 568,574 ---- int i; { CHECK_VALID(NULL); ! if (i < 0 || (size_t)i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return NULL; } *************** *** 583,595 **** CHECK_VALID(NULL); if (ilow < 0) ilow = 0; ! else if (ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; ! else if (ihigh > self->size) ihigh = self->size; return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow); --- 583,595 ---- CHECK_VALID(NULL); if (ilow < 0) ilow = 0; ! else if ((size_t)ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; ! else if ((size_t)ihigh > self->size) ihigh = self->size; return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow); *************** *** 628,640 **** CHECK_VALID(-1); if (ilow < 0) ilow = 0; ! else if (ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; ! else if (ihigh > self->size) ihigh = self->size; if (! (PyString_Check(v)) ) { --- 628,640 ---- CHECK_VALID(-1); if (ilow < 0) ilow = 0; ! else if ((size_t)ilow > self->size) ilow = self->size; if (ihigh < 0) ihigh = 0; if (ihigh < ilow) ihigh = ilow; ! else if ((size_t)ihigh > self->size) ihigh = self->size; if (! (PyString_Check(v)) ) { *************** *** 661,667 **** const char *buf; CHECK_VALID(-1); ! if (i < 0 || i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } --- 661,667 ---- const char *buf; CHECK_VALID(-1); ! if (i < 0 || (size_t)i >= self->size) { PyErr_SetString(PyExc_IndexError, "mmap index out of range"); return -1; } Legal: I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. -- Trent Mick trentm@activestate.com From trentm@activestate.com Fri Jun 23 03:43:11 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 22 Jun 2000 19:43:11 -0700 Subject: [Patches] clean up warnings in Win32 build of mmapmodule.c In-Reply-To: <20000622193634.A17914@activestate.com> References: <20000622193634.A17914@activestate.com> Message-ID: <20000622194311.B17914@activestate.com> On Thu, Jun 22, 2000 at 07:36:34PM -0700, Trent Mick wrote: > > Discussion: > > Fix a few warnings in the Win32 build of mmapmodule.c. The warnings were > about comparison of singed (int) and unsigned (size_t) values. This was > patched by casting every int to size_t for comparison. This is safe because > every cast is preceded with a check guaranteeing that the int is positive. > > I also put this up at SOurceForge: https://sourceforge.net/patch/index.php?func=detailpatch&patch_id=100613&group_id=5470 Side note: My earlier mmap patch was recently applied (thanks Andrew!) but it remains open on the SourceForge patch manager. Apparently (am I wrong) you have to have admin priviledges to close a patch. I would have thought that maybe development status would have confered this. Anyway, could someone please close that bug: https://sourceforge.net/patch/?func=detailpatch&patch_id=100515&group_id=5470 Thanks, Trent -- Trent Mick trentm@activestate.com From mal@lemburg.com Fri Jun 23 09:03:41 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 23 Jun 2000 10:03:41 +0200 Subject: [Patches] Patch management (was: Warnings in pythonrun.c) References: Message-ID: <395319DD.F2584321@lemburg.com> Tim Peters wrote: > > > Worrying about patch management mechanism, while more patches pile up > > and are ignored in the meantime, is not going to help and will just > > results in continued stagnation. > > At an all-hands PythonLabs group mtg today, it was decided to move patch > activity to SourceForge and kill the patches list. I'll send more about > that later. There is absolutely nothing new stopping checkins while the > move to the SourceForge patch manager is in progress, so if the patches > continue to pile up it's certainly not the move's fault. If the pythonrun.c > patch is still sitting untouched after the move, I'll assign it to you <0.7 > wink>. But how are we going to discuss new patches from people outside python-dev then ? I do see the use of moving patch submission to SourceForge, but posting the patches on the list for revision by everyone who listens is certainly better than having to scan the patch manager entries... (push strategies usually produce more feedback than pull ones). A gateway from the patch manager to the patches list would solve this nicely. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From mal@lemburg.com Fri Jun 23 09:04:48 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 23 Jun 2000 10:04:48 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> Message-ID: <39531A20.1BEAA51E@lemburg.com> Gisle Aas wrote: > > "M.-A. Lemburg" writes: > > > > Index: Objects/object.c > > > =================================================================== > > > RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v > > > retrieving revision 2.71 > > > diff -u -p -u -r2.71 object.c > > > --- Objects/object.c 2000/06/09 16:20:39 2.71 > > > +++ Objects/object.c 2000/06/22 19:27:51 > > > @@ -600,8 +600,12 @@ PyObject_GetAttr(v, name) > > > { > > > if (v->ob_type->tp_getattro != NULL) > > > return (*v->ob_type->tp_getattro)(v, name); > > > - else > > > + else if (PyString_Check(name)) > > > return PyObject_GetAttrString(v, PyString_AsString(name)); > > > + else { > > > + PyErr_SetString(PyExc_TypeError, > > > + "attribute name must be string"); > > > + } > > > } > > > > Hmm, I think it would be more generic to add a NULL > > check to PyObject_GetAttrString() (PyString_AsString() returns > > NULL in case name is not a string object). > > Ok. But it also set up the exception to be BadInternalCall() which > does not feel right :-) But that's what it is, right ? ;-) > I also forgot to "return NULL" here. > > > > int > > > @@ -626,12 +630,18 @@ PyObject_SetAttr(v, name, value) > > > { > > > int err; > > > Py_INCREF(name); > > > - PyString_InternInPlace(&name); > > > if (v->ob_type->tp_setattro != NULL) > > > err = (*v->ob_type->tp_setattro)(v, name, value); > > > - else > > > + else if (PyString_Check(name)) { > > > + PyString_InternInPlace(&name); > > > err = PyObject_SetAttrString( > > > v, PyString_AsString(name), value); > > > + } > > > + else { > > > + PyErr_SetString(PyExc_TypeError, > > > + "attribute name must be string"); > > > + err = -1; > > > + } > > > > Here, I think you ought to move the string test just before > > the interning call. > > But you still want to be able to pass non-string objects to > v->ob_type->tp_setattro I guess. Anyway, an alternative patch is > included here. > > Thanks for the quick feedback! > > Regards, > Gisle > > Index: Objects/object.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v > retrieving revision 2.71 > diff -u -p -u -r2.71 object.c > --- Objects/object.c 2000/06/09 16:20:39 2.71 > +++ Objects/object.c 2000/06/22 20:37:21 > @@ -598,10 +598,17 @@ PyObject_GetAttr(v, name) > PyObject *v; > PyObject *name; > { > + char *name_str; > if (v->ob_type->tp_getattro != NULL) > return (*v->ob_type->tp_getattro)(v, name); > - else > - return PyObject_GetAttrString(v, PyString_AsString(name)); > + > + name_str = PyString_AsString(name); > + if (name_str == NULL) { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + return NULL; > + } > + return PyObject_GetAttrString(v, name_str); > } This one looks ok. I would still be curious how the size increase affects performance (you should note that the above API is one of the more often used ones in Python). I would guess that the addition of a variable makes inlining harder -- so why not inline PyString_AsString() here: if (!PyString_Check(name)) { ...error... return NULL; } return PyObject_GetAttrString(v, PyString_AS_STRING(name)); > int > @@ -625,13 +632,23 @@ PyObject_SetAttr(v, name, value) > PyObject *value; > { > int err; > + int name_is_string = 0; > Py_INCREF(name); > - PyString_InternInPlace(&name); > + if (PyString_Check(name)) { > + PyString_InternInPlace(&name); > + name_is_string = 1; > + } > if (v->ob_type->tp_setattro != NULL) > err = (*v->ob_type->tp_setattro)(v, name, value); > - else > + else if (name_is_string) { It's better to avoid this variable and repeat the PyString_Check() (the check only tests a pointer, so it doesn't cost much more). This would also allow using PyString_AS_STRING() instead of the function _AsString(). > err = PyObject_SetAttrString( > v, PyString_AsString(name), value); > + } > + else { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + err = -1; > + } > Py_DECREF(name); > return err; > } > > I confirm that, to the best of my knowledge and belief, this > contribution is free of any claims of third parties under > copyright, patent or other rights or interests ("claims"). To > the extent that I have any such claims, I hereby grant to CNRI a > nonexclusive, irrevocable, royalty-free, worldwide license to > reproduce, distribute, perform and/or display publicly, prepare > derivative versions, and otherwise use this contribution as part > of the Python software and its related documentation, or any > derivative versions thereof, at no cost to CNRI or its licensed > users, and to authorize others to do so. > > I acknowledge that CNRI may, at its sole discretion, decide > whether or not to incorporate this contribution in the Python > software and its related documentation. I further grant CNRI > permission to use my name and other identifying information > provided to CNRI by me for use in connection with the Python > software and its related documentation. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From gisle@ActiveState.com Fri Jun 23 10:51:59 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 23 Jun 2000 11:51:59 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names In-Reply-To: "M.-A. Lemburg"'s message of "Fri, 23 Jun 2000 10:04:48 +0200" References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> <39531A20.1BEAA51E@lemburg.com> Message-ID: This is a modified patch that should address you latest suggestions: Regards, Gisle Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.71 diff -u -p -u -r2.71 object.c --- Objects/object.c 2000/06/09 16:20:39 2.71 +++ Objects/object.c 2000/06/23 09:50:07 @@ -600,8 +600,13 @@ PyObject_GetAttr(v, name) { if (v->ob_type->tp_getattro != NULL) return (*v->ob_type->tp_getattro)(v, name); - else - return PyObject_GetAttrString(v, PyString_AsString(name)); + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + return NULL; + } + return PyObject_GetAttrString(v, PyString_AS_STRING(name)); } int @@ -626,12 +631,19 @@ PyObject_SetAttr(v, name, value) { int err; Py_INCREF(name); - PyString_InternInPlace(&name); + if (PyString_Check(name)) + PyString_InternInPlace(&name); if (v->ob_type->tp_setattro != NULL) err = (*v->ob_type->tp_setattro)(v, name, value); - else + else if (PyString_Check(name)) { err = PyObject_SetAttrString( - v, PyString_AsString(name), value); + v, PyString_AS_STRING(name), value); + } + else { + PyErr_SetString(PyExc_TypeError, + "attribute name must be string"); + err = -1; + } Py_DECREF(name); return err; } I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. From mal@lemburg.com Fri Jun 23 11:06:45 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 23 Jun 2000 12:06:45 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> <39531A20.1BEAA51E@lemburg.com> Message-ID: <395336B5.C059F8D7@lemburg.com> Gisle Aas wrote: > > This is a modified patch that should address you latest suggestions: This one looks ok to me. Anyone else have an opinion on this patch ? > Regards, > Gisle > > Index: Objects/object.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v > retrieving revision 2.71 > diff -u -p -u -r2.71 object.c > --- Objects/object.c 2000/06/09 16:20:39 2.71 > +++ Objects/object.c 2000/06/23 09:50:07 > @@ -600,8 +600,13 @@ PyObject_GetAttr(v, name) > { > if (v->ob_type->tp_getattro != NULL) > return (*v->ob_type->tp_getattro)(v, name); > - else > - return PyObject_GetAttrString(v, PyString_AsString(name)); > + > + if (!PyString_Check(name)) { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + return NULL; > + } > + return PyObject_GetAttrString(v, PyString_AS_STRING(name)); > } > > int > @@ -626,12 +631,19 @@ PyObject_SetAttr(v, name, value) > { > int err; > Py_INCREF(name); > - PyString_InternInPlace(&name); > + if (PyString_Check(name)) > + PyString_InternInPlace(&name); > if (v->ob_type->tp_setattro != NULL) > err = (*v->ob_type->tp_setattro)(v, name, value); > - else > + else if (PyString_Check(name)) { > err = PyObject_SetAttrString( > - v, PyString_AsString(name), value); > + v, PyString_AS_STRING(name), value); > + } > + else { > + PyErr_SetString(PyExc_TypeError, > + "attribute name must be string"); > + err = -1; > + } > Py_DECREF(name); > return err; > } > > I confirm that, to the best of my knowledge and belief, this > contribution is free of any claims of third parties under > copyright, patent or other rights or interests ("claims"). To > the extent that I have any such claims, I hereby grant to CNRI a > nonexclusive, irrevocable, royalty-free, worldwide license to > reproduce, distribute, perform and/or display publicly, prepare > derivative versions, and otherwise use this contribution as part > of the Python software and its related documentation, or any > derivative versions thereof, at no cost to CNRI or its licensed > users, and to authorize others to do so. > > I acknowledge that CNRI may, at its sole discretion, decide > whether or not to incorporate this contribution in the Python > software and its related documentation. I further grant CNRI > permission to use my name and other identifying information > provided to CNRI by me for use in connection with the Python > software and its related documentation. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From akuchlin@mems-exchange.org Fri Jun 23 12:17:42 2000 From: akuchlin@mems-exchange.org (Andrew Kuchling) Date: Fri, 23 Jun 2000 07:17:42 -0400 Subject: [Patches] clean up warnings in Win32 build of mmapmodule.c In-Reply-To: <20000622194311.B17914@activestate.com>; from trentm@activestate.com on Thu, Jun 22, 2000 at 07:43:11PM -0700 References: <20000622193634.A17914@activestate.com> <20000622194311.B17914@activestate.com> Message-ID: <20000623071742.A9385@newcnri.cnri.reston.va.us> >My earlier mmap patch was recently applied (thanks Andrew!) but it remains >open on the SourceForge patch manager. Apparently (am I wrong) you have to >have admin priviledges to close a patch. I can't seem to find an option to let me mark the patch at closed; presumably if it was explicitly assigned to me, I'd be able to close it. --amk From Nils.Fischbeck@icn.siemens.de Fri Jun 23 07:26:21 2000 From: Nils.Fischbeck@icn.siemens.de (Fischbeck Nils) Date: Fri, 23 Jun 2000 08:26:21 +0200 Subject: [Patches] Tkinter with doc string Message-ID: This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_000_01BFDCDB.F3B3F44E Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Hello Guido, I've finished to document the Tkinter-module. It is based on version = 1.138. Martin von L=F6wis has reviewed it. Please check it in if you = like. Regards Nils <>=20 --- Nils Fischbeck +49 03834 555 8178 SIEMENS AG, ICN WN AN AM46 New E-mail address: Nils.Fischbeck@icn.siemens.de ------_=_NextPart_000_01BFDCDB.F3B3F44E Content-Type: application/octet-stream; name="Tkinter1_138a.py" Content-Disposition: attachment; filename="Tkinter1_138a.py" Content-Transfer-Encoding: quoted-printable """Wrapper functions for Tcl/Tk.=0A= =0A= Tkinter provides classes which allow the display, positioning and=0A= control of widgets. Toplevel widgets are Tk and Toplevel. Other=0A= widgets are Frame, Label, Entry, Text, Canvas, Button, Radiobutton,=0A= Checkbutton, Scale, Listbox, Scrollbar, OptionMenu. Properties of the = widgets are=0A= specified with keyword arguments. Keyword arguments have the same=0A= name as the corresponding resource under Tk.=0A= =0A= Widgets are positioned with one of the geometry managers Place, Pack=0A= or Grid. These managers can be called with methods place, pack, grid=0A= available in every Widget.=0A= =0A= Actions are bound to events by resources (e.g. keyword argument = command) or=0A= with the method bind.=0A= =0A= Example (Hello, World):=0A= import Tkinter=0A= from Tkconstants import *=0A= tk =3D Tkinter.Tk()=0A= frame =3D Tkinter.Frame(tk, relief=3DRIDGE, borderwidth=3D2)=0A= frame.pack(fill=3DBOTH,expand=3D1)=0A= label =3D Tkinter.Label(frame, text=3D"Hello, World")=0A= label.pack(fill=3DX, expand=3D1)=0A= button =3D Tkinter.Button(frame,text=3D"Exit",command=3Dtk.destroy)=0A= button.pack(side=3DBOTTOM)=0A= tk.mainloop()=0A= """=0A= =0A= __version__ =3D "$Revision: 1.138 $"=0A= =0A= import sys=0A= if sys.platform =3D=3D "win32":=0A= import FixTk # Attempt to configure Tcl/Tk without requiring PATH=0A= import _tkinter # If this fails your Python may not be configured for = Tk=0A= tkinter =3D _tkinter # b/w compat for export=0A= TclError =3D _tkinter.TclError=0A= from types import *=0A= from Tkconstants import *=0A= import string; _string =3D string; del string=0A= try:=0A= import MacOS; _MacOS =3D MacOS; del MacOS=0A= except ImportError:=0A= _MacOS =3D None=0A= =0A= TkVersion =3D _string.atof(_tkinter.TK_VERSION)=0A= TclVersion =3D _string.atof(_tkinter.TCL_VERSION)=0A= =0A= READABLE =3D _tkinter.READABLE=0A= WRITABLE =3D _tkinter.WRITABLE=0A= EXCEPTION =3D _tkinter.EXCEPTION=0A= =0A= # These are not always defined, e.g. not on Win32 with Tk 8.0 :-(=0A= try: _tkinter.createfilehandler=0A= except AttributeError: _tkinter.createfilehandler =3D None=0A= try: _tkinter.deletefilehandler=0A= except AttributeError: _tkinter.deletefilehandler =3D None=0A= =0A= =0A= def _flatten(tuple):=0A= """Internal function."""=0A= res =3D ()=0A= for item in tuple:=0A= if type(item) in (TupleType, ListType):=0A= res =3D res + _flatten(item)=0A= elif item is not None:=0A= res =3D res + (item,)=0A= return res=0A= =0A= try: _flatten =3D _tkinter._flatten=0A= except AttributeError: pass=0A= =0A= def _cnfmerge(cnfs):=0A= """Internal function."""=0A= if type(cnfs) is DictionaryType:=0A= return cnfs=0A= elif type(cnfs) in (NoneType, StringType):=0A= return cnfs=0A= else:=0A= cnf =3D {}=0A= for c in _flatten(cnfs):=0A= try:=0A= cnf.update(c)=0A= except (AttributeError, TypeError), msg:=0A= print "_cnfmerge: fallback due to:", msg=0A= for k, v in c.items():=0A= cnf[k] =3D v=0A= return cnf=0A= =0A= try: _cnfmerge =3D _tkinter._cnfmerge=0A= except AttributeError: pass=0A= =0A= class Event:=0A= """Container for the properties of an event.=0A= =0A= Instances of this type are generated if one of the following events = occurs:=0A= =0A= KeyPress, KeyRelease - for keyboard events=0A= ButtonPress, ButtonRelease, Motion, Enter, Leave, MouseWheel - for = mouse events=0A= Visibility, Unmap, Map, Expose, FocusIn, FocusOut, Circulate,=0A= Colormap, Gravity, Reparent, Property, Destroy, Activate,=0A= Deactivate - for window events.=0A= =0A= If a callback function for one of these events is registered=0A= using bind, bind_all, bind_class, or tag_bind, the callback is=0A= called with an Event as first argument. It will have the=0A= following attributes (in braces are the event types for which=0A= the attribute is valid):=0A= =0A= serial - serial number of event=0A= num - mouse button pressed (ButtonPress, ButtonRelease)=0A= focus - whether the window has the focus (Enter, Leave)=0A= height - height of the exposed window (Configure, Expose)=0A= width - width of the exposed window (Configure, Expose)=0A= keycode - keycode of the pressed key (KeyPress, KeyRelease)=0A= state - state of the event as a number (ButtonPress, ButtonRelease,=0A= Enter, KeyPress, KeyRelease,=0A= Leave, Motion)=0A= state - state as a string (Visibility)=0A= time - when the event occured=0A= x - x-position of the mouse=0A= y - y-position of the mouse=0A= x_root - x-position of the mouse on the screen=0A= (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)=0A= y_root - y-position of the mouse on the screen=0A= (ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)=0A= char - pressed character (KeyPress, KeyRelease)=0A= send_event - see X/Windows documentation=0A= keysym - keysym of the the event as a string (KeyPress, KeyRelease)=0A= keysym_num - keysym of the event as a number (KeyPress, KeyRelease)=0A= type - type of the event as a number=0A= widget - widget in which the event occured=0A= delta - delta of wheel movement (MouseWheel)=0A= """=0A= pass=0A= =0A= _support_default_root =3D 1=0A= _default_root =3D None=0A= =0A= def NoDefaultRoot():=0A= """Inhibit setting of default root window.=0A= =0A= Call this function to inhibit that the first instance of=0A= Tk is used for windows without an explicit parent window.=0A= """ =0A= global _support_default_root=0A= _support_default_root =3D 0=0A= global _default_root=0A= _default_root =3D None=0A= del _default_root=0A= =0A= def _tkerror(err):=0A= """Internal function."""=0A= pass=0A= =0A= def _exit(code=3D'0'):=0A= """Internal function. Calling it will throw the exception = SystemExit."""=0A= raise SystemExit, code=0A= =0A= _varnum =3D 0=0A= class Variable:=0A= """Internal class. Base class to define value holders for e.g. = buttons."""=0A= _default =3D ""=0A= def __init__(self, master=3DNone):=0A= """Construct a variable with an optional MASTER as master widget.=0A= The variable is named PY_VAR_number in Tcl.=0A= """=0A= global _varnum=0A= if not master:=0A= master =3D _default_root=0A= self._master =3D master=0A= self._tk =3D master.tk=0A= self._name =3D 'PY_VAR' + `_varnum`=0A= _varnum =3D _varnum + 1=0A= self.set(self._default)=0A= def __del__(self):=0A= """Unset the variable in Tcl."""=0A= self._tk.globalunsetvar(self._name)=0A= def __str__(self):=0A= """Return the name of the variable in Tcl."""=0A= return self._name=0A= def set(self, value):=0A= """Set the variable to VALUE."""=0A= return self._tk.globalsetvar(self._name, value)=0A= def trace_variable(self, mode, callback):=0A= """Define a trace callback for the variable.=0A= =0A= MODE is one of "r", "w", "u" for read, write, undefine.=0A= CALLBACK must be a function which is called when=0A= the variable is read, written or undefined.=0A= =0A= Return the name of the callback.=0A= """=0A= cbname =3D self._master._register(callback)=0A= self._tk.call("trace", "variable", self._name, mode, cbname)=0A= return cbname=0A= trace =3D trace_variable=0A= def trace_vdelete(self, mode, cbname):=0A= """Delete the trace callback for a variable.=0A= =0A= MODE is one of "r", "w", "u" for read, write, undefine.=0A= CBNAME is the name of the callback returned from trace_variable or = trace.=0A= """=0A= self._tk.call("trace", "vdelete", self._name, mode, cbname)=0A= self._master.deletecommand(cbname)=0A= def trace_vinfo(self):=0A= """Return all trace callback information."""=0A= return map(self._tk.split, self._tk.splitlist(=0A= self._tk.call("trace", "vinfo", self._name)))=0A= =0A= class StringVar(Variable):=0A= """Value holder for strings variables."""=0A= _default =3D ""=0A= def __init__(self, master=3DNone):=0A= """Construct a string variable.=0A= =0A= MASTER can be given as master widget."""=0A= Variable.__init__(self, master)=0A= =0A= def get(self):=0A= """Return value of variable as string."""=0A= return self._tk.globalgetvar(self._name)=0A= =0A= class IntVar(Variable):=0A= """Value holder for integer variables."""=0A= _default =3D 0=0A= def __init__(self, master=3DNone):=0A= """Construct an integer variable.=0A= =0A= MASTER can be given as master widget."""=0A= Variable.__init__(self, master)=0A= =0A= def get(self):=0A= """Return the value of the variable as an integer."""=0A= return getint(self._tk.globalgetvar(self._name))=0A= =0A= class DoubleVar(Variable):=0A= """Value holder for float variables."""=0A= _default =3D 0.0=0A= def __init__(self, master=3DNone):=0A= """Construct a float variable.=0A= =0A= MASTER can be given as a master widget."""=0A= Variable.__init__(self, master)=0A= =0A= def get(self):=0A= """Return the value of the variable as a float."""=0A= return getdouble(self._tk.globalgetvar(self._name))=0A= =0A= class BooleanVar(Variable):=0A= """Value holder for boolean variables."""=0A= _default =3D "false"=0A= def __init__(self, master=3DNone):=0A= """Construct a boolean variable.=0A= =0A= MASTER can be given as a master widget."""=0A= Variable.__init__(self, master)=0A= =0A= def get(self):=0A= """Return the value of the variable as 0 or 1."""=0A= return self._tk.getboolean(self._tk.globalgetvar(self._name))=0A= =0A= def mainloop(n=3D0):=0A= """Run the main loop of Tcl."""=0A= _default_root.tk.mainloop(n)=0A= =0A= getint =3D int=0A= =0A= getdouble =3D float=0A= =0A= def getboolean(s):=0A= """Convert true and false to integer values 1 and 0."""=0A= return _default_root.tk.getboolean(s)=0A= =0A= # Methods defined on both toplevel and interior widgets=0A= class Misc:=0A= """Internal class.=0A= =0A= Base class which defines methods common for interior widgets."""=0A= =0A= # XXX font command?=0A= _tclCommands =3D None=0A= def destroy(self):=0A= """Internal function.=0A= =0A= Delete all Tcl commands created for=0A= this widget in the Tcl interpreter."""=0A= if self._tclCommands is not None:=0A= for name in self._tclCommands:=0A= #print '- Tkinter: deleted command', name=0A= self.tk.deletecommand(name)=0A= self._tclCommands =3D None=0A= def deletecommand(self, name):=0A= """Internal function.=0A= =0A= Delete the Tcl command provided in NAME."""=0A= #print '- Tkinter: deleted command', name=0A= self.tk.deletecommand(name)=0A= try:=0A= self._tclCommands.remove(name)=0A= except ValueError:=0A= pass=0A= def tk_strictMotif(self, boolean=3DNone):=0A= """Set Tcl internal variable, whether the look and feel=0A= should adhere to Motif.=0A= =0A= A parameter of 1 means adhere to Motif (e.g. no color=0A= change if mouse passes over slider).=0A= Returns the set value."""=0A= return self.tk.getboolean(self.tk.call(=0A= 'set', 'tk_strictMotif', boolean))=0A= def tk_bisque(self):=0A= """Change the color scheme to light brown as used in Tk 3.6 and = before.""" =0A= self.tk.call('tk_bisque')=0A= def tk_setPalette(self, *args, **kw):=0A= """Set a new color scheme for all widget elements.=0A= =0A= A single color as argument will cause that all colors of Tk=0A= widget elements are derived from this.=0A= Alternatively several keyword parameters and its associated=0A= colors can be given. The following keywords are valid:=0A= activeBackground, foreground, selectColor,=0A= activeForeground, highlightBackground, selectBackground,=0A= background, highlightColor, selectForeground,=0A= disabledForeground, insertBackground, troughColor."""=0A= self.tk.call(('tk_setPalette',)=0A= + _flatten(args) + _flatten(kw.items()))=0A= def tk_menuBar(self, *args):=0A= """Do not use. Needed in Tk 3.6 and earlier."""=0A= pass # obsolete since Tk 4.0=0A= def wait_variable(self, name=3D'PY_VAR'):=0A= """Wait until the variable is modified.=0A= =0A= A parameter of type IntVar, StringVar, DoubleVar or=0A= BooleanVar must be given."""=0A= self.tk.call('tkwait', 'variable', name)=0A= waitvar =3D wait_variable # XXX b/w compat=0A= def wait_window(self, window=3DNone):=0A= """Wait until a WIDGET is destroyed.=0A= =0A= If no parameter is given self is used."""=0A= if window =3D=3D None:=0A= window =3D self=0A= self.tk.call('tkwait', 'window', window._w)=0A= def wait_visibility(self, window=3DNone):=0A= """Wait until the visibility of a WIDGET changes=0A= (e.g. it appears).=0A= =0A= If no parameter is given self is used."""=0A= if window =3D=3D None:=0A= window =3D self=0A= self.tk.call('tkwait', 'visibility', window._w)=0A= def setvar(self, name=3D'PY_VAR', value=3D'1'):=0A= """Set Tcl variable NAME to VALUE."""=0A= self.tk.setvar(name, value)=0A= def getvar(self, name=3D'PY_VAR'):=0A= """Return value of Tcl variable NAME."""=0A= return self.tk.getvar(name)=0A= getint =3D int=0A= getdouble =3D float=0A= def getboolean(self, s):=0A= """Return 0 or 1 for Tcl boolean values true and false given as = parameter."""=0A= return self.tk.getboolean(s)=0A= def focus_set(self):=0A= """Direct input focus to this widget.=0A= =0A= If the application currently does not have the focus=0A= this widget will get the focus if the application gets=0A= the focus through the window manager."""=0A= self.tk.call('focus', self._w)=0A= focus =3D focus_set # XXX b/w compat?=0A= def focus_force(self):=0A= """Direct input focus to this widget even if the=0A= application does not have the focus. Use with=0A= caution!"""=0A= self.tk.call('focus', '-force', self._w)=0A= def focus_get(self):=0A= """Return the widget which has currently the focus in the=0A= application.=0A= =0A= Use focus_displayof to allow working with several=0A= displays. Return None if application does not have=0A= the focus."""=0A= name =3D self.tk.call('focus')=0A= if name =3D=3D 'none' or not name: return None=0A= return self._nametowidget(name)=0A= def focus_displayof(self):=0A= """Return the widget which has currently the focus on the=0A= display where this widget is located.=0A= =0A= Return None if the application does not have the focus."""=0A= name =3D self.tk.call('focus', '-displayof', self._w)=0A= if name =3D=3D 'none' or not name: return None=0A= return self._nametowidget(name)=0A= def focus_lastfor(self):=0A= """Return the widget which would have the focus if top level=0A= for this widget gets the focus from the window manager."""=0A= name =3D self.tk.call('focus', '-lastfor', self._w)=0A= if name =3D=3D 'none' or not name: return None=0A= return self._nametowidget(name)=0A= def tk_focusFollowsMouse(self):=0A= """The widget under mouse will get automatically focus. Can not=0A= be disabled easily."""=0A= self.tk.call('tk_focusFollowsMouse')=0A= def tk_focusNext(self):=0A= """Return the next widget in the focus order which follows=0A= widget which has currently the focus.=0A= =0A= The focus order first goes to the next child, then to=0A= the children of the child recursively and then to the=0A= next sibling which is higher in the stacking order. A=0A= widget is ommited if it has the takefocus resource set=0A= to 0."""=0A= name =3D self.tk.call('tk_focusNext', self._w)=0A= if not name: return None=0A= return self._nametowidget(name)=0A= def tk_focusPrev(self):=0A= """Return previous widget in the focus order. See tk_focusNext for = details."""=0A= name =3D self.tk.call('tk_focusPrev', self._w)=0A= if not name: return None=0A= return self._nametowidget(name)=0A= def after(self, ms, func=3DNone, *args):=0A= """Call function once after given time.=0A= =0A= MS specifies the time in milliseconds. FUNC gives the=0A= function which shall be called. Additional parameters=0A= are given as parameters to the function call. Return=0A= identifier to cancel scheduling with after_cancel."""=0A= if not func:=0A= # I'd rather use time.sleep(ms*0.001)=0A= self.tk.call('after', ms)=0A= else:=0A= # XXX Disgusting hack to clean up after calling func=0A= tmp =3D []=0A= def callit(func=3Dfunc, args=3Dargs, self=3Dself, tmp=3Dtmp):=0A= try:=0A= apply(func, args)=0A= finally:=0A= try:=0A= self.deletecommand(tmp[0])=0A= except TclError:=0A= pass=0A= name =3D self._register(callit)=0A= tmp.append(name)=0A= return self.tk.call('after', ms, name)=0A= def after_idle(self, func, *args):=0A= """Call FUNC once if the Tcl main loop has no event to=0A= process.=0A= =0A= Return an identifier to cancel the scheduling with=0A= after_cancel."""=0A= return apply(self.after, ('idle', func) + args)=0A= def after_cancel(self, id):=0A= """Cancel scheduling of function identified with ID.=0A= =0A= Identifier returned by after or after_idle must be=0A= given as first parameter."""=0A= self.tk.call('after', 'cancel', id)=0A= def bell(self, displayof=3D0):=0A= """Ring a display's bell."""=0A= self.tk.call(('bell',) + self._displayof(displayof))=0A= # Clipboard handling:=0A= def clipboard_clear(self, **kw):=0A= """Clear the data in the Tk clipboard.=0A= =0A= A widget specified for the optional displayof keyword=0A= argument specifies the target display."""=0A= if not kw.has_key('displayof'): kw['displayof'] =3D self._w=0A= self.tk.call(('clipboard', 'clear') + self._options(kw))=0A= def clipboard_append(self, string, **kw):=0A= """Append STRING to the Tk clipboard.=0A= =0A= A widget specified at the optional displayof keyword=0A= argument specifies the target display. The clipboard=0A= can be retrieved with selection_get."""=0A= if not kw.has_key('displayof'): kw['displayof'] =3D self._w=0A= self.tk.call(('clipboard', 'append') + self._options(kw)=0A= + ('--', string))=0A= # XXX grab current w/o window argument=0A= def grab_current(self):=0A= """Return widget which has currently the grab in this application=0A= or None."""=0A= name =3D self.tk.call('grab', 'current', self._w)=0A= if not name: return None=0A= return self._nametowidget(name)=0A= def grab_release(self):=0A= """Release grab for this widget if currently set."""=0A= self.tk.call('grab', 'release', self._w)=0A= def grab_set(self):=0A= """Set grab for this widget.=0A= =0A= A grab directs all events to this and descendant=0A= widgets in the application."""=0A= self.tk.call('grab', 'set', self._w)=0A= def grab_set_global(self):=0A= """Set global grab for this widget.=0A= =0A= A global grab directs all events to this and=0A= descendant widgets on the display. Use with caution -=0A= other applications do not get events anymore."""=0A= self.tk.call('grab', 'set', '-global', self._w)=0A= def grab_status(self):=0A= """Return None, "local" or "global" if this widget has=0A= no, a local or a global grab."""=0A= status =3D self.tk.call('grab', 'status', self._w)=0A= if status =3D=3D 'none': status =3D None=0A= return status=0A= def lower(self, belowThis=3DNone):=0A= """Lower this widget in the stacking order."""=0A= self.tk.call('lower', self._w, belowThis)=0A= def option_add(self, pattern, value, priority =3D None):=0A= """Set a VALUE (second parameter) for an option=0A= PATTERN (first parameter).=0A= =0A= An optional third parameter gives the numeric priority=0A= (defaults to 80)."""=0A= self.tk.call('option', 'add', pattern, value, priority)=0A= def option_clear(self):=0A= """Clear the option database.=0A= =0A= It will be reloaded if option_add is called."""=0A= self.tk.call('option', 'clear')=0A= def option_get(self, name, className):=0A= """Return the value for an option NAME for this widget=0A= with CLASSNAME.=0A= =0A= Values with higher priority override lower values."""=0A= return self.tk.call('option', 'get', self._w, name, className)=0A= def option_readfile(self, fileName, priority =3D None):=0A= """Read file FILENAME into the option database.=0A= =0A= An optional second paramter gives the numeric=0A= priority."""=0A= self.tk.call('option', 'readfile', fileName, priority)=0A= def selection_clear(self, **kw):=0A= """Clear the current X selection."""=0A= if not kw.has_key('displayof'): kw['displayof'] =3D self._w=0A= self.tk.call(('selection', 'clear') + self._options(kw))=0A= def selection_get(self, **kw):=0A= """Return the contents of the current X selection.=0A= =0A= A keyword parameter selection specifies the name of=0A= the selection and defaults to PRIMARY. A keyword=0A= parameter displayof specifies a widget on the display=0A= to use."""=0A= if not kw.has_key('displayof'): kw['displayof'] =3D self._w=0A= return self.tk.call(('selection', 'get') + self._options(kw))=0A= def selection_handle(self, command, **kw):=0A= """Specify a function COMMAND to call if the X=0A= selection owned by this widget is queried by another=0A= application.=0A= =0A= This function must return the contents of the=0A= selection. The function will be called with the=0A= arguments OFFSET and LENGTH which allows the chunking=0A= of very long selections. The following keyword=0A= parameters can be provided:=0A= selection - name of the selection (default PRIMARY),=0A= type - type of the selection (e.g. STRING, FILE_NAME)."""=0A= name =3D self._register(command)=0A= self.tk.call(('selection', 'handle') + self._options(kw)=0A= + (self._w, name))=0A= def selection_own(self, **kw):=0A= """Become owner of X selection.=0A= =0A= A keyword parameter selection specifies the name of=0A= the selection (default PRIMARY)."""=0A= self.tk.call(('selection', 'own') +=0A= self._options(kw) + (self._w,))=0A= def selection_own_get(self, **kw):=0A= """Return owner of X selection.=0A= =0A= The following keyword parameter can=0A= be provided:=0A= selection - name of the selection (default PRIMARY),=0A= type - type of the selection (e.g. STRING, FILE_NAME)."""=0A= if not kw.has_key('displayof'): kw['displayof'] =3D self._w=0A= name =3D self.tk.call(('selection', 'own') + self._options(kw))=0A= if not name: return None=0A= return self._nametowidget(name)=0A= def send(self, interp, cmd, *args):=0A= """Send Tcl command CMD to different interpreter INTERP to be = executed."""=0A= return self.tk.call(('send', interp, cmd) + args)=0A= def lower(self, belowThis=3DNone):=0A= """Lower this widget in the stacking order."""=0A= self.tk.call('lower', self._w, belowThis)=0A= def tkraise(self, aboveThis=3DNone):=0A= """Raise this widget in the stacking order."""=0A= self.tk.call('raise', self._w, aboveThis)=0A= lift =3D tkraise=0A= def colormodel(self, value=3DNone):=0A= """Useless. Not implemented in Tk."""=0A= return self.tk.call('tk', 'colormodel', self._w, value)=0A= def winfo_atom(self, name, displayof=3D0):=0A= """Return integer which represents atom NAME."""=0A= args =3D ('winfo', 'atom') + self._displayof(displayof) + (name,)=0A= return getint(self.tk.call(args))=0A= def winfo_atomname(self, id, displayof=3D0):=0A= """Return name of atom with identifier ID."""=0A= args =3D ('winfo', 'atomname') \=0A= + self._displayof(displayof) + (id,)=0A= return self.tk.call(args)=0A= def winfo_cells(self):=0A= """Return number of cells in the colormap for this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'cells', self._w))=0A= def winfo_children(self):=0A= """Return a list of all widgets which are children of this = widget."""=0A= return map(self._nametowidget,=0A= self.tk.splitlist(self.tk.call(=0A= 'winfo', 'children', self._w)))=0A= def winfo_class(self):=0A= """Return window class name of this widget."""=0A= return self.tk.call('winfo', 'class', self._w)=0A= def winfo_colormapfull(self):=0A= """Return true if at the last color request the colormap was = full."""=0A= return self.tk.getboolean(=0A= self.tk.call('winfo', 'colormapfull', self._w))=0A= def winfo_containing(self, rootX, rootY, displayof=3D0):=0A= """Return the widget which is at the root coordinates ROOTX, = ROOTY."""=0A= args =3D ('winfo', 'containing') \=0A= + self._displayof(displayof) + (rootX, rootY)=0A= name =3D self.tk.call(args)=0A= if not name: return None=0A= return self._nametowidget(name)=0A= def winfo_depth(self):=0A= """Return the number of bits per pixel."""=0A= return getint(self.tk.call('winfo', 'depth', self._w))=0A= def winfo_exists(self):=0A= """Return true if this widget exists."""=0A= return getint(=0A= self.tk.call('winfo', 'exists', self._w))=0A= def winfo_fpixels(self, number):=0A= """Return the number of pixels for the given distance NUMBER=0A= (e.g. "3c") as float."""=0A= return getdouble(self.tk.call(=0A= 'winfo', 'fpixels', self._w, number))=0A= def winfo_geometry(self):=0A= """Return geometry string for this widget in the form = "widthxheight+X+Y"."""=0A= return self.tk.call('winfo', 'geometry', self._w)=0A= def winfo_height(self):=0A= """Return heigth of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'height', self._w))=0A= def winfo_id(self):=0A= """Return identifier ID for this widget."""=0A= return self.tk.getint(=0A= self.tk.call('winfo', 'id', self._w))=0A= def winfo_interps(self, displayof=3D0):=0A= """Return the name of all Tcl interpreters for this display."""=0A= args =3D ('winfo', 'interps') + self._displayof(displayof)=0A= return self.tk.splitlist(self.tk.call(args))=0A= def winfo_ismapped(self):=0A= """Return true if this widget is mapped."""=0A= return getint(=0A= self.tk.call('winfo', 'ismapped', self._w))=0A= def winfo_manager(self):=0A= """Return the window mananger name for this widget."""=0A= return self.tk.call('winfo', 'manager', self._w)=0A= def winfo_name(self):=0A= """Return the name of this widget."""=0A= return self.tk.call('winfo', 'name', self._w)=0A= def winfo_parent(self):=0A= """Return the name of the parent of this widget."""=0A= return self.tk.call('winfo', 'parent', self._w)=0A= def winfo_pathname(self, id, displayof=3D0):=0A= """Return the pathname of the widget given by ID."""=0A= args =3D ('winfo', 'pathname') \=0A= + self._displayof(displayof) + (id,)=0A= return self.tk.call(args)=0A= def winfo_pixels(self, number):=0A= """Rounded integer value of winfo_fpixels."""=0A= return getint(=0A= self.tk.call('winfo', 'pixels', self._w, number))=0A= def winfo_pointerx(self):=0A= """Return the x coordinate of the pointer on the root window."""=0A= return getint(=0A= self.tk.call('winfo', 'pointerx', self._w))=0A= def winfo_pointerxy(self):=0A= """Return a tupel of x and y coordinates of the pointer on the root = window."""=0A= return self._getints(=0A= self.tk.call('winfo', 'pointerxy', self._w))=0A= def winfo_pointery(self):=0A= """Return the y coordinate of the pointer on the root window."""=0A= return getint(=0A= self.tk.call('winfo', 'pointery', self._w))=0A= def winfo_reqheight(self):=0A= """Return requested height of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'reqheight', self._w))=0A= def winfo_reqwidth(self):=0A= """Return requested width of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'reqwidth', self._w))=0A= def winfo_rgb(self, color):=0A= """Return tupel of decimal values for red, green, blue for=0A= COLOR in this widget."""=0A= return self._getints(=0A= self.tk.call('winfo', 'rgb', self._w, color))=0A= def winfo_rootx(self):=0A= """Return x coordinate of upper left corner of this widget on the=0A= root window."""=0A= return getint(=0A= self.tk.call('winfo', 'rootx', self._w))=0A= def winfo_rooty(self):=0A= """Return y coordinate of upper left corner of this widget on the=0A= root window."""=0A= return getint(=0A= self.tk.call('winfo', 'rooty', self._w))=0A= def winfo_screen(self):=0A= """Return the screen name of this widget."""=0A= return self.tk.call('winfo', 'screen', self._w)=0A= def winfo_screencells(self):=0A= """Return the number of the cells in the colormap of the screen=0A= of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'screencells', self._w))=0A= def winfo_screendepth(self):=0A= """Return the number of bits per pixel of the root window of the=0A= screen of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'screendepth', self._w))=0A= def winfo_screenheight(self):=0A= """Return the number of pixels of the height of the screen of this = widget=0A= in pixel."""=0A= return getint(=0A= self.tk.call('winfo', 'screenheight', self._w))=0A= def winfo_screenmmheight(self):=0A= """Return the number of pixels of the height of the screen of=0A= this widget in mm."""=0A= return getint(=0A= self.tk.call('winfo', 'screenmmheight', self._w))=0A= def winfo_screenmmwidth(self):=0A= """Return the number of pixels of the width of the screen of=0A= this widget in mm."""=0A= return getint(=0A= self.tk.call('winfo', 'screenmmwidth', self._w))=0A= def winfo_screenvisual(self):=0A= """Return one of the strings directcolor, grayscale, pseudocolor,=0A= staticcolor, staticgray, or truecolor for the default=0A= colormodel of this screen."""=0A= return self.tk.call('winfo', 'screenvisual', self._w)=0A= def winfo_screenwidth(self):=0A= """Return the number of pixels of the width of the screen of=0A= this widget in pixel."""=0A= return getint(=0A= self.tk.call('winfo', 'screenwidth', self._w))=0A= def winfo_server(self):=0A= """Return information of the X-Server of the screen of this widget = in=0A= the form "XmajorRminor vendor vendorVersion"."""=0A= return self.tk.call('winfo', 'server', self._w)=0A= def winfo_toplevel(self):=0A= """Return the toplevel widget of this widget."""=0A= return self._nametowidget(self.tk.call(=0A= 'winfo', 'toplevel', self._w))=0A= def winfo_viewable(self):=0A= """Return true if the widget and all its higher anchestors are = mapped."""=0A= return getint(=0A= self.tk.call('winfo', 'viewable', self._w))=0A= def winfo_visual(self):=0A= """Return one of the strings directcolor, grayscale, pseudocolor,=0A= staticcolor, staticgray, or truecolor for the =0A= colormodel of this widget."""=0A= return self.tk.call('winfo', 'visual', self._w)=0A= def winfo_visualid(self):=0A= """Return the X identifier for the visual for this widget."""=0A= return self.tk.call('winfo', 'visualid', self._w)=0A= def winfo_visualsavailable(self, includeids=3D0):=0A= """Return a list of all visuals available for the screen=0A= of this widget.=0A= =0A= Each item in the list consists of a visual name (see winfo_visual), = a=0A= depth and if INCLUDEIDS=3D1 is given also the X identifier."""=0A= data =3D self.tk.split(=0A= self.tk.call('winfo', 'visualsavailable', self._w,=0A= includeids and 'includeids' or None))=0A= return map(self.__winfo_parseitem, data)=0A= def __winfo_parseitem(self, t):=0A= """Internal function."""=0A= return t[:1] + tuple(map(self.__winfo_getint, t[1:]))=0A= def __winfo_getint(self, x):=0A= """Internal function."""=0A= return _string.atoi(x, 0)=0A= def winfo_vrootheight(self):=0A= """Return the height of the virtual root window associated with = this=0A= widget in pixels. If there is no virtual root window return the=0A= height of the screen."""=0A= return getint(=0A= self.tk.call('winfo', 'vrootheight', self._w))=0A= def winfo_vrootwidth(self):=0A= """Return the width of the virtual root window associated with = this=0A= widget in pixel. If there is no virtual root window return the=0A= width of the screen."""=0A= return getint(=0A= self.tk.call('winfo', 'vrootwidth', self._w))=0A= def winfo_vrootx(self):=0A= """Return the x offset of the virtual root relative to the root=0A= window of the screen of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'vrootx', self._w))=0A= def winfo_vrooty(self):=0A= """Return the y offset of the virtual root relative to the root=0A= window of the screen of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'vrooty', self._w))=0A= def winfo_width(self):=0A= """Return the width of this widget."""=0A= return getint(=0A= self.tk.call('winfo', 'width', self._w))=0A= def winfo_x(self):=0A= """Return the x coordinate of the upper left corner of this widget=0A= in the parent."""=0A= return getint(=0A= self.tk.call('winfo', 'x', self._w))=0A= def winfo_y(self):=0A= """Return the y coordinate of the upper left corner of this widget=0A= in the parent."""=0A= return getint(=0A= self.tk.call('winfo', 'y', self._w))=0A= def update(self):=0A= """Enter event loop until all pending events have been processed by = Tcl."""=0A= self.tk.call('update')=0A= def update_idletasks(self):=0A= """Enter event loop until all idle callbacks have been called. = This=0A= will update the display of windows but not process events caused = by=0A= the user."""=0A= self.tk.call('update', 'idletasks')=0A= def bindtags(self, tagList=3DNone):=0A= """Set or get the list of bindtags for this widget.=0A= =0A= With no argument return the list of all bindtags associated with=0A= this widget. With a list of strings as argument the bindtags are=0A= set to this list. The bindtags determine in which order events are=0A= processed (see bind)."""=0A= if tagList is None:=0A= return self.tk.splitlist(=0A= self.tk.call('bindtags', self._w))=0A= else:=0A= self.tk.call('bindtags', self._w, tagList)=0A= def _bind(self, what, sequence, func, add, needcleanup=3D1):=0A= """Internal function."""=0A= if type(func) is StringType:=0A= self.tk.call(what + (sequence, func))=0A= elif func:=0A= funcid =3D self._register(func, self._substitute,=0A= needcleanup)=0A= cmd =3D ('%sif {"[%s %s]" =3D=3D "break"} break\n'=0A= %=0A= (add and '+' or '',=0A= funcid,=0A= _string.join(self._subst_format)))=0A= self.tk.call(what + (sequence, cmd))=0A= return funcid=0A= elif sequence:=0A= return self.tk.call(what + (sequence,))=0A= else:=0A= return self.tk.splitlist(self.tk.call(what))=0A= def bind(self, sequence=3DNone, func=3DNone, add=3DNone):=0A= """Bind to this widget at event SEQUENCE a call to function FUNC.=0A= =0A= SEQUENCE is a string of concatenated event=0A= patterns. An event pattern is of the form=0A= where MODIFIER is one=0A= of Control, Mod2, M2, Shift, Mod3, M3, Lock, Mod4, M4,=0A= Button1, B1, Mod5, M5 Button2, B2, Meta, M, Button3,=0A= B3, Alt, Button4, B4, Double, Button5, B5 Triple,=0A= Mod1, M1. TYPE is one of Activate, Enter, Map,=0A= ButtonPress, Button, Expose, Motion, ButtonRelease=0A= FocusIn, MouseWheel, Circulate, FocusOut, Property,=0A= Colormap, Gravity Reparent, Configure, KeyPress, Key,=0A= Unmap, Deactivate, KeyRelease Visibility, Destroy,=0A= Leave and DETAIL is the button number for ButtonPress,=0A= ButtonRelease and DETAIL is the Keysym for KeyPress and=0A= KeyRelease. Examples are=0A= for pressing Control and mouse button 1 or=0A= for pressing A and the Alt key (KeyPress can be omitted).=0A= An event pattern can also be a virtual event of the form=0A= <> where AString can be arbitrary. This=0A= event can be generated by event_generate.=0A= If events are concatenated they must appear shortly=0A= after each other.=0A= =0A= FUNC will be called if the event sequence occurs with an=0A= instance of Event as argument. If the return value of FUNC is=0A= "break" no further bound function is invoked.=0A= =0A= An additional boolean parameter ADD specifies whether FUNC will=0A= be called additionally to the other bound function or whether=0A= it will replace the previous function.=0A= =0A= Bind will return an identifier to allow deletion of the bound = function with=0A= unbind without memory leak.=0A= =0A= If FUNC or SEQUENCE is omitted the bound function or list=0A= of bound events are returned."""=0A= =0A= return self._bind(('bind', self._w), sequence, func, add)=0A= def unbind(self, sequence, funcid=3DNone):=0A= """Unbind for this widget for event SEQUENCE the=0A= function identified with FUNCID."""=0A= self.tk.call('bind', self._w, sequence, '')=0A= if funcid:=0A= self.deletecommand(funcid)=0A= def bind_all(self, sequence=3DNone, func=3DNone, add=3DNone):=0A= """Bind to all widgets at an event SEQUENCE a call to function = FUNC.=0A= An additional boolean parameter ADD specifies whether FUNC will=0A= be called additionally to the other bound function or whether=0A= it will replace the previous function. See bind for the return = value."""=0A= return self._bind(('bind', 'all'), sequence, func, add, 0)=0A= def unbind_all(self, sequence):=0A= """Unbind for all widgets for event SEQUENCE all functions."""=0A= self.tk.call('bind', 'all' , sequence, '')=0A= def bind_class(self, className, sequence=3DNone, func=3DNone, = add=3DNone):=0A= =0A= """Bind to widgets with bindtag CLASSNAME at event=0A= SEQUENCE a call of function FUNC. An additional=0A= boolean parameter ADD specifies whether FUNC will be=0A= called additionally to the other bound function or=0A= whether it will replace the previous function. See bind for=0A= the return value."""=0A= =0A= return self._bind(('bind', className), sequence, func, add, 0)=0A= def unbind_class(self, className, sequence):=0A= """Unbind for a all widgets with bindtag CLASSNAME for event = SEQUENCE=0A= all functions."""=0A= self.tk.call('bind', className , sequence, '')=0A= def mainloop(self, n=3D0):=0A= """Call the mainloop of Tk."""=0A= self.tk.mainloop(n)=0A= def quit(self):=0A= """Quit the Tcl interpreter. All widgets will be destroyed."""=0A= self.tk.quit()=0A= def _getints(self, string):=0A= """Internal function."""=0A= if string:=0A= return tuple(map(getint, self.tk.splitlist(string)))=0A= def _getdoubles(self, string):=0A= """Internal function."""=0A= if string:=0A= return tuple(map(getdouble, self.tk.splitlist(string)))=0A= def _getboolean(self, string):=0A= """Internal function."""=0A= if string:=0A= return self.tk.getboolean(string)=0A= def _displayof(self, displayof):=0A= """Internal function."""=0A= if displayof:=0A= return ('-displayof', displayof)=0A= if displayof is None:=0A= return ('-displayof', self._w)=0A= return ()=0A= def _options(self, cnf, kw =3D None):=0A= """Internal function."""=0A= if kw:=0A= cnf =3D _cnfmerge((cnf, kw))=0A= else:=0A= cnf =3D _cnfmerge(cnf)=0A= res =3D ()=0A= for k, v in cnf.items():=0A= if v is not None:=0A= if k[-1] =3D=3D '_': k =3D k[:-1]=0A= if callable(v):=0A= v =3D self._register(v)=0A= res =3D res + ('-'+k, v)=0A= return res=0A= def nametowidget(self, name):=0A= """Return the Tkinter instance of a widget identified by=0A= its Tcl name NAME."""=0A= w =3D self=0A= if name[0] =3D=3D '.':=0A= w =3D w._root()=0A= name =3D name[1:]=0A= find =3D _string.find=0A= while name:=0A= i =3D find(name, '.')=0A= if i >=3D 0:=0A= name, tail =3D name[:i], name[i+1:]=0A= else:=0A= tail =3D ''=0A= w =3D w.children[name]=0A= name =3D tail=0A= return w=0A= _nametowidget =3D nametowidget=0A= def _register(self, func, subst=3DNone, needcleanup=3D1):=0A= """Return a newly created Tcl function. If this=0A= function is called, the Python function FUNC will=0A= be executed. An optional function SUBST can=0A= be given which will be executed before FUNC."""=0A= f =3D CallWrapper(func, subst, self).__call__=0A= name =3D `id(f)`=0A= try:=0A= func =3D func.im_func=0A= except AttributeError:=0A= pass=0A= try:=0A= name =3D name + func.__name__=0A= except AttributeError:=0A= pass=0A= self.tk.createcommand(name, f)=0A= if needcleanup:=0A= if self._tclCommands is None:=0A= self._tclCommands =3D []=0A= self._tclCommands.append(name)=0A= #print '+ Tkinter created command', name=0A= return name=0A= register =3D _register=0A= def _root(self):=0A= """Internal function."""=0A= w =3D self=0A= while w.master: w =3D w.master=0A= return w=0A= _subst_format =3D ('%#', '%b', '%f', '%h', '%k', =0A= '%s', '%t', '%w', '%x', '%y',=0A= '%A', '%E', '%K', '%N', '%W', '%T', '%X', '%Y', '%D')=0A= def _substitute(self, *args):=0A= """Internal function."""=0A= if len(args) !=3D len(self._subst_format): return args=0A= getboolean =3D self.tk.getboolean=0A= getint =3D int=0A= nsign, b, f, h, k, s, t, w, x, y, A, E, K, N, W, T, X, Y, D =3D = args=0A= # Missing: (a, c, d, m, o, v, B, R)=0A= e =3D Event()=0A= e.serial =3D getint(nsign)=0A= e.num =3D getint(b)=0A= try: e.focus =3D getboolean(f)=0A= except TclError: pass=0A= e.height =3D getint(h)=0A= e.keycode =3D getint(k)=0A= # For Visibility events, event state is a string and=0A= # not an integer:=0A= try:=0A= e.state =3D getint(s)=0A= except ValueError:=0A= e.state =3D s=0A= e.time =3D getint(t)=0A= e.width =3D getint(w)=0A= e.x =3D getint(x)=0A= e.y =3D getint(y)=0A= e.char =3D A=0A= try: e.send_event =3D getboolean(E)=0A= except TclError: pass=0A= e.keysym =3D K=0A= e.keysym_num =3D getint(N)=0A= e.type =3D T=0A= try:=0A= e.widget =3D self._nametowidget(W)=0A= except KeyError:=0A= e.widget =3D W=0A= e.x_root =3D getint(X)=0A= e.y_root =3D getint(Y)=0A= e.delta =3D getint(D)=0A= return (e,)=0A= def _report_exception(self):=0A= """Internal function."""=0A= import sys=0A= exc, val, tb =3D sys.exc_type, sys.exc_value, sys.exc_traceback=0A= root =3D self._root()=0A= root.report_callback_exception(exc, val, tb)=0A= # These used to be defined in Widget:=0A= def configure(self, cnf=3DNone, **kw):=0A= """Configure resources of a widget.=0A= =0A= The values for resources are specified as keyword=0A= arguments. To get an overview about=0A= the allowed keyword arguments call the method keys.=0A= """=0A= # XXX ought to generalize this so tag_config etc. can use it=0A= if kw:=0A= cnf =3D _cnfmerge((cnf, kw))=0A= elif cnf:=0A= cnf =3D _cnfmerge(cnf)=0A= if cnf is None:=0A= cnf =3D {}=0A= for x in self.tk.split(=0A= self.tk.call(self._w, 'configure')):=0A= cnf[x[0][1:]] =3D (x[0][1:],) + x[1:]=0A= return cnf=0A= if type(cnf) is StringType:=0A= x =3D self.tk.split(self.tk.call(=0A= self._w, 'configure', '-'+cnf))=0A= return (x[0][1:],) + x[1:]=0A= self.tk.call((self._w, 'configure')=0A= + self._options(cnf))=0A= config =3D configure=0A= def cget(self, key):=0A= """Return the resource value for a KEY given as string."""=0A= return self.tk.call(self._w, 'cget', '-' + key)=0A= __getitem__ =3D cget=0A= def __setitem__(self, key, value):=0A= self.configure({key: value})=0A= def keys(self):=0A= """Return a list of all resource names of this widget."""=0A= return map(lambda x: x[0][1:],=0A= self.tk.split(self.tk.call(self._w, 'configure')))=0A= def __str__(self):=0A= """Return the window path name of this widget."""=0A= return self._w=0A= # Pack methods that apply to the master=0A= _noarg_ =3D ['_noarg_']=0A= def pack_propagate(self, flag=3D_noarg_):=0A= """Set or get the status for propagation of geometry information.=0A= =0A= A boolean argument specifies whether the geometry information=0A= of the slaves will determine the size of this widget. If no = argument=0A= is given the current setting will be returned.=0A= """=0A= if flag is Misc._noarg_:=0A= return self._getboolean(self.tk.call(=0A= 'pack', 'propagate', self._w))=0A= else:=0A= self.tk.call('pack', 'propagate', self._w, flag)=0A= propagate =3D pack_propagate=0A= def pack_slaves(self):=0A= """Return a list of all slaves of this widget=0A= in its packing order."""=0A= return map(self._nametowidget,=0A= self.tk.splitlist(=0A= self.tk.call('pack', 'slaves', self._w)))=0A= slaves =3D pack_slaves=0A= # Place method that applies to the master=0A= def place_slaves(self):=0A= """Return a list of all slaves of this widget=0A= in its packing order."""=0A= return map(self._nametowidget,=0A= self.tk.splitlist(=0A= self.tk.call(=0A= 'place', 'slaves', self._w)))=0A= # Grid methods that apply to the master=0A= def grid_bbox(self, column=3DNone, row=3DNone, col2=3DNone, = row2=3DNone):=0A= """Return a tuple of integer coordinates for the bounding=0A= box of this widget controlled by the geometry manager grid.=0A= =0A= If COLUMN, ROW is given the bounding box applies from=0A= the cell with row and column 0 to the specified=0A= cell. If COL2 and ROW2 are given the bounding box=0A= starts at that cell.=0A= =0A= The returned integers specify the offset of the uppler left=0A= corner in the master widget and the width and height.=0A= """=0A= args =3D ('grid', 'bbox', self._w)=0A= if column is not None and row is not None:=0A= args =3D args + (column, row)=0A= if col2 is not None and row2 is not None:=0A= args =3D args + (col2, row2)=0A= return self._getints(apply(self.tk.call, args)) or None=0A= =0A= bbox =3D grid_bbox=0A= def _grid_configure(self, command, index, cnf, kw):=0A= """Internal function."""=0A= if type(cnf) is StringType and not kw:=0A= if cnf[-1:] =3D=3D '_':=0A= cnf =3D cnf[:-1]=0A= if cnf[:1] !=3D '-':=0A= cnf =3D '-'+cnf=0A= options =3D (cnf,)=0A= else:=0A= options =3D self._options(cnf, kw)=0A= if not options:=0A= res =3D self.tk.call('grid',=0A= command, self._w, index)=0A= words =3D self.tk.splitlist(res)=0A= dict =3D {}=0A= for i in range(0, len(words), 2):=0A= key =3D words[i][1:]=0A= value =3D words[i+1]=0A= if not value:=0A= value =3D None=0A= elif '.' in value:=0A= value =3D getdouble(value)=0A= else:=0A= value =3D getint(value)=0A= dict[key] =3D value=0A= return dict=0A= res =3D self.tk.call(=0A= ('grid', command, self._w, index) =0A= + options)=0A= if len(options) =3D=3D 1:=0A= if not res: return None=0A= # In Tk 7.5, -width can be a float=0A= if '.' in res: return getdouble(res)=0A= return getint(res)=0A= def grid_columnconfigure(self, index, cnf=3D{}, **kw):=0A= """Configure column INDEX of a grid.=0A= =0A= Valid resources are minsize (minimum size of the column),=0A= weight (how much does additional space propagate to this column)=0A= and pad (how much space to let additionally)."""=0A= return self._grid_configure('columnconfigure', index, cnf, kw)=0A= columnconfigure =3D grid_columnconfigure=0A= def grid_propagate(self, flag=3D_noarg_):=0A= """Set or get the status for propagation of geometry information.=0A= =0A= A boolean argument specifies whether the geometry information=0A= of the slaves will determine the size of this widget. If no = argument=0A= is given, the current setting will be returned.=0A= """=0A= if flag is Misc._noarg_:=0A= return self._getboolean(self.tk.call(=0A= 'grid', 'propagate', self._w))=0A= else:=0A= self.tk.call('grid', 'propagate', self._w, flag)=0A= def grid_rowconfigure(self, index, cnf=3D{}, **kw):=0A= """Configure row INDEX of a grid.=0A= =0A= Valid resources are minsize (minimum size of the row),=0A= weight (how much does additional space propagate to this row)=0A= and pad (how much space to let additionally)."""=0A= return self._grid_configure('rowconfigure', index, cnf, kw)=0A= rowconfigure =3D grid_rowconfigure=0A= def grid_size(self):=0A= """Return a tuple of the number of column and rows in the grid."""=0A= return self._getints(=0A= self.tk.call('grid', 'size', self._w)) or None=0A= size =3D grid_size=0A= def grid_slaves(self, row=3DNone, column=3DNone):=0A= """Return a list of all slaves of this widget=0A= in its packing order."""=0A= args =3D ()=0A= if row is not None:=0A= args =3D args + ('-row', row)=0A= if column is not None:=0A= args =3D args + ('-column', column)=0A= return map(self._nametowidget,=0A= self.tk.splitlist(self.tk.call(=0A= ('grid', 'slaves', self._w) + args)))=0A= =0A= # Support for the "event" command, new in Tk 4.2.=0A= # By Case Roole.=0A= =0A= def event_add(self, virtual, *sequences):=0A= """Bind a virtual event VIRTUAL (of the form <>)=0A= to an event SEQUENCE such that the virtual event is triggered=0A= whenever SEQUENCE occurs."""=0A= args =3D ('event', 'add', virtual) + sequences=0A= self.tk.call(args)=0A= =0A= def event_delete(self, virtual, *sequences):=0A= """Unbind a virtual event VIRTUAL from SEQUENCE."""=0A= args =3D ('event', 'delete', virtual) + sequences=0A= self.tk.call(args)=0A= =0A= def event_generate(self, sequence, **kw):=0A= """Generate an event SEQUENCE. Additional=0A= keyword arguments specify parameter of the event=0A= (e.g. x, y, rootx, rooty)."""=0A= args =3D ('event', 'generate', self._w, sequence)=0A= for k, v in kw.items():=0A= args =3D args + ('-%s' % k, str(v))=0A= self.tk.call(args)=0A= =0A= def event_info(self, virtual=3DNone):=0A= """Return a list of all virtual events or the information=0A= about the SEQUENCE bound to the virtual event VIRTUAL."""=0A= return self.tk.splitlist(=0A= self.tk.call('event', 'info', virtual))=0A= =0A= # Image related commands=0A= =0A= def image_names(self):=0A= """Return a list of all existing image names."""=0A= return self.tk.call('image', 'names')=0A= =0A= def image_types(self):=0A= """Return a list of all available image types (e.g. phote = bitmap)."""=0A= return self.tk.call('image', 'types')=0A= =0A= =0A= class CallWrapper:=0A= """Internal class. Stores function to call when some user=0A= defined Tcl function is called e.g. after an event occured."""=0A= def __init__(self, func, subst, widget):=0A= """Store FUNC, SUBST and WIDGET as members."""=0A= self.func =3D func=0A= self.subst =3D subst=0A= self.widget =3D widget=0A= def __call__(self, *args):=0A= """Apply first function SUBST to arguments, than FUNC."""=0A= try:=0A= if self.subst:=0A= args =3D apply(self.subst, args)=0A= return apply(self.func, args)=0A= except SystemExit, msg:=0A= raise SystemExit, msg=0A= except:=0A= self.widget._report_exception()=0A= =0A= =0A= class Wm:=0A= """Provides functions for the communication with the window = manager."""=0A= def wm_aspect(self,=0A= minNumer=3DNone, minDenom=3DNone, =0A= maxNumer=3DNone, maxDenom=3DNone):=0A= """Instruct the window manager to set the aspect ratio = (width/height)=0A= of this widget to be between MINNUMER/MINDENOM and MAXNUMER/MAXDENOM. = Return a tuple=0A= of the actual values if no argument is given."""=0A= return self._getints(=0A= self.tk.call('wm', 'aspect', self._w, =0A= minNumer, minDenom, =0A= maxNumer, maxDenom))=0A= aspect =3D wm_aspect=0A= def wm_client(self, name=3DNone):=0A= """Store NAME in WM_CLIENT_MACHINE property of this widget. Return=0A= current value."""=0A= return self.tk.call('wm', 'client', self._w, name)=0A= client =3D wm_client=0A= def wm_colormapwindows(self, *wlist):=0A= """Store list of window names (WLIST) into WM_COLORMAPWINDOWS = property=0A= of this widget. This list contains windows whose colormaps differ = from their=0A= parents. Return current list of widgets if WLIST is empty."""=0A= if len(wlist) > 1:=0A= wlist =3D (wlist,) # Tk needs a list of windows here=0A= args =3D ('wm', 'colormapwindows', self._w) + wlist=0A= return map(self._nametowidget, self.tk.call(args))=0A= colormapwindows =3D wm_colormapwindows=0A= def wm_command(self, value=3DNone):=0A= """Store VALUE in WM_COMMAND property. It is the command=0A= which shall be used to invoke the application. Return current=0A= commmand if VALUE is None."""=0A= return self.tk.call('wm', 'command', self._w, value)=0A= command =3D wm_command=0A= def wm_deiconify(self):=0A= """Deiconify this widget. If it was never mapped it will not be = mapped.=0A= On Windows it will raise this widget and give it the focus."""=0A= return self.tk.call('wm', 'deiconify', self._w)=0A= deiconify =3D wm_deiconify=0A= def wm_focusmodel(self, model=3DNone):=0A= """Set focus model to MODEL. "active" means that this widget will = claim=0A= the focus itself, "passive" means that the window manager shall = give=0A= the focus. Return current focus model if MODEL is None."""=0A= return self.tk.call('wm', 'focusmodel', self._w, model)=0A= focusmodel =3D wm_focusmodel=0A= def wm_frame(self):=0A= """Return identifier for decorative frame of this widget if = present."""=0A= return self.tk.call('wm', 'frame', self._w)=0A= frame =3D wm_frame=0A= def wm_geometry(self, newGeometry=3DNone):=0A= """Set geometry to NEWGEOMETRY of the form =3Dwidthxheigth+x+y. = Return=0A= current value if None is given."""=0A= return self.tk.call('wm', 'geometry', self._w, newGeometry)=0A= geometry =3D wm_geometry=0A= def wm_grid(self,=0A= baseWidth=3DNone, baseHeight=3DNone, =0A= widthInc=3DNone, heightInc=3DNone):=0A= """Instruct the window manager that this widget shall only be=0A= resized on grid boundaries. WIDTHINC and HEIGHTINC are the width = and=0A= height of a grid unit in pixels. BASEWIDTH and BASEHEIGHT are the=0A= number of grid units requested in Tk_GeometryRequest."""=0A= return self._getints(self.tk.call(=0A= 'wm', 'grid', self._w,=0A= baseWidth, baseHeight, widthInc, heightInc))=0A= grid =3D wm_grid=0A= def wm_group(self, pathName=3DNone):=0A= """Set the group leader widgets for related widgets to PATHNAME. = Return=0A= the group leader of this widget if None is given."""=0A= return self.tk.call('wm', 'group', self._w, pathName)=0A= group =3D wm_group=0A= def wm_iconbitmap(self, bitmap=3DNone):=0A= """Set bitmap for the iconified widget to BITMAP. Return=0A= the bitmap if None is given."""=0A= return self.tk.call('wm', 'iconbitmap', self._w, bitmap)=0A= iconbitmap =3D wm_iconbitmap=0A= def wm_iconify(self):=0A= """Display widget as icon."""=0A= return self.tk.call('wm', 'iconify', self._w)=0A= iconify =3D wm_iconify=0A= def wm_iconmask(self, bitmap=3DNone):=0A= """Set mask for the icon bitmap of this widget. Return the=0A= mask if None is given."""=0A= return self.tk.call('wm', 'iconmask', self._w, bitmap)=0A= iconmask =3D wm_iconmask=0A= def wm_iconname(self, newName=3DNone):=0A= """Set the name of the icon for this widget. Return the name if=0A= None is given."""=0A= return self.tk.call('wm', 'iconname', self._w, newName)=0A= iconname =3D wm_iconname=0A= def wm_iconposition(self, x=3DNone, y=3DNone):=0A= """Set the position of the icon of this widget to X and Y. Return=0A= a tuple of the current values of X and X if None is given."""=0A= return self._getints(self.tk.call(=0A= 'wm', 'iconposition', self._w, x, y))=0A= iconposition =3D wm_iconposition=0A= def wm_iconwindow(self, pathName=3DNone):=0A= """Set widget PATHNAME to be displayed instead of icon. Return the = current=0A= value if None is given."""=0A= return self.tk.call('wm', 'iconwindow', self._w, pathName)=0A= iconwindow =3D wm_iconwindow=0A= def wm_maxsize(self, width=3DNone, height=3DNone):=0A= """Set max WIDTH and HEIGHT for this widget. If the window is = gridded=0A= the values are given in grid units. Return the current values if = None=0A= is given."""=0A= return self._getints(self.tk.call(=0A= 'wm', 'maxsize', self._w, width, height))=0A= maxsize =3D wm_maxsize=0A= def wm_minsize(self, width=3DNone, height=3DNone):=0A= """Set min WIDTH and HEIGHT for this widget. If the window is = gridded=0A= the values are given in grid units. Return the current values if = None=0A= is given."""=0A= return self._getints(self.tk.call(=0A= 'wm', 'minsize', self._w, width, height))=0A= minsize =3D wm_minsize=0A= def wm_overrideredirect(self, boolean=3DNone):=0A= """Instruct the window manager to ignore this widget=0A= if BOOLEAN is given with 1. Return the current value if None=0A= is given."""=0A= return self._getboolean(self.tk.call(=0A= 'wm', 'overrideredirect', self._w, boolean))=0A= overrideredirect =3D wm_overrideredirect=0A= def wm_positionfrom(self, who=3DNone):=0A= """Instruct the window manager that the position of this widget = shall=0A= be defined by the user if WHO is "user", and by its own policy if WHO = is=0A= "program"."""=0A= return self.tk.call('wm', 'positionfrom', self._w, who)=0A= positionfrom =3D wm_positionfrom=0A= def wm_protocol(self, name=3DNone, func=3DNone):=0A= """Bind function FUNC to command NAME for this widget.=0A= Return the function bound to NAME if None is given. NAME could be=0A= e.g. "WM_SAVE_YOURSELF" or "WM_DELETE_WINDOW"."""=0A= if callable(func):=0A= command =3D self._register(func)=0A= else:=0A= command =3D func=0A= return self.tk.call(=0A= 'wm', 'protocol', self._w, name, command)=0A= protocol =3D wm_protocol=0A= def wm_resizable(self, width=3DNone, height=3DNone):=0A= """Instruct the window manager whether this width can be resized=0A= in WIDTH or HEIGHT. Both values are boolean values."""=0A= return self.tk.call('wm', 'resizable', self._w, width, height)=0A= resizable =3D wm_resizable=0A= def wm_sizefrom(self, who=3DNone):=0A= """Instruct the window manager that the size of this widget shall=0A= be defined by the user if WHO is "user", and by its own policy if WHO = is=0A= "program"."""=0A= return self.tk.call('wm', 'sizefrom', self._w, who)=0A= sizefrom =3D wm_sizefrom=0A= def wm_state(self):=0A= """Return the state of this widget as one of normal,=0A= icon, iconic (see wm_iconwindow) and withdrawn."""=0A= return self.tk.call('wm', 'state', self._w)=0A= state =3D wm_state=0A= def wm_title(self, string=3DNone):=0A= """Set the title of this widget."""=0A= return self.tk.call('wm', 'title', self._w, string)=0A= title =3D wm_title=0A= def wm_transient(self, master=3DNone):=0A= """Instruct the window manager that this widget is transient=0A= with regard to widget MASTER."""=0A= return self.tk.call('wm', 'transient', self._w, master)=0A= transient =3D wm_transient=0A= def wm_withdraw(self):=0A= """Withdraw this widget from the screen such that it is unmapped=0A= and forgotten by the window manager. Re-draw it with = wm_deiconify."""=0A= return self.tk.call('wm', 'withdraw', self._w)=0A= withdraw =3D wm_withdraw=0A= =0A= =0A= class Tk(Misc, Wm):=0A= """Toplevel widget of Tk which represents mostly the main window=0A= of an appliation. It has an associated Tcl interpreter."""=0A= _w =3D '.'=0A= def __init__(self, screenName=3DNone, baseName=3DNone, = className=3D'Tk'):=0A= """Return a new Toplevel widget on screen SCREENNAME. A new Tcl = interpreter will=0A= be created. BASENAME will be used for the identification of the = profile file (see=0A= readprofile).=0A= It is constructed from sys.argv[0] without extensions if None is = given. CLASSNAME=0A= is the name of the widget class."""=0A= global _default_root=0A= self.master =3D None=0A= self.children =3D {}=0A= if baseName is None:=0A= import sys, os=0A= baseName =3D os.path.basename(sys.argv[0])=0A= baseName, ext =3D os.path.splitext(baseName)=0A= if ext not in ('.py', '.pyc', '.pyo'):=0A= baseName =3D baseName + ext=0A= self.tk =3D _tkinter.create(screenName, baseName, className)=0A= if _MacOS:=0A= # Disable event scanning except for Command-Period=0A= _MacOS.SchedParams(1, 0)=0A= # Work around nasty MacTk bug=0A= # XXX Is this one still needed?=0A= self.update()=0A= # Version sanity checks=0A= tk_version =3D self.tk.getvar('tk_version')=0A= if tk_version !=3D _tkinter.TK_VERSION:=0A= raise RuntimeError, \=0A= "tk.h version (%s) doesn't match libtk.a version (%s)" \=0A= % (_tkinter.TK_VERSION, tk_version)=0A= tcl_version =3D self.tk.getvar('tcl_version')=0A= if tcl_version !=3D _tkinter.TCL_VERSION:=0A= raise RuntimeError, \=0A= "tcl.h version (%s) doesn't match libtcl.a version (%s)" \=0A= % (_tkinter.TCL_VERSION, tcl_version)=0A= if TkVersion < 4.0:=0A= raise RuntimeError, \=0A= "Tk 4.0 or higher is required; found Tk %s" \=0A= % str(TkVersion)=0A= self.tk.createcommand('tkerror', _tkerror)=0A= self.tk.createcommand('exit', _exit)=0A= self.readprofile(baseName, className)=0A= if _support_default_root and not _default_root:=0A= _default_root =3D self=0A= self.protocol("WM_DELETE_WINDOW", self.destroy)=0A= def destroy(self):=0A= """Destroy this and all descendants widgets. This will=0A= end the application of this Tcl interpreter."""=0A= for c in self.children.values(): c.destroy()=0A= self.tk.call('destroy', self._w)=0A= Misc.destroy(self)=0A= global _default_root=0A= if _support_default_root and _default_root is self:=0A= _default_root =3D None=0A= def readprofile(self, baseName, className):=0A= """Internal function. It reads BASENAME.tcl and CLASSNAME.tcl into=0A= the Tcl Interpreter and calls execfile on BASENAME.py and = CLASSNAME.py if=0A= such a file exists in the home directory."""=0A= import os=0A= if os.environ.has_key('HOME'): home =3D os.environ['HOME']=0A= else: home =3D os.curdir=0A= class_tcl =3D os.path.join(home, '.%s.tcl' % className)=0A= class_py =3D os.path.join(home, '.%s.py' % className)=0A= base_tcl =3D os.path.join(home, '.%s.tcl' % baseName)=0A= base_py =3D os.path.join(home, '.%s.py' % baseName)=0A= dir =3D {'self': self}=0A= exec 'from Tkinter import *' in dir=0A= if os.path.isfile(class_tcl):=0A= print 'source', `class_tcl`=0A= self.tk.call('source', class_tcl)=0A= if os.path.isfile(class_py):=0A= print 'execfile', `class_py`=0A= execfile(class_py, dir)=0A= if os.path.isfile(base_tcl):=0A= print 'source', `base_tcl`=0A= self.tk.call('source', base_tcl)=0A= if os.path.isfile(base_py):=0A= print 'execfile', `base_py`=0A= execfile(base_py, dir)=0A= def report_callback_exception(self, exc, val, tb):=0A= """Internal function. It reports exception on sys.stderr."""=0A= import traceback, sys=0A= sys.stderr.write("Exception in Tkinter callback\n")=0A= sys.last_type =3D exc=0A= sys.last_value =3D val=0A= sys.last_traceback =3D tb=0A= traceback.print_exception(exc, val, tb)=0A= =0A= # Ideally, the classes Pack, Place and Grid disappear, the=0A= # pack/place/grid methods are defined on the Widget class, and=0A= # everybody uses w.pack_whatever(...) instead of Pack.whatever(w,=0A= # ...), with pack(), place() and grid() being short for=0A= # pack_configure(), place_configure() and grid_columnconfigure(), = and=0A= # forget() being short for pack_forget(). As a practical matter, = I'm=0A= # afraid that there is too much code out there that may be using the=0A= # Pack, Place or Grid class, so I leave them intact -- but only as=0A= # backwards compatibility features. Also note that those methods = that=0A= # take a master as argument (e.g. pack_propagate) have been moved to=0A= # the Misc class (which now incorporates all methods common between=0A= # toplevel and interior widgets). Again, for compatibility, these = are=0A= # copied into the Pack, Place or Grid class.=0A= =0A= class Pack:=0A= """Geometry manager Pack.=0A= =0A= Base class to use the methods pack_* in every widget."""=0A= def pack_configure(self, cnf=3D{}, **kw):=0A= """Pack a widget in the parent widget. Use as options:=0A= after=3Dwidget - pack it after you have packed widget=0A= anchor=3DNSEW (or subset) - position widget according to=0A= given direction=0A= before=3Dwidget - pack it before you will pack = widget=0A= expand=3D1 or 0 - expand widget if parent size grows=0A= fill=3DNONE or X or Y or BOTH - fill widget if widget grows=0A= in=3Dmaster - use master to contain this widget=0A= ipadx=3Damount - add internal padding in x direction=0A= ipady=3Damount - add internal padding in y direction=0A= padx=3Damount - add padding in x direction=0A= pady=3Damount - add padding in y direction=0A= side=3DTOP or BOTTOM or LEFT or RIGHT - where to add this widget.=0A= """=0A= self.tk.call(=0A= ('pack', 'configure', self._w) =0A= + self._options(cnf, kw))=0A= pack =3D configure =3D config =3D pack_configure=0A= def pack_forget(self):=0A= """Unmap this widget and do not use it for the packing order."""=0A= self.tk.call('pack', 'forget', self._w)=0A= forget =3D pack_forget=0A= def pack_info(self):=0A= """Return information about the packing options=0A= for this widget."""=0A= words =3D self.tk.splitlist(=0A= self.tk.call('pack', 'info', self._w))=0A= dict =3D {}=0A= for i in range(0, len(words), 2):=0A= key =3D words[i][1:]=0A= value =3D words[i+1]=0A= if value[:1] =3D=3D '.':=0A= value =3D self._nametowidget(value)=0A= dict[key] =3D value=0A= return dict=0A= info =3D pack_info=0A= propagate =3D pack_propagate =3D Misc.pack_propagate=0A= slaves =3D pack_slaves =3D Misc.pack_slaves=0A= =0A= class Place:=0A= """Geometry manager Place.=0A= =0A= Base class to use the methods place_* in every widget."""=0A= def place_configure(self, cnf=3D{}, **kw):=0A= """Place a widget in the parent widget. Use as options:=0A= in=3Dmaster - master relative to which the widget is placed.=0A= x=3Damount - locate anchor of this widget at position x of master=0A= y=3Damount - locate anchor of this widget at position y of master=0A= relx=3Damount - locate anchor of this widget between 0.0 and 1.0=0A= relative to width of master (1.0 is right edge)=0A= rely=3Damount - locate anchor of this widget between 0.0 and = 1.0=0A= relative to height of master (1.0 is bottom edge)=0A= anchor=3DNSEW (or subset) - position anchor according to given = direction=0A= width=3Damount - width of this widget in pixel=0A= height=3Damount - height of this widget in pixel=0A= relwidth=3Damount - width of this widget between 0.0 and 1.0=0A= relative to width of master (1.0 is the same = width=0A= as the master)=0A= relheight=3Damount - height of this widget between 0.0 and = 1.0=0A= relative to heigth of master (1.0 is the same=0A= height as the master)=0A= bordermode=3D"inside" or "outside" - whether to take border = width of master widget=0A= into account=0A= """=0A= for k in ['in_']:=0A= if kw.has_key(k):=0A= kw[k[:-1]] =3D kw[k]=0A= del kw[k]=0A= self.tk.call(=0A= ('place', 'configure', self._w) =0A= + self._options(cnf, kw))=0A= place =3D configure =3D config =3D place_configure=0A= def place_forget(self):=0A= """Unmap this widget."""=0A= self.tk.call('place', 'forget', self._w)=0A= forget =3D place_forget=0A= def place_info(self):=0A= """Return information about the placing options=0A= for this widget."""=0A= words =3D self.tk.splitlist(=0A= self.tk.call('place', 'info', self._w))=0A= dict =3D {}=0A= for i in range(0, len(words), 2):=0A= key =3D words[i][1:]=0A= value =3D words[i+1]=0A= if value[:1] =3D=3D '.':=0A= value =3D self._nametowidget(value)=0A= dict[key] =3D value=0A= return dict=0A= info =3D place_info=0A= slaves =3D place_slaves =3D Misc.place_slaves=0A= =0A= class Grid:=0A= """Geometry manager Grid.=0A= =0A= Base class to use the methods grid_* in every widget."""=0A= # Thanks to Masazumi Yoshikawa (yosikawa@isi.edu)=0A= def grid_configure(self, cnf=3D{}, **kw):=0A= """Position a widget in the parent widget in a grid. Use as = options:=0A= column=3Dnumber - use cell identified with given column (starting = with 0)=0A= columnspan=3Dnumber - this widget will span several columns=0A= in=3Dmaster - use master to contain this widget=0A= ipadx=3Damount - add internal padding in x direction=0A= ipady=3Damount - add internal padding in y direction=0A= padx=3Damount - add padding in x direction=0A= pady=3Damount - add padding in y direction=0A= row=3Dnumber - use cell identified with given row (starting with = 0)=0A= rowspan=3Dnumber - this widget will span several rows=0A= sticky=3DNSEW - if cell is larger on which sides will this=0A= widget stick to the cell boundary=0A= """=0A= self.tk.call(=0A= ('grid', 'configure', self._w) =0A= + self._options(cnf, kw))=0A= grid =3D configure =3D config =3D grid_configure=0A= bbox =3D grid_bbox =3D Misc.grid_bbox=0A= columnconfigure =3D grid_columnconfigure =3D = Misc.grid_columnconfigure=0A= def grid_forget(self):=0A= """Unmap this widget."""=0A= self.tk.call('grid', 'forget', self._w)=0A= forget =3D grid_forget=0A= def grid_remove(self):=0A= """Unmap this widget but remember the grid options."""=0A= self.tk.call('grid', 'remove', self._w)=0A= def grid_info(self):=0A= """Return information about the options=0A= for positioning this widget in a grid."""=0A= words =3D self.tk.splitlist(=0A= self.tk.call('grid', 'info', self._w))=0A= dict =3D {}=0A= for i in range(0, len(words), 2):=0A= key =3D words[i][1:]=0A= value =3D words[i+1]=0A= if value[:1] =3D=3D '.':=0A= value =3D self._nametowidget(value)=0A= dict[key] =3D value=0A= return dict=0A= info =3D grid_info=0A= def grid_location(self, x, y):=0A= """Return a tuple of column and row which identify the cell=0A= at which the pixel at position X and Y inside the master=0A= widget is located."""=0A= return self._getints(=0A= self.tk.call(=0A= 'grid', 'location', self._w, x, y)) or None=0A= location =3D grid_location=0A= propagate =3D grid_propagate =3D Misc.grid_propagate=0A= rowconfigure =3D grid_rowconfigure =3D Misc.grid_rowconfigure=0A= size =3D grid_size =3D Misc.grid_size=0A= slaves =3D grid_slaves =3D Misc.grid_slaves=0A= =0A= class BaseWidget(Misc):=0A= """Internal class."""=0A= def _setup(self, master, cnf):=0A= """Internal function. Sets up information about children."""=0A= if _support_default_root:=0A= global _default_root=0A= if not master:=0A= if not _default_root:=0A= _default_root =3D Tk()=0A= master =3D _default_root=0A= self.master =3D master=0A= self.tk =3D master.tk=0A= name =3D None=0A= if cnf.has_key('name'):=0A= name =3D cnf['name']=0A= del cnf['name']=0A= if not name:=0A= name =3D `id(self)`=0A= self._name =3D name=0A= if master._w=3D=3D'.':=0A= self._w =3D '.' + name=0A= else:=0A= self._w =3D master._w + '.' + name=0A= self.children =3D {}=0A= if self.master.children.has_key(self._name):=0A= self.master.children[self._name].destroy()=0A= self.master.children[self._name] =3D self=0A= def __init__(self, master, widgetName, cnf=3D{}, kw=3D{}, = extra=3D()):=0A= """Construct a widget with the parent widget MASTER, a name = WIDGETNAME=0A= and appropriate options."""=0A= if kw:=0A= cnf =3D _cnfmerge((cnf, kw))=0A= self.widgetName =3D widgetName=0A= BaseWidget._setup(self, master, cnf)=0A= classes =3D []=0A= for k in cnf.keys():=0A= if type(k) is ClassType:=0A= classes.append((k, cnf[k]))=0A= del cnf[k]=0A= self.tk.call(=0A= (widgetName, self._w) + extra + self._options(cnf))=0A= for k, v in classes:=0A= k.configure(self, v)=0A= def destroy(self):=0A= """Destroy this and all descendants widgets."""=0A= for c in self.children.values(): c.destroy()=0A= if self.master.children.has_key(self._name):=0A= del self.master.children[self._name]=0A= self.tk.call('destroy', self._w)=0A= Misc.destroy(self)=0A= def _do(self, name, args=3D()):=0A= # XXX Obsolete -- better use self.tk.call directly!=0A= return self.tk.call((self._w, name) + args)=0A= =0A= class Widget(BaseWidget, Pack, Place, Grid):=0A= """Internal class.=0A= =0A= Base class for a widget which can be positioned with the geometry = managers=0A= Pack, Place or Grid."""=0A= pass=0A= =0A= class Toplevel(BaseWidget, Wm):=0A= """Toplevel widget, e.g. for dialogs."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a toplevel widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, class,=0A= colormap, container, cursor, height, highlightbackground,=0A= highlightcolor, highlightthickness, menu, relief, screen, = takefocus,=0A= use, visual, width."""=0A= if kw:=0A= cnf =3D _cnfmerge((cnf, kw))=0A= extra =3D ()=0A= for wmkey in ['screen', 'class_', 'class', 'visual',=0A= 'colormap']:=0A= if cnf.has_key(wmkey):=0A= val =3D cnf[wmkey]=0A= # TBD: a hack needed because some keys=0A= # are not valid as keyword arguments=0A= if wmkey[-1] =3D=3D '_': opt =3D '-'+wmkey[:-1]=0A= else: opt =3D '-'+wmkey=0A= extra =3D extra + (opt, val)=0A= del cnf[wmkey]=0A= BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)=0A= root =3D self._root()=0A= self.iconname(root.iconname())=0A= self.title(root.title())=0A= self.protocol("WM_DELETE_WINDOW", self.destroy)=0A= =0A= class Button(Widget):=0A= """Button widget."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a button widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, activeforeground, anchor,=0A= background, bd, bg, bitmap, borderwidth, command, cursor, default,=0A= disabledforeground, fg, font, foreground, height,=0A= highlightbackground, highlightcolor, highlightthickness, image,=0A= justify, padx, pady, relief, state, takefocus, text, textvariable,=0A= underline, width, wraplength."""=0A= Widget.__init__(self, master, 'button', cnf, kw)=0A= def tkButtonEnter(self, *dummy):=0A= self.tk.call('tkButtonEnter', self._w)=0A= def tkButtonLeave(self, *dummy):=0A= self.tk.call('tkButtonLeave', self._w)=0A= def tkButtonDown(self, *dummy):=0A= self.tk.call('tkButtonDown', self._w)=0A= def tkButtonUp(self, *dummy):=0A= self.tk.call('tkButtonUp', self._w)=0A= def tkButtonInvoke(self, *dummy):=0A= self.tk.call('tkButtonInvoke', self._w)=0A= def flash(self):=0A= self.tk.call(self._w, 'flash')=0A= def invoke(self):=0A= return self.tk.call(self._w, 'invoke')=0A= =0A= # Indices:=0A= # XXX I don't like these -- take them away=0A= def AtEnd():=0A= return 'end'=0A= def AtInsert(*args):=0A= s =3D 'insert'=0A= for a in args:=0A= if a: s =3D s + (' ' + a)=0A= return s=0A= def AtSelFirst():=0A= return 'sel.first'=0A= def AtSelLast():=0A= return 'sel.last'=0A= def At(x, y=3DNone):=0A= if y is None:=0A= return '@' + `x` =0A= else:=0A= return '@' + `x` + ',' + `y`=0A= =0A= class Canvas(Widget):=0A= """Canvas widget to display graphical elements like lines or = text."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a canvas widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, = closeenough,=0A= confine, cursor, height, highlightbackground, highlightcolor,=0A= highlightthickness, insertbackground, insertborderwidth,=0A= insertofftime, insertontime, insertwidth, offset, relief,=0A= scrollregion, selectbackground, selectborderwidth, = selectforeground,=0A= state, takefocus, width, xscrollcommand, xscrollincrement,=0A= yscrollcommand, yscrollincrement."""=0A= Widget.__init__(self, master, 'canvas', cnf, kw)=0A= def addtag(self, *args):=0A= """Internal function."""=0A= self.tk.call((self._w, 'addtag') + args)=0A= def addtag_above(self, newtag, tagOrId):=0A= """Add tag NEWTAG to all items above TAGORID."""=0A= self.addtag(newtag, 'above', tagOrId)=0A= def addtag_all(self, newtag):=0A= """Add tag NEWTAG to all items."""=0A= self.addtag(newtag, 'all')=0A= def addtag_below(self, newtag, tagOrId):=0A= """Add tag NEWTAG to all items below TAGORID."""=0A= self.addtag(newtag, 'below', tagOrId)=0A= def addtag_closest(self, newtag, x, y, halo=3DNone, start=3DNone):=0A= """Add tag NEWTAG to item which is closest to pixel at X, Y.=0A= If several match take the top-most.=0A= All items closer than HALO are considered overlapping (all are=0A= closests). If START is specified the next below this tag is = taken."""=0A= self.addtag(newtag, 'closest', x, y, halo, start)=0A= def addtag_enclosed(self, newtag, x1, y1, x2, y2):=0A= """Add tag NEWTAG to all items in the rectangle defined=0A= by X1,Y1,X2,Y2."""=0A= self.addtag(newtag, 'enclosed', x1, y1, x2, y2)=0A= def addtag_overlapping(self, newtag, x1, y1, x2, y2):=0A= """Add tag NEWTAG to all items which overlap the rectangle=0A= defined by X1,Y1,X2,Y2."""=0A= self.addtag(newtag, 'overlapping', x1, y1, x2, y2)=0A= def addtag_withtag(self, newtag, tagOrId):=0A= """Add tag NEWTAG to all items with TAGORID."""=0A= self.addtag(newtag, 'withtag', tagOrId)=0A= def bbox(self, *args):=0A= """Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle=0A= which encloses all items with tags specified as arguments."""=0A= return self._getints(=0A= self.tk.call((self._w, 'bbox') + args)) or None=0A= def tag_unbind(self, tagOrId, sequence, funcid=3DNone):=0A= """Unbind for all items with TAGORID for event SEQUENCE the=0A= function identified with FUNCID."""=0A= self.tk.call(self._w, 'bind', tagOrId, sequence, '')=0A= if funcid:=0A= self.deletecommand(funcid)=0A= def tag_bind(self, tagOrId, sequence=3DNone, func=3DNone, = add=3DNone):=0A= """Bind to all items with TAGORID at event SEQUENCE a call to = function FUNC.=0A= =0A= An additional boolean parameter ADD specifies whether FUNC will be=0A= called additionally to the other bound function or whether it will=0A= replace the previous function. See bind for the return value."""=0A= return self._bind((self._w, 'bind', tagOrId),=0A= sequence, func, add)=0A= def canvasx(self, screenx, gridspacing=3DNone):=0A= """Return the canvas x coordinate of pixel position SCREENX = rounded=0A= to nearest muliple of GRIDSPACING units."""=0A= return getdouble(self.tk.call(=0A= self._w, 'canvasx', screenx, gridspacing))=0A= def canvasy(self, screeny, gridspacing=3DNone):=0A= """Return the canvas y coordinate of pixel position SCREENY = rounded=0A= to nearest muliple of GRIDSPACING units."""=0A= return getdouble(self.tk.call(=0A= self._w, 'canvasy', screeny, gridspacing))=0A= def coords(self, *args):=0A= """Return a list of coordinates for the item given in ARGS."""=0A= # XXX Should use _flatten on args=0A= return map(getdouble,=0A= self.tk.splitlist(=0A= self.tk.call((self._w, 'coords') + args)))=0A= def _create(self, itemType, args, kw): # Args: (val, val, ..., = cnf=3D{})=0A= """Internal function."""=0A= args =3D _flatten(args)=0A= cnf =3D args[-1]=0A= if type(cnf) in (DictionaryType, TupleType):=0A= args =3D args[:-1]=0A= else:=0A= cnf =3D {}=0A= return getint(apply(=0A= self.tk.call,=0A= (self._w, 'create', itemType) =0A= + args + self._options(cnf, kw)))=0A= def create_arc(self, *args, **kw):=0A= """Create arc shaped region with coordinates x1,y1,x2,y2."""=0A= return self._create('arc', args, kw)=0A= def create_bitmap(self, *args, **kw):=0A= """Create bitmap with coordinates x1,y1."""=0A= return self._create('bitmap', args, kw)=0A= def create_image(self, *args, **kw):=0A= """Create image item with coordinates x1,y1."""=0A= return self._create('image', args, kw)=0A= def create_line(self, *args, **kw):=0A= """Create line with coordinates x1,y1,...,xn,yn."""=0A= return self._create('line', args, kw)=0A= def create_oval(self, *args, **kw):=0A= """Create oval with coordinates x1,y1,x2,y2."""=0A= return self._create('oval', args, kw)=0A= def create_polygon(self, *args, **kw):=0A= """Create polygon with coordinates x1,y1,...,xn,yn."""=0A= return self._create('polygon', args, kw)=0A= def create_rectangle(self, *args, **kw):=0A= """Create rectangle with coordinates x1,y1,x2,y2."""=0A= return self._create('rectangle', args, kw)=0A= def create_text(self, *args, **kw):=0A= """Create text with coordinates x1,y1."""=0A= return self._create('text', args, kw)=0A= def create_window(self, *args, **kw):=0A= """Create window with coordinates x1,y1,x2,y2."""=0A= return self._create('window', args, kw)=0A= def dchars(self, *args):=0A= """Delete characters of text items identified by tag or id in ARGS = (possibly=0A= several times) from FIRST to LAST character (including)."""=0A= self.tk.call((self._w, 'dchars') + args)=0A= def delete(self, *args):=0A= """Delete items identified by all tag or ids contained in ARGS."""=0A= self.tk.call((self._w, 'delete') + args)=0A= def dtag(self, *args):=0A= """Delete tag or id given as last arguments in ARGS from items=0A= identified by first argument in ARGS."""=0A= self.tk.call((self._w, 'dtag') + args)=0A= def find(self, *args):=0A= """Internal function."""=0A= return self._getints(=0A= self.tk.call((self._w, 'find') + args)) or ()=0A= def find_above(self, tagOrId):=0A= """Return items above TAGORID."""=0A= return self.find('above', tagOrId)=0A= def find_all(self):=0A= """Return all items."""=0A= return self.find('all')=0A= def find_below(self, tagOrId):=0A= """Return all items below TAGORID."""=0A= return self.find('below', tagOrId)=0A= def find_closest(self, x, y, halo=3DNone, start=3DNone):=0A= """Return item which is closest to pixel at X, Y.=0A= If several match take the top-most.=0A= All items closer than HALO are considered overlapping (all are=0A= closests). If START is specified the next below this tag is = taken."""=0A= return self.find('closest', x, y, halo, start)=0A= def find_enclosed(self, x1, y1, x2, y2):=0A= """Return all items in rectangle defined=0A= by X1,Y1,X2,Y2."""=0A= return self.find('enclosed', x1, y1, x2, y2)=0A= def find_overlapping(self, x1, y1, x2, y2):=0A= """Return all items which overlap the rectangle=0A= defined by X1,Y1,X2,Y2."""=0A= return self.find('overlapping', x1, y1, x2, y2)=0A= def find_withtag(self, tagOrId):=0A= """Return all items with TAGORID."""=0A= return self.find('withtag', tagOrId)=0A= def focus(self, *args):=0A= """Set focus to the first item specified in ARGS."""=0A= return self.tk.call((self._w, 'focus') + args)=0A= def gettags(self, *args):=0A= """Return tags associated with the first item specified in = ARGS."""=0A= return self.tk.splitlist(=0A= self.tk.call((self._w, 'gettags') + args))=0A= def icursor(self, *args):=0A= """Set cursor at position POS in the item identified by TAGORID.=0A= In ARGS TAGORID must be first."""=0A= self.tk.call((self._w, 'icursor') + args)=0A= def index(self, *args):=0A= """Return position of cursor as integer in item specified in = ARGS."""=0A= return getint(self.tk.call((self._w, 'index') + args))=0A= def insert(self, *args):=0A= """Insert TEXT in item TAGORID at position POS. ARGS must=0A= be TAGORID POS TEXT."""=0A= self.tk.call((self._w, 'insert') + args)=0A= def itemcget(self, tagOrId, option):=0A= """Return the resource value for an OPTION for item TAGORID."""=0A= return self.tk.call(=0A= (self._w, 'itemcget') + (tagOrId, '-'+option))=0A= def itemconfigure(self, tagOrId, cnf=3DNone, **kw):=0A= """Configure resources of an item TAGORID.=0A= =0A= The values for resources are specified as keyword=0A= arguments. To get an overview about=0A= the allowed keyword arguments call the method without arguments.=0A= """=0A= if cnf is None and not kw:=0A= cnf =3D {}=0A= for x in self.tk.split(=0A= self.tk.call(self._w,=0A= 'itemconfigure', tagOrId)):=0A= cnf[x[0][1:]] =3D (x[0][1:],) + x[1:]=0A= return cnf=0A= if type(cnf) =3D=3D StringType and not kw:=0A= x =3D self.tk.split(self.tk.call(=0A= self._w, 'itemconfigure', tagOrId, '-'+cnf))=0A= return (x[0][1:],) + x[1:]=0A= self.tk.call((self._w, 'itemconfigure', tagOrId) +=0A= self._options(cnf, kw))=0A= itemconfig =3D itemconfigure=0A= # lower, tkraise/lift hide Misc.lower, Misc.tkraise/lift,=0A= # so the preferred name for them is tag_lower, tag_raise=0A= # (similar to tag_bind, and similar to the Text widget);=0A= # unfortunately can't delete the old ones yet (maybe in 1.6)=0A= def tag_lower(self, *args):=0A= """Lower an item TAGORID given in ARGS=0A= (optional below another item)."""=0A= self.tk.call((self._w, 'lower') + args)=0A= lower =3D tag_lower=0A= def move(self, *args):=0A= """Move an item TAGORID given in ARGS."""=0A= self.tk.call((self._w, 'move') + args)=0A= def postscript(self, cnf=3D{}, **kw):=0A= """Print the contents of the canvas to a postscript=0A= file. Valid options: colormap, colormode, file, fontmap,=0A= height, pageanchor, pageheight, pagewidth, pagex, pagey,=0A= rotate, witdh, x, y."""=0A= return self.tk.call((self._w, 'postscript') +=0A= self._options(cnf, kw))=0A= def tag_raise(self, *args):=0A= """Raise an item TAGORID given in ARGS=0A= (optional above another item)."""=0A= self.tk.call((self._w, 'raise') + args)=0A= lift =3D tkraise =3D tag_raise=0A= def scale(self, *args):=0A= """Scale item TAGORID with XORIGIN, YORIGIN, XSCALE, YSCALE."""=0A= self.tk.call((self._w, 'scale') + args)=0A= def scan_mark(self, x, y):=0A= """Remember the current X, Y coordinates."""=0A= self.tk.call(self._w, 'scan', 'mark', x, y)=0A= def scan_dragto(self, x, y):=0A= """Adjust the view of the canvas to 10 times the=0A= difference between X and Y and the coordinates given in=0A= scan_mark."""=0A= self.tk.call(self._w, 'scan', 'dragto', x, y)=0A= def select_adjust(self, tagOrId, index):=0A= """Adjust the end of the selection near the cursor of an item TAGORID = to index."""=0A= self.tk.call(self._w, 'select', 'adjust', tagOrId, index)=0A= def select_clear(self):=0A= """Clear the selection if it is in this widget."""=0A= self.tk.call(self._w, 'select', 'clear')=0A= def select_from(self, tagOrId, index):=0A= """Set the fixed end of a selection in item TAGORID to INDEX."""=0A= self.tk.call(self._w, 'select', 'from', tagOrId, index)=0A= def select_item(self):=0A= """Return the item which has the selection."""=0A= self.tk.call(self._w, 'select', 'item')=0A= def select_to(self, tagOrId, index):=0A= """Set the variable end of a selection in item TAGORID to = INDEX."""=0A= self.tk.call(self._w, 'select', 'to', tagOrId, index)=0A= def type(self, tagOrId):=0A= """Return the type of the item TAGORID."""=0A= return self.tk.call(self._w, 'type', tagOrId) or None=0A= def xview(self, *args):=0A= """Query and change horizontal position of the view."""=0A= if not args:=0A= return self._getdoubles(self.tk.call(self._w, 'xview'))=0A= self.tk.call((self._w, 'xview') + args)=0A= def xview_moveto(self, fraction):=0A= """Adjusts the view in the window so that FRACTION of the=0A= total width of the canvas is off-screen to the left."""=0A= self.tk.call(self._w, 'xview', 'moveto', fraction)=0A= def xview_scroll(self, number, what):=0A= """Shift the x-view according to NUMBER which is measured in "units" = or "pages" (WHAT)."""=0A= self.tk.call(self._w, 'xview', 'scroll', number, what)=0A= def yview(self, *args):=0A= """Query and change vertical position of the view."""=0A= if not args:=0A= return self._getdoubles(self.tk.call(self._w, 'yview'))=0A= self.tk.call((self._w, 'yview') + args)=0A= def yview_moveto(self, fraction):=0A= """Adjusts the view in the window so that FRACTION of the=0A= total height of the canvas is off-screen to the top."""=0A= self.tk.call(self._w, 'yview', 'moveto', fraction)=0A= def yview_scroll(self, number, what):=0A= """Shift the y-view according to NUMBER which is measured in "units" = or "pages" (WHAT)."""=0A= self.tk.call(self._w, 'yview', 'scroll', number, what)=0A= =0A= class Checkbutton(Widget):=0A= """Checkbutton widget which is either in on- or off-state."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a checkbutton widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, activeforeground, anchor,=0A= background, bd, bg, bitmap, borderwidth, command, cursor,=0A= disabledforeground, fg, font, foreground, height,=0A= highlightbackground, highlightcolor, highlightthickness, image,=0A= indicatoron, justify, offvalue, onvalue, padx, pady, relief,=0A= selectcolor, selectimage, state, takefocus, text, textvariable,=0A= underline, variable, width, wraplength.""" =0A= Widget.__init__(self, master, 'checkbutton', cnf, kw)=0A= def deselect(self):=0A= """Put the button in off-state."""=0A= self.tk.call(self._w, 'deselect')=0A= def flash(self):=0A= """Flash the button."""=0A= self.tk.call(self._w, 'flash')=0A= def invoke(self):=0A= """Toggle the button and invoke a command if given as resource."""=0A= return self.tk.call(self._w, 'invoke')=0A= def select(self):=0A= """Put the button in on-state."""=0A= self.tk.call(self._w, 'select')=0A= def toggle(self):=0A= """Toggle the button."""=0A= self.tk.call(self._w, 'toggle')=0A= =0A= class Entry(Widget):=0A= """Entry widget which allows to display simple text."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct an entry widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, cursor,=0A= exportselection, fg, font, foreground, highlightbackground,=0A= highlightcolor, highlightthickness, insertbackground,=0A= insertborderwidth, insertofftime, insertontime, insertwidth,=0A= invalidcommand, invcmd, justify, relief, selectbackground,=0A= selectborderwidth, selectforeground, show, state, takefocus,=0A= textvariable, validate, validatecommand, vcmd, width,=0A= xscrollcommand."""=0A= Widget.__init__(self, master, 'entry', cnf, kw)=0A= def delete(self, first, last=3DNone):=0A= """Delete text from FIRST to LAST (not included)."""=0A= self.tk.call(self._w, 'delete', first, last)=0A= def get(self):=0A= """Return the text."""=0A= return self.tk.call(self._w, 'get')=0A= def icursor(self, index):=0A= """Insert cursor at INDEX."""=0A= self.tk.call(self._w, 'icursor', index)=0A= def index(self, index):=0A= """Return position of cursor."""=0A= return getint(self.tk.call(=0A= self._w, 'index', index))=0A= def insert(self, index, string):=0A= """Insert STRING at INDEX."""=0A= self.tk.call(self._w, 'insert', index, string)=0A= def scan_mark(self, x):=0A= """Remember the current X, Y coordinates."""=0A= self.tk.call(self._w, 'scan', 'mark', x)=0A= def scan_dragto(self, x):=0A= """Adjust the view of the canvas to 10 times the=0A= difference between X and Y and the coordinates given in=0A= scan_mark."""=0A= self.tk.call(self._w, 'scan', 'dragto', x)=0A= def selection_adjust(self, index):=0A= """Adjust the end of the selection near the cursor to INDEX."""=0A= self.tk.call(self._w, 'selection', 'adjust', index)=0A= select_adjust =3D selection_adjust=0A= def selection_clear(self):=0A= """Clear the selection if it is in this widget."""=0A= self.tk.call(self._w, 'selection', 'clear')=0A= select_clear =3D selection_clear=0A= def selection_from(self, index):=0A= """Set the fixed end of a selection to INDEX."""=0A= self.tk.call(self._w, 'selection', 'from', index)=0A= select_from =3D selection_from=0A= def selection_present(self):=0A= """Return whether the widget has the selection."""=0A= return self.tk.getboolean(=0A= self.tk.call(self._w, 'selection', 'present'))=0A= select_present =3D selection_present=0A= def selection_range(self, start, end):=0A= """Set the selection from START to END (not included)."""=0A= self.tk.call(self._w, 'selection', 'range', start, end)=0A= select_range =3D selection_range=0A= def selection_to(self, index):=0A= """Set the variable end of a selection to INDEX."""=0A= self.tk.call(self._w, 'selection', 'to', index)=0A= select_to =3D selection_to=0A= def xview(self, index):=0A= """Query and change horizontal position of the view."""=0A= self.tk.call(self._w, 'xview', index)=0A= def xview_moveto(self, fraction):=0A= """Adjust the view in the window so that FRACTION of the=0A= total width of the entry is off-screen to the left."""=0A= self.tk.call(self._w, 'xview', 'moveto', fraction)=0A= def xview_scroll(self, number, what):=0A= """Shift the x-view according to NUMBER which is measured in "units" = or "pages" (WHAT)."""=0A= self.tk.call(self._w, 'xview', 'scroll', number, what)=0A= =0A= class Frame(Widget):=0A= """Frame widget which may contain other widgets and can have a 3D = border."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a frame widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, class,=0A= colormap, container, cursor, height, highlightbackground,=0A= highlightcolor, highlightthickness, relief, takefocus, visual, = width.""" =0A= cnf =3D _cnfmerge((cnf, kw))=0A= extra =3D ()=0A= if cnf.has_key('class_'):=0A= extra =3D ('-class', cnf['class_'])=0A= del cnf['class_']=0A= elif cnf.has_key('class'):=0A= extra =3D ('-class', cnf['class'])=0A= del cnf['class']=0A= Widget.__init__(self, master, 'frame', cnf, {}, extra)=0A= =0A= class Label(Widget):=0A= """Label widget which can display text and bitmaps."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a label widget with the parent MASTER.=0A= =0A= Valid resource names: anchor, background, bd, bg, bitmap,=0A= borderwidth, cursor, fg, font, foreground, height,=0A= highlightbackground, highlightcolor, highlightthickness, image,=0A= justify, padx, pady, relief, takefocus, text, textvariable,=0A= underline, width, wraplength.""" =0A= Widget.__init__(self, master, 'label', cnf, kw)=0A= =0A= class Listbox(Widget):=0A= """Listbox widget which can display a list of strings."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a listbox widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, cursor,=0A= exportselection, fg, font, foreground, height, = highlightbackground,=0A= highlightcolor, highlightthickness, relief, selectbackground,=0A= selectborderwidth, selectforeground, selectmode, setgrid, = takefocus,=0A= width, xscrollcommand, yscrollcommand, listvariable."""=0A= Widget.__init__(self, master, 'listbox', cnf, kw)=0A= def activate(self, index):=0A= """Activate item identified by INDEX."""=0A= self.tk.call(self._w, 'activate', index)=0A= def bbox(self, *args):=0A= """Return a tuple of X1,Y1,X2,Y2 coordinates for a rectangle=0A= which encloses the item identified by index in ARGS."""=0A= return self._getints(=0A= self.tk.call((self._w, 'bbox') + args)) or None=0A= def curselection(self):=0A= """Return list of indices of currently selected item."""=0A= # XXX Ought to apply self._getints()...=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'curselection'))=0A= def delete(self, first, last=3DNone):=0A= """Delete items from FIRST to LAST (not included)."""=0A= self.tk.call(self._w, 'delete', first, last)=0A= def get(self, first, last=3DNone):=0A= """Get list of items from FIRST to LAST (not included)."""=0A= if last:=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'get', first, last))=0A= else:=0A= return self.tk.call(self._w, 'get', first)=0A= def index(self, index):=0A= """Return index of item identified with INDEX."""=0A= i =3D self.tk.call(self._w, 'index', index)=0A= if i =3D=3D 'none': return None=0A= return getint(i)=0A= def insert(self, index, *elements):=0A= """Insert ELEMENTS at INDEX."""=0A= self.tk.call((self._w, 'insert', index) + elements)=0A= def nearest(self, y):=0A= """Get index of item which is nearest to y coordinate Y."""=0A= return getint(self.tk.call(=0A= self._w, 'nearest', y))=0A= def scan_mark(self, x, y):=0A= """Remember the current X, Y coordinates."""=0A= self.tk.call(self._w, 'scan', 'mark', x, y)=0A= def scan_dragto(self, x, y):=0A= """Adjust the view of the listbox to 10 times the=0A= difference between X and Y and the coordinates given in=0A= scan_mark."""=0A= self.tk.call(self._w, 'scan', 'dragto', x, y)=0A= def see(self, index):=0A= """Scroll such that INDEX is visible."""=0A= self.tk.call(self._w, 'see', index)=0A= def selection_anchor(self, index):=0A= """Set the fixed end oft the selection to INDEX."""=0A= self.tk.call(self._w, 'selection', 'anchor', index)=0A= select_anchor =3D selection_anchor=0A= def selection_clear(self, first, last=3DNone):=0A= """Clear the selection from FIRST to LAST (not included)."""=0A= self.tk.call(self._w,=0A= 'selection', 'clear', first, last)=0A= select_clear =3D selection_clear=0A= def selection_includes(self, index):=0A= """Return 1 if INDEX is part of the selection."""=0A= return self.tk.getboolean(self.tk.call(=0A= self._w, 'selection', 'includes', index))=0A= select_includes =3D selection_includes=0A= def selection_set(self, first, last=3DNone):=0A= """Set the selection from FIRST to LAST (not included) without=0A= changing the currently selected elements."""=0A= self.tk.call(self._w, 'selection', 'set', first, last)=0A= select_set =3D selection_set=0A= def size(self):=0A= """Return the number of elements in the listbox."""=0A= return getint(self.tk.call(self._w, 'size'))=0A= def xview(self, *what):=0A= """Query and change horizontal position of the view."""=0A= if not what:=0A= return self._getdoubles(self.tk.call(self._w, 'xview'))=0A= self.tk.call((self._w, 'xview') + what)=0A= def xview_moveto(self, fraction):=0A= """Adjust the view in the window so that FRACTION of the=0A= total width of the entry is off-screen to the left."""=0A= self.tk.call(self._w, 'xview', 'moveto', fraction)=0A= def xview_scroll(self, number, what):=0A= """Shift the x-view according to NUMBER which is measured in "units" = or "pages" (WHAT)."""=0A= self.tk.call(self._w, 'xview', 'scroll', number, what)=0A= def yview(self, *what):=0A= """Query and change vertical position of the view."""=0A= if not what:=0A= return self._getdoubles(self.tk.call(self._w, 'yview'))=0A= self.tk.call((self._w, 'yview') + what)=0A= def yview_moveto(self, fraction):=0A= """Adjust the view in the window so that FRACTION of the=0A= total width of the entry is off-screen to the top."""=0A= self.tk.call(self._w, 'yview', 'moveto', fraction)=0A= def yview_scroll(self, number, what):=0A= """Shift the y-view according to NUMBER which is measured in "units" = or "pages" (WHAT)."""=0A= self.tk.call(self._w, 'yview', 'scroll', number, what)=0A= =0A= class Menu(Widget):=0A= """Menu widget which allows to display menu bars, pull-down menus and = pop-up menus."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct menu widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, activeborderwidth,=0A= activeforeground, background, bd, bg, borderwidth, cursor,=0A= disabledforeground, fg, font, foreground, postcommand, relief,=0A= selectcolor, takefocus, tearoff, tearoffcommand, title, type."""=0A= Widget.__init__(self, master, 'menu', cnf, kw)=0A= def tk_bindForTraversal(self):=0A= pass # obsolete since Tk 4.0=0A= def tk_mbPost(self):=0A= self.tk.call('tk_mbPost', self._w)=0A= def tk_mbUnpost(self):=0A= self.tk.call('tk_mbUnpost')=0A= def tk_traverseToMenu(self, char):=0A= self.tk.call('tk_traverseToMenu', self._w, char)=0A= def tk_traverseWithinMenu(self, char):=0A= self.tk.call('tk_traverseWithinMenu', self._w, char)=0A= def tk_getMenuButtons(self):=0A= return self.tk.call('tk_getMenuButtons', self._w)=0A= def tk_nextMenu(self, count):=0A= self.tk.call('tk_nextMenu', count)=0A= def tk_nextMenuEntry(self, count):=0A= self.tk.call('tk_nextMenuEntry', count)=0A= def tk_invokeMenu(self):=0A= self.tk.call('tk_invokeMenu', self._w)=0A= def tk_firstMenu(self):=0A= self.tk.call('tk_firstMenu', self._w)=0A= def tk_mbButtonDown(self):=0A= self.tk.call('tk_mbButtonDown', self._w)=0A= def tk_popup(self, x, y, entry=3D""):=0A= """Post the menu at position X,Y with entry ENTRY."""=0A= self.tk.call('tk_popup', self._w, x, y, entry)=0A= def activate(self, index):=0A= """Activate entry at INDEX."""=0A= self.tk.call(self._w, 'activate', index)=0A= def add(self, itemType, cnf=3D{}, **kw):=0A= """Internal function."""=0A= self.tk.call((self._w, 'add', itemType) +=0A= self._options(cnf, kw))=0A= def add_cascade(self, cnf=3D{}, **kw):=0A= """Add hierarchical menu item."""=0A= self.add('cascade', cnf or kw)=0A= def add_checkbutton(self, cnf=3D{}, **kw):=0A= """Add checkbutton menu item."""=0A= self.add('checkbutton', cnf or kw)=0A= def add_command(self, cnf=3D{}, **kw):=0A= """Add command menu item."""=0A= self.add('command', cnf or kw)=0A= def add_radiobutton(self, cnf=3D{}, **kw):=0A= """Addd radio menu item."""=0A= self.add('radiobutton', cnf or kw)=0A= def add_separator(self, cnf=3D{}, **kw):=0A= """Add separator."""=0A= self.add('separator', cnf or kw)=0A= def insert(self, index, itemType, cnf=3D{}, **kw):=0A= """Internal function."""=0A= self.tk.call((self._w, 'insert', index, itemType) +=0A= self._options(cnf, kw))=0A= def insert_cascade(self, index, cnf=3D{}, **kw):=0A= """Add hierarchical menu item at INDEX."""=0A= self.insert(index, 'cascade', cnf or kw)=0A= def insert_checkbutton(self, index, cnf=3D{}, **kw):=0A= """Add checkbutton menu item at INDEX."""=0A= self.insert(index, 'checkbutton', cnf or kw)=0A= def insert_command(self, index, cnf=3D{}, **kw):=0A= """Add command menu item at INDEX."""=0A= self.insert(index, 'command', cnf or kw)=0A= def insert_radiobutton(self, index, cnf=3D{}, **kw):=0A= """Addd radio menu item at INDEX."""=0A= self.insert(index, 'radiobutton', cnf or kw)=0A= def insert_separator(self, index, cnf=3D{}, **kw):=0A= """Add separator at INDEX."""=0A= self.insert(index, 'separator', cnf or kw)=0A= def delete(self, index1, index2=3DNone):=0A= """Delete menu items between INDEX1 and INDEX2 (not included)."""=0A= self.tk.call(self._w, 'delete', index1, index2)=0A= def entrycget(self, index, option):=0A= """Return the resource value of an menu item for OPTION at = INDEX."""=0A= return self.tk.call(self._w, 'entrycget', index, '-' + option)=0A= def entryconfigure(self, index, cnf=3DNone, **kw):=0A= """Configure a menu item at INDEX."""=0A= if cnf is None and not kw:=0A= cnf =3D {}=0A= for x in self.tk.split(self.tk.call(=0A= (self._w, 'entryconfigure', index))):=0A= cnf[x[0][1:]] =3D (x[0][1:],) + x[1:]=0A= return cnf=0A= if type(cnf) =3D=3D StringType and not kw:=0A= x =3D self.tk.split(self.tk.call(=0A= (self._w, 'entryconfigure', index, '-'+cnf)))=0A= return (x[0][1:],) + x[1:]=0A= self.tk.call((self._w, 'entryconfigure', index)=0A= + self._options(cnf, kw))=0A= entryconfig =3D entryconfigure=0A= def index(self, index):=0A= """Return the index of a menu item identified by INDEX."""=0A= i =3D self.tk.call(self._w, 'index', index)=0A= if i =3D=3D 'none': return None=0A= return getint(i)=0A= def invoke(self, index):=0A= """Invoke a menu item identified by INDEX and execute=0A= the associated command."""=0A= return self.tk.call(self._w, 'invoke', index)=0A= def post(self, x, y):=0A= """Display a menu at position X,Y."""=0A= self.tk.call(self._w, 'post', x, y)=0A= def type(self, index):=0A= """Return the type of the menu item at INDEX."""=0A= return self.tk.call(self._w, 'type', index)=0A= def unpost(self):=0A= """Unmap a menu."""=0A= self.tk.call(self._w, 'unpost')=0A= def yposition(self, index):=0A= """Return the y-position of the topmost pixel of the menu item at = INDEX."""=0A= return getint(self.tk.call(=0A= self._w, 'yposition', index))=0A= =0A= class Menubutton(Widget):=0A= """Menubutton widget, obsolete since Tk8.0."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= Widget.__init__(self, master, 'menubutton', cnf, kw)=0A= =0A= class Message(Widget):=0A= """Message widget to display multiline text. Obsolete since Label does = it too."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= Widget.__init__(self, master, 'message', cnf, kw)=0A= =0A= class Radiobutton(Widget):=0A= """Radiobutton widget which shows only one of several buttons in = on-state."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a radiobutton widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, activeforeground, anchor,=0A= background, bd, bg, bitmap, borderwidth, command, cursor,=0A= disabledforeground, fg, font, foreground, height,=0A= highlightbackground, highlightcolor, highlightthickness, image,=0A= indicatoron, justify, padx, pady, relief, selectcolor, = selectimage,=0A= state, takefocus, text, textvariable, underline, value, variable,=0A= width, wraplength."""=0A= Widget.__init__(self, master, 'radiobutton', cnf, kw)=0A= def deselect(self):=0A= """Put the button in off-state."""=0A= =0A= self.tk.call(self._w, 'deselect')=0A= def flash(self):=0A= """Flash the button."""=0A= self.tk.call(self._w, 'flash')=0A= def invoke(self):=0A= """Toggle the button and invoke a command if given as resource."""=0A= return self.tk.call(self._w, 'invoke')=0A= def select(self):=0A= """Put the button in on-state."""=0A= self.tk.call(self._w, 'select')=0A= =0A= class Scale(Widget):=0A= """Scale widget which can display a numerical scale."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a scale widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, background, bigincrement, = bd,=0A= bg, borderwidth, command, cursor, digits, fg, font, foreground, = from,=0A= highlightbackground, highlightcolor, highlightthickness, label,=0A= length, orient, relief, repeatdelay, repeatinterval, resolution,=0A= showvalue, sliderlength, sliderrelief, state, takefocus,=0A= tickinterval, to, troughcolor, variable, width.""" =0A= Widget.__init__(self, master, 'scale', cnf, kw)=0A= def get(self):=0A= """Get the current value as integer or float."""=0A= value =3D self.tk.call(self._w, 'get')=0A= try:=0A= return getint(value)=0A= except ValueError:=0A= return getdouble(value)=0A= def set(self, value):=0A= """Set the value to VALUE."""=0A= self.tk.call(self._w, 'set', value)=0A= def coords(self, value=3DNone):=0A= """Return a tuple (X,Y) of the point along the centerline of the=0A= trough that corresponds to VALUE or the current value if None is=0A= given."""=0A= =0A= return self._getints(self.tk.call(self._w, 'coords', value))=0A= def identify(self, x, y):=0A= """Return where the point X,Y lies. Valid return values are = "slider",=0A= "though1" and "though2"."""=0A= return self.tk.call(self._w, 'identify', x, y)=0A= =0A= class Scrollbar(Widget):=0A= """Scrollbar widget which displays a slider at a certain = position."""=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a scrollbar widget with the parent MASTER.=0A= =0A= Valid resource names: activebackground, activerelief,=0A= background, bd, bg, borderwidth, command, cursor,=0A= elementborderwidth, highlightbackground,=0A= highlightcolor, highlightthickness, jump, orient,=0A= relief, repeatdelay, repeatinterval, takefocus,=0A= troughcolor, width."""=0A= Widget.__init__(self, master, 'scrollbar', cnf, kw)=0A= def activate(self, index):=0A= """Display the element at INDEX with activebackground and = activerelief.=0A= INDEX can be "arrow1","slider" or "arrow2"."""=0A= self.tk.call(self._w, 'activate', index)=0A= def delta(self, deltax, deltay):=0A= """Return the fractional change of the scrollbar setting if it=0A= would be moved by DELTAX or DELTAY pixels."""=0A= return getdouble(=0A= self.tk.call(self._w, 'delta', deltax, deltay))=0A= def fraction(self, x, y):=0A= """Return the fractional value which corresponds to a slider=0A= position of X,Y."""=0A= return getdouble(self.tk.call(self._w, 'fraction', x, y))=0A= def identify(self, x, y):=0A= """Return the element under position X,Y as one of=0A= "arrow1","slider","arrow2" or ""."""=0A= return self.tk.call(self._w, 'identify', x, y)=0A= def get(self):=0A= """Return the current fractional values (upper and lower end)=0A= of the slider position."""=0A= return self._getdoubles(self.tk.call(self._w, 'get'))=0A= def set(self, *args):=0A= """Set the fractional values of the slider position (upper and=0A= lower ends as value between 0 and 1)."""=0A= self.tk.call((self._w, 'set') + args)=0A= =0A= class Text(Widget):=0A= """Text widget which can display text in various forms."""=0A= # XXX Add dump()=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= """Construct a text widget with the parent MASTER.=0A= =0A= Valid resource names: background, bd, bg, borderwidth, cursor,=0A= exportselection, fg, font, foreground, height,=0A= highlightbackground, highlightcolor, highlightthickness,=0A= insertbackground, insertborderwidth, insertofftime,=0A= insertontime, insertwidth, padx, pady, relief,=0A= selectbackground, selectborderwidth, selectforeground,=0A= setgrid, spacing1, spacing2, spacing3, state, tabs, takefocus,=0A= width, wrap, xscrollcommand, yscrollcommand."""=0A= Widget.__init__(self, master, 'text', cnf, kw)=0A= def bbox(self, *args):=0A= """Return a tuple of (x,y,width,heigth) which gives the bounding=0A= box of the visible part of the character at the index in ARGS."""=0A= return self._getints(=0A= self.tk.call((self._w, 'bbox') + args)) or None=0A= def tk_textSelectTo(self, index):=0A= self.tk.call('tk_textSelectTo', self._w, index)=0A= def tk_textBackspace(self):=0A= self.tk.call('tk_textBackspace', self._w)=0A= def tk_textIndexCloser(self, a, b, c):=0A= self.tk.call('tk_textIndexCloser', self._w, a, b, c)=0A= def tk_textResetAnchor(self, index):=0A= self.tk.call('tk_textResetAnchor', self._w, index)=0A= def compare(self, index1, op, index2):=0A= """Return whether between index INDEX1 and index INDEX2 the=0A= relation OP is satisfied. OP is one of <, <=3D, =3D=3D, >=3D, >, or = !=3D."""=0A= return self.tk.getboolean(self.tk.call(=0A= self._w, 'compare', index1, op, index2))=0A= def debug(self, boolean=3DNone):=0A= """Turn on the internal consistency checks of the B-Tree inside the = text=0A= widget according to BOOLEAN."""=0A= return self.tk.getboolean(self.tk.call(=0A= self._w, 'debug', boolean))=0A= def delete(self, index1, index2=3DNone):=0A= """Delete the characters between INDEX1 and INDEX2 (not = included)."""=0A= self.tk.call(self._w, 'delete', index1, index2)=0A= def dlineinfo(self, index):=0A= """Return tuple (x,y,width,height,baseline) giving the bounding = box=0A= and baseline position of the visible part of the line containing=0A= the character at INDEX."""=0A= return self._getints(self.tk.call(self._w, 'dlineinfo', index))=0A= def get(self, index1, index2=3DNone):=0A= """Return the text from INDEX1 to INDEX2 (not included)."""=0A= return self.tk.call(self._w, 'get', index1, index2)=0A= # (Image commands are new in 8.0)=0A= def image_cget(self, index, option):=0A= """Return the value of OPTION of an embedded image at INDEX."""=0A= if option[:1] !=3D "-":=0A= option =3D "-" + option=0A= if option[-1:] =3D=3D "_":=0A= option =3D option[:-1]=0A= return self.tk.call(self._w, "image", "cget", index, option)=0A= def image_configure(self, index, cnf=3D{}, **kw):=0A= """Configure an embedded image at INDEX."""=0A= if not cnf and not kw:=0A= cnf =3D {}=0A= for x in self.tk.split(=0A= self.tk.call(=0A= self._w, "image", "configure", index)):=0A= cnf[x[0][1:]] =3D (x[0][1:],) + x[1:]=0A= return cnf=0A= apply(self.tk.call,=0A= (self._w, "image", "configure", index)=0A= + self._options(cnf, kw))=0A= def image_create(self, index, cnf=3D{}, **kw):=0A= """Create an embedded image at INDEX."""=0A= return apply(self.tk.call,=0A= (self._w, "image", "create", index)=0A= + self._options(cnf, kw))=0A= def image_names(self):=0A= """Return all names of embedded images in this widget."""=0A= return self.tk.call(self._w, "image", "names")=0A= def index(self, index):=0A= """Return the index in the form line.char for INDEX."""=0A= return self.tk.call(self._w, 'index', index)=0A= def insert(self, index, chars, *args):=0A= """Insert CHARS before the charaters at INDEX. An additional=0A= tag can be given in ARGS. Additional CHARS and tags can follow in = ARGS."""=0A= self.tk.call((self._w, 'insert', index, chars) + args)=0A= def mark_gravity(self, markName, direction=3DNone):=0A= """Change the gravity of a mark MARKNAME to DIRECTION (LEFT or = RIGHT).=0A= Return the current value if None is given for DIRECTION."""=0A= return self.tk.call(=0A= (self._w, 'mark', 'gravity', markName, direction))=0A= def mark_names(self):=0A= """Return all mark names."""=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'mark', 'names'))=0A= def mark_set(self, markName, index):=0A= """Set mark MARKNAME before the character at INDEX."""=0A= self.tk.call(self._w, 'mark', 'set', markName, index)=0A= def mark_unset(self, *markNames):=0A= """Delete all marks in MARKNAMES."""=0A= self.tk.call((self._w, 'mark', 'unset') + markNames)=0A= def mark_next(self, index):=0A= """Return the name of the next mark after INDEX."""=0A= return self.tk.call(self._w, 'mark', 'next', index) or None=0A= def mark_previous(self, index):=0A= """Return the name of the previous mark before INDEX."""=0A= return self.tk.call(self._w, 'mark', 'previous', index) or None=0A= def scan_mark(self, x, y):=0A= """Remember the current X, Y coordinates."""=0A= self.tk.call(self._w, 'scan', 'mark', x, y)=0A= def scan_dragto(self, x, y):=0A= """Adjust the view of the text to 10 times the=0A= difference between X and Y and the coordinates given in=0A= scan_mark."""=0A= self.tk.call(self._w, 'scan', 'dragto', x, y)=0A= def search(self, pattern, index, stopindex=3DNone,=0A= forwards=3DNone, backwards=3DNone, exact=3DNone,=0A= regexp=3DNone, nocase=3DNone, count=3DNone):=0A= """Search PATTERN beginning from INDEX until STOPINDEX.=0A= Return the index of the first character of a match or an empty = string."""=0A= args =3D [self._w, 'search']=0A= if forwards: args.append('-forwards')=0A= if backwards: args.append('-backwards')=0A= if exact: args.append('-exact')=0A= if regexp: args.append('-regexp')=0A= if nocase: args.append('-nocase')=0A= if count: args.append('-count'); args.append(count)=0A= if pattern[0] =3D=3D '-': args.append('--')=0A= args.append(pattern)=0A= args.append(index)=0A= if stopindex: args.append(stopindex)=0A= return self.tk.call(tuple(args))=0A= def see(self, index):=0A= """Scroll such that the character at INDEX is visible."""=0A= self.tk.call(self._w, 'see', index)=0A= def tag_add(self, tagName, index1, *args):=0A= """Add tag TAGNAME to all characters between INDEX1 and index2 in = ARGS.=0A= Addtional pairs of indices may follow in ARGS."""=0A= self.tk.call(=0A= (self._w, 'tag', 'add', tagName, index1) + args)=0A= def tag_unbind(self, tagName, sequence, funcid=3DNone):=0A= """Unbind for all characters with TAGNAME for event SEQUENCE the=0A= function identified with FUNCID."""=0A= self.tk.call(self._w, 'tag', 'bind', tagName, sequence, '')=0A= if funcid:=0A= self.deletecommand(funcid)=0A= def tag_bind(self, tagName, sequence, func, add=3DNone):=0A= """Bind to all characters with TAGNAME at event SEQUENCE a call to = function FUNC.=0A= =0A= An additional boolean parameter ADD specifies whether FUNC will be=0A= called additionally to the other bound function or whether it will=0A= replace the previous function. See bind for the return value."""=0A= return self._bind((self._w, 'tag', 'bind', tagName),=0A= sequence, func, add)=0A= def tag_cget(self, tagName, option):=0A= """Return the value of OPTION for tag TAGNAME."""=0A= if option[:1] !=3D '-':=0A= option =3D '-' + option=0A= if option[-1:] =3D=3D '_':=0A= option =3D option[:-1]=0A= return self.tk.call(self._w, 'tag', 'cget', tagName, option)=0A= def tag_configure(self, tagName, cnf=3D{}, **kw):=0A= """Configure a tag TAGNAME."""=0A= if type(cnf) =3D=3D StringType:=0A= x =3D self.tk.split(self.tk.call(=0A= self._w, 'tag', 'configure', tagName, '-'+cnf))=0A= return (x[0][1:],) + x[1:]=0A= self.tk.call(=0A= (self._w, 'tag', 'configure', tagName)=0A= + self._options(cnf, kw))=0A= tag_config =3D tag_configure=0A= def tag_delete(self, *tagNames):=0A= """Delete all tags in TAGNAMES."""=0A= self.tk.call((self._w, 'tag', 'delete') + tagNames)=0A= def tag_lower(self, tagName, belowThis=3DNone):=0A= """Change the priority of tag TAGNAME such that it is lower=0A= than the priority of BELOWTHIS."""=0A= self.tk.call(self._w, 'tag', 'lower', tagName, belowThis)=0A= def tag_names(self, index=3DNone):=0A= """Return a list of all tag names."""=0A= return self.tk.splitlist(=0A= self.tk.call(self._w, 'tag', 'names', index))=0A= def tag_nextrange(self, tagName, index1, index2=3DNone):=0A= """Return a list of start and end index for the first sequence of=0A= characters between INDEX1 and INDEX2 which all have tag TAGNAME.=0A= The text is searched forward from INDEX1."""=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'tag', 'nextrange', tagName, index1, index2))=0A= def tag_prevrange(self, tagName, index1, index2=3DNone):=0A= """Return a list of start and end index for the first sequence of=0A= characters between INDEX1 and INDEX2 which all have tag TAGNAME.=0A= The text is searched backwards from INDEX1."""=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'tag', 'prevrange', tagName, index1, index2))=0A= def tag_raise(self, tagName, aboveThis=3DNone):=0A= """Change the priority of tag TAGNAME such that it is higher=0A= than the priority of ABOVETHIS."""=0A= self.tk.call(=0A= self._w, 'tag', 'raise', tagName, aboveThis)=0A= def tag_ranges(self, tagName):=0A= """Return a list of ranges of text which have tag TAGNAME."""=0A= return self.tk.splitlist(self.tk.call(=0A= self._w, 'tag', 'ranges', tagName))=0A= def tag_remove(self, tagName, index1, index2=3DNone):=0A= """Remove tag TAGNAME from all characters between INDEX1 and = INDEX2."""=0A= self.tk.call(=0A= self._w, 'tag', 'remove', tagName, index1, index2)=0A= def window_cget(self, index, option):=0A= """Return the value of OPTION of an embedded window at INDEX."""=0A= if option[:1] !=3D '-':=0A= option =3D '-' + option=0A= if option[-1:] =3D=3D '_':=0A= option =3D option[:-1]=0A= return self.tk.call(self._w, 'window', 'cget', index, option)=0A= def window_configure(self, index, cnf=3D{}, **kw):=0A= """Configure an embedded window at INDEX."""=0A= if type(cnf) =3D=3D StringType:=0A= x =3D self.tk.split(self.tk.call(=0A= self._w, 'window', 'configure',=0A= index, '-'+cnf))=0A= return (x[0][1:],) + x[1:]=0A= self.tk.call(=0A= (self._w, 'window', 'configure', index)=0A= + self._options(cnf, kw))=0A= window_config =3D window_configure=0A= def window_create(self, index, cnf=3D{}, **kw):=0A= """Create a window at INDEX."""=0A= self.tk.call(=0A= (self._w, 'window', 'create', index)=0A= + self._options(cnf, kw))=0A= def window_names(self):=0A= """Return all names of embedded windows in this widget."""=0A= return self.tk.splitlist(=0A= self.tk.call(self._w, 'window', 'names'))=0A= def xview(self, *what):=0A= """Query and change horizontal position of the view."""=0A= if not what:=0A= return self._getdoubles(self.tk.call(self._w, 'xview'))=0A= self.tk.call((self._w, 'xview') + what)=0A= def yview(self, *what):=0A= """Query and change vertical position of the view."""=0A= if not what:=0A= return self._getdoubles(self.tk.call(self._w, 'yview'))=0A= self.tk.call((self._w, 'yview') + what)=0A= def yview_pickplace(self, *what):=0A= """Obsolete function, use see."""=0A= self.tk.call((self._w, 'yview', '-pickplace') + what)=0A= =0A= class _setit:=0A= """Internal class. It wraps the command in the widget = OptionMenu."""=0A= def __init__(self, var, value, callback=3DNone):=0A= self.__value =3D value=0A= self.__var =3D var=0A= self.__callback =3D callback=0A= def __call__(self, *args):=0A= self.__var.set(self.__value)=0A= if self.__callback:=0A= apply(self.__callback, (self.__value,)+args)=0A= =0A= class OptionMenu(Menubutton):=0A= """OptionMenu which allows the user to select a value from a = menu."""=0A= def __init__(self, master, variable, value, *values, **kwargs):=0A= """Construct an optionmenu widget with the parent MASTER, with=0A= the resource textvariable set to VARIABLE, the initially selected=0A= value VALUE, the other menu values VALUES and an additional=0A= keyword argument command."""=0A= kw =3D {"borderwidth": 2, "textvariable": variable,=0A= "indicatoron": 1, "relief": RAISED, "anchor": "c",=0A= "highlightthickness": 2}=0A= Widget.__init__(self, master, "menubutton", kw)=0A= self.widgetName =3D 'tk_optionMenu'=0A= menu =3D self.__menu =3D Menu(self, name=3D"menu", tearoff=3D0)=0A= self.menuname =3D menu._w=0A= # 'command' is the only supported keyword=0A= callback =3D kwargs.get('command')=0A= if kwargs.has_key('command'):=0A= del kwargs['command']=0A= if kwargs:=0A= raise TclError, 'unknown option -'+kwargs.keys()[0]=0A= menu.add_command(label=3Dvalue,=0A= command=3D_setit(variable, value, callback))=0A= for v in values:=0A= menu.add_command(label=3Dv,=0A= command=3D_setit(variable, v, callback))=0A= self["menu"] =3D menu=0A= =0A= def __getitem__(self, name):=0A= if name =3D=3D 'menu':=0A= return self.__menu=0A= return Widget.__getitem__(self, name)=0A= =0A= def destroy(self):=0A= """Destroy this widget and the associated menu."""=0A= Menubutton.destroy(self)=0A= self.__menu =3D None=0A= =0A= class Image:=0A= """Base class for images."""=0A= def __init__(self, imgtype, name=3DNone, cnf=3D{}, master=3DNone, = **kw):=0A= self.name =3D None=0A= if not master:=0A= master =3D _default_root=0A= if not master:=0A= raise RuntimeError, 'Too early to create image'=0A= self.tk =3D master.tk=0A= if not name:=0A= name =3D `id(self)`=0A= # The following is needed for systems where id(x)=0A= # can return a negative number, such as Linux/m68k:=0A= if name[0] =3D=3D '-': name =3D '_' + name[1:]=0A= if kw and cnf: cnf =3D _cnfmerge((cnf, kw))=0A= elif kw: cnf =3D kw=0A= options =3D ()=0A= for k, v in cnf.items():=0A= if callable(v):=0A= v =3D self._register(v)=0A= options =3D options + ('-'+k, v)=0A= self.tk.call(('image', 'create', imgtype, name,) + options)=0A= self.name =3D name=0A= def __str__(self): return self.name=0A= def __del__(self):=0A= if self.name:=0A= try:=0A= self.tk.call('image', 'delete', self.name)=0A= except TclError:=0A= # May happen if the root was destroyed=0A= pass=0A= def __setitem__(self, key, value):=0A= self.tk.call(self.name, 'configure', '-'+key, value)=0A= def __getitem__(self, key):=0A= return self.tk.call(self.name, 'configure', '-'+key)=0A= def configure(self, **kw):=0A= """Configure the image."""=0A= res =3D ()=0A= for k, v in _cnfmerge(kw).items():=0A= if v is not None:=0A= if k[-1] =3D=3D '_': k =3D k[:-1]=0A= if callable(v):=0A= v =3D self._register(v)=0A= res =3D res + ('-'+k, v)=0A= self.tk.call((self.name, 'config') + res)=0A= config =3D configure=0A= def height(self):=0A= """Return the height of the image."""=0A= return getint(=0A= self.tk.call('image', 'height', self.name))=0A= def type(self):=0A= """Return the type of the imgage, e.g. "photo" or "bitmap"."""=0A= return self.tk.call('image', 'type', self.name)=0A= def width(self):=0A= """Return the width of the image."""=0A= return getint(=0A= self.tk.call('image', 'width', self.name))=0A= =0A= class PhotoImage(Image):=0A= """Widget which can display colored images in GIF, PPM/PGM = format."""=0A= def __init__(self, name=3DNone, cnf=3D{}, master=3DNone, **kw):=0A= """Create an image with NAME.=0A= =0A= Valid resource names: data, format, file, gamma, height, palette,=0A= width."""=0A= apply(Image.__init__, (self, 'photo', name, cnf, master), kw)=0A= def blank(self):=0A= """Display a transparent image."""=0A= self.tk.call(self.name, 'blank')=0A= def cget(self, option):=0A= """Return the value of OPTION."""=0A= return self.tk.call(self.name, 'cget', '-' + option)=0A= # XXX config=0A= def __getitem__(self, key):=0A= return self.tk.call(self.name, 'cget', '-' + key)=0A= # XXX copy -from, -to, ...?=0A= def copy(self):=0A= """Return a new PhotoImage with the same image as this widget."""=0A= destImage =3D PhotoImage()=0A= self.tk.call(destImage, 'copy', self.name)=0A= return destImage=0A= def zoom(self,x,y=3D''):=0A= """Return a new PhotoImage with the same image as this widget=0A= but zoom it with X and Y."""=0A= destImage =3D PhotoImage()=0A= if y=3D=3D'': y=3Dx=0A= self.tk.call(destImage, 'copy', self.name, '-zoom',x,y)=0A= return destImage=0A= def subsample(self,x,y=3D''):=0A= """Return a new PhotoImage based on the same image as this widget=0A= but use only every Xth or Yth pixel."""=0A= destImage =3D PhotoImage()=0A= if y=3D=3D'': y=3Dx=0A= self.tk.call(destImage, 'copy', self.name, '-subsample',x,y)=0A= return destImage=0A= def get(self, x, y):=0A= """Return the color (red, green, blue) of the pixel at X,Y."""=0A= return self.tk.call(self.name, 'get', x, y)=0A= def put(self, data, to=3DNone):=0A= """Put row formated colors to image starting from=0A= position TO, e.g. image.put("{red green} {blue yellow}", = to=3D(4,6))"""=0A= args =3D (self.name, 'put', data)=0A= if to:=0A= if to[0] =3D=3D '-to':=0A= to =3D to[1:]=0A= args =3D args + ('-to',) + tuple(to)=0A= self.tk.call(args)=0A= # XXX read=0A= def write(self, filename, format=3DNone, from_coords=3DNone):=0A= """Write image to file FILENAME in FORMAT starting from=0A= position FROM_COORDS."""=0A= args =3D (self.name, 'write', filename)=0A= if format:=0A= args =3D args + ('-format', format)=0A= if from_coords:=0A= args =3D args + ('-from',) + tuple(from_coords)=0A= self.tk.call(args)=0A= =0A= class BitmapImage(Image):=0A= """Widget which can display a bitmap."""=0A= def __init__(self, name=3DNone, cnf=3D{}, master=3DNone, **kw):=0A= """Create a bitmap with NAME.=0A= =0A= Valid resource names: background, data, file, foreground, maskdata, = maskfile."""=0A= apply(Image.__init__, (self, 'bitmap', name, cnf, master), kw)=0A= =0A= def image_names(): return _default_root.tk.call('image', 'names')=0A= def image_types(): return _default_root.tk.call('image', 'types')=0A= =0A= ######################################################################=0A= # Extensions:=0A= =0A= class Studbutton(Button):=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= Widget.__init__(self, master, 'studbutton', cnf, kw)=0A= self.bind('', self.tkButtonEnter)=0A= self.bind('', self.tkButtonLeave)=0A= self.bind('<1>', self.tkButtonDown)=0A= self.bind('', self.tkButtonUp)=0A= =0A= class Tributton(Button):=0A= def __init__(self, master=3DNone, cnf=3D{}, **kw):=0A= Widget.__init__(self, master, 'tributton', cnf, kw)=0A= self.bind('', self.tkButtonEnter)=0A= self.bind('', self.tkButtonLeave)=0A= self.bind('<1>', self.tkButtonDown)=0A= self.bind('', self.tkButtonUp)=0A= self['fg'] =3D self['bg']=0A= self['activebackground'] =3D self['bg']=0A= =0A= ######################################################################=0A= # Test:=0A= =0A= def _test():=0A= root =3D Tk()=0A= text =3D "This is Tcl/Tk version %s" % TclVersion=0A= if TclVersion >=3D 8.1:=0A= text =3D text + u"\nThis should be a cedilla: \347"=0A= label =3D Label(root, text=3Dtext)=0A= label.pack()=0A= test =3D Button(root, text=3D"Click me!",=0A= command=3Dlambda root=3Droot: root.test.configure(=0A= text=3D"[%s]" % root.test['text']))=0A= test.pack()=0A= root.test =3D test=0A= quit =3D Button(root, text=3D"QUIT", command=3Droot.destroy)=0A= quit.pack()=0A= # The following three commands are needed so the window pops=0A= # up on top on Windows...=0A= root.iconify()=0A= root.update()=0A= root.deiconify()=0A= root.mainloop()=0A= =0A= if __name__ =3D=3D '__main__':=0A= _test()=0A= ------_=_NextPart_000_01BFDCDB.F3B3F44E-- From jeremy@beopen.com Fri Jun 23 15:37:13 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Fri, 23 Jun 2000 10:37:13 -0400 (EDT) Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names In-Reply-To: References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> <39531A20.1BEAA51E@lemburg.com> Message-ID: <14675.30233.658776.764865@localhost.localdomain> Do you have a pure-Python test case that causes the new code to be executed? Jeremy From mmuller@enduden.com Fri Jun 23 01:09:36 2000 From: mmuller@enduden.com (Michael Muller) Date: Thu, 22 Jun 2000 20:09:36 -0400 Subject: [Patches] Fix for deadlock on OS/2 python Message-ID: <200006230020.UAA15416@bogus.com> This is a MIME/Multipart message. --192.168.100.3.501.15379.961719655.001.19084 Content-type: text/plain Hi guys, I recently ran into a really cool deadlock condition in OS/2 Python. It occurs when fdopen() is called from within a critical section in the OS/2 popen() function in posixmodule when an fflush() is occuring in another thread. I'm guessing that the high-level IO functions in Visual Age have some sort of semaphore protection: fdopen() remains blocked until fflush() finishes, but fflush can't finish because another thread is in a critical section. Unfortunately, I am unable to create a small script to reproduce this. It occurs consistantly in the program where I discovered it (which is, of course, property of IBM). However, you may be able to get it to occur in the debugger. The enclosed patch fixes it. ============================================================================= michaelMuller = mmuller@enduden.com | http://www.cloud9.net/~proteus ----------------------------------------------------------------------------- We are explorers in the further reaches of experience: demons to some, angels to others. - "Pinhead" from "Hellraiser" ============================================================================= --192.168.100.3.501.15379.961719655.001.19084 Content-type: text/plain; charset="us-ascii" Content-disposition: attachment; filename="posixmodule-2000-06-20.patch" Content-description: fdopen deadlock fix Content-Transfer-Encoding: base64 LS0tIHBvc2l4bW9kdWxlLmMub3JnCVR1ZSBKdW4gMjAgMDg6NTM6MTQgMjAwMAorKysgcG9zaXht b2R1bGUuYwlUdWUgSnVuIDIwIDA4OjU2OjU4IDIwMDAKQEAgLTE5MDYsMTMgKzE5MDYsMTUgQEAK ICAgICAgICAgaWYgKGR1cDIod2hhbiwgMSkgPT0gMCkgeyAgICAgIC8qIENvbm5lY3QgU1RET1VU IHRvIFBpcGUgV3JpdGUgU2lkZSAqLwogICAgICAgICAgICAgRG9zQ2xvc2Uod2hhbik7ICAgICAg ICAgICAgLyogQ2xvc2UgTm93LVVudXNlZCBQaXBlIFdyaXRlIEhhbmRsZSAqLwogCi0gICAgICAg ICAgICBpZiAoYXN5bmNfc3lzdGVtKGNvbW1hbmQpID09IE5PX0VSUk9SKQotICAgICAgICAgICAg ICAgIHJldGZkID0gZmRvcGVuKHJoYW4sIG1vZGUpOyAvKiBBbmQgUmV0dXJuIFBpcGUgUmVhZCBI YW5kbGUgKi8KKyAgICAgICAgICAgIHJjID0gYXN5bmNfc3lzdGVtKGNvbW1hbmQpOwogICAgICAg ICB9CiAKICAgICAgICAgZHVwMihvbGRmZCwgMSk7ICAgICAgICAgIC8qIFJlY29ubmVjdCBTVERP VVQgdG8gT3JpZ2luYWwgSGFuZGxlICovCiAgICAgICAgIERvc0V4aXRDcml0U2VjKCk7ICAgICAg ICAvKiBOb3cgQWxsb3cgT3RoZXIgVGhyZWFkcyB0byBSdW4gKi8KIAorICAgICAgICBpZiAocmMg PT0gTk9fRVJST1IpCisgICAgICAgICAgICByZXRmZCA9IGZkb3BlbihyaGFuLCBtb2RlKTsgLyog QW5kIFJldHVybiBQaXBlIFJlYWQgSGFuZGxlICovCisKICAgICAgICAgY2xvc2Uob2xkZmQpOyAg ICAgICAgICAgIC8qIEFuZCBDbG9zZSBTYXZlZCBTVERPVVQgSGFuZGxlICovCiAgICAgICAgIHJl dHVybiByZXRmZDsgICAgICAgICAgICAvKiBSZXR1cm4gZmQgb2YgUGlwZSBvciBOVUxMIGlmIEVy cm9yICovCiAKQEAgLTE5MjUsMTIgKzE5MjcsMTQgQEAKICAgICAgICAgaWYgKGR1cDIocmhhbiwg MCkgPT0gMCkgICAgIHsgLyogQ29ubmVjdCBTVERJTiB0byBQaXBlIFJlYWQgU2lkZSAqLwogICAg ICAgICAgICAgRG9zQ2xvc2Uocmhhbik7ICAgICAgICAgICAvKiBDbG9zZSBOb3ctVW51c2VkIFBp cGUgUmVhZCBIYW5kbGUgKi8KIAotICAgICAgICAgICAgaWYgKGFzeW5jX3N5c3RlbShjb21tYW5k KSA9PSBOT19FUlJPUikKLSAgICAgICAgICAgICAgICByZXRmZCA9IGZkb3Blbih3aGFuLCBtb2Rl KTsgLyogQW5kIFJldHVybiBQaXBlIFdyaXRlIEhhbmRsZSAqLworICAgICAgICAgICAgcmMgPSBh c3luY19zeXN0ZW0oY29tbWFuZCk7CiAgICAgICAgIH0KIAogICAgICAgICBkdXAyKG9sZGZkLCAw KTsgICAgICAgICAgLyogUmVjb25uZWN0IFNURElOIHRvIE9yaWdpbmFsIEhhbmRsZSAqLwogICAg ICAgICBEb3NFeGl0Q3JpdFNlYygpOyAgICAgICAgLyogTm93IEFsbG93IE90aGVyIFRocmVhZHMg dG8gUnVuICovCisKKyAgICAgICAgaWYgKHJjID09IE5PX0VSUk9SKQorICAgICAgICAgICAgcmV0 ZmQgPSBmZG9wZW4od2hhbiwgbW9kZSk7IC8qIEFuZCBSZXR1cm4gUGlwZSBXcml0ZSBIYW5kbGUg Ki8KIAogICAgICAgICBjbG9zZShvbGRmZCk7ICAgICAgICAgICAgLyogQW5kIENsb3NlIFNhdmVk IFNURElOIEhhbmRsZSAqLwogICAgICAgICByZXR1cm4gcmV0ZmQ7ICAgICAgICAgICAgLyogUmV0 dXJuIGZkIG9mIFBpcGUgb3IgTlVMTCBpZiBFcnJvciAqLwo= --192.168.100.3.501.15379.961719655.001.19084-- From R.Liebscher@gmx.de Fri Jun 23 16:38:33 2000 From: R.Liebscher@gmx.de (Rene Liebscher) Date: Fri, 23 Jun 2000 17:38:33 +0200 Subject: [Patches] Extension building on Win32 using Gnu C References: <14670.8034.259577.659664@cj42289-a.reston1.va.home.com> <14670.8799.164083.353719@cj42289-a.reston1.va.home.com> Message-ID: <39538479.CDD12C3A@gmx.de> Fred L. Drake, Jr. wrote: > > Daniel Berlin writes: > > People who are concerned about stability tend to stay one major > > release behind, mainly because before EGCS became the official GCC, major > > releases often had very annoying bugs. > > Sounds like this is safe to accept; I'll check it in momentarily. > Thanks! > I would use a #warning instead of an #error. It is possible to use gcc2.91.* and build perfect working extensions as long you use C and not C++. You get some warnings, but this is not a big problem. So we shouldn't force users to update their compilers if they only use C. But we should give them a hint where problems could come from. If they use C++, the last what they see is this warning text before the compiler crashes.("Almost the same behaviour as using an #error." OK, not really.) So there is no reason to be too restrictive and using an #error. But if you checked in these lines, you could also check in the rest of the patch. (or what now is remaining from my first submission) Without these lines in config.h GNU C won't work. ---------------------------------------------------------------- /* egcs/gnu-win32 defines __GNUC__ and _WIN32 */ #if defined(__GNUC__) && defined(_WIN32) #define NT /* NT is obsolete - please use MS_WIN32 instead */ #define MS_WIN32 #define MS_WINDOWS #define HAVE_CLOCK #define HAVE_STRFTIME #define HAVE_STRERROR #define NT_THREADS #define WITH_THREAD #define WORD_BIT 32 #define HAVE_LONG_LONG 1 #define LONG_LONG long long #define PYTHONPATH ".\\DLLs;.\\lib;.\\lib\\plat-win;.\\lib\\lib-tk" #ifndef MS_NO_COREDLL #define MS_COREDLL /* Python core is in a DLL */ #ifndef USE_DL_EXPORT #define USE_DL_IMPORT #endif /* !USE_DL_EXPORT */ #endif /* !MS_NO_COREDLL */ #ifdef USE_DL_IMPORT #define DL_IMPORT(sym) __declspec(dllimport) sym #endif /* USE_DL_IMPORT */ #endif /* (defined(__GNUC__) && defined(_WIN32)) */ -------------------------------------------------------------- kind regards Rene Liebscher From gisle@ActiveState.com Fri Jun 23 19:31:09 2000 From: gisle@ActiveState.com (Gisle Aas) Date: 23 Jun 2000 20:31:09 +0200 Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names In-Reply-To: Jeremy Hylton's message of "Fri, 23 Jun 2000 10:37:13 -0400 (EDT)" References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> <39531A20.1BEAA51E@lemburg.com> <14675.30233.658776.764865@localhost.localdomain> Message-ID: Jeremy Hylton writes: > Do you have a pure-Python test case that causes the new code to be > executed? No. If I call the python level getattr() then it will demand that the second argument is a string. This is probably also the reason this has not been a problem for "normal" people. But, if I mix some perl into this (using an unpatched python): >>> import perl >>> hasattr = perl.eval("sub { shift->HasAttr(shift) }") >>> hasattr >>> hasattr({}, "keys") 1 >>> hasattr({}, "foo") 0 >>> hasattr({}, 42) Segmentation fault I could of course make the perl interface to HasAttr() also demand a string as name argument before passing it on to PyObject_HasAttr, but the current proposed patch looked more right to me. An alternative could be to patch the api documentation to say that the name argument to these functions has to be PyString objects. You might then even consider changing the prototypes to be like this: int PyObject_HasAttr(PyObject *v, PyStringObject* name); Regards, Gisle From billtut@microsoft.com Sun Jun 25 11:14:31 2000 From: billtut@microsoft.com (Bill Tutt) Date: Sun, 25 Jun 2000 03:14:31 -0700 Subject: [Patches] New Unicode Character Name \N{..} patches Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD233@RED-MSG-50> This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible. ------_=_NextPart_000_01BFDE8E.27727CC0 Content-Type: text/plain; charset="windows-1252" Files: patch.txt: Contains changes to the existing files in CVS for the following things: Adds ucnhash.c into the build gunk: Modules\Setup.in Modules\Makefile.pre.in Patch to pcbuild.dsw not included on purpose. Add build support for strnicmp on platforms that don't have it: configure.in Python\Makefile.in Note: The strnicmp configure magic for platforms that don't have it haven't been tested since I don't have such a platform. Have unicode-escape support \N{...} syntax: Objects\unicodeobject.c Dynamically imports the ucnhash module. Add \N{..} specific test cases: Lib\test\test_unicode.py New files: Python\strnicmp.c: Guess... Although Win32 does have strnicmp, this code has been tested since it was mystrnicmp in this patch's last incarnation. Modules\ucnhash.c: Already generated file PCBuild\ucnhash.dsp: MSVC project file, drop into PCBuild, and insert into pcbuild.dsw, and create a dependancy on python16. Include\ucnhash.h Tools used in generating ucnhash.c/.h: Tools\perfecthash\perfect_hash.py Tools\perfecthash\GenUCNHash.py Tools\perfecthash\perfhash.c The generation tools are more generic than before, but still could use some cleaning up, but the generated C code is in shape to be reviewed again for 1.6 so here it is. :) This drop also doesn't include the UnicodeData.txt file. Bill <> ------_=_NextPart_000_01BFDE8E.27727CC0 Content-Type: application/octet-stream; name="ucn.zip" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="ucn.zip" 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 AQAA9skBAAAA ------_=_NextPart_000_01BFDE8E.27727CC0-- From gotti@gmx.de Sun Jun 25 21:52:30 2000 From: gotti@gmx.de (=?iso-8859-1?Q?Gottfried_Gan=DFauge?=) Date: Sun, 25 Jun 2000 22:52:30 +0200 Subject: [Patches] Patch for zipfile.py Message-ID: <000801bfdee7$47f08560$42a837c2@gorki120.de> This is a multi-part message in MIME format. ------=_NextPart_000_0005_01BFDEF8.0AC1C530 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8bit Currently I am writing the build script for my company's software system and used that as an opportunity to learn python. One of the tasks performed during our builds is the extraction of some precompiled objects from a Zip-File compressed using pkzip-2.5. As we don't have that installed on all of our machines I wanted to write a small python class which would extract all of the files from that Zip archive. A quick search on the internet brought zipfile.py to my knowledge, a few minutes later the class ZipFile was written. During my tests I permanently got decompression errors on Zip archives known to be good. When I traced back to the error i found out about a small missinterpretation of the zip format within unzip.py: The central directory obviously need not contain an exact copy of the local file header: The value "extra field length" was always 0 in the central directory whereas it was different in the local file header. After correcting that error I went on with debugging and almost immediately found out, that crc32() is not an attribute of binascii in Python 1.5.2. So I expanded the trial import of zlib: If module zlib is available, we take the crc32() routine from there, otherwise we check binascii and if that fails (it does under 1.5.2), we define a dummy crc32() which just raises NotImplementedError. The attached patch is a context diff against zipfile.py Version 1.2 from the CVS repository Here comes my test module: -------------8>< snip 8><--------------------------8>< snip 8><---------------- # # Utility Modules # import os import string import sys import time import zipfile # # Encapsulation of PKZip class Unzip: def __init__(self): "Constructor" # # extract an archive # # @param archive # archive to extract # # @param dir # destination directory # def extract(self, archive, dir): if not os.access (archive, os.R_OK): raise "Cannot access %s" % (archive) if not zipfile.is_zipfile(archive): raise "%s: not a zipfile" % (archive) z = zipfile.ZipFile (archive) for name in z.namelist(): outfile = os.path.join (dir, name) makedir (os.path.dirname (outfile)) f = open (outfile, "wb") f.write (z.read (name)) f.close () date = z.getinfo (name).date_time # year, month, day, hour, min, sec try: os.utime ( outfile, (self._makedate (date), self._makedate (date))) except: pass # ignore errors # # Create a time value from a tuple returned by the ZIP-Functions # # @param zipdate # tuple: (year, month, day, hour, min, sec) def _makedate(self, zipdate): "Create a time value from a tuple returned by the ZIP-Functions" year, month, day, hour, min, sec = zipdate return time.mktime ((year, month, day, hour, min, sec, 0, 0, -1)) # ############################################################################ ######## # # Try to create a directory # fail only if it doesn't exist afterwards # # @param path # Directory to make # def makedir(path): try: os.makedirs (path) except: if not os.path.isdir (path): raise Unzip().extract ("i:\\_BuildTools\\x.zip", "i:\\_BuildTools\\fred") -------------8>< snip 8><--------------------------8>< snip 8><---------------- I confirm that, to the best of my knowledge and belief, this contribution is free of any claims of third parties under copyright, patent or other rights or interests ("claims"). To the extent that I have any such claims, I hereby grant to CNRI a nonexclusive, irrevocable, royalty-free, worldwide license to reproduce, distribute, perform and/or display publicly, prepare derivative versions, and otherwise use this contribution as part of the Python software and its related documentation, or any derivative versions thereof, at no cost to CNRI or its licensed users, and to authorize others to do so. I acknowledge that CNRI may, at its sole discretion, decide whether or not to incorporate this contribution in the Python software and its related documentation. I further grant CNRI permission to use my name and other identifying information provided to CNRI by me for use in connection with the Python software and its related documentation. mit freundlichen Grüßen, Gottfried Ganßauge Gorkistraße 120 13509 Berlin ganssauge@gmx.de ------=_NextPart_000_0005_01BFDEF8.0AC1C530 Content-Type: text/x-vcard; name="=?iso-8859-1?Q?Gottfried_Gan=DFauge.vcf?=" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="=?iso-8859-1?Q?Gottfried_Gan=DFauge.vcf?=" BEGIN:VCARD VERSION:2.1 N:Gan=DFauge;Gottfried FN:Gottfried Gan=DFauge ORG:;Softwareentwicklung TEL;HOME;FAX:+49-30-434 90 038 ADR;WORK:;;;Berlin;Berlin;;Deutschland LABEL;WORK;ENCODING=3DQUOTED-PRINTABLE:Berlin, = Berlin=3D0D=3D0ADeutschland ADR;HOME:;;Gorkistra=DFe 120;Berlin;Berlin;13509;Deutschland LABEL;HOME;ENCODING=3DQUOTED-PRINTABLE:Gorkistra=3DDFe = 120=3D0D=3D0ABerlin, Berlin 13509=3D0D=3D0ADeutschland X-WAB-GENDER:2 BDAY:19620226 EMAIL;PREF;INTERNET:ganssauge@gmx.de REV:20000625T205230Z END:VCARD ------=_NextPart_000_0005_01BFDEF8.0AC1C530 Content-Type: application/octet-stream; name="zipfile.py.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="zipfile.py.patch" *** org/zipfile.py Sun Jun 25 20:22:24 2000=0A= --- ./zipfile.py Sun Jun 25 20:46:36 2000=0A= ***************=0A= *** 6,14 ****=0A= import binascii, py_compile=0A= =0A= try:=0A= ! import zlib # We may need its compression method=0A= except:=0A= ! zlib =3D None=0A= =0A= class _BadZipfile(Exception):=0A= pass=0A= --- 6,20 ----=0A= import binascii, py_compile=0A= =0A= try:=0A= ! import zlib # We may need its compression method=0A= ! crc32 =3D zlib.crc32 # O.K., then let's also take crc32 from = there (and that works under 1.5.2!)=0A= except:=0A= ! zlib =3D None=0A= ! if hasattr(binascii, "crc32"):=0A= ! crc32 =3D binascii.crc32 # no zlib, if we need crc32 we might = get it here? (on 1.6!)=0A= ! else:=0A= ! def crc32 (bytes): # O.k. We give up, if someone needs = crc32, he must implement it himself=0A= ! raise NotImplementedError=0A= =0A= class _BadZipfile(Exception):=0A= pass=0A= ***************=0A= *** 181,187 ****=0A= if fname !=3D data.filename:=0A= raise RuntimeError, \=0A= 'File name in Central Directory "%s" and File Header "%s" differ.' % (=0A= ! data.filename, fname)=0A= =0A= def namelist(self):=0A= "Return a list of file names in the archive"=0A= --- 187,196 ----=0A= if fname !=3D data.filename:=0A= raise RuntimeError, \=0A= 'File name in Central Directory "%s" and File Header "%s" differ.' % (=0A= ! data.filename, fname)=0A= ! =0A= ! # The data in the central directory doesn't say it all ... = =0A= ! data.file_offset =3D data.header_offset + 30 + fheader[10] = + fheader[11]=0A= =0A= def namelist(self):=0A= "Return a list of file names in the archive"=0A= ***************=0A= *** 232,238 ****=0A= raise RuntimeError, \=0A= "De-compression requires the (missing) zlib module"=0A= # zlib compress/decompress code by Jeremy Hylton of CNRI=0A= ! dc =3D zlib.decompressobj(-15)=0A= bytes =3D dc.decompress(bytes)=0A= # need to feed in unused pad byte so that zlib won't choke=0A= ex =3D dc.decompress('Z') + dc.flush()=0A= --- 241,247 ----=0A= raise RuntimeError, \=0A= "De-compression requires the (missing) zlib module"=0A= # zlib compress/decompress code by Jeremy Hylton of CNRI=0A= ! dc =3D zlib.decompressobj(-15)=0A= bytes =3D dc.decompress(bytes)=0A= # need to feed in unused pad byte so that zlib won't choke=0A= ex =3D dc.decompress('Z') + dc.flush()=0A= ***************=0A= *** 242,248 ****=0A= raise BadZipfile, \=0A= "Unsupported compression method %d for file %s" % \=0A= (zinfo.compress_type, name)=0A= ! crc =3D binascii.crc32(bytes)=0A= if crc !=3D zinfo.CRC:=0A= raise BadZipfile, "Bad CRC-32 for file %s" % name=0A= return bytes=0A= --- 251,257 ----=0A= raise BadZipfile, \=0A= "Unsupported compression method %d for file %s" % \=0A= (zinfo.compress_type, name)=0A= ! crc =3D crc32(bytes)=0A= if crc !=3D zinfo.CRC:=0A= raise BadZipfile, "Bad CRC-32 for file %s" % name=0A= return bytes=0A= ***************=0A= *** 298,304 ****=0A= if not buf:=0A= break=0A= file_size =3D file_size + len(buf)=0A= ! CRC =3D binascii.crc32(buf, CRC)=0A= if cmpr:=0A= buf =3D cmpr.compress(buf)=0A= compress_size =3D compress_size + len(buf)=0A= --- 307,313 ----=0A= if not buf:=0A= break=0A= file_size =3D file_size + len(buf)=0A= ! CRC =3D crc32(buf, CRC)=0A= if cmpr:=0A= buf =3D cmpr.compress(buf)=0A= compress_size =3D compress_size + len(buf)=0A= ***************=0A= *** 323,329 ****=0A= 'Write a file into the archive. The contents is the string = "bytes"'=0A= self._writecheck(zinfo)=0A= zinfo.file_size =3D len(bytes) # Uncompressed size=0A= ! zinfo.CRC =3D binascii.crc32(bytes) # CRC-32 checksum=0A= if zinfo.compress_type =3D=3D ZIP_DEFLATED:=0A= co =3D zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,=0A= zlib.DEFLATED, -15)=0A= --- 332,338 ----=0A= 'Write a file into the archive. The contents is the string = "bytes"'=0A= self._writecheck(zinfo)=0A= zinfo.file_size =3D len(bytes) # Uncompressed size=0A= ! zinfo.CRC =3D crc32(bytes) # CRC-32 checksum=0A= if zinfo.compress_type =3D=3D ZIP_DEFLATED:=0A= co =3D zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION,=0A= zlib.DEFLATED, -15)=0A= ------=_NextPart_000_0005_01BFDEF8.0AC1C530-- From guido@python.org Mon Jun 26 15:49:11 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 26 Jun 2000 09:49:11 -0500 Subject: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: Your message of "Fri, 23 Jun 2000 10:03:41 +0200." <395319DD.F2584321@lemburg.com> References: <395319DD.F2584321@lemburg.com> Message-ID: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> It's official: I've changed the patch submission guidelines (http://www.python.org/patches/) to point to the patch manager at SourceForge. We are no longer bound by CNRI's legal department, so the requirement for disclaimers or wet signatures is gone. We'll have to see how it works in practice. I've set the address where new patches are mailed to patches@python.org; this should send notifications to the patches list. We could change this to python-dev perhaps, so we can retire the patches address completely (giving it an auto-respond pointing to the SF patch manager, as barry suggested). There are several tasks to be assigned now: we need a triage person who should go through the list of new patches regularly to assign them to developers; we need developers who are willing to have patches assigned to them. We also need a consensus process to decide which patches will be allowed through. I'm hoping to experiment with SF in the coming days to come up with something. Finally, we still need to do something about the existing backlog of patches. The PythonLabs team will try to do something reasonable here. This is not the end -- it's the beginning! --Guido van Rossum (home page: http://www.python.org/~guido/) From noreply@sourceforge.net Mon Jun 26 15:24:16 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Mon, 26 Jun 2000 07:24:16 -0700 Subject: [Patches] [Patch #100637] get rid of warning in pythonrun.c Message-ID: <200006261424.HAA05584@delerium.i.sourceforge.net> Patch #100637 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100637&group_id=5470 From mal@lemburg.com Mon Jun 26 16:03:30 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Mon, 26 Jun 2000 17:03:30 +0200 Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager References: <395319DD.F2584321@lemburg.com> <200006261449.JAA01684@cj20424-a.reston1.va.home.com> Message-ID: <395770C2.B903724A@lemburg.com> Guido van Rossum wrote: > > It's official: I've changed the patch submission guidelines > (http://www.python.org/patches/) to point to the patch manager at > SourceForge. We are no longer bound by CNRI's legal department, so > the requirement for disclaimers or wet signatures is gone. > > We'll have to see how it works in practice. I've set the address > where new patches are mailed to patches@python.org; this should send > notifications to the patches list. We could change this to python-dev > perhaps, so we can retire the patches address completely (giving it an > auto-respond pointing to the SF patch manager, as barry suggested). Will there be a list which gets the patches mailed to it by SF ? I'm just asking because the current setup of having the patches available through mail really helps in discussing patch details. > There are several tasks to be assigned now: we need a triage person > who should go through the list of new patches regularly to assign them > to developers; we need developers who are willing to have patches > assigned to them. I'll volunteer for the Unicode side of things :-) > We also need a consensus process to decide which patches will be > allowed through. I'm hoping to experiment with SF in the coming days > to come up with something. > > Finally, we still need to do something about the existing backlog of > patches. The PythonLabs team will try to do something reasonable > here. > > This is not the end -- it's the beginning! -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From fdrake@beopen.com Mon Jun 26 17:04:40 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Mon, 26 Jun 2000 09:04:40 -0700 (PDT) Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: <395770C2.B903724A@lemburg.com> References: <395319DD.F2584321@lemburg.com> <200006261449.JAA01684@cj20424-a.reston1.va.home.com> <395770C2.B903724A@lemburg.com> Message-ID: <14679.32536.133849.573542@mailhost.beopen.com> M.-A. Lemburg writes: > Will there be a list which gets the patches mailed to it > by SF ? patches@python.org should get messages of patch manager activity (at least certain actions; not sure which ones yet, but at least additions). > I'm just asking because the current setup of having the patches > available through mail really helps in discussing patch details. Yes! I'd really hate to lose notifications! -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From tpeters@beopen.com Mon Jun 26 19:41:12 2000 From: tpeters@beopen.com (Tim Peters) Date: Mon, 26 Jun 2000 14:41:12 -0400 Subject: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> Message-ID: [Guido] > It's official: I've changed the patch submission guidelines > (http://www.python.org/patches/) to point to the patch manager at > SourceForge. We are no longer bound by CNRI's legal department, so > the requirement for disclaimers or wet signatures is gone. Yay! Wonder how long that will last . Attached is a first cut at documenting the intended use of SourceForge's patch status tags, and the workflow associated with patch status changes. The areas in need of fleshing out are marked with "[xxx ...]". Gripe at will. I don't think anyone expects this to work smoothly at first. Strive for patience, and let's work to make SF a really *good* place for patches! never-thought-i'd-actually-miss-lotus-notes-ly y'rs - tim PS: I'll move this (& related info) to a reasonable place eventually, so don't bother griping about email for now. Intended use of SourceForge patch status tags --------------------------------------------- revision 1 26-Jun-2000 Open The initial status of all patches. The patch is under consideration, but has not been reviewed yet. The status will normally change to Accepted or Rejected next. The person submitting the patch should (if they can) assign it to the person they most want to review it. Else the patch will be assigned via [xxx a list of expertise areas should be developed] Discussion of patches is carried out via [xxx Python-Dev? patches list? without a mail gateway, the SourceForge patch interface looks too clumsy to use for controversial patches] Accepted The powers that be have accepted the patch, but it has not been applied yet. [xxx flesh out -- Guido Bottleneck avoidable here?] The status will normally change to Closed next. The person changing the status to Accepted should, at the same time, assign the patch to whoever they believe is most likely to be able & willing to apply it (the submitter if possible). Closed The patch has been accepted and applied. The previous status was Accepted, or possibly Open if the submitter was Guido (or moral equivalent in some particular area of expertise). If possible, the submitter should apply the patch and change the status to Closed. Else anyone with sufficient power should feel encouraged to do these on the submitter's behalf. Rejected The patch has been reviewed and rejected. When the objections are addressed, the status may change to Open again. Note that SourceForge allows the submitter to overwrite the patch with a new version. Out of date Previous status was Open or Accepted or Postponed, but the patch no longer works. Please enter a comment when changing the status to "Out of date", to record the nature of the problem and the previous status. Postponed The previous status was Open or Accepted, but for some reason (e.g., pending release) the patch should not be reviewed or applied until further notice. The status will normally change to Open or Accepted next. Please enter a comment when changing the status to Postponed, to record the reason, the previous status, and the conditions under which the patch should revert to Open or Accepted. Deleted Bit bucket. Use only if it's OK for the patch and its SourceForge history to disappear. As of 26-June-2000, SF does not actually throw away Deleted patches, but that may change. From tpeters@beopen.com Mon Jun 26 20:19:58 2000 From: tpeters@beopen.com (Tim Peters) Date: Mon, 26 Jun 2000 15:19:58 -0400 Subject: [Patches] RE: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: <395770C2.B903724A@lemburg.com> Message-ID: [MAL] > Will there be a list which gets the patches mailed to it > by SF ? > > I'm just asking because the current setup of having the patches > available through mail really helps in discussing patch details. I agree -- SF isn't (yet) good for patch discussions. Plugging away, but haven't yet figured out exactly when or how SF decides to send email. In particular, don't yet know how (or whether it's possible) to trick current SF into populating a mailing list. From fdrake@beopen.com Mon Jun 26 23:25:42 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Mon, 26 Jun 2000 15:25:42 -0700 (PDT) Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: References: <14679.32536.133849.573542@mailhost.beopen.com> Message-ID: <14679.55398.996503.269852@mailhost.beopen.com> Tim Peters writes: > Fred, would you please explain how that works or where that was set up? > I've puttered away many hours now playing with the SourceForge facilities From the "project page", go to "Project Admin" on the left navigation bar, then "Edit Public Info" at the top of the page. There are places to edit some email addresses near the bottom of the page. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From tpeters@beopen.com Mon Jun 26 22:38:51 2000 From: tpeters@beopen.com (Tim Peters) Date: Mon, 26 Jun 2000 17:38:51 -0400 Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: <14679.32536.133849.573542@mailhost.beopen.com> Message-ID: [Fred] > patches@python.org should get messages of patch manager activity (at > least certain actions; not sure which ones yet, but at least > additions). Fred, would you please explain how that works or where that was set up? I've puttered away many hours now playing with the SourceForge facilities (alas, most of that time waiting for web pages to load), but haven't stumbled into anything that hints the patch manager knows anything about patches@python.org. so-stupid-in-so-many-ways-ly y'rs - tim From tpeters@beopen.com Tue Jun 27 00:14:06 2000 From: tpeters@beopen.com (Tim Peters) Date: Mon, 26 Jun 2000 19:14:06 -0400 Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: <14679.55398.996503.269852@mailhost.beopen.com> Message-ID: [Fred L. Drake, Jr.] > From the "project page", go to "Project Admin" on the left > navigation bar, then "Edit Public Info" at the top of the page. There > are places to edit some email addresses near the bottom of the page. Aha! The one & only link I had never clicked -- I bet I could have figured that out myself in another week or two . Thank you. Now why do we have "Use Bug Tracker" checked? If nobody objects, I'll turn that off -- we're still doing bugs w/ Jitterbug on python.org. ten-stop-shopping-ly y'rs - tim From jeremy@beopen.com Mon Jun 26 18:18:28 2000 From: jeremy@beopen.com (Jeremy Hylton) Date: Mon, 26 Jun 2000 13:18:28 -0400 (EDT) Subject: [Patches] PyObject_GetAttr/PyObject_SetAttr core dumps if given non-string names In-Reply-To: References: <20000622193610.27452.qmail@eik.g.aas.no> <395272D0.B82A0353@lemburg.com> <39531A20.1BEAA51E@lemburg.com> <14675.30233.658776.764865@localhost.localdomain> Message-ID: <14679.36964.766774.864078@localhost.localdomain> >>>>> "GA" == Gisle Aas writes: GA> Jeremy Hylton writes: >> Do you have a pure-Python test case that causes the new code to >> be executed? GA> No. If I call the python level getattr() then it will demand GA> that the second argument is a string. This is probably also the GA> reason this has not been a problem for "normal" people. Ok. I was looking for a test case to include in the test suite. I've made the change, but it looks like it will have to go without an accompanying test. Jeremy From billtut@microsoft.com Tue Jun 27 07:57:25 2000 From: billtut@microsoft.com (Bill Tutt) Date: Mon, 26 Jun 2000 23:57:25 -0700 Subject: [Patches] \N{..} Unicode CharacterName expansion patch Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD239@RED-MSG-50> has been posted to Sourceforge. FYI, Bill From mal@lemburg.com Tue Jun 27 13:13:33 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 27 Jun 2000 14:13:33 +0200 Subject: [Patches] New Unicode Character Name \N{..} patches References: <4D0A23B3F74DD111ACCD00805F31D8101D8BD233@RED-MSG-50> Message-ID: <39589A6D.B07C4A9F@lemburg.com> [New version of the patch] Great work :-) Some minor nits: * I think the inclusion of strnicmp will cause more compiler problems than do good -- why not simply inline the code in the one spot that needs it in unicodeobject.c ? * The typedefs in ucnhash.h should probably have the _Py_ prefix to make it clear that the code is part of the Python dist. Could you submit this as patch to the SF patch manager (with the new files included) ?! Thanks, -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From guido@beopen.com Tue Jun 27 15:30:30 2000 From: guido@beopen.com (Guido van Rossum) Date: Tue, 27 Jun 2000 09:30:30 -0500 Subject: [Patches] Re: [Python-Dev] Let's use the SourceForge Patch Manager In-Reply-To: Your message of "Mon, 26 Jun 2000 17:38:51 -0400." References: Message-ID: <200006271430.JAA01769@cj20424-a.reston1.va.home.com> > [Fred] > > patches@python.org should get messages of patch manager activity (at > > least certain actions; not sure which ones yet, but at least > > additions). [Tim] > Fred, would you please explain how that works or where that was set up? > I've puttered away many hours now playing with the SourceForge facilities > (alas, most of that time waiting for web pages to load), but haven't > stumbled into anything that hints the patch manager knows anything about > patches@python.org. Yes, it's hidden, and Fred had to show me too. First, login to SourceForge. Then, go to the Python Project. In the left sidebar, under Project: Python, go to Project Admin. Near the top, you now see some navigation links; go to Edit Public Info. At the very bottom there are three text fields for email addresses. The address for New Patches (a misnomer -- it's really all changes made to the Patch Manager) says patches@python.org. The address for New Bugs is currently set to guido@beopen.com. I suppose I should set it to pythoneers@beopen.com or even to python-dev@python.org? We're not using the Support manager yet. --Guido van Rossum (home page: http://www.python.org/~guido/) From trentm@activestate.com Tue Jun 27 18:16:58 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 27 Jun 2000 10:16:58 -0700 Subject: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: References: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> Message-ID: <20000627101658.E7257@activestate.com> On Mon, Jun 26, 2000 at 02:41:12PM -0400, Tim Peters wrote: > Intended use of SourceForge patch status tags > --------------------------------------------- > revision 1 26-Jun-2000 > > > Open > The initial status of all patches. > The patch is under consideration, but has not > been reviewed yet. > The status will normally change to Accepted or Rejected next. > The person submitting the patch should (if they can) assign > it to the person they most want to review it. > Else the patch will be assigned via > [xxx a list of expertise areas should be developed] What are the chances of getting other meta data fields on patches, i.e. changes to the patch manager? Categorizing patches could really help as a filter. For instance, I may be a Unicode genius and would like to see the patches associated with it. > Discussion of patches is carried out via > [xxx Python-Dev? patches list? without a mail gateway, > the SourceForge patch interface looks too clumsy > to use for controversial patches] I like the separation of python-dev and patches, but it is not a biggie for me. > Postponed > The previous status was Open or Accepted, but for some reason > (e.g., pending release) the patch should not be reviewed or > applied until further notice. > The status will normally change to Open or Accepted next. > Please enter a comment when changing the status to Postponed, > to record the reason, the previous status, and the conditions > under which the patch should revert to Open or Accepted. Perhaps ownership (i.e. 'assigned to') of the patch should transfer to the person responsible for later taking to patch out of 'postponed' status. Trent -- Trent Mick trentm@activestate.com From noreply@sourceforge.net Tue Jun 27 20:39:35 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Tue, 27 Jun 2000 12:39:35 -0700 Subject: [Patches] [Patch #100650] SRE: pickling support (see comment) Message-ID: <200006271939.MAA24307@bush.i.sourceforge.net> Patch #100650 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100650&group_id=5470 From guido@beopen.com Tue Jun 27 22:11:46 2000 From: guido@beopen.com (Guido van Rossum) Date: Tue, 27 Jun 2000 16:11:46 -0500 Subject: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: Your message of "Tue, 27 Jun 2000 10:16:58 MST." <20000627101658.E7257@activestate.com> References: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> <20000627101658.E7257@activestate.com> Message-ID: <200006272111.QAA04542@cj20424-a.reston1.va.home.com> > What are the chances of getting other meta data fields on patches, i.e. > changes to the patch manager? Categorizing patches could really help as a > filter. For instance, I may be a Unicode genius and would like to see the > patches associated with it. Good idea. The PM clearly needs work. I see two places where you could submit feature requests: (1) the "Report SF Bug" item in the left side bar; (2) the "Feature Requests" discussion forum (http://sourceforge.net/forum/forum.php?forum_id=4&et=0) > I like the separation of python-dev and patches, but it is not a biggie for > me. For me it's just an annoyance, especially when cross-posting is used. --Guido van Rossum (home page: http://www.python.org/~guido/) From fdrake@beopen.com Tue Jun 27 22:01:54 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 27 Jun 2000 17:01:54 -0400 (EDT) Subject: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: <20000627101658.E7257@activestate.com> References: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> <20000627101658.E7257@activestate.com> Message-ID: <14681.5698.732269.523890@cj42289-a.reston1.va.home.com> Trent Mick writes: > Perhaps ownership (i.e. 'assigned to') of the patch should transfer to the > person responsible for later taking to patch out of 'postponed' status. Agreed; assignment should be changed whenever the next person required to deal with it changes. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 01:00:21 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 02:00:21 +0200 (CEST) Subject: [Patches] getargs.c In-Reply-To: <20000617202459.B20019@activestate.com> from "Trent Mick" at Jun 17, 2000 08:24:59 PM Message-ID: <200006280000.CAA01569@python.inrialpes.fr> Trent Mick wrote: > > On Sun, Jun 18, 2000 at 01:37:35AM +0200, Vladimir Marangozov wrote: > > > > So, as far as > > such patches don't hurt the semantics of the code, they are fine. > > > > Seconded. +1 > > Plus you are fixing my poor formatting. That is always good for me. :) > > Cheers, > Trent Patch moved to SourceForge with a summary of the issue. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 02:02:07 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 03:02:07 +0200 (CEST) Subject: [Patches] GC patch 3 and 4 In-Reply-To: <20000614133900.A22867@acs.ucalgary.ca> from "Neil Schemenauer" at Jun 14, 2000 01:39:00 PM Message-ID: <200006280102.DAA01678@python.inrialpes.fr> I'm concerned about the following with these patches: 1. The PyObject_GC API This is related with #2 below. As it was discussed previously, PyObject_GC_NEW is useless. I think that the same applies to PyObject_GC_DEL - we don't need it. I'd suggest to officialize the following API -- better names are welcome: PyObject_FROM_GC(gp) - returns a pointer to a Python object given a pointer to a GC_INFO struct. This is the current PyGC_INFO macro. PyObject_AS_GC(op) - returns a pointer to a GC_INFO struct given an object pointer. This is the reverse macro (the current PyGC_OBJ macro) PyObject_GC_Init(op) - init an object for GC (usually, at the end of the constructor, cf. comments in objimpl.h) PyObject_GC_Fini(op) - finalize an object subject to GC (usually, in the beginning of the destructor, cf. objimpl.h) BTW, I'd really prefer a more Pythonic name for GC_INFO, like GC_HEAD as per Greg Stein's comments on these patches. 2. Extension types that participate in GC The GC code implemented in the (core) object constructors is #ifdef'ed which is not what one is expected to do for custom extension types. If I am about to implement a GC'd type with the proposed patches, I'll have to #ifdef things which is not really what I want. GC or not, I'd prefer to see the same code in the object constructors and destructors (be they core or extension objects). PyObject_GC_Init/Fini are fine. They are empty macros without GC, so why not using the same approach for the inlined #ifdef'ed code? For example, the PyList_New code reads: ... if (op == NULL) { return PyErr_NoMemory(); } #ifdef WITH_CYCLE_GC op = (PyListObject *) PyGC_OBJ((PyGCInfo *)op); #endif ... I'd expect to see something like this instead: ... if (op == NULL) { return PyErr_NoMemory(); } op = (PyListObject *) PyObject_FROM_GC(op); ... where: #ifdef WITH_CYCLE_GC #define PyObject_FROM_GC(gp) PyGC_INFO((PyGCInfo *)(gp)) #else #define PyObject_FROM_GC(gp) (gp) #endif The same goes for the object destructors, where PyObject_GC_DEL(op) would be replaced by: op = PyObject_AS_GC(op); PyObject_DEL(op) Neil Schemenauer wrote: [snip] > > + /* > + * Garbage Collection Support > + * ========================== > + */ > > + /* To make a new object participate in garbage collection use > + PyObject_{New, VarNew, Del} to manage the memory. Set the type flag ^^^^^^ NewVar > + Py_TPFLAGS_GC and define the type method tp_recurse. You should also > + add the method tp_clear if your object is mutable. Include > + PyGC_INFO_SIZE in the calculation of tp_basicsize. Call > + PyObject_GC_Init after the pointers followed by tp_recurse become > + valid (usually just before returning the object from the allocation > + method. Call PyObject_GC_Fini before those pointers become invalid > + (usually at the top of the deallocation method). */ > [snip] -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From nascheme@enme.ucalgary.ca Wed Jun 28 02:41:36 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Tue, 27 Jun 2000 19:41:36 -0600 Subject: [Patches] GC patch 3 and 4 In-Reply-To: <200006280102.DAA01678@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Wed, Jun 28, 2000 at 03:02:07AM +0200 References: <20000614133900.A22867@acs.ucalgary.ca> <200006280102.DAA01678@python.inrialpes.fr> Message-ID: <20000627194136.A5109@acs.ucalgary.ca> On Wed, Jun 28, 2000 at 03:02:07AM +0200, Vladimir Marangozov wrote: > I'd suggest to officialize the following API -- better names are welcome: > > PyObject_FROM_GC(gp) - returns a pointer to a Python object given a > pointer to a GC_INFO struct. This is the current > PyGC_INFO macro. > > PyObject_AS_GC(op) - returns a pointer to a GC_INFO struct given an > object pointer. This is the reverse macro > (the current PyGC_OBJ macro) > > PyObject_GC_Init(op) - init an object for GC (usually, at the end of the > constructor, cf. comments in objimpl.h) > > PyObject_GC_Fini(op) - finalize an object subject to GC (usually, in the > beginning of the destructor, cf. objimpl.h) > > BTW, I'd really prefer a more Pythonic name for GC_INFO, like GC_HEAD > as per Greg Stein's comments on these patches. Those look fine to me. The original names came mostly from code by Guido. Does anyone want to vote on this? If not, I will use the names Vladimir suggests. > 2. Extension types that participate in GC > > The GC code implemented in the (core) object constructors is #ifdef'ed > which is not what one is expected to do for custom extension types. > If I am about to implement a GC'd type with the proposed patches, I'll > have to #ifdef things which is not really what I want. Aren't extensions supposed to use the function APIs? If so, there are no ifdefs. > #ifdef WITH_CYCLE_GC > #define PyObject_FROM_GC(gp) PyGC_INFO((PyGCInfo *)(gp)) > #else > #define PyObject_FROM_GC(gp) (gp) > #endif Okay, I understand how you are thinking of getting rid of PyObject_GC_DEL. I will resubmit a patch with these changes. Neil -- Real programmers don't make mistrakes From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 04:10:22 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 05:10:22 +0200 (CEST) Subject: [Patches] GC patch 3 and 4 In-Reply-To: <20000627194136.A5109@acs.ucalgary.ca> from "Neil Schemenauer" at Jun 27, 2000 07:41:36 PM Message-ID: <200006280310.FAA02252@python.inrialpes.fr> Neil Schemenauer wrote: > > [me] > > 2. Extension types that participate in GC > > > > The GC code implemented in the (core) object constructors is #ifdef'ed > > which is not what one is expected to do for custom extension types. > > If I am about to implement a GC'd type with the proposed patches, I'll > > have to #ifdef things which is not really what I want. > > Aren't extensions supposed to use the function APIs? If so, > there are no ifdefs. In the "normal" case, when using PyObject_New, yes. I was thinking about the rare cases when PyObject_New needs to be inlined in the object constructor of the extension type, as it is done in the core. In short, we'd better provide the primitives hidden in PyObject_New/NewVar/Del for the developer who needs to go at a lower level for customizing objects, mallocs, etc. For that matter, PyGC_TYPE_HAS_INFO(tp) has to be exported in the public API too, probably under a more friendly name, like PyObject_Check_GC(op) (or better) which would be defined as PyType_HAS_GC(op->ob_type), equivalent to the PyGC_TYPE_HAS_INFO(op->ob_type) ... But I agree that the above statement of mine doesn't reflect exactly what I was thinking about :) -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From nascheme@enme.ucalgary.ca Wed Jun 28 04:11:56 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Tue, 27 Jun 2000 21:11:56 -0600 Subject: [Patches] GC patch 3 and 4 In-Reply-To: <200006280310.FAA02252@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Wed, Jun 28, 2000 at 05:10:22AM +0200 References: <20000627194136.A5109@acs.ucalgary.ca> <200006280310.FAA02252@python.inrialpes.fr> Message-ID: <20000627211156.A18253@acs.ucalgary.ca> On Wed, Jun 28, 2000 at 05:10:22AM +0200, Vladimir Marangozov wrote: > For that matter, PyGC_TYPE_HAS_INFO(tp) has to be exported in the public > API too, probably under a more friendly name, like PyObject_Check_GC(op) > (or better) which would be defined as PyType_HAS_GC(op->ob_type), equivalent > to the PyGC_TYPE_HAS_INFO(op->ob_type) ... I changed them to PyType_IS_GC and PyObject_IS_GC. Neil From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 06:17:40 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 07:17:40 +0200 (CEST) Subject: [Patches] Revised patch for import.c In-Reply-To: <394015D2.A29350BA@oratrix.com> from "Jack Jansen" at Jun 08, 2000 11:53:23 PM Message-ID: <200006280517.HAA02553@python.inrialpes.fr> Jack Jansen wrote: > > Here's a new version of my previous patch to import.c, using #elif in stead of > nested #ifdefs. > > Use a different way to compare pyc filenames, on the mac only, making it easier > to port to macosx. Jack, the HAVE_STAT_H symbol does not have an entry in the usual config.h file, so my guess is that you have a Mac-specific version of it that you are maintaining and that I can't eyeball. Is this correct? If yes, I don't see anything wrong with this patch because there's no way it can interfere with other systems. So, +1 from me. If you don't move it to SourceForge quickly and nobody applies it in the meantime, I'll move it to SF for you. > > Index: import.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Python/import.c,v > retrieving revision 2.134 > diff -c -r2.134 import.c > *** import.c 2000/05/03 23:44:39 2.134 > --- import.c 2000/06/08 21:50:24 > *************** > *** 60,65 **** > --- 60,67 ---- > #endif > #ifndef DONT_HAVE_SYS_STAT_H > #include > + #elif defined(HAVE_STAT_H) > + #include > #endif > > #if defined(PYCC_VACPP) > *************** > *** 1132,1139 **** > name, buf); > return 0; > } > ! p2cstr(fss.name); > ! if ( strncmp(name, (char *)fss.name, namelen) != 0 ) { > PyErr_Format(PyExc_NameError, > "Case mismatch for module name %.100s\n(filename %.300s)", > name, fss.name); > --- 1134,1140 ---- > name, buf); > return 0; > } > ! if ( namelen > fss.name[0] || strncmp(name, (char *)fss.name+1, namelen) != > 0 ) { > PyErr_Format(PyExc_NameError, > "Case mismatch for module name %.100s\n(filename %.300s)", > name, fss.name); > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches > -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 07:10:41 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 08:10:41 +0200 (CEST) Subject: [Patches] protection for marshalling recursive data structures In-Reply-To: from "Michael Hudson" at Jun 19, 2000 01:20:50 AM Message-ID: <200006280610.IAA02626@python.inrialpes.fr> Michael Hudson wrote: > > As I really do not have anything better to do at the moment, I've written > a patch to Python/marshal.c that prevents Python dumping core when trying > to marshal stack bustingly deep (or recursive) data structure. > > It just throws an exception; even slightly clever handling of recursive > data is what pickle is for... I have submitted a patch for this either; see "marshalling recursive objects" dated May 12-13 on the patches list. The solution I proposed is more heavyweight than this one because it effectively detects cyclic references. As Guido noted at that time, my version changed the existing marshal semantics because I wanted to marshal recursive objects a la pickle. To which I replied that I have a corrected version which preserves the existing semantics and asked for advice on what version to resubmit, out of two: a) accept marshalling recursive objects with backwards compatibility or b) reject recursive objects by raising an exception. And this is where the story ended at that time. So it boils down to which one of these three is most appropriate: 1. Your solution (lightweight) based on a fixed watermark value without effectively detecting cyclic references 2. Detect cyclic objects and reject them by raising an exception 3. Detect cyclic objects and accept them by introducing a new marshal type code 'o' just like pickle does. #2 & #3 are more heavy as they require tracking the currently marshalled objects in a dict (or a list). A priori, #3 is out of scope as it does too much and overlaps pickle. So my guess is that Guido has to decide which one he prefers (#1 or #2). If you're not Guido, you may want to chime in too with an opinion. #2 hasn't been posted anywhere as I waited for Guido's response... > > Index: marshal.c > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Python/marshal.c,v > retrieving revision 1.47 > diff -u -r1.47 marshal.c > --- marshal.c 2000/05/03 23:44:39 1.47 > +++ marshal.c 2000/06/19 00:18:44 > @@ -58,6 +58,7 @@ > typedef struct { > FILE *fp; > int error; > + int depth; > /* If fp == NULL, the following are valid: */ > PyObject *str; > char *ptr; > @@ -144,8 +145,13 @@ > { > int i, n; > PyBufferProcs *pb; > + > + p->depth++; > > - if (v == NULL) { > + if (p->depth > 5000) { > + p->error = 2; > + } > + else if (v == NULL) { > w_byte(TYPE_NULL, p); > } > else if (v == Py_None) { > @@ -301,6 +307,7 @@ > WFILE wf; > wf.fp = fp; > wf.error = 0; > + wf.depth = 0; > w_long(x, &wf); > } > > @@ -690,6 +697,7 @@ > wf.ptr = PyString_AS_STRING((PyStringObject *)wf.str); > wf.end = wf.ptr + PyString_Size(wf.str); > wf.error = 0; > + wf.depth = 0; > w_object(x, &wf); > if (wf.str != NULL) > _PyString_Resize(&wf.str, > @@ -697,7 +705,9 @@ > PyString_AS_STRING((PyStringObject *)wf.str))); > if (wf.error) { > Py_XDECREF(wf.str); > - PyErr_SetString(PyExc_ValueError, "unmarshallable object"); > + PyErr_SetString(PyExc_ValueError, > + (wf.error==1)?"unmarshallable object" > + :"object too deeply nested to marshal"); > return NULL; > } > return wf.str; > @@ -724,9 +734,12 @@ > wf.str = NULL; > wf.ptr = wf.end = NULL; > wf.error = 0; > + wf.depth = 0; > w_object(x, &wf); > if (wf.error) { > - PyErr_SetString(PyExc_ValueError, "unmarshallable object"); > + PyErr_SetString(PyExc_ValueError, > + (wf.error==1)?"unmarshallable object" > + :"object too deeply nested to marshal"); > return NULL; > } > Py_INCREF(Py_None); > > On my machine, it seems an unpatched marshal blows up at a depth of about > 13000, so I hope 5000 is OK almost everywhere. > > I confirm that, to the best of my knowledge and belief, this > contribution is free of any claims of third parties under > copyright, patent or other rights or interests ("claims"). To > the extent that I have any such claims, I hereby grant to CNRI a > nonexclusive, irrevocable, royalty-free, worldwide license to > reproduce, distribute, perform and/or display publicly, prepare > derivative versions, and otherwise use this contribution as part > of the Python software and its related documentation, or any > derivative versions thereof, at no cost to CNRI or its licensed > users, and to authorize others to do so. > > I acknowledge that CNRI may, at its sole discretion, decide > whether or not to incorporate this contribution in the Python > software and its related documentation. I further grant CNRI > permission to use my name and other identifying information > provided to CNRI by me for use in connection with the Python > software and its related documentation. > > Cheers, > M. > > > _______________________________________________ > Patches mailing list > Patches@python.org > http://www.python.org/mailman/listinfo/patches > -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From noreply@sourceforge.net Wed Jun 28 10:39:42 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 02:39:42 -0700 Subject: [Patches] [Patch #100656] adds CVS files to sdist.prune_file_list() Message-ID: <200006280939.CAA16978@delerium.i.sourceforge.net> Patch #100656 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100656&group_id=5470 From noreply@sourceforge.net Wed Jun 28 10:52:03 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 02:52:03 -0700 Subject: [Patches] [Patch #100657] SRE: towards 1.6b1 Message-ID: <200006280952.CAA17295@delerium.i.sourceforge.net> Patch #100657 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100657&group_id=5470 From noreply@sourceforge.net Wed Jun 28 10:57:52 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 02:57:52 -0700 Subject: [Patches] [Patch #100658] SRE: towards 1.6b1 Message-ID: <200006280957.CAA17465@delerium.i.sourceforge.net> Patch #100658 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100658&group_id=5470 From billtut@microsoft.com Wed Jun 28 11:49:45 2000 From: billtut@microsoft.com (Bill Tutt) Date: Wed, 28 Jun 2000 03:49:45 -0700 Subject: [Patches] New Unicode Character Name \N{..} patches Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD23F@RED-MSG-50> I've tossed the new patch into the SF patch manager by updating #100642. Bill -----Original Message----- From: M.-A. Lemburg [mailto:mal@lemburg.com] Sent: Tuesday, June 27, 2000 5:14 AM To: Bill Tutt Cc: 'patches@python.org' Subject: Re: [Patches] New Unicode Character Name \N{..} patches [New version of the patch] Great work :-) Some minor nits: * I think the inclusion of strnicmp will cause more compiler problems than do good -- why not simply inline the code in the one spot that needs it in unicodeobject.c ? * The typedefs in ucnhash.h should probably have the _Py_ prefix to make it clear that the code is part of the Python dist. Could you submit this as patch to the SF patch manager (with the new files included) ?! Thanks, -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From noreply@sourceforge.net Wed Jun 28 11:56:30 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 03:56:30 -0700 Subject: [Patches] [Patch #100659] Allows sdist to work with old-style extensions Message-ID: <200006281056.DAA19211@delerium.i.sourceforge.net> Patch #100659 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100659&group_id=5470 From guido@beopen.com Wed Jun 28 16:27:16 2000 From: guido@beopen.com (Guido van Rossum) Date: Wed, 28 Jun 2000 10:27:16 -0500 Subject: [Patches] protection for marshalling recursive data structures In-Reply-To: Your message of "Wed, 28 Jun 2000 08:10:41 +0200." <200006280610.IAA02626@python.inrialpes.fr> References: <200006280610.IAA02626@python.inrialpes.fr> Message-ID: <200006281527.KAA01980@cj20424-a.reston1.va.home.com> > 1. Your solution (lightweight) based on a fixed watermark value without > effectively detecting cyclic references > 2. Detect cyclic objects and reject them by raising an exception > 3. Detect cyclic objects and accept them by introducing a new marshal > type code 'o' just like pickle does. > > #2 & #3 are more heavy as they require tracking the currently marshalled > objects in a dict (or a list). A priori, #3 is out of scope as it does too > much and overlaps pickle. > > So my guess is that Guido has to decide which one he prefers (#1 or #2). > If you're not Guido, you may want to chime in too with an opinion. > > #2 hasn't been posted anywhere as I waited for Guido's response... I'm for the lightweight #1... --Guido van Rossum (home page: http://www.python.org/~guido/) From Vladimir.Marangozov@inrialpes.fr Wed Jun 28 17:33:10 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 28 Jun 2000 18:33:10 +0200 (CEST) Subject: [Patches] GC patch 3 and 4 In-Reply-To: <20000627211156.A18253@acs.ucalgary.ca> from "Neil Schemenauer" at Jun 27, 2000 09:11:56 PM Message-ID: <200006281633.SAA03915@python.inrialpes.fr> Neil Schemenauer wrote: > > On Wed, Jun 28, 2000 at 05:10:22AM +0200, Vladimir Marangozov wrote: > > For that matter, PyGC_TYPE_HAS_INFO(tp) has to be exported in the public > > API too, probably under a more friendly name, like PyObject_Check_GC(op) > > (or better) which would be defined as PyType_HAS_GC(op->ob_type), equivalent > > to the PyGC_TYPE_HAS_INFO(op->ob_type) ... > > I changed them to PyType_IS_GC and PyObject_IS_GC. > > Neil Good. BTW, what about the macro/function differenciation regarding the GC API? For example, the memory API goes as follows: ------ Interface summary ================= Each memory interface exports both functions and macros. Functions preserve binary compatibility of the code across different releases while MACROS trade it for speed. Public API Functions MACROS -------------- ---------------------------- -------------------- 1) Core Memory Allocator (see mymalloc.h) - raw mem malloc PyMem_Malloc/Realloc/Free PyMem_MALLOC/REALLOC/FREE - type-oriented PyMem_New/Resize/Del PyMem_NEW/RESIZE/DEL 2) Core Object Memory Allocator & Facilities (see objimpl.h) - object malloc PyObject_Malloc/Realloc/Free PyObject_MALLOC/REALLOC/FREE - initialization PyObject_Init/InitVar PyObject_INIT/INIT_VAR - constr./destr. PyObject_New/NewVar/Del PyObject_NEW/NEW_VAR/DEL ------ In your opinion, what would that be for GC? Also, I don't think we need all the macros in objimpl.h. For instance, PyGC_INFO_UNSAFE seems unreasonable. Since it is a capitalized MACRO, it is supposed to be unsafe. Functions (or lowercased macros) are safe. Have you considered this issue? -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From nascheme@enme.ucalgary.ca Wed Jun 28 17:50:56 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 28 Jun 2000 10:50:56 -0600 Subject: [Patches] GC patch 3 and 4 In-Reply-To: <200006281633.SAA03915@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Wed, Jun 28, 2000 at 06:33:10PM +0200 References: <20000627211156.A18253@acs.ucalgary.ca> <200006281633.SAA03915@python.inrialpes.fr> Message-ID: <20000628105056.B12351@acs.ucalgary.ca> On Wed, Jun 28, 2000 at 06:33:10PM +0200, Vladimir Marangozov wrote: > BTW, what about the macro/function differenciation regarding the GC API? I don't fully understand your question. The GC API is as follows: functions for objects: PyObject_GC_Init - tell GC to track an object PyObject_GC_Fini - tell GC to stop tracking an object macros for objects: PyObject_AS_GC - convert from object pointer to GC pointer PyObject_FROM_GC - convert from GC pointer to object pointer test macros: PyType_IS_GC - true if objects of type have GC header PyObject_IS_GC - true of object has GC header The major problem I see with the current API is that PyObject_NEW and PyObject_DEL are not symmetric. When GC is enabled PyObject_NEW returns an object pointer while PyObject_DEL takes a GC pointer. > Also, I don't think we need all the macros in objimpl.h. For instance, > PyGC_INFO_UNSAFE seems unreasonable. Since it is a capitalized MACRO, > it is supposed to be unsafe. Functions (or lowercased macros) are safe. It probably can be removed now. The safe version was for debugging. Neil From guido@beopen.com Tue Jun 27 22:11:46 2000 From: guido@beopen.com (Guido van Rossum) Date: Tue, 27 Jun 2000 16:11:46 -0500 Subject: [Python-Dev] Re: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: Your message of "Tue, 27 Jun 2000 10:16:58 MST." <20000627101658.E7257@activestate.com> References: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> <20000627101658.E7257@activestate.com> Message-ID: <200006272111.QAA04542@cj20424-a.reston1.va.home.com> > What are the chances of getting other meta data fields on patches, i.e. > changes to the patch manager? Categorizing patches could really help as a > filter. For instance, I may be a Unicode genius and would like to see the > patches associated with it. Good idea. The PM clearly needs work. I see two places where you could submit feature requests: (1) the "Report SF Bug" item in the left side bar; (2) the "Feature Requests" discussion forum (http://sourceforge.net/forum/forum.php?forum_id=4&et=0) > I like the separation of python-dev and patches, but it is not a biggie for > me. For me it's just an annoyance, especially when cross-posting is used. --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://www.python.org/mailman/listinfo/python-dev From fdrake@beopen.com Tue Jun 27 22:01:54 2000 From: fdrake@beopen.com (Fred L. Drake, Jr.) Date: Tue, 27 Jun 2000 17:01:54 -0400 (EDT) Subject: [Python-Dev] Re: [Patches] Let's use the SourceForge Patch Manager In-Reply-To: <20000627101658.E7257@activestate.com> References: <200006261449.JAA01684@cj20424-a.reston1.va.home.com> <20000627101658.E7257@activestate.com> Message-ID: <14681.5698.732269.523890@cj42289-a.reston1.va.home.com> Trent Mick writes: > Perhaps ownership (i.e. 'assigned to') of the patch should transfer to the > person responsible for later taking to patch out of 'postponed' status. Agreed; assignment should be changed whenever the next person required to deal with it changes. -Fred -- Fred L. Drake, Jr. BeOpen PythonLabs Team Member _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://www.python.org/mailman/listinfo/python-dev From noreply@sourceforge.net Wed Jun 28 20:20:55 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 12:20:55 -0700 Subject: [Patches] [Patch #100664] Fix for bug no. 48 (Annoyance in ftpmirror.py script) Message-ID: <200006281920.MAA02218@bush.i.sourceforge.net> Patch #100664 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100664&group_id=5470 From noreply@sourceforge.net Wed Jun 28 21:23:13 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 13:23:13 -0700 Subject: [Patches] [Patch #100665] Support for conditional inclusion of methods and functions Message-ID: <200006282023.NAA04120@bush.i.sourceforge.net> Patch #100665 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100665&group_id=5470 From noreply@sourceforge.net Wed Jun 28 21:26:56 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 13:26:56 -0700 Subject: [Patches] [Patch #100666] Removed Macintosh tab-guessing code Message-ID: <200006282026.NAA05385@delerium.i.sourceforge.net> Patch #100666 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100666&group_id=5470 From noreply@sourceforge.net Wed Jun 28 21:29:32 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 13:29:32 -0700 Subject: [Patches] [Patch #100667] Removed support for long-dead Think C compiler Message-ID: <200006282029.NAA05429@delerium.i.sourceforge.net> Patch #100667 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100667&group_id=5470 From noreply@sourceforge.net Wed Jun 28 21:31:47 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 13:31:47 -0700 Subject: [Patches] [Patch #100668] Mac Carbon: don't include sys/types if we don't have it Message-ID: <200006282031.NAA05555@delerium.i.sourceforge.net> Patch #100668 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100668&group_id=5470 From noreply@sourceforge.net Wed Jun 28 23:06:33 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 15:06:33 -0700 Subject: [Patches] [Patch #100670] Use include "" in stead of <> and staticforward declarations Message-ID: <200006282206.PAA07358@bush.i.sourceforge.net> Patch #100670 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100670&group_id=5470 From Vladimir.Marangozov@inrialpes.fr Thu Jun 29 04:20:35 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Thu, 29 Jun 2000 05:20:35 +0200 (CEST) Subject: [Patches] GC patch 3 and 4 In-Reply-To: <20000628105056.B12351@acs.ucalgary.ca> from "Neil Schemenauer" at Jun 28, 2000 10:50:56 AM Message-ID: <200006290320.FAA20221@python.inrialpes.fr> Neil Schemenauer wrote: > > On Wed, Jun 28, 2000 at 06:33:10PM +0200, Vladimir Marangozov wrote: > > BTW, what about the macro/function differenciation regarding the GC API? > > I don't fully understand your question. The GC API is as > follows: I asked because you know that code by heart, which is probably not my case, and I wanted to be in sync with you. I haven't seen the need for API function/macro pairs either (with their respective differences)... > The major problem I see with the current API is that PyObject_NEW > and PyObject_DEL are not symmetric. When GC is enabled > PyObject_NEW returns an object pointer while PyObject_DEL takes a > GC pointer. I see. Would it make sense for PyObject_NEW to return the GC pointer ? (only if the object type supports GC). If so, it would be followed systematically (for GC objects) by op = PyObject_FROM_GC(op), and we get the symmetry. We're talking about the macros after all. Extension types are not supposed to use them. Only pre-1.6 extensions (may) use them, but they do not have GC. Only the core + eventual customized extension types will use the macros, whenever they inline these things, but then, if they want GC, they'll have to convert the pointers explicitely after _NEW and before _DEL. In the normal use cases, the functions, _New and _Del perform the conversions automatically. This pb comes from the fact that only a subset of the objects are GC'd but we want to use the same API for all objects. The above is probably a good compromise. All this really boils down to what you've implemented from the start, i.e. have PyObject_GC_NEW and _GC_DEL, but there are no _GC_New and _GC_Del function equivalents and this is most probably the cause of my original gripe about _GC_NEW and _GC_DEL ... -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From nascheme@enme.ucalgary.ca Thu Jun 29 06:22:32 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 28 Jun 2000 23:22:32 -0600 Subject: [Patches] GC patch 3 and 4 In-Reply-To: <200006290320.FAA20221@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Thu, Jun 29, 2000 at 05:20:35AM +0200 References: <20000628105056.B12351@acs.ucalgary.ca> <200006290320.FAA20221@python.inrialpes.fr> Message-ID: <20000628232232.A18845@acs.ucalgary.ca> On Thu, Jun 29, 2000 at 05:20:35AM +0200, Vladimir Marangozov wrote: > Neil Schemenauer wrote: > > The major problem I see with the current API is that PyObject_NEW > > and PyObject_DEL are not symmetric. When GC is enabled > > PyObject_NEW returns an object pointer while PyObject_DEL takes a > > GC pointer. > > I see. Would it make sense for PyObject_NEW to return the GC pointer ? > (only if the object type supports GC). I would say that's a step in the wrong direction. Since the PyObject_Init code has to access the object structure two conversions would have to be done. Also, I don't like that part of the implementation leaking out. If PyObject_DEL could be made a statement instead of an expression then something like: #ifdef WITH_CYCLE_GC #define PyObject_DEL(op) do { \ if (PyObject_IS_GC(op)) { \ PyObject_FREE(PyObject_AS_GC(op)); \ } else { \ PyObject_FREE(op); \ } \ } while (0); #else #define PyObject_DEL(op) PyObject_FREE(op) #endif would do the trick. The PyObject_AS_GC garbage in types could then be dropped. A quick look at the code indicates that PyObject_DEL as a statement would be okay for the types supporting GC. Could this work? Is it a good idea? Neil From noreply@sourceforge.net Thu Jun 29 07:21:08 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Wed, 28 Jun 2000 23:21:08 -0700 Subject: [Patches] [Patch #100672] modify test_socket.py to listen/connect using loopback addr Message-ID: <200006290621.XAA20809@bush.i.sourceforge.net> Patch #100672 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100672&group_id=5470 From Vladimir.Marangozov@inrialpes.fr Thu Jun 29 08:38:01 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Thu, 29 Jun 2000 09:38:01 +0200 (CEST) Subject: [Patches] GC patch 3 and 4 In-Reply-To: <20000628232232.A18845@acs.ucalgary.ca> from "Neil Schemenauer" at Jun 28, 2000 11:22:32 PM Message-ID: <200006290738.JAA20560@python.inrialpes.fr> Neil Schemenauer wrote: > > On Thu, Jun 29, 2000 at 05:20:35AM +0200, Vladimir Marangozov wrote: > > Neil Schemenauer wrote: > > > The major problem I see with the current API is that PyObject_NEW > > > and PyObject_DEL are not symmetric. When GC is enabled > > > PyObject_NEW returns an object pointer while PyObject_DEL takes a > > > GC pointer. > > > > I see. Would it make sense for PyObject_NEW to return the GC pointer ? > > (only if the object type supports GC). > > I would say that's a step in the wrong direction. Since the > PyObject_Init code has to access the object structure two > conversions would have to be done. Also, I don't like that part > of the implementation leaking out. If PyObject_DEL could be made > a statement instead of an expression then something like: > > #ifdef WITH_CYCLE_GC > #define PyObject_DEL(op) do { \ > if (PyObject_IS_GC(op)) { \ > PyObject_FREE(PyObject_AS_GC(op)); \ > } else { \ > PyObject_FREE(op); \ > } \ > } while (0); > #else > #define PyObject_DEL(op) PyObject_FREE(op) > #endif > > would do the trick. The PyObject_AS_GC garbage in types could > then be dropped. A quick look at the code indicates that > PyObject_DEL as a statement would be okay for the types > supporting GC. Could this work? Is it a good idea? Yes. Go for it! I wanted to avoid it but there's a price to pay and it seems that the other way around is more expensive and indeed, not so clean. OTOH, this is the genuine inlined version of PyObject_Del() which is good. In objimpl.h, in the WITH_CYCLE_GC block, the above would look like #ifdef WITH_CYCLE_GC ... #undef PyObject_DEL #define PyObject_DEL(op) ( PyObject_IS_GC(op) ? \ PyObject_FREE(PyObject_AS_GC(op)) : \ PyObject_FREE(op) ) ... #endif -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From noreply@sourceforge.net Thu Jun 29 11:25:44 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Thu, 29 Jun 2000 03:25:44 -0700 Subject: [Patches] [Patch #100673] minor fix to make 1.6 compile under MSVC 5.0 Message-ID: <200006291025.DAA28731@delerium.i.sourceforge.net> Patch #100673 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100673&group_id=5470 From nascheme@enme.ucalgary.ca Thu Jun 29 14:43:53 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Thu, 29 Jun 2000 07:43:53 -0600 Subject: [Patches] GC patch 3 and 4 In-Reply-To: <200006290738.JAA20560@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Thu, Jun 29, 2000 at 09:38:01AM +0200 References: <20000628232232.A18845@acs.ucalgary.ca> <200006290738.JAA20560@python.inrialpes.fr> Message-ID: <20000629074353.A21821@acs.ucalgary.ca> On Thu, Jun 29, 2000 at 09:38:01AM +0200, Vladimir Marangozov wrote: > In objimpl.h, in the WITH_CYCLE_GC block, the above would look like > > #ifdef WITH_CYCLE_GC > ... > #undef PyObject_DEL > #define PyObject_DEL(op) ( PyObject_IS_GC(op) ? \ > PyObject_FREE(PyObject_AS_GC(op)) : \ > PyObject_FREE(op) ) > ... > #endif I didn't do this originally for two reasons. First, that above macro evaluates the op argument twice. In practice that should not really be a problem. Secound, the PyObject_IS_GC test will be done for all objects using PyObject_DEL which is a little more expensive then things would have to be. Neil From noreply@sourceforge.net Thu Jun 29 15:31:57 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Thu, 29 Jun 2000 07:31:57 -0700 Subject: [Patches] [Patch #100674] ucnhash staticforward, "" vs <> generation patch Message-ID: <200006291431.HAA02384@bush.i.sourceforge.net> Patch #100674 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100674&group_id=5470 From noreply@sourceforge.net Fri Jun 30 07:05:18 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Thu, 29 Jun 2000 23:05:18 -0700 Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py Message-ID: <200006300605.XAA29903@bush.i.sourceforge.net> Patch #100683 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100683&group_id=5470 From trentm@activestate.com Fri Jun 30 07:14:01 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 29 Jun 2000 23:14:01 -0700 Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py In-Reply-To: <200006300605.XAA29903@bush.i.sourceforge.net> References: <200006300605.XAA29903@bush.i.sourceforge.net> Message-ID: <20000629231401.B24811@activestate.com> [skip] > http://sourceforge.net/patch/?func=detailpatch&patch_id=100683&group_id=5470 I can see the value in this but it would be nice to enable this through an option. I don't really care if randomization is the default (perhaps it should be, as you suggest), but one should still be able to get the old behavious shouldn't they? Or rather, in the interest of reproducibility, can the "random" order be given a seed to be able to get the same "random" order on multiple invocations. (The "random" is pseudo-random, right?). Trent -- Trent Mick trentm@activestate.com From noreply@sourceforge.net Fri Jun 30 13:22:21 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 05:22:21 -0700 Subject: [Patches] [Patch #100685] conversion.xml illformed Message-ID: <200006301222.FAA08972@delerium.i.sourceforge.net> Patch #100685 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100685&group_id=5470 From noreply@sourceforge.net Fri Jun 30 13:24:34 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 05:24:34 -0700 Subject: [Patches] [Patch #100686] xml package not installed Message-ID: <200006301224.FAA09091@delerium.i.sourceforge.net> Patch #100686 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100686&group_id=5470 From guido@python.org Fri Jun 30 15:35:16 2000 From: guido@python.org (Guido van Rossum) Date: Fri, 30 Jun 2000 09:35:16 -0500 Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py In-Reply-To: Your message of "Thu, 29 Jun 2000 23:14:01 MST." <20000629231401.B24811@activestate.com> References: <200006300605.XAA29903@bush.i.sourceforge.net> <20000629231401.B24811@activestate.com> Message-ID: <200006301435.JAA27350@cj20424-a.reston1.va.home.com> > [skip] > > http://sourceforge.net/patch/?func=detailpatch&patch_id=100683&group_id=5470 [trent] > I can see the value in this but it would be nice to enable this through an > option. I don't really care if randomization is the default (perhaps it > should be, as you suggest), but one should still be able to get the old > behavious shouldn't they? Or rather, in the interest of reproducibility, can > the "random" order be given a seed to be able to get the same "random" order > on multiple invocations. (The "random" is pseudo-random, right?). It's cute, but we've had dependencies in the past between tests. These would be very difficult to reproduce if this was the default! I vote -1 in this form. I'd vote +0 if it was an option you had to explicitly turn on. --Guido van Rossum (home page: http://www.python.org/~guido/) From noreply@sourceforge.net Fri Jun 30 15:22:18 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 07:22:18 -0700 Subject: [Patches] [Patch #100687] Fixes for freeze on 1.6 (mostly win32) Message-ID: <200006301422.HAA11299@bush.i.sourceforge.net> Patch #100687 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100687&group_id=5470 From skip@mojam.com (Skip Montanaro) Fri Jun 30 15:06:29 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Fri, 30 Jun 2000 09:06:29 -0500 (CDT) Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py In-Reply-To: <200006301435.JAA27350@cj20424-a.reston1.va.home.com> References: <200006300605.XAA29903@bush.i.sourceforge.net> <20000629231401.B24811@activestate.com> <200006301435.JAA27350@cj20424-a.reston1.va.home.com> Message-ID: <14684.43365.980836.621044@beluga.mojam.com> Guido> I vote -1 in this form. I'd vote +0 if it was an option you had Guido> to explicitly turn on. I can be persuaded to add a -r flag to regrtest.py... Skip From guido@python.org Fri Jun 30 17:25:45 2000 From: guido@python.org (Guido van Rossum) Date: Fri, 30 Jun 2000 11:25:45 -0500 Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py In-Reply-To: Your message of "Fri, 30 Jun 2000 09:06:29 EST." <14684.43365.980836.621044@beluga.mojam.com> References: <200006300605.XAA29903@bush.i.sourceforge.net> <20000629231401.B24811@activestate.com> <200006301435.JAA27350@cj20424-a.reston1.va.home.com> <14684.43365.980836.621044@beluga.mojam.com> Message-ID: <200006301625.LAA11252@cj20424-a.reston1.va.home.com> > Guido> I vote -1 in this form. I'd vote +0 if it was an option you had > Guido> to explicitly turn on. > > I can be persuaded to add a -r flag to regrtest.py... OK, go for it. (It would be cool if there was at least a hackish way to do this with imports too, e.g. import regrtest regrtest.randomize = 1 regrtest.main() --Guido van Rossum (home page: http://www.python.org/~guido/) From noreply@sourceforge.net Fri Jun 30 16:35:53 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 08:35:53 -0700 Subject: [Patches] [Patch #100689] If we have stat.h include it if we don't have sys/stat.h Message-ID: <200006301535.IAA13511@bush.i.sourceforge.net> Patch #100689 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100689&group_id=5470 From noreply@sourceforge.net Fri Jun 30 17:20:27 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 09:20:27 -0700 Subject: [Patches] [Patch #100692] Include limits.h if we have it. Message-ID: <200006301620.JAA14903@bush.i.sourceforge.net> Patch #100692 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100692&group_id=5470 From noreply@sourceforge.net Fri Jun 30 17:22:00 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 09:22:00 -0700 Subject: [Patches] [Patch #100693] Include stat.h if needed; different Mac filename compare Message-ID: <200006301622.JAA15019@bush.i.sourceforge.net> Patch #100693 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100693&group_id=5470 From noreply@sourceforge.net Fri Jun 30 17:23:15 2000 From: noreply@sourceforge.net (noreply@sourceforge.net) Date: Fri, 30 Jun 2000 09:23:15 -0700 Subject: [Patches] [Patch #100694] Include limits.h if we have it. Message-ID: <200006301623.JAA16168@delerium.i.sourceforge.net> Patch #100694 has been updated. Visit SourceForge.net for more info. http://sourceforge.net/patch/?func=detailpatch&patch_id=100694&group_id=5470 From skip@mojam.com (Skip Montanaro) Fri Jun 30 16:25:13 2000 From: skip@mojam.com (Skip Montanaro) (Skip Montanaro) Date: Fri, 30 Jun 2000 10:25:13 -0500 (CDT) Subject: [Patches] [Patch #100683] randomize test execution order in regrtest.py In-Reply-To: <200006301625.LAA11252@cj20424-a.reston1.va.home.com> References: <200006300605.XAA29903@bush.i.sourceforge.net> <20000629231401.B24811@activestate.com> <200006301435.JAA27350@cj20424-a.reston1.va.home.com> <14684.43365.980836.621044@beluga.mojam.com> <200006301625.LAA11252@cj20424-a.reston1.va.home.com> Message-ID: <14684.48089.862990.304395@beluga.mojam.com> Guido> OK, go for it. (It would be cool if there was at least a hackish Guido> way to do this with imports too, e.g. Guido> import regrtest Guido> regrtest.randomize = 1 Guido> regrtest.main() Done. Instead of adding a module-level variable I simply migrated the initialization of the various flag variables normally set using command line flags into the main function definition: def main(tests=None, testdir=None, verbose=0, quiet=0, generate=0, exclude=0, single=0, randomize=0): Also, I noticed that I had to disable my PYTHONSTARTUP environment variable before running regrtest.main from the interpreter prompt. test_exceptions was failing if I didn't do that. I have no idea yet if my .pythonrc.py file screwed up the environment somehow or if there is some strange interaction between the PYTHONSTARTUP logic and test_exceptions.py. Haven't looked into that yet. Skip