From mal@lemburg.com Mon May 1 11:08:36 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Mon, 01 May 2000 12:08:36 +0200 Subject: [Patches] Bug in codecs.py References: <390D5787.69F717EF@lemburg.com> Message-ID: <390D57A4.2A9E09E7@lemburg.com> This is a multi-part message in MIME format. --------------7F32F59AEC796F5D8F610ECC Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Patch Set Contents: ------------------- Lib/codecs.py: The two methods .readline() and .readlines() in StreamReaderWriter didn't define the self argument. Found by Tom Emerson. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ --------------7F32F59AEC796F5D8F610ECC Content-Type: text/plain; charset=us-ascii; name="Unicode-Implementation-2000-05-01.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Unicode-Implementation-2000-05-01.patch" diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/codecs.py Python+Unicode/Lib/codecs.py --- CVS-Python/Lib/codecs.py Thu Apr 13 18:10:57 2000 +++ Python+Unicode/Lib/codecs.py Mon May 1 11:54:03 2000 @@ -324,11 +324,11 @@ return self.reader.read(size) - def readline(size=None): + def readline(self, size=None): return self.reader.readline(size) - def readlines(sizehint=None): + def readlines(self, sizehint=None): return self.reader.readlines(sizehint) Only in CVS-Python/Lib/test: test_winsound.py --------------7F32F59AEC796F5D8F610ECC-- From mal@lemburg.com Mon May 1 11:56:23 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Mon, 01 May 2000 12:56:23 +0200 Subject: [Patches] Re: issues with int/long on 64bit platforms - eg stringobject (PR#306) References: <390D6205.CC4AAE76@lemburg.com> Message-ID: <390D62D7.C6BC031@lemburg.com> This is a multi-part message in MIME format. --------------0B731F6F3B362F9549B80A95 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Patch Set Contents: ------------------- Python/getargs.c: Added silent truncation to 'i' parser marker to enable the use of sys.maxint as argument on 64-bit platforms. Values outside the range INT_MIN - INT_MAX are silently truncated to the resp. maximum values for int(egers). The fix is needed to get e.g. string methods with sys.maxint slicing default values to work on 64-bit platforms. ____________________________________________________________________ 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. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ --------------0B731F6F3B362F9549B80A95 Content-Type: text/plain; charset=us-ascii; name="getargs.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="getargs.patch" --- CVS-Python/Python/getargs.c Mon May 1 12:39:42 2000 +++ Python+Unicode/Python/getargs.c Mon May 1 12:46:16 2000 @@ -38,10 +38,16 @@ PERFORMANCE OF THIS SOFTWARE. #include "Python.h" #include +#ifdef HAVE_LIMITS_H +#include +#else +#define INT_MAX 2147483647 +#define INT_MIN (-INT_MAX - 1) +#endif int PyArg_Parse Py_PROTO((PyObject *, char *, ...)); int PyArg_ParseTuple Py_PROTO((PyObject *, char *, ...)); int PyArg_VaParse Py_PROTO((PyObject *, char *, va_list)); @@ -491,12 +497,20 @@ convertsimple1(arg, p_format, p_va) { int *p = va_arg(*p_va, int *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; - else - *p = ival; + /* Silently truncate to INT_MAX/INT_MIN to + make passing sys.maxint to 'i' parser + markers work on 64-bit platforms work just + like on 32-bit platforms. Overflow errors + are not raised. */ + else if (ival > INT_MAX) + ival = INT_MAX; + else if (ival < INT_MIN) + ival = INT_MIN; + *p = ival; break; } case 'l': /* long int */ { --------------0B731F6F3B362F9549B80A95-- From guido@python.org Mon May 1 14:02:32 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 01 May 2000 09:02:32 -0400 Subject: [Patches] utime(path, NULL) In-Reply-To: Your message of "Fri, 28 Apr 2000 20:20:20 EDT." <14602.10948.514287.329941@anthem.cnri.reston.va.us> References: <14602.10948.514287.329941@anthem.cnri.reston.va.us> Message-ID: <200005011302.JAA20180@eric.cnri.reston.va.us> > On some OSes (Solaris and Linux at least), the second argument to > utime() can be NULL, which sets the atime and mtime of the file to the > current time. Here is a patch that gives this functionality if second > argument to os.utime() is omitted. E.g. > > import os > os.utime(path) > > == > > #include > utime(path, NULL) > > One minor bogosity: because of the way default arguments work for > longs, os.utime(path) is equivalent to os.utime(path, (-1, -1)). Is > this a big deal? Should other magic be used instead? The logical translation would be to require passing in None rather than leaving out the argument. The (-1, -1) default is ugly. --Guido van Rossum (home page: http://www.python.org/~guido/) From fdrake@acm.org Mon May 1 14:50:25 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Mon, 1 May 2000 09:50:25 -0400 (EDT) Subject: [Patches] slightly expanded Unicode supported Py_BuildValue In-Reply-To: <390ADD0D.9722FA7D@lemburg.com> References: <20000429031355.84728.qmail@hotmail.com> <390ADD0D.9722FA7D@lemburg.com> Message-ID: <14605.35745.601828.779693@seahag.cnri.reston.va.us> M.-A. Lemburg writes: > One could argue to also have a set of "u" markers for > PyArgs_ParseTuple(): these should then return Py_UNICODE* > instead of char*. Perhaps this is what you are thinking > about ? It would make a nice complement to your recent patches. I agree. I'll accept patches for this. ;) -Fred -- Fred L. Drake, Jr. Corporation for National Research Initiatives From bwarsaw@python.org Mon May 1 16:53:50 2000 From: bwarsaw@python.org (bwarsaw@python.org) Date: Mon, 1 May 2000 11:53:50 -0400 (EDT) Subject: [Patches] utime(path, NULL) References: <14602.10948.514287.329941@anthem.cnri.reston.va.us> <200005011302.JAA20180@eric.cnri.reston.va.us> Message-ID: <14605.43150.864992.155310@anthem.cnri.reston.va.us> >>>>> "GvR" == Guido van Rossum writes: GvR> The logical translation would be to require passing in None GvR> rather than leaving out the argument. The (-1, -1) default GvR> is ugly. I like this better, so I'll make the change and check it in. -Barry From guido@python.org Mon May 1 18:20:48 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 01 May 2000 13:20:48 -0400 Subject: [Patches] acosh and asinh functions In-Reply-To: Your message of "Wed, 26 Apr 2000 21:44:54 +0200." <39074736.B1C7D90F@envision.co.il> References: <39074736.B1C7D90F@envision.co.il> Message-ID: <200005011720.NAA20553@eric.cnri.reston.va.us> > The computation of the inverse hyperbolic functions 'acosh' and 'asinh' > is erroneous -- it has both low precision and discontinuities. > > The patch (using diff) is followed: > ==================================================================== > 60,61c60,63 > < return c_log(c_sum(x,c_prod(c_i, > < c_sqrt(c_diff(c_1,c_prod(x,x)))))); > --- > > Py_complex z; > > z = c_sqrt(c_half); > > c_temp = c_log(c_prod(z, c_sum( c_sqrt(c_sum(x,c_1)), > c_sqrt(c_diff(x,c_1))))); > > return c_sum(c_temp,c_temp); > 89,90c91 > < z = c_diff(c_sqrt(z),x); > < return c_neg(c_log(z)); > --- > > return c_log(c_sum(c_sqrt(z),x)); > 338c339 > < PyErr_SetFromErrno(PyExc_ValueError); > --- > > PyErr_SetFromErrno(PyExc_ValueError); > 414c415 > < > --- > > > 422c423 > < } > --- > > } > \ No newline at end of file > ================================================================= Thanks for your contribution. My math skills are insufficient to decide whether your patch is correct. There are several problems though: (1) c_temp is not declared; (2) this code raises OverflowError for cmath.asinh(1e154). Which gives me doubts about the reliability of the patch. Perhaps you would care to write up a brief mathematical analysis (with some literature references) of how acosh and asinh are defined, how they are typically calculated, and how to recognize a quality implementation? If we have a test suite (written in Python) for a particular acosh/asinh implementation, it will be easier to decide whether a given implementation is correct. --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 1 18:26:15 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 01 May 2000 13:26:15 -0400 Subject: [Patches] win32 module case bugfix to allcaps83 In-Reply-To: Your message of "Sat, 29 Apr 2000 09:40:45 BST." References: Message-ID: <200005011726.NAA20584@eric.cnri.reston.va.us> > The following patch seems to fix a module case bug in 1.6a2 caused > by wrong return values in routine allcaps83 in import.c Bizarre... This code must not have been exercised much. I'm sure that Mark Hammond didn't mind it returning 1 for too many cases. :-) > *** import.c.orig Sat Apr 29 09:12:18 2000 > --- import.c Sat Apr 29 09:14:34 2000 > *************** > *** 1035,1046 **** > char *end = strchr(s, '\0'); > if (dot != NULL) { > if (dot-s > 8) > ! return 1; /* More than 8 before '.' */ > if (end-dot > 4) > ! return 1; /* More than 3 after '.' */ > end = strchr(dot+1, '.'); > if (end != NULL) > ! return 1; /* More than one dot */ > } > else if (end-s > 8) > return 1; /* More than 8 and no dot */ > --- 1035,1046 ---- > char *end = strchr(s, '\0'); > if (dot != NULL) { > if (dot-s > 8) > ! return 0; /* More than 8 before '.' */ > if (end-dot > 4) > ! return 0; /* More than 3 after '.' */ > end = strchr(dot+1, '.'); > if (end != NULL) > ! return 0; /* More than one dot */ > } > else if (end-s > 8) > return 1; /* More than 8 and no dot */ I would think that this case should also return 0! I'll check this in with the above addition. --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 1 19:43:47 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 01 May 2000 14:43:47 -0400 Subject: [Patches] Re: issues with int/long on 64bit platforms - eg stringobject (PR#306) In-Reply-To: Your message of "Mon, 01 May 2000 12:56:23 +0200." <390D62D7.C6BC031@lemburg.com> References: <390D6205.CC4AAE76@lemburg.com> <390D62D7.C6BC031@lemburg.com> Message-ID: <200005011843.OAA21865@eric.cnri.reston.va.us> > Added silent truncation to 'i' parser marker to enable the use > of sys.maxint as argument on 64-bit platforms. Values outside > the range INT_MIN - INT_MAX are silently truncated to the > resp. maximum values for int(egers). Nice try, but given Tim Peters' post on this subject I can't apply this... --Guido van Rossum (home page: http://www.python.org/~guido/) From mal@lemburg.com Mon May 1 22:22:11 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Mon, 01 May 2000 23:22:11 +0200 Subject: [Patches] Fix for ord(u'\777') Message-ID: <390DF583.BA85FC19@lemburg.com> This is a multi-part message in MIME format. --------------B79882C431C01EF7F5593B52 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Patch Set Contents: ------------------- Objects/unicodeobject.c: Fixed \OOO interpretation for Unicode objects. \777 now correctly produces the Unicode character with ordinal 511. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ --------------B79882C431C01EF7F5593B52 Content-Type: text/plain; charset=us-ascii; name="Unicode-Implementation-2000-05-01a.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="Unicode-Implementation-2000-05-01a.patch" --- CVS-Python/Objects/unicodeobject.c Mon May 1 12:39:41 2000 +++ Python+Unicode/Objects/unicodeobject.c Mon May 1 23:13:47 2000 @@ -1014,17 +1014,17 @@ PyObject *PyUnicode_DecodeUnicodeEscape( case 'a': *p++ = '\007'; break; /* BEL, not classic C */ /* \OOO (octal) escapes */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - c = s[-1] - '0'; + x = s[-1] - '0'; if ('0' <= *s && *s <= '7') { - c = (c<<3) + *s++ - '0'; + x = (x<<3) + *s++ - '0'; if ('0' <= *s && *s <= '7') - c = (c<<3) + *s++ - '0'; + x = (x<<3) + *s++ - '0'; } - *p++ = c; + *p++ = x; break; /* \xXXXX escape with 0-4 hex digits */ case 'x': x = 0; --------------B79882C431C01EF7F5593B52-- From mal@lemburg.com Tue May 2 09:44:58 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 02 May 2000 10:44:58 +0200 Subject: [Patches] slightly expanded Unicode supported Py_BuildValue References: <20000429031355.84728.qmail@hotmail.com> <390ADD0D.9722FA7D@lemburg.com> <14605.35745.601828.779693@seahag.cnri.reston.va.us> Message-ID: <390E958A.1129C82E@lemburg.com> "Fred L. Drake, Jr." wrote: > > M.-A. Lemburg writes: > > One could argue to also have a set of "u" markers for > > PyArgs_ParseTuple(): these should then return Py_UNICODE* > > instead of char*. Perhaps this is what you are thinking > > about ? It would make a nice complement to your recent patches. > > I agree. I'll accept patches for this. ;) Brian :) ? -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Vladimir.Marangozov@inrialpes.fr Tue May 2 13:11:40 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Tue, 2 May 2000 14:11:40 +0200 (CEST) Subject: [Patches] PyMem [Windows] - PC/* Message-ID: <200005021211.OAA02240@python.inrialpes.fr> [ PC/* ] I forgot completely to inspect at the Windows specific code, sorry. I hardly ever look at the PC/* directory. Here's the patch (this is untested by me). There are a couple of malloc/free calls, but I think they're fine because they come in pairs. So at the end, the Windows patch is tiny. -- 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 ]--------------------------- diff -cr PyCVS/PC/winreg.c PyMem/PC/winreg.c *** PyCVS/PC/winreg.c Sat Apr 29 00:24:10 2000 --- PyMem/PC/winreg.c Tue May 2 13:50:57 2000 *************** *** 370,376 **** PyHKEYObject *obkey = (PyHKEYObject *)ob; if (obkey->hkey) RegCloseKey((HKEY)obkey->hkey); ! PyMem_DEL(ob); } static int --- 370,376 ---- PyHKEYObject *obkey = (PyHKEYObject *)ob; if (obkey->hkey) RegCloseKey((HKEY)obkey->hkey); ! PyObject_DEL(ob); } static int *************** *** 604,615 **** PyObject * PyHKEY_FromHKEY(HKEY h) { ! PyHKEYObject *op = (PyHKEYObject *) malloc(sizeof(PyHKEYObject)); if (op == NULL) return PyErr_NoMemory(); ! op->ob_type = &PyHKEY_Type; op->hkey = h; - _Py_NewReference((PyObject *)op); return (PyObject *)op; } --- 604,617 ---- PyObject * PyHKEY_FromHKEY(HKEY h) { ! PyHKEYObject *op; ! ! /* PyObject_New is inlined */ ! op = (PyHKEYObject *) PyObject_MALLOC(sizeof(PyHKEYObject)); if (op == NULL) return PyErr_NoMemory(); ! PyObject_INIT(op, &PyHKEY_Type); op->hkey = h; return (PyObject *)op; } *************** *** 1348,1354 **** Py_BEGIN_ALLOW_THREADS rc = RegSetValueEx(hKey, valueName, 0, typ, data, len); Py_END_ALLOW_THREADS ! PyMem_Free(data); if (rc != ERROR_SUCCESS) return PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValueEx"); --- 1350,1356 ---- Py_BEGIN_ALLOW_THREADS rc = RegSetValueEx(hKey, valueName, 0, typ, data, len); Py_END_ALLOW_THREADS ! PyMem_DEL(data); if (rc != ERROR_SUCCESS) return PyErr_SetFromWindowsErrWithFunction(rc, "RegSetValueEx"); From sjoerd@oratrix.nl Tue May 2 13:51:55 2000 From: sjoerd@oratrix.nl (Sjoerd Mullender) Date: Tue, 02 May 2000 14:51:55 +0200 Subject: [Patches] freeze patch Message-ID: <20000502125156.63E30301CF9@bireme.oratrix.nl> Bad % formatting. Index: modulefinder.py =================================================================== RCS file: /projects/cvsroot/python/dist/src/Tools/freeze/modulefinder.py,v retrieving revision 1.11 diff -u -r1.11 modulefinder.py --- modulefinder.py 1999/11/02 15:46:44 1.11 +++ modulefinder.py 2000/05/02 12:47:49 @@ -249,7 +249,7 @@ elif type == imp.PY_COMPILED: if fp.read(4) != imp.get_magic(): self.msgout(2, "raise ImportError: Bad magic number", pathname) - raise ImportError, "Bad magic number in %s", pathname + raise ImportError, "Bad magic number in %s" % pathname fp.read(4) co = marshal.load(fp) else: 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 caolan@csn.ul.ie Tue May 2 15:23:32 2000 From: caolan@csn.ul.ie (Caolan McNamara) Date: Tue, 2 May 2000 15:23:32 +0100 (IST) Subject: [Patches] telnetlib fails to work with freebsd etc, a fix 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. ---913833367-1158589385-957277412=:18393 Content-Type: TEXT/PLAIN; charset=US-ASCII telnetlib is unable to connect to a few telnet daemons because of improper IAC handling, heres an attached oneliner to reject WILL messages which will allow many more telnet daemons to work with it, namely FreeBSD. C. ===yadda yadda=== 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. Real Life: Caolan McNamara * Doing: MSc in HCI Work: Caolan.McNamara@ul.ie * Phone: +353-86-8790257 URL: http://www.csn.ul.ie/~caolan * Sig: an oblique strategy Idiot Glee (?) ---913833367-1158589385-957277412=:18393 Content-Type: TEXT/PLAIN; charset=US-ASCII; name="telnetlib.patch" Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename="telnetlib.patch" KioqIG9sZC9MaWIvdGVsbmV0bGliLnB5CVR1ZSBNYXkgIDIgMTY6MDI6MDAg MjAwMA0KLS0tIFB5dGhvbi0xLjZhMi9MaWIvdGVsbmV0bGliLnB5CVR1ZSBN YXkgIDIgMTY6MDg6MTEgMjAwMA0KKioqKioqKioqKioqKioqDQoqKiogMzI5 LDMzNCAqKioqDQotLS0gMzI5LDMzNSAtLS0tDQogICAgICAgICAgICAgICAg ICAgICAgb3B0ID0gc2VsZi5yYXdxX2dldGNoYXIoKQ0KICAgICAgICAgICAg ICAgICAgICAgIHNlbGYubXNnKCdJQUMgJXMgJWQnLA0KICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgIGMgPT0gV0lMTCBhbmQgJ1dJTEwnIG9yICdX T05UJywgb3JkKGMpKQ0KKyAgICAgICAgICAgICAgICAgICAgIHNlbGYuc29j ay5zZW5kKElBQyArIERPTlQgKyBvcHQpDQogICAgICAgICAgICAgICAgICBl bHNlOg0KICAgICAgICAgICAgICAgICAgICAgIHNlbGYubXNnKCdJQUMgJXMg bm90IHJlY29nbml6ZWQnICUgYGNgKQ0KICAgICAgICAgIGV4Y2VwdCBFT0ZF cnJvcjogIyByYWlzZWQgYnkgc2VsZi5yYXdxX2dldGNoYXIoKQ0K ---913833367-1158589385-957277412=:18393-- From brian@garage.co.jp Tue May 2 21:34:41 2000 From: brian@garage.co.jp (Brian Hooper) Date: Tue, 02 May 2000 20:34:41 GMT Subject: [Patches] slightly expanded Unicode supported Py_BuildValue Message-ID: <20000502203441.87537.qmail@hotmail.com> This is a multi-part message in MIME format. ------=_NextPart_000_4ecd2596_4c79ecf$266a925d Content-Type: text/plain; format=flowed OK, here's the patch, and a corresponding documentation patch. Added 'u' and 'u#' tags for PyArg_ParseTuple - these turn a PyUnicodeObject argument into a Py_UNICODE * buffer, or a Py_UNICODE * buffer plus a length with the '#'. Also added an analog to 'U' for Py_BuildValue, and documented each in ext.tex. --Brian 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. ________________________________________________________________________ Get Your Private, Free E-mail from MSN Hotmail at http://www.hotmail.com ------=_NextPart_000_4ecd2596_4c79ecf$266a925d Content-Type: application/octet-stream; name="getargs.patch" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="getargs.patch" ZGlmZiAtYyBQeXRob24ub3JpZy9nZXRhcmdzLmMgUHl0aG9uL2dldGFyZ3Mu YwoqKiogUHl0aG9uLm9yaWcvZ2V0YXJncy5jCVdlZCBNYXkgIDMgMDU6MTA6 MTMgMjAwMAotLS0gUHl0aG9uL2dldGFyZ3MuYwlXZWQgTWF5ICAzIDA0OjE4 OjIzIDIwMDAKKioqKioqKioqKioqKioqCioqKiA3NzcsNzgyICoqKioKLS0t IDc3Nyw4MTQgLS0tLQogIAkJCWJyZWFrOwogIAkJfQogIAorIAljYXNlICd1 JzogLyogcmF3IHVuaWNvZGUgYnVmZmVyIChQeV9VTklDT0RFICopICovCisg CQl7CisgCQkJaWYgKCpmb3JtYXQgPT0gJyMnKSB7IC8qIGFueSBidWZmZXIt bGlrZSBvYmplY3QgKi8KKyAJCQkgICAgICAgIHZvaWQgKipwID0gKHZvaWQg KiopdmFfYXJnKCpwX3ZhLCBjaGFyICoqKTsKKyAJCQkgICAgICAgIFB5QnVm ZmVyUHJvY3MgKnBiID0gYXJnLT5vYl90eXBlLT50cF9hc19idWZmZXI7Cisg CQkJCWludCAqcSA9IHZhX2FyZygqcF92YSwgaW50ICopOworIAkJCQlpbnQg Y291bnQ7CisgCisgCQkJCWlmICggcGIgPT0gTlVMTCB8fAorIAkJCQkgICAg IHBiLT5iZl9nZXRyZWFkYnVmZmVyID09IE5VTEwgfHwKKyAJCQkJICAgICBw Yi0+YmZfZ2V0c2VnY291bnQgPT0gTlVMTCApCisgCQkJCSAgcmV0dXJuICJy ZWFkLW9ubHkgYnVmZmVyIjsKKyAJCQkJaWYgKCAoKnBiLT5iZl9nZXRzZWdj b3VudCkoYXJnLCBOVUxMKSAhPSAxICkKKyAJCQkJICByZXR1cm4gInNpbmds ZS1zZWdtZW50IHJlYWQtb25seSBidWZmZXIiOworIAkJCQlpZiAoIChjb3Vu dCA9CisgCQkJCSAgICAgICgqcGItPmJmX2dldHJlYWRidWZmZXIpKGFyZywg MCwgcCkpIDwgMCApCisgCQkJCSAgcmV0dXJuICIodW5zcGVjaWZpZWQpIjsK KyAJCQkJLyogYnVmZmVyIGludGVyZmFjZSByZXR1cm5zIGJ5dGVzLCB3ZSB3 YW50CisgCQkJCSAgIGxlbmd0aCBpbiBjaGFyYWN0ZXJzICovCisgCQkJCSpx ID0gY291bnQvKHNpemVvZihQeV9VTklDT0RFKSk7IAorIAkJCQlmb3JtYXQr KzsKKyAJCQl9IGVsc2UgeworIAkJCSAgICAgICAgUHlfVU5JQ09ERSAqKnAg PSB2YV9hcmcoKnBfdmEsIFB5X1VOSUNPREUgKiopOworIAkJCQorIAkJCSAg ICAgICAgaWYgKFB5VW5pY29kZV9DaGVjayhhcmcpKQorIAkJCQkgICAgKnAg PSBQeVVuaWNvZGVfQVNfVU5JQ09ERShhcmcpOworIAkJCQllbHNlCisgCQkJ CSAgcmV0dXJuICJ1bmljb2RlIjsKKyAJCQl9CisgCQkJYnJlYWs7CisgCQl9 CisgCiAgCWNhc2UgJ1MnOiAvKiBzdHJpbmcgb2JqZWN0ICovCiAgCQl7CiAg CQkJUHlPYmplY3QgKipwID0gdmFfYXJnKCpwX3ZhLCBQeU9iamVjdCAqKik7 CmRpZmYgLWMgUHl0aG9uLm9yaWcvbW9kc3VwcG9ydC5jIFB5dGhvbi9tb2Rz dXBwb3J0LmMKKioqIFB5dGhvbi5vcmlnL21vZHN1cHBvcnQuYwlXZWQgTWF5 ICAzIDA1OjEwOjEzIDIwMDAKLS0tIFB5dGhvbi9tb2RzdXBwb3J0LmMJV2Vk IE1heSAgMyAwNDoxODoyMyAyMDAwCioqKioqKioqKioqKioqKgoqKiogMzY1 LDM3MCAqKioqCi0tLSAzNjUsMzcxIC0tLS0KICAJCWNhc2UgJ04nOgogIAkJ Y2FzZSAnUyc6CiAgCQljYXNlICdPJzoKKyAJCWNhc2UgJ1UnOgogIAkJaWYg KCoqcF9mb3JtYXQgPT0gJyYnKSB7CiAgCQkJdHlwZWRlZiBQeU9iamVjdCAq KCpjb252ZXJ0ZXIpIFB5X1BST1RPKCh2b2lkICopKTsKICAJCQljb252ZXJ0 ZXIgZnVuYyA9IHZhX2FyZygqcF92YSwgY29udmVydGVyKTsK ------=_NextPart_000_4ecd2596_4c79ecf$266a925d Content-Type: application/octet-stream; name="getargsdoc.patch" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="getargsdoc.patch" KioqIERvYy5vcmlnL2V4dC9leHQudGV4CVRodSBBcHIgMjcgMDQ6NTA6MDAg MjAwMAotLS0gRG9jL2V4dC9leHQudGV4CVdlZCBNYXkgIDMgMDQ6MDM6NTQg MjAwMAoqKioqKioqKioqKioqKioKKioqIDY5MSw2OTYgKioqKgotLS0gNjkx LDcwNyAtLS0tCiAgXGl0ZW1bXHNhbXB7elwjfSAoc3RyaW5nIG9yIFxjb2Rl e05vbmV9KSB7W2NoYXIgKiwgaW50XX1dCiAgVGhpcyBpcyB0byBcc2FtcHtz XCN9IGFzIFxzYW1we3p9IGlzIHRvIFxzYW1we3N9LgogIAorIFxpdGVtW1xz YW1we3V9IChVbmljb2RlIHN0cmluZykge1tQeV9VTklDT0RFICpdfV0KKyBD b252ZXJ0IGEgUHl0aG9uIFVuaWNvZGUgb2JqZWN0IHRvIGEgQyBwb2ludGVy IHRvIGEgbnVsbC10ZXJtaW5hdGVkCisgYnVmZmVyIG9mIFVuaWNvZGUgKFVD Uy0yKSBkYXRhLiAgQXMgd2l0aCBcc2FtcHtzfSwgdGhlcmUgaXMgbm8gbmVl ZAorIHRvIHByb3ZpZGUgc3RvcmFnZSBmb3IgdGhlIFVuaWNvZGUgZGF0YSBi dWZmZXI7IGEgcG9pbnRlciB0byB0aGUKKyBleGlzdGluZyBVbmljb2RlIGRh dGEgaXMgc3RvcmVkIGludG8gdGhlIFB5X1VOSUNPREUgcG9pbnRlciB2YXJp YWJsZSB3aG9zZQorIGFkZHJlc3MgeW91IHBhc3MuICAKKyAKKyBcaXRlbVtc c2FtcHt1XCN9IChVbmljb2RlIHN0cmluZykge1tQeV9VTklDT0RFICosIGlu dF19XQorIFRoaXMgdmFyaWFudCBvbiBcc2FtcHt1fSBzdG9yZXMgaW50byB0 d28gQyB2YXJpYWJsZXMsIHRoZSBmaXJzdCBvbmUKKyBhIHBvaW50ZXIgdG8g YSBVbmljb2RlIGRhdGEgYnVmZmVyLCB0aGUgc2Vjb25kIG9uZSBpdHMgbGVu Z3RoLgorIAogIFxpdGVtW1xzYW1we2J9IChpbnRlZ2VyKSB7W2NoYXJdfV0K ICBDb252ZXJ0IGEgUHl0aG9uIGludGVnZXIgdG8gYSB0aW55IGludCwgc3Rv cmVkIGluIGEgQyBcY3R5cGV7Y2hhcn0uCiAgCioqKioqKioqKioqKioqKgoq KiogNzUxLDc1NiAqKioqCi0tLSA3NjIsNzcyIC0tLS0KICBSYWlzZXMgXGV4 Y2VwdGlvbntUeXBlRXJyb3J9IGlmIHRoZSBvYmplY3QgaXMgbm90IGEgc3Ry aW5nIG9iamVjdC4KICBUaGUgQyB2YXJpYWJsZSBtYXkgYWxzbyBiZSBkZWNs YXJlZCBhcyBcY3R5cGV7UHlPYmplY3QgKn0uCiAgCisgXGl0ZW1bXHNhbXB7 VX0gKFVuaWNvZGUgc3RyaW5nKSB7W1B5VW5pY29kZU9iamVjdCAqXX1dCisg TGlrZSBcc2FtcHtPfSBidXQgcmVxdWlyZXMgdGhhdCB0aGUgUHl0aG9uIG9i amVjdCBpcyBhIFVuaWNvZGUgb2JqZWN0LgorIFJhaXNlcyBcZXhjZXB0aW9u e1R5cGVFcnJvcn0gaWYgdGhlIG9iamVjdCBpcyBub3QgYSBVbmljb2RlIG9i amVjdC4KKyBUaGUgQyB2YXJpYWJsZSBtYXkgYWxzbyBiZSBkZWNsYXJlZCBh cyBcY3R5cGV7UHlPYmplY3QgKn0uCisgCiAgXGl0ZW1bXHNhbXB7dFwjfSAo cmVhZC1vbmx5IGNoYXJhY3RlciBidWZmZXIpIHtbY2hhciAqLCBpbnRdfV0K ICBMaWtlIFxzYW1we3NcI30sIGJ1dCBhY2NlcHRzIGFueSBvYmplY3Qgd2hp Y2ggaW1wbGVtZW50cyB0aGUgcmVhZC1vbmx5IAogIGJ1ZmZlciBpbnRlcmZh Y2UuICBUaGUgXGN0eXBle2NoYXIgKn0gdmFyaWFibGUgaXMgc2V0IHRvIHBv aW50IHRvIHRoZQoqKioqKioqKioqKioqKioKKioqIDEwMDYsMTAxMSAqKioq Ci0tLSAxMDIyLDEwMzYgLS0tLQogIFxpdGVtW1xzYW1we3pcI30gKHN0cmlu ZyBvciBcY29kZXtOb25lfSkge1tjaGFyICosIGludF19XQogIFNhbWUgYXMg XHNhbXB7c1wjfS4KICAKKyBcaXRlbVtcc2FtcHt1fSAoVW5pY29kZSBzdHJp bmcpIHtbUHlfVU5JQ09ERSAqXX1dCisgQ29udmVydCBhIG51bGwtdGVybWlu YXRlZCBidWZmZXIgb2YgVW5pY29kZSAoVUNTLTIpIGRhdGEgdG8gYSBQeXRo b24gVW5pY29kZSAKKyBvYmplY3QuIElmIHRoZSBVbmljb2RlIGJ1ZmZlciBw b2ludGVyIGlzIFxOVUxMe30sIFxjb2Rle05vbmV9IGlzIHJldHVybmVkLgor IAorIFxpdGVtW1xzYW1we3VcI30gKFVuaWNvZGUgc3RyaW5nKSB7W1B5X1VO SUNPREUgKiwgaW50XX1dCisgQ29udmVydCBhIFVuaWNvZGUgKFVDUy0yKSBk YXRhIGJ1ZmZlciBhbmQgaXRzIGxlbmd0aCB0byBhIFB5dGhvbiBVbmljb2Rl IAorIG9iamVjdC4gSWYgdGhlIFVuaWNvZGUgYnVmZmVyIHBvaW50ZXIgaXMg XE5VTEx7fSwgdGhlIGxlbmd0aCBpcyBpZ25vcmVkIGFuZCAKKyBcY29kZXtO b25lfSBpcyByZXR1cm5lZC4KKyAKICBcaXRlbVtcc2FtcHtpfSAoaW50ZWdl cikge1tpbnRdfV0KICBDb252ZXJ0IGEgcGxhaW4gQyBcY3R5cGV7aW50fSB0 byBhIFB5dGhvbiBpbnRlZ2VyIG9iamVjdC4KICAKKioqKioqKioqKioqKioq CioqKiAxMDM4LDEwNDMgKioqKgotLS0gMTA2MywxMDcxIC0tLS0KICBcY2Rh dGF7UHlFeGNfU3lzdGVtRXJyb3J9IGlzIHNldC4KICAKICBcaXRlbVtcc2Ft cHtTfSAob2JqZWN0KSB7W1B5T2JqZWN0ICpdfV0KKyBTYW1lIGFzIFxzYW1w e099LgorIAorIFxpdGVtW1xzYW1we1V9IChvYmplY3QpIHtbUHlPYmplY3Qg Kl19XQogIFNhbWUgYXMgXHNhbXB7T30uCiAgCiAgXGl0ZW1bXHNhbXB7Tn0g KG9iamVjdCkge1tQeU9iamVjdCAqXX1dCg== ------=_NextPart_000_4ecd2596_4c79ecf$266a925d-- From mhammond@skippinet.com.au Wed May 3 03:04:13 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Wed, 3 May 2000 12:04:13 +1000 Subject: [Patches] posixmodulec fails with stat("\\") or stat("/") on Windows. Message-ID: Checkin 2.131 of posixmodule.c changed os.stat on Windows, so that "/bin/" type notation (trailing backslash) would work on Windows to be consistent with Unix. However, the patch broke the simple case of: os.stat("\\") This did work in 1.5.2, and obviously should! This patch addresses this, and restores the correct behaviour. diff -c -r2.133 posixmodule.c *** posixmodule.c 2000/05/01 16:17:24 2.133 --- posixmodule.c 2000/05/03 01:58:57 *************** *** 567,576 **** } if ((pathlen > 0) && (path[pathlen-1] == '\\' || path[pathlen-1] == '/')) { ! /* exception for drive root */ ! if (!((pathlen == 3) && (path[1] == ':') && ! (path[2] == '\\' || path[2] == '/'))) { strncpy(pathcopy, path, pathlen); pathcopy[pathlen-1] = '\0'; /* nuke the trailing backslash */ --- 567,577 ---- } if ((pathlen > 0) && (path[pathlen-1] == '\\' || path[pathlen-1] == '/')) { ! /* exception for specific or current drive root */ ! if (!((pathlen == 1) || ! ((pathlen == 3) && (path[1] == ':') && ! (path[2] == '\\' || path[2] == '/')))) { strncpy(pathcopy, path, pathlen); pathcopy[pathlen-1] = '\0'; /* nuke the trailing backslash */ 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 Wed May 3 07:55:34 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Wed, 3 May 2000 16:55:34 +1000 Subject: [Patches] MBCS codes fails on zero length string. Message-ID: Fixes the MBCS codec to work correctly with zero length strings. 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. diff -c -r2.13 unicodeobject.c *** unicodeobject.c 2000/05/01 21:27:20 2.13 --- unicodeobject.c 2000/05/03 06:53:20 *************** *** 1555,1561 **** /* First get the size of the result */ DWORD usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); ! if (usize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); v = _PyUnicode_New(usize); --- 1555,1561 ---- /* First get the size of the result */ DWORD usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); ! if (size > 0 && usize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); v = _PyUnicode_New(usize); *************** *** 1578,1586 **** { PyObject *repr; char *s; /* First get the size of the result */ ! DWORD mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); if (mbcssize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); --- 1578,1591 ---- { PyObject *repr; char *s; + DWORD mbcssize; + /* If there are no characters, bail now! */ + if (size==0) + return PyString_FromString(""); + /* First get the size of the result */ ! mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); if (mbcssize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); From mhammond@skippinet.com.au Wed May 3 12:52:00 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Wed, 3 May 2000 21:52:00 +1000 Subject: [Patches] MBCS codes fails on zero length string. In-Reply-To: Message-ID: > Fixes the MBCS codec to work correctly with zero length strings. Eeek - sorry - my mistake. The "size" param includes the NULL terminator. Thus, a 0 size is invalid. Please ignore that patch! Mark. From fdrake@acm.org Wed May 3 16:18:21 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Wed, 3 May 2000 11:18:21 -0400 (EDT) Subject: [Patches] slightly expanded Unicode supported Py_BuildValue In-Reply-To: <20000502203441.87537.qmail@hotmail.com> References: <20000502203441.87537.qmail@hotmail.com> Message-ID: <14608.17213.927045.692970@seahag.cnri.reston.va.us> Brian Hooper writes: > OK, here's the patch, and a corresponding documentation patch. > > Added 'u' and 'u#' tags for PyArg_ParseTuple - these turn a > PyUnicodeObject argument into a Py_UNICODE * buffer, or a Py_UNICODE * > buffer plus a length with the '#'. Also added an analog to 'U' > for Py_BuildValue, and documented each in ext.tex. Brian, Thanks! I've checked this patch in. -Fred -- Fred L. Drake, Jr. Corporation for National Research Initiatives From mal@lemburg.com Wed May 3 15:35:33 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Wed, 03 May 2000 16:35:33 +0200 Subject: [Patches] slightly expanded Unicode supported Py_BuildValue References: <20000502203441.87537.qmail@hotmail.com> Message-ID: <39103935.1DFCCA74@lemburg.com> Brian Hooper wrote: > > OK, here's the patch, and a corresponding documentation patch. > > Added 'u' and 'u#' tags for PyArg_ParseTuple - these turn a > PyUnicodeObject argument into a Py_UNICODE * buffer, or a Py_UNICODE * > buffer plus a length with the '#'. Also added an analog to 'U' > for Py_BuildValue, and documented each in ext.tex. Looks good :-) > Name: getargs.patch > getargs.patch Type: unspecified type (application/octet-stream) > Encoding: base64 > > Name: getargsdoc.patch > getargsdoc.patch Type: unspecified type (application/octet-stream) > Encoding: base64 Minor nit: sending these as text/plain would help commenting the patches. base64 is a little rough on the eyes ;-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From adustman@comstar.net Wed May 3 18:00:31 2000 From: adustman@comstar.net (Andy Dustman) Date: Wed, 3 May 2000 13:00:31 -0400 (EDT) Subject: [Patches] GNU pth thread library support 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. ---187888452-1274021780-957373218=:24903 Content-Type: TEXT/PLAIN; charset=US-ASCII This patch adds the ability for Python to use the GNU pth threading library. pth is a non-preemptive user-space threading library. For more information, see http://www.gnu.org/software/pth. It presently has only been tested on Linux. And of course it's against current CVS... Buglets: Some annoying compiler warnings about socketbits.h. The configuration could probably be better: It may conflict if other threading libraries (other than pthreads) are installed. -- andy dustman | programmer/analyst | comstar.net, inc. telephone: 770.485.6025 / 706.549.7689 | icq: 32922760 | pgp: 0xc72f3f1d "Therefore, sweet knights, if you may doubt your strength or courage, come no further, for death awaits you all, with nasty, big, pointy teeth!" 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. So there. ---187888452-1274021780-957373218=:24903 Content-Type: TEXT/PLAIN; charset=US-ASCII; name="python-pth.patch" Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename="python-pth.patch" SW5kZXg6IGNvbmZpZy5oLmluDQo9PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQpS Q1MgZmlsZTogL3Byb2plY3RzL2N2c3Jvb3QvcHl0aG9uL2Rpc3Qvc3JjL2Nv bmZpZy5oLmluLHYNCnJldHJpZXZpbmcgcmV2aXNpb24gMi41Mw0KZGlmZiAt YyAtcjIuNTMgY29uZmlnLmguaW4NCioqKiBjb25maWcuaC5pbgkyMDAwLzA0 LzI0IDE1OjEyOjAzCTIuNTMNCi0tLSBjb25maWcuaC5pbgkyMDAwLzA1LzAz IDE2OjQ5OjMzDQoqKioqKioqKioqKioqKioNCioqKiAxMzcsMTQyICoqKioN Ci0tLSAxMzcsMTQ1IC0tLS0NCiAgLyogRGVmaW5lIGlmIG1hbGxvYygwKSBy ZXR1cm5zIGEgTlVMTCBwb2ludGVyICovDQogICN1bmRlZiBNQUxMT0NfWkVS T19SRVRVUk5TX05VTEwNCiAgDQorIC8qIERlZmluZSBpZiB5b3UgaGF2ZSBH TlUgUFRIIHRocmVhZHMgKi8NCisgI3VuZGVmIF9HTlVfUFRIDQorIA0KICAv KiBEZWZpbmUgaWYgeW91IGhhdmUgUE9TSVggdGhyZWFkcyAqLw0KICAjdW5k ZWYgX1BPU0lYX1RIUkVBRFMNCiAgDQoqKioqKioqKioqKioqKioNCioqKiAz NjgsMzczICoqKioNCi0tLSAzNzEsMzc5IC0tLS0NCiAgDQogIC8qIERlZmlu ZSBpZiB5b3UgaGF2ZSB0aGUgcGxvY2sgZnVuY3Rpb24uICAqLw0KICAjdW5k ZWYgSEFWRV9QTE9DSw0KKyANCisgLyogRGVmaW5lIGlmIHlvdSBoYXZlIHRo ZSBwdGhfaW5pdCBmdW5jdGlvbi4gICovDQorICN1bmRlZiBIQVZFX1BUSF9J TklUDQogIA0KICAvKiBEZWZpbmUgaWYgeW91IGhhdmUgdGhlIHB0aHJlYWRf aW5pdCBmdW5jdGlvbi4gICovDQogICN1bmRlZiBIQVZFX1BUSFJFQURfSU5J VA0KSW5kZXg6IGNvbmZpZ3VyZS5pbg0KPT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PQ0KUkNTIGZpbGU6IC9wcm9qZWN0cy9jdnNyb290L3B5dGhvbi9kaXN0L3Ny Yy9jb25maWd1cmUuaW4sdg0KcmV0cmlldmluZyByZXZpc2lvbiAxLjExOQ0K ZGlmZiAtYyAtcjEuMTE5IGNvbmZpZ3VyZS5pbg0KKioqIGNvbmZpZ3VyZS5p bgkyMDAwLzA0LzI0IDE1OjEyOjA0CTEuMTE5DQotLS0gY29uZmlndXJlLmlu CTIwMDAvMDUvMDMgMTY6NDk6MzMNCioqKioqKioqKioqKioqKg0KKioqIDY1 NCw2NTkgKioqKg0KLS0tIDY1NCw2NjMgLS0tLQ0KICBBQ19DSEVDS19IRUFE RVIobWFjaC9jdGhyZWFkcy5oLCBbQUNfREVGSU5FKFdJVEhfVEhSRUFEKQ0K ICBBQ19ERUZJTkUoQ19USFJFQURTKQ0KICBMSUJPQkpTPSIkTElCT0JKUyB0 aHJlYWQubyJdLFsNCisgQUNfQ0hFQ0tfTElCKHB0aCwgcHRoX2luaXQsIFtB Q19ERUZJTkUoV0lUSF9USFJFQUQpDQorIEFDX0RFRklORShfR05VX1BUSCkN CisgTElCUz0iLWxwdGggJExJQlMiDQorIExJQk9CSlM9IiRMSUJPQkpTIHRo cmVhZC5vIl0sWw0KICBBQ19DSEVDS19MSUIocHRocmVhZCwgcHRocmVhZF9j cmVhdGUsIFtBQ19ERUZJTkUoV0lUSF9USFJFQUQpDQogIEFDX0RFRklORShf UE9TSVhfVEhSRUFEUykNCiAgTElCUz0iLWxwdGhyZWFkICRMSUJTIg0KKioq KioqKioqKioqKioqDQoqKiogNjgwLDY4NiAqKioqDQogIEFDX0RFRklORShf UE9TSVhfVEhSRUFEUykNCiAgTElCUz0iJExJQlMgLWxjbWEiDQogIExJQk9C SlM9IiRMSUJPQkpTIHRocmVhZC5vIl0pDQohIF0pXSldKV0pXSldKV0pDQog IA0KICBBQ19DSEVDS19MSUIobXBjLCB1c2NvbmZpZywgW0FDX0RFRklORShX SVRIX1RIUkVBRCkNCiAgTElCUz0iJExJQlMgLWxtcGMiDQotLS0gNjg0LDY5 MCAtLS0tDQogIEFDX0RFRklORShfUE9TSVhfVEhSRUFEUykNCiAgTElCUz0i JExJQlMgLWxjbWEiDQogIExJQk9CSlM9IiRMSUJPQkpTIHRocmVhZC5vIl0p DQohIF0pXSldKV0pXSldKV0pXSkNCiAgDQogIEFDX0NIRUNLX0xJQihtcGMs IHVzY29uZmlnLCBbQUNfREVGSU5FKFdJVEhfVEhSRUFEKQ0KICBMSUJTPSIk TElCUyAtbG1wYyINCkluZGV4OiBQeXRob24vdGhyZWFkLmMNCj09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT0NClJDUyBmaWxlOiAvcHJvamVjdHMvY3Zzcm9vdC9w eXRob24vZGlzdC9zcmMvUHl0aG9uL3RocmVhZC5jLHYNCnJldHJpZXZpbmcg cmV2aXNpb24gMi4yOA0KZGlmZiAtYyAtcjIuMjggdGhyZWFkLmMNCioqKiB0 aHJlYWQuYwkyMDAwLzA0LzI0IDE1OjA2OjUxCTIuMjgNCi0tLSB0aHJlYWQu YwkyMDAwLzA1LzAzIDE2OjQ5OjMzDQoqKioqKioqKioqKioqKioNCioqKiAx NTAsMTU3ICoqKioNCi0tLSAxNTAsMTYxIC0tLS0NCiAgI2luY2x1ZGUgInRo cmVhZF9sd3AuaCINCiAgI2VuZGlmDQogIA0KKyAjaWZkZWYgX0dOVV9QVEgN CisgI2luY2x1ZGUgInRocmVhZF9wdGguaCINCisgI2Vsc2UNCiAgI2lmZGVm IF9QT1NJWF9USFJFQURTDQogICNpbmNsdWRlICJ0aHJlYWRfcHRocmVhZC5o Ig0KKyAjZW5kaWYNCiAgI2VuZGlmDQogIA0KICAjaWZkZWYgQ19USFJFQURT DQpJbmRleDogSW5jbHVkZS9QeXRob24uaA0KPT09PT09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PQ0KUkNTIGZpbGU6IC9wcm9qZWN0cy9jdnNyb290L3B5dGhvbi9kaXN0 L3NyYy9JbmNsdWRlL1B5dGhvbi5oLHYNCnJldHJpZXZpbmcgcmV2aXNpb24g Mi4xNQ0KZGlmZiAtYyAtcjIuMTUgUHl0aG9uLmgNCioqKiBQeXRob24uaAky MDAwLzA0LzA1IDIwOjExOjA4CTIuMTUNCi0tLSBQeXRob24uaAkyMDAwLzA1 LzAzIDE2OjQ5OjMzDQoqKioqKioqKioqKioqKioNCioqKiAxMjgsMTMxICoq KioNCi0tLSAxMjgsMTM1IC0tLS0NCiAgI2RlZmluZSBQeV9maWxlX2lucHV0 IDI1Nw0KICAjZGVmaW5lIFB5X2V2YWxfaW5wdXQgMjU4DQogIA0KKyAjaWZk ZWYgX0dOVV9QVEgNCisgLyogR05VIHB0aCB1c2VyLXNwYWNlIHRocmVhZCBz dXBwb3J0ICovDQorICNpbmNsdWRlIDxwdGguaD4NCisgI2VuZGlmDQogICNl bmRpZiAvKiAhUHlfUFlUSE9OX0ggKi8NCioqKiBQeXRob24vdGhyZWFkX3B0 aC5oCVdlZCBNYXkgIDMgMTI6NTE6MjMgMjAwMA0KLS0tIFB5dGhvbi90aHJl YWRfcHRoLmgJV2VkIE1heSAgMyAxMjo0ODo1MyAyMDAwDQoqKioqKioqKioq KioqKioNCioqKiAwICoqKioNCi0tLSAxLDMyOCAtLS0tDQorIC8qKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKg0KKyBDb3B5cmlnaHQgMTk5MS0xOTk1IGJ5IFN0aWNodGluZyBN YXRoZW1hdGlzY2ggQ2VudHJ1bSwgQW1zdGVyZGFtLA0KKyBUaGUgTmV0aGVy bGFuZHMuDQorIA0KKyAgICAgICAgICAgICAgICAgICAgICAgICBBbGwgUmln aHRzIFJlc2VydmVkDQorIA0KKyBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwg bW9kaWZ5LCBhbmQgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGFuZCBpdHMN CisgZG9jdW1lbnRhdGlvbiBmb3IgYW55IHB1cnBvc2UgYW5kIHdpdGhvdXQg ZmVlIGlzIGhlcmVieSBncmFudGVkLA0KKyBwcm92aWRlZCB0aGF0IHRoZSBh Ym92ZSBjb3B5cmlnaHQgbm90aWNlIGFwcGVhciBpbiBhbGwgY29waWVzIGFu ZCB0aGF0DQorIGJvdGggdGhhdCBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlz IHBlcm1pc3Npb24gbm90aWNlIGFwcGVhciBpbg0KKyBzdXBwb3J0aW5nIGRv Y3VtZW50YXRpb24sIGFuZCB0aGF0IHRoZSBuYW1lcyBvZiBTdGljaHRpbmcg TWF0aGVtYXRpc2NoDQorIENlbnRydW0gb3IgQ1dJIG9yIENvcnBvcmF0aW9u IGZvciBOYXRpb25hbCBSZXNlYXJjaCBJbml0aWF0aXZlcyBvcg0KKyBDTlJJ IG5vdCBiZSB1c2VkIGluIGFkdmVydGlzaW5nIG9yIHB1YmxpY2l0eSBwZXJ0 YWluaW5nIHRvDQorIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc29mdHdhcmUgd2l0 aG91dCBzcGVjaWZpYywgd3JpdHRlbiBwcmlvcg0KKyBwZXJtaXNzaW9uLg0K KyANCisgV2hpbGUgQ1dJIGlzIHRoZSBpbml0aWFsIHNvdXJjZSBmb3IgdGhp cyBzb2Z0d2FyZSwgYSBtb2RpZmllZCB2ZXJzaW9uDQorIGlzIG1hZGUgYXZh aWxhYmxlIGJ5IHRoZSBDb3Jwb3JhdGlvbiBmb3IgTmF0aW9uYWwgUmVzZWFy Y2ggSW5pdGlhdGl2ZXMNCisgKENOUkkpIGF0IHRoZSBJbnRlcm5ldCBhZGRy ZXNzIGZ0cDovL2Z0cC5weXRob24ub3JnLg0KKyANCisgU1RJQ0hUSU5HIE1B VEhFTUFUSVNDSCBDRU5UUlVNIEFORCBDTlJJIERJU0NMQUlNIEFMTCBXQVJS QU5USUVTIFdJVEgNCisgUkVHQVJEIFRPIFRISVMgU09GVFdBUkUsIElOQ0xV RElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GDQorIE1FUkNIQU5UQUJJ TElUWSBBTkQgRklUTkVTUywgSU4gTk8gRVZFTlQgU0hBTEwgU1RJQ0hUSU5H IE1BVEhFTUFUSVNDSA0KKyBDRU5UUlVNIE9SIENOUkkgQkUgTElBQkxFIEZP UiBBTlkgU1BFQ0lBTCwgSU5ESVJFQ1QgT1IgQ09OU0VRVUVOVElBTA0KKyBE QU1BR0VTIE9SIEFOWSBEQU1BR0VTIFdIQVRTT0VWRVIgUkVTVUxUSU5HIEZS T00gTE9TUyBPRiBVU0UsIERBVEEgT1INCisgUFJPRklUUywgV0hFVEhFUiBJ TiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIE5FR0xJR0VOQ0UgT1IgT1RIRVIN CisgVE9SVElPVVMgQUNUSU9OLCBBUklTSU5HIE9VVCBPRiBPUiBJTiBDT05O RUNUSU9OIFdJVEggVEhFIFVTRSBPUg0KKyBQRVJGT1JNQU5DRSBPRiBUSElT IFNPRlRXQVJFLg0KKyANCisgKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqLw0KKyAN CisgLyogR05VIHB0aCB0aHJlYWRzIGludGVyZmFjZQ0KKyAgICBodHRwOi8v d3d3LmdudS5vcmcvc29mdHdhcmUvcHRoDQorICAgIDIwMDAtMDUtMDMgQW5k eSBEdXN0bWFuIDxhbmR5QGR1c3RtYW4ubmV0Pg0KKyANCisgICAgQWRhcHRl ZCBmcm9tIFBvc2l4IHRocmVhZHMgaW50ZXJmYWNlIA0KKyAgICAxMiBNYXkg MTk5NyAtLSBkYXZpZCBhcm5vbGQgPGRhdmlkYUBwb2JveC5jb20+DQorICAq Lw0KKyANCisgI2luY2x1ZGUgPHN0ZGxpYi5oPg0KKyAjaW5jbHVkZSA8c3Ry aW5nLmg+DQorICNpbmNsdWRlIDxwdGguaD4NCisgDQorIC8qIEEgcHRoIG11 dGV4IGlzbid0IHN1ZmZpY2llbnQgdG8gbW9kZWwgdGhlIFB5dGhvbiBsb2Nr IHR5cGUNCisgICogYmVjYXVzZSBwdGggbXV0ZXhlcyBjYW4gYmUgYWNxdWly ZWQgbXVsdGlwbGUgdGltZXMgYnkgdGhlDQorICAqIHNhbWUgdGhyZWFkLg0K KyAgKg0KKyAgKiBUaGUgcHRoX2xvY2sgc3RydWN0IGltcGxlbWVudHMgYSBQ eXRob24gbG9jayBhcyBhICJsb2NrZWQ/IiBiaXQNCisgICogYW5kIGEgPGNv bmRpdGlvbiwgbXV0ZXg+IHBhaXIuICBJbiBnZW5lcmFsLCBpZiB0aGUgYml0 IGNhbiBiZSBhY3F1aXJlZA0KKyAgKiBpbnN0YW50bHksIGl0IGlzLCBlbHNl IHRoZSBwYWlyIGlzIHVzZWQgdG8gYmxvY2sgdGhlIHRocmVhZCB1bnRpbCB0 aGUNCisgICogYml0IGlzIGNsZWFyZWQuDQorICAqLw0KKyANCisgdHlwZWRl ZiBzdHJ1Y3Qgew0KKyAJY2hhciAgICAgICAgICAgICBsb2NrZWQ7IC8qIDA9 dW5sb2NrZWQsIDE9bG9ja2VkICovDQorIAkvKiBhIDxjb25kLCBtdXRleD4g cGFpciB0byBoYW5kbGUgYW4gYWNxdWlyZSBvZiBhIGxvY2tlZCBsb2NrICov DQorIAlwdGhfY29uZF90ICAgbG9ja19yZWxlYXNlZDsNCisgCXB0aF9tdXRl eF90ICBtdXQ7DQorIH0gcHRoX2xvY2s7DQorIA0KKyAjZGVmaW5lIENIRUNL X1NUQVRVUyhuYW1lKSAgaWYgKHN0YXR1cyA9PSAtMSkgeyBwcmludGYoIiVk ICIsIHN0YXR1cyk7IHBlcnJvcihuYW1lKTsgZXJyb3IgPSAxOyB9DQorIA0K KyAvKg0KKyAgKiBJbml0aWFsaXphdGlvbi4NCisgICovDQorIA0KKyBzdGF0 aWMgdm9pZCBQeVRocmVhZF9faW5pdF90aHJlYWQgX1AwKCkNCisgew0KKyAJ cHRoX2luaXQoKTsNCisgfQ0KKyANCisgLyoNCisgICogVGhyZWFkIHN1cHBv cnQuDQorICAqLw0KKyANCisgDQorIGludCBQeVRocmVhZF9zdGFydF9uZXdf dGhyZWFkIF9QMihmdW5jLCB2b2lkICgqZnVuYykgX1AoKHZvaWQgKikpLCBh cmcsIHZvaWQgKmFyZykNCisgew0KKyAJcHRoX3QgdGg7DQorIAlpbnQgc3Vj Y2VzczsNCisgCWRwcmludGYoKCJQeVRocmVhZF9zdGFydF9uZXdfdGhyZWFk IGNhbGxlZFxuIikpOw0KKyAJaWYgKCFpbml0aWFsaXplZCkNCisgCQlQeVRo cmVhZF9pbml0X3RocmVhZCgpOw0KKyANCisgCXRoID0gcHRoX3NwYXduKFBU SF9BVFRSX0RFRkFVTFQsDQorIAkJCQkgKHZvaWQqICgqKV9QKCh2b2lkICop KSlmdW5jLA0KKyAJCQkJICh2b2lkICopYXJnDQorIAkJCQkgKTsNCisgDQor IAlyZXR1cm4gdGggPT0gTlVMTCA/IDAgOiAxOw0KKyB9DQorIA0KKyBsb25n IFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQgX1AwKCkNCisgew0KKyAJdm9s YXRpbGUgcHRoX3QgdGhyZWFkaWQ7DQorIAlpZiAoIWluaXRpYWxpemVkKQ0K KyAJCVB5VGhyZWFkX2luaXRfdGhyZWFkKCk7DQorIAkvKiBKdW1wIHRocm91 Z2ggc29tZSBob29wcyBmb3IgQWxwaGEgT1NGLzEgKi8NCisgCXRocmVhZGlk ID0gcHRoX3NlbGYoKTsNCisgCXJldHVybiAobG9uZykgKihsb25nICopICZ0 aHJlYWRpZDsNCisgfQ0KKyANCisgc3RhdGljIHZvaWQgZG9fUHlUaHJlYWRf ZXhpdF90aHJlYWQgX1AxKG5vX2NsZWFudXAsIGludCBub19jbGVhbnVwKQ0K KyB7DQorIAlkcHJpbnRmKCgiUHlUaHJlYWRfZXhpdF90aHJlYWQgY2FsbGVk XG4iKSk7DQorIAlpZiAoIWluaXRpYWxpemVkKSB7DQorIAkJaWYgKG5vX2Ns ZWFudXApDQorIAkJCV9leGl0KDApOw0KKyAJCWVsc2UNCisgCQkJZXhpdCgw KTsNCisgCX0NCisgfQ0KKyANCisgdm9pZCBQeVRocmVhZF9leGl0X3RocmVh ZCBfUDAoKQ0KKyB7DQorIAlkb19QeVRocmVhZF9leGl0X3RocmVhZCgwKTsN CisgfQ0KKyANCisgdm9pZCBQeVRocmVhZF9fZXhpdF90aHJlYWQgX1AwKCkN Cisgew0KKyAJZG9fUHlUaHJlYWRfZXhpdF90aHJlYWQoMSk7DQorIH0NCisg DQorICNpZm5kZWYgTk9fRVhJVF9QUk9HDQorIHN0YXRpYyB2b2lkIGRvX1B5 VGhyZWFkX2V4aXRfcHJvZyBfUDIoc3RhdHVzLCBpbnQgc3RhdHVzLCBub19j bGVhbnVwLCBpbnQgbm9fY2xlYW51cCkNCisgew0KKyAJZHByaW50ZigoIlB5 VGhyZWFkX2V4aXRfcHJvZyglZCkgY2FsbGVkXG4iLCBzdGF0dXMpKTsNCisg CWlmICghaW5pdGlhbGl6ZWQpDQorIAkJaWYgKG5vX2NsZWFudXApDQorIAkJ CV9leGl0KHN0YXR1cyk7DQorIAkJZWxzZQ0KKyAJCQlleGl0KHN0YXR1cyk7 DQorIH0NCisgDQorIHZvaWQgUHlUaHJlYWRfZXhpdF9wcm9nIF9QMShzdGF0 dXMsIGludCBzdGF0dXMpDQorIHsNCisgCWRvX1B5VGhyZWFkX2V4aXRfcHJv ZyhzdGF0dXMsIDApOw0KKyB9DQorIA0KKyB2b2lkIFB5VGhyZWFkX19leGl0 X3Byb2cgX1AxKHN0YXR1cywgaW50IHN0YXR1cykNCisgew0KKyAJZG9fUHlU aHJlYWRfZXhpdF9wcm9nKHN0YXR1cywgMSk7DQorIH0NCisgI2VuZGlmIC8q IE5PX0VYSVRfUFJPRyAqLw0KKyANCisgLyoNCisgICogTG9jayBzdXBwb3J0 Lg0KKyAgKi8NCisgUHlUaHJlYWRfdHlwZV9sb2NrIFB5VGhyZWFkX2FsbG9j YXRlX2xvY2sgX1AwKCkNCisgew0KKyAJcHRoX2xvY2sgKmxvY2s7DQorIAlp bnQgc3RhdHVzLCBlcnJvciA9IDA7DQorIA0KKyAJZHByaW50ZigoIlB5VGhy ZWFkX2FsbG9jYXRlX2xvY2sgY2FsbGVkXG4iKSk7DQorIAlpZiAoIWluaXRp YWxpemVkKQ0KKyAJCVB5VGhyZWFkX2luaXRfdGhyZWFkKCk7DQorIA0KKyAJ bG9jayA9IChwdGhfbG9jayAqKSBtYWxsb2Moc2l6ZW9mKHB0aF9sb2NrKSk7 DQorICAgICAgICAgbWVtc2V0KCh2b2lkICopbG9jaywgJ1wwJywgc2l6ZW9m KHB0aF9sb2NrKSk7DQorIAlpZiAobG9jaykgew0KKyAJCWxvY2stPmxvY2tl ZCA9IDA7DQorIAkJc3RhdHVzID0gcHRoX211dGV4X2luaXQoJmxvY2stPm11 dCk7DQorIAkJQ0hFQ0tfU1RBVFVTKCJwdGhfbXV0ZXhfaW5pdCIpOw0KKyAJ CXN0YXR1cyA9IHB0aF9jb25kX2luaXQoJmxvY2stPmxvY2tfcmVsZWFzZWQp Ow0KKyAJCUNIRUNLX1NUQVRVUygicHRoX2NvbmRfaW5pdCIpOw0KKyAJCWlm IChlcnJvcikgew0KKyAJCQlmcmVlKCh2b2lkICopbG9jayk7DQorIAkJCWxv Y2sgPSBOVUxMOw0KKyAJCX0NCisgCX0NCisgCWRwcmludGYoKCJQeVRocmVh ZF9hbGxvY2F0ZV9sb2NrKCkgLT4gJWx4XG4iLCAobG9uZylsb2NrKSk7DQor IAlyZXR1cm4gKFB5VGhyZWFkX3R5cGVfbG9jaykgbG9jazsNCisgfQ0KKyAN Cisgdm9pZCBQeVRocmVhZF9mcmVlX2xvY2sgX1AxKGxvY2ssIFB5VGhyZWFk X3R5cGVfbG9jayBsb2NrKQ0KKyB7DQorIAlwdGhfbG9jayAqdGhlbG9jayA9 IChwdGhfbG9jayAqKWxvY2s7DQorIAlpbnQgc3RhdHVzLCBlcnJvciA9IDA7 DQorIA0KKyAJZHByaW50ZigoIlB5VGhyZWFkX2ZyZWVfbG9jayglbHgpIGNh bGxlZFxuIiwgKGxvbmcpbG9jaykpOw0KKyANCisgCWZyZWUoKHZvaWQgKil0 aGVsb2NrKTsNCisgfQ0KKyANCisgaW50IFB5VGhyZWFkX2FjcXVpcmVfbG9j ayBfUDIobG9jaywgUHlUaHJlYWRfdHlwZV9sb2NrIGxvY2ssIHdhaXRmbGFn LCBpbnQgd2FpdGZsYWcpDQorIHsNCisgCWludCBzdWNjZXNzOw0KKyAJcHRo X2xvY2sgKnRoZWxvY2sgPSAocHRoX2xvY2sgKilsb2NrOw0KKyAJaW50IHN0 YXR1cywgZXJyb3IgPSAwOw0KKyANCisgCWRwcmludGYoKCJQeVRocmVhZF9h Y3F1aXJlX2xvY2soJWx4LCAlZCkgY2FsbGVkXG4iLCAobG9uZylsb2NrLCB3 YWl0ZmxhZykpOw0KKyANCisgCXN0YXR1cyA9IHB0aF9tdXRleF9hY3F1aXJl KCZ0aGVsb2NrLT5tdXQsICF3YWl0ZmxhZywgTlVMTCk7DQorIAlDSEVDS19T VEFUVVMoInB0aF9tdXRleF9hY3F1aXJlWzFdIik7DQorIAlzdWNjZXNzID0g dGhlbG9jay0+bG9ja2VkID09IDA7DQorICAgICAgICAgaWYgKHN1Y2Nlc3Mp IHRoZWxvY2stPmxvY2tlZCA9IDE7DQorICAgICAgICAgc3RhdHVzID0gcHRo X211dGV4X3JlbGVhc2UoICZ0aGVsb2NrLT5tdXQgKTsNCisgICAgICAgICBD SEVDS19TVEFUVVMoInB0aF9tdXRleF9yZWxlYXNlWzFdIik7DQorIA0KKyAg ICAgICAgIGlmICggIXN1Y2Nlc3MgJiYgd2FpdGZsYWcgKSB7DQorICAgICAg ICAgICAgICAgICAvKiBjb250aW51ZSB0cnlpbmcgdW50aWwgd2UgZ2V0IHRo ZSBsb2NrICovDQorIA0KKyAgICAgICAgICAgICAgICAgLyogbXV0IG11c3Qg YmUgbG9ja2VkIGJ5IG1lIC0tIHBhcnQgb2YgdGhlIGNvbmRpdGlvbg0KKyAg ICAgICAgICAgICAgICAgICogcHJvdG9jb2wgKi8NCisgICAgICAgICAgICAg ICAgIHN0YXR1cyA9IHB0aF9tdXRleF9hY3F1aXJlKCAmdGhlbG9jay0+bXV0 LCAhd2FpdGZsYWcsIE5VTEwgKTsNCisgICAgICAgICAgICAgICAgIENIRUNL X1NUQVRVUygicHRoX211dGV4X2FjcXVpcmVbMl0iKTsNCisgICAgICAgICAg ICAgICAgIHdoaWxlICggdGhlbG9jay0+bG9ja2VkICkgew0KKyAgICAgICAg ICAgICAgICAgICAgICAgICBzdGF0dXMgPSBwdGhfY29uZF9hd2FpdCgmdGhl bG9jay0+bG9ja19yZWxlYXNlZCwNCisgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgJnRoZWxvY2stPm11dCwgTlVM TCk7DQorICAgICAgICAgICAgICAgICAgICAgICAgIENIRUNLX1NUQVRVUygi cHRoX2NvbmRfYXdhaXQiKTsNCisgICAgICAgICAgICAgICAgIH0NCisgICAg ICAgICAgICAgICAgIHRoZWxvY2stPmxvY2tlZCA9IDE7DQorICAgICAgICAg ICAgICAgICBzdGF0dXMgPSBwdGhfbXV0ZXhfcmVsZWFzZSggJnRoZWxvY2st Pm11dCApOw0KKyAgICAgICAgICAgICAgICAgQ0hFQ0tfU1RBVFVTKCJwdGhf bXV0ZXhfcmVsZWFzZVsyXSIpOw0KKyAgICAgICAgICAgICAgICAgc3VjY2Vz cyA9IDE7DQorICAgICAgICAgfQ0KKyAgICAgICAgIGlmIChlcnJvcikgc3Vj Y2VzcyA9IDA7DQorICAgICAgICAgZHByaW50ZigoIlB5VGhyZWFkX2FjcXVp cmVfbG9jayglbHgsICVkKSAtPiAlZFxuIiwgKGxvbmcpbG9jaywgd2FpdGZs YWcsIHN1Y2Nlc3MpKTsNCisgCXJldHVybiBzdWNjZXNzOw0KKyB9DQorIA0K KyB2b2lkIFB5VGhyZWFkX3JlbGVhc2VfbG9jayBfUDEobG9jaywgUHlUaHJl YWRfdHlwZV9sb2NrIGxvY2spDQorIHsNCisgICAgICAgICBwdGhfbG9jayAq dGhlbG9jayA9IChwdGhfbG9jayAqKWxvY2s7DQorICAgICAgICAgaW50IHN0 YXR1cywgZXJyb3IgPSAwOw0KKyANCisgICAgICAgICBkcHJpbnRmKCgiUHlU aHJlYWRfcmVsZWFzZV9sb2NrKCVseCkgY2FsbGVkXG4iLCAobG9uZylsb2Nr KSk7DQorIA0KKyAgICAgICAgIHN0YXR1cyA9IHB0aF9tdXRleF9hY3F1aXJl KCAmdGhlbG9jay0+bXV0LCAwLCBOVUxMICk7DQorICAgICAgICAgQ0hFQ0tf U1RBVFVTKCJwdGhfbXV0ZXhfYWNxdWlyZVszXSIpOw0KKyANCisgICAgICAg ICB0aGVsb2NrLT5sb2NrZWQgPSAwOw0KKyANCisgICAgICAgICBzdGF0dXMg PSBwdGhfbXV0ZXhfcmVsZWFzZSggJnRoZWxvY2stPm11dCApOw0KKyAgICAg ICAgIENIRUNLX1NUQVRVUygicHRoX211dGV4X3JlbGVhc2VbM10iKTsNCisg DQorICAgICAgICAgLyogd2FrZSB1cCBzb21lb25lIChhbnlvbmUsIGlmIGFu eSkgd2FpdGluZyBvbiB0aGUgbG9jayAqLw0KKyAgICAgICAgIHN0YXR1cyA9 IHB0aF9jb25kX25vdGlmeSggJnRoZWxvY2stPmxvY2tfcmVsZWFzZWQsIDAg KTsNCisgICAgICAgICBDSEVDS19TVEFUVVMoInB0aF9jb25kX25vdGlmeSIp Ow0KKyB9DQorIA0KKyAvKg0KKyAgKiBTZW1hcGhvcmUgc3VwcG9ydC4NCisg ICovDQorIA0KKyBzdHJ1Y3Qgc2VtYXBob3JlIHsNCisgCXB0aF9tdXRleF90 IG11dGV4Ow0KKyAJcHRoX2NvbmRfdCBjb25kOw0KKyAJaW50IHZhbHVlOw0K KyB9Ow0KKyANCisgUHlUaHJlYWRfdHlwZV9zZW1hIFB5VGhyZWFkX2FsbG9j YXRlX3NlbWEgX1AxKHZhbHVlLCBpbnQgdmFsdWUpDQorIHsNCisgCXN0cnVj dCBzZW1hcGhvcmUgKnNlbWE7DQorIAlpbnQgc3RhdHVzLCBlcnJvciA9IDA7 DQorIA0KKyAJZHByaW50ZigoIlB5VGhyZWFkX2FsbG9jYXRlX3NlbWEgY2Fs bGVkXG4iKSk7DQorIAlpZiAoIWluaXRpYWxpemVkKQ0KKyAJCVB5VGhyZWFk X2luaXRfdGhyZWFkKCk7DQorIA0KKyAJc2VtYSA9IChzdHJ1Y3Qgc2VtYXBo b3JlICopIG1hbGxvYyhzaXplb2Yoc3RydWN0IHNlbWFwaG9yZSkpOw0KKyAJ aWYgKHNlbWEgIT0gTlVMTCkgew0KKyAJCXNlbWEtPnZhbHVlID0gdmFsdWU7 DQorIAkJc3RhdHVzID0gcHRoX211dGV4X2luaXQoJnNlbWEtPm11dGV4KTsN CisgCQlDSEVDS19TVEFUVVMoInB0aF9tdXRleF9pbml0Iik7DQorIAkJc3Rh dHVzID0gcHRoX2NvbmRfaW5pdCgmc2VtYS0+Y29uZCk7DQorIAkJQ0hFQ0tf U1RBVFVTKCJwdGhfbXV0ZXhfaW5pdCIpOw0KKyAJCWlmIChlcnJvcikgew0K KyAJCQlmcmVlKCh2b2lkICopIHNlbWEpOw0KKyAJCQlzZW1hID0gTlVMTDsN CisgCQl9DQorIAl9DQorIAlkcHJpbnRmKCgiUHlUaHJlYWRfYWxsb2NhdGVf c2VtYSgpIC0+ICVseFxuIiwgKGxvbmcpIHNlbWEpKTsNCisgCXJldHVybiAo UHlUaHJlYWRfdHlwZV9zZW1hKSBzZW1hOw0KKyB9DQorIA0KKyB2b2lkIFB5 VGhyZWFkX2ZyZWVfc2VtYSBfUDEoc2VtYSwgUHlUaHJlYWRfdHlwZV9zZW1h IHNlbWEpDQorIHsNCisgCWludCBzdGF0dXMsIGVycm9yID0gMDsNCisgCXN0 cnVjdCBzZW1hcGhvcmUgKnRoZXNlbWEgPSAoc3RydWN0IHNlbWFwaG9yZSAq KSBzZW1hOw0KKyANCisgCWRwcmludGYoKCJQeVRocmVhZF9mcmVlX3NlbWEo JWx4KSBjYWxsZWRcbiIsIChsb25nKSBzZW1hKSk7DQorIAlmcmVlKCh2b2lk ICopIHRoZXNlbWEpOw0KKyB9DQorIA0KKyBpbnQgUHlUaHJlYWRfZG93bl9z ZW1hIF9QMihzZW1hLCBQeVRocmVhZF90eXBlX3NlbWEgc2VtYSwgd2FpdGZs YWcsIGludCB3YWl0ZmxhZykNCisgew0KKyAJaW50IHN0YXR1cywgZXJyb3Ig PSAwLCBzdWNjZXNzOw0KKyAJc3RydWN0IHNlbWFwaG9yZSAqdGhlc2VtYSA9 IChzdHJ1Y3Qgc2VtYXBob3JlICopIHNlbWE7DQorIA0KKyAJZHByaW50Zigo IlB5VGhyZWFkX2Rvd25fc2VtYSglbHgsICVkKSBjYWxsZWRcbiIsIChsb25n KSBzZW1hLCB3YWl0ZmxhZykpOw0KKyAJc3RhdHVzID0gcHRoX211dGV4X2Fj cXVpcmUoJnRoZXNlbWEtPm11dGV4LCAhd2FpdGZsYWcsIE5VTEwpOw0KKyAJ Q0hFQ0tfU1RBVFVTKCJwdGhfbXV0ZXhfYWNxdWlyZSIpOw0KKyAJaWYgKHdh aXRmbGFnKSB7DQorIAkJd2hpbGUgKCFlcnJvciAmJiB0aGVzZW1hLT52YWx1 ZSA8PSAwKSB7DQorIAkJCXN0YXR1cyA9IHB0aF9jb25kX2F3YWl0KCZ0aGVz ZW1hLT5jb25kLA0KKyAJCQkJCQkmdGhlc2VtYS0+bXV0ZXgsIE5VTEwpOw0K KyAJCQlDSEVDS19TVEFUVVMoInB0aF9jb25kX2F3YWl0Iik7DQorIAkJfQ0K KyAJfQ0KKyAJaWYgKGVycm9yKQ0KKyAJCXN1Y2Nlc3MgPSAwOw0KKyAJZWxz ZSBpZiAodGhlc2VtYS0+dmFsdWUgPiAwKSB7DQorIAkJdGhlc2VtYS0+dmFs dWUtLTsNCisgCQlzdWNjZXNzID0gMTsNCisgCX0NCisgCWVsc2UNCisgCQlz dWNjZXNzID0gMDsNCisgCXN0YXR1cyA9IHB0aF9tdXRleF9yZWxlYXNlKCZ0 aGVzZW1hLT5tdXRleCk7DQorIAlDSEVDS19TVEFUVVMoInB0aF9tdXRleF9y ZWxlYXNlIik7DQorIAlkcHJpbnRmKCgiUHlUaHJlYWRfZG93bl9zZW1hKCVs eCkgcmV0dXJuXG4iLCAobG9uZykgc2VtYSkpOw0KKyAJcmV0dXJuIHN1Y2Nl c3M7DQorIH0NCisgDQorIHZvaWQgUHlUaHJlYWRfdXBfc2VtYSBfUDEoc2Vt YSwgUHlUaHJlYWRfdHlwZV9zZW1hIHNlbWEpDQorIHsNCisgCWludCBzdGF0 dXMsIGVycm9yID0gMDsNCisgCXN0cnVjdCBzZW1hcGhvcmUgKnRoZXNlbWEg PSAoc3RydWN0IHNlbWFwaG9yZSAqKSBzZW1hOw0KKyANCisgCWRwcmludGYo KCJQeVRocmVhZF91cF9zZW1hKCVseClcbiIsIChsb25nKSBzZW1hKSk7DQor IAlzdGF0dXMgPSBwdGhfbXV0ZXhfYWNxdWlyZSgmdGhlc2VtYS0+bXV0ZXgs IDAsIE5VTEwpOw0KKyAJQ0hFQ0tfU1RBVFVTKCJwdGhfbXV0ZXhfYWNxdWly ZSIpOw0KKyAJdGhlc2VtYS0+dmFsdWUrKzsNCisgCXN0YXR1cyA9IHB0aF9j b25kX25vdGlmeSgmdGhlc2VtYS0+Y29uZCwgMSk7DQorIAlDSEVDS19TVEFU VVMoInB0aF9jb25kX25vdGlmeSIpOw0KKyAJc3RhdHVzID0gcHRoX211dGV4 X3JlbGVhc2UoJnRoZXNlbWEtPm11dGV4KTsNCisgCUNIRUNLX1NUQVRVUygi cHRoX211dGV4X3JlbGVhc2UiKTsNCisgfQ0K ---187888452-1274021780-957373218=:24903-- From trentm@activestate.com Thu May 4 00:16:56 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 3 May 2000 16:16:56 -0700 Subject: [Patches] make 'b','h','i' raise overflow exception (was: issues with int/long on 64bit platforms - eg stringobject (PR#306)) Message-ID: <20000503161656.A20275@activestate.com> Description: Changes the 'b', 'h', and 'i' formatters in PyArg_ParseTuple to raise an Overflow exception if they overflow (previously they just silently overflowed). 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: --- main/Apps/Perlium/Python/dist/src/Python/getargs.c.~1~ Tue May 2 16:48:46 2000 +++ main/Apps/Perlium/Python/dist/src/Python/getargs.c Tue May 2 16:48:46 2000 @@ -471,6 +471,16 @@ long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; + else if (ival < CHAR_MIN) { + PyErr_SetString(PyExc_OverflowError, + "byte integer is less than minimum"); + return "integer"; + } + else if (ival > CHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "byte integer is greater than maximum"); + return "integer"; + } else *p = (char) ival; break; @@ -482,6 +492,16 @@ long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "short integer is less than minimum"); + return "integer"; + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "short integer is greater than maximum"); + return "integer"; + } else *p = (short) ival; break; @@ -493,6 +513,16 @@ long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; + else if (ival < INT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "integer is less than minimum"); + return "integer"; + } + else if (ival > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "integer is greater than maximum"); + return "integer"; + } else *p = ival; break; End of Patch. From trentm@activestate.com Thu May 4 00:18:11 2000 From: trentm@activestate.com (Trent Mick) Date: Wed, 3 May 2000 16:18:11 -0700 Subject: [Patches] fix string methods implementing slice-like arguments (was:issues with int/long on 64bit platforms - eg stringobject (PR#306)) Message-ID: <20000503161811.B20275@activestate.com> Decription: Fix the string methods that implement slice-like semantics with optional args (count, find, endswith, etc.) to properly handle indeces outside [INT_MIN, INT_MAX]. Previously the "i" formatter for PyArg_ParseTuple was used to get the indeces. These could overflow. This patch changes the string methods to use the "O&" formatter with the slice_index() function from ceval.c which is used to do the same job for Python code slices (e.g. 'abcabcabc'[0:1000000000L]). slice_index() is renamed _PyEval_SliceIndex() and is now exported. As well, the return values for success/fail were changed to make slice_index directly usable as required by the "O&" formatter. 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: --- main/Apps/Perlium/Python/dist/src/Include/ceval.h.~1~ Wed May 3 15:45:50 2000 +++ main/Apps/Perlium/Python/dist/src/Include/ceval.h Wed May 3 15:45:50 2000 @@ -144,6 +144,9 @@ #endif /* !WITH_THREAD */ +extern DL_IMPORT(int) _PyEval_SliceIndex Py_PROTO((PyObject *, int *)); + + #ifdef __cplusplus } #endif --- main/Apps/Perlium/Python/dist/src/Objects/stringobject.c.~1~ Wed May 3 15:45:50 2000 +++ main/Apps/Perlium/Python/dist/src/Objects/stringobject.c Wed May 3 15:45:50 2000 @@ -825,8 +825,8 @@ int n, i = 0, last = INT_MAX; PyObject *subobj; - if (!PyArg_ParseTuple(args, "O|ii:find/rfind/index/rindex", - &subobj, &i, &last)) + if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", + &subobj, _PyEval_SliceIndex, &i, _PyEval_SliceIndex, &last)) return -2; if (PyString_Check(subobj)) { sub = PyString_AS_STRING(subobj); @@ -1197,8 +1197,10 @@ int m, r; PyObject *subobj; - if (!PyArg_ParseTuple(args, "O|ii:count", &subobj, &i, &last)) + if (!PyArg_ParseTuple(args, "O|O&O&:count", &subobj, + _PyEval_SliceIndex, &i, _PyEval_SliceIndex, &last)) return NULL; + if (PyString_Check(subobj)) { sub = PyString_AS_STRING(subobj); n = PyString_GET_SIZE(subobj); @@ -1620,7 +1622,8 @@ int end = -1; PyObject *subobj; - if (!PyArg_ParseTuple(args, "O|ii:startswith", &subobj, &start, &end)) + if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; if (PyString_Check(subobj)) { prefix = PyString_AS_STRING(subobj); @@ -1674,7 +1677,8 @@ int lower, upper; PyObject *subobj; - if (!PyArg_ParseTuple(args, "O|ii:endswith", &subobj, &start, &end)) + if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; if (PyString_Check(subobj)) { suffix = PyString_AS_STRING(subobj); --- main/Apps/Perlium/Python/dist/src/Python/ceval.c.~1~ Wed May 3 15:45:50 2000 +++ main/Apps/Perlium/Python/dist/src/Python/ceval.c Wed May 3 15:45:50 2000 @@ -80,7 +80,6 @@ static PyObject *call_builtin Py_PROTO((PyObject *, PyObject *, PyObject *)); static PyObject *call_function Py_PROTO((PyObject *, PyObject *, PyObject *)); static PyObject *loop_subscript Py_PROTO((PyObject *, PyObject *)); -static int slice_index Py_PROTO((PyObject *, int *)); static PyObject *apply_slice Py_PROTO((PyObject *, PyObject *, PyObject *)); static int assign_slice Py_PROTO((PyObject *, PyObject *, PyObject *, PyObject *)); @@ -2585,8 +2584,12 @@ return NULL; } -static int -slice_index(v, pi) +/* Extract a slice index from a PyInt or PyLong, the index is bound to + the range [-INT_MAX+1, INTMAX]. Returns 0 and an exception if there is + and error. Returns 1 on success.*/ + +int +_PyEval_SliceIndex(v, pi) PyObject *v; int *pi; { @@ -2602,7 +2605,7 @@ if (!PyErr_ExceptionMatches( PyExc_OverflowError ) ) { /* It's not an overflow error, so just signal an error */ - return -1; + return 0; } /* It's an overflow error, so we need to @@ -2612,7 +2615,7 @@ /* Create a long integer with a value of 0 */ long_zero = PyLong_FromLong( 0L ); - if (long_zero == NULL) return -1; + if (long_zero == NULL) return 0; /* Check sign */ if (PyObject_Compare(long_zero, v) < 0) @@ -2628,7 +2631,7 @@ } else { PyErr_SetString(PyExc_TypeError, "slice index must be int"); - return -1; + return 0; } /* Truncate -- very long indices are truncated anyway */ if (x > INT_MAX) @@ -2637,7 +2640,7 @@ x = 0; *pi = x; } - return 0; + return 1; } static PyObject * @@ -2645,9 +2648,9 @@ PyObject *u, *v, *w; { int ilow = 0, ihigh = INT_MAX; - if (slice_index(v, &ilow) != 0) + if (!_PyEval_SliceIndex(v, &ilow)) return NULL; - if (slice_index(w, &ihigh) != 0) + if (!_PyEval_SliceIndex(w, &ihigh)) return NULL; return PySequence_GetSlice(u, ilow, ihigh); } @@ -2657,9 +2660,9 @@ PyObject *u, *v, *w, *x; { int ilow = 0, ihigh = INT_MAX; - if (slice_index(v, &ilow) != 0) + if (!_PyEval_SliceIndex(v, &ilow)) return -1; - if (slice_index(w, &ihigh) != 0) + if (!_PyEval_SliceIndex(w, &ihigh)) return -1; if (x == NULL) return PySequence_DelSlice(u, ilow, ihigh); End of Patch. From guido@python.org Thu May 4 00:37:14 2000 From: guido@python.org (Guido van Rossum) Date: Wed, 03 May 2000 19:37:14 -0400 Subject: [Patches] PyMem [2/8] - Include/mymalloc.h In-Reply-To: Your message of "Sun, 30 Apr 2000 21:40:33 +0200." <200004301940.VAA15018@python.inrialpes.fr> References: <200004301940.VAA15018@python.inrialpes.fr> Message-ID: <200005032337.TAA06202@eric.cnri.reston.va.us> Vladimir, I'm checking it all in now. We'll see how well it works in the next alpha release. Here are some comments... Suggestion: Include instructions for using your own allocator -- what you need to change, what you need to implement, what rules you need to play by. (Is there only one level where you can substitute your own? Or more?) Questions: Do we really need to have even b/w compat macro support for Py_Malloc()? I think it's cleaner to fail with an error during compilation or linking than to silently mess up things when someone calls it expecting that it will raise an exception where in fact it won't. I've deleted it. And also PyMem_XDEL, for the same reason. Should the PyCore_* names be _PyCore_* to indicate they are for internal use only? When *is* it okay to use them? --Guido van Rossum (home page: http://www.python.org/~guido/) From mhammond@skippinet.com.au Thu May 4 00:42:20 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Thu, 4 May 2000 09:42:20 +1000 Subject: [Patches] MBCS codecs fails on zero length string. Message-ID: I was obviously having a bad day :-( It is with great embarrassment and humility that I withdraw my previous withdrawal of this patch ;-) The NULL terminator does not come into these routines at all - the exact number of bytes (which may or may not include the NULL) are converted. Thus, being asked to encode or decode zero characters is perfectly valid. I promise in the future that I will wait at least 24 hours between code changes and patch submissions! Checkin message: Mark Hammond should get his act into gear (his words :-). Zero length strings _are_ valid! 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. diff -c -r2.15 unicodeobject.c *** unicodeobject.c 2000/05/03 12:27:22 2.15 --- unicodeobject.c 2000/05/03 23:41:05 *************** *** 1555,1561 **** /* First get the size of the result */ DWORD usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); ! if (usize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); v = _PyUnicode_New(usize); --- 1555,1561 ---- /* First get the size of the result */ DWORD usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); ! if (size > 0 && usize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); v = _PyUnicode_New(usize); *************** *** 1578,1586 **** { PyObject *repr; char *s; /* First get the size of the result */ ! DWORD mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); if (mbcssize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); --- 1578,1591 ---- { PyObject *repr; char *s; + DWORD mbcssize; + /* If there are no characters, bail now! */ + if (size==0) + return PyString_FromString(""); + /* First get the size of the result */ ! mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); if (mbcssize==0) return PyErr_SetFromWindowsErrWithFilename(0, NULL); From Vladimir.Marangozov@inrialpes.fr Thu May 4 10:41:01 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Thu, 4 May 2000 11:41:01 +0200 (CEST) Subject: [Patches] PyMem [2/8] - Include/mymalloc.h In-Reply-To: <200005032337.TAA06202@eric.cnri.reston.va.us> from "Guido van Rossum" at May 03, 2000 07:37:14 PM Message-ID: <200005040941.LAA31556@python.inrialpes.fr> Guido van Rossum wrote: > > Suggestion: > > Include instructions for using your own allocator -- what you need to > change, what you need to implement, what rules you need to play by. > (Is there only one level where you can substitute your own? Or more?) Okay, will do. A scenario might help: 1) Scenario A Suppose we want to use a debugging malloc library that collects info on where the malloc calls originate from. Assume the interface is: d_malloc(size_t n, char* src_file, unsigned long src_line) c.s. In this case, we would define (for example in config.h) : #define PyCore_MALLOC_FUNC d_malloc ... #define PyCore_MALLOC_PROTO Py_PROTO((size_t, char *, unsigned long)) ... #define NEED_TO_DECLARE_MALLOC_AND_FRIEND #define PyCore_MALLOC(n) PyCore_MALLOC_FUNC((n), __FILE__, __LINE__) ... 2) Scenario B For some reason, we want to use malloc hooks (defined & initialized in a 3rd party malloc library) instead of malloc functions. In this case, we would define: #define PyCore_MALLOC(n) ( (*malloc_hook)(n) ) ... and ignore the previous definitions about PyCore_MALLOC_FUNC, etc. > > Questions: > > Do we really need to have even b/w compat macro support for > Py_Malloc()? I think it's cleaner to fail with an error during > compilation or linking than to silently mess up things when someone > calls it expecting that it will raise an exception where in fact it > won't. I've deleted it. And also PyMem_XDEL, for the same reason. I leave this to your appreciation. It's about breaking/fixing 3rd party extensions... > > Should the PyCore_* names be _PyCore_* to indicate they are for > internal use only? Maybe. > When *is* it okay to use them? In a custom memory manager, not in user's code. They are supposed to be defined/overloaded in config.h whenever a custom allocator is used. They should never appear in the usual Python-related C code. In low-level memory management code, yes (or maybe, depends on the needs) -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From guido@python.org Thu May 4 16:40:59 2000 From: guido@python.org (Guido van Rossum) Date: Thu, 04 May 2000 11:40:59 -0400 Subject: [Patches] PyMem [2/8] - Include/mymalloc.h In-Reply-To: Your message of "Thu, 04 May 2000 11:41:01 +0200." <200005040941.LAA31556@python.inrialpes.fr> References: <200005040941.LAA31556@python.inrialpes.fr> Message-ID: <200005041540.LAA13253@eric.cnri.reston.va.us> > Okay, will do. A scenario might help: > > 1) Scenario A > > Suppose we want to use a debugging malloc library that collects info > on where the malloc calls originate from. Assume the interface is: > > d_malloc(size_t n, char* src_file, unsigned long src_line) c.s. > > In this case, we would define (for example in config.h) : > > #define PyCore_MALLOC_FUNC d_malloc > ... > #define PyCore_MALLOC_PROTO Py_PROTO((size_t, char *, unsigned long)) > ... > #define NEED_TO_DECLARE_MALLOC_AND_FRIEND > > #define PyCore_MALLOC(n) PyCore_MALLOC_FUNC((n), __FILE__, __LINE__) > ... > > 2) Scenario B > > For some reason, we want to use malloc hooks (defined & initialized in a 3rd > party malloc library) instead of malloc functions. In this case, we would > define: > > #define PyCore_MALLOC(n) ( (*malloc_hook)(n) ) > ... > > and ignore the previous definitions about PyCore_MALLOC_FUNC, etc. Shall I just paste these into the comments in mymalloc.h? > > Questions: > > > > Do we really need to have even b/w compat macro support for > > Py_Malloc()? I think it's cleaner to fail with an error during > > compilation or linking than to silently mess up things when someone > > calls it expecting that it will raise an exception where in fact it > > won't. I've deleted it. And also PyMem_XDEL, for the same reason. > > I leave this to your appreciation. > It's about breaking/fixing 3rd party extensions... OK, I'll disable them during alpha testing and re-enable them in the final release. > > Should the PyCore_* names be _PyCore_* to indicate they are for > > internal use only? > > Maybe. > > > When *is* it okay to use them? > > In a custom memory manager, not in user's code. They are supposed to be > defined/overloaded in config.h whenever a custom allocator is used. > They should never appear in the usual Python-related C code. > In low-level memory management code, yes (or maybe, depends on the needs) OK, I'll leave it as it is for now. --Guido van Rossum (home page: http://www.python.org/~guido/) From Vladimir.Marangozov@inrialpes.fr Thu May 4 18:00:56 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Thu, 4 May 2000 19:00:56 +0200 (CEST) Subject: [Patches] PyMem [2/8] - Include/mymalloc.h In-Reply-To: <200005041540.LAA13253@eric.cnri.reston.va.us> from "Guido van Rossum" at May 04, 2000 11:40:59 AM Message-ID: <200005041700.TAA06972@python.inrialpes.fr> Guido van Rossum wrote: > > Shall I just paste these into the comments in mymalloc.h? Why not. Perhaps with small stylistic changes to the text (without 'we') and by replacing the definition in Scenario B with #define PyCore_MALLOC_FUNC (*malloc_hook) ... #define NEED_TO_DECLARE_MALLOC_AND_FRIEND This would declare the hook vars as extern and would make PyCore_MALLOC(n) = (*malloc_hook)(n) in one shot (I've tested this and it works well). -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From guido@python.org Thu May 4 19:51:12 2000 From: guido@python.org (Guido van Rossum) Date: Thu, 04 May 2000 14:51:12 -0400 Subject: [Patches] Patch for thread_nt.h, radically increasing Python perfomance In-Reply-To: Your message of "Thu, 04 May 2000 10:50:01 +1000." References: Message-ID: <200005041851.OAA13727@eric.cnri.reston.va.us> Yakov, Thanks for your patches. They have been 'vetted' by Mark Hammond who loves the speed increase, so now I am checking them in to the source -- they will get good exercise when the next alpha release comes out! --Guido van Rossum (home page: http://www.python.org/~guido/) From mhammond@skippinet.com.au Fri May 5 02:34:11 2000 From: mhammond@skippinet.com.au (Mark Hammond) Date: Fri, 5 May 2000 11:34:11 +1000 Subject: [Patches] thread_nt.h typo in debug mode Message-ID: I forgot that I made this quick fix - a simple typo in the debug statement: diff -r2.7 thread_nt.h 170c170 < dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), aThreadId)); --- > dprintf(("%ld: PyThread_start_new_thread succeeded: %ld\n", PyThread_get_thread_ident(), rv)); Note I am violating my 24 hour rule already! 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 tdickenson@geminidataloggers.com Fri May 5 15:04:41 2000 From: tdickenson@geminidataloggers.com (Toby Dickenson) Date: Fri, 5 May 2000 15:04:41 +0100 Subject: [Patches] patch for freeze with "-s service" and "-m" Message-ID: <9FC702711D39D3118D4900902778ADC81284D7@JUPITER> Fix for problem with freeze when both "-m" and "-s service" options are used. *** freeze.1.34.py Fri May 05 13:59:50 2000 --- freeze.py Fri May 05 14:01:41 2000 *************** *** 335,344 **** if python_entry_is_main: mf.run_script(scriptfile) else: ! if modargs: ! mf.import_hook(scriptfile) ! else: ! mf.load_file(scriptfile) if debug > 0: mf.report() --- 335,341 ---- if python_entry_is_main: mf.run_script(scriptfile) else: ! mf.load_file(scriptfile) if debug > 0: mf.report() 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. Toby Dickenson From trentm@activestate.com Fri May 5 21:58:17 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 5 May 2000 13:58:17 -0700 Subject: [Patches] PC\config.[hc] changes for Win64 Message-ID: <20000505135817.A9859@activestate.com> Discussion: Changes to PC\config.[hc] for Win64. MSVC defines _WINxx to differentiate the various windows platforms. Python's MS_WINxx are keyed off of these. Note that _WIN32 (and hence MS_WIN32 in Python) are defined on Win32 *and* on Win64. This is for compatibility reasons. The idea is that the common case is that code specific to Win32 will also work on Win64 rather than being specific to Win32 (i.e. there is more the same than different in WIn32 and Win64). The following modules are specifically excluded in the Win64 build: audioop, binascii, imageop, rgbimg. They are advertised as heavily 32-bit dependent. The patch to config.h looks big but it really is not. These are the effective changes: - MS_WINxx are keyed off _WINxx - SIZEOF_VOID_P is set to 8 for Win64 - COMPILER string is changed appropriately for Win64 Trent -- Trent Mick trentm@activestate.com 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 Fri May 5 10:53:35 2000 --- ./PC/config.h Fri May 5 13:10:11 2000 *************** *** 11,17 **** The code specific to Windows should be wrapped around one of the following #defines ! MS_WIN32 - Code specific to the MS Win32 API MS_WIN16 - Code specific to the old 16 bit Windows API. MS_WINDOWS - Code specific to Windows, but all versions. MS_COREDLL - Code if the Python core is built as a DLL. --- 11,18 ---- The code specific to Windows should be wrapped around one of the following #defines ! MS_WIN64 - Code specific to the MS Win64 API ! MS_WIN32 - Code specific to the MS Win32 (and Win64) API MS_WIN16 - Code specific to the old 16 bit Windows API. MS_WINDOWS - Code specific to Windows, but all versions. MS_COREDLL - Code if the Python core is built as a DLL. *************** *** 42,54 **** #define EXEC_PREFIX "" /* Microsoft C defines _MSC_VER */ ! #if defined(_MSC_VER) && _MSC_VER > 850 ! /* Start of defines for MS_WIN32 using VC++ 2.0 and up */ #define NT /* NT is obsolete - please use MS_WIN32 instead */ #define MS_WIN32 #define MS_WINDOWS /* For NT the Python core is in a DLL by default. Test the standard macro MS_COREDLL to find out. If you have an exception you must define MS_NO_COREDLL (do not test this macro) */ --- 43,96 ---- #define EXEC_PREFIX "" /* Microsoft C defines _MSC_VER */ + #ifdef _MSC_VER ! /* MSVC defines _WINxx to differentiate the windows platform types ! ! Note that for compatibility reasons _WIN32 is defined on Win32 ! *and* on Win64. For the same reasons, in Python, MS_WIN32 is ! defined on Win32 *and* Win64. Win32 only code must therefore be ! guarded as follows: ! #if defined(MS_WIN32) && !defined(MS_WIN64) ! */ ! #ifdef _WIN64 ! #define MS_WIN64 ! #endif ! #ifdef _WIN32 #define NT /* NT is obsolete - please use MS_WIN32 instead */ #define MS_WIN32 + #endif + #ifdef _WIN16 + #define MS_WIN16 + #endif #define MS_WINDOWS + /* set the COMPILER */ + #ifdef MS_WIN64 + #ifdef _M_IX86 + #define COMPILER "[MSC 64 bit (Intel)]" + #elif defined(_M_ALPHA) + #define COMPILER "[MSC 64 bit (Alpha)]" + #else + #define COMPILER "[MSC 64 bit (Unknown)]" + #endif + #endif /* MS_WIN64 */ + + #if defined(MS_WIN32) && !defined(MS_WIN64) + #ifdef _M_IX86 + #define COMPILER "[MSC 32 bit (Intel)]" + #elif defined(_M_ALPHA) + #define COMPILER "[MSC 32 bit (Alpha)]" + #else + #define COMPILER "[MSC (Unknown)]" + #endif + #endif /* MS_WIN32 && !MS_WIN64 */ + + #endif /* _MSC_VER */ + + #if defined(_MSC_VER) && _MSC_VER > 850 + /* Start of defines for MS_WIN32 using VC++ 2.0 and up */ + /* For NT the Python core is in a DLL by default. Test the standard macro MS_COREDLL to find out. If you have an exception you must define MS_NO_COREDLL (do not test this macro) */ *************** *** 59,71 **** #endif /* !USE_DL_EXPORT */ #endif /* !MS_NO_COREDLL */ - #ifdef _M_IX86 - #define COMPILER "[MSC 32 bit (Intel)]" - #elif defined(_M_ALPHA) - #define COMPILER "[MSC 32 bit (Alpha)]" - #else - #define COMPILER "[MSC (Unknown)]" - #endif #define PYTHONPATH ".\\DLLs;.\\lib;.\\lib\\plat-win;.\\lib\\lib-tk" typedef int pid_t; #define WORD_BIT 32 --- 101,106 ---- *************** *** 92,102 **** #define LONG_LONG __int64 #endif /* _MSC_VER && > 850 */ ! #if defined(_MSC_VER) && _MSC_VER <= 850 /* Start of defines for 16-bit Windows using VC++ 1.5 */ #define COMPILER "[MSC 16-bit]" - #define MS_WIN16 - #define MS_WINDOWS #define PYTHONPATH ".;.\\lib;.\\lib\\plat-win;.\\lib\\dos-8x3" #define IMPORT_8x3_NAMES typedef int pid_t; --- 127,135 ---- #define LONG_LONG __int64 #endif /* _MSC_VER && > 850 */ ! #if defined(_MSC_VER) && _MSC_VER <= 850 /* presume this implies Win16 */ /* Start of defines for 16-bit Windows using VC++ 1.5 */ #define COMPILER "[MSC 16-bit]" #define PYTHONPATH ".;.\\lib;.\\lib\\plat-win;.\\lib\\dos-8x3" #define IMPORT_8x3_NAMES typedef int pid_t; *************** *** 200,214 **** /* End of compilers - finish up */ ! #ifdef MS_WIN32 #define PLATFORM "win32" #else ! #ifdef MS_WIN16 #define PLATFORM "win16" #else #define PLATFORM "dos" ! #endif /* !MS_WIN16 */ ! #endif /* !MS_WIN32 */ #ifdef MS_WIN32 --- 233,254 ---- /* End of compilers - finish up */ ! #if defined(MS_WIN64) ! #define PLATFORM "win64" ! #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 ! #ifdef MS_WIN32 *************** *** 229,240 **** #define SIZEOF_LONG 4 #define SIZEOF_LONG_LONG 8 - #ifdef _M_ALPHA - #define SIZEOF_VOID_P 8 - #else - #define SIZEOF_VOID_P 4 - #endif - /* Smaller stack size limit. (9500 would work too, but we're conservative.) */ #ifndef MAX_RECURSION_DEPTH --- 269,274 ---- *** /home/trentm/main/contrib/python/dist/src/PC/config.c Fri May 5 10:53:35 2000 --- ./PC/config.c Fri May 5 13:10:11 2000 *************** *** 37,54 **** --- 37,60 ---- #include "Python.h" extern void initarray(); + #ifndef MS_WIN64 extern void initaudioop(); extern void initbinascii(); + #endif extern void initcmath(); extern void initerrno(); + #ifndef MS_WIN64 extern void initimageop(); + #endif extern void initmath(); extern void initmd5(); extern void initnew(); extern void initnt(); extern void initoperator(); extern void initregex(); + #ifndef MS_WIN64 extern void initrgbimg(); + #endif extern void initrotor(); extern void initsignal(); extern void initsha(); *************** *** 74,92 **** --- 80,106 ---- {"array", initarray}, #ifdef MS_WINDOWS + #ifndef MS_WIN64 {"audioop", initaudioop}, #endif + #endif + #ifndef MS_WIN64 {"binascii", initbinascii}, + #endif {"cmath", initcmath}, {"errno", initerrno}, + #ifndef MS_WIN64 {"imageop", initimageop}, + #endif {"math", initmath}, {"md5", initmd5}, {"new", initnew}, {"nt", initnt}, /* Use the NT os functions, not posix */ {"operator", initoperator}, {"regex", initregex}, + #ifndef MS_WIN64 {"rgbimg", initrgbimg}, + #endif {"rotor", initrotor}, {"signal", initsignal}, {"sha", initsha}, From trentm@activestate.com Sat May 6 00:13:59 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 5 May 2000 16:13:59 -0700 Subject: [Patches] fix overflow bug in ldexp(x, exp) Message-ID: <20000505161359.B11901@activestate.com> Discussion: Fix overflow bug in ldexp(x, exp). The 'exp' argument maps to a C int for the math library call [double ldexp(double, int)], however the 'd' PyArg_ParseTuple formatter was used to yield a double, which was subsequently cast to an int. This could overflow. Actually, this patch depends on my earlier patch to make the 'i' formatter throw an Overflow exception, see: http://www.python.org/pipermail/patches/2000-May/000607.html This is a very unlikely (ldexp with a huge exponent) case but... >>> from math import * >>> pow(2, 31) # max C 'int' value + 1 2147483648.0 >>> >>> ldexp(1, 1) 2.0 >>> ldexp(1, 100) 1.26765060023e+30 >>> ldexp(1, 10000) inf >>> ldexp(1, 100000) inf >>> ldexp(1, 2147483647) inf >>> ldexp(1, 2147483648) OverflowError: integer literal too large >>> ldexp(1, 2147483648L) # this overflows the int to s large negative 0.0 >>> With this patch (and an earlier one of mine)... >>> from math import * >>> ldexp(1, 100) 1.2676506002282294e+30 >>> ldexp(1, 2147483647) inf >>> ldexp(1, 2147483648L) Traceback (most recent call last): File "", line 1, in ? OverflowError: long int too long to convert >>> 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/mathmodule.c ./Modules/mathmodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/mathmodule.c Fri May 5 10:53:32 2000 --- ./Modules/mathmodule.c Fri May 5 15:41:43 2000 *************** *** 196,208 **** PyObject *self; PyObject *args; { ! double x, y; ! /* Cheat -- allow float as second argument */ ! if (! PyArg_Parse(args, "(dd)", &x, &y)) return NULL; errno = 0; PyFPE_START_PROTECT("ldexp", return 0) ! x = ldexp(x, (int)y); PyFPE_END_PROTECT(x) CHECK(x); if (errno != 0) --- 196,208 ---- PyObject *self; PyObject *args; { ! double x; ! int exp; ! if (! PyArg_Parse(args, "(di)", &x, &exp)) return NULL; errno = 0; PyFPE_START_PROTECT("ldexp", return 0) ! x = ldexp(x, exp); PyFPE_END_PROTECT(x) CHECK(x); if (errno != 0) -- Trent Mick trentm@activestate.com From guido@python.org Mon May 8 14:45:32 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 09:45:32 -0400 Subject: [Patches] GNU pth thread library support In-Reply-To: Your message of "Wed, 03 May 2000 13:00:31 EDT." References: Message-ID: <200005081345.JAA19803@eric.cnri.reston.va.us> > This patch adds the ability for Python to use the GNU pth threading > library. pth is a non-preemptive user-space threading library. For more > information, see http://www.gnu.org/software/pth. It presently has only > been tested on Linux. And of course it's against current CVS... > > Buglets: Some annoying compiler warnings about socketbits.h. The > configuration could probably be better: It may conflict if other threading > libraries (other than pthreads) are installed. Andy, I've applied your patch -- I don't know anything about GNU pth, but it seems your patch doesn't affect anything when GNU pth is not installed, so I'm fine with it. One thing: you sent in a change to config.h.in. That's not how it's done -- you add symbols to acconfig.h (in the proper alphabetical order!), and they automatically get added to config.h.in when you run autoheader. I fixed this by adding _GNU_PTH to acconfig.h; I didn't see any references to the HAVE_PTH_INIT symbol in your code so I left that out. Realize that I don't have the time to maintain or debug this -- if a conflict is reported with the configuration during the alpha cycle, it's up to you to fix it. --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 8 15:00:30 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 10:00:30 -0400 Subject: [Patches] make 'b','h','i' raise overflow exception (was: issues with int/long on 64bit platforms - eg stringobject (PR#306)) In-Reply-To: Your message of "Wed, 03 May 2000 16:16:56 PDT." <20000503161656.A20275@activestate.com> References: <20000503161656.A20275@activestate.com> Message-ID: <200005081400.KAA19889@eric.cnri.reston.va.us> > Changes the 'b', 'h', and 'i' formatters in PyArg_ParseTuple to raise an > Overflow exception if they overflow (previously they just silently > overflowed). Trent, There's one issue with this: I believe the 'b' format is mostly used with unsigned character arguments in practice. However on systems with default signed characters, CHAR_MAX is 127 and values 128-255 are rejected. I'll change the overflow test to: else if (ival > CHAR_MAX && ival >= 256) { if that's okay with you. I'm not sure that the same problem arises with the 'h' format, so I'll leave that one alone. Another issue however is that there are probably cases where an 'i' format is used (which can't overflow on 32-bit architectures) but where the int value is then copied into a short field without an additional check... I'm not sure how to fix this except by a complete inspection of all code... Not clear if it's worth it. --Guido van Rossum (home page: http://www.python.org/~guido/) From adustman@comstar.net Mon May 8 15:02:04 2000 From: adustman@comstar.net (Andy Dustman) Date: Mon, 8 May 2000 10:02:04 -0400 (EDT) Subject: [Patches] GNU pth thread library support In-Reply-To: <200005081345.JAA19803@eric.cnri.reston.va.us> Message-ID: On Mon, 8 May 2000, Guido van Rossum wrote: > I've applied your patch -- I don't know anything about GNU pth, but it > seems your patch doesn't affect anything when GNU pth is not > installed, so I'm fine with it. > > One thing: you sent in a change to config.h.in. That's not how it's > done -- you add symbols to acconfig.h (in the proper alphabetical > order!), and they automatically get added to config.h.in when you run > autoheader. I fixed this by adding _GNU_PTH to acconfig.h; I didn't > see any references to the HAVE_PTH_INIT symbol in your code so I left > that out. Sorry about that. This is really the first stab I've had at modifying anything that uses GNU autoconf. > Realize that I don't have the time to maintain or debug this -- if a > conflict is reported with the configuration during the alpha cycle, > it's up to you to fix it. I'll do my best. At least it passes the normal threading tests. -- andy dustman | programmer/analyst | comstar.net, inc. telephone: 770.485.6025 / 706.549.7689 | icq: 32922760 | pgp: 0xc72f3f1d "Therefore, sweet knights, if you may doubt your strength or courage, come no further, for death awaits you all, with nasty, big, pointy teeth!" From guido@python.org Mon May 8 15:09:35 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 10:09:35 -0400 Subject: [Patches] fix string methods implementing slice-like arguments (was:issues with int/long on 64bit platforms - eg stringobject (PR#306)) In-Reply-To: Your message of "Wed, 03 May 2000 16:18:11 PDT." <20000503161811.B20275@activestate.com> References: <20000503161811.B20275@activestate.com> Message-ID: <200005081409.KAA20094@eric.cnri.reston.va.us> > Fix the string methods that implement slice-like semantics with > optional args (count, find, endswith, etc.) to properly handle > indeces outside [INT_MIN, INT_MAX]. Previously the "i" formatter > for PyArg_ParseTuple was used to get the indeces. These could overflow. > > This patch changes the string methods to use the "O&" formatter with > the slice_index() function from ceval.c which is used to do the same > job for Python code slices (e.g. 'abcabcabc'[0:1000000000L]). slice_index() > is renamed _PyEval_SliceIndex() and is now exported. As well, the return > values for success/fail were changed to make slice_index directly > usable as required by the "O&" formatter. Thanks, Trent! Did you look into unicodeobject.c? It has similar methods with similar weaknesses! --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 8 15:16:42 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 10:16:42 -0400 Subject: [Patches] PC\config.[hc] changes for Win64 In-Reply-To: Your message of "Fri, 05 May 2000 13:58:17 PDT." <20000505135817.A9859@activestate.com> References: <20000505135817.A9859@activestate.com> Message-ID: <200005081416.KAA20158@eric.cnri.reston.va.us> > Changes to PC\config.[hc] for Win64. MSVC defines _WINxx to differentiate the > various windows platforms. Python's MS_WINxx are keyed off of these. Note > that _WIN32 (and hence MS_WIN32 in Python) are defined on Win32 *and* on > Win64. This is for compatibility reasons. The idea is that the common case is > that code specific to Win32 will also work on Win64 rather than being > specific to Win32 (i.e. there is more the same than different in WIn32 and > Win64). > > The following modules are specifically excluded in the Win64 build: > audioop, binascii, imageop, rgbimg. They are advertised as heavily 32-bit > dependent. > > The patch to config.h looks big but it really is not. These are the effective > changes: > - MS_WINxx are keyed off _WINxx > - SIZEOF_VOID_P is set to 8 for Win64 > - COMPILER string is changed appropriately for Win64 Thanks, Trent! One thing worries me: if COMPILER is changed, that changes sys.platform to "win64", right? I'm sure that will break plenty of code which currently tests for sys.platform=="win32" but really wants to test for any form of Windows. Maybe sys.platform should remain win32? --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 8 15:35:19 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 10:35:19 -0400 Subject: [Patches] fix overflow bug in ldexp(x, exp) In-Reply-To: Your message of "Fri, 05 May 2000 16:13:59 PDT." <20000505161359.B11901@activestate.com> References: <20000505161359.B11901@activestate.com> Message-ID: <200005081435.KAA20562@eric.cnri.reston.va.us> > Fix overflow bug in ldexp(x, exp). The 'exp' argument maps to a C int for the > math library call [double ldexp(double, int)], however the 'd' > PyArg_ParseTuple formatter was used to yield a double, which was subsequently > cast to an int. This could overflow. > > Actually, this patch depends on my earlier patch to make the 'i' formatter > throw an Overflow exception, see: > http://www.python.org/pipermail/patches/2000-May/000607.html > > This is a very unlikely (ldexp with a huge exponent) case but... > > >>> from math import * > >>> pow(2, 31) # max C 'int' value + 1 > 2147483648.0 > >>> > >>> ldexp(1, 1) > 2.0 > >>> ldexp(1, 100) > 1.26765060023e+30 > >>> ldexp(1, 10000) > inf > >>> ldexp(1, 100000) > inf > >>> ldexp(1, 2147483647) > inf > >>> ldexp(1, 2147483648) > OverflowError: integer literal too large > >>> ldexp(1, 2147483648L) # this overflows the int to s large negative > 0.0 > >>> > > > With this patch (and an earlier one of mine)... > > >>> from math import * > >>> ldexp(1, 100) > 1.2676506002282294e+30 > >>> ldexp(1, 2147483647) > inf > >>> ldexp(1, 2147483648L) > Traceback (most recent call last): > File "", line 1, in ? > OverflowError: long int too long to convert > >>> Thanks, Trent. I've applied this patch, but actually I'm a little confused. On Solaris 2.7, I'm now getting this: >>> ldexp(1, 100000000) Traceback (most recent call last): File "", line 1, in ? OverflowError: math range error >>> ldexp(1, sys.maxint-1) Traceback (most recent call last): File "", line 1, in ? OverflowError: math range error >>> ldexp(1, sys.maxint) # this takes a second or two... Infinity # ...expected OverflowError! >>> I have a feeling though that this is a bug in the C math library -- not sure if it's worth fixing. On Linux I get an OverflowError as expected for sys.maxint. Note that ldexp(1, 3.14) is still accepted! The 'i' format calls tp_int for floats and int(3.14) is 3. --Guido van Rossum (home page: http://www.python.org/~guido/) From caolan@csn.ul.ie Mon May 8 17:51:28 2000 From: caolan@csn.ul.ie (Caolan McNamara) Date: Mon, 8 May 2000 17:51:28 +0100 (IST) Subject: [Patches] oneliner for poplib bug 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. ---913833367-1090922277-957804688=:12767 Content-Type: TEXT/PLAIN; charset=US-ASCII The pop3 spec (rfc 1939) states that lines that begin with a single "." in the original message are presented by the server to the client bytestuffed with an additional ".", poplib does not strip this leading byte. The attached mini patch takes care of it . <-- Should only be one dot not two :-) C. ===yadda yadda=== 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. Real Life: Caolan McNamara * Doing: MSc in HCI Work: Caolan.McNamara@ul.ie * Phone: +353-86-8790257 URL: http://www.csn.ul.ie/~caolan * Sig: an oblique strategy Ask people to work against their better judgements ---913833367-1090922277-957804688=:12767 Content-Type: TEXT/PLAIN; charset=US-ASCII; name=patch Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename=patch LS0tIFB5dGhvbi0xLjUuMi9MaWIvcG9wbGliLnB5CU1vbiBTZXAgMTQgMTk6 MzY6NTEgMTk5OA0KKysrIG5ldy9MaWIvcG9wbGliLnB5CU1vbiBNYXkgIDgg MTg6NDA6MTggMjAwMA0KQEAgLTEzMyw2ICsxMzMsOSBAQA0KIAkJbGlzdCA9 IFtdOyBvY3RldHMgPSAwDQogCQlsaW5lLCBvID0gc2VsZi5fZ2V0bGluZSgp DQogCQl3aGlsZSBsaW5lICE9ICcuJzoNCisJCQlpZiBsaW5lWzoxXSA9PSAn Lic6DQorCQkJCW8gPSBvLTENCisJCQkJbGluZSA9IGxpbmVbMTpdDQogCQkJ b2N0ZXRzID0gb2N0ZXRzICsgbw0KIAkJCWxpc3QuYXBwZW5kKGxpbmUpDQog CQkJbGluZSwgbyA9IHNlbGYuX2dldGxpbmUoKQ0K ---913833367-1090922277-957804688=:12767-- From guido@python.org Mon May 8 17:54:21 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 12:54:21 -0400 Subject: [Patches] oneliner for poplib bug In-Reply-To: Your message of "Mon, 08 May 2000 17:51:28 BST." References: Message-ID: <200005081654.MAA21099@eric.cnri.reston.va.us> > The pop3 spec (rfc 1939) states that lines that begin > with a single "." in the original message are presented > by the server to the client bytestuffed with an > additional ".", poplib does not strip this leading byte. > > The attached mini patch takes care of it > . <-- Should only be one dot not two :-) | --- Python-1.5.2/Lib/poplib.py Mon Sep 14 19:36:51 1998 | +++ new/Lib/poplib.py Mon May 8 18:40:18 2000 | @@ -133,6 +133,9 @@ | list = []; octets = 0 | line, o = self._getline() | while line != '.': | + if line[:1] == '.': | + o = o-1 | + line = line[1:] | octets = octets + o | list.append(line) | line, o = self._getline() Hm, wouldn't it be safer if you did if line[:2] == '..': o = o-1 line = line[1:] ??? That way if there was a line that *wasn't* bytestuffed (server bug?) the single leading dot wouldn't disappear. --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Mon May 8 18:40:10 2000 From: guido@python.org (Guido van Rossum) Date: Mon, 08 May 2000 13:40:10 -0400 Subject: [Patches] Final request for GC patch In-Reply-To: Your message of "Wed, 26 Apr 2000 09:51:37 MDT." <20000426095137.B13009@acs.ucalgary.ca> References: <14597.49537.611625.343576@buffalo.fnal.gov> <20000426095137.B13009@acs.ucalgary.ca> Message-ID: <200005081740.NAA21503@eric.cnri.reston.va.us> Neil (or Charles), Now that Vladimir's memory patches are in, could you generate another version of your GC patch? I think I'm ready to incorporate this now as an experimental feature, but I don't have the time to deal with all the FAILED hunks that patch complains about... Also, Greg Stein is right that the spare fields should be renamed unconditionally. --Guido van Rossum (home page: http://www.python.org/~guido/) From trentm@activestate.com Mon May 8 22:58:19 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 8 May 2000 14:58:19 -0700 Subject: [Patches] fix string methods implementing slice-like arguments (was:issues with int/long on 64bit platforms - eg stringobject (PR#306)) In-Reply-To: <200005081409.KAA20094@eric.cnri.reston.va.us> References: <20000503161811.B20275@activestate.com> <200005081409.KAA20094@eric.cnri.reston.va.us> Message-ID: <20000508145819.A10917@activestate.com> On Mon, May 08, 2000 at 10:09:35AM -0400, Guido van Rossum wrote: > > Fix the string methods that implement slice-like semantics with > > optional args (count, find, endswith, etc.) to properly handle > > indeces outside [INT_MIN, INT_MAX]. Previously the "i" formatter > > for PyArg_ParseTuple was used to get the indeces. These could overflow. > > > > This patch changes the string methods to use the "O&" formatter with > > the slice_index() function from ceval.c which is used to do the same > > job for Python code slices (e.g. 'abcabcabc'[0:1000000000L]). slice_index() > > is renamed _PyEval_SliceIndex() and is now exported. As well, the return > > values for success/fail were changed to make slice_index directly > > usable as required by the "O&" formatter. > > Did you look into unicodeobject.c? It has similar methods with > similar weaknesses! > Here you go. I had a problem sending this (I apologize if you get this twice). Description: Fix the unicode string methods that implement slice-like semantics with optional args (count, find, endswith, etc.) to properly handle indeces outside [INT_MIN, INT_MAX]. Previously the "i" formatter for PyArg_ParseTuple was used to get the indeces. These could overflow. This patch changes the unicode string methods to use the "O&" formatter with the _PyEval_SliceIndex() function from ceval.c which is used to do the same job for Python code slices (e.g. 'abcabcabc'[0:1000000000L]). 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/Objects/unicodeobject.c ./Objects/unicodeobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/unicodeobject.c Fri May 5 12:50:04 2000 --- ./Objects/unicodeobject.c Mon May 8 13:47:56 2000 *************** *** 3023,3029 **** int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|ii:count", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( --- 3023,3030 ---- int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( *************** *** 3150,3156 **** int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|ii:find", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); --- 3151,3158 ---- int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|O&O&:find", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); *************** *** 3212,3218 **** int start = 0; int end = INT_MAX; ! if (!PyArg_ParseTuple(args, "O|ii:index", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( --- 3214,3221 ---- int start = 0; int end = INT_MAX; ! if (!PyArg_ParseTuple(args, "O|O&O&:index", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( *************** *** 3642,3648 **** int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|ii:rfind", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); --- 3645,3652 ---- int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|O&O&:rfind", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); *************** *** 3668,3674 **** int start = 0; int end = INT_MAX; ! if (!PyArg_ParseTuple(args, "O|ii:rindex", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); --- 3672,3679 ---- int start = 0; int end = INT_MAX; ! if (!PyArg_ParseTuple(args, "O|O&O&:rindex", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); *************** *** 3937,3943 **** int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|ii:startswith", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); --- 3942,3949 ---- int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); *************** *** 3967,3973 **** int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|ii:endswith", &substring, &start, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); --- 3973,3980 ---- int end = INT_MAX; PyObject *result; ! if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &substring, ! _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; substring = (PyUnicodeObject *)PyUnicode_FromObject( (PyObject *)substring); -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon May 8 23:19:30 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 8 May 2000 15:19:30 -0700 Subject: [Patches] fix overflow bug in ldexp(x, exp) In-Reply-To: <200005081435.KAA20562@eric.cnri.reston.va.us> References: <20000505161359.B11901@activestate.com> <200005081435.KAA20562@eric.cnri.reston.va.us> Message-ID: <20000508151930.B10917@activestate.com> On Mon, May 08, 2000 at 10:35:19AM -0400, Guido van Rossum wrote: > Thanks, Trent. I've applied this patch, but actually I'm a little > confused. > > On Solaris 2.7, I'm now getting this: > > >>> ldexp(1, 100000000) > Traceback (most recent call last): > File "", line 1, in ? > OverflowError: math range error > >>> ldexp(1, sys.maxint-1) > Traceback (most recent call last): > File "", line 1, in ? > OverflowError: math range error > >>> ldexp(1, sys.maxint) # this takes a second or two... > Infinity # ...expected OverflowError! > >>> > > I have a feeling though that this is a bug in the C math library -- > not sure if it's worth fixing. On Linux I get an OverflowError as > expected for sys.maxint. It seems to me, as well, that that is a C math library bug. It is not returning an ERANGE errno. Can you reproduce this with a simple C program, on Solaris? #include #include #include #include int main(void) { double x; printf("ldexp(1.0, %d)=%lf\n", INT_MAX, ldexp(1.0, INT_MAX)); printf("errno = %d (ERANGE=%d)\n", errno, ERANGE); } > > Note that ldexp(1, 3.14) is still accepted! The 'i' format calls > tp_int for floats and int(3.14) is 3. That is another matter. I don't know what I should expect the 'i' formatter to do. It calls PyInt_AsLong. Should PyInt_AsLong complain if it is given a PyFloatObject? That is a philosophical question that is kind of moot here (its behaviour is not going to change). I think that ldexp() should *not* accept a float for the 'exp' argument because the rounding to an int is not obvious to the user. I suppose the 'O&' formatter could be used with a special converter that raises a TypeError if the argument is not an integral type (i.e. PyInt or PyLong). Is it worth making that change? Is it even desired to make that change because it might break some code out there. thanks, Trent -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon May 8 23:49:58 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 8 May 2000 15:49:58 -0700 Subject: [Python-Dev] Re: [Patches] PC\config.[hc] changes for Win64 In-Reply-To: References: <20000508142651.C8000@activestate.com> Message-ID: <20000508154958.C10917@activestate.com> On Tue, May 09, 2000 at 08:15:17AM +1000, Mark Hammond wrote: > [Trent] > > What if someone needs to do something in Python code for either Win32 or > > Win64 but not both? Or should this never be necessary (not > > likely). I would > > like Mark H's opinion on this stuff. > > OK :-) > > I have always thought that it _would_ move to "win64", and the official way > of checking for "Windows" will be sys.platform[:3]=="win". > > In fact, Ive noticed Guido use this idiom (both stand-alone, and as :if > sys.platform[:3] in ["win", "mac"]) > > It will no doubt cause a bit of pain, but IMO it is cleaner... > Mark's a smart guy. I think using "win64" should be okay. When the "pain" comes, the user should not be totally blind to it. She should be inclined to blame failures on her new Windows64 OS anyway. :) I have included a patch to correct those occurences in the core python code. There weren't that many. Is there some bullet list somewhere that the following comment could get appended to: """The prefered method of checking for a windows platform in python code is: if sys.platform[:3] == "win" This includes the "win32" and "win64" """ Acutally it also includes "win16". Is that a problem? Discussion: Correct checks in python code for the windows platform to include "win64" as well. Thus the common idiom: if sys.platform == "win32": becomes: if sys.platform[:3] == "win" 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/Lib/dos-8x3/telnetli.py ./Lib/dos-8x3/telnetli.py *** /home/trentm/main/contrib/python/dist/src/Lib/dos-8x3/telnetli.py Mon May 8 11:49:03 2000 --- ./Lib/dos-8x3/telnetli.py Mon May 8 15:30:29 2000 *************** *** 377,383 **** def interact(self): """Interaction function, emulates a very dumb telnet client.""" ! if sys.platform == "win32": self.mt_interact() return while 1: --- 377,383 ---- def interact(self): """Interaction function, emulates a very dumb telnet client.""" ! if sys.platform[:3] == "win": self.mt_interact() return while 1: diff -c3 /home/trentm/main/contrib/python/dist/src/Lib/lib-tk/Tkinter.py ./Lib/lib-tk/Tkinter.py *** /home/trentm/main/contrib/python/dist/src/Lib/lib-tk/Tkinter.py Fri May 5 10:53:25 2000 --- ./Lib/lib-tk/Tkinter.py Mon May 8 15:31:31 2000 *************** *** 3,9 **** __version__ = "$Revision: 1.137 $" import sys ! if sys.platform == "win32": import FixTk # Attempt to configure Tcl/Tk without requiring PATH import _tkinter # If this fails your Python may not be configured for Tk tkinter = _tkinter # b/w compat for export --- 3,9 ---- __version__ = "$Revision: 1.137 $" import sys ! if sys.platform[:3] == "win": import FixTk # Attempt to configure Tcl/Tk without requiring PATH import _tkinter # If this fails your Python may not be configured for Tk tkinter = _tkinter # b/w compat for export diff -c3 /home/trentm/main/contrib/python/dist/src/Lib/telnetlib.py ./Lib/telnetlib.py *** /home/trentm/main/contrib/python/dist/src/Lib/telnetlib.py Fri May 5 10:53:28 2000 --- ./Lib/telnetlib.py Mon May 8 15:31:58 2000 *************** *** 377,383 **** def interact(self): """Interaction function, emulates a very dumb telnet client.""" ! if sys.platform == "win32": self.mt_interact() return while 1: --- 377,383 ---- def interact(self): """Interaction function, emulates a very dumb telnet client.""" ! if sys.platform[:3] == "win": self.mt_interact() return while 1: diff -c3 /home/trentm/main/contrib/python/dist/src/Tools/freeze/freeze.py ./Tools/freeze/freeze.py *** /home/trentm/main/contrib/python/dist/src/Tools/freeze/freeze.py Mon May 8 11:49:05 2000 --- ./Tools/freeze/freeze.py Mon May 8 15:33:03 2000 *************** *** 54,60 **** 'console' (default), 'windows', 'service' or 'com_dll' -w: Toggle Windows (NT or 95) behavior. ! (For debugging only -- on a win32 platform, win32 behaviour is automatic.) Arguments: --- 54,60 ---- 'console' (default), 'windows', 'service' or 'com_dll' -w: Toggle Windows (NT or 95) behavior. ! (For debugging only -- on a win32/64 platform, win32/64 behaviour is automatic.) Arguments: diff -c3 /home/trentm/main/contrib/python/dist/src/Tools/freeze/modulefinder.py ./Tools/freeze/modulefinder.py *** /home/trentm/main/contrib/python/dist/src/Tools/freeze/modulefinder.py Fri May 5 10:53:39 2000 --- ./Tools/freeze/modulefinder.py Mon May 8 15:34:29 2000 *************** *** 8,14 **** import string import sys ! if sys.platform=="win32": # On Windows, we can locate modules in the registry with # the help of the win32api package. try: --- 8,14 ---- import string import sys ! if sys.platform[:3] == "win": # On Windows, we can locate modules in the registry with # the help of the win32api package. try: *************** *** 332,338 **** return (None, None, ("", "", imp.C_BUILTIN)) # Emulate the Registered Module support on Windows. ! if sys.platform=="win32" and win32api is not None: HKEY_LOCAL_MACHINE = 0x80000002 try: pathname = win32api.RegQueryValue(HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore\\%s\\Modules\\%s" % (sys.winver, name)) --- 332,338 ---- return (None, None, ("", "", imp.C_BUILTIN)) # Emulate the Registered Module support on Windows. ! if sys.platform[:3] == "win" and win32api is not None: HKEY_LOCAL_MACHINE = 0x80000002 try: pathname = win32api.RegQueryValue(HKEY_LOCAL_MACHINE, "Software\\Python\\PythonCore\\%s\\Modules\\%s" % (sys.winver, name)) diff -c3 /home/trentm/main/contrib/python/dist/src/Tools/idle/Bindings.py ./Tools/idle/Bindings.py *** /home/trentm/main/contrib/python/dist/src/Tools/idle/Bindings.py Fri May 5 10:53:39 2000 --- ./Tools/idle/Bindings.py Mon May 8 15:34:51 2000 *************** *** 49,55 **** ]), ] ! if sys.platform == 'win32': default_keydefs = windows_keydefs else: default_keydefs = unix_keydefs --- 49,55 ---- ]), ] ! if sys.platform[:3] == 'win': default_keydefs = windows_keydefs else: default_keydefs = unix_keydefs diff -c3 /home/trentm/main/contrib/python/dist/src/Tools/idle/EditorWindow.py ./Tools/idle/EditorWindow.py *** /home/trentm/main/contrib/python/dist/src/Tools/idle/EditorWindow.py Fri May 5 10:53:39 2000 --- ./Tools/idle/EditorWindow.py Mon May 8 15:35:30 2000 *************** *** 538,544 **** ins = cls(self) self.extensions[name] = ins kdnames = ["keydefs"] ! if sys.platform == 'win32': kdnames.append("windows_keydefs") elif sys.platform == 'mac': kdnames.append("mac_keydefs") --- 538,544 ---- ins = cls(self) self.extensions[name] = ins kdnames = ["keydefs"] ! if sys.platform[:3] == 'win': kdnames.append("windows_keydefs") elif sys.platform == 'mac': kdnames.append("mac_keydefs") diff -c3 /home/trentm/main/contrib/python/dist/src/Tools/idle/ZoomHeight.py ./Tools/idle/ZoomHeight.py *** /home/trentm/main/contrib/python/dist/src/Tools/idle/ZoomHeight.py Fri May 5 10:53:40 2000 --- ./Tools/idle/ZoomHeight.py Mon May 8 15:35:58 2000 *************** *** 33,39 **** return width, height, x, y = map(int, m.groups()) newheight = top.winfo_screenheight() ! if sys.platform == 'win32': newy = 0 newheight = newheight - 72 else: --- 33,39 ---- return width, height, x, y = map(int, m.groups()) newheight = top.winfo_screenheight() ! if sys.platform[:3] == 'win': newy = 0 newheight = newheight - 72 else: -- Trent Mick trentm@activestate.com From fdrake@acm.org Tue May 9 05:59:34 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Tue, 9 May 2000 00:59:34 -0400 (EDT) Subject: [Python-Dev] Re: [Patches] PC\config.[hc] changes for Win64 In-Reply-To: <20000508154958.C10917@activestate.com> References: <20000508142651.C8000@activestate.com> <20000508154958.C10917@activestate.com> Message-ID: <14615.39734.203440.241659@newcnri.cnri.reston.va.us> Trent Mick writes: > Is there some bullet list somewhere that the following comment could get > appended to: """The prefered method of checking for a windows platform in I could add something to the documentation for sys.platform; that seems the most reasonable spot for it. If there's consensus on this I'll add this. -Fred -- Fred L. Drake, Jr. Corporation for National Research Initiatives From tim_one@email.msn.com Tue May 9 07:55:17 2000 From: tim_one@email.msn.com (Tim Peters) Date: Tue, 9 May 2000 02:55:17 -0400 Subject: [Patches] fix overflow bug in ldexp(x, exp) In-Reply-To: <20000508151930.B10917@activestate.com> Message-ID: <000501bfb983$8882efc0$592d153f@tim> [Trent Mick] > ... > I think that ldexp() should *not* accept a float for the 'exp' argument > because the rounding to an int is not obvious to the user. I agree, although a float may nevertheless be an exact integer (like 2.0). The NumPy folks would probably prefer a rule based on exactness rather than on concrete type. Screw 'em . > I suppose the 'O&' formatter could be used with a special converter > that raises a TypeError if the argument is not an integral type (i.e. > PyInt or PyLong). Is it worth making that change? Is it even desired > to make that change because it might break some code out there. Good question; ldexp's source code comment: /* Cheat -- allow float as second argument */ leaves the reason for the current behavior a mystery. Note another current revoltingism: >>> range(1., 8., 3.5) [1, 4, 7] >>> OK by me if all such crap "gets broke". From caolan@csn.ul.ie Tue May 9 08:26:50 2000 From: caolan@csn.ul.ie (Caolan McNamara) Date: Tue, 9 May 2000 08:26:50 +0100 (IST) Subject: [Patches] oneliner for poplib bug In-Reply-To: <200005081654.MAA21099@eric.cnri.reston.va.us> Message-ID: On Mon, 8 May 2000, Guido van Rossum wrote: > | while line != '.': > | + if line[:1] == '.': > | + o = o-1 > | + line = line[1:] > > Hm, wouldn't it be safer if you did > > if line[:2] == '..': > o = o-1 > line = line[1:] > > ??? > > That way if there was a line that *wasn't* bytestuffed (server bug?) > the single leading dot wouldn't disappear. Well the spec does say that "if the line begins with the termination octet and if octets other than CRLF follow, the first octet of the line is stripped away by the client" Though I do admit I can see no other case than that of a doubled .. where it might happen seeing as "If any line of the multi-line response begins with the termination octet, the line is "byte-stuffed" [by the server] by pre-pending the termination octet to that line of the response." So the second should also be ok. C. Real Life: Caolan McNamara * Doing: MSc in HCI Work: Caolan.McNamara@ul.ie * Phone: +353-86-8790257 URL: http://www.csn.ul.ie/~caolan * Sig: an oblique strategy Use an old idea From nascheme@enme.ucalgary.ca Tue May 9 10:00:04 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Tue, 9 May 2000 03:00:04 -0600 Subject: [Patches] Re: Final request for GC patch In-Reply-To: <200005081740.NAA21503@eric.cnri.reston.va.us>; from guido@python.org on Mon, May 08, 2000 at 01:40:10PM -0400 References: <14597.49537.611625.343576@buffalo.fnal.gov> <20000426095137.B13009@acs.ucalgary.ca> <200005081740.NAA21503@eric.cnri.reston.va.us> Message-ID: <20000509030004.A20169@acs.ucalgary.ca> I am quite busy writing my MSc thesis right now but here is a patch I think is okay. Some random notes: Object alloction has been changed from macros to functions for some important objects (list, tuple, dict). This will make Python go slower even with GC disabled. We will have to profile things and find out what should be inlined. For now I wanted the patch to be easy to understand. The PyObject_{New, VarNew} and PyObject_Del methods seem to be non-orthogonal regarding reference tracing. I think PyObject_Del should call _Py_ForgetReference. Setting ob_type to NULL does not make the collector happy. Guido likes this for debugging so it is enabled when GC is not used. Trashcan does funky stuff with ob_type but I think it is okay because it fixes ob_type before calling tp_dealloc and I call PyGC_Remove before TRASHCAN_BEGIN. Christian? The renaming of Setup.in.thread to Setup.in.auto may not be a good idea. I don't know if there is a better way of automaticly enabling a module based on an autoconf setting. Maybe PyGC_Insert and PyGC_Remove could be added to the PyObject_{New, VarNew, Del} functions. However, objects should only be in the collector set when they are "valid". You could change malloc to calloc and then check for null pointers in tp_recurse. I think it is better the way it is. The gc module could probably be better designed. Perhaps we should call it configure option --with-gc rather than --with-cycle-gc. I have only tested this latest patch on Linux. Vladimir's patches remove the special cases for Windows I think it should be okay on other platforms. Guido, if you want a leaking application try Grail or Sketch. There is also test_gc.py. My comment in objimp.h should tell people to define tp_clear too. Its pretty late here right now so it is possible I have attached something stupid to this message. In that case, forgive me. :) Neil -- Evolution of Language Through The Ages: 6000 B.C.: ungh. grrf. booga. 2000 A.D.: grep. awk. sed. Index: 0.5/Makefile.in --- 0.5/Makefile.in Tue, 25 Apr 2000 17:33:19 -0600 nas (python/0_Makefile.i 1.1 644) +++ gc.8(w)/Makefile.in Tue, 25 Apr 2000 17:59:00 -0600 nas (python/0_Makefile.i 1.1.1.1 644) @@ -401,7 +401,7 @@ $(INSTALL_DATA) Modules/Makefile $(LIBPL)/Makefile $(INSTALL_DATA) Modules/Setup $(LIBPL)/Setup $(INSTALL_DATA) Modules/Setup.local $(LIBPL)/Setup.local - $(INSTALL_DATA) Modules/Setup.thread $(LIBPL)/Setup.thread + $(INSTALL_DATA) Modules/Setup.auto $(LIBPL)/Setup.auto $(INSTALL_PROGRAM) $(srcdir)/Modules/makesetup $(LIBPL)/makesetup $(INSTALL_PROGRAM) $(srcdir)/install-sh $(LIBPL)/install-sh $(INSTALL_DATA) $(srcdir)/Misc/Makefile.pre.in $(LIBPL)/Makefile.pre.in Index: 0.5/config.h.in --- 0.5/config.h.in Mon, 08 May 2000 12:24:03 -0600 nas (python/3_config.h.i 1.1.2.1 644) +++ gc.8(w)/config.h.in Mon, 08 May 2000 12:27:51 -0600 nas (python/3_config.h.i 1.1.2.1 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.5/configure.in --- 0.5/configure.in Mon, 08 May 2000 12:24:03 -0600 nas (python/5_configure. 1.1.2.1 644) +++ gc.8(w)/configure.in Mon, 08 May 2000 12:28:06 -0600 nas (python/5_configure. 1.1.2.1 644) @@ -1074,10 +1074,21 @@ fi], [AC_MSG_RESULT(no)]) +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)) + # generate output files AC_OUTPUT(Makefile \ Objects/Makefile \ Parser/Makefile \ Python/Makefile \ Modules/Makefile.pre \ - Modules/Setup.thread) + Modules/Setup.auto) Index: 0.5/Include/object.h --- 0.5/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 Tue, 09 May 2000 02:08:30 -0600 nas (python/o/18_object.h 1.1.1.1 644) @@ -145,6 +147,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 +247,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 +326,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.5/Include/objimpl.h --- 0.5/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 Tue, 09 May 2000 01:46:04 -0600 nas (python/o/19_objimpl.h 1.1.2.1 644) @@ -144,7 +144,7 @@ constructor inlines PyObject_{New, NewVar}, either because the latter functions cannot allocate the exact amount of needed memory, either for speed. This situation is exceptional, but occurs for - some object constructors (PyBuffer_New, PyList_New...). Inlining + some object constructors (eg. PyBuffer_New). Inlining PyObject_{New, NewVar} for objects that are supposed to belong to the Python heap is discouraged. If you really have to, make sure the object is initialized with PyObject_{Init, InitVar}. Do *not* @@ -234,6 +234,56 @@ 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. + You should call PyGC_Insert after all the pointers followed by + tp_recurse become valid (usually just before returning the object + from allocation method. Call the PyGC_Remove before those pointers + become invalid (usually at the top of the deallocation method). */ + +/* Structure *prefixed* to container objects participating in GC */ +typedef struct _gcinfo { + struct _gcinfo *gc_next; + struct _gcinfo *gc_prev; + int gc_refs; +} PyGCInfo; + +/* Test if a type has GC info */ +#define Py_TYPEISGC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GCINFO) + +/* Test if an object has GC info */ +#define Py_ISGC(o) Py_TYPEISGC((o)->ob_type) + +/* Get an object's GC info -- NULL if the object has none */ +#define Py_GCINFO(o) (Py_ISGC(o) ? ((PyGCInfo *)(o)-1) : NULL) + +/* Unsafe version of Py_GCINFO() -- only call if Py_ISGC(p) is true */ +#define Py_GCINFO_UNSAFE(o) ((PyGCInfo *)(o)-1) + +/* Get the object given the PyGCInfo */ +#define Py_GCOBJ(g) ((PyObject *)((g)+1)) + +/* 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 *)); + +#else /* ! WITH_CYCLE_GC */ + +#define PyGC_Insert +#define PyGC_Remove + +#endif #ifdef __cplusplus } #endif Index: 0.5/Misc/Makefile.pre.in --- 0.5/Misc/Makefile.pre.in Tue, 25 Apr 2000 17:33:19 -0600 nas (python/B/45_Makefile.p 1.1 644) +++ gc.8(w)/Misc/Makefile.pre.in Tue, 25 Apr 2000 17:59:00 -0600 nas (python/B/45_Makefile.p 1.2 644) @@ -168,7 +168,7 @@ MAKEFILE= $(LIBPL)/Makefile CONFIGC= $(LIBPL)/config.c CONFIGCIN= $(LIBPL)/config.c.in -SETUP= $(LIBPL)/Setup.thread $(LIBPL)/Setup.local $(LIBPL)/Setup +SETUP= $(LIBPL)/Setup.auto $(LIBPL)/Setup.local $(LIBPL)/Setup SYSLIBS= $(LIBM) $(LIBC) Index: 0.5/Modules/Makefile.pre.in --- 0.5/Modules/Makefile.pre.in Tue, 25 Apr 2000 17:33:19 -0600 nas (python/C/17_Makefile.p 1.1 644) +++ gc.8(w)/Modules/Makefile.pre.in Tue, 25 Apr 2000 17:59:00 -0600 nas (python/C/17_Makefile.p 1.1.1.1 644) @@ -147,10 +147,10 @@ # gets remade from scratch; this ensures to remove modules that are no # longer pertinent (but that were in a previous configuration). config.c Makefile: Makefile.pre config.c.in $(MAKESETUP) -config.c Makefile: Setup.thread Setup Setup.local +config.c Makefile: Setup.auto Setup Setup.local config.c Makefile: -rm -f $(LIBRARY) - $(SHELL) $(MAKESETUP) Setup.thread Setup.local Setup + $(SHELL) $(MAKESETUP) Setup.auto Setup.local Setup hassignal: -rm -f hassignal Index: 0.5/Modules/Setup.in --- 0.5/Modules/Setup.in Mon, 08 May 2000 12:24:03 -0600 nas (python/C/18_Setup.in 1.1.2.1 644) +++ gc.8(w)/Modules/Setup.in Mon, 08 May 2000 12:28:14 -0600 nas (python/C/18_Setup.in 1.1.2.1 644) @@ -100,7 +100,7 @@ GLHACK=-Dclear=__GLclear #gl glmodule.c cgensupport.c -I$(srcdir) $(GLHACK) -lgl -lX11 -# The thread module is now automatically enabled, see Setup.thread. +# The thread module is now automatically enabled, see Setup.auto. # Pure module. Cannot be linked dynamically. # -DWITH_QUANTIFY, -DWITH_PURIFY, or -DWITH_ALL_PURE Index: 0.5/Modules/cPickle.c --- 0.5/Modules/cPickle.c Mon, 08 May 2000 12:24:03 -0600 nas (python/C/27_cPickle.c 1.1.2.1 644) +++ gc.8(w)/Modules/cPickle.c Tue, 09 May 2000 00:36:33 -0600 nas (python/C/27_cPickle.c 1.1.2.1 644) @@ -2893,7 +2893,7 @@ Py_DECREF(inst); goto err; } - + PyGC_Insert((PyObject *)inst); return (PyObject *)inst; } Py_DECREF(__getinitargs__); Index: 0.5/Modules/newmodule.c --- 0.5/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 Tue, 09 May 2000 00:36:44 -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.5/Objects/classobject.c --- 0.5/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 Tue, 09 May 2000 01:50:26 -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 = PyObject_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); + PyObject_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 = PyObject_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); + PyObject_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.5/Objects/dictobject.c --- 0.5/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 Tue, 09 May 2000 01:20:27 -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 = PyObject_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; } @@ -480,6 +481,7 @@ { register int i; register dictentry *ep; + PyGC_Remove((PyObject *)mp); Py_TRASHCAN_SAFE_BEGIN(mp) for (i = 0, ep = mp->ma_table; i < mp->ma_size; i++, ep++) { if (ep->me_key != NULL) { @@ -491,7 +493,7 @@ } if (mp->ma_table != NULL) PyMem_DEL(mp->ma_table); - PyObject_DEL(mp); + PyObject_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.5/Objects/funcobject.c --- 0.5/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 Tue, 09 May 2000 01:20:15 -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 = PyObject_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); + PyObject_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.5/Objects/listobject.c --- 0.5/Objects/listobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/25_listobject 1.1.2.2 644) +++ gc.8(w)/Objects/listobject.c Tue, 09 May 2000 01:19:41 -0600 nas (python/E/25_listobject 1.1.2.2 644) @@ -70,10 +70,9 @@ if (nbytes / sizeof(PyObject *) != (size_t)size) { return PyErr_NoMemory(); } - /* PyObject_NewVar is inlined */ - op = (PyListObject *) PyObject_MALLOC(sizeof(PyListObject)); + op = PyObject_NewVar(PyListObject, &PyList_Type, size); if (op == NULL) { - return PyErr_NoMemory(); + return NULL; } if (size <= 0) { op->ob_item = NULL; @@ -81,13 +80,13 @@ else { op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); if (op->ob_item == NULL) { - PyObject_FREE(op); + PyObject_Del(op); return PyErr_NoMemory(); } } - 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; } @@ -214,6 +213,7 @@ PyListObject *op; { int i; + PyGC_Remove((PyObject *)op); Py_TRASHCAN_SAFE_BEGIN(op) if (op->ob_item != NULL) { /* Do it backwards, for Christian Tismer. @@ -226,7 +226,7 @@ } PyMem_FREE(op->ob_item); } - PyObject_DEL(op); + PyObject_Del(op); Py_TRASHCAN_SAFE_END(op) } @@ -1419,6 +1419,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[] = @@ -1485,6 +1508,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 }; @@ -1553,5 +1588,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.5/Objects/object.c --- 0.5/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 Tue, 09 May 2000 02:04:32 -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 (Py_TYPEISGC(tp)) { + PyGCInfo *g; + g = (PyGCInfo *) PyObject_MALLOC(sizeof(*g) + + _PyObject_SIZE(tp)); + if (g == NULL) { + op = NULL; + } else { + op = Py_GCOBJ(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 (Py_TYPEISGC(tp)) { + PyGCInfo *g; + g = (PyGCInfo *) PyObject_MALLOC(sizeof(*g) + + _PyObject_VAR_SIZE(tp, size)); + if (g == NULL) { + op = NULL; + } else { + op = (PyVarObject *)Py_GCOBJ(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 (Py_TYPEISGC(op->ob_type)) { + PyGCInfo *g = Py_GCINFO(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.5/Objects/tupleobject.c --- 0.5/Objects/tupleobject.c Mon, 08 May 2000 12:24:03 -0600 nas (python/E/33_tupleobjec 1.1.2.2 644) +++ gc.8(w)/Objects/tupleobject.c Tue, 09 May 2000 01:30:56 -0600 nas (python/E/33_tupleobjec 1.1.2.2 644) @@ -98,12 +98,9 @@ { return PyErr_NoMemory(); } - /* PyObject_NewVar is inlined */ - op = (PyTupleObject *) PyObject_MALLOC(nbytes); + op = PyObject_NewVar(PyTupleObject, &PyTuple_Type, size); if (op == NULL) - return PyErr_NoMemory(); - - PyObject_INIT_VAR(op, &PyTuple_Type, size); + return NULL; } for (i = 0; i < size; i++) op->ob_item[i] = NULL; @@ -114,6 +111,7 @@ Py_INCREF(op); /* extra INCREF so that this is never freed */ } #endif + PyGC_Insert((PyObject *)op); return (PyObject *) op; } @@ -179,6 +177,9 @@ { register int i; register int len = op->ob_size; + if (len > 0) { + PyGC_Remove((PyObject *)op); + } Py_TRASHCAN_SAFE_BEGIN(op) if (len > 0) { i = len; @@ -193,7 +194,7 @@ } #endif } - PyObject_DEL(op); + PyObject_Del(op); done: Py_TRASHCAN_SAFE_END(op) } @@ -418,6 +419,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*/ @@ -445,6 +462,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: @@ -529,9 +556,21 @@ } else #endif { +#ifdef WITH_CYCLE_GC + PyGCInfo *g = Py_GCINFO((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 *)Py_GCOBJ(g); + } +#else sv = (PyTupleObject *) - PyObject_REALLOC((char *)v, + PyObject_Realloc((char *)v, sizeof(PyTupleObject) + newsize * sizeof(PyObject *)); +#endif *pv = (PyObject *) sv; if (sv == NULL) { PyObject_DEL(v); @@ -549,6 +588,7 @@ sv->ob_item[i - sizediff] = NULL; } } + PyGC_Insert((PyObject *)sv); sv->ob_size = newsize; return 0; } @@ -569,7 +609,7 @@ while (p) { q = p; p = (PyTupleObject *)(p->ob_item[0]); - PyObject_DEL(q); + PyObject_Del(q); } } #endif Index: 0.5/PC/config.c --- 0.5/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 Tue, 09 May 2000 00:50:42 -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.5/PC/config.h --- 0.5/PC/config.h Mon, 08 May 2000 12:24:03 -0600 nas (python/E/40_config.h 1.1.2.1 644) +++ gc.8(w)/PC/config.h Mon, 08 May 2000 12:28:15 -0600 nas (python/E/40_config.h 1.1.2.1 644) @@ -418,6 +418,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.5/PCbuild/python16.dsp --- 0.5/PCbuild/python16.dsp Tue, 25 Apr 2000 17:33:19 -0600 nas (python/G/1_python16.d 1.1 644) +++ gc.8(w)/PCbuild/python16.dsp Tue, 25 Apr 2000 17:59:00 -0600 nas (python/G/1_python16.d 1.2 644) @@ -645,6 +645,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.5/Modules/gcmodule.c --- 0.5/Modules/gcmodule.c Tue, 09 May 2000 02:20:05 -0600 nas () +++ gc.8(w)/Modules/gcmodule.c Tue, 09 May 2000 02:14:53 -0600 nas (python/M/10_gcmodule.c 1.3 644) @@ -0,0 +1,672 @@ +/* + + 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" + +#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; +} + +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 = Py_GCOBJ(gc)->ob_refcnt; + } +} + +static int +visit_decref(PyObject *op, void *data) +{ + if (op && Py_ISGC(op)) { + Py_GCINFO_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 = Py_GCOBJ(gc)->ob_type->tp_recurse; + (void) recurse(Py_GCOBJ(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 = Py_GCINFO(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 = Py_GCOBJ(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 = Py_GCOBJ(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 = Py_GCINFO(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 = Py_GCOBJ(gc)->ob_type->tp_recurse; + (void) recurse(Py_GCOBJ(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 = Py_GCOBJ(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 = Py_GCOBJ(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 ", Py_GCOBJ(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 ", Py_GCOBJ(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 (!Py_ISGC(op)) { + abort(); + } +#endif + if (threshold0 && allocated > threshold0 && !collecting) { + collecting++; + collect_generations(); + collecting--; + } + allocated++; + list_append(Py_GCINFO(op), &generation0); +} + +void +PyGC_Remove(PyObject *op) +{ + PyGCInfo *g = Py_GCINFO(op); +#ifdef Py_DEBUG + if (!Py_ISGC(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.5/Modules/Setup.auto.in --- 0.5/Modules/Setup.auto.in Tue, 09 May 2000 02:20:05 -0600 nas () +++ gc.8(w)/Modules/Setup.auto.in Tue, 25 Apr 2000 17:59:00 -0600 nas (python/M/11_Setup.auto 1.1 644) @@ -0,0 +1,16 @@ +# This file is transmogrified into Setup.auto by config.status. Its +# purpose is to automatically enable modules given when certain +# arguments are given to the configure script. It replaces the old +# Setup.thread.in file. + +# Include the thread module when the --with-thread argument is given to +# the configure script. +# +# *NOTE*: if the configure script decides it can't support threads, the +# thread module will still be enabled and cause compile errors. The +# solution is not to use --with-thread on platforms that don't support +# threads. +@USE_THREAD_MODULE@thread threadmodule.c + +# Garbage collection enabled with --with-cycle-gc +@USE_GC_MODULE@gc gcmodule.c Index: 0.5/Lib/test/test_gc.py --- 0.5/Lib/test/test_gc.py Tue, 09 May 2000 02:20:05 -0600 nas () +++ gc.8(w)/Lib/test/test_gc.py Tue, 25 Apr 2000 17:59:00 -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 guido@python.org Tue May 9 11:24:03 2000 From: guido@python.org (Guido van Rossum) Date: Tue, 09 May 2000 06:24:03 -0400 Subject: [Patches] fix overflow bug in ldexp(x, exp) In-Reply-To: Your message of "Tue, 09 May 2000 02:55:17 EDT." <000501bfb983$8882efc0$592d153f@tim> References: <000501bfb983$8882efc0$592d153f@tim> Message-ID: <200005091024.GAA22884@eric.cnri.reston.va.us> > Note another current revoltingism: > > >>> range(1., 8., 3.5) > [1, 4, 7] > >>> > > OK by me if all such crap "gets broke". Ditto here. But it's hard to fix. This was the consequence of a patch by Don Beaudry (remember Don?) with a good purpose: if an extension type supports "int-ness", e.g. by defining a tp_int function in its type object or (for a class instance) by having an __int__ method, it is acceptable for integral formats (e.g. i) in PyArg_Parse*(). Unfortunately, floats also have int-ness, in order to support the int() built-in function. I'm not sure how to fix this, but I believe that the best fix might be to define separate APIs an object can expose for int-ness and for roundable-or-truncatable-to-int-ness. Seems a Py3k issue though. BTW, this also suggests that Trent's recent patches to string methods are slightly backward incompatible, since they specifically check for int-or-long-ness. However, since these arguments are *documented* as behaving just like slice indices, and slice indices do the same thing, I think it's best to leave it like this. If we find a lot of user complaints of needlessly broken code, we can back out of this one... --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Tue May 9 15:05:27 2000 From: guido@python.org (Guido van Rossum) Date: Tue, 09 May 2000 10:05:27 -0400 Subject: [Patches] fix overflow bug in ldexp(x, exp) In-Reply-To: Your message of "Mon, 08 May 2000 15:19:30 PDT." <20000508151930.B10917@activestate.com> References: <20000505161359.B11901@activestate.com> <200005081435.KAA20562@eric.cnri.reston.va.us> <20000508151930.B10917@activestate.com> Message-ID: <200005091405.KAA23437@eric.cnri.reston.va.us> [me] > > On Solaris 2.7, I'm now getting this: > > > > >>> ldexp(1, 100000000) > > Traceback (most recent call last): > > File "", line 1, in ? > > OverflowError: math range error > > >>> ldexp(1, sys.maxint-1) > > Traceback (most recent call last): > > File "", line 1, in ? > > OverflowError: math range error > > >>> ldexp(1, sys.maxint) # this takes a second or two... > > Infinity # ...expected OverflowError! > > >>> > > > > I have a feeling though that this is a bug in the C math library -- > > not sure if it's worth fixing. On Linux I get an OverflowError as > > expected for sys.maxint. [Trent] > It seems to me, as well, that that is a C math library bug. It is not > returning an ERANGE errno. Can you reproduce this with a simple C program, on > Solaris? > > #include > #include > #include > #include ! > int main(void) > { > double x; > printf("ldexp(1.0, %d)=%lf\n", INT_MAX, ldexp(1.0, INT_MAX)); > printf("errno = %d (ERANGE=%d)\n", errno, ERANGE); > } This takes over a second to run and then prints ldexp(1.0, 2147483647)=Inf errno = 0 (ERANGE=34) Clearly a C library bug. I won't bother to report it to Sun. > > Note that ldexp(1, 3.14) is still accepted! The 'i' format calls > > tp_int for floats and int(3.14) is 3. > > That is another matter. I don't know what I should expect the 'i' formatter > to do. It calls PyInt_AsLong. Should PyInt_AsLong complain if it is given a > PyFloatObject? That is a philosophical question that is kind of moot here > (its behaviour is not going to change). See other discusssion. I agree. > I think that ldexp() should *not* accept a float for the 'exp' argument > because the rounding to an int is not obvious to the user. I suppose the 'O&' > formatter could be used with a special converter that raises a TypeError if > the argument is not an integral type (i.e. PyInt or PyLong). Is it worth > making that change? Is it even desired to make that change because it might > break some code out there. See other discussion. It's not worth the change -- too many other places suffer in the same way. --Guido van Rossum (home page: http://www.python.org/~guido/) From mal@lemburg.com Tue May 9 19:59:32 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Tue, 09 May 2000 20:59:32 +0200 Subject: [Patches] Unicode Patch Set 2000-05-09 Message-ID: <39186014.2E156C14@lemburg.com> This is a multi-part message in MIME format. --------------80712B74A5371BBFE8498331 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit This patch fixes a few bugglets and adds an experimental feature which allows setting the string encoding assumed by the Unicode implementation at run-time. The current implementation uses a process global for the string encoding. This should subsequently be changed to a thread state variable, so that the setting can be done on a per thread basis. Note that only the coercions from strings to Unicode are affected by the encoding parameter. str(unicode) and the "s" parser marker still return UTF-8. The main intent of this patch is to provide a test bed for the ongoing Unicode debate, e.g. to have the implementation use 'latin-1' as default string encoding, put import sys sys.set_string_encoding('latin-1') in you site.py file. Patch Set Contents: ------------------- Include/codecs.h: Added documentation and the missing PyCodec_StreamWriter API. Include/unicodeobject.h: Added PyUnicode_GetDefaultEncoding() and PyUnicode_GetDefaultEncoding() APIs. Modules/timemodule.c: Fixed a bug due to a /* inside /*...*/. GCC doesn't like this and bombs. Objects/unicodeobject.c: Added support for user settable default encodings. The current implementation uses a per-process global which defines the value of the encoding parameter in case it is set to NULL (meaning: use the default encoding). Fixed a core dump in PyUnicode_Format(). Python/bltinmodule.c: Fixed docs according to the new behaviour (the Unicode encoding is no longer fixed to UTF-8). Python/codecs.c: Moved some docs to the include file. Added a NULL check to _PyCodec_Lookup() to make it core dump safe. Python/sysmodule.c: Added APIs to allow setting and querying the system's current string encoding: sys.set_string_encoding() and sys.get_string_encoding(). Lib/test/test_unicode.py: Added another test for string formatting (the one that produced the core dump now fixed in unicodeobject.c). Misc/unicode.txt: Added a useful link to Markus Kuhn's Unicode and UTF-8 FAQ. _____________________________________________________________________ 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/ --------------80712B74A5371BBFE8498331 Content-Type: text/plain; charset=iso-8859-1; name="Unicode-Implementation-2000-05-09.patch" Content-Transfer-Encoding: 8bit Content-Disposition: inline; filename="Unicode-Implementation-2000-05-09.patch" diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Include/codecs.h Python+Unicode/Include/codecs.h --- CVS-Python/Include/codecs.h Fri Mar 10 23:32:23 2000 +++ Python+Unicode/Include/codecs.h Tue May 9 19:38:52 2000 @@ -15,37 +15,105 @@ ------------------------------------------------------------------------ */ +/* Register a new codec search function. + + As side effect, this tries to load the encodings package, if not + yet done, to make sure that it is always first in the list of + search functions. + + The search_function's refcount is incremented by this function. */ + extern DL_IMPORT(int) PyCodec_Register( PyObject *search_function ); +/* Codec register lookup API. + + Looks up the given encoding and returns a tuple (encoder, decoder, + stream reader, stream writer) of functions which implement the + different aspects of processing the encoding. + + The encoding string is looked up converted to all lower-case + characters. This makes encodings looked up through this mechanism + effectively case-insensitive. + + If no codec is found, a KeyError is set and NULL returned. + + As side effect, this tries to load the encodings package, if not + yet done. This is part of the lazy load strategy for the encodings + package. + + */ + extern DL_IMPORT(PyObject *) _PyCodec_Lookup( const char *encoding ); +/* Generic codec based encoding API. + + object is passed through the encoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +extern DL_IMPORT(PyObject *) PyCodec_Encode( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* Generic codec based decoding API. + + object is passed through the decoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +extern DL_IMPORT(PyObject *) PyCodec_Decode( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* --- Codec Lookup APIs -------------------------------------------------- + + All APIs return a codec object with incremented refcount and are + based on _PyCodec_Lookup(). The same comments w/r to the encoding + name also apply to these APIs. + +*/ + +/* Get an encoder function for the given encoding. */ + extern DL_IMPORT(PyObject *) PyCodec_Encoder( const char *encoding ); +/* Get a decoder function for the given encoding. */ + extern DL_IMPORT(PyObject *) PyCodec_Decoder( const char *encoding ); +/* Get a StreamReader factory function for the given encoding. */ + extern DL_IMPORT(PyObject *) PyCodec_StreamReader( const char *encoding, PyObject *stream, const char *errors ); -extern DL_IMPORT(PyObject *) PyCodec_Encode( - PyObject *object, - const char *encoding, - const char *errors - ); +/* Get a StreamWriter factory function for the given encoding. */ -extern DL_IMPORT(PyObject *) PyCodec_Decode( - PyObject *object, +extern DL_IMPORT(PyObject *) PyCodec_StreamWriter( const char *encoding, + PyObject *stream, const char *errors ); diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Include/unicodeobject.h Python+Unicode/Include/unicodeobject.h --- CVS-Python/Include/unicodeobject.h Thu Apr 13 11:11:33 2000 +++ Python+Unicode/Include/unicodeobject.h Tue May 9 19:46:29 2000 @@ -265,8 +265,8 @@ refcount. 2. String and other char buffer compatible objects are decoded - under the assumptions that they contain UTF-8 data. Decoding - is done in "strict" mode. + under the assumptions that they contain data using the current + default encoding. Decoding is done in "strict" mode. 3. All other objects raise an exception. @@ -313,8 +313,7 @@ parameters encoding and errors have the same semantics as the ones of the builtin unicode() API. - Setting encoding to NULL causes the default encoding to be used - which is UTF-8. + Setting encoding to NULL causes the default encoding to be used. Error handling is set by errors which may also be set to NULL meaning to use the default handling defined for the codec. Default @@ -325,6 +324,29 @@ generic ones are documented. */ + +/* --- Manage the default encoding ---------------------------------------- */ + +/* Returns the currently active default encoding. + + The default encoding is currently implemented as run-time settable + process global. This may change in future versions of the + interpreter to become a parameter which is managed on a per-thread + basis. + + */ + +extern DL_IMPORT(const char*) PyUnicode_GetDefaultEncoding(); + +/* Sets the currently active default encoding. + + Returns 0 on success, -1 in case of an error. + + */ + +extern DL_IMPORT(int) PyUnicode_SetDefaultEncoding( + const char *encoding /* Encoding name in standard form */ + ); /* --- Generic Codecs ----------------------------------------------------- */ diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Modules/timemodule.c Python+Unicode/Modules/timemodule.c --- CVS-Python/Modules/timemodule.c Thu Apr 27 21:29:40 2000 +++ Python+Unicode/Modules/timemodule.c Tue May 9 17:42:03 2000 @@ -421,7 +421,10 @@ #endif /* HAVE_STRFTIME */ #ifdef HAVE_STRPTIME -/* extern char *strptime(); /* Enable this if it's not declared in */ + +#if 0 +extern char *strptime(); /* Enable this if it's not declared in */ +#endif static PyObject * time_strptime(self, args) diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -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 16:14:50 2000 +++ Python+Unicode/Objects/unicodeobject.c Tue May 9 20:25:42 2000 @@ -117,6 +117,16 @@ static PyUnicodeObject *unicode_freelist = NULL; static int unicode_freelist_size = 0; +/* Default encoding to use and assume when NULL is passed as encoding + parameter; it is initialized by _PyUnicode_Init(). + + Always use the PyUnicode_SetDefaultEncoding() and + PyUnicode_GetDefaultEncoding() APIs to access this global. + +*/ + +static char unicode_default_encoding[100]; + /* --- Unicode Object ----------------------------------------------------- */ static @@ -366,7 +376,7 @@ Py_INCREF(unicode_empty); return (PyObject *)unicode_empty; } - return PyUnicode_DecodeUTF8(s, len, "strict"); + return PyUnicode_Decode(s, len, NULL, "strict"); } PyObject *PyUnicode_Decode(const char *s, @@ -376,10 +386,16 @@ { PyObject *buffer = NULL, *unicode; - /* Shortcut for the default encoding UTF-8 */ - if (encoding == NULL || - (strcmp(encoding, "utf-8") == 0)) + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Shortcuts for common default encodings */ + if (strcmp(encoding, "utf-8") == 0) return PyUnicode_DecodeUTF8(s, size, errors); + else if (strcmp(encoding, "latin-1") == 0) + return PyUnicode_DecodeLatin1(s, size, errors); + else if (strcmp(encoding, "ascii") == 0) + return PyUnicode_DecodeASCII(s, size, errors); /* Decode via the codec registry */ buffer = PyBuffer_FromMemory((void *)s, size); @@ -428,11 +444,19 @@ PyErr_BadArgument(); goto onError; } - /* Shortcut for the default encoding UTF-8 */ - if ((encoding == NULL || - (strcmp(encoding, "utf-8") == 0)) && - errors == NULL) + + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Shortcuts for common default encodings */ + if (errors == NULL) { + if (strcmp(encoding, "utf-8") == 0) return PyUnicode_AsUTF8String(unicode); + else if (strcmp(encoding, "latin-1") == 0) + return PyUnicode_AsLatin1String(unicode); + else if (strcmp(encoding, "ascii") == 0) + return PyUnicode_AsASCIIString(unicode); + } /* Encode via the codec registry */ v = PyCodec_Encode(unicode, encoding, errors); @@ -476,6 +500,30 @@ return -1; } +const char *PyUnicode_GetDefaultEncoding() +{ + return unicode_default_encoding; +} + +int PyUnicode_SetDefaultEncoding(const char *encoding) +{ + PyObject *v; + + /* Make sure the encoding is valid. As side effect, this also + loads the encoding into the codec registry cache. */ + v = _PyCodec_Lookup(encoding); + if (v == NULL) + goto onError; + Py_DECREF(v); + strncpy(unicode_default_encoding, + encoding, + sizeof(unicode_default_encoding)); + return 0; + + onError: + return -1; +} + /* --- UTF-8 Codec -------------------------------------------------------- */ static @@ -772,7 +820,8 @@ } else { PyErr_Format(PyExc_ValueError, - "UTF-16 decoding error; unknown error handling code: %.400s", + "UTF-16 decoding error; " + "unknown error handling code: %.400s", errors); return -1; } @@ -3057,10 +3106,10 @@ static char encode__doc__[] = "S.encode([encoding[,errors]]) -> string\n\ \n\ -Return an encoded string version of S. Default encoding is 'UTF-8'.\n\ -errors may be given to set a different error handling scheme. Default\n\ -is 'strict' meaning that encoding errors raise a ValueError. Other\n\ -possible values are 'ignore' and 'replace'."; +Return an encoded string version of S. Default encoding is the current\n\ +default string encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a ValueError. Other possible values are 'ignore' and 'replace'."; static PyObject * unicode_encode(PyUnicodeObject *self, PyObject *args) @@ -3816,7 +3865,7 @@ static PyObject *unicode_str(PyUnicodeObject *self) { - return PyUnicode_AsUTF8String((PyObject *)self); + return PyUnicode_AsEncodedString((PyObject *)self, NULL, NULL); } static char strip__doc__[] = @@ -4246,6 +4295,8 @@ return NULL; } uformat = PyUnicode_FromObject(format); + if (uformat == NULL) + return NULL; fmt = PyUnicode_AS_UNICODE(uformat); fmtcnt = PyUnicode_GET_SIZE(uformat); @@ -4322,13 +4373,10 @@ "incomplete format key"); goto onError; } - /* keys are converted to strings (using UTF-8) and + /* keys are converted to strings using UTF-8 and then looked up since Python uses strings to hold variables names etc. in its namespaces and we - wouldn't want to break common idioms. The - alternative would be using Unicode objects for the - lookup but u"abc" and "abc" have different hash - values (on purpose). */ + wouldn't want to break common idioms. */ key = PyUnicode_EncodeUTF8(keystart, keylen, NULL); @@ -4472,8 +4520,9 @@ "%s argument has non-string str()"); goto onError; } - unicode = PyUnicode_DecodeUTF8(PyString_AS_STRING(temp), + unicode = PyUnicode_Decode(PyString_AS_STRING(temp), PyString_GET_SIZE(temp), + NULL, "strict"); Py_DECREF(temp); temp = unicode; @@ -4659,7 +4708,9 @@ Py_FatalError("Unicode configuration error: " "sizeof(Py_UNICODE) != 2 bytes"); + /* Init the implementation */ unicode_empty = _PyUnicode_New(0); + strcpy(unicode_default_encoding, "utf-8"); } /* Finalize the Unicode implementation */ diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Python/bltinmodule.c Python+Unicode/Python/bltinmodule.c --- CVS-Python/Python/bltinmodule.c Mon May 8 15:13:55 2000 +++ Python+Unicode/Python/bltinmodule.c Tue May 9 20:10:30 2000 @@ -193,8 +193,8 @@ "unicode(string [, encoding[, errors]]) -> object\n\ \n\ Creates a new Unicode object from the given encoded string.\n\ -encoding defaults to 'utf-8' and errors, defining the error handling,\n\ -to 'strict'."; +encoding defaults to the current default string encoding and \n\ +errors, defining the error handling, to 'strict'."; static PyObject * diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.py -x ACKS -x *.txt -x README CVS-Python/Python/codecs.c Python+Unicode/Python/codecs.c --- CVS-Python/Python/codecs.c Wed Apr 5 22:11:21 2000 +++ Python+Unicode/Python/codecs.c Tue May 9 19:40:32 2000 @@ -55,14 +55,6 @@ return 0; } -/* Register a new codec search function. - - As side effect, this tries to load the encodings package, if not - yet done, to make sure that it is always first in the list of - search functions. - - The search_function's refcount is incremented by this function. */ - int PyCodec_Register(PyObject *search_function) { if (!import_encodings_called) { @@ -117,7 +109,7 @@ characters. This makes encodings looked up through this mechanism effectively case-insensitive. - If no codec is found, a KeyError is set and NULL returned. + If no codec is found, a LookupError is set and NULL returned. As side effect, this tries to load the encodings package, if not yet done. This is part of the lazy load strategy for the encodings @@ -130,6 +122,10 @@ PyObject *result, *args = NULL, *v; int i, len; + if (encoding == NULL) { + PyErr_BadArgument(); + goto onError; + } if (_PyCodec_SearchCache == NULL || _PyCodec_SearchPath == NULL) { PyErr_SetString(PyExc_SystemError, diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -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 Apr 25 12:34:22 2000 +++ Python+Unicode/Python/sysmodule.c Tue May 9 20:09:31 2000 @@ -143,6 +143,41 @@ exit status will be one (i.e., failure)."; static PyObject * +sys_get_string_encoding(self, args) + PyObject *self; + PyObject *args; +{ + if (!PyArg_ParseTuple(args, ":get_string_encoding")) + return NULL; + return PyString_FromString(PyUnicode_GetDefaultEncoding()); +} + +static char get_string_encoding_doc[] = +"get_string_encoding() -> string\n\ +\n\ +Return the current default string encoding used by the Unicode \n\ +implementation."; + +static PyObject * +sys_set_string_encoding(self, args) + PyObject *self; + PyObject *args; +{ + char *encoding; + if (!PyArg_ParseTuple(args, "s:set_string_encoding", &encoding)) + return NULL; + if (PyUnicode_SetDefaultEncoding(encoding)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static char set_string_encoding_doc[] = +"set_string_encoding(encoding)\n\ +\n\ +Set the current default string encoding used by the Unicode implementation."; + +static PyObject * sys_settrace(self, args) PyObject *self; PyObject *args; @@ -266,6 +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}, #ifdef COUNT_ALLOCS {"getcounts", sys_getcounts, 1}, #endif @@ -279,6 +315,7 @@ #ifdef USE_MALLOPT {"mdebug", sys_mdebug, 1}, #endif + {"set_string_encoding", sys_set_string_encoding, 1, set_string_encoding_doc}, {"setcheckinterval", sys_setcheckinterval, 1, setcheckinterval_doc}, {"setprofile", sys_setprofile, 0, setprofile_doc}, {"settrace", sys_settrace, 0, settrace_doc}, diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Lib/test/test_unicode.py Python+Unicode/Lib/test/test_unicode.py --- CVS-Python/Lib/test/test_unicode.py Mon May 1 12:39:38 2000 +++ Python+Unicode/Lib/test/test_unicode.py Tue May 9 20:25:10 2000 @@ -263,6 +263,12 @@ assert '...%(foo)s...' % {u'foo':u"abc",u'def':123} == u'...abc...' assert '...%s...%s...%s...%s...' % (1,2,3,u"abc") == u'...1...2...3...abc...' assert '...%s...' % u"abc" == u'...abc...' +try: + '...%s...äöü...' % u"abc" +except ValueError: + pass +else: + raise AssertionError, "'...%s...äöü...' % u'abc' failed to raise an exception" print 'done.' # Test builtin codecs diff -u -rP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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 PC -x PCbuild -x *.c -x *.h -x *.in -x output CVS-Python/Misc/unicode.txt Python+Unicode/Misc/unicode.txt --- CVS-Python/Misc/unicode.txt Thu Apr 13 18:10:59 2000 +++ Python+Unicode/Misc/unicode.txt Tue May 9 20:28:57 2000 @@ -976,11 +976,14 @@ http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html For comparison: - Introducing Unicode to ECMAScript -- + Introducing Unicode to ECMAScript (aka JavaScript) -- http://www-4.ibm.com/software/developer/library/internationalization-support.html IANA Character Set Names: ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets + +Discussion of UTF-8 and Unicode support for POSIX and Linux: + http://www.cl.cam.ac.uk/~mgk25/unicode.html Encodings: --------------80712B74A5371BBFE8498331-- From cgw@fnal.gov Tue May 9 20:45:34 2000 From: cgw@fnal.gov (Charles G Waldman) Date: Tue, 9 May 2000 14:45:34 -0500 (CDT) Subject: [Patches] fix for bug open/81 Message-ID: <14616.27358.400229.243540@buffalo.fnal.gov> According to the buglist (open/81): def f(a,a): return a is not caught as an error by the bytecode compiler. I thought this would be quick and easy to fix and so I added an approprate com_error call to com_newlocal_o in compile.c. However, to my surprise, this didn't work. On closer examination I realized it is because a bunch of functions (e.g. PyDict_GetItem, PyDict_SetItem, PyObject_Compare) call PyErr_Clear, clobbering the exception set by com_error. (Subsequently PyErr_Print dumps core, since tstate->curexc_type is 0). Basically, if one does any dictionary operations after an error has occurred, that error is clobbered. If one checks for errors after every operation, this is OK, but for instance in compile_node, many operations get done and the error check is only done at the end, so the intervening dictionary operations have clobbered the exception. I have fixed this in dictobject.c and object.c - replacing the PyErr_Clear with a PyErr_Fetch/PyErr_Restore pair, to avoid generating new exceptions while not clobbering any old exceptions. It seems to me that a lot of the other places where PyErr_Clear is used, it really ought to be replaced with PyErr_Fetch/PyErr_Restore in a similar fashion. Commit notice: compile.c (com_newlocal_o): check that new local variable is actually new. Trap errors like def f(a,a): return a dictobject.c (PyDict_GetItem, dict_compare): don't clobber an existing exception object.c (get_inprogress_dict): don't clobber an existing exception 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. index: Objects/dictobject.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Objects/dictobject.c,v retrieving revision 2.52 diff -c -r2.52 dictobject.c *** dictobject.c 2000/05/03 23:44:34 2.52 --- dictobject.c 2000/05/09 19:18:45 *************** *** 312,317 **** --- 312,319 ---- PyObject *key; { long hash; + PyObject *exception, *value, *traceback; + if (!PyDict_Check(op)) { return NULL; } *************** *** 322,330 **** (hash = ((PyStringObject *) key)->ob_shash) == -1) #endif { hash = PyObject_Hash(key); if (hash == -1) { - PyErr_Clear(); return NULL; } } --- 324,333 ---- (hash = ((PyStringObject *) key)->ob_shash) == -1) #endif { + PyErr_Fetch(&exception, &value, &traceback); hash = PyObject_Hash(key); + PyErr_Restore(exception, value, traceback); if (hash == -1) { return NULL; } } *************** *** 936,954 **** if (!PyString_Check(akey) || (ahash = ((PyStringObject *) akey)->ob_shash) == -1) #endif ! { ahash = PyObject_Hash(akey); ! if (ahash == -1) ! PyErr_Clear(); /* Don't want errors here */ } #ifdef CACHE_HASH if (!PyString_Check(bkey) || (bhash = ((PyStringObject *) bkey)->ob_shash) == -1) #endif { bhash = PyObject_Hash(bkey); ! if (bhash == -1) ! PyErr_Clear(); /* Don't want errors here */ } aval = lookdict(a, akey, ahash) -> me_value; bval = lookdict(b, bkey, bhash) -> me_value; --- 939,959 ---- if (!PyString_Check(akey) || (ahash = ((PyStringObject *) akey)->ob_shash) == -1) #endif ! { ! /* Don't want errors here */ ! PyErr_Fetch(&exception, &value, &traceback); ahash = PyObject_Hash(akey); ! PyErr_Restore(exception, value, traceback); } #ifdef CACHE_HASH if (!PyString_Check(bkey) || (bhash = ((PyStringObject *) bkey)->ob_shash) == -1) #endif { + /* Don't want errors here */ + PyErr_Fetch(&exception, &value, &traceback); bhash = PyObject_Hash(bkey); ! PyErr_Restore(exception, value, traceback); } aval = lookdict(a, akey, ahash) -> me_value; bval = lookdict(b, bkey, bhash) -> me_value; Index: Objects/object.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Objects/object.c,v retrieving revision 2.70 diff -c -r2.70 object.c *** object.c 2000/05/03 23:44:35 2.70 --- object.c 2000/05/09 19:18:46 *************** *** 334,348 **** get_inprogress_dict() { PyObject *tstate_dict, *inprogress; tstate_dict = PyThreadState_GetDict(); if (tstate_dict == NULL) { PyErr_BadInternalCall(); return NULL; } inprogress = PyDict_GetItem(tstate_dict, _PyCompareState_Key); if (inprogress == NULL) { - PyErr_Clear(); inprogress = PyDict_New(); if (inprogress == NULL) return NULL; --- 334,350 ---- get_inprogress_dict() { PyObject *tstate_dict, *inprogress; + PyObject *exception, *value, *traceback; tstate_dict = PyThreadState_GetDict(); if (tstate_dict == NULL) { PyErr_BadInternalCall(); return NULL; } + PyErr_Fetch(&exception, &value, &traceback); inprogress = PyDict_GetItem(tstate_dict, _PyCompareState_Key); + PyErr_Restore(exception, value, traceback); if (inprogress == NULL) { inprogress = PyDict_New(); if (inprogress == NULL) return NULL; Index: Python/compile.c =================================================================== RCS file: /projects/cvsroot/python/dist/src/Python/compile.c,v retrieving revision 2.108 diff -c -r2.108 compile.c *** compile.c 2000/05/03 23:44:38 2.108 --- compile.c 2000/05/09 19:18:48 *************** *** 2228,2233 **** --- 2228,2238 ---- } return 0; } + if (PyDict_GetItem(c->c_locals, nameval) != NULL) { + com_error(c, PyExc_SyntaxError, + "duplicate argument name"); + return 0; + } ival = PyInt_FromLong(i = c->c_nlocals++); if (ival == NULL) c->c_errors++; From cgw@fnal.gov Tue May 9 20:52:07 2000 From: cgw@fnal.gov (Charles G Waldman) Date: Tue, 9 May 2000 14:52:07 -0500 (CDT) Subject: [Patches] buglist updates Message-ID: <14616.27751.908717.774683@buffalo.fnal.gov> Bug Open/113 was fixed by my patch http://www.python.org/pipermail/patches/2000-April/000522.html And bug Open/7 was apparently fixed quite a while ago. From guido@python.org Tue May 9 20:55:13 2000 From: guido@python.org (Guido van Rossum) Date: Tue, 09 May 2000 15:55:13 -0400 Subject: [Patches] fix for bug open/81 In-Reply-To: Your message of "Tue, 09 May 2000 14:45:34 CDT." <14616.27358.400229.243540@buffalo.fnal.gov> References: <14616.27358.400229.243540@buffalo.fnal.gov> Message-ID: <200005091955.PAA25481@eric.cnri.reston.va.us> Just wanted to note that I think that I'm not keen on doing PyErr_Fetch() and PyErr_Restore() -- it's slower etc. Lots of things can cause an indirect call to PyErr_Clear() -- the assumption simply shouldn't be made that one can call anything while an exception is being passed down. The one exception is DECREF: this will never affect the exception status (and will use Fetch/Restore when needed to guarantee this). --Guido van Rossum (home page: http://www.python.org/~guido/) From fdrake@acm.org Tue May 9 20:58:47 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Tue, 9 May 2000 15:58:47 -0400 (EDT) Subject: [Patches] Unicode Patch Set 2000-05-09 In-Reply-To: <39186014.2E156C14@lemburg.com> References: <39186014.2E156C14@lemburg.com> Message-ID: <14616.28151.859980.273437@seahag.cnri.reston.va.us> M.-A. Lemburg writes: > This patch fixes a few bugglets and adds an experimental > feature which allows setting the string encoding assumed > by the Unicode implementation at run-time. Ok, I think I got it all! -Fred -- Fred L. Drake, Jr. Corporation for National Research Initiatives From cgw@fnal.gov Tue May 9 21:06:19 2000 From: cgw@fnal.gov (Charles G Waldman) Date: Tue, 9 May 2000 15:06:19 -0500 (CDT) Subject: [Patches] fix for bug open/81 In-Reply-To: <200005091955.PAA25481@eric.cnri.reston.va.us> References: <14616.27358.400229.243540@buffalo.fnal.gov> <200005091955.PAA25481@eric.cnri.reston.va.us> Message-ID: <14616.28603.915231.608@buffalo.fnal.gov> Guido van Rossum writes: > Just wanted to note that I think that I'm not keen on doing > PyErr_Fetch() and PyErr_Restore() -- it's slower etc. Lots of things > can cause an indirect call to PyErr_Clear() -- the assumption simply > shouldn't be made that one can call anything while an exception is > being passed down. OK, then how can we fix com_error? Since a lot of the com_* functions use PyDict_SetItem, I'm not seeing a good way to get the exception which is set in com_error to be preserved. The only other solution I can think of would require a lot of work modifying compile.c to check for errors as we go, rather than the way it is now, where you just check once after compiling. From trentm@activestate.com Tue May 9 22:22:19 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 9 May 2000 14:22:19 -0700 Subject: [Patches] make 'b' formatter an *unsigned* char Message-ID: <20000509142219.A23212@activestate.com> Discussion: Limit the 'b' formatter of PyArg_ParseTuple to valid values of an unsigned char, i.e. [0,UCHAR_MAX]. It is expected that this is the common usage of 'b'. An OverflowError is raised if the parsed value is outside this range. 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/Python/getargs.c ./Python/getargs.c *** /home/trentm/main/contrib/python/dist/src/Python/getargs.c Mon May 8 11:49:05 2000 --- ./Python/getargs.c Tue May 9 14:15:53 2000 *************** *** 465,492 **** switch (c) { ! case 'b': /* byte -- very short int */ { char *p = va_arg(*p_va, char *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; ! else if (ival < CHAR_MIN) { PyErr_SetString(PyExc_OverflowError, ! "byte integer is less than minimum"); return "integer"; } ! else if (ival > CHAR_MAX && ival >= 256) { PyErr_SetString(PyExc_OverflowError, ! "byte integer is greater than maximum"); return "integer"; } else ! *p = (char) ival; break; } ! case 'h': /* short int */ { short *p = va_arg(*p_va, short *); long ival = PyInt_AsLong(arg); --- 465,492 ---- switch (c) { ! case 'b': /* unsigned byte -- very short int */ { char *p = va_arg(*p_va, char *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) 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 ! *p = (unsigned char) ival; break; } ! case 'h': /* signed short int */ { short *p = va_arg(*p_va, short *); long ival = PyInt_AsLong(arg); *************** *** 494,505 **** return "integer"; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "short integer is less than minimum"); return "integer"; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "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 *************** *** 507,513 **** break; } ! case 'i': /* int */ { int *p = va_arg(*p_va, int *); long ival = PyInt_AsLong(arg); --- 507,513 ---- break; } ! case 'i': /* signed int */ { int *p = va_arg(*p_va, int *); long ival = PyInt_AsLong(arg); *************** *** 515,526 **** return "integer"; else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, ! "integer is less than minimum"); return "integer"; } else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, ! "integer is greater than maximum"); return "integer"; } else --- 515,526 ---- 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 From fdrake@acm.org Tue May 9 22:50:39 2000 From: fdrake@acm.org (Fred L. Drake, Jr.) Date: Tue, 9 May 2000 17:50:39 -0400 (EDT) Subject: [Patches] make 'b' formatter an *unsigned* char In-Reply-To: <20000509142219.A23212@activestate.com> References: <20000509142219.A23212@activestate.com> Message-ID: <14616.34863.105478.298933@seahag.cnri.reston.va.us> Trent Mick writes: > Limit the 'b' formatter of PyArg_ParseTuple to valid values of an unsigned > char, i.e. [0,UCHAR_MAX]. It is expected that this is the common usage of 'b'. > An OverflowError is raised if the parsed value is outside this range. Trent, Thanks, I've applied this patch. -Fred -- Fred L. Drake, Jr. Corporation for National Research Initiatives From trentm@activestate.com Wed May 10 00:25:04 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 9 May 2000 16:25:04 -0700 Subject: [Patches] fix float_hash and complex_hash for 64-bit *nix Message-ID: <20000509162504.A31192@activestate.com> Discussion: Okay, it is debatable to call float_hash and complex_hash broken, but their code presumed that sizeof(long) was 32-bits. As a result the hashed values for floats and complex values were not the same on a 64-bit *nix system as on a 32-bit *nix system. With this patch they are. 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/Objects/floatobject.c ./Objects/floatobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Fri May 5 10:53:34 2000 --- ./Objects/floatobject.c Tue May 9 14:52:46 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 *************** *** 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,405 **** 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) --- 399,411 ---- else { /* Note -- if you change this code, also change the copy in complexobject.c */ ! int hipart; /* algorithm expects this to be 32-bits */ fractpart = frexp(fractpart, &expo); fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (int)fractpart; /* Take the top 32 bits */ fractpart = (fractpart - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ ! x = hipart + (int)fractpart + (int)intpart + (expo << 15); /* Combine everything */ } if (x == -1) *************** *** 805,812 **** char buf[100]; PyFloat_AsString(buf, p); fprintf(stderr, ! "# \n", ! (long)p, p->ob_refcnt, buf); } } list = list->next; --- 811,818 ---- 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/complexobject.c ./Objects/complexobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c Fri May 5 10:53:34 2000 --- ./Objects/complexobject.c Tue May 9 16:01:28 2000 *************** *** 286,292 **** { 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 */ --- 286,292 ---- { 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 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) --- 302,308 ---- #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,325 **** 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 */ --- 314,326 ---- x = (long)intpart; } else { + int hipart; /* algorithm expects this to be 32-bits */ fractpart = frexp(fractpart, &expo); fractpart = fractpart * 2147483648.0; /* 2**31 */ ! hipart = (int)fractpart; /* Take the top 32 bits */ fractpart = (fractpart - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ ! x = hipart + (int)fractpart + (int)intpart + (expo << 15); /* Combine everything */ if (v->cval.imag != 0.0) { /* Hash the imaginary part */ *************** *** 336,348 **** 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 */ } } --- 337,349 ---- fractpart = modf(v->cval.imag, &intpart); #endif fractpart = frexp(fractpart, &expo); ! fractpart = fractpart * 2147483648.0; ! hipart = (int)fractpart; fractpart = (fractpart - (double)hipart) * 2147483648.0; /* Get the next 32 bits */ ! x ^= hipart + (int)fractpart + ! (int)intpart + (expo << 15); /* Combine everything */ } } -- Trent Mick trentm@activestate.com From trentm@activestate.com Wed May 10 01:43:57 2000 From: trentm@activestate.com (Trent Mick) Date: Tue, 9 May 2000 17:43:57 -0700 Subject: [Patches] use "win32" for sys.platform on Win64 Message-ID: <20000509174357.A19010@activestate.com> Discussion: Use "win32" for sys.platform on Win64 instead of "win32" because: 1. While it may be confusing to the Python scriptor on Win64 that he has to check for win*32*, that is something that he will learn the first time. It is better than the alternative of the scriptor happily using "win64" and then that code not running on Win32 for no good reason. 2. The main question is: is Win64 so much more like Win32 than different from it that the common-case general Python programmer should not ever have to make the differentiation in his Python code. Or, at least, enough so that such differentiation by the Python scriptor is rare enough that some other provided mechanism is sufficient (even preferable). Currently the answer is yes. Hopefully MS will not change this answer. 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/PC/config.h ./PC/config.h *** /home/trentm/main/contrib/python/dist/src/PC/config.h Mon May 8 07:14:48 2000 --- ./PC/config.h Tue May 9 17:40:54 2000 *************** *** 234,240 **** /* End of compilers - finish up */ #if defined(MS_WIN64) ! #define PLATFORM "win64" #define SIZEOF_VOID_P 8 #elif defined(MS_WIN32) #define PLATFORM "win32" --- 234,243 ---- /* 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" -- Trent Mick trentm@activestate.com From tim_one@email.msn.com Wed May 10 05:53:16 2000 From: tim_one@email.msn.com (Tim Peters) Date: Wed, 10 May 2000 00:53:16 -0400 Subject: [Patches] fix float_hash and complex_hash for 64-bit *nix In-Reply-To: <20000509162504.A31192@activestate.com> Message-ID: <000201bfba3b$a74ad7c0$022d153f@tim> [Trent Mick] > Discussion: > > Okay, it is debatable to call float_hash and complex_hash broken, > but their code presumed that sizeof(long) was 32-bits. As a result > the hashed values for floats and complex values were not the same > on a 64-bit *nix system as on a 32-bit *nix system. With this > patch they are. The goal is laudable but the analysis seems flawed. For example, this new comment: > ! int hipart; /* algorithm expects this to be 32-bits */ isn't true. The algorithm assumes that hipart is *at least* 32 bits, as nothing larger than that can possibly get assigned to it (that's why it's careful to multiply by 2**31 instead of something larger -- C guarantees that frexp returns a result with abs value strictly less than 1.0, and that times 2**31 occupies at most 31 bits with 1 bit to spare for the sign). On that basis, it's safer to (as the original code did) assume that sizeof(long) >= 4 than (as the new code does) assume that sizeof(int) >= 4. Looks to me like the real problem in the original was here: x = hipart + (long)fractpart + (long)intpart + (expo << 15); ^^^^^^^^^^^^^ The difficulty is that intpart may *not* fit in 32 bits, so the cast of intpart to long is ill-defined when sizeof(long) == 4. Note this consequence under the Win32 Python: >>> base = 2.**40 + 0.5 >>> base 1099511627776.5 >>> for i in range(32, 45): x = base + 2.**i print x, hash(x) 1.10380659507e+012 1073741824 1.10810156237e+012 1073741824 1.11669149696e+012 1073741824 1.13387136614e+012 1073741824 1.16823110451e+012 1073741824 1.23695058125e+012 1073741824 1.37438953472e+012 1073741824 1.64926744166e+012 1073741824 2.19902325555e+012 1073741824 3.29853488333e+012 1073741824 5.49755813888e+012 1073741824 9.89560464998e+012 1073741824 1.86916976722e+013 1073741824 That is, the hash function truly is broken for "large" values with a fractional part, and I expect your after-patch code suffers the same problem: a hash function should never ignore any bit in its input. The solution to this is to break intpart in this branch into pieces no larger than 32 bits too -- and that should also fix your 64-bit woes "by magic". From Vladimir.Marangozov@inrialpes.fr Wed May 10 13:45:54 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 10 May 2000 14:45:54 +0200 (CEST) Subject: [Patches] Re: Final request for GC patch In-Reply-To: <20000509030004.A20169@acs.ucalgary.ca> from "Neil Schemenauer" at May 09, 2000 03:00:04 AM Message-ID: <200005101245.OAA09732@python.inrialpes.fr> Neil Schemenauer wrote: > > Object alloction has been changed from macros to functions for > some important objects (list, tuple, dict). This will make > Python go slower even with GC disabled. We will have to profile > things and find out what should be inlined. For now I wanted the > patch to be easy to understand. What is the rationale behind this change? > > The PyObject_{New, VarNew} and PyObject_Del methods seem to be > non-orthogonal regarding reference tracing. I think PyObject_Del > should call _Py_ForgetReference. > _Py_NewReference and _Py_ForgetReference are asymetric. I haven't looked into this, but perhaps it is time to see whether they can be made more symetric. I seem to recall a comment in the source that regrets they aren't. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From nascheme@enme.ucalgary.ca Wed May 10 14:24:08 2000 From: nascheme@enme.ucalgary.ca (Neil Schemenauer) Date: Wed, 10 May 2000 07:24:08 -0600 Subject: [Patches] Re: Final request for GC patch In-Reply-To: <200005101245.OAA09732@python.inrialpes.fr>; from Vladimir.Marangozov@inrialpes.fr on Wed, May 10, 2000 at 02:45:54PM +0200 References: <20000509030004.A20169@acs.ucalgary.ca> <200005101245.OAA09732@python.inrialpes.fr> Message-ID: <20000510072408.A43121@cranky.arctrix.com> On Wed, May 10, 2000 at 02:45:54PM +0200, Vladimir Marangozov wrote: > Neil Schemenauer wrote: > > Object alloction has been changed from macros to functions for > > some important objects (list, tuple, dict). This will make > > Python go slower even with GC disabled. We will have to profile > > things and find out what should be inlined. For now I wanted the > > patch to be easy to understand. > > What is the rationale behind this change? Look at _PyObject_New. In order to link GC objects together extra memory must be allocated for objects that set Py_TPFLAGS_HAVE_GCINFO. Although this check does not have to be done a run time I didn't want to clutter my patch with lots of ifdefs. Extension modules that set HAVE_GCINFO should always use the object functions for memory managment. That way they will work with both GC enabled and GC disabled Python. Neil From Vladimir.Marangozov@inrialpes.fr Wed May 10 14:38:12 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Wed, 10 May 2000 15:38:12 +0200 (CEST) Subject: [Patches] Re: Final request for GC patch In-Reply-To: <20000510072408.A43121@cranky.arctrix.com> from "Neil Schemenauer" at May 10, 2000 07:24:08 AM Message-ID: <200005101338.PAA10073@python.inrialpes.fr> Neil Schemenauer wrote: > > [me, on why Object_DEL is changed to Object_Del for lists, tuples, dicts] > > > > What is the rationale behind this change? > > Look at _PyObject_New. In order to link GC objects together > extra memory must be allocated for objects that set > Py_TPFLAGS_HAVE_GCINFO. Although this check does not have to be > done a run time I didn't want to clutter my patch with lots of > ifdefs. You'd have to reflect these changes in PyObject_NEW/DEL anyway, so ifdef'ing objimpl.h cannot be avoided when you touch at the object allocator. It's the developer's responsability to not use them for extensions, but the macros should be updated (ifdef'ed) Therefore, for all core objects, I think it is safe to leave the macros (PyObject_NEW/DEL) as is. -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From ej@ee.duke.edu Thu May 11 04:25:01 2000 From: ej@ee.duke.edu (eric jones) Date: Wed, 10 May 2000 23:25:01 -0400 Subject: [Patches] per module locking patch for import.c Message-ID: <01f301bfbaf8$80037830$d70a1918@nc.rr.com> This is a multi-part message in MIME format. ------=_NextPart_000_01F0_01BFBAD6.F6E2F560 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Hello, This is a patch to import.c that allows per module locking. It stems from an issue I have run into when trying to import and run wxPython in a second thread. The central issue has been discussed lately on the thread-sig under the title: RE: [Thread-SIG] thread behavior with join() and import I've included one of the pertinent messages at the bottom. Mark Hammond tracked the issue to the import lock. His comments follow: [begin comments] Damn. The problem is clearly the import lock. * Main script is imported - this acquires the import lock. * Main script starts new thread * New thread attempts import - blocks on the import lock. * Main thread does a join() on the new thread; still holds the import lock. * Deadlocked. Hrm. We have the situation that _any_ time code run via an import, creates threads which themselves do imports, we have a problem. [snip] The only other, much harder alternative, is to make the import lock more fine-grained - eg, effectively attach a lock to each module, so the threads are only locked out when the _same_ module is being imported by 2 threads (rather than _any_ module). [snip] [end comments] I've tried my hand at writing the patch for this so that the module lock is applied on a per module bases instead of a single lock for all imports. I looked through the import.c file, and, best I can tell, the lock is totally encapsulated within import_lock() and import_unlock(). These functions were re-written and a very slight change was made to one other function. I am new to looking at the python core and the INCREF/DECREF stuff, so I hope I got it right. I can not think of any global side-affects to what I've done, but it is possible I overlooked something. The approach is as follows: Locking: 1. A lock structure is created for each module the request a lock. A pointer to this structure is stored in a standard python dictionary. 2. When modules request a lock, this dictionary is checked for that modules entry. If it does not exist, a new structure is allocated and its pointer is added to the dictionary. Otherwise, the lock info is pulled from the dictionary. 3. The rest of locking proceeds in the same way as the current locking code, but using this per module lock info. Unlocking: 1. Read the module lock pointer from the dictionary. Failuer is fatal. 2. If lock_level is 0, do the standard stuff, and then delete the dictionary entry for this module. 3. If the dictionary is empty, delete the dictionary. These last two steps could really be saved until the shutdown of python. This would be more efficient (I'm pretty sure), but it would also necessitate altering other code. Including them here keeps the entire process encapsulated in the lock functions. The only other change is that the module name has to be passed to import_lock(char *mod_name) and import_unlock(char *mod_name). They are only called once each (in import.c The patches are against the CVS tree for 1.6 as of 8:00 pm on 5/10/00. It has been tested on NT 4.0 and RH6.1. The "make test" on RH 6.1 hangs on "test_fork1.py" **with or without** the patch. After removing this test, it passed all test tried(52 passed, 21 skipped). thanks, eric #### Disclaimer Text #### 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. #### THREAD SIG message detailing the issue. #### >> I ask a question about threadin with import. > Tim responds: Huh! Works fine for me under Win95 -- get a real OS . > D:\Python>python misc/ttest.py > and code runs correctly Hmmm. Thats odd. It actually works for me when I run it this way. The problem occurs if you run it like this: D:\Python> python PythonWin 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> import ttest worker: without done main: without import done main: with import done code blocks! I've re-written the sample to illustrate the strangeness a little better. Running the thread_test.py code at the end of the message from the command line causes the problem. >>> import thread_test worker: without done main: without import done main: with import done ! and then an endless block If I comment out the call to test() at the bottom of the module, and then run: >>> import thread_test >>> thread_test.test() worker: without done main: without import done main: with import done worker: with done worker: with done main: with import done ALL TESTS PASS So the problem only appears when the thread is executed during a module import from the command line. thanks, eric ------------- thread_test.py ----------------------------- import threading ,time class without_import(threading.Thread): def run(self): time.sleep(.5) print 'worker: without done' class with_import(threading.Thread): def run(self): import time time.sleep(.5) print 'worker: with done' def test(): ############# this works fine wo = without_import() wo.start() wo.join() print 'main: without import done' ######## without join(), thread also terminates normally w = with_import() w.start() print 'main: with import done' ##### this blocks indefinitely w = with_import() w.start() w.join() print 'main: with import done' print 'ALL TESTS PASS' test() ------=_NextPart_000_01F0_01BFBAD6.F6E2F560 Content-Type: application/octet-stream; name="import.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="import.diff" *** /home/emagserver/ej/wrk/python/dist/src/Python/import.c Wed May 10 = 22:17:38 2000=0A= --- import.c Wed May 10 22:10:34 2000=0A= ***************=0A= *** 165,214 ****=0A= =0A= #include "pythread.h"=0A= =0A= ! static PyThread_type_lock import_lock =3D 0;=0A= ! static long import_lock_thread =3D -1;=0A= ! static int import_lock_level =3D 0;=0A= =0A= static void=0A= ! lock_import()=0A= {=0A= ! long me =3D PyThread_get_thread_ident();=0A= ! if (me =3D=3D -1)=0A= return; /* Too bad */=0A= ! if (import_lock =3D=3D NULL)=0A= ! import_lock =3D PyThread_allocate_lock();=0A= ! if (import_lock_thread =3D=3D me) {=0A= ! import_lock_level++;=0A= ! return;=0A= }=0A= ! if (import_lock_thread !=3D -1 || !PyThread_acquire_lock(import_lock, = 0)) {=0A= PyThreadState *tstate =3D PyEval_SaveThread();=0A= ! PyThread_acquire_lock(import_lock, 1);=0A= PyEval_RestoreThread(tstate);=0A= }=0A= ! import_lock_thread =3D me;=0A= ! import_lock_level =3D 1;=0A= }=0A= =0A= static void=0A= ! unlock_import()=0A= {=0A= ! long me =3D PyThread_get_thread_ident();=0A= ! if (me =3D=3D -1)=0A= return; /* Too bad */=0A= ! if (import_lock_thread !=3D me)=0A= Py_FatalError("unlock_import: not holding the import lock");=0A= ! import_lock_level--;=0A= ! if (import_lock_level =3D=3D 0) {=0A= ! import_lock_thread =3D -1;=0A= ! PyThread_release_lock(import_lock);=0A= }=0A= }=0A= =0A= #else=0A= =0A= ! #define lock_import()=0A= ! #define unlock_import()=0A= =0A= #endif=0A= =0A= --- 165,254 ----=0A= =0A= #include "pythread.h"=0A= =0A= ! static PyObject *import_locks =3D NULL;=0A= ! typedef struct {=0A= ! PyThread_type_lock lock;=0A= ! long thread;=0A= ! int level;=0A= ! } mod_lock;=0A= =0A= static void=0A= ! lock_import(char* mod_name)=0A= {=0A= ! PyObject* py_lock =3D NULL;=0A= ! mod_lock *lock =3D NULL; =0A= ! long current_thread =3D PyThread_get_thread_ident();=0A= ! =0A= ! if (current_thread =3D=3D -1)=0A= return; /* Too bad */=0A= ! =0A= ! if (import_locks =3D=3D NULL) {=0A= ! import_locks =3D PyDict_New();=0A= ! if( !import_locks)=0A= ! Py_FatalError("lock_import: failed to create lock list");=0A= ! }=0A= ! py_lock =3D PyDict_GetItemString(import_locks,mod_name); =0A= ! if (!py_lock) { /* First import of this module */=0A= ! lock =3D malloc(sizeof(mod_lock));=0A= ! lock->lock =3D PyThread_allocate_lock();=0A= ! lock->thread =3D -1;=0A= ! lock->level =3D 0;=0A= ! py_lock =3D PyInt_FromLong((long)lock);=0A= ! if(!py_lock)=0A= ! Py_FatalError("lock_import: failed to create lock");=0A= ! PyDict_SetItemString(import_locks,mod_name,py_lock); =0A= ! }=0A= ! else /* Module already has been locked before */=0A= ! lock =3D (mod_lock*)PyInt_AsLong(py_lock);=0A= ! if( lock->thread =3D=3D current_thread ) {=0A= ! lock->level++;=0A= ! return; /* ??what do we need to do to clean up REFs */=0A= }=0A= ! if (lock->thread !=3D 1 || !PyThread_acquire_lock(lock->lock,0)) {=0A= PyThreadState *tstate =3D PyEval_SaveThread();=0A= ! PyThread_acquire_lock(lock->lock, 1);=0A= PyEval_RestoreThread(tstate);=0A= }=0A= ! lock->thread =3D current_thread;=0A= ! lock->level =3D 1;=0A= }=0A= =0A= static void=0A= ! unlock_import(char* mod_name)=0A= {=0A= ! PyObject* py_lock =3D NULL;=0A= ! mod_lock *lock =3D NULL; =0A= ! long current_thread =3D PyThread_get_thread_ident();=0A= ! =0A= ! if (current_thread =3D=3D -1)=0A= return; /* Too bad */=0A= ! if (!import_locks)=0A= ! Py_FatalError("unlock_import: no import lock list");=0A= ! =0A= ! py_lock =3D PyDict_GetItemString(import_locks,mod_name); =0A= ! if (!py_lock)=0A= ! Py_FatalError("unlock_import: module was never locked");=0A= ! =0A= ! lock =3D (mod_lock*)PyInt_AsLong(py_lock); =0A= ! if (lock->thread !=3D current_thread)=0A= Py_FatalError("unlock_import: not holding the import lock");=0A= ! lock->level--;=0A= ! if (lock->level =3D=3D 0) {=0A= ! lock->thread =3D -1; /* not necessary */=0A= ! PyThread_release_lock(lock->lock);=0A= ! PyDict_DelItemString(import_locks,mod_name);=0A= ! free(lock);=0A= ! if(!PyDict_Size(import_locks)) {=0A= ! Py_DECREF(import_locks);=0A= ! import_locks =3D NULL;=0A= ! }=0A= }=0A= }=0A= =0A= #else=0A= =0A= ! #define lock_import(char* mod_name)=0A= ! #define unlock_import(char* mod_name)=0A= =0A= #endif=0A= =0A= ***************=0A= *** 1527,1535 ****=0A= PyObject *fromlist;=0A= {=0A= PyObject *result;=0A= ! lock_import();=0A= result =3D import_module_ex(name, globals, locals, fromlist);=0A= ! unlock_import();=0A= return result;=0A= }=0A= =0A= --- 1567,1575 ----=0A= PyObject *fromlist;=0A= {=0A= PyObject *result;=0A= ! lock_import(name);=0A= result =3D import_module_ex(name, globals, locals, fromlist);=0A= ! unlock_import(name);=0A= return result;=0A= }=0A= =0A= ------=_NextPart_000_01F0_01BFBAD6.F6E2F560-- From billtut@microsoft.com Thu May 11 08:36:13 2000 From: billtut@microsoft.com (Bill Tutt) Date: Thu, 11 May 2000 00:36:13 -0700 Subject: [Patches] re: Yakov's patch to thread_nt.h Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD091@RED-MSG-50> Calling Sleep(0) for a spinlock can cause a priority inversion. Here's a patch to fix that, with comments explaining whats going on. The only other possible tweak that came to mind was adding a spinlock with a max count of 500 or so before actually hitting the WaitForSingleObject() call in EnterNonRecursiveMutex(). Ring transitions into kernel mode are exspensive, so try and avoid them when possible. :) Index: thread_nt.h =================================================================== RCS file: /projects/cvsroot/python/dist/src/Python/thread_nt.h,v retrieving revision 2.8 diff -u -r2.8 thread_nt.h --- thread_nt.h 2000/05/05 14:29:59 2.8 +++ thread_nt.h 2000/05/11 07:24:28 @@ -50,9 +50,32 @@ { static LONG spinlock = 0 ; PVOID result ; + DWORD dwSleep = 0; /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */ - while(InterlockedExchange(&spinlock, 1)) Sleep(0) ; + while(InterlockedExchange(&spinlock, 1)) + { + // Using Sleep(0) can cause a priority inversion. + // Sleep(0) only yields the processor if there's + // another thread of the same priority that's + // ready to run. If a high-priority thread is + // trying to acquire the lock, which is held by + // a low-priority thread, then the low-priority + // thread may never get scheduled and hence never + // free the lock. NT attempts to avoid priority + // inversions by temporarily boosting the priority + // of low-priority runnable threads, but the problem + // can still occur if there's a medium-priority + // thread that's always runnable. If Sleep(1) is used, + // then the thread unconditionally yields the CPU. We + // only do this for the second and subsequent even + // iterations, since a millisecond is a long time to wait + // if the thread can be scheduled in again sooner + // (~100,000 instructions). + // Avoid priority inversion: 0, 1, 0, 1,... + Sleep(dwSleep); + dwSleep = !dwSleep; + } result = *dest ; if (result == comperand) *dest = exc ; 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. Bill From peter@schneider-kamp.de Thu May 11 17:44:47 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Thu, 11 May 2000 18:44:47 +0200 Subject: [Patches] introducing math.rint Message-ID: <391AE37F.60A995CC@stud.ntnu.no> This is a multi-part message in MIME format. --------------3E43382254608E73673E4C24 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Problem: "4.26. math.rint is missing" from to-do list: Although the math modules provides a wrapper around ceil(3) and floor(3), there is no wrapper around rint(3). This is necessary for IEEE-conforming rounding. Edit this entry / Log info / Last changed on Tue Oct 26 12:49:36 1999 by Martin v. Loewis Solution: introduced math.rint to Modules/mathmodule.c updated documentation / updated Include/mymath.h / updated tests 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 --------------3E43382254608E73673E4C24 Content-Type: text/plain; charset=us-ascii; name="math.rint.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="math.rint.patch" diff -c --recursive python/dist/src/Doc/lib/libmath.tex python-mod/dist/src/Doc/lib/libmath.tex *** python/dist/src/Doc/lib/libmath.tex Mon Apr 3 22:13:53 2000 --- python-mod/dist/src/Doc/lib/libmath.tex Thu May 11 18:04:14 2000 *************** *** 93,98 **** --- 93,102 ---- Return \code{\var{x}**\var{y}}. \end{funcdesc} + \begin{funcdesc}{rint}{x, y} + Return the integer nearest to \var{x} as a real. + \end{funcdesc} + \begin{funcdesc}{sin}{x} Return the sine of \var{x}. \end{funcdesc} diff -c --recursive python/dist/src/Include/mymath.h python-mod/dist/src/Include/mymath.h *** python/dist/src/Include/mymath.h Mon Nov 2 17:21:39 1998 --- python-mod/dist/src/Include/mymath.h Thu May 11 18:02:46 2000 *************** *** 48,53 **** --- 48,54 ---- #undef log #undef log10 #undef pow + #undef rint #undef sin #undef sinh #undef sqrt *************** *** 67,72 **** --- 68,74 ---- #define log logd #define log10 log10d #define pow powd + #define rint rintd #define sin sind #define sinh sinhd #define sqrt sqrtd diff -c --recursive python/dist/src/Lib/test/output/test_math python-mod/dist/src/Lib/test/output/test_math *** python/dist/src/Lib/test/output/test_math Wed Dec 11 00:19:51 1996 --- python-mod/dist/src/Lib/test/output/test_math Thu May 11 18:01:16 2000 *************** *** 19,24 **** --- 19,25 ---- log10 modf pow + rint sin sinh sqrt diff -c --recursive python/dist/src/Lib/test/test_math.py python-mod/dist/src/Lib/test/test_math.py *** python/dist/src/Lib/test/test_math.py Thu Aug 29 21:00:46 1996 --- python-mod/dist/src/Lib/test/test_math.py Thu May 11 18:01:02 2000 *************** *** 129,134 **** --- 129,140 ---- testit('pow(2,1)', math.pow(2,1), 2) 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) testit('sin(pi/2)', math.sin(math.pi/2), 1) diff -c --recursive python/dist/src/Modules/mathmodule.c python-mod/dist/src/Modules/mathmodule.c *** python/dist/src/Modules/mathmodule.c Mon May 8 16:29:38 2000 --- python-mod/dist/src/Modules/mathmodule.c Thu May 11 17:58:45 2000 *************** *** 156,161 **** --- 156,163 ---- FUNC2(math_pow, pow, math_pow_doc, "pow(x,y)\n\nReturn x**y.") #endif + FUNC1(math_rint, rint, math_rint_doc, + "rint(x)\n\nReturn the integer nearest to x as a real.") FUNC1(math_sin, sin, math_sin_doc, "sin(x)\n\nReturn the sine of x.") FUNC1(math_sinh, sinh, math_sinh_doc, *************** *** 266,272 **** {"log", math_log, 0, math_log_doc}, {"log10", math_log10, 0, math_log10_doc}, {"modf", math_modf, 0, math_modf_doc}, ! {"pow", math_pow, 0, math_pow_doc}, {"sin", math_sin, 0, math_sin_doc}, {"sinh", math_sinh, 0, math_sinh_doc}, {"sqrt", math_sqrt, 0, math_sqrt_doc}, --- 268,275 ---- {"log", math_log, 0, math_log_doc}, {"log10", math_log10, 0, math_log10_doc}, {"modf", math_modf, 0, math_modf_doc}, ! {"pow", math_pow, 0, math_pow_doc}, ! {"rint", math_rint, 0, math_rint_doc}, {"sin", math_sin, 0, math_sin_doc}, {"sinh", math_sinh, 0, math_sinh_doc}, {"sqrt", math_sqrt, 0, math_sqrt_doc}, --------------3E43382254608E73673E4C24-- From guido@python.org Thu May 11 19:29:36 2000 From: guido@python.org (Guido van Rossum) Date: Thu, 11 May 2000 14:29:36 -0400 Subject: [Patches] introducing math.rint In-Reply-To: Your message of "Thu, 11 May 2000 18:44:47 +0200." <391AE37F.60A995CC@stud.ntnu.no> References: <391AE37F.60A995CC@stud.ntnu.no> Message-ID: <200005111829.OAA02880@eric.cnri.reston.va.us> Thanks, Peter! I've checked this in, but I have one nagging doubt: it's not a standard ANSI C function, so may not exist on all platforms? --Guido van Rossum (home page: http://www.python.org/~guido/) From trentm@activestate.com Thu May 11 22:52:41 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 11 May 2000 14:52:41 -0700 Subject: [Patches] Re: bug in PyLong_FromLongLong (PR#324) In-Reply-To: <200005111323.JAA00637@eric.cnri.reston.va.us> References: <200005111323.JAA00637@eric.cnri.reston.va.us> Message-ID: <20000511145241.A15936@activestate.com> [Thomas] > 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. On Thu, May 11, 2000 at 09:23:16AM -0400, Guido van Rossum wrote: > I think he's right. I have no access to a 64-bit machine -- can you > come up with a fix and test it? Yup, Thomas is right. Actually I demonstrated the bug and the fix on linux32 and win32. You need a machine where sizeof(long) != sizeof(LONG_LONG). Please, see a related email on python-dev about being able to test for this kind of thing. Patch Discussion: Correct bounds checking in PyLong_FromLongLong. Previously, it did not check properly for negative values when looking checking to see if the given value fit in a long or unsigned long. 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/Objects/longobject.c ./Objects/longobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/longobject.c Wed May 3 16:44:35 2000 --- ./Objects/longobject.c Thu May 11 14:22:34 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 adustman@comstar.net Thu May 11 22:55:22 2000 From: adustman@comstar.net (Andy Dustman) Date: Thu, 11 May 2000 17:55:22 -0400 (EDT) Subject: [Patches] signal module patch for GNU pth support 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. ---187888452-1685517700-958082122=:8382 Content-Type: TEXT/PLAIN; charset=US-ASCII Since GNU pth runs in user-space in a single process, (getpid() == main_pid) is always true, and so signal_handler check the thread id and use pth_raise() to send the signal to the main thread if another thread was running when the signal arrived. NOTE: pth-1.3.5 currently has a bug (IMHO) in that pth_sleep() (replacement for POSIX sleep()) is not awakened by signals. The severity of the bug depends on how long you were sleeping... This has been reported. -- andy dustman | programmer/analyst | comstar.net, inc. telephone: 770.485.6025 / 706.549.7689 | icq: 32922760 | pgp: 0xc72f3f1d "Therefore, sweet knights, if you may doubt your strength or courage, come no further, for death awaits you all, with nasty, big, pointy teeth!" ---187888452-1685517700-958082122=:8382 Content-Type: TEXT/PLAIN; charset=US-ASCII; name=signalmodule-pth-patch Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename=signalmodule-pth-patch SW5kZXg6IE1vZHVsZXMvc2lnbmFsbW9kdWxlLmMNCj09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT0NClJDUyBmaWxlOiAvcHJvamVjdHMvY3Zzcm9vdC9weXRob24v ZGlzdC9zcmMvTW9kdWxlcy9zaWduYWxtb2R1bGUuYyx2DQpyZXRyaWV2aW5n IHJldmlzaW9uIDIuMzkNCmRpZmYgLWMgLXIyLjM5IHNpZ25hbG1vZHVsZS5j DQoqKiogc2lnbmFsbW9kdWxlLmMJMTk5OC8xMi8yMSAxOTozMjozOQkyLjM5 DQotLS0gc2lnbmFsbW9kdWxlLmMJMjAwMC8wNS8xMSAyMTo0Njo1Nw0KKioq KioqKioqKioqKioqDQoqKiogODksOTQgKioqKg0KLS0tIDg5LDk3IC0tLS0N CiAgICAgaGFuZGxlciBpZ25vcmVzIHNpZ25hbHMgaWYgZ2V0cGlkKCkgaXNu J3QgdGhlIHNhbWUgYXMgaW4gdGhlIG1haW4NCiAgICAgdGhyZWFkLiAgWFhY IFRoaXMgaXMgYSBoYWNrLg0KICANCisgICAgR05VIHB0aCBpcyBhIHVzZXIt c3BhY2UgdGhyZWFkaW5nIGxpYnJhcnksIGFuZCBhcyBzdWNoLCBhbGwgdGhy ZWFkcw0KKyAgICBydW4gd2l0aGluIHRoZSBzYW1lIHByb2Nlc3MuIEluIHRo aXMgY2FzZSwgaWYgdGhlIGN1cnJlbnRseSBydW5uaW5nDQorICAgIHRocmVh ZCBpcyBub3QgdGhlIG1haW5fdGhyZWFkLCBzZW5kIHRoZSBzaWduYWwgdG8g dGhlIG1haW5fdGhyZWFkLg0KICAqLw0KICANCiAgI2lmZGVmIFdJVEhfVEhS RUFEDQoqKioqKioqKioqKioqKioNCioqKiAxMzQsMTM5ICoqKioNCi0tLSAx MzcsMTQ4IC0tLS0NCiAgCWludCBzaWdfbnVtOw0KICB7DQogICNpZmRlZiBX SVRIX1RIUkVBRA0KKyAjaWZkZWYgX0dOVV9QVEgNCisgCWlmIChQeVRocmVh ZF9nZXRfdGhyZWFkX2lkZW50KCkgIT0gbWFpbl90aHJlYWQpIHsNCisgCQlw dGhfcmFpc2UoKihwdGhfdCAqKSBtYWluX3RocmVhZCwgc2lnX251bSk7DQor IAkJcmV0dXJuOw0KKyAJfQ0KKyAjZW5kaWYNCiAgCS8qIFNlZSBOT1RFUyBz ZWN0aW9uIGFib3ZlICovDQogIAlpZiAoZ2V0cGlkKCkgPT0gbWFpbl9waWQp IHsNCiAgI2VuZGlmDQo= ---187888452-1685517700-958082122=:8382-- From gstein@lyra.org Thu May 11 23:02:39 2000 From: gstein@lyra.org (Greg Stein) Date: Thu, 11 May 2000 15:02:39 -0700 (PDT) Subject: [Patches] signal module patch for GNU pth support In-Reply-To: Message-ID: Need the patch disclaimer... On Thu, 11 May 2000, Andy Dustman wrote: > Since GNU pth runs in user-space in a single process, (getpid() == > main_pid) is always true, and so signal_handler check the thread id and > use pth_raise() to send the signal to the main thread if another thread > was running when the signal arrived. > > NOTE: pth-1.3.5 currently has a bug (IMHO) in that pth_sleep() > (replacement for POSIX sleep()) is not awakened by signals. The severity > of the bug depends on how long you were sleeping... This has been > reported. -- Greg Stein, http://www.lyra.org/ From adustman@comstar.net Thu May 11 23:11:00 2000 From: adustman@comstar.net (Andy Dustman) Date: Thu, 11 May 2000 18:11:00 -0400 (EDT) Subject: [Patches] signal module patch for GNU pth support In-Reply-To: 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. ---187888452-1540299381-958083060=:8382 Content-Type: TEXT/PLAIN; charset=US-ASCII On Thu, 11 May 2000, Greg Stein wrote: > > Need the patch disclaimer... For THAT? It's bigger than the patch... -- andy dustman | programmer/analyst | comstar.net, inc. telephone: 770.485.6025 / 706.549.7689 | icq: 32922760 | pgp: 0xc72f3f1d "Therefore, sweet knights, if you may doubt your strength or courage, come no further, for death awaits you all, with nasty, big, pointy teeth!" 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. All hail Guido! ---187888452-1540299381-958083060=:8382 Content-Type: TEXT/PLAIN; charset=US-ASCII; name=signalmodule-pth-patch Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename=signalmodule-pth-patch SW5kZXg6IE1vZHVsZXMvc2lnbmFsbW9kdWxlLmMNCj09PT09PT09PT09PT09 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 PT09PT09PT0NClJDUyBmaWxlOiAvcHJvamVjdHMvY3Zzcm9vdC9weXRob24v ZGlzdC9zcmMvTW9kdWxlcy9zaWduYWxtb2R1bGUuYyx2DQpyZXRyaWV2aW5n IHJldmlzaW9uIDIuMzkNCmRpZmYgLWMgLXIyLjM5IHNpZ25hbG1vZHVsZS5j DQoqKiogc2lnbmFsbW9kdWxlLmMJMTk5OC8xMi8yMSAxOTozMjozOQkyLjM5 DQotLS0gc2lnbmFsbW9kdWxlLmMJMjAwMC8wNS8xMSAyMTo0Njo1Nw0KKioq KioqKioqKioqKioqDQoqKiogODksOTQgKioqKg0KLS0tIDg5LDk3IC0tLS0N CiAgICAgaGFuZGxlciBpZ25vcmVzIHNpZ25hbHMgaWYgZ2V0cGlkKCkgaXNu J3QgdGhlIHNhbWUgYXMgaW4gdGhlIG1haW4NCiAgICAgdGhyZWFkLiAgWFhY IFRoaXMgaXMgYSBoYWNrLg0KICANCisgICAgR05VIHB0aCBpcyBhIHVzZXIt c3BhY2UgdGhyZWFkaW5nIGxpYnJhcnksIGFuZCBhcyBzdWNoLCBhbGwgdGhy ZWFkcw0KKyAgICBydW4gd2l0aGluIHRoZSBzYW1lIHByb2Nlc3MuIEluIHRo aXMgY2FzZSwgaWYgdGhlIGN1cnJlbnRseSBydW5uaW5nDQorICAgIHRocmVh ZCBpcyBub3QgdGhlIG1haW5fdGhyZWFkLCBzZW5kIHRoZSBzaWduYWwgdG8g dGhlIG1haW5fdGhyZWFkLg0KICAqLw0KICANCiAgI2lmZGVmIFdJVEhfVEhS RUFEDQoqKioqKioqKioqKioqKioNCioqKiAxMzQsMTM5ICoqKioNCi0tLSAx MzcsMTQ4IC0tLS0NCiAgCWludCBzaWdfbnVtOw0KICB7DQogICNpZmRlZiBX SVRIX1RIUkVBRA0KKyAjaWZkZWYgX0dOVV9QVEgNCisgCWlmIChQeVRocmVh ZF9nZXRfdGhyZWFkX2lkZW50KCkgIT0gbWFpbl90aHJlYWQpIHsNCisgCQlw dGhfcmFpc2UoKihwdGhfdCAqKSBtYWluX3RocmVhZCwgc2lnX251bSk7DQor IAkJcmV0dXJuOw0KKyAJfQ0KKyAjZW5kaWYNCiAgCS8qIFNlZSBOT1RFUyBz ZWN0aW9uIGFib3ZlICovDQogIAlpZiAoZ2V0cGlkKCkgPT0gbWFpbl9waWQp IHsNCiAgI2VuZGlmDQo= ---187888452-1540299381-958083060=:8382-- From gstein@lyra.org Thu May 11 23:12:20 2000 From: gstein@lyra.org (Greg Stein) Date: Thu, 11 May 2000 15:12:20 -0700 (PDT) Subject: [Patches] signal module patch for GNU pth support In-Reply-To: Message-ID: On Thu, 11 May 2000, Andy Dustman wrote: > On Thu, 11 May 2000, Greg Stein wrote: > > > > Need the patch disclaimer... > > For THAT? It's bigger than the patch... hehe... I don't make the rules. And I don't necessarily agree with the rules. But they *are* the rules :-) And if you keep complaining, then we'll make you physically sign a paper and fax it to CNRI instead... the dreaded "wet sign" document! Muahahahaa! :-) Of course, if everybody would simply play nice, then none of this would be important. sigh. -g -- Greg Stein, http://www.lyra.org/ From billtut@microsoft.com Fri May 12 00:11:21 2000 From: billtut@microsoft.com (Bill Tutt) Date: Thu, 11 May 2000 16:11:21 -0700 Subject: [Patches] Unicode Character Name codec support Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD095@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_01BFBB9E.38874800 Content-Type: text/plain; charset="windows-1252" This is all based on AMK's perfect_hash work and MAL's unicode-escape decoding, so hopefully a wet signature isn't necessary. This unicode-named codec also handles normal unicode-escapes since codecs are not easily and usefully stackable, and not stacking them is more effecient in any event. An altertnative to this approach would be to stick the data in one .c file, and move PyUnicode_DecodeNamedUnicodeEscape into the unicode-escape code. Just as an informational matter, the hash table is 1.79 times bigger than the # of unicode characters that have names. Attached in the zip file are the requisite changes: Files: patch.txt: Contains changes to the existing files in CVS for the following things: Adds _ucn.c into the build gunk Trivial patch to pcbuild.dsw not included on purpose since my Visual Studio was making more changes than made me comfortable. New files: _ucn.c: Already generated file, should just drop into Modules\ _ucn.dsp: MSVC project file, drop into PCBuild, and insert into pcbuild.dsw, and create a dependancy on python16. test_ucn.py: Drop in Lib\test unicode_named.py: Codec file, should be dropped into Lib\encodings The following files are provided for informational purposes and as a mechanism to explain how this was generated: Suggestions of how or if this should be included in Python's build process are greatly appreciated. perfect_hash.py: A tweaked copy of AMK's perfect_hash.py that sucks in UnicodeData.txt and generates _ucn.c. perfhash.c: A helper module for perfect_hash.py. This just lets the generated C code be more effecient than AMK's original code. UnicodeData.txt: Input file for perfect_hash.py Usage of perfect_hash.py: perfect_hash.py UnicodeData.txt > _ucn.c Bill 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. <> ------_=_NextPart_000_01BFBB9E.38874800 Content-Type: application/octet-stream; name="ucn.zip" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="ucn.zip" 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 K6LXPVNSq/gzlFsROkAmCBlqr2mCP6M5g5Qp/oymDFKl+DOYMUiN4s9owiAlij/D+YLUKP6MpgtS oghnC1KhCCcLUqGI5gpSnwinClKdiGcKUp2IJwpSnQjnCVKciKcJUp34CTemSHUink5IcSKcTUht Ip5MSG0inEtIbSKcSkhlIppJSF0inEhIWSKcR0hVIpxGSFUimkVITSKcREhJ4ifMTElJ4idKTElJ 4ieKMaQi8RPFGFKQ+AliDClH/EQxhpQjfsIYQ8oRP1GMmSoCr6I5SHEct0VvA9m5o3SRTnc8ILJY Jxs+iwToEp1uTEcBYaoTDi/4ALpMpxuuNQK6XKcbP04BCAuDUEG6Uqc7QbmVTjY+5g4IhdHR/bgB ulqnq+sHBJSGgrjBjU7Xxw1ApnSyCxbbmg1+IEBhWOBdIEBhWOBOIDLDYJrmgTpQGBZTYzpiMbgh hWnTsKeFYTL3ByIzTAajGQYz7vcBQsNivqCrC8NgLp+QzjCY/Qn2i2Exn9DyhWExP+CA1IbBDFVM gM4wmB/Qg2sjZn0hw6qNkPUdtbbOzOGA2plmBUejLky8PicChIZVfUD9DKtqkPHVwuxkPBq1OTFA 9aQZyBGZYVTju4KA0LAqCSeQmsQhCCiJWcFAJGOTECMaFjNcWQJ0RsiaXmIDlIbRvANAudls/7D/ 5a//+p9/frv9nz//+Zf/+edf/6+39re//+Of/8JlAU0hEobh+AuiLwcB3d/++nb5+2//+5d//vr2 +Mevb/vf/vXf3m7/+fe//+1f+/+0yJP/sPnrPkn18k/iWfY+ef3D7xXdtm5eLHbs1uPf/itQUjtI IuQQXG02ZptWaLv/25I0YgFmaKseWH5/f5Pn00XcD/XheLh/vh0add5dxWX/bSR4DnIp05IwRz7m aGbO8zYlzLGPOV4kKykIc+JjTla1JVU79TGni9qqiQhz5mPOZuZUJTFhzn3M+cycDVVhJnPhYy5m 5qrt8zqTufQxlw7mysdcLWpXGe0w4WNeqm6ryOrt2sdcL5KzfnVmMksfs1zVtmy78TE3i5EMX5A1 mZWPedm7KPK8Isytj7ldmNuSGEnk8+do9ec8aQmzz5+jxZ/LoiYuGfn8OVr9uWxJb0c+f44Wf+4t lart8+do9WexIS4Z+fw5Wvw5b6KaMPv8OVr8udg0ZJwjnz9Hiz8XQ+2syezz52jx53I4bTSZff4c VatL5nScff4crf5ctcSfI58/R/UaPUs6VD5/jlZ/Hm5Hm8w+f45Wf643ZK6KfP4crf4cW0bi8+eo XV0yJkMV+/w5Xvy5UhExktjnz/Hiz1mTbQizz5/jxZ/zVpE2xz5/jtf5OZO0zT5/jhd/LqucDFXs 8+d49efhhWqT2efP8eLPZdSQGBb7/Dku1gAYkRgW+/w5Xvw5s7Kh2OfP8eLPeRGRWTL2+XMs1gBI g0Hs8+e4Xh2jJWlF7PPnWK5BX1Lb9vlzvPhz2pZkfo59/hwv/pxFNe0wnz/Hiz9nMY3bic+fk8Wf 82HpZzL7/DlZ823RJITZ589JrMUwEgwSnz8nyZrQKNJhic+fk9WfNxsyYyQ+f06yNXpuyDgnPn9O Vn/OM2Keic+fk9WfG0X8OfH5c7Lm2wVdJiQ+f07W+bnOqWSfPyfr/Ny0xJ8Tnz8nqz+XJe0wnz8n iz8XVUHV9vlzsvhz0Qhqnj5/ThZ/LhMa9BOfPyeLP1cJzQxSnz+n2vxM25z6/Dld823RENtOff6c Lv6clQ2V7PPndPHnrLXa7PPndPHnQuZkqFKfP6erP28KEj1Tnz+na749fKLSZPb5c7rm2yWdYlOf P6eltuFAJfv8OV39OW9J9Ex9/pwKbZxJTpL6/Dld18/S6jCfP6dynW4iMt2kPn9O13y7aWhv+/w5 VWvuuaG27fPndF0/NzFhznz+nC3+XKiEDFXm8+cs0saZpMyZz5+zWEsryFBlPn/O1nx7U1LJPn/O 0jUbakjQz3z+nGUrs6TMPn/OVn8WEWX2+XO2+nNTk0iS+fw5W/05oavYzOfPmebPdCGa+fw5W/y5 HPayTWafP2e1trqhtu3z50zifZLM589Zs85VLe1tnz9nSts0JfNz5vPnbM23a5p75j5/ztd8exOR Nuc+f86jdYeG7j7mPn/O13w7K8g45z5/ztf5OaErutznz/k6P5c0DOU+f87X/e22JhaW+/w5X/e3 W0HGOff5c16sRrIhewa5z5/zxZ9zScNQ7vPnfF0/ZwWZYnOfP+dCm26ohfn8OV/n5+HlDZPZ58/5 uh9WZsQlc58/52u+XdBFWe7z53zNt4cCeJPZ58/5uh8mBMkMCp8/F6s/13SLuvD5c7Hm221NXLLw +XOx7ofJkhhJ4fPnIlnjNo2ehc+fi3X9HNNTo8Lnz8W6H5bQdVXh8+dinZ+znEr2+XOh+bOgbfb5 c7Huh0X0BKXw+XNRaTkJZfb5c7Huh5UlcYzC58/Fun6WdK4qfP5cyHWc6bK/8Plzoc3PNH0sfP5c qPVAgKYVhc+fC20/rCVGUvr8uVz8ORuuGpnMPn8u1/3twcNMZp8/l2u+rRSZMUqfP5erP2eSttnn z+V6XtXSYFD6/LnM1k2WmATA0ufP5eLPfRpKptjS58/lev4s6EZx6fPnct0PUxVxjNLnz+Wabyu6 UVz6/Llc18/DF55NZp8/l2u+nUuyQ1P6/Llc8+26oG32+XO5+nNLV+6lz5/LdX9bFWR7p/T5c9mu J98VmTEqnz9X6/wcbyizz5+rdX97KIU1mX3+XGnnVTEJBpXPn6t1fzuiCU3l8+dqzbeHkm+T2efP lebPdFeq8vlztc7PDS3AqXz+XK372xs63VQ+f67W9XMbE8eofP5cVWv6qIg/Vz5/rtb97Y01zj5/ rup1rzelve3z52rNt2O6KKt8/lw1K7Ogavv8uVr9eSiSNJl9/lyt+2EbWislfP4s1nqSku57Cp8/ iwhn+sLnz0Kbn2kSJ3z+LLT9bZqTCJ8/i3V+Ht4jN5l9/izWfLumWa/w+bNY/VkmlNnnz0KrJ6G7 UsLnz6Jck3VFIonw+bNY8+28pUPl82ch8PaO8PmzWNfPDV0OCp8/C6ntDZEMUPj8Wazr5+GlV5PZ 589irSdJ6epG+PxZaPVhdJasff5cr/68SUncrn3+XK/723FCjKT2+XMda5vjVLLPn+u1PqygpXy1 z5/rxZ/7FQNl9vlzre2H0Z312ufP9erPFQ0Gtc+f6zXfjmra2z5/rtd8O69pm33+XK/7YRtFlsC1 z59roZV40XH2+XO9+vOGnhrVPn+upRZJaG/7/Lle52dJCydrnz/X63lVVhF/rn3+XLd4W176/Fmu 51URXRpJnz/LdX87p4tv6fNnudZ7prT0R/r8WWr1ngVl9vmzXP25LUk2JH3+LNf5OafbeNLnz3Jd P+cx7W2fP8tizQDpMkH6/Fmu+9sFzUmkz5+lVh/WktxT+vxZavVhKQkG0ufPcl0/K1p2Ln3+LNd6 kuFpPpPZ589ynZ+zjDL7/Fmu83OZ0972+bPUzp9poVXj8+dmrSex9vQbnz83kbZpShyj8flzs66f Y2rbjc+fm0Q7ESVe1fj8uVnPnzcx6e3G58/Nev7cRGScG58/N/lq24pMN43Pn5tCWwJTZp8/N+v+ tpVWND5/blZ/jlKSGTQ+f260/W26im18/tzU+ES08flzs9Z75jQzaHz+3Gjr55iOs8+fG239TOtJ Gp8/N61WQ0PWVcrnz2rdD8tpDY3y+bNa98OKlLik8vmzWv25FMQllc+f1bq/LemRk/L5s9L2w2jJ pvL5s1r3wzJFchLl82e15tttQYxE+fxZafXb9BBE+fxZrfthJU2Zlc+flXYfgx5eK58/q3U/LLc6 zOfPSjt/plmv8vmzWtfPii6+lc+f1erPw5uiJrPPn9U6P0cNmWKVz5/VOj8PDzgYzK3Pn9t1/ZzR 6trW58+tVh9G9wBbnz+36/pZZiT0tj5/bhPt+IWMc+vz53bdDyvo2U3r8+dWu18lyUTX+vy51e5j KDpUPn9u1/0wYUn2+XO7+HNRx8TCWp8/t9W6jVcRl2x9/tyu9SSxpJJ9/tyu8/OGLkRbnz+36/lz ndHe9vlzu97HUJbaPn9utfrthMwYrc+fW+38OTFdUvjuP4v1/nMWbwrCHPmY13xbiZwwxz5mLd8m lzmE7/6zWO8/F7KhklMf85pv1+SCqfDdfxYb/b6kIsy5j3nNt3OypSV895/FRsu3k5owlz5mbX5O JWGufMxavWfaEGbhY17rPauSql37mNf5WVlGIn3M635YlG4Ic+NjXufnTFJm5WNm327r/3vrY2x5 Rt+9Z7Hee87KjAQB371nsd57Jow+H17vPOc5OWcXvjvPYr3zTBh9/rvedyaMPt+NtFptcnNN+O46 C+2ucxLTHvb5rnbXOZeU2ee7613nYrhjZDL7fHe961xUGW2zz3fXu85FRZZ+wnfXWax3nYuK3GkX vrvOYr3rXBUZCfC+u85ivetcyJq22ee72l3nlpw1C99dZxFR//0fT07fRWcRaw8XkEJt4bvoLGLg wL5LzmK95FwK8miB8F1yFnGCGuvz4Bh4sO92s1hvN1ebhOrr8+D1dnO1acnI+m43i/V2M2H0ee96 s5kw+jx3vdVMGH1eu95orkpycVP4bjSL9UZz77Qk2PhuNAvtRvNwo9tk9nnteqO5akhyVA9pas/V vd1O4ji8tLUT98dVvQ25759Hnj/88W9/+Y9f/vkvb5tNno8/BCECCAeIUBGEGCAcIYIkCAlqBVaC 1SRFOEc3DtUn43GO5273dnu722BR0fY4BR2dnMe5MQibImEQ+lxAXE+qOwgLpP+vb935w0bKinT4 IePcJwcuJCX3CIlMcHWfLbiQDt0BItUEKYdIP9QHap3iWlc4dfpZ4dY1BKnZ7lV97cUf1f2urm+f 5+bt43Dfv+0P18NPkytet5usqXpu6o/9JPnkvpwP3f3t+6N35G+3i+gOt/3bD3E9vIvt6a/bPuR2 t9MzgBkcT5oZr120mdvzeWiaAWzQa/i/PmqI/apWGw9qmSvWYafCbJQ49r9db5s/1Jv4PHQz/x/+ 19/+OvYN2TGs+5nURPjoQ1QPM2+aaaxk463u51KGtel57zZvQngTjnf+eLDOSAain0kZxnfBqEuM sp9KGc6jOM07kzovCRz9sDK87aEbHllVJ5ufGF8/mTL8V3Xb2wNUEtaSY72LHzanIJyVwzgux8ft 7XbYddvbX3qYfshmHHokV/fTq4lz2/ehb3Sd8X815/tqpmrwHhkRhBoj8ADUSiUEaMSu78Y30TWW Nm2dsto0QWA8FlVMWX2s2gmL+G+z4fy3hew/iZO43yg/MY5kA/lP4mJEtZGdmHVCnb9Wd70jNPaI Y6cBYHc4qSMAiDkAGgXG4AEAEg6ARoO94lufcsw0IPwQP4DsjGOnMeFrCLgAIOcAqGffYdtLjr1C E5rFXnHs1KunaNZHUgAiOBDq2Ji95tipW4/RGABIDoC6Xx+MAbti2FPqPt0DDKDi3Cel7nPr1X/f AwTOg9KEHYSLAhicD6TUByA35wQpteL7TTQHAMBZcUqntp/OwARUwbFTJxgmRcDPeUFaeYI5mVks fuoGdxQEFOcAaY1iyP7cGzMNIWRdk0oUf6+iVTT6toS5Qb5HmGuOWQGjMXknk6G8du46TjtmKrWm 4+PUQzOqbNMn9qI+SHPmErejeDvc+r6794GgPV+fXSj6BP+3f/ztz7/889c/9Zh5Qeb0LMJwk0+Z WP/rt7/+8mcWKCZAtVL7II1I1pQlHJBbFwqRsrp0h/vBAvntr7/98zcAk3Ew/VjZKH/59U8IJCcg l8BuUQSnYHDcvUIRSk4Tb6dQlIpB8fUJxRBWx+7DeoW8A1JnNYvk7BcLQ/La+HrGwmlYHE/fWCiK oPQ/gZ1TkHVM1vJQbqshIPkG6OM1HAoU8UA+26EwNM6Edw8Jx3nCIrl7h2KkvDbezqE4GYvj6xuK kjNdHNQ1ZH7NCw7I3TMUomR18XYMhak4GF+/UBAab36EdYsgeyh5zeA4e8VCkJwmvk6xUBoGxdMn Foay43hgr5Ctxrxlkdz9QjCKDa+Nt2coTsTi+PqGotAY03wGTk+kk4uEA3LPThQiZXXxTk4UJuNg fHMTBaHxpQvtF7KLWRQckLtfKETJ6uLtFwpTcTC+fqEgNL7cZWg+Qy2vZpHcPUMxJK+Nt2soTsPi +PqGoigOJbB3yK5f0QIsd/8QlHKDNPL2EEWKAJKvjyiOFW8ase/5Q7qIbJiXCQ/l7iEKYsWcYHXI arXMWCS3NhSDRp3mEaYLWXWUBYPj1oQilHbnhqlCtp/LigNy60IhaMz5HuZTFcWpGRynJhYCjTfX a6AqZAuhbDggty4Ugkab9+CshuSMZcsiubMaglFteG28WQ3FiVgcX1ZDUWiU2Yk2qGfIKqNKGBx3 v1CElNPE2ysUJWNQfH1CMWhs2T3CzKUmKUBVcEDOXrEgSlYXX7dYMBUH4+kXC4RGl253DuwY4pFV zSK5e4ZiSF4bb9dQnIbF8fUNRaExpjufu7fd/tF1QVuw5AZQXbUOPHc/ESRB4811hArRiexaiohF cmtDMWJeG++oUZyExfGNGkWhMWeIoOPO/ZDwi/r8Q4V0FKnwrkXmh3X2mgWYM4C7c1ieQU/sRYHA 3DpRmBLq5BtMC6pCUJ7xtIAEA9SchdyL2/6kggaTlPzWovZguu2fokmfhl5PoIiNB9HnExSPRrLB ZmvRp11B3Udez6xFi+GcPUeB6g0Gms4IxelLhDstLaKqoxfw3ZoT5CaxZpigFIsswJrUhnFnWBQg Y/TwJlgUJLdBfPkVhaAB6BEUxsj6uCktFHf8ovw06JzDYj3ZymiEDePWgwLQ+PIZ1h1kwdVIG8at BwVorP78PW5V0G5W1rZ0UPPITN20Noy7eQRAWcuuw3W3P3yFDjsp71URhnPrRYFiABRoBmQ9pxIM 59aLAtFoExZUSeKiMgvFHTopf25r4YtYFkZhYXgCloVghZpDn4kPNSJf4n2/dPFYJXES77fHVfjV TGmHV68L8bTDErHGqqVOes5MdTcf/8MoKGDI43z4IV6v6lclOc2ClyFfkaGC29JQD21ek+NviSVB vSDhQ3wEN4U89ler9kVB/rZQEe3mBRGP4JbQ2buNXhLjb4clIH5BwDncuuj03yavyQloCZWQviDh 84UhoSOfvSYnoCVUQv6ChBccnoT7tnhJTIC/UwHla+3wTSW8kMoSMs8oc0rgjsjLTBYabMhs04r/ nxQICEJUdP3/V9uDut4ST3PxVlxvh7fAc3HyhlHdNhDNndFRHIW18u7YUKwWYvm2bEwkuXllvviu 1Ck8J6GSXpky9mIfLqghgl6ZOk6vNCnNiKTk1TTrv+nUcvPSZKLCO5G8Jy839mxSz4KCzaDkzCDH wKGjXnKjXmDc95eAFQEuMfDplZ6wrKfCwC8bS8kZi8ACQm2j5GzDDu/3l21DcLYhMXDoEArONhqM +/4SMLUNhYFPr/SEZRstBn7ZNgRjG9EGCwi1DcHYRmRH+fv+ZeOoGeOIYgfy6RVk2tlR4kB+ubdr rrdTh4TQ7q657rbD9NjJL7mMZFwmyh3Awb0tud62A/Wg6GsG0nAGUmLg0yvAlsZ2oH5/XWXFqSwc yKHDp7jhqx3Ap1dUtjrDjtE3pbrXOiNJuM5oHMiBnTEB085QDuD3l5BJ/I9aB/Lplc6g3Rzb8fkm mtf6ImP6Io4wbrDCGaewHZ6bGTjYLLh1Q5xg4NCe4JYJcYpx318CJkYRZxj49EpPWF1sx+T7i8Ei KbieKDBusMIFp7Adkb9eBuZS59iOyOLwagyqOGMTGPj0CrClsR2Qd/vXdeay5li6oE+vQFta2yG5 fTWZSyNOZ4WBA015wqWm3GLc95eAiVMnGwx8eqUnaBcnEQZ+NfecBJDcM4mxgMDUc8IlqWdix+Wf 5kvboT0dM0OYpBg3uKdjrqczDPxyT8dcT+dYQGhPx1xP2/H53VA8BDixj/BkUmLgYPfmUrmkwsCh tsFlconAuO8vAVP3rjHwUYR3BPmghUwkxj290sOWMTcem3jFmBPOmBUWEGrMCWfMdoQeOvg1m0sZ m0s3GDjUNFLG5tII476/BExsLo0x8OmVnqC2kSYY+GXbSBnbSFMsINQ2UsY2UjtCn5ZNh2DjyDjj yB3IoYPIrafSwgH8/hIyNY/SgXx6pTMs+6gcyC8bSMYZiHBICLWQjLMQO06PheevWQi3zEylAzl0 HLl1Zto4gN9fQqYWohzIp1c6w7KQ1oH8soVwB1nZxiEh1EK4g6vMDtcv7z+nBWMgWYyBT68A087O Egz8cl8XXF+nWEBoVxdcVzsqToK7mlvRZs5Ck304LnHFzFFZ8v4SMPHEzFFRcnqlJyzbqDDwy7bB nQNljprEUNvgzoEy5oxwuGU8vZP5uKjrTV4Pl3vwAibZDNXNGyLFDtrXWfvfJSTihNgB3Oj63y1t eITTlsZsVu9F04j5IbfTSdxFyAWyTTx0WTqcwWQREdI6hbyL2/U1IQ0jJN84hbSiN4hwCYqTEPn7 KlxCy0mI/R0VLCHbcBISp4TfYVdPYZwp56+Uj3gveo+FIwltzytliF/DNmWAjJjIyF+t8AmoYSOR N3+lCtF/EXOSkRMZ5e+tH3q5Jk/m1YuVQwEiSMzPHfUmfmMqOWOqMWKA7ZSc7UhPOY8f0jKVBkMG WEbJWYYKrA0KgKaG0LqrggIQybgXjloS/7gLZtyLCCMGjLtgxr2IPaU6fkg67kWCIQPGXTDjXqSB dT8B0GTci8xd8ROASMc9d1S1+Ae+5ga+cEAGjHzNjXzpKxzyY1pDXzkwA8a+5sZehJYhBWDTwa89 BUgBkHT0ZeDBlROaPbIqGveRVQAiVVYFnv24oblTn6J1n/oEIBJly41nb98NyZ30lJH7fMOPSE82 ythzshEASZyqTALPNAKgySCVqfs0IwCRDlLm2b13Q3L79mUeuG8fAE3bX7h37AMQaftL3yayGzPj rLTybXn7Ma1OFY6NRu8klXJLnNK1Ce2fpFJuSVNK316uH9Nqumvn2T9JpdySpVShO8MB2NRIW8+e cAAksdJq83v2btxyuF2bynG5xW9kXApcOW6xBNgYlwJXiWeX0g9JTaxybCgEWBiXAldZ4JZnADQx sCp3b3YGIFL7Kl6+PhV0pY3uiFflq5enwsSQDfLqlU2C9xfkkP3ySrx8RSvsJiA1z1fuwQc9AziJ IfNWJX2Xpbyw3FWpqvFclQpDpWOsfBelwmDpkLa+a1JBsHQExcbRBypUWTpgIvLdYPLCcudWIvbc XwpDJQMmEt/tpTBYMmAi9d1dCoK1BsyxzRA2YIIbsNx7+ceLy63jReG7P+OF5W7PiNJ7eyYI11K3 8t2d8cJyN2eE8N2cCYK1tK2992a8uNytGSG9l1uCcC19G+/VFh8ue7FFKN/FljBYamSt91pLGC4J DPXGe6klCJd2bx15rrR4UbkCrDrGqO8vwNJOSHz3ZIJgrT5IfbdkvLBcelhnnjsyYai0a3PfDZkw WNq1he9+TBCs1bWl53aMF5W7G1NXvissXlguramF7wKLF5a7vlLXvusrQbCWttJ/ecULzCVMdeO/ uhIEbGmsfBdXvO+DcddW6tZzbSUMldiY3PgurYTBEj+Tke/KShAs7VoZe+59eFG5Wx8y8d36CIK1 lE19Nxy8sNyMLjPP/YYwVNoHue92QxgstYPCc7chCJXu/8vSd7MhDJYOWOW7HuCF5S4HSOG5HBCG Sges9l0NCIOlAyZ9FwOCYK2ubRx9oEKVpSszqbw1+15crmJftr6K/TBYMmTNxluvH4ZLxqyJvNX6 Qbh00JrYW/DuxeUyxibxlbuHwdLuTb3F7mG4tHszb6l7EK7VvbmrG1SoutQpmsJXhO6F5UrQm9JX gh4Ea3VChWHt+sMgEfR8pBG+UnEvLJc/NrWnUDwMlRqx9JWJh8FSG258ReJBsNbouV4vVaHKWhbc vrpD73l4jt2fV5sX9+eDhJCmqMizM+0D5RZwKnbvSwdhUkUTz46sD5QzD5W692ODMKmimW831ofK 7cUq1x5viKo1p2rh28zyoLJbWap07ej5VZ1AqaoVUwn+mq5c2se8Oq3BhijLpX3Kc2Ha9zQ2t6RQ vsvSQaC0+Y0nmfaBsn3qvXnnQ2WjYetJRoJAyUC5HoQO0pQLKs7nnwMU5YJKGwdcF/EBw6sibRJw VSQInbsmwrzxbF8TCUFnr4gwLzsvO5uvXgJLuAuCreNhocBLYAl3QZB5yXnZ3HtZ8YpTvMQCQhWv OMUr177ky6pztSjM88yaiFDluZoU5vXldXJ6WXeumrJ1vQEXqjpXVNk2rrnqZd25SshWuUSEKs9V RLYtPkV9+RXJxla9Yd5q3r/ophOuILiR47T6Zc0lp3nskBCquuRUTxxHwS+rrjjVU4eEUNUVp3qG TxhftvSM0zzHAkLtPOMUd5zfvax4zileYgGhiuec4s4EO/gNNmZ/udm4k2wRHlXIZkTDPLasIb+/ BK0ItPQuOIJjYUagnYH8+kKUJXWxzcZVTHF9Ye6xgFvsLtcX3IXiMi8tN6/i5hxuFJgVOqtauXyw 4Z5aFqF1slwm2DBPLPPplBu64pRN3TlgACJVNgvO/tzgglM39+V9AZhU4SI043NjJ5y+pSfXC4Ck 6lbBWZ4bPOX0Fb78LgCTKlwHZnbuW3RcTsc8p7wPdjU2m2OeUQbZnBuby+OYl5TNPC4AkqrbhmZw bmwud2MeUX5/oXe5rM31fvILlsvla3HsztcCEKmySWCm5obmcjTX68l+ZbnsjHk2mWZnfs+leRnz ZDLJywIwSUbGPJdMM7IAUJKLMU8l01wsIG6RLCyufFmYH5OmHcwLybcXILnMi3kb2ci8/IZvIUp3 zuW3Tgux8a8dvJVqrIUq78ohDJdaaetfN4QBE0tNNv5VQxAwtVbmJWTzUCWw7LggsLHv/CNQXYqb +F5NDyo4tXoh9RWhh5wtUStj3j42S9CDQImJMe8dkwL0IFRqX4XX00IOrKweKH1+FoRKu6DyelkQ LO0D4bEtHyhrWbWnlNkHWnKgkr9gu57ZDO+IufOsUdma4DYhuCF7byy62p6vXc/51mPe3y7iqrr7 Xt0Ot+3lHz3IeSLVGNqZ4XrY7QnHrxxHtvFcMXv1ohV3IajJIveNs8Dc6XnvjHGbLA4VEHq5jROS BAg5vSjE6qrUc43uZSmKk5J5ajhe7TCuOLJhHshkpITfDeRKJRvmtUxGyPurUkioy7xX5cJS9ad7 cO2ogiWE3srjpPju0L2ypOcWc1kdIuDV7QhuIZpJT7Lw8oU41um9t+1evR8nuWFRQVJe3CRjN0cy 78egAhedCbKxfBMsIfSKHiclCpLy/ZWbgMz4c09rMmIClr4JKJ5uuLc1kYgXWmKJSd0XGwOHPVs8 hQ5IFogfeoOSk5F77juGDkYGe6nwJeCvbHWwU3xehosIXVVzYvzniC9sNrO7ornwLrJf2W1iZ968 fkFG6JKekyPD5ARvcnFD0rwg44W2WHKU+6Lt79laZc8FmFc6zbu3oV2Wo0y12ARLCL3ny0mJPCvZ wOBYoNmqiEMFhO7HcEKSECEv7fpwfZWGSAk8gOVSSOYJUPMWb6hRVWg9yjwJal7nfUUC30lFsITQ y86clDJEyqsn11yyXVTeK9ChfSZga0SYjMDTZ9a06jARr56es10mPfelQ180i2DUaoIlhN7N5qQo z53nsNj4vPjMha02REBAR8XIskrPR7deeQ6TzbXKKEBA2AuW7Gl5GQfgv/j4Jjuhl4nnYvPrV5yZ RVWZBksJaAcrIfPceX5pyDm3cD2D+rLzYSmF515IoPOlyPmYB1KBgNDr3JyQynNL+uVr2NxWTSlC pJxelGKNSB0ixe/rGfR16buq/urlcm7HiXl1lZPySm9xmVapfBfZXx56xQ19GyTm9KIY2hrmtVOu 095fHRuyFK0SzwXqV29osztbVRoi5fSiFKvLMs8N/lfvxrNOWeUhUl58+JedIJmnVMlLB6+8hcz6 DPOKKhQR+qwCJ6YKEvNqp3F7zpXwXUR85fFkLrGv6iAJrz79zOX1lfRcVXztpWJuZJpgCaGX8Tkp vhdWX/jWCluEyLy1ypwth33Ug91+FEGH1y9+kIQ1YNdLrK/0lUB95XqT9XcVmgpUbSqSkPPSwE+t cK7ofbH1d30mhvNE5hFX7sg0sOKXbUvueXj195Qrs/OK84nX0++ujGa7rfQVRP2uw0bW2KqAM6Gw qmE2VxYi6Cgl8IiDlVAHbKWHlRLz+DJkKRy4dcAGySZkgRf4dQ3WR5T7dZsX3q3ne6j1PMrzigCu h+pNyHQb+PI+10O199WtF9aMvIQ4ZAst8Ds/rIAkJMEOS+DYUWaenAW7jKFPLDKL3joL3QcMfWmP yavqoMOFwDtf7FgUngdIXvleECsgbAHywjtp3A5EXQWt2QN3UrikqhYhsfX04mamNd51yHAEf2yK kyCD2xE6SVAJTfCIBy4BrdFWIZlUWKrGB5DW8+j8C5Vt7DQhN0GbP4H2ykrwPYX7yqflOMeWsftT Ha+s+LgxkEmwK4S+u8oYq0yDz4dD36fmpGTBpUahj6xzUvKgXDzsBisbBGXYhlXg1M2ZLfN2000c j+LtcVPNm7i9vZ+vouv/fLufL2+3w64Lf9RhiFhNTORFTKrw3xU3JQ2suJip8T+GPWgwlfWn4FXa hnnuSbzX4hoOnYBvEjfMW0+n8354P6oJ6o7MqL2NW4LOOcf4SvMrA8u94t4wrzxdxe38OAZhR0sJ ZGk/3dZwLz0dxedehT/BlIKHwRrmkacPMfpBUK+M+k6ac7fO2gr42EsdTpfnzOtOI+pg3ufH3Ddz M/zo81fdLbOf/2D14fJZe775s3bqfldXp25zi+xk7PtA0P+I4/nRc7qe7UmXBsglXSqo85o6UfRJ DxVvtvJ8qvuZodtpWdtwjWcvju329NdtnGy23e1kXshRccQxTtd5PJyxxtmcH/VRvd0PxyZMbIKY Q0T3//FyVTfV3cX9MHxOr7fF4efth7reD7KfVO4f5x723qsiGnXdXv42XUb6w//+9e///O2PwwwT b+LnoO+On5e9k30WG/nE9rNbI2777eVPjLwohfJmvllQ7BXUuQQlWFBnCkp8go7nj94sOrW9/NGS tNlkLZR0uwg5DO6ja4anks9XtQhNfUI/xI/P/77kEYURn3nbjG6/GRrEJdTgfFGjYesYs/TcJx1f pTPFV1C8PJ5vSHwR1Hj5uB4/3+qrkO/qzje/qL3NN1FmDcqwDiAqcF1QNN4u4FWogjrhfr7ez4fb uMV7PLp6I3H59twbAG7WSYR1C1LqV06pzNs/HqXqoI6qjz1X/z+7/r89jn066e6qjberIOCslwzr LKwY212Rt7u8ijVBHfac8ES363+dnbUR3s5iwWZ9VFhH8QpxnbSpvZ3kVKgN6qCQnvGHX1aDdBPW JSF94Q/BvApRWBA+XzvlcaaN9EdhE2bWIQ4Mw0QJth8C4jCvRBLUER/7w12FdYfydgcLNuuThnUK rxDbNa23a5wKVdshXeuXW+eeb8qG5lT2j3/7y3/88s8h30uerZ4TH43FyHxSsZV9265qAHoJcWCb qBnUejtmWq/gLQwmktw+Y8fLgJTPxG3mXrRzyhlyzShJL9oJZKr0bnwFUutGBrbdgrwXA4IUN9ts b6d+odhb1ekkpv6Tt+0f/vGXX/48JY9mbZ7KoifDoVHn3VVc9v2KU2MetHgy9zYdEeb4ydw++p9h F4yTOA/YSHlR18O5WQDS53++qdNBno+9NCp1s0lqIjVb2rgwGBITQRjyJ8NPD3Ub3fskru+cpJYw Fk9G9bPsl/7CxRvTvilnXroyfLKsy8KFpXqy4GXIKq7Ue9Wx7MjEk8axulhRKx3VsZrIal1VsGhY YOcVg6ksm6Fn0lAXrAVW5IZTmEdudJV9Kf5i8/Mgmbq7s+dMGY3wZe6rrIxrjUdW+yTvHqd62Lo6 7J4+0dNoI5uYtpbPgUKchg8aia7hbDonTHOwELc+mh1urB8Q58vnGHE5Pm6Tdre/WNoRF8+TJ9O+ nzxV9+106B63yYNMvobwpcsY327f7nvRaRJNVydxMJ+Dyu6qRN84N7MizHOAUT89xPEG2ai2c4i4 qmHi6gf4fDw0Q0OtXs2kbhl1bwG3o7abk8+Rozkfh8XJpMAfre4iAScXa1QeZihoPBnhq7VZpmcd jqTEnVE7NT97pdY7ti88WfTct62NTdF5HpxxFgnLkU2fyX0odSQvJI3fT8IfszCFLFx92H/CLXKW s5rxUxkvtUSyLZlxFgnLucr4uYyXJDSshBlnkZAbDQ2HV3goFpNc76W+8qUSu/v3XOeXRueHK97i nl8Vr0zwsI+gGMATIKe4MMY0WPFsgwd0Vbw2wcO+r2IAT4Cc4kthyPM7LsGaR6zmE8qqekPgg3Qn 0BMkp/xSEXJ7vD/C3SiLed0HkAW7NbGDFCe4I6OttnaXdDoBmr4AF3Jia+1nPZnenoAj0tL72p3S SdD6stxpHI3po3MhgmOP4NMyRoOMRYE4SAF3rYgleiJ3C06gYP1zeyEtT4K63FIgDVLA3fLE2XIg OCOCP8TH72t4GtzwXsQiPg8R7252GthsXWzh6e5aDYvwkGZnYc0el+hmz5dBOrjbnoW0nZFdEdns 1yVDmp8Hj/qnWKSLEOnuhueBg65JrYPa7H3pzm7xk8UlW4bI9n7Ek0p+MrgEN5yRBRX7eAbWMCfF SfE8buocQAO9Jeh14NeFSk8TarH0U7VhZHhqEp0N0LEjTn+vnZUeO9MlxIwE75dW3dakw9PZcbhd dRLX+nEPS0Mqz0DchZjxlmSkSh1C3SNTOUeGFZYxwkJaJvwtW2TkjAzPPTRfQxbsgtPf//iox8R0 CSU3HL5v5LpNTIenE9L4hduQEah9I7DXpAhOinsMavcY6Og12wbvKNS+UdBlSE6G9wPAnnHQBdAJ I/TzX7H0DMQAtEhRnBRPHb5zIAz0lm2D/w1bz0DoMsSGk+EbCOkeCENAZK36Ar9k6M3IlsEWMSPD c1nBk3et2Amnv3cMGm92tUpIGQm+EWh8OdQKT+eE0G/KxcozAu+6lJyT4vn+jnMMDPSCbYN3FJRn FAwZJSfDNw7KPQ6GADo3NCKoNDtuPePQ4ywyBCPDPQqtcxR0bHteCGtAsvHPbasUyUlxX+HY+Oa2 FZ1OC6Ff6PPtQF3XYVaMCLf+kVN/DZpOCF/D9Z0Q9X37WAPQLKXecFLcLXBvVhnodD4Yb+0EfdTR 04YBaJESc1I8F4GcbTDQE7YN/hemPeHIkJFyMrwfXHGHI0MAnRem+/9B3+30jcRel5OzcjyvCrjH wsAv+Hb4HwH2jYYhpWSleD/+4hkPQ0Rl3dpowm6p+IZDLAUqtWBkeJ6QcA+Fhl1z+vtv+PmGQZMg GQm+Icg8Q6DBN9bkGTYAuXeCXmUoRobnBQzPBL1it5z+/redPQOgSZAbRoJvADzbfTo8nRvugV8/ LrzbF8sWiYwZGZ73lj3bFyt2wunvfzDau32xSkgZCd6PRfm2L1b4zJr6wwbAt0XZaCfpMmeEuEfA vUdpgBdcC7xD4NukNESUjAjvt7U8TqDj03kgNMnzbU9qWZgUjAzPqxrujW4Nu+b0998n9wyBLkEy EnwjULlHQIen88D00nXIEPj2UUekRY5i5XhezXYOg4nf8u3wDoVvP9WQ0mxYKb7h8OypmiLovNCG rdpS36qtXZZWTcyI8DwW4RwJDTrhtPc/K+4ZBE1AygjwFW5E7v7X0OmcMLwuFPQugKfze5xFRs7I 8Dy45Ox9Hbvg9Pc/heTpfl1CyUjw9X/s7n8dns4H74ED4FswS02GYGR4Ht1xDoCOXXP6+18x8QyA LkEyEnwD4Fkq6/B0Pgh9mcC3Tl6v36tGMTI8bxI5B0DHbjn9/e82eQZAk6A2jATfAHjWxjo8jf+n wMOc1Lc0PmknFSrmpHheJHIXaenoCdsG/1vXnlEwZKScDN84eBbIhgA6F4wP4oQMhG+JPAAtUnJO iueNHedAGOgF2wb/c2yegTBklJwM30B4FsqGADonBB4zp4X3VG0RIRgR7kEoPIdqC3TNae9/Kt17 prYIkIwAX/cXviO1Bb1hiv2CXqrxdL5W2acUI8Pd++5Fso7dcmVO84O1IQ2pAoqqesCfBsBlXdtu XGLdbau8VVa2uIipVQtpnG8Nt1altTEjwvPUqbMhGnTCae9/s9zjIpqAlBHgcxHPok1Dd7wX+rur sadnhcJLsg3ReiVem7+qXcDrkKH12lirIkSrFwtbJ93Ci7mxduWr2gX0WWilN9aqCtcquBZ60u2l gmisoHhVwYBue6FaGitWexQL7ihfSoFVkB4VArrCnXJg0e32S13PvaymF9adv9VXJd7HKzFqK/9X L6vunk911Z99U87XoTPHq9ITQruJtsMt8QkA36f+r9/+9CtznbrdxBr7T4/z3ckcE+ZEY2bvyS6c CeFMNU72cuXCmRLOTOPk71curBlhzTVW5n7uwpcTvkLnu5xv9+v5slcMY0EYS40RXz5f2J+Z08qD 75+3m0qjc9xBX8ArCo6vobcbobfYupS8YArS3lofG/te8sJXEz6pq2W+sLDwSMLTaDz8deaFtSGs SmNlnlhY+BTtMuOVhXbTan8y7hgrHaWlKPoV4zba6J5w2B3ub0NE2HZjK7TOTjbb6d/akCiyeM+d Ylij7fRPY40t1vsHJzXeTv801sRm3V8VJzfZTv805tRibs+PK8Obbqd/Gm9m8x5+cHKz7fRP480t 3tvhZ4Y1307/NNbCZlU/eiabudhO/zTm0mJWg7MyzOV2+qcxVxZzd2AHuNpO/zReYfiU8aLHwkb8 N9L9l3k6ZOEj/htJI87xTwQszMSRI92R2Yv+Cyfx40j3Y8f7Agu/IvytMfexb5gsvOYTJm28ISGL ua4/85Lb+m2su22foRy6Nykuh/v4OtO0It0e/7MHOWoY67zdtv3/M+LEPpzaxol1nHjCSXw40sZJ dJxkwkl9OI2Nk+o46YST+XCUjZPpONmEk/twWhsn13HyCafw4exsnELHKSac0oezt3FKHaeccCof zsHGqXScasIRPpzvNo7QccSEU/tw3m2cWsepJxzpwznaOFLHkRNO48M52TiNjtNMOMqH09k4SsdR E07rwznbOK2O0444ycaHc7Fwso2G0/8/I443/vxk4+jxJ5viT+KNP1cbR48/2RR/Em/8udk4evzJ pviTeOPP3cbR4082xZ/EG38eNo4ef7Ip/iTe+PPDxtHjTzbFn8Qbfz5sHD3+ZFP8Sbzx52cbR48/ 2RR/Em/8+bRx9PiTTfEn8cafLxtHjz/ZFH+Smi6zbn0acWWeu1xQarTSIpzPGTvRIxN8VWhBlxSd PizUJo21eqM60wVc1qAFHNBZj17ycJWPU3tUP78JOSyZt7d/p/jWamd5ZG9hXrCNiGY9r7dAtgjS emGvTTdGMid+KKhpvkGwI9+CaIe5+RGrOcn6s2lc+RLkxiRt/B2RYjdSbSPFGlI8/Y5IiRtJ2kiJ hpRMvyNS6kZqbKRUQ0qn3xEpcyMpGynTkLLpd0TK3UitjZRrSPn0OyIVbqSdjVRoSMX0OyKVbqS9 jVRqSOX0OyJVbqSDjVRpSNX0OyIJN9J3G0loSGL6HZFqN9K7jVRrSPX0OyJJN9LRRpIakpx+R6TG jXSykRoNqZl+RyTlRupsJKUhqel3RGrdSGcbqdWQ2ul3QMo2bqSLhVRsVqThitjwOyJ54tNPNpIW n5Jo+h2RPPHpaiNp8SmJp98RyROfbjaSFp+SZPodkTzx6W4jafEpSaffEckTnx42khafkmz6HZE8 8emHjaTFpySffkckT3z6sJG0+JQU0++I5IlPP9tIWnxKyul3RPLEp08bSYtPSTX9jkie+PRlI2nx KRHT74hkpWbgTdMFCGZm3OOjbaZHrfWN6yEbsbZ/CistWxhqcV0Q7cwMPJa64MLEjFdZD2rjF1oY VWEuNjE8ofp8Zfisy0ShPzRMNrUH6L/+8ve//+2/xteGn77Ps5pb3H0es5I531DX8CXFdz6c3vYZ zkrqfiNdE9JQIc6H0ds++eHbS95k1iSQk7I+6VkR3sVdvItOvJ0OTXNUw6dt1vR3xWjJRmmf7jAY c8w4T6eLRwOBHLn1aQ5GeD4iy8AI2pjSC3PgYMgxXp/g+GAeHAw5mOuzGx+M4mDIcVuf2vhguC4W FYGRXphPro8V7ZzGj8P1jqK9o/w4XLsU7Z7Wi3Pn9JGkXX0+Y+N82x+uYjcAXq7DocFONf0CuV/m Tfvpx79Yhk2OAYrIoR1r0sQzitgBwBozOVkuEgcAa8bknLhIHQCsAZcEIHMAsKZLDnAKV3x5Z3uR RKjCFV/e2W4kpzKFK7S8s/1IzlYKV1R55zqyJuGtcAWUd64na2rkzljC9WRN3LZwhhGuJ2visIUz gHA9WZNQVjhDB9uT1B6cQYPtSWIP5caBcGd7kthD6QoNd64nJbGH0hUb+KBHgkPpCg53ricliQ6l KzrcuZ6UJDyUrvDQcT0pSXwoXfGhY3uS2EPpig8d25Mk0Jeu+NCxPUktyhUfOrYnyclv6YoPe7Yn qU264sOe60nyVdq2dMWHPdeTDYkwpSs+7LmebKhFueLDnuvJhtqDKz6cuJ5syFhUrvhwYnuSjEXl ig8nNsUiJ/KVKz6cuJ5UJMJUrvhwYtMzYg+VKz7wCSeJUZUrPvCpJolRlSs+8EkmsajKFR+ubCvI nFW54sOVswdFolzlig9Xth+IVVeu+HBl7YFEucoVH65sT5IoV7niwwfbk9QvXPGh4xabJAmq2PDw 43yQvuy+mgf133758//6r9/+9M9/e/v3X/75y7//8tdfvv3bb3//5V/7//H2v//22x9//dPbP/72 n3/909tffvn7v89i2Zgy1CN9C5ItAmT/49e//PYNKSD0kLQX3e4xvPx1PKqr3WnRfKxicUih3s7z lbVWRDbFklZ/qvM7Az0/yIUYdwPjbpEQQ8Lbrf9/sZjYLWbkpsIST3O+3Q7nGycsCWnT28g9y0oh dXdQj46TQkKjyNwQ32T/KzmgzK3uyP32vf/9vsjKPbL2/e+ek5WHyJq4Z1kFpL4f3tXjzokp3GKa w049lh1AUbrtAospQ6yKCKsg+bVv9pETU7nFHEe+GV+48b9hHxEBYqiP1B5pp/73xAmrQ4RN3LMs 6ZF16X8vnCwZIqvuf+tFVuORhVy/CRFleL7ySLoP3nBnnUmFCLsP7Iu01teHg7QLK60NkTaNwVNa vfFIQ2FiLid1yzLCRI0nH2SDKUlwazy7INNKPfOKYVR14o4UUEgSEmZMUam7Kch+0zSgPYb91nja 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 xxGsGyjIU9eNFBRTd+0bKQmm+tYbTZ3qG200dWrBVuO79k00njrVt8wY1jfIaOq6mTFveeq6qTHU 3HKE+S6Mpy50YTx1h/5N+a7HLi5P3amPI9i5C+Op6+5hH3nqumFQsnVVNzfmk4xd1U2O+SRrV3Wz Yz7Z3FXd9JhPtndVNz/m81+Gdfc6snhVN0PmJz9bT5h+8oT0ZOknz8ehe0e+ZU+SfubZOHVhhOrJ 0U+ei54Y/WQp0t29i1DddJw3mrJuNs4bTVk3GeeNp6ybi/PGU9ZNxXljVHfXoinrJuK88ZSZbtLo N8O6OcoZ1pWzDJsRtL/37w8fbxuKf6u5lJmfX8/PPz4+92+EmZn9+/0LZVar2UyZ7cvufv9MbPBq Lk2m+n1mtt/etz/HJ61xM/P919f2A3qKxrbxhJuZ8Ca5tZrLlZn00lJzmTKTZlpqLk/mppuWmkuT mbbTUnNJMtN+WmouR2bSUEvNZcjcdNRScwkyNy211FyCzLSnlprLj3n9ermLHPt8v7n0GAL9vX39 /CacauOedu8Zp5u4n/sCZtqw3c8Ms03YOLEZ5tqwOLcZ6JtAmF7GhSYuTnDGHZq4p6/Xh3dqBabm cmXyt4gq/9fH5pXRWeZGxfd9/2u7nXRMVEXYeQqh718Em6cQ2s+LEPMUQkupiCtPIXR2FMHkKeQ3 QUwTwsZuETmeYn4xxrWvw+/t2xh+8dDG8Jsf2hh+9WMbw+/e/ppsXxQR4hsMv9eljeH3urYx9F7H tuiwIXNsy84TvdexLTxUWqaObemh8i11bIsPlZWpY1t+nvm92vLzzO/Vlp9nfq+2/PBRe2zLzwu/ V1t+Xvi92vLzwu/Vlp8Xfq+2/LzyM3fkJ4OunQulEkt1aksQnz6ntgRRkpU6tSWI0p3UqS1BlNKl Tm0JeqWvempL0F9f9PYn2wHxm7kOiF/Nd0D8bqED4pc7dED8dm05YkP81JajD4K0xYhN4VNbjNhK P7WliG3lc1uI2ClwbgvRB736uS1EFIZR57YQfTKmLUQUCVHnthB9MqYtQxTIUee2CH0ypi1BDzyH bQF64Dlsy88Dz2FbfB54Lz+35eczg84dEE/RpQPi9792QDQBl6EDohm4iA6IpuDSFqPsy7p05IgX yEV3QPR2l44k8RK52A6I364jS7xILm1hYtv40hYmjltc2sLEIZVLW5jYQLu0ZelvfrG2KP3N79WW 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 ------_=_NextPart_000_01BFBB9E.38874800-- From Vladimir.Marangozov@inrialpes.fr Fri May 12 02:19:58 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Fri, 12 May 2000 03:19:58 +0200 (CEST) Subject: [Patches] marshalling recursive objects Message-ID: <200005120119.DAA16649@python.inrialpes.fr> I saw recently in c.l.py a discussion about recursive objects. It was noted that recursive comparisons were fixed, but marshalling recursive objects still core dumps. >>> l = [] >>> l.append(l) >>> marshal.dumps(l) Paf! The following patch aims at fixing this. The approach is the same as the one used in pickle (I believe). Container objects are kept in an internal list. When serializing, on recursion branches, the list index of the container is stored in the byte stream, instead of its contents. This index should be the same when deserializing, because of the strict object ordering. Recursions are thus restored, and we have the invariant: o == marshal.loads(marshal.dumps(o)) even when o involves cyclic references. -- 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 ]--------------------------- *** marshal.c-CVS Fri May 12 02:51:29 2000 --- marshal.c Fri May 12 02:46:17 2000 *************** *** 52,57 **** --- 52,58 ---- #define TYPE_LIST '[' #define TYPE_DICT '{' #define TYPE_CODE 'c' + #define TYPE_OBJECT 'o' #define TYPE_UNICODE 'u' #define TYPE_UNKNOWN '?' *************** *** 68,73 **** --- 69,114 ---- else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \ else w_more(c, p) + static PyObject *victims = NULL; /* processed containers while in progress */ + static int _PyMarshalState_nesting = 0; + + static int + set_victim(op) + PyObject *op; + { + if (op == NULL) + return -1; + if (victims == NULL) { + victims = PyList_New(0); + if (victims == NULL) + return -1; + } + return PyList_Append(victims, op); + } + + static PyObject * + get_victim(n) + int n; + { + if (victims == NULL) + return NULL; + return PyList_GetItem(victims, n); + } + + static int + victim_index(op) + PyObject *op; + { + int i; + if (op == NULL || victims == NULL) + return -1; + for (i = 0; i < PyList_GET_SIZE(victims); i++) { + if (op == PyList_GET_ITEM(victims, i)) + return i; + } + return -1; + } + static void w_more(c, p) char c; *************** *** 144,150 **** { int i, n; PyBufferProcs *pb; ! if (v == NULL) { w_byte(TYPE_NULL, p); } --- 185,193 ---- { int i, n; PyBufferProcs *pb; ! ! ++_PyMarshalState_nesting; ! if (v == NULL) { w_byte(TYPE_NULL, p); } *************** *** 223,229 **** utf8 = PyUnicode_AsUTF8String(v); if (utf8 == NULL) { p->error = 1; ! return; } w_byte(TYPE_UNICODE, p); n = PyString_GET_SIZE(utf8); --- 266,272 ---- utf8 = PyUnicode_AsUTF8String(v); if (utf8 == NULL) { p->error = 1; ! goto finally; } w_byte(TYPE_UNICODE, p); n = PyString_GET_SIZE(utf8); *************** *** 232,263 **** Py_DECREF(utf8); } else if (PyTuple_Check(v)) { ! w_byte(TYPE_TUPLE, p); ! n = PyTuple_Size(v); ! w_long((long)n, p); ! for (i = 0; i < n; i++) { ! w_object(PyTuple_GET_ITEM(v, i), p); } } else if (PyList_Check(v)) { ! w_byte(TYPE_LIST, p); ! n = PyList_GET_SIZE(v); ! w_long((long)n, p); ! for (i = 0; i < n; i++) { ! w_object(PyList_GET_ITEM(v, i), p); } } else if (PyDict_Check(v)) { int pos; PyObject *key, *value; ! w_byte(TYPE_DICT, p); ! /* This one is NULL object terminated! */ ! pos = 0; ! while (PyDict_Next(v, &pos, &key, &value)) { ! w_object(key, p); ! w_object(value, p); } - w_object((PyObject *)NULL, p); } else if (PyCode_Check(v)) { PyCodeObject *co = (PyCodeObject *)v; --- 275,333 ---- Py_DECREF(utf8); } else if (PyTuple_Check(v)) { ! int x = victim_index(v); ! if (x >= 0) { ! w_byte(TYPE_OBJECT, p); ! w_long((long)x, p); ! } ! else { ! if (set_victim(v) < 0) ! goto finally; ! w_byte(TYPE_TUPLE, p); ! n = PyTuple_Size(v); ! w_long((long)n, p); ! for (i = 0; i < n; i++) { ! w_object(PyTuple_GET_ITEM(v, i), p); ! } } } else if (PyList_Check(v)) { ! int x = victim_index(v); ! if (x >= 0) { ! w_byte(TYPE_OBJECT, p); ! w_long((long)x, p); ! } ! else { ! if (set_victim(v) < 0) ! goto finally; ! w_byte(TYPE_LIST, p); ! n = PyList_GET_SIZE(v); ! w_long((long)n, p); ! for (i = 0; i < n; i++) { ! w_object(PyList_GET_ITEM(v, i), p); ! } } } else if (PyDict_Check(v)) { int pos; PyObject *key, *value; ! int x = victim_index(v); ! if (x >= 0) { ! w_byte(TYPE_OBJECT, p); ! w_long((long)x, p); ! } ! else { ! if (set_victim(v) < 0) ! goto finally; ! w_byte(TYPE_DICT, p); ! /* This one is NULL object terminated! */ ! pos = 0; ! while (PyDict_Next(v, &pos, &key, &value)) { ! w_object(key, p); ! w_object(value, p); ! } ! w_object((PyObject *)NULL, p); } } else if (PyCode_Check(v)) { PyCodeObject *co = (PyCodeObject *)v; *************** *** 291,296 **** --- 361,373 ---- w_byte(TYPE_UNKNOWN, p); p->error = 1; } + + finally: + --_PyMarshalState_nesting; + if (_PyMarshalState_nesting == 0) { + Py_XDECREF(victims); + victims = NULL; + } } void *************** *** 397,429 **** r_object(p) RFILE *p; { ! PyObject *v, *v2; long i, n; int type = r_byte(p); switch (type) { case EOF: PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! return NULL; case TYPE_NULL: ! return NULL; case TYPE_NONE: Py_INCREF(Py_None); ! return Py_None; case TYPE_ELLIPSIS: Py_INCREF(Py_Ellipsis); ! return Py_Ellipsis; case TYPE_INT: ! return PyInt_FromLong(r_long(p)); case TYPE_INT64: ! return PyInt_FromLong(r_long64(p)); case TYPE_LONG: { --- 474,514 ---- r_object(p) RFILE *p; { ! PyObject *v, *v2, *ret; long i, n; int type = r_byte(p); + ++_PyMarshalState_nesting; + switch (type) { case EOF: PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! ret = NULL; ! break; case TYPE_NULL: ! ret = NULL; ! break; case TYPE_NONE: Py_INCREF(Py_None); ! ret = Py_None; ! break; case TYPE_ELLIPSIS: Py_INCREF(Py_Ellipsis); ! ret = Py_Ellipsis; ! break; case TYPE_INT: ! ret = PyInt_FromLong(r_long(p)); ! break; case TYPE_INT64: ! ret = PyInt_FromLong(r_long64(p)); ! break; case TYPE_LONG: { *************** *** 437,443 **** ob->ob_size = n; for (i = 0; i < size; i++) ob->ob_digit[i] = r_short(p); ! return (PyObject *)ob; } case TYPE_FLOAT: --- 522,529 ---- ob->ob_size = n; for (i = 0; i < size; i++) ob->ob_digit[i] = r_short(p); ! ret = (PyObject *)ob; ! break; } case TYPE_FLOAT: *************** *** 449,461 **** if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! return NULL; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", return 0) dx = atof(buf); PyFPE_END_PROTECT(dx) ! return PyFloat_FromDouble(dx); } #ifndef WITHOUT_COMPLEX --- 535,549 ---- if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! ret = NULL; ! break; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", break) dx = atof(buf); PyFPE_END_PROTECT(dx) ! ret = PyFloat_FromDouble(dx); ! break; } #ifndef WITHOUT_COMPLEX *************** *** 468,490 **** if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! return NULL; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", return 0) c.real = atof(buf); PyFPE_END_PROTECT(c) n = r_byte(p); if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! return NULL; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", return 0) c.imag = atof(buf); PyFPE_END_PROTECT(c) ! return PyComplex_FromCComplex(c); } #endif --- 556,581 ---- if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! ret = NULL; ! break; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", break) c.real = atof(buf); PyFPE_END_PROTECT(c) n = r_byte(p); if (r_string(buf, (int)n, p) != n) { PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! ret = NULL; ! break; } buf[n] = '\0'; ! PyFPE_START_PROTECT("atof", break) c.imag = atof(buf); PyFPE_END_PROTECT(c) ! ret = PyComplex_FromCComplex(c); ! break; } #endif *************** *** 492,498 **** n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! return NULL; } v = PyString_FromStringAndSize((char *)NULL, n); if (v != NULL) { --- 583,590 ---- n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! ret = NULL; ! break; } v = PyString_FromStringAndSize((char *)NULL, n); if (v != NULL) { *************** *** 503,509 **** "EOF read where object expected"); } } ! return v; case TYPE_UNICODE: { --- 595,602 ---- "EOF read where object expected"); } } ! ret = v; ! break; case TYPE_UNICODE: { *************** *** 512,542 **** n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! return NULL; } buffer = PyMem_NEW(char, n); ! if (buffer == NULL) ! return PyErr_NoMemory(); if (r_string(buffer, (int)n, p) != n) { PyMem_DEL(buffer); PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! return NULL; } v = PyUnicode_DecodeUTF8(buffer, n, NULL); PyMem_DEL(buffer); ! return v; } case TYPE_TUPLE: n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! return NULL; } v = PyTuple_New((int)n); ! if (v == NULL) ! return v; for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { --- 605,644 ---- n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! ret = NULL; ! break; } buffer = PyMem_NEW(char, n); ! if (buffer == NULL) { ! ret = PyErr_NoMemory(); ! break; ! } if (r_string(buffer, (int)n, p) != n) { PyMem_DEL(buffer); PyErr_SetString(PyExc_EOFError, "EOF read where object expected"); ! ret = NULL; ! break; } v = PyUnicode_DecodeUTF8(buffer, n, NULL); PyMem_DEL(buffer); ! ret = v; ! break; } case TYPE_TUPLE: n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! ret = NULL; ! break; } v = PyTuple_New((int)n); ! if (v == NULL || ! set_victim(v) < 0) { ! ret = NULL; ! break; ! } for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { *************** *** 546,562 **** } PyTuple_SET_ITEM(v, (int)i, v2); } ! return v; case TYPE_LIST: n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! return NULL; } v = PyList_New((int)n); ! if (v == NULL) ! return v; for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { --- 648,669 ---- } PyTuple_SET_ITEM(v, (int)i, v2); } ! ret = v; ! break; case TYPE_LIST: n = r_long(p); if (n < 0) { PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! ret = NULL; ! break; } v = PyList_New((int)n); ! if (v == NULL || ! set_victim(v) < 0) { ! ret = NULL; ! break; ! } for (i = 0; i < n; i++) { v2 = r_object(p); if ( v2 == NULL ) { *************** *** 566,577 **** } PyList_SetItem(v, (int)i, v2); } ! return v; case TYPE_DICT: v = PyDict_New(); ! if (v == NULL) ! return NULL; for (;;) { PyObject *key, *val; key = r_object(p); --- 673,688 ---- } PyList_SetItem(v, (int)i, v2); } ! ret = v; ! break; case TYPE_DICT: v = PyDict_New(); ! if (v == NULL || ! set_victim(v) < 0) { ! ret = NULL; ! break; ! } for (;;) { PyObject *key, *val; key = r_object(p); *************** *** 583,589 **** Py_DECREF(key); Py_XDECREF(val); } ! return v; case TYPE_CODE: { --- 694,712 ---- Py_DECREF(key); Py_XDECREF(val); } ! ret = v; ! break; ! ! case TYPE_OBJECT: ! n = r_long(p); ! v = get_victim((int)n); ! if (v == NULL) { ! ret = NULL; ! break; ! } ! Py_INCREF(v); ! ret = v; ! break; case TYPE_CODE: { *************** *** 628,642 **** Py_XDECREF(lnotab); } ! return v; default: /* Bogus data got written, which isn't ideal. This will let you keep working and recover. */ PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! return NULL; } } long --- 751,775 ---- Py_XDECREF(lnotab); } ! ret = v; ! break; default: /* Bogus data got written, which isn't ideal. This will let you keep working and recover. */ PyErr_SetString(PyExc_ValueError, "bad marshal data"); ! ret = NULL; ! break; } + + --_PyMarshalState_nesting; + if (_PyMarshalState_nesting == 0) { + Py_XDECREF(victims); + victims = NULL; + } + + return ret; } long From trentm@activestate.com Fri May 12 05:54:33 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 11 May 2000 21:54:33 -0700 Subject: fix hashing (was: Re: [Python-Dev] Re: [Patches] fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <000b01bfbaff$43d320c0$2aa0143f@tim> References: <20000510131446.A25926@activestate.com> <000b01bfbaff$43d320c0$2aa0143f@tim> Message-ID: <20000511215433.A31196@activestate.com> --T4sUOijqQbZv57TR Content-Type: text/plain; charset=us-ascii This email provides a fair-sized patch for fixing the hashing stuff in the Python code. I discuss it after responding to Tim and Guido. [Tim] > It's OK to use "*=" in C . I think that I often don't know what language I am programming in :) so I resort to a minimal safe set of operators. As soon as Python gets augmented assignments and C loses the braces, I'll be fine. :) > > Would like a comment that this is 2**31 (which makes the code obvious > instead of mysterious). A comment block at the top would help too, like ... snip ... You'll see that comment show up in the patch. Thanks. > And this code has gotten messy enough that it's probably better to pkg it in > a utility function rather than duplicate it. Okay, I have made a try at that, too. > > Another approach would be to play with the bits directly, via casting > tricks. But then you have to wrestle with platform crap like endianness. No thanks. If this works then I am content. > > > hipart = (long)fractpart; > > fractpart = (fractpart - (double)hipart) * 2147483648.0; > > > > x = hipart + (long)fractpart + (expo << 15); /* combine > > the fract parts */ > > > > intpart = frexp(intpart, &expo); > > intpart = intpart * 2147483648.0; > > hipart = (long)intpart; > > intpart = (intpart - (double)hipart) * 2147483648.0; > > > > x += hipart + (long)intpart + (expo << 15); /* add in the > > int parts */ > > There's no point adding in (expo << 15) a second time. The second 'expo' is a different value (one from fractpart, one from intpart). Anyway this may be moot, see my patch below. > > > Overflow can be avoided by using xor instead of addition, but addition is > generally preferred because it helps to "scramble" the bits a little more. Most of the existing hashing algorithms use XORing rather than addition. I did not bother changing them for fear of ignorantly changing algorithms with one rule of thumb. [Guido] > In the mean time, I'd like to emphasize the key invariant here: we > must ensure that (a==b) => (hash(a)==hash(b)). One quick way to deal > Thanks for expressing it. The proper expression of the guarantees to which Python subscribes help me a lot. I have added a test (test_hash.py) which tests some cases of this (e.g. hash(4.5) == hash(complex(4.5)), etc.). Discussion of patch: Correct (presumably) and cleanup certain hash functions (float, complex, object, class, func, method, winreg). Two new hash helper function (_Py_HashDouble() and _Py_HashPointer()) were added to group common hash function code (this helps maintain the hash function invariant: (a==b) => (hash(a)==hash(b))). Tim, a question: Before, the float_hash algorithm that we were discussing did the frexp-and-32-bits-at-a-time reduction magic to the fractpart of the float and then you identified that the same needed to be done to the intpart. Instead of doing this twice, I just applied the reduction to whole double (fractpart+intpart). I don't see any error in doing that. Do you? As well, is there some hashing benefit that is lost by my doing the reduction only once? Note to a reviewer: Please check my refcount usage in _Py_HashPointer. I am a newbie there. _Py_HashPointer just casts to a long (as before) if it fits and goes through a long if it does not (i.e. on Win64 where sizeof(long) < sizeof(void*)). The function is applied where previously a pointer was cast to a long. test_hash.py is added (see attached) to test some cases for the mentioned invariant. 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/Include/object.h ./Include/object.h *** /home/trentm/main/contrib/python/dist/src/Include/object.h Mon Apr 24 08:40:45 2000 --- ./Include/object.h Thu May 11 20:19:53 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. */ diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/object.c ./Objects/object.c *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Wed May 3 16:44:35 2000 --- ./Objects/object.c Thu May 11 20:30:57 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(p); + + 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; diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c ./Objects/floatobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Wed May 3 16:44:34 2000 --- ./Objects/floatobject.c Thu May 11 20:27:05 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; diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c ./Objects/complexobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c Wed May 3 16:44:34 2000 --- ./Objects/complexobject.c Thu May 11 20:48:26 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) diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/classobject.c ./Objects/classobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Wed May 3 16:44:34 2000 --- ./Objects/classobject.c Thu May 11 20:31:51 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; *************** *** 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 = { diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c ./Objects/funcobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c Wed May 3 16:44:35 2000 --- ./Objects/funcobject.c Thu May 11 20:28:45 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; } diff -c3 /home/trentm/main/contrib/python/dist/src/PC/winreg.c ./PC/winreg.c *** /home/trentm/main/contrib/python/dist/src/PC/winreg.c Wed May 3 16:44:37 2000 --- ./PC/winreg.c Thu May 11 20:31:22 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); } And test_hash.py and test_hash are attached. -- Trent Mick trentm@activestate.com --T4sUOijqQbZv57TR Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="test_hash.py" # 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)) --T4sUOijqQbZv57TR Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=test_hash test_hash --T4sUOijqQbZv57TR-- From mal@lemburg.com Fri May 12 09:19:47 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 12 May 2000 10:19:47 +0200 Subject: [Patches] Unicode Character Name codec support References: <4D0A23B3F74DD111ACCD00805F31D8101D8BD095@RED-MSG-50> Message-ID: <391BBEA3.F61CEDC9@lemburg.com> Bill Tutt wrote: > > This is all based on AMK's perfect_hash work and MAL's unicode-escape > decoding, so hopefully a wet signature isn't necessary. > > This unicode-named codec also handles normal unicode-escapes since codecs > are not easily and usefully stackable, and not stacking them is more > effecient in any event. > > An altertnative to this approach would be to stick the data in one .c file, > and move PyUnicode_DecodeNamedUnicodeEscape into the unicode-escape code. > > Just as an informational matter, the hash table is 1.79 times bigger than > the # of unicode characters that have names. > > Attached in the zip file are the requisite changes: > > Files: > patch.txt: > Contains changes to the existing files in CVS for the following things: > Adds _ucn.c into the build gunk > Trivial patch to pcbuild.dsw not included on purpose since my Visual Studio > was making more changes than made me comfortable. > > New files: > _ucn.c: Already generated file, should just drop into Modules\ > _ucn.dsp: MSVC project file, drop into PCBuild, and insert into pcbuild.dsw, > and create a dependancy on python16. > test_ucn.py: Drop in Lib\test > unicode_named.py: Codec file, should be dropped into Lib\encodings > > The following files are provided for informational purposes and as a > mechanism to explain how this was generated: > Suggestions of how or if this should be included in Python's build process > are greatly appreciated. > > perfect_hash.py: A tweaked copy of AMK's perfect_hash.py that sucks in > UnicodeData.txt and generates _ucn.c. > perfhash.c: A helper module for perfect_hash.py. This just lets the > generated C code be more effecient than AMK's original code. > UnicodeData.txt: Input file for perfect_hash.py > > Usage of perfect_hash.py: > perfect_hash.py UnicodeData.txt > _ucn.c Great work, Bill :-) Some questions: I'm not sure about the copyright restrictions on the UnicodeData.txt file -- I think it's better to leave it out of the Python distribution (I noticed you didn't mention it under "New files", so perhaps you've already considered this). The perfect_hash tools sure look interesting, BTW. Wouldn't they be a good candidate for the Tools/ subdir ? I guess they would have to be tweaked a little to allow using them without having to modify the internals like you did. The Asian codecs could probably make some good use of these utilities too. Would the perfhash.c module be usable for all hash modules generated by perfect_hash.py ? The tables generated by perfect_hash.py could be too large for some compilers (also it would probably be a good idea providing the array size -- another source of compiler warnings). The unicodedatabase module had the same problem and I solved it by breaking the tables into pages which are accessed through a small utility function (see Modules/unicodedata*.c). -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From billtut@microsoft.com Fri May 12 10:05:12 2000 From: billtut@microsoft.com (Bill Tutt) Date: Fri, 12 May 2000 02:05:12 -0700 Subject: [Patches] Unicode Character Name codec support Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD099@RED-MSG-50> > From: M.-A. Lemburg [mailto:mal@lemburg.com] > > > Bill Tutt wrote: > > > > This is all based on AMK's perfect_hash work and MAL's > unicode-escape > > decoding, so hopefully a wet signature isn't necessary. > > > > This unicode-named codec also handles normal > unicode-escapes since codecs > > are not easily and usefully stackable, and not stacking them is more > > effecient in any event. > > > > An altertnative to this approach would be to stick the data > in one .c file, > > and move PyUnicode_DecodeNamedUnicodeEscape into the > unicode-escape code. > > > > Just as an informational matter, the hash table is 1.79 > times bigger than > > the # of unicode characters that have names. > > > > Attached in the zip file are the requisite changes: > > > > Files: > > patch.txt: > > Contains changes to the existing files in CVS for the > following things: > > Adds _ucn.c into the build gunk > > Trivial patch to pcbuild.dsw not included on purpose since > my Visual Studio > > was making more changes than made me comfortable. > > > > New files: > > _ucn.c: Already generated file, should just drop into Modules\ > > _ucn.dsp: MSVC project file, drop into PCBuild, and insert > into pcbuild.dsw, > > and create a dependancy on python16. > > test_ucn.py: Drop in Lib\test > > unicode_named.py: Codec file, should be dropped into Lib\encodings > > > > The following files are provided for informational purposes and as a > > mechanism to explain how this was generated: > > Suggestions of how or if this should be included in > Python's build process > > are greatly appreciated. > > > > perfect_hash.py: A tweaked copy of AMK's perfect_hash.py > that sucks in > > UnicodeData.txt and generates _ucn.c. > > perfhash.c: A helper module for perfect_hash.py. This > just lets the > > generated C code be more effecient than AMK's original code. > > UnicodeData.txt: Input file for perfect_hash.py > > > > Usage of perfect_hash.py: > > perfect_hash.py UnicodeData.txt > _ucn.c > > Great work, Bill :-) > > Some questions: > > I'm not sure about the copyright restrictions on > the UnicodeData.txt file -- I think it's better to leave > it out of the Python distribution (I noticed you didn't > mention it under "New files", so perhaps you've already > considered this). > I don't know off the top of my head either. Anything not listed under New Files isn't strictly necessary for the code to work, it was just used in generating _ucn.c. > The perfect_hash tools sure look interesting, BTW. Wouldn't > they be a good candidate for the Tools/ subdir ? Probably, atm perfect_hash.py is only useful with UnicodeData.txt as its input. That was just done to simplify my work and get _ucn.c working. :) The oddest thing about perfect_hash.py's UnicodeData only way of thinking is that Unicode Character Names are case insensitive, as the definition of f1, and f2 will attest. I was simply amazed at how fast perfect_hash.py combined with Python's string hashing function converged on a perfect hash table. (It did take a nice long while running perfect_hash until I found the magic random number seed that allowed a 1.79 multiple instead of a 1.9 multiple :) ) > I guess they would have to be tweaked a little to allow using > them without having to modify the internals like you did. The > Asian codecs could probably make some good use of these > utilities too. > Yes, I'm sure it would. Feel free to take what I did with perfect_hash.py and run with it. :) > Would the perfhash.c module be usable for all hash modules > generated by perfect_hash.py ? > Yes. perfhash.c's sole purpose in life is to calculate x's initial value in f1 and f2. Its applicable to any incoming dataset. > The tables generated by perfect_hash.py could be too > large for some compilers (also it would probably be > a good idea providing the array size -- another source > of compiler warnings). The unicodedatabase module > had the same problem and I solved it by breaking the > tables into pages which are accessed through a small > utility function (see Modules/unicodedata*.c). > Quite possibly, although IIRC the arrays that _ucn.c has are quite smaller than the unicodedatabase module has and so I'm relunctant to do that until someone actually complains. For the generic version of perfect_hash.py you were referring to it'd be preferrable to know what the acceptable sizes of the arrays actually are. I put the code at the beginning of _ucn.c so that MSVC would find the code at line #s < 64k so that it would generate debugging information for the code. (MSVC stops emitting debug info after line 65,536. :( ) Any thoughts on replacing the unicode-escape stuff with this? Bill From mal@lemburg.com Fri May 12 11:49:39 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 12 May 2000 12:49:39 +0200 Subject: [Patches] Unicode Character Name codec support References: <4D0A23B3F74DD111ACCD00805F31D8101D8BD099@RED-MSG-50> Message-ID: <391BE1C3.1612442F@lemburg.com> Bill Tutt wrote: > > > I'm not sure about the copyright restrictions on > > the UnicodeData.txt file -- I think it's better to leave > > it out of the Python distribution (I noticed you didn't > > mention it under "New files", so perhaps you've already > > considered this). > > > > I don't know off the top of my head either. Anything not listed under New > Files isn't strictly necessary for the code to work, it was just used in > generating _ucn.c. Ok. Perhaps putting a URL to the file into _ucn.c or the generator script would do. > > The perfect_hash tools sure look interesting, BTW. Wouldn't > > they be a good candidate for the Tools/ subdir ? > > Probably, atm perfect_hash.py is only useful with UnicodeData.txt as its > input. > That was just done to simplify my work and get _ucn.c working. :) > The oddest thing about perfect_hash.py's UnicodeData only way of thinking is > that Unicode Character Names are case insensitive, as the definition of f1, > and f2 will attest. > > I was simply amazed at how fast perfect_hash.py combined with Python's > string hashing function converged on a perfect hash table. (It did take a > nice long while running perfect_hash until I found the magic random number > seed that allowed a 1.79 multiple instead of a 1.9 multiple :) ) Looks like the algorithm used does a good job :-) > > I guess they would have to be tweaked a little to allow using > > them without having to modify the internals like you did. The > > Asian codecs could probably make some good use of these > > utilities too. > > > > Yes, I'm sure it would. Feel free to take what I did with perfect_hash.py > and run with it. :) > > > Would the perfhash.c module be usable for all hash modules > > generated by perfect_hash.py ? > > > > Yes. perfhash.c's sole purpose in life is to calculate x's initial value in > f1 and f2. Its applicable to any incoming dataset. So those two modules would make a great tool set... I wish I had more time to look into these. > > The tables generated by perfect_hash.py could be too > > large for some compilers (also it would probably be > > a good idea providing the array size -- another source > > of compiler warnings). The unicodedatabase module > > had the same problem and I solved it by breaking the > > tables into pages which are accessed through a small > > utility function (see Modules/unicodedata*.c). > > > > Quite possibly, although IIRC the arrays that _ucn.c has are quite smaller > than the unicodedatabase module has and so I'm relunctant to do that until > someone actually complains. For the generic version of perfect_hash.py you > were referring to it'd be preferrable to know what the acceptable sizes of > the arrays actually are. Ok. I did it the same way ;-) > I put the code at the beginning of _ucn.c so that MSVC would find the code > at line #s < 64k so that it would generate debugging information for the > code. > (MSVC stops emitting debug info after line 65,536. :( ) > > Any thoughts on replacing the unicode-escape stuff with this? I'd rather not: unicode-escape is needed by the compiler and that would mean having link the hash table to the interpreter. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From billtut@microsoft.com Fri May 12 12:26:09 2000 From: billtut@microsoft.com (Bill Tutt) Date: Fri, 12 May 2000 04:26:09 -0700 Subject: [Patches] Unicode Character Name codec support Message-ID: <4D0A23B3F74DD111ACCD00805F31D8101D8BD09A@RED-MSG-50> > From: M.-A. Lemburg [mailto:mal@lemburg.com] > > Bill Tutt wrote: > > > > > I'm not sure about the copyright restrictions on > > > the UnicodeData.txt file -- I think it's better to leave > > > it out of the Python distribution (I noticed you didn't > > > mention it under "New files", so perhaps you've already > > > considered this). > > > > > > > I don't know off the top of my head either. Anything not > listed under New > > Files isn't strictly necessary for the code to work, it was > just used in > > generating _ucn.c. > > Ok. Perhaps putting a URL to the file into _ucn.c or the > generator script would do. > Sounds like a plan to me. I'd kind of like to get feedback from other folks on where exactly in the tree perfect_hash.py & perfhash.c would reside that way I can make all of the chances to the docs at the beginning of _ucn.c at once. > > I was simply amazed at how fast perfect_hash.py combined > with Python's > > string hashing function converged on a perfect hash table. > (It did take a > > nice long while running perfect_hash until I found the > magic random number > > seed that allowed a 1.79 multiple instead of a 1.9 multiple :) ) > > Looks like the algorithm used does a good job :-) > Nah, the algorithm just got lucky. Python's string hash function just doesn't produce a lot of collisions for this data. If the hash function wasn't so cool, the algorithm might have stopped at some much larger multiple factor. :) > > Any thoughts on replacing the unicode-escape stuff with this? > > I'd rather not: unicode-escape is needed by the compiler > and that would mean having link the hash table to the > interpreter. > Well, I mentioned it since I think Perl's built in Unicode stuff supports it, and you won't have a working set hit if you never use the feature. It would also be possible to dynamically link to the hash table data by using shared library stuff, and only doing so when someone actually passes in a \N{LATIN SMALL LETTER H}. Bill From mal@lemburg.com Fri May 12 14:06:01 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Fri, 12 May 2000 15:06:01 +0200 Subject: [Patches] Unicode Character Name codec support References: <4D0A23B3F74DD111ACCD00805F31D8101D8BD09A@RED-MSG-50> Message-ID: <391C01B9.E7903036@lemburg.com> Bill Tutt wrote: > > > > Any thoughts on replacing the unicode-escape stuff with this? > > > > I'd rather not: unicode-escape is needed by the compiler > > and that would mean having link the hash table to the > > interpreter. > > > > Well, I mentioned it since I think Perl's built in Unicode stuff supports > it, and you won't have a working set hit if you never use the feature. Ok, but it's really just one call away :-) ... s = unicode('\N{LATIN SMALL H}', 'unicode-named') > It would also be possible to dynamically link to the hash table data by > using shared library stuff, and only doing so when someone actually passes > in a \N{LATIN SMALL LETTER H}. Hmm, you could probably extend the builtin unicode-escape codec to import the needed tables on-demand (and via the standard Python import APIs) when the codec sees a \N escape. A bit tricky to do in C, but certainly possible. -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From tim_one@email.msn.com Fri May 12 16:11:24 2000 From: tim_one@email.msn.com (Tim Peters) Date: Fri, 12 May 2000 11:11:24 -0400 Subject: [Patches] introducing math.rint In-Reply-To: <200005111829.OAA02880@eric.cnri.reston.va.us> Message-ID: [Guido van Rossum] > I've checked this in, but I have one nagging doubt: it's not a > standard ANSI C function, so may not exist on all platforms? Legitimate concern -- rint is one of many functions recommended by the IEEE-754 std that aren't in ISO/ANSI C. Most platforms support all of those one way or another now, but usually via platform-specific spellings. This won't improve until C9X is adopted. IIRC (& I have no way to check this right now), rint is not supported under EPOC32 (the Symbian/Psion OS that Duncan Booth did a port for). To be safe, afraid this really needs conditional config support. From guido@python.org Fri May 12 16:18:28 2000 From: guido@python.org (Guido van Rossum) Date: Fri, 12 May 2000 11:18:28 -0400 Subject: [Patches] introducing math.rint In-Reply-To: Your message of "Fri, 12 May 2000 11:11:24 EDT." References: Message-ID: <200005121518.LAA07320@eric.cnri.reston.va.us> > [Guido van Rossum] > > I've checked this in, but I have one nagging doubt: it's not a > > standard ANSI C function, so may not exist on all platforms? [Tim] > Legitimate concern -- rint is one of many functions recommended by the > IEEE-754 std that aren't in ISO/ANSI C. Most platforms support all of those > one way or another now, but usually via platform-specific spellings. This > won't improve until C9X is adopted. IIRC (& I have no way to check this > right now), rint is not supported under EPOC32 (the Symbian/Psion OS that > Duncan Booth did a port for). To be safe, afraid this really needs > conditional config support. Not to worry, I've already added the necessary magic to the configure script. (PS Tim, did you get a chance to look at the second installment of the cmarh.acosh/asinh patches?) --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Fri May 12 18:48:56 2000 From: guido@python.org (Guido van Rossum) Date: Fri, 12 May 2000 13:48:56 -0400 Subject: [Patches] marshalling recursive objects In-Reply-To: Your message of "Fri, 12 May 2000 03:19:58 +0200." <200005120119.DAA16649@python.inrialpes.fr> References: <200005120119.DAA16649@python.inrialpes.fr> Message-ID: <200005121748.NAA07903@eric.cnri.reston.va.us> > I saw recently in c.l.py a discussion about recursive objects. It was > noted that recursive comparisons were fixed, but marshalling recursive > objects still core dumps. > > >>> l = [] > >>> l.append(l) > >>> marshal.dumps(l) > Paf! > > The following patch aims at fixing this. The approach is the same as the > one used in pickle (I believe). Container objects are kept in an internal > list. When serializing, on recursion branches, the list index of the container > is stored in the byte stream, instead of its contents. This index should > be the same when deserializing, because of the strict object ordering. > Recursions are thus restored, and we have the invariant: > > o == marshal.loads(marshal.dumps(o)) > > even when o involves cyclic references. Vladimir, Thanks for this patch. However, I'm worried that it does too much! I'd be happy if marshalling a recursive data structure just raised an exception. I'm happy enough to see a solution that's better, but I'm not sure I like it to write different marshalling strings for data structures that aren't recursive. Here's an example: >>> a = [] >>> b = [a,a,a] >>> marshal.dumps(b) '[\003\000\000\000[\000\000\000\000o\001\000\000\000o\001\000\000\000' >>> Before your patch, this produced: '[\003\000\000\000[\000\000\000\000[\000\000\000\000[\000\000\000\000' Why do I care? Marshals may be used for data interchange between applications running on different machines and using different Python versions. I realize this is harder, and I understand that in some sense your solution is "better" -- but for the semantics that you are creating, we already have a better solution: pickle. The marshal module is about values, not objects. I'm not sure how to fix it -- if the easiest solution is to raise an exception for recursive objects, that's fine. (It's a heck of a lot better than Memory fault!) --Guido van Rossum (home page: http://www.python.org/~guido/) From mwh21@cam.ac.uk Fri May 12 19:16:49 2000 From: mwh21@cam.ac.uk (Michael Hudson) Date: Fri, 12 May 2000 19:16:49 +0100 (BST) Subject: [Patches] Augmented assignment 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. --8323328-30061660-958155409=:18681 Content-Type: TEXT/PLAIN; charset=US-ASCII After a resounding silence on comp.lang.python, I thought I'd try here. Actually this patch is somewhat updated from the one I mentioned there. I have implemented these operators += -= *= /= %= |= &= ^= <<= >>= **= to have basically the same semantics as C (well, C doesn't have **=, but you can guess what that does). I have taken the Common Lisp approach of evaluating things as little as possible; so in the expression e1[e2] += e3 each of e3, e1 and e2 are evaluated (in that order) once, though obviously the result of e1 has both BINARY_SUBSCR and STORE_SUBSCR done to it. The stack gymnastics required to pull this off look like an attempt to generate S_3 given a 3-cycle (ROT_THREE) and a 2-cycle (ROT_TWO), so the resulting code could be much simplified with a couple of well chosen stack manipulation opcodes. I have beaten up the tokenizer to accept 3 character tokens; no idea if what I did was right, but it works. I hope this is a "you-don't-pay-for-what-you-don't-use" patch. Comments, flames, etc welcome, but I'm not subscribed to patches, so I'd appreciate being Cc-ed on any responses. The patch is somewhat chunky because it's got the changes to Python/graminit.c in it. And, I don't expect the patch to go in in this form, but I'll say: 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. --8323328-30061660-958155409=:18681 Content-Type: TEXT/PLAIN; charset=US-ASCII; name="aug-patch2.diff" Content-Transfer-Encoding: BASE64 Content-ID: Content-Description: Content-Disposition: attachment; filename="aug-patch2.diff" ZGlmZiAtTnVyIC0tZXhjbHVkZT0qLnB5YyAtLWV4Y2x1ZGU9Kn4gc3JjLWNs ZWFuL0dyYW1tYXIvR3JhbW1hciBzcmMtYXVnL0dyYW1tYXIvR3JhbW1hcg0K LS0tIHNyYy1jbGVhbi9HcmFtbWFyL0dyYW1tYXIJVGh1IE1hciAzMCAxMDox NDozNSAyMDAwDQorKysgc3JjLWF1Zy9HcmFtbWFyL0dyYW1tYXIJRnJpIE1h eSAxMiAxODo0NToyMSAyMDAwDQpAQCAtMzEsNyArMzEsNyBAQA0KIHNpbXBs ZV9zdG10OiBzbWFsbF9zdG10ICgnOycgc21hbGxfc3RtdCkqIFsnOyddIE5F V0xJTkUNCiAjc21hbGxfc3RtdDogZXhwcl9zdG10IHwgcHJpbnRfc3RtdCAg fCBkZWxfc3RtdCB8IHBhc3Nfc3RtdCB8IGZsb3dfc3RtdCB8IGltcG9ydF9z dG10IHwgZ2xvYmFsX3N0bXQgfCBhY2Nlc3Nfc3RtdCB8IGV4ZWNfc3RtdA0K IHNtYWxsX3N0bXQ6IGV4cHJfc3RtdCB8IHByaW50X3N0bXQgIHwgZGVsX3N0 bXQgfCBwYXNzX3N0bXQgfCBmbG93X3N0bXQgfCBpbXBvcnRfc3RtdCB8IGds b2JhbF9zdG10IHwgZXhlY19zdG10IHwgYXNzZXJ0X3N0bXQNCi1leHByX3N0 bXQ6IHRlc3RsaXN0ICgnPScgdGVzdGxpc3QpKg0KK2V4cHJfc3RtdDogdGVz dGxpc3QgKCgnPSd8Jys9J3wnLT0nfCcqPSd8Jy89J3wnJT0nfCcmPSd8J3w9 J3wnXj0nfCc8PD0nfCc+Pj0nfCcqKj0nKSB0ZXN0bGlzdCkqDQogIyBGb3Ig YXNzaWdubWVudHMsIGFkZGl0aW9uYWwgcmVzdHJpY3Rpb25zIGVuZm9yY2Vk IGJ5IHRoZSBpbnRlcnByZXRlcg0KIHByaW50X3N0bXQ6ICdwcmludCcgKHRl c3QgJywnKSogW3Rlc3RdDQogZGVsX3N0bXQ6ICdkZWwnIGV4cHJsaXN0DQpk aWZmIC1OdXIgLS1leGNsdWRlPSoucHljIC0tZXhjbHVkZT0qfiBzcmMtY2xl YW4vSW5jbHVkZS90b2tlbi5oIHNyYy1hdWcvSW5jbHVkZS90b2tlbi5oDQot LS0gc3JjLWNsZWFuL0luY2x1ZGUvdG9rZW4uaAlGcmkgRGVjICA0IDE4OjQ4 OjIzIDE5OTgNCisrKyBzcmMtYXVnL0luY2x1ZGUvdG9rZW4uaAlGcmkgTWF5 IDEyIDE4OjQyOjA4IDIwMDANCkBAIC03NCwxMCArNzQsMjIgQEANCiAjZGVm aW5lIExFRlRTSElGVAkzNA0KICNkZWZpbmUgUklHSFRTSElGVAkzNQ0KICNk ZWZpbmUgRE9VQkxFU1RBUgkzNg0KKyNkZWZpbmUgUExVU0VRVUFMCTM3DQor I2RlZmluZSBNSU5VU0VRVUFMCTM4DQorI2RlZmluZSBTVEFSRVFVQUwJMzkN CisjZGVmaW5lIFNMQVNIRVFVQUwJNDANCisjZGVmaW5lIFBFUkNFTlRFUVVB TAk0MQ0KKyNkZWZpbmUgQU1QRVJFUVVBTAk0Mg0KKyNkZWZpbmUgVkJBUkVR VUFMCTQzDQorI2RlZmluZSBDQVJFVEVRVUFMCTQ0DQorI2RlZmluZSBMRUZU U0hJRlRFUVVBTAk0NQ0KKyNkZWZpbmUgUklHSFRTSElGVEVRVUFMCTQ2DQor I2RlZmluZSBTVEFSU1RBUkVRVUFMCTQ3DQorDQogLyogRG9uJ3QgZm9yZ2V0 IHRvIHVwZGF0ZSB0aGUgdGFibGUgX1B5UGFyc2VyX1Rva2VuTmFtZXMgaW4g dG9rZW5pemVyLmMhICovDQotI2RlZmluZSBPUAkJMzcNCi0jZGVmaW5lIEVS Uk9SVE9LRU4JMzgNCi0jZGVmaW5lIE5fVE9LRU5TCTM5DQorI2RlZmluZSBP UAkJNDgNCisjZGVmaW5lIEVSUk9SVE9LRU4JNDkNCisjZGVmaW5lIE5fVE9L RU5TCTUwDQogDQogLyogU3BlY2lhbCBkZWZpbml0aW9ucyBmb3IgY29vcGVy YXRpb24gd2l0aCBwYXJzZXIgKi8NCiANCmRpZmYgLU51ciAtLWV4Y2x1ZGU9 Ki5weWMgLS1leGNsdWRlPSp+IHNyYy1jbGVhbi9MaWIvdGVzdC9vdXRwdXQv dGVzdF9hdWdhc3NpZ24gc3JjLWF1Zy9MaWIvdGVzdC9vdXRwdXQvdGVzdF9h dWdhc3NpZ24NCi0tLSBzcmMtY2xlYW4vTGliL3Rlc3Qvb3V0cHV0L3Rlc3Rf YXVnYXNzaWduCVRodSBKYW4gIDEgMDE6MDA6MDAgMTk3MA0KKysrIHNyYy1h dWcvTGliL3Rlc3Qvb3V0cHV0L3Rlc3RfYXVnYXNzaWduCUZyaSBNYXkgMTIg MTg6MzI6MzUgMjAwMA0KQEAgLTAsMCArMSwxNCBAQA0KK3Rlc3RfYXVnYXNz aWduDQorcDogcmhzDQorZ2V0YXR0cjogYQ0KK2dldGF0dHI6IGINCitnZXRh dHRyOiBjDQorYWRkOiByaHMNCitzZXRhdHRyOiBjDQorDQorcDogcmhzDQor Z2V0YXR0cjogYQ0KK3A6IGluZGV4DQorZ2V0aXRlbTogaW5kZXgNCittdWw6 IHJocw0KK3NldGl0ZW06IGluZGV4DQpkaWZmIC1OdXIgLS1leGNsdWRlPSou cHljIC0tZXhjbHVkZT0qfiBzcmMtY2xlYW4vTGliL3Rlc3QvdGVzdF9hdWdh c3NpZ24ucHkgc3JjLWF1Zy9MaWIvdGVzdC90ZXN0X2F1Z2Fzc2lnbi5weQ0K LS0tIHNyYy1jbGVhbi9MaWIvdGVzdC90ZXN0X2F1Z2Fzc2lnbi5weQlUaHUg SmFuICAxIDAxOjAwOjAwIDE5NzANCisrKyBzcmMtYXVnL0xpYi90ZXN0L3Rl c3RfYXVnYXNzaWduLnB5CUZyaSBNYXkgMTIgMTg6NTg6NDAgMjAwMA0KQEAg LTAsMCArMSw1OSBAQA0KK2NsYXNzIFA6DQorICAgIGRlZiBfX2dldGF0dHJf XyhzZWxmLGF0dHIpOg0KKyAgICAgICAgaWYgYXR0clswXSA9PSAnXyc6DQor ICAgICAgICAgICAgcmFpc2UgQXR0cmlidXRlRXJyb3INCisgICAgICAgIHBy aW50ICJnZXRhdHRyOiIsIGF0dHINCisgICAgICAgIHJldHVybiBzZWxmDQor ICAgIGRlZiBfX3NldGF0dHJfXyhzZWxmLGF0dHIsdmFsdWUpOg0KKyAgICAg ICAgcHJpbnQgInNldGF0dHI6IiwgYXR0cg0KKyAgICBkZWYgX19nZXRpdGVt X18oc2VsZixpdGVtKToNCisgICAgICAgIHByaW50ICJnZXRpdGVtOiIsIGl0 ZW0NCisgICAgICAgIHJldHVybiBzZWxmDQorICAgIGRlZiBfX3NldGl0ZW1f XyhzZWxmLGl0ZW0sdmFsdWUpOg0KKyAgICAgICAgcHJpbnQgInNldGl0ZW06 IiwgaXRlbQ0KKyAgICBkZWYgX19hZGRfXyhzZWxmLHJocyk6DQorICAgICAg ICBwcmludCAiYWRkOiIsIHJocw0KKyAgICAgICAgcmV0dXJuIHNlbGYNCisg ICAgZGVmIF9fbXVsX18oc2VsZixyaHMpOg0KKyAgICAgICAgcHJpbnQgIm11 bDoiLCByaHMNCisgICAgICAgIHJldHVybiBzZWxmDQorDQorZGVmIHAoeCk6 DQorICAgIHByaW50ICJwOiIsIHgNCisgICAgcmV0dXJuIHgNCisNCitQKCku YS5iLmMgKz0gcCgicmhzIikNCitwcmludA0KK1AoKS5hW3AoImluZGV4Iild ICo9IHAoInJocyIpDQorDQorZGVmIHNob3VsZGZhaWwoeCk6DQorICAgIHRy eToNCisgICAgICAgIGNvbXBpbGUoeCwiIiwiZXhlYyIpDQorICAgICAgICBh c3NlcnQgInNob3VsZCBmYWlsICVzIiV4DQorICAgIGV4Y2VwdCBTeW50YXhF cnJvcjoNCisgICAgICAgIHBhc3MNCisNCitzaG91bGRmYWlsKCJ4LCs9MSIp DQorc2hvdWxkZmFpbCgiW3hdKz0xIikNCitzaG91bGRmYWlsKCIoeCwpKz0x IikNCitzaG91bGRmYWlsKCJ4Kz15Kz0yIikNCitzaG91bGRmYWlsKCJ4Wzpd Kz0yIikNCitzaG91bGRmYWlsKCJ4WzE6XSs9MiIpDQorc2hvdWxkZmFpbCgi eFs6Ml0rPTIiKQ0KK3Nob3VsZGZhaWwoInhbMToyXSs9MiIpDQorDQorYSA9 IDEwDQorYSAqPSAyDQorYXNzZXJ0IGE9PTIwDQorYSArPSAzDQorYXNzZXJ0 IGE9PTIzDQorYSAvPSAyDQorYXNzZXJ0IGE9PTExDQorYSAlPSAzDQorYXNz ZXJ0IGE9PTINCithIDw8PSA0DQorYXNzZXJ0IGE9PTMyDQorYSA+Pj0gMw0K K2Fzc2VydCBhPT00DQorYSAqKj0gMg0KK2Fzc2VydCBhPT0xNg0KZGlmZiAt TnVyIC0tZXhjbHVkZT0qLnB5YyAtLWV4Y2x1ZGU9Kn4gc3JjLWNsZWFuL1Bh cnNlci9ncmFtbWFyLmMgc3JjLWF1Zy9QYXJzZXIvZ3JhbW1hci5jDQotLS0g c3JjLWNsZWFuL1BhcnNlci9ncmFtbWFyLmMJRnJpIEFwciAxMCAyMzowOToz NiAxOTk4DQorKysgc3JjLWF1Zy9QYXJzZXIvZ3JhbW1hci5jCUZyaSBNYXkg MTIgMTg6NDk6NDYgMjAwMA0KQEAgLTI0OCw2ICsyNDgsMTggQEANCiAJCQkJ cHJpbnRmKCJVbmtub3duIE9QIGxhYmVsICVzXG4iLA0KIAkJCQkJbGItPmxi X3N0cik7DQogCQl9DQorCQllbHNlIGlmIChsYi0+bGJfc3RyWzJdICYmIGxi LT5sYl9zdHJbM10gJiYgbGItPmxiX3N0cls0XSA9PSBsYi0+bGJfc3RyWzBd KSB7DQorCQkJaW50IHR5cGUgPSAoaW50KSBQeVRva2VuX1RocmVlQ2hhcnMo bGItPmxiX3N0clsxXSwNCisJCQkJCQkJICAgIGxiLT5sYl9zdHJbMl0sDQor CQkJCQkJCSAgICBsYi0+bGJfc3RyWzNdKTsNCisJCQlpZiAodHlwZSAhPSBP UCkgew0KKwkJCQlsYi0+bGJfdHlwZSA9IHR5cGU7DQorCQkJCWxiLT5sYl9z dHIgPSBOVUxMOw0KKwkJCX0NCisJCQllbHNlDQorCQkJCXByaW50ZigiVW5r bm93biBPUCBsYWJlbCAlc1xuIiwNCisJCQkJCWxiLT5sYl9zdHIpOw0KKwkJ fQ0KIAkJZWxzZQ0KIAkJCXByaW50ZigiQ2FuJ3QgdHJhbnNsYXRlIFNUUklO RyBsYWJlbCAlc1xuIiwNCiAJCQkJbGItPmxiX3N0cik7DQpAQCAtMjU2LDMg KzI2OCw0IEBADQogCQlwcmludGYoIkNhbid0IHRyYW5zbGF0ZSBsYWJlbCAn JXMnXG4iLA0KIAkJICAgICAgIFB5R3JhbW1hcl9MYWJlbFJlcHIobGIpKTsN CiB9DQorDQpkaWZmIC1OdXIgLS1leGNsdWRlPSoucHljIC0tZXhjbHVkZT0q fiBzcmMtY2xlYW4vUGFyc2VyL3Rva2VuaXplci5jIHNyYy1hdWcvUGFyc2Vy L3Rva2VuaXplci5jDQotLS0gc3JjLWNsZWFuL1BhcnNlci90b2tlbml6ZXIu YwlUaHUgTWF5IDExIDIxOjQ4OjU3IDIwMDANCisrKyBzcmMtYXVnL1BhcnNl ci90b2tlbml6ZXIuYwlGcmkgTWF5IDEyIDE4OjQ2OjQ3IDIwMDANCkBAIC05 OSw2ICs5OSwxNyBAQA0KIAkiTEVGVFNISUZUIiwNCiAJIlJJR0hUU0hJRlQi LA0KIAkiRE9VQkxFU1RBUiIsDQorCSJQTFVTRVFVQUwiLA0KKwkiTUlOVVNF UVVBTCIsDQorCSJTVEFSRVFVQUwiLA0KKwkiU0xBU0hFUVVBTCIsDQorCSJQ RVJDRU5URVFVQUwiLA0KKwkiQU1QRVJFUVVBTCIsDQorCSJWQkFSRVFVQUwi LA0KKwkiQ0FSRVRFUVVBTCIsDQorCSJMRUZUU0hJRlRFUVVBTCIsDQorCSJS SUdIVFNISUZURVFVQUwiLA0KKwkiU1RBUlNUQVJFUVVBTCIsDQogCS8qIFRo aXMgdGFibGUgbXVzdCBtYXRjaCB0aGUgI2RlZmluZXMgaW4gdG9rZW4uaCEg Ki8NCiAJIk9QIiwNCiAJIjxFUlJPUlRPS0VOPiIsDQpAQCAtNDE4LDE1ICs0 MjksOTIgQEANCiAJCWNhc2UgJz4nOglyZXR1cm4gUklHSFRTSElGVDsNCiAJ CX0NCiAJCWJyZWFrOw0KKwljYXNlICcrJzoNCisJCXN3aXRjaCAoYzIpIHsN CisJCWNhc2UgJz0nOglyZXR1cm4gUExVU0VRVUFMOw0KKwkJfQ0KKwkJYnJl YWs7DQorCWNhc2UgJy0nOg0KKwkJc3dpdGNoIChjMikgew0KKwkJY2FzZSAn PSc6CXJldHVybiBNSU5VU0VRVUFMOw0KKwkJfQ0KKwkJYnJlYWs7DQogCWNh c2UgJyonOg0KIAkJc3dpdGNoIChjMikgew0KIAkJY2FzZSAnKic6CXJldHVy biBET1VCTEVTVEFSOw0KKwkJY2FzZSAnPSc6CXJldHVybiBTVEFSRVFVQUw7 DQorCQl9DQorCQlicmVhazsNCisJY2FzZSAnLyc6DQorCQlzd2l0Y2ggKGMy KSB7DQorCQljYXNlICc9JzoJcmV0dXJuIFNMQVNIRVFVQUw7DQorCQl9DQor CQlicmVhazsNCisJY2FzZSAnfCc6DQorCQlzd2l0Y2ggKGMyKSB7DQorCQlj YXNlICc9JzoJcmV0dXJuIFZCQVJFUVVBTDsNCisJCX0NCisJCWJyZWFrOw0K KwljYXNlICclJzoNCisJCXN3aXRjaCAoYzIpIHsNCisJCWNhc2UgJz0nOgly ZXR1cm4gUEVSQ0VOVEVRVUFMOw0KKwkJfQ0KKwkJYnJlYWs7DQorCWNhc2Ug JyYnOg0KKwkJc3dpdGNoIChjMikgew0KKwkJY2FzZSAnPSc6CXJldHVybiBB TVBFUkVRVUFMOw0KKwkJfQ0KKwkJYnJlYWs7DQorCWNhc2UgJ14nOg0KKwkJ c3dpdGNoIChjMikgew0KKwkJY2FzZSAnPSc6CXJldHVybiBDQVJFVEVRVUFM Ow0KIAkJfQ0KIAkJYnJlYWs7DQogCX0NCiAJcmV0dXJuIE9QOw0KIH0NCiAN CitpbnQNCitQeVRva2VuX1RocmVlQ2hhcnMoYzEsIGMyLCBjMykNCisJaW50 IGMxLCBjMiwgYzM7DQorew0KKwlzd2l0Y2ggKGMxKSB7DQorCWNhc2UgJzwn Og0KKwkJc3dpdGNoIChjMikgew0KKwkJY2FzZSAnPCc6DQorCQkJc3dpdGNo IChjMykgew0KKwkJCWNhc2UgJz0nOg0KKwkJCQlyZXR1cm4gTEVGVFNISUZU RVFVQUw7DQorCQkJCWJyZWFrOw0KKwkJCX0NCisJCQlicmVhazsNCisJCX0N CisJCWJyZWFrOw0KKwljYXNlICc+JzoNCisJCXN3aXRjaCAoYzIpIHsNCisJ CWNhc2UgJz4nOg0KKwkJCXN3aXRjaCAoYzMpIHsNCisJCQljYXNlICc9JzoN CisJCQkJcmV0dXJuIFJJR0hUU0hJRlRFUVVBTDsNCisJCQkJYnJlYWs7DQor CQkJfQ0KKwkJCWJyZWFrOw0KKwkJfQ0KKwkJYnJlYWs7DQorCWNhc2UgJyon Og0KKwkJc3dpdGNoIChjMikgew0KKwkJY2FzZSAnKic6DQorCQkJc3dpdGNo IChjMykgew0KKwkJCWNhc2UgJz0nOg0KKwkJCQlyZXR1cm4gU1RBUlNUQVJF UVVBTDsNCisJCQkJYnJlYWs7DQorCQkJfQ0KKwkJCWJyZWFrOw0KKwkJfQ0K KwkJYnJlYWs7DQorCX0NCisJcmV0dXJuIE9QOw0KK30NCiANCiBzdGF0aWMg aW50DQogaW5kZW50ZXJyb3IodG9rKQ0KQEAgLTgwNiw2ICs4OTQsMTMgQEAN CiAJCWludCBjMiA9IHRva19uZXh0Yyh0b2spOw0KIAkJaW50IHRva2VuID0g UHlUb2tlbl9Ud29DaGFycyhjLCBjMik7DQogCQlpZiAodG9rZW4gIT0gT1Ap IHsNCisJCQlpbnQgYzMgPSB0b2tfbmV4dGModG9rKTsNCisJCQlpbnQgdG9r ZW4zID0gUHlUb2tlbl9UaHJlZUNoYXJzKGMsIGMyLCBjMyk7DQorCQkJaWYg KHRva2VuMyAhPSBPUCkgew0KKwkJCQl0b2tlbiA9IHRva2VuMzsNCisJCQl9 IGVsc2Ugew0KKwkJCQl0b2tfYmFja3VwKHRvaywgYzMpOw0KKwkJCX0NCiAJ CQkqcF9zdGFydCA9IHRvay0+c3RhcnQ7DQogCQkJKnBfZW5kID0gdG9rLT5j dXI7DQogCQkJcmV0dXJuIHRva2VuOw0KZGlmZiAtTnVyIC0tZXhjbHVkZT0q LnB5YyAtLWV4Y2x1ZGU9Kn4gc3JjLWNsZWFuL1B5dGhvbi9jb21waWxlLmMg c3JjLWF1Zy9QeXRob24vY29tcGlsZS5jDQotLS0gc3JjLWNsZWFuL1B5dGhv bi9jb21waWxlLmMJVGh1IE1heSAxMSAyMTo0OTowMiAyMDAwDQorKysgc3Jj LWF1Zy9QeXRob24vY29tcGlsZS5jCUZyaSBNYXkgMTIgMTg6NTU6MTggMjAw MA0KQEAgLTc0LDcgKzc0LDYgQEANCiAjZGVmaW5lIE9QX0RFTEVURSAwDQog I2RlZmluZSBPUF9BU1NJR04gMQ0KICNkZWZpbmUgT1BfQVBQTFkgMg0KLQ0K ICNkZWZpbmUgT0ZGKHgpIG9mZnNldG9mKFB5Q29kZU9iamVjdCwgeCkNCiAN CiBzdGF0aWMgc3RydWN0IG1lbWJlcmxpc3QgY29kZV9tZW1iZXJsaXN0W10g PSB7DQpAQCAtNTAxLDEwICs1MDAsMTAgQEANCiAJaW50IG47DQogew0KIAlp ZiAoYy0+Y19zdGFja2xldmVsIDwgbikgew0KLQkJLyogZnByaW50ZihzdGRl cnIsDQorCQlmcHJpbnRmKHN0ZGVyciwNCiAJCQkiJXM6JWQ6IHVuZGVyZmxv dyEgbmV4dGk9JWQsIGxldmVsPSVkLCBuPSVkXG4iLA0KIAkJCWMtPmNfZmls ZW5hbWUsIGMtPmNfbGluZW5vLA0KLQkJCWMtPmNfbmV4dGksIGMtPmNfc3Rh Y2tsZXZlbCwgbik7ICovDQorCQkJYy0+Y19uZXh0aSwgYy0+Y19zdGFja2xl dmVsLCBuKTsNCiAJCWMtPmNfc3RhY2tsZXZlbCA9IDA7DQogCX0NCiAJZWxz ZQ0KQEAgLTEzNTksMTUgKzEzNTgsMjUgQEANCiAJCW5vZGUgKnN1YiA9IENI SUxEKG4sIDApOyAvKiBzdWJzY3JpcHQgKi8NCiAJCS8qIE1ha2UgaXQgaXMg YSBzaW1wbGUgc2xpY2UuDQogCQkgICBTaG91bGQgaGF2ZSBleGFjdGx5IG9u ZSBjb2xvbi4gKi8NCi0gICAgICAgIGlmICgoVFlQRShDSElMRChzdWIsIDAp KSA9PSBDT0xPTg0KLSAgICAgICAgICAgICB8fCAoTkNIKHN1YikgPiAxICYm IFRZUEUoQ0hJTEQoc3ViLCAxKSkgPT0gQ09MT04pKQ0KLSAgICAgICAgICAg ICYmIChUWVBFKENISUxEKHN1YixOQ0goc3ViKS0xKSkgIT0gc2xpY2VvcCkp DQotCXsNCi0JCQlpZiAoYXNzaWduaW5nID09IE9QX0FQUExZKQ0KKwkJaWYg KChUWVBFKENISUxEKHN1YiwgMCkpID09IENPTE9ODQorCQkgICAgIHx8IChO Q0goc3ViKSA+IDEgJiYgVFlQRShDSElMRChzdWIsIDEpKSA9PSBDT0xPTikp DQorCQkgICAgJiYgKFRZUEUoQ0hJTEQoc3ViLE5DSChzdWIpLTEpKSAhPSBz bGljZW9wKSkNCisJCXsNCisJCQlzd2l0Y2ggKGFzc2lnbmluZykgew0KKwkJ CWNhc2UgT1BfREVMRVRFOg0KKwkJCQlvcCA9IERFTEVURV9TTElDRTsNCisJ CQkJYnJlYWs7DQorCQkJY2FzZSBPUF9BUFBMWToNCiAJCQkJb3AgPSBTTElD RTsNCi0JCQllbHNlDQotCQkJCW9wID0gKChhc3NpZ25pbmcgPT0gT1BfQVNT SUdOKSA/DQotCQkJCSAgICAgIFNUT1JFX1NMSUNFIDogREVMRVRFX1NMSUNF KTsNCisJCQkJYnJlYWs7DQorCQkJY2FzZSBPUF9BU1NJR046DQorCQkJCW9w ID0gU1RPUkVfU0xJQ0U7DQorCQkJCWJyZWFrOw0KKwkJCWRlZmF1bHQ6DQor CQkJCWNvbV9lcnJvcihjLCBQeUV4Y19TeW50YXhFcnJvciwNCisJCQkJCSAg ImNhbid0IGRvIGF1Z21lbnRlZCBhc3NpZ25tZW50IHRvIHNsaWNlcyAoeWV0 ISkiKTsNCisJCQkJcmV0dXJuOw0KKwkJCX0NCiAJCQljb21fc2xpY2UoYywg c3ViLCBvcCk7DQogCQkJaWYgKG9wID09IFNUT1JFX1NMSUNFKQ0KIAkJCQlj b21fcG9wKGMsIDIpOw0KQEAgLTEzNzYsMjkgKzEzODUsNjAgQEANCiAJCQly ZXR1cm47DQogCQl9DQogCX0NCi0JLyogRWxzZSBub3JtYWwgc3Vic2NyaXB0 bGlzdC4gIENvbXBpbGUgZWFjaCBzdWJzY3JpcHQuICovDQotCWZvciAoaSA9 IDA7IGkgPCBOQ0gobik7IGkgKz0gMikNCi0JCWNvbV9zdWJzY3JpcHQoYywg Q0hJTEQobiwgaSkpOw0KLQkvKiBQdXQgbXVsdGlwbGUgc3Vic2NyaXB0cyBp bnRvIGEgdHVwbGUgKi8NCi0JaWYgKE5DSChuKSA+IDEpIHsNCi0JCWkgPSAo TkNIKG4pKzEpIC8gMjsNCi0JCWNvbV9hZGRvcGFyZyhjLCBCVUlMRF9UVVBM RSwgaSk7DQotCQljb21fcG9wKGMsIGktMSk7DQotCX0NCi0JaWYgKGFzc2ln bmluZyA9PSBPUF9BUFBMWSkgew0KLQkJb3AgPSBCSU5BUllfU1VCU0NSOw0K LQkJaSA9IDE7DQotCX0NCi0JZWxzZSBpZiAoYXNzaWduaW5nID09IE9QX0FT U0lHTikgew0KLQkJb3AgPSBTVE9SRV9TVUJTQ1I7DQotCQlpID0gMzsNCi0J fQ0KLQllbHNlIHsNCi0JCW9wID0gREVMRVRFX1NVQlNDUjsNCi0JCWkgPSAy Ow0KKwlpZiAoYXNzaWduaW5nIDw9IE9QX0FQUExZKSB7DQorCQkvKiBFbHNl IG5vcm1hbCBzdWJzY3JpcHRsaXN0LiAgQ29tcGlsZSBlYWNoIHN1YnNjcmlw dC4gKi8NCisJCWZvciAoaSA9IDA7IGkgPCBOQ0gobik7IGkgKz0gMikNCisJ CQljb21fc3Vic2NyaXB0KGMsIENISUxEKG4sIGkpKTsNCisJCS8qIFB1dCBt dWx0aXBsZSBzdWJzY3JpcHRzIGludG8gYSB0dXBsZSAqLw0KKwkJaWYgKE5D SChuKSA+IDEpIHsNCisJCQlpID0gKE5DSChuKSsxKSAvIDI7DQorCQkJY29t X2FkZG9wYXJnKGMsIEJVSUxEX1RVUExFLCBpKTsNCisJCQljb21fcG9wKGMs IGktMSk7DQorCQl9DQorCQlzd2l0Y2ggKGFzc2lnbmluZykgew0KKwkJY2Fz ZSBPUF9ERUxFVEU6DQorCQkJb3AgPSBERUxFVEVfU1VCU0NSOw0KKwkJCWkg PSAyOw0KKwkJCWJyZWFrOw0KKwkJY2FzZSBPUF9BUFBMWToNCisJCQlvcCA9 IEJJTkFSWV9TVUJTQ1I7DQorCQkJaSA9IDE7DQorCQkJYnJlYWs7DQorCQlj YXNlIE9QX0FTU0lHTjoNCisJCQlvcCA9IFNUT1JFX1NVQlNDUjsNCisJCQlp ID0gMzsNCisJCQlicmVhazsNCisJCX0NCisJCWNvbV9hZGRieXRlKGMsIG9w KTsNCisJCWNvbV9wb3AoYywgaSk7DQorCX0gZWxzZSB7IC8qIGRvIE5PVCBh dHRlbXB0IHRvIGZvbGxvdyB0aGUgZm9sbG93aW5nIGNvZGUgd2l0aG91dCBw ZW5jaWwNCisJCSAgICBhbmQgcGFwZXIhICovDQorCQljb21fYWRkYnl0ZShj LCBEVVBfVE9QKTsNCisJCWNvbV9wdXNoKGMsIDEpOw0KKwkJY29tX2FkZGJ5 dGUoYywgUk9UX1RIUkVFKTsNCisJCS8qIENvbXBpbGUgZWFjaCBzdWJzY3Jp cHQuICovDQorCQlmb3IgKGkgPSAwOyBpIDwgTkNIKG4pOyBpICs9IDIpDQor CQkJY29tX3N1YnNjcmlwdChjLCBDSElMRChuLCBpKSk7DQorCQkvKiBQdXQg bXVsdGlwbGUgc3Vic2NyaXB0cyBpbnRvIGEgdHVwbGUgKi8NCisJCWlmIChO Q0gobikgPiAxKSB7DQorCQkJaSA9IChOQ0gobikrMSkgLyAyOw0KKwkJCWNv bV9hZGRvcGFyZyhjLCBCVUlMRF9UVVBMRSwgaSk7DQorCQkJY29tX3BvcChj LCBpLTEpOw0KKwkJfQ0KKwkJY29tX2FkZGJ5dGUoYywgRFVQX1RPUCk7DQor CQljb21fcHVzaChjLCAxKTsNCisJCWNvbV9hZGRieXRlKGMsIFJPVF9USFJF RSk7DQorCQljb21fYWRkYnl0ZShjLCBCSU5BUllfU1VCU0NSKTsNCisJCWNv bV9wb3AoYywgMSk7DQorCQljb21fYWRkYnl0ZShjLCBST1RfVFdPKTsNCisJ CWNvbV9hZGRieXRlKGMsIFJPVF9USFJFRSk7DQorCQljb21fYWRkYnl0ZShj LCBST1RfVFdPKTsNCisJCWNvbV9hZGRieXRlKGMsIGFzc2lnbmluZyk7DQor CQljb21fcG9wKGMsIDEpOw0KKwkJY29tX2FkZGJ5dGUoYywgUk9UX1RIUkVF KTsNCisJCWNvbV9hZGRieXRlKGMsIFNUT1JFX1NVQlNDUik7DQorCQljb21f cG9wKGMsIDMpOw0KIAl9DQotCWNvbV9hZGRieXRlKGMsIG9wKTsNCi0JY29t X3BvcChjLCBpKTsNCiB9DQogDQogc3RhdGljIHZvaWQNCkBAIC0xODQ2LDgg KzE4ODYsMjIgQEANCiAJbm9kZSAqbjsNCiAJaW50IGFzc2lnbmluZzsNCiB7 DQotCWNvbV9hZGRvcG5hbWUoYywgYXNzaWduaW5nID8gU1RPUkVfQVRUUiA6 IERFTEVURV9BVFRSLCBuKTsNCi0JY29tX3BvcChjLCBhc3NpZ25pbmcgPyAy IDogMSk7DQorCWlmIChhc3NpZ25pbmcgPD0gT1BfQVNTSUdOKSB7DQorCQlj b21fYWRkb3BuYW1lKGMsIGFzc2lnbmluZyA/IFNUT1JFX0FUVFIgOiBERUxF VEVfQVRUUiwgbik7DQorCQljb21fcG9wKGMsIGFzc2lnbmluZyA/IDIgOiAx KTsNCisJfSBlbHNlIHsNCisJCWNvbV9hZGRieXRlKGMsIERVUF9UT1ApOw0K KwkJY29tX3B1c2goYywgMSk7DQorCQljb21fYWRkYnl0ZShjLCBST1RfVEhS RUUpOw0KKwkJY29tX2FkZG9wbmFtZShjLCBMT0FEX0FUVFIsIG4pOw0KKwkJ Y29tX3B1c2goYywgMSk7DQorCQljb21fYWRkYnl0ZShjLCBST1RfVFdPKTsN CisJCWNvbV9hZGRieXRlKGMsIGFzc2lnbmluZyk7DQorCQljb21fcG9wKGMs IDEpOw0KKwkJY29tX2FkZGJ5dGUoYywgUk9UX1RXTyk7DQorCQljb21fYWRk b3BuYW1lKGMsIFNUT1JFX0FUVFIsIG4pOw0KKwkJY29tX3BvcChjLCAyKTsN CisJfQ0KIH0NCiANCiBzdGF0aWMgdm9pZA0KQEAgLTE5MzIsNiArMTk4Niwx MSBAQA0KIAkJY2FzZSBleHBybGlzdDoNCiAJCWNhc2UgdGVzdGxpc3Q6DQog CQkJaWYgKE5DSChuKSA+IDEpIHsNCisJCQkJaWYgKCBhc3NpZ25pbmcgPiBP UF9BUFBMWSApIHsNCisJCQkJCWNvbV9lcnJvcihjLCBQeUV4Y19TeW50YXhF cnJvciwNCisJCQkJCQkgICJubyBhdWdtZW50ZWQgYXNzaWdubWVudCB0byB0 dXBsZSIpOw0KKwkJCQkJcmV0dXJuOw0KKwkJCQl9DQogCQkJCWNvbV9hc3Np Z25fdHVwbGUoYywgbiwgYXNzaWduaW5nKTsNCiAJCQkJcmV0dXJuOw0KIAkJ CX0NCkBAIC0xOTc2LDcgKzIwMzUsNyBAQA0KIAkJCQkJY29tX2FwcGx5X3Ry YWlsZXIoYywgQ0hJTEQobiwgaSkpOw0KIAkJCQl9IC8qIE5CIGkgaXMgc3Rp bGwgYWxpdmUgKi8NCiAJCQkJY29tX2Fzc2lnbl90cmFpbGVyKGMsDQotCQkJ CQkJQ0hJTEQobiwgaSksIGFzc2lnbmluZyk7DQorCQkJCQkJICAgQ0hJTEQo biwgaSksIGFzc2lnbmluZyk7DQogCQkJCXJldHVybjsNCiAJCQl9DQogCQkJ biA9IENISUxEKG4sIDApOw0KQEAgLTE5OTIsNiArMjA1MSwxMSBAQA0KIAkJ CQkJCSAgImNhbid0IGFzc2lnbiB0byAoKSIpOw0KIAkJCQkJcmV0dXJuOw0K IAkJCQl9DQorCQkJCWlmICggYXNzaWduaW5nID4gT1BfQVBQTFkgKSB7DQor CQkJCQljb21fZXJyb3IoYywgUHlFeGNfU3ludGF4RXJyb3IsDQorCQkJCQkJ ICAibm8gYXVnbWVudGVkIGFzc2lnbm1lbnQgdG8gdHVwbGUiKTsNCisJCQkJ CXJldHVybjsNCisJCQkJfQ0KIAkJCQlicmVhazsNCiAJCQljYXNlIExTUUI6 DQogCQkJCW4gPSBDSElMRChuLCAxKTsNCkBAIC0yMDAwLDkgKzIwNjQsMjEg QEANCiAJCQkJCQkgICJjYW4ndCBhc3NpZ24gdG8gW10iKTsNCiAJCQkJCXJl dHVybjsNCiAJCQkJfQ0KKwkJCQlpZiAoIGFzc2lnbmluZyA+IE9QX0FQUExZ ICkgew0KKwkJCQkJY29tX2Vycm9yKGMsIFB5RXhjX1N5bnRheEVycm9yLA0K KwkJCQkJCSAgIm5vIGF1Z21lbnRlZCBhc3NpZ25tZW50IHRvIGxpc3QiKTsN CisJCQkJCXJldHVybjsNCisJCQkJfQ0KIAkJCQljb21fYXNzaWduX2xpc3Qo YywgbiwgYXNzaWduaW5nKTsNCiAJCQkJcmV0dXJuOw0KIAkJCWNhc2UgTkFN RToNCisJCQkJaWYgKCBhc3NpZ25pbmcgPiBPUF9BUFBMWSApIHsgDQorCQkJ CQljb21fYWRkb3BuYW1lKGMsIExPQURfTkFNRSwgQ0hJTEQobiwgMCkpOw0K KwkJCQkJY29tX3B1c2goYywgMSk7DQorCQkJCQljb21fYWRkYnl0ZShjLCBS T1RfVFdPKTsNCisJCQkJCWNvbV9hZGRieXRlKGMsIGFzc2lnbmluZyk7DQor CQkJCQljb21fcG9wKGMsIDEpOw0KKwkJCQl9DQogCQkJCWNvbV9hc3NpZ25f bmFtZShjLCBDSElMRChuLCAwKSwgYXNzaWduaW5nKTsNCiAJCQkJcmV0dXJu Ow0KIAkJCWRlZmF1bHQ6DQpAQCAtMjA0NywxMyArMjEyMyw2NCBAQA0KIAkJ Y29tX3BvcChjLCAxKTsNCiAJfQ0KIAllbHNlIHsNCi0JCWludCBpOw0KLQkJ Zm9yIChpID0gMDsgaSA8IE5DSChuKS0yOyBpKz0yKSB7DQotCQkJaWYgKGkr MiA8IE5DSChuKS0yKSB7DQotCQkJCWNvbV9hZGRieXRlKGMsIERVUF9UT1Ap Ow0KLQkJCQljb21fcHVzaChjLCAxKTsNCisJCWlmIChOQ0gobikgPT0gMyAm JiBTVFIoIENISUxEKG4sIDEpIClbMF0gIT0gJz0nKSB7DQorCQkJaW50IG9w Ow0KKwkJCXN3aXRjaCAoU1RSKCBDSElMRChuLCAxKSApWzBdKSB7DQorCQkJ Y2FzZSAnKyc6DQorCQkJCW9wID0gQklOQVJZX0FERDsNCisJCQkJYnJlYWs7 DQorCQkJY2FzZSAnLSc6DQorCQkJCW9wID0gQklOQVJZX1NVQlRSQUNUOw0K KwkJCQlicmVhazsNCisJCQljYXNlICcqJzoNCisJCQkJaWYgKCBTVFIoIENI SUxEKG4sIDEpIClbMl0gKSB7DQorCQkJCQlvcCA9IEJJTkFSWV9QT1dFUjsN CisJCQkJfSBlbHNlIHsNCisJCQkJCW9wID0gQklOQVJZX01VTFRJUExZOw0K KwkJCQl9DQorCQkJCWJyZWFrOw0KKwkJCWNhc2UgJy8nOg0KKwkJCQlvcCA9 IEJJTkFSWV9ESVZJREU7DQorCQkJCWJyZWFrOw0KKwkJCWNhc2UgJyUnOg0K KwkJCQlvcCA9IEJJTkFSWV9NT0RVTE87DQorCQkJCWJyZWFrOw0KKwkJCWNh c2UgJ3wnOg0KKwkJCQlvcCA9IEJJTkFSWV9PUjsNCisJCQkJYnJlYWs7DQor CQkJY2FzZSAnJic6DQorCQkJCW9wID0gQklOQVJZX0FORDsNCisJCQkJYnJl YWs7DQorCQkJY2FzZSAnXic6DQorCQkJCW9wID0gQklOQVJZX1hPUjsNCisJ CQkJYnJlYWs7DQorCQkJY2FzZSAnPCc6DQorCQkJCW9wID0gQklOQVJZX0xT SElGVDsNCisJCQkJYnJlYWs7DQorCQkJY2FzZSAnPic6DQorCQkJCW9wID0g QklOQVJZX1JTSElGVDsNCisJCQkJYnJlYWs7DQorCQkJZGVmYXVsdDoNCisJ CQkJY29tX2Vycm9yKGMsIFB5RXhjX1N5c3RlbUVycm9yLA0KKwkJCQkJICAi dW5rbm93biBhdWdtZW50ZWQgYXNzaWdubWVudCB0eXBlIik7DQorCQkJCXJl dHVybjsNCisJCQl9DQorCQkJY29tX2Fzc2lnbihjLCBDSElMRChuLCAwKSwg b3ApOw0KKwkJfQ0KKwkJZWxzZSB7DQorCQkJaW50IGk7DQorCQkJZm9yIChp ID0gMDsgaSA8IE5DSChuKS0yOyBpKz0yKSB7DQorCQkJCWlmIChpKzIgPCBO Q0gobiktMikgew0KKwkJCQkJY29tX2FkZGJ5dGUoYywgRFVQX1RPUCk7DQor CQkJCQljb21fcHVzaChjLCAxKTsNCisJCQkJfQ0KKyAgCQkJCWlmICggU1RS KCBDSElMRChuLCBpKzEpIClbMF0gIT0gJz0nICkgew0KKyAgCQkJCQljb21f ZXJyb3IoYyxQeUV4Y19TeW50YXhFcnJvciwNCisgIAkJCQkJCSAgIm5vIG11 bHRpcGxlIGF1Z21lbnRlZCBhc3NpZ21lbnQiKTsNCisgIAkJCQkJcmV0dXJu OyANCisgIAkJCQl9IA0KKwkJCQljb21fYXNzaWduKGMsIENISUxEKG4sIGkp LCBPUF9BU1NJR04pOw0KIAkJCX0NCi0JCQljb21fYXNzaWduKGMsIENISUxE KG4sIGkpLCBPUF9BU1NJR04pOw0KIAkJfQ0KIAl9DQogfQ0KZGlmZiAtTnVy IC0tZXhjbHVkZT0qLnB5YyAtLWV4Y2x1ZGU9Kn4gc3JjLWNsZWFuL1B5dGhv bi9ncmFtaW5pdC5jIHNyYy1hdWcvUHl0aG9uL2dyYW1pbml0LmMNCi0tLSBz cmMtY2xlYW4vUHl0aG9uL2dyYW1pbml0LmMJVGh1IE1hciAzMCAxMDoxNDo1 OCAyMDAwDQorKysgc3JjLWF1Zy9QeXRob24vZ3JhbWluaXQuYwlGcmkgTWF5 IDEyIDE4OjUwOjAwIDIwMDANCkBAIC0yMjYsMTYgKzIyNiwyNyBAQA0KIHN0 YXRpYyBhcmMgYXJjc18xMV8wWzFdID0gew0KIAl7OSwgMX0sDQogfTsNCi1z dGF0aWMgYXJjIGFyY3NfMTFfMVsyXSA9IHsNCitzdGF0aWMgYXJjIGFyY3Nf MTFfMVsxM10gPSB7DQogCXsyMCwgMH0sDQorCXszNywgMH0sDQorCXszOCwg MH0sDQorCXszOSwgMH0sDQorCXs0MCwgMH0sDQorCXs0MSwgMH0sDQorCXs0 MiwgMH0sDQorCXs0MywgMH0sDQorCXs0NCwgMH0sDQorCXs0NSwgMH0sDQor CXs0NiwgMH0sDQorCXs0NywgMH0sDQogCXswLCAxfSwNCiB9Ow0KIHN0YXRp YyBzdGF0ZSBzdGF0ZXNfMTFbMl0gPSB7DQogCXsxLCBhcmNzXzExXzB9LA0K LQl7MiwgYXJjc18xMV8xfSwNCisJezEzLCBhcmNzXzExXzF9LA0KIH07DQog c3RhdGljIGFyYyBhcmNzXzEyXzBbMV0gPSB7DQotCXszNywgMX0sDQorCXs0 OCwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMTJfMVsyXSA9IHsNCiAJ ezIxLCAyfSwNCkBAIC0yNTEsMTAgKzI2MiwxMCBAQA0KIAl7MiwgYXJjc18x Ml8yfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18xM18wWzFdID0gew0KLQl7 MzgsIDF9LA0KKwl7NDksIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzEz XzFbMV0gPSB7DQotCXszOSwgMn0sDQorCXs1MCwgMn0sDQogfTsNCiBzdGF0 aWMgYXJjIGFyY3NfMTNfMlsxXSA9IHsNCiAJezAsIDJ9LA0KQEAgLTI2NSw3 ICsyNzYsNyBAQA0KIAl7MSwgYXJjc18xM18yfSwNCiB9Ow0KIHN0YXRpYyBh cmMgYXJjc18xNF8wWzFdID0gew0KLQl7NDAsIDF9LA0KKwl7NTEsIDF9LA0K IH07DQogc3RhdGljIGFyYyBhcmNzXzE0XzFbMV0gPSB7DQogCXswLCAxfSwN CkBAIC0yNzUsMTAgKzI4NiwxMCBAQA0KIAl7MSwgYXJjc18xNF8xfSwNCiB9 Ow0KIHN0YXRpYyBhcmMgYXJjc18xNV8wWzRdID0gew0KLQl7NDEsIDF9LA0K LQl7NDIsIDF9LA0KLQl7NDMsIDF9LA0KLQl7NDQsIDF9LA0KKwl7NTIsIDF9 LA0KKwl7NTMsIDF9LA0KKwl7NTQsIDF9LA0KKwl7NTUsIDF9LA0KIH07DQog c3RhdGljIGFyYyBhcmNzXzE1XzFbMV0gPSB7DQogCXswLCAxfSwNCkBAIC0y ODgsNyArMjk5LDcgQEANCiAJezEsIGFyY3NfMTVfMX0sDQogfTsNCiBzdGF0 aWMgYXJjIGFyY3NfMTZfMFsxXSA9IHsNCi0JezQ1LCAxfSwNCisJezU2LCAx fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18xNl8xWzFdID0gew0KIAl7MCwg MX0sDQpAQCAtMjk4LDcgKzMwOSw3IEBADQogCXsxLCBhcmNzXzE2XzF9LA0K IH07DQogc3RhdGljIGFyYyBhcmNzXzE3XzBbMV0gPSB7DQotCXs0NiwgMX0s DQorCXs1NywgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMTdfMVsxXSA9 IHsNCiAJezAsIDF9LA0KQEAgLTMwOCw3ICszMTksNyBAQA0KIAl7MSwgYXJj c18xN18xfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18xOF8wWzFdID0gew0K LQl7NDcsIDF9LA0KKwl7NTgsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNz XzE4XzFbMl0gPSB7DQogCXs5LCAyfSwNCkBAIC0zMjMsNyArMzM0LDcgQEAN CiAJezEsIGFyY3NfMThfMn0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMTlf MFsxXSA9IHsNCi0JezQ4LCAxfSwNCisJezU5LCAxfSwNCiB9Ow0KIHN0YXRp YyBhcmMgYXJjc18xOV8xWzJdID0gew0KIAl7MjEsIDJ9LA0KQEAgLTM1Niwy MSArMzY3LDIxIEBADQogCXsxLCBhcmNzXzE5XzZ9LA0KIH07DQogc3RhdGlj IGFyYyBhcmNzXzIwXzBbMl0gPSB7DQotCXs0OSwgMX0sDQotCXs1MSwgMn0s DQorCXs2MCwgMX0sDQorCXs2MiwgMn0sDQogfTsNCiBzdGF0aWMgYXJjIGFy Y3NfMjBfMVsxXSA9IHsNCi0JezUwLCAzfSwNCisJezYxLCAzfSwNCiB9Ow0K IHN0YXRpYyBhcmMgYXJjc18yMF8yWzFdID0gew0KLQl7NTAsIDR9LA0KKwl7 NjEsIDR9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzIwXzNbMl0gPSB7DQog CXsyMiwgMX0sDQogCXswLCAzfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18y MF80WzFdID0gew0KLQl7NDksIDV9LA0KKwl7NjAsIDV9LA0KIH07DQogc3Rh dGljIGFyYyBhcmNzXzIwXzVbMl0gPSB7DQogCXsyMywgNn0sDQpAQCAtNDAx LDcgKzQxMiw3IEBADQogCXsxMiwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFy Y3NfMjFfMVsyXSA9IHsNCi0JezUyLCAwfSwNCisJezYzLCAwfSwNCiAJezAs IDF9LA0KIH07DQogc3RhdGljIHN0YXRlIHN0YXRlc18yMVsyXSA9IHsNCkBA IC00MDksNyArNDIwLDcgQEANCiAJezIsIGFyY3NfMjFfMX0sDQogfTsNCiBz dGF0aWMgYXJjIGFyY3NfMjJfMFsxXSA9IHsNCi0JezUzLCAxfSwNCisJezY0 LCAxfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18yMl8xWzFdID0gew0KIAl7 MTIsIDJ9LA0KQEAgLTQyNCwxMyArNDM1LDEzIEBADQogCXsyLCBhcmNzXzIy XzJ9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzIzXzBbMV0gPSB7DQotCXs1 NCwgMX0sDQorCXs2NSwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMjNf MVsxXSA9IHsNCi0JezU1LCAyfSwNCisJezY2LCAyfSwNCiB9Ow0KIHN0YXRp YyBhcmMgYXJjc18yM18yWzJdID0gew0KLQl7NTYsIDN9LA0KKwl7NjcsIDN9 LA0KIAl7MCwgMn0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMjNfM1sxXSA9 IHsNCkBAIC00NTYsNyArNDY3LDcgQEANCiAJezEsIGFyY3NfMjNfNn0sDQog fTsNCiBzdGF0aWMgYXJjIGFyY3NfMjRfMFsxXSA9IHsNCi0JezU3LCAxfSwN CisJezY4LCAxfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18yNF8xWzFdID0g ew0KIAl7MjEsIDJ9LA0KQEAgLTQ3OSwxMiArNDkwLDEyIEBADQogCXsxLCBh cmNzXzI0XzR9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzI1XzBbNl0gPSB7 DQotCXs1OCwgMX0sDQotCXs1OSwgMX0sDQotCXs2MCwgMX0sDQotCXs2MSwg MX0sDQorCXs2OSwgMX0sDQorCXs3MCwgMX0sDQorCXs3MSwgMX0sDQorCXs3 MiwgMX0sDQogCXsxMCwgMX0sDQotCXs2MiwgMX0sDQorCXs3MywgMX0sDQog fTsNCiBzdGF0aWMgYXJjIGFyY3NfMjVfMVsxXSA9IHsNCiAJezAsIDF9LA0K QEAgLTQ5NCw3ICs1MDUsNyBAQA0KIAl7MSwgYXJjc18yNV8xfSwNCiB9Ow0K IHN0YXRpYyBhcmMgYXJjc18yNl8wWzFdID0gew0KLQl7NjMsIDF9LA0KKwl7 NzQsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzI2XzFbMV0gPSB7DQog CXsyMSwgMn0sDQpAQCAtNTA2LDggKzUxNyw4IEBADQogCXsxNSwgNH0sDQog fTsNCiBzdGF0aWMgYXJjIGFyY3NfMjZfNFszXSA9IHsNCi0JezY0LCAxfSwN Ci0JezY1LCA1fSwNCisJezc1LCAxfSwNCisJezc2LCA1fSwNCiAJezAsIDR9 LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzI2XzVbMV0gPSB7DQpAQCAtNTMw LDcgKzU0MSw3IEBADQogCXsxLCBhcmNzXzI2Xzd9LA0KIH07DQogc3RhdGlj IGFyYyBhcmNzXzI3XzBbMV0gPSB7DQotCXs2NiwgMX0sDQorCXs3NywgMX0s DQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMjdfMVsxXSA9IHsNCiAJezIxLCAy fSwNCkBAIC01NDIsNyArNTUzLDcgQEANCiAJezE1LCA0fSwNCiB9Ow0KIHN0 YXRpYyBhcmMgYXJjc18yN180WzJdID0gew0KLQl7NjUsIDV9LA0KKwl7NzYs IDV9LA0KIAl7MCwgNH0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMjdfNVsx XSA9IHsNCkBAIC01NjUsMTMgKzU3NiwxMyBAQA0KIAl7MSwgYXJjc18yN183 fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18yOF8wWzFdID0gew0KLQl7Njcs IDF9LA0KKwl7NzgsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzI4XzFb MV0gPSB7DQotCXszOSwgMn0sDQorCXs1MCwgMn0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfMjhfMlsxXSA9IHsNCi0JezU2LCAzfSwNCisJezY3LCAzfSwN CiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18yOF8zWzFdID0gew0KIAl7OSwgNH0s DQpAQCAtNTgzLDcgKzU5NCw3IEBADQogCXsxNSwgNn0sDQogfTsNCiBzdGF0 aWMgYXJjIGFyY3NfMjhfNlsyXSA9IHsNCi0JezY1LCA3fSwNCisJezc2LCA3 fSwNCiAJezAsIDZ9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzI4XzdbMV0g PSB7DQpAQCAtNjA4LDcgKzYxOSw3IEBADQogCXsxLCBhcmNzXzI4Xzl9LA0K IH07DQogc3RhdGljIGFyYyBhcmNzXzI5XzBbMV0gPSB7DQotCXs2OCwgMX0s DQorCXs3OSwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMjlfMVsxXSA9 IHsNCiAJezE0LCAyfSwNCkBAIC02MTcsOCArNjI4LDggQEANCiAJezE1LCAz fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18yOV8zWzJdID0gew0KLQl7Njks IDR9LA0KLQl7NzAsIDV9LA0KKwl7ODAsIDR9LA0KKwl7ODEsIDV9LA0KIH07 DQogc3RhdGljIGFyYyBhcmNzXzI5XzRbMV0gPSB7DQogCXsxNCwgNn0sDQpA QCAtNjMzLDggKzY0NCw4IEBADQogCXsxNSwgOX0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfMjlfOFszXSA9IHsNCi0JezY5LCA0fSwNCi0JezY1LCA1fSwN CisJezgwLCA0fSwNCisJezc2LCA1fSwNCiAJezAsIDh9LA0KIH07DQogc3Rh dGljIGFyYyBhcmNzXzI5XzlbMV0gPSB7DQpAQCAtNjUzLDcgKzY2NCw3IEBA DQogCXsxLCBhcmNzXzI5Xzl9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzMw XzBbMV0gPSB7DQotCXs3MSwgMX0sDQorCXs4MiwgMX0sDQogfTsNCiBzdGF0 aWMgYXJjIGFyY3NfMzBfMVsyXSA9IHsNCiAJezIxLCAyfSwNCkBAIC02ODQs MTQgKzY5NSwxNCBAQA0KIAl7MCwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFy Y3NfMzFfMlsxXSA9IHsNCi0JezcyLCAzfSwNCisJezgzLCAzfSwNCiB9Ow0K IHN0YXRpYyBhcmMgYXJjc18zMV8zWzFdID0gew0KIAl7NiwgNH0sDQogfTsN CiBzdGF0aWMgYXJjIGFyY3NfMzFfNFsyXSA9IHsNCiAJezYsIDR9LA0KLQl7 NzMsIDF9LA0KKwl7ODQsIDF9LA0KIH07DQogc3RhdGljIHN0YXRlIHN0YXRl c18zMVs1XSA9IHsNCiAJezIsIGFyY3NfMzFfMH0sDQpAQCAtNzAxLDE4ICs3 MTIsMTggQEANCiAJezIsIGFyY3NfMzFfNH0sDQogfTsNCiBzdGF0aWMgYXJj IGFyY3NfMzJfMFsyXSA9IHsNCi0Jezc0LCAxfSwNCi0Jezc2LCAyfSwNCisJ ezg1LCAxfSwNCisJezg3LCAyfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18z Ml8xWzJdID0gew0KLQl7NzUsIDN9LA0KKwl7ODYsIDN9LA0KIAl7MCwgMX0s DQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzJfMlsxXSA9IHsNCiAJezAsIDJ9 LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzMyXzNbMV0gPSB7DQotCXs3NCwg MX0sDQorCXs4NSwgMX0sDQogfTsNCiBzdGF0aWMgc3RhdGUgc3RhdGVzXzMy WzRdID0gew0KIAl7MiwgYXJjc18zMl8wfSwNCkBAIC03MjEsMTAgKzczMiwx MCBAQA0KIAl7MSwgYXJjc18zMl8zfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJj c18zM18wWzFdID0gew0KLQl7NzcsIDF9LA0KKwl7ODgsIDF9LA0KIH07DQog c3RhdGljIGFyYyBhcmNzXzMzXzFbMl0gPSB7DQotCXs3OCwgMH0sDQorCXs4 OSwgMH0sDQogCXswLCAxfSwNCiB9Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNf MzNbMl0gPSB7DQpAQCAtNzMyLDExICs3NDMsMTEgQEANCiAJezIsIGFyY3Nf MzNfMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzRfMFsyXSA9IHsNCi0J ezc5LCAxfSwNCi0JezgwLCAyfSwNCisJezkwLCAxfSwNCisJezkxLCAyfSwN CiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18zNF8xWzFdID0gew0KLQl7NzcsIDJ9 LA0KKwl7ODgsIDJ9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzM0XzJbMV0g PSB7DQogCXswLCAyfSwNCkBAIC03NDcsMTAgKzc1OCwxMCBAQA0KIAl7MSwg YXJjc18zNF8yfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18zNV8wWzFdID0g ew0KLQl7NTUsIDF9LA0KKwl7NjYsIDF9LA0KIH07DQogc3RhdGljIGFyYyBh cmNzXzM1XzFbMl0gPSB7DQotCXs4MSwgMH0sDQorCXs5MiwgMH0sDQogCXsw LCAxfSwNCiB9Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfMzVbMl0gPSB7DQpA QCAtNzU4LDI1ICs3NjksMjUgQEANCiAJezIsIGFyY3NfMzVfMX0sDQogfTsN CiBzdGF0aWMgYXJjIGFyY3NfMzZfMFsxMF0gPSB7DQotCXs4MiwgMX0sDQot CXs4MywgMX0sDQotCXs4NCwgMX0sDQotCXs4NSwgMX0sDQotCXs4NiwgMX0s DQotCXs4NywgMX0sDQotCXs4OCwgMX0sDQotCXs1NiwgMX0sDQotCXs3OSwg Mn0sDQotCXs4OSwgM30sDQorCXs5MywgMX0sDQorCXs5NCwgMX0sDQorCXs5 NSwgMX0sDQorCXs5NiwgMX0sDQorCXs5NywgMX0sDQorCXs5OCwgMX0sDQor CXs5OSwgMX0sDQorCXs2NywgMX0sDQorCXs5MCwgMn0sDQorCXsxMDAsIDN9 LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzM2XzFbMV0gPSB7DQogCXswLCAx fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc18zNl8yWzFdID0gew0KLQl7NTYs IDF9LA0KKwl7NjcsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzM2XzNb Ml0gPSB7DQotCXs3OSwgMX0sDQorCXs5MCwgMX0sDQogCXswLCAzfSwNCiB9 Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfMzZbNF0gPSB7DQpAQCAtNzg2LDEw ICs3OTcsMTAgQEANCiAJezIsIGFyY3NfMzZfM30sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfMzdfMFsxXSA9IHsNCi0JezkwLCAxfSwNCisJezEwMSwgMX0s DQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzdfMVsyXSA9IHsNCi0JezkxLCAw fSwNCisJezEwMiwgMH0sDQogCXswLCAxfSwNCiB9Ow0KIHN0YXRpYyBzdGF0 ZSBzdGF0ZXNfMzdbMl0gPSB7DQpAQCAtNzk3LDEwICs4MDgsMTAgQEANCiAJ ezIsIGFyY3NfMzdfMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzhfMFsx XSA9IHsNCi0JezkyLCAxfSwNCisJezEwMywgMX0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfMzhfMVsyXSA9IHsNCi0JezkzLCAwfSwNCisJezEwNCwgMH0s DQogCXswLCAxfSwNCiB9Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfMzhbMl0g PSB7DQpAQCAtODA4LDEwICs4MTksMTAgQEANCiAJezIsIGFyY3NfMzhfMX0s DQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzlfMFsxXSA9IHsNCi0Jezk0LCAx fSwNCisJezEwNSwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfMzlfMVsy XSA9IHsNCi0Jezk1LCAwfSwNCisJezEwNiwgMH0sDQogCXswLCAxfSwNCiB9 Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfMzlbMl0gPSB7DQpAQCAtODE5LDEx ICs4MzAsMTEgQEANCiAJezIsIGFyY3NfMzlfMX0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfNDBfMFsxXSA9IHsNCi0Jezk2LCAxfSwNCisJezEwNywgMX0s DQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDBfMVszXSA9IHsNCi0Jezk3LCAw fSwNCi0Jezk4LCAwfSwNCisJezEwOCwgMH0sDQorCXsxMDksIDB9LA0KIAl7 MCwgMX0sDQogfTsNCiBzdGF0aWMgc3RhdGUgc3RhdGVzXzQwWzJdID0gew0K QEAgLTgzMSwxMSArODQyLDExIEBADQogCXszLCBhcmNzXzQwXzF9LA0KIH07 DQogc3RhdGljIGFyYyBhcmNzXzQxXzBbMV0gPSB7DQotCXs5OSwgMX0sDQor CXsxMTAsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQxXzFbM10gPSB7 DQotCXsxMDAsIDB9LA0KLQl7MTAxLCAwfSwNCisJezExMSwgMH0sDQorCXsx MTIsIDB9LA0KIAl7MCwgMX0sDQogfTsNCiBzdGF0aWMgc3RhdGUgc3RhdGVz XzQxWzJdID0gew0KQEAgLTg0MywxMiArODU0LDEyIEBADQogCXszLCBhcmNz XzQxXzF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQyXzBbMV0gPSB7DQot CXsxMDIsIDF9LA0KKwl7MTEzLCAxfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJj c180Ml8xWzRdID0gew0KIAl7MjMsIDB9LA0KLQl7MTAzLCAwfSwNCi0JezEw NCwgMH0sDQorCXsxMTQsIDB9LA0KKwl7MTE1LCAwfSwNCiAJezAsIDF9LA0K IH07DQogc3RhdGljIHN0YXRlIHN0YXRlc180MlsyXSA9IHsNCkBAIC04NTYs MTMgKzg2NywxMyBAQA0KIAl7NCwgYXJjc180Ml8xfSwNCiB9Ow0KIHN0YXRp YyBhcmMgYXJjc180M18wWzRdID0gew0KLQl7MTAwLCAxfSwNCi0JezEwMSwg MX0sDQotCXsxMDUsIDF9LA0KLQl7MTA2LCAyfSwNCisJezExMSwgMX0sDQor CXsxMTIsIDF9LA0KKwl7MTE2LCAxfSwNCisJezExNywgMn0sDQogfTsNCiBz dGF0aWMgYXJjIGFyY3NfNDNfMVsxXSA9IHsNCi0JezEwMiwgMn0sDQorCXsx MTMsIDJ9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQzXzJbMV0gPSB7DQog CXswLCAyfSwNCkBAIC04NzMsMTUgKzg4NCwxNSBAQA0KIAl7MSwgYXJjc180 M18yfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180NF8wWzFdID0gew0KLQl7 MTA3LCAxfSwNCisJezExOCwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3Nf NDRfMVszXSA9IHsNCi0JezEwOCwgMX0sDQorCXsxMTksIDF9LA0KIAl7MjQs IDJ9LA0KIAl7MCwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDRfMlsx XSA9IHsNCi0JezEwMiwgM30sDQorCXsxMTMsIDN9LA0KIH07DQogc3RhdGlj IGFyYyBhcmNzXzQ0XzNbMl0gPSB7DQogCXsyNCwgMn0sDQpAQCAtODk1LDEy ICs5MDYsMTIgQEANCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180NV8wWzddID0g ew0KIAl7MTYsIDF9LA0KLQl7MTA5LCAyfSwNCi0JezExMSwgM30sDQotCXsx MTQsIDR9LA0KKwl7MTIwLCAyfSwNCisJezEyMiwgM30sDQorCXsxMjUsIDR9 LA0KIAl7MTIsIDV9LA0KLQl7MTE1LCA1fSwNCi0JezExNiwgNn0sDQorCXsx MjYsIDV9LA0KKwl7MTI3LCA2fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180 NV8xWzJdID0gew0KIAl7OSwgN30sDQpAQCAtOTA4LDExICs5MTksMTEgQEAN CiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180NV8yWzJdID0gew0KIAl7OSwgOH0s DQotCXsxMTAsIDV9LA0KKwl7MTIxLCA1fSwNCiB9Ow0KIHN0YXRpYyBhcmMg YXJjc180NV8zWzJdID0gew0KLQl7MTEyLCA5fSwNCi0JezExMywgNX0sDQor CXsxMjMsIDl9LA0KKwl7MTI0LCA1fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJj c180NV80WzFdID0gew0KIAl7OSwgMTB9LA0KQEAgLTkyMSwyMCArOTMyLDIw IEBADQogCXswLCA1fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180NV82WzJd ID0gew0KLQl7MTE2LCA2fSwNCisJezEyNywgNn0sDQogCXswLCA2fSwNCiB9 Ow0KIHN0YXRpYyBhcmMgYXJjc180NV83WzFdID0gew0KIAl7MTgsIDV9LA0K IH07DQogc3RhdGljIGFyYyBhcmNzXzQ1XzhbMV0gPSB7DQotCXsxMTAsIDV9 LA0KKwl7MTIxLCA1fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180NV85WzFd ID0gew0KLQl7MTEzLCA1fSwNCisJezEyNCwgNX0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfNDVfMTBbMV0gPSB7DQotCXsxMTQsIDV9LA0KKwl7MTI1LCA1 fSwNCiB9Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfNDVbMTFdID0gew0KIAl7 NywgYXJjc180NV8wfSwNCkBAIC05NTAsNyArOTYxLDcgQEANCiAJezEsIGFy Y3NfNDVfMTB9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQ2XzBbMV0gPSB7 DQotCXsxMTcsIDF9LA0KKwl7MTI4LCAxfSwNCiB9Ow0KIHN0YXRpYyBhcmMg YXJjc180Nl8xWzJdID0gew0KIAl7MTcsIDJ9LA0KQEAgLTk3NCwxNSArOTg1 LDE1IEBADQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDdfMFszXSA9IHsNCiAJ ezE2LCAxfSwNCi0JezEwOSwgMn0sDQotCXs1MiwgM30sDQorCXsxMjAsIDJ9 LA0KKwl7NjMsIDN9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQ3XzFbMl0g PSB7DQotCXsxMTgsIDR9LA0KKwl7MTI5LCA0fSwNCiAJezE4LCA1fSwNCiB9 Ow0KIHN0YXRpYyBhcmMgYXJjc180N18yWzFdID0gew0KLQl7MTE5LCA2fSwN CisJezEzMCwgNn0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDdfM1sxXSA9 IHsNCiAJezEyLCA1fSwNCkBAIC05OTQsNyArMTAwNSw3IEBADQogCXswLCA1 fSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180N182WzFdID0gew0KLQl7MTEw LCA1fSwNCisJezEyMSwgNX0sDQogfTsNCiBzdGF0aWMgc3RhdGUgc3RhdGVz XzQ3WzddID0gew0KIAl7MywgYXJjc180N18wfSwNCkBAIC0xMDA2LDE0ICsx MDE3LDE0IEBADQogCXsxLCBhcmNzXzQ3XzZ9LA0KIH07DQogc3RhdGljIGFy YyBhcmNzXzQ4XzBbMV0gPSB7DQotCXsxMjAsIDF9LA0KKwl7MTMxLCAxfSwN CiB9Ow0KIHN0YXRpYyBhcmMgYXJjc180OF8xWzJdID0gew0KIAl7MjIsIDJ9 LA0KIAl7MCwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDhfMlsyXSA9 IHsNCi0JezEyMCwgMX0sDQorCXsxMzEsIDF9LA0KIAl7MCwgMn0sDQogfTsN CiBzdGF0aWMgc3RhdGUgc3RhdGVzXzQ4WzNdID0gew0KQEAgLTEwMjIsMTIg KzEwMzMsMTIgQEANCiAJezIsIGFyY3NfNDhfMn0sDQogfTsNCiBzdGF0aWMg YXJjIGFyY3NfNDlfMFszXSA9IHsNCi0JezUyLCAxfSwNCisJezYzLCAxfSwN CiAJezIxLCAyfSwNCiAJezE0LCAzfSwNCiB9Ow0KIHN0YXRpYyBhcmMgYXJj c180OV8xWzFdID0gew0KLQl7NTIsIDR9LA0KKwl7NjMsIDR9LA0KIH07DQog c3RhdGljIGFyYyBhcmNzXzQ5XzJbMl0gPSB7DQogCXsxNCwgM30sDQpAQCAt MTAzNSwxNCArMTA0NiwxNCBAQA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQ5 XzNbM10gPSB7DQogCXsyMSwgNX0sDQotCXsxMjEsIDZ9LA0KKwl7MTMyLCA2 fSwNCiAJezAsIDN9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzQ5XzRbMV0g PSB7DQotCXs1MiwgNn0sDQorCXs2MywgNn0sDQogfTsNCiBzdGF0aWMgYXJj IGFyY3NfNDlfNVsyXSA9IHsNCi0JezEyMSwgNn0sDQorCXsxMzIsIDZ9LA0K IAl7MCwgNX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNDlfNlsxXSA9IHsN CkBAIC0xMDczLDE0ICsxMDg0LDE0IEBADQogCXsxLCBhcmNzXzUwXzJ9LA0K IH07DQogc3RhdGljIGFyYyBhcmNzXzUxXzBbMV0gPSB7DQotCXs1NSwgMX0s DQorCXs2NiwgMX0sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNTFfMVsyXSA9 IHsNCiAJezIyLCAyfSwNCiAJezAsIDF9LA0KIH07DQogc3RhdGljIGFyYyBh cmNzXzUxXzJbMl0gPSB7DQotCXs1NSwgMX0sDQorCXs2NiwgMX0sDQogCXsw LCAyfSwNCiB9Ow0KIHN0YXRpYyBzdGF0ZSBzdGF0ZXNfNTFbM10gPSB7DQpA QCAtMTEyOSw3ICsxMTQwLDcgQEANCiAJezIsIGFyY3NfNTNfNH0sDQogfTsN CiBzdGF0aWMgYXJjIGFyY3NfNTRfMFsxXSA9IHsNCi0JezEyMiwgMX0sDQor CXsxMzMsIDF9LA0KIH07DQogc3RhdGljIGFyYyBhcmNzXzU0XzFbMV0gPSB7 DQogCXsxMiwgMn0sDQpAQCAtMTE2NCw3ICsxMTc1LDcgQEANCiAJezEsIGFy Y3NfNTRfN30sDQogfTsNCiBzdGF0aWMgYXJjIGFyY3NfNTVfMFszXSA9IHsN Ci0JezEyMywgMX0sDQorCXsxMzQsIDF9LA0KIAl7MjMsIDJ9LA0KIAl7MjQs IDN9LA0KIH07DQpAQCAtMTE3OSw3ICsxMTkwLDcgQEANCiAJezIxLCA2fSwN CiB9Ow0KIHN0YXRpYyBhcmMgYXJjc181NV80WzRdID0gew0KLQl7MTIzLCAx fSwNCisJezEzNCwgMX0sDQogCXsyMywgMn0sDQogCXsyNCwgM30sDQogCXsw LCA0fSwNCkBAIC0xMjI1LDEyMSArMTIzNiwxMjEgQEANCiB9Ow0KIHN0YXRp YyBkZmEgZGZhc1s1N10gPSB7DQogCXsyNTYsICJzaW5nbGVfaW5wdXQiLCAw LCAzLCBzdGF0ZXNfMCwNCi0JICJcMDA0XDAzMFwwMDFcMDAwXDE0MFwzNDFc MTUzXDIwMlwwMzRcMjAwXDAwMFwwMDBcMDYwXDI0MlwwNzRcMDA0In0sDQor CSAiXDAwNFwwMzBcMDAxXDAwMFwwMDBcMDAwXDAxM1wxMzdcMDIzXDM0NFww MDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwNDEifSwNCiAJezI1NywgImZpbGVf aW5wdXQiLCAwLCAyLCBzdGF0ZXNfMSwNCi0JICJcMjA0XDAzMFwwMDFcMDAw XDE0MFwzNDFcMTUzXDIwMlwwMzRcMjAwXDAwMFwwMDBcMDYwXDI0MlwwNzRc MDA0In0sDQorCSAiXDIwNFwwMzBcMDAxXDAwMFwwMDBcMDAwXDAxM1wxMzdc MDIzXDM0NFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwNDEifSwNCiAJezI1 OCwgImV2YWxfaW5wdXQiLCAwLCAzLCBzdGF0ZXNfMiwNCi0JICJcMDAwXDAy MFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMjAwXDAwMFwwMDBcMDYw XDI0MlwwNzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwMDEi fSwNCiAJezI1OSwgImZ1bmNkZWYiLCAwLCA2LCBzdGF0ZXNfMywNCi0JICJc MDAwXDAxMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwIn0sDQorCSAiXDAwMFwwMTBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDAifSwNCiAJezI2MCwgInBhcmFtZXRlcnMiLCAwLCA0LCBzdGF0ZXNf NCwNCi0JICJcMDAwXDAwMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQorCSAiXDAwMFwwMDBc MDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDAifSwNCiAJezI2MSwgInZhcmFyZ3NsaXN0IiwgMCwg MTAsIHN0YXRlc181LA0KLQkgIlwwMDBcMDIwXDIwMVwwMDFcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJ ICJcMDAwXDAyMFwyMDFcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7MjYyLCAiZnBkZWYi LCAwLCA0LCBzdGF0ZXNfNiwNCi0JICJcMDAwXDAyMFwwMDFcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0s DQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCiAJezI2MywgImZw bGlzdCIsIDAsIDMsIHN0YXRlc183LA0KLQkgIlwwMDBcMDIwXDAwMVwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDAifSwNCisJICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7MjY0 LCAic3RtdCIsIDAsIDIsIHN0YXRlc184LA0KLQkgIlwwMDBcMDMwXDAwMVww MDBcMTQwXDM0MVwxNTNcMjAyXDAzNFwyMDBcMDAwXDAwMFwwNjBcMjQyXDA3 NFwwMDQifSwNCisJICJcMDAwXDAzMFwwMDFcMDAwXDAwMFwwMDBcMDEzXDEz N1wwMjNcMzQ0XDAwMFwwMDRcMDAwXDIwMFwwMjFcMzQ1XDA0MSJ9LA0KIAl7 MjY1LCAic2ltcGxlX3N0bXQiLCAwLCA0LCBzdGF0ZXNfOSwNCi0JICJcMDAw XDAyMFwwMDFcMDAwXDE0MFwzNDFcMTUzXDAwMlwwMDBcMjAwXDAwMFwwMDBc MDYwXDI0MlwwNzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBc MDAwXDAxM1wxMzdcMDIzXDAwMFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVww MDEifSwNCiAJezI2NiwgInNtYWxsX3N0bXQiLCAwLCAyLCBzdGF0ZXNfMTAs DQotCSAiXDAwMFwwMjBcMDAxXDAwMFwxNDBcMzQxXDE1M1wwMDJcMDAwXDIw MFwwMDBcMDAwXDA2MFwyNDJcMDc0XDAwMCJ9LA0KKwkgIlwwMDBcMDIwXDAw MVwwMDBcMDAwXDAwMFwwMTNcMTM3XDAyM1wwMDBcMDAwXDAwNFwwMDBcMjAw XDAyMVwzNDVcMDAxIn0sDQogCXsyNjcsICJleHByX3N0bXQiLCAwLCAyLCBz dGF0ZXNfMTEsDQotCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDIwMFwwMDBcMDAwXDA2MFwyNDJcMDc0XDAwMCJ9LA0KKwkgIlww MDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw NFwwMDBcMjAwXDAyMVwzNDVcMDAxIn0sDQogCXsyNjgsICJwcmludF9zdG10 IiwgMCwgMywgc3RhdGVzXzEyLA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDQw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAi fSwNCisJICJcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAxXDAwMFwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7MjY5LCAi ZGVsX3N0bXQiLCAwLCAzLCBzdGF0ZXNfMTMsDQotCSAiXDAwMFwwMDBcMDAw XDAwMFwxMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMCJ9LA0KKwkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQog CXsyNzAsICJwYXNzX3N0bXQiLCAwLCAyLCBzdGF0ZXNfMTQsDQotCSAiXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMCJ9LA0KKwkgIlwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMTBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwIn0sDQogCXsyNzEsICJmbG93X3N0bXQiLCAwLCAyLCBzdGF0ZXNfMTUs DQotCSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMzQwXDAwMVwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KKwkgIlwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDE3XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwIn0sDQogCXsyNzIsICJicmVha19zdG10IiwgMCwgMiwg c3RhdGVzXzE2LA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDA0MFwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMVwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7MjczLCAiY29udGludWVf c3RtdCIsIDAsIDIsIHN0YXRlc18xNywNCi0JICJcMDAwXDAwMFwwMDBcMDAw XDAwMFwxMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwIn0sDQorCSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCiAJezI3 NCwgInJldHVybl9zdG10IiwgMCwgMywgc3RhdGVzXzE4LA0KLQkgIlwwMDBc MDAwXDAwMFwwMDBcMDAwXDIwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDAifSwNCisJICJcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwNFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MCJ9LA0KIAl7Mjc1LCAicmFpc2Vfc3RtdCIsIDAsIDcsIHN0YXRlc18xOSwN Ci0JICJcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQorCSAiXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMTBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDAifSwNCiAJezI3NiwgImltcG9ydF9zdG10IiwgMCwgOSwg c3RhdGVzXzIwLA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMTJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDEyMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7Mjc3LCAiZG90dGVkX25h bWUiLCAwLCAyLCBzdGF0ZXNfMjEsDQotCSAiXDAwMFwwMjBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MCJ9LA0KKwkgIlwwMDBcMDIwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQogCXsyNzgs ICJnbG9iYWxfc3RtdCIsIDAsIDMsIHN0YXRlc18yMiwNCi0JICJcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDQwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwIn0sDQorCSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAi fSwNCiAJezI3OSwgImV4ZWNfc3RtdCIsIDAsIDcsIHN0YXRlc18yMywNCi0J ICJcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMTAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQorCSAiXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAyXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDAifSwNCiAJezI4MCwgImFzc2VydF9zdG10IiwgMCwgNSwgc3Rh dGVzXzI0LA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAy XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMjBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7MjgxLCAiY29tcG91bmRfc3Rt dCIsIDAsIDIsIHN0YXRlc18yNSwNCi0JICJcMDAwXDAxMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDIwMFwwMzRcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDA0 In0sDQorCSAiXDAwMFwwMTBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDM0NFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwNDAifSwNCiAJezI4Miwg ImlmX3N0bXQiLCAwLCA4LCBzdGF0ZXNfMjYsDQotCSAiXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwyMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMCJ9LA0KKwkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDRcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwIn0sDQog CXsyODMsICJ3aGlsZV9zdG10IiwgMCwgOCwgc3RhdGVzXzI3LA0KLQkgIlww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwNFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDQwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMCJ9LA0KIAl7Mjg0LCAiZm9yX3N0bXQiLCAwLCAxMCwgc3RhdGVzXzI4 LA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAxMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMTAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMCJ9LA0KIAl7Mjg1LCAidHJ5X3N0bXQiLCAwLCAxMCwg c3RhdGVzXzI5LA0KLQkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAyMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCisJICJc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMjAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMCJ9LA0KIAl7Mjg2LCAiZXhjZXB0X2Ns YXVzZSIsIDAsIDUsIHN0YXRlc18zMCwNCi0JICJcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwyMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwIn0sDQorCSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDRcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDAifSwNCiAJezI4 NywgInN1aXRlIiwgMCwgNSwgc3RhdGVzXzMxLA0KLQkgIlwwMDRcMDIwXDAw MVwwMDBcMTQwXDM0MVwxNTNcMDAyXDAwMFwyMDBcMDAwXDAwMFwwNjBcMjQy XDA3NFwwMDAifSwNCisJICJcMDA0XDAyMFwwMDFcMDAwXDAwMFwwMDBcMDEz XDEzN1wwMjNcMDAwXDAwMFwwMDRcMDAwXDIwMFwwMjFcMzQ1XDAwMSJ9LA0K IAl7Mjg4LCAidGVzdCIsIDAsIDQsIHN0YXRlc18zMiwNCi0JICJcMDAwXDAy MFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMjAwXDAwMFwwMDBcMDYw XDI0MlwwNzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwMDEi fSwNCiAJezI4OSwgImFuZF90ZXN0IiwgMCwgMiwgc3RhdGVzXzMzLA0KLQkg IlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwyMDBcMDAw XDAwMFwwNjBcMjQyXDAzNFwwMDAifSwNCisJICJcMDAwXDAyMFwwMDFcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDRcMDAwXDIwMFwwMjFc MzQ1XDAwMCJ9LA0KIAl7MjkwLCAibm90X3Rlc3QiLCAwLCAzLCBzdGF0ZXNf MzQsDQotCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDIwMFwwMDBcMDAwXDA2MFwyNDJcMDM0XDAwMCJ9LA0KKwkgIlwwMDBcMDIw XDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwNFwwMDBc MjAwXDAyMVwzNDVcMDAwIn0sDQogCXsyOTEsICJjb21wYXJpc29uIiwgMCwg Miwgc3RhdGVzXzM1LA0KLQkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwNjBcMjQyXDAzNFwwMDAifSwNCisJ ICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDIwMFwwMjFcMzQ1XDAwMCJ9LA0KIAl7MjkyLCAiY29tcF9v cCIsIDAsIDQsIHN0YXRlc18zNiwNCi0JICJcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMVwwMDBcMjAwXDM3NFwwMDNcMDAwXDAwMFwwMDBcMDAw In0sDQorCSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDEw XDAwMFwwMDBcMzQ0XDAzN1wwMDBcMDAwXDAwMFwwMDAifSwNCiAJezI5Mywg ImV4cHIiLCAwLCAyLCBzdGF0ZXNfMzcsDQotCSAiXDAwMFwwMjBcMDAxXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDA2MFwyNDJcMDM0 XDAwMCJ9LA0KKwkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMjAwXDAyMVwzNDVcMDAwIn0sDQogCXsy OTQsICJ4b3JfZXhwciIsIDAsIDIsIHN0YXRlc18zOCwNCi0JICJcMDAwXDAy MFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDYw XDI0MlwwMzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwyMDBcMDIxXDM0NVwwMDAi fSwNCiAJezI5NSwgImFuZF9leHByIiwgMCwgMiwgc3RhdGVzXzM5LA0KLQkg IlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwNjBcMjQyXDAzNFwwMDAifSwNCisJICJcMDAwXDAyMFwwMDFcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDIwMFwwMjFc MzQ1XDAwMCJ9LA0KIAl7Mjk2LCAic2hpZnRfZXhwciIsIDAsIDIsIHN0YXRl c180MCwNCi0JICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDYwXDI0MlwwMzRcMDAwIn0sDQorCSAiXDAwMFww MjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwyMDBcMDIxXDM0NVwwMDAifSwNCiAJezI5NywgImFyaXRoX2V4cHIiLCAw LCAyLCBzdGF0ZXNfNDEsDQotCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDA2MFwyNDJcMDM0XDAwMCJ9LA0K KwkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDBcMjAwXDAyMVwzNDVcMDAwIn0sDQogCXsyOTgsICJ0ZXJt IiwgMCwgMiwgc3RhdGVzXzQyLA0KLQkgIlwwMDBcMDIwXDAwMVwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwNjBcMjQyXDAzNFwwMDAi fSwNCisJICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDAwMFwwMDBcMDAwXDIwMFwwMjFcMzQ1XDAwMCJ9LA0KIAl7Mjk5LCAi ZmFjdG9yIiwgMCwgMywgc3RhdGVzXzQzLA0KLQkgIlwwMDBcMDIwXDAwMVww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwNjBcMjQyXDAz NFwwMDAifSwNCisJICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDIwMFwwMjFcMzQ1XDAwMCJ9LA0KIAl7 MzAwLCAicG93ZXIiLCAwLCA0LCBzdGF0ZXNfNDQsDQotCSAiXDAwMFwwMjBc MDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwy NDBcMDM0XDAwMCJ9LA0KKwkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwzNDVcMDAwIn0s DQogCXszMDEsICJhdG9tIiwgMCwgMTEsIHN0YXRlc180NSwNCi0JICJcMDAw XDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBc MDAwXDI0MFwwMzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAwMFwwMDBc MDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDM0NVww MDAifSwNCiAJezMwMiwgImxhbWJkZWYiLCAwLCA1LCBzdGF0ZXNfNDYsDQot CSAiXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDQwXDAwMCJ9LA0KKwkgIlwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAxIn0sDQogCXszMDMsICJ0cmFpbGVyIiwgMCwgNywgc3RhdGVz XzQ3LA0KLQkgIlwwMDBcMDAwXDAwMVwwMDBcMDAwXDAwMFwwMjBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDQwXDAwMFwwMDAifSwNCisJICJcMDAwXDAw MFwwMDFcMDAwXDAwMFwwMDBcMDAwXDIwMFwwMDBcMDAwXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAxXDAwMCJ9LA0KIAl7MzA0LCAic3Vic2NyaXB0bGlzdCIs IDAsIDMsIHN0YXRlc180OCwNCi0JICJcMDAwXDEyMFwwMDFcMDAwXDAwMFww MDBcMDIwXDAwMFwwMDBcMjAwXDAwMFwwMDBcMDYwXDI0MlwwNzRcMDAwIn0s DQorCSAiXDAwMFwxMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwyMDBcMDAwXDAw MFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwMDEifSwNCiAJezMwNSwgInN1 YnNjcmlwdCIsIDAsIDcsIHN0YXRlc180OSwNCi0JICJcMDAwXDEyMFwwMDFc MDAwXDAwMFwwMDBcMDIwXDAwMFwwMDBcMjAwXDAwMFwwMDBcMDYwXDI0Mlww NzRcMDAwIn0sDQorCSAiXDAwMFwxMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwy MDBcMDAwXDAwMFwwMDBcMDA0XDAwMFwyMDBcMDIxXDM0NVwwMDEifSwNCiAJ ezMwNiwgInNsaWNlb3AiLCAwLCAzLCBzdGF0ZXNfNTAsDQotCSAiXDAwMFwx MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMCJ9LA0KKwkgIlwwMDBcMTAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAw In0sDQogCXszMDcsICJleHBybGlzdCIsIDAsIDMsIHN0YXRlc181MSwNCi0J ICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDYwXDI0MlwwMzRcMDAwIn0sDQorCSAiXDAwMFwwMjBcMDAxXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwyMDBcMDIx XDM0NVwwMDAifSwNCiAJezMwOCwgInRlc3RsaXN0IiwgMCwgMywgc3RhdGVz XzUyLA0KLQkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwyMDBcMDAwXDAwMFwwNjBcMjQyXDA3NFwwMDAifSwNCisJICJcMDAwXDAy MFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDRcMDAw XDIwMFwwMjFcMzQ1XDAwMSJ9LA0KIAl7MzA5LCAiZGljdG1ha2VyIiwgMCwg NSwgc3RhdGVzXzUzLA0KLQkgIlwwMDBcMDIwXDAwMVwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwyMDBcMDAwXDAwMFwwNjBcMjQyXDA3NFwwMDAifSwNCisJ ICJcMDAwXDAyMFwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDRcMDAwXDIwMFwwMjFcMzQ1XDAwMSJ9LA0KIAl7MzEwLCAiY2xhc3Nk ZWYiLCAwLCA4LCBzdGF0ZXNfNTQsDQotCSAiXDAwMFwwMDBcMDAwXDAwMFww MDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw NCJ9LA0KKwkgIlwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAw MFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDQwIn0sDQogCXszMTEs ICJhcmdsaXN0IiwgMCwgOCwgc3RhdGVzXzU1LA0KLQkgIlwwMDBcMDIwXDIw MVwwMDFcMDAwXDAwMFwwMDBcMDAwXDAwMFwyMDBcMDAwXDAwMFwwNjBcMjQy XDA3NFwwMDAifSwNCisJICJcMDAwXDAyMFwyMDFcMDAxXDAwMFwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDRcMDAwXDIwMFwwMjFcMzQ1XDAwMSJ9LA0K IAl7MzEyLCAiYXJndW1lbnQiLCAwLCA0LCBzdGF0ZXNfNTYsDQotCSAiXDAw MFwwMjBcMDAxXDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDIwMFwwMDBcMDAw XDA2MFwyNDJcMDc0XDAwMCJ9LA0KKwkgIlwwMDBcMDIwXDAwMVwwMDBcMDAw XDAwMFwwMDBcMDAwXDAwMFwwMDBcMDAwXDAwNFwwMDBcMjAwXDAyMVwzNDVc MDAxIn0sDQogfTsNCi1zdGF0aWMgbGFiZWwgbGFiZWxzWzEyNF0gPSB7DQor c3RhdGljIGxhYmVsIGxhYmVsc1sxMzVdID0gew0KIAl7MCwgIkVNUFRZIn0s DQogCXsyNTYsIDB9LA0KIAl7NCwgMH0sDQpAQCAtMTM3Nyw2ICsxMzg4LDE3 IEBADQogCXsyNzgsIDB9LA0KIAl7Mjc5LCAwfSwNCiAJezI4MCwgMH0sDQor CXszNywgMH0sDQorCXszOCwgMH0sDQorCXszOSwgMH0sDQorCXs0MCwgMH0s DQorCXs0MSwgMH0sDQorCXs0MiwgMH0sDQorCXs0MywgMH0sDQorCXs0NCwg MH0sDQorCXs0NSwgMH0sDQorCXs0NiwgMH0sDQorCXs0NywgMH0sDQogCXsx LCAicHJpbnQifSwNCiAJezEsICJkZWwifSwNCiAJezMwNywgMH0sDQpAQCAt MTQ2OCw2ICsxNDkwLDYgQEANCiBncmFtbWFyIF9QeVBhcnNlcl9HcmFtbWFy ID0gew0KIAk1NywNCiAJZGZhcywNCi0JezEyNCwgbGFiZWxzfSwNCisJezEz NSwgbGFiZWxzfSwNCiAJMjU2DQogfTsNCg== --8323328-30061660-958155409=:18681-- From trentm@activestate.com Fri May 12 19:50:49 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 12 May 2000 11:50:49 -0700 Subject: [Patches] rint test in test_math.py fails on Win32 Message-ID: <20000512115049.A20275@activestate.com> Rationale: With the conditional addition of math.rint the test in test_math has to be made tolerant of rint not being defined for a platform (e.g. Win32, Win64). This patch does that. 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/Lib/test/test_math.py /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_math.py *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_math.py Fri May 12 10:08:39 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_math.py Fri May 12 11:20:15 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 Fri May 12 05:54:33 2000 From: trentm@activestate.com (Trent Mick) Date: Thu, 11 May 2000 21:54:33 -0700 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <000b01bfbaff$43d320c0$2aa0143f@tim> References: <20000510131446.A25926@activestate.com> <000b01bfbaff$43d320c0$2aa0143f@tim> Message-ID: <20000511215433.A31196@activestate.com> --huq684BweRXVnRxX Content-Type: text/plain; charset=us-ascii Sorry, I goofed in _Py_HashPointer in my first patch. Caused an infinite loop on Win64. Here is the correct ed patch .... Discussion of patch: Correct (presumably) and cleanup certain hash functions (float, complex, object, class, func, method, winreg). Two new hash helper function (_Py_HashDouble() and _Py_HashPointer()) were added to group common hash function code (this helps maintain the hash function invariant: (a==b) => (hash(a)==hash(b))). Tim, a question: Before, the float_hash algorithm that we were discussing did the frexp-and-32-bits-at-a-time reduction magic to the fractpart of the float and then you identified that the same needed to be done to the intpart. Instead of doing this twice, I just applied the reduction to whole double (fractpart+intpart). I don't see any error in doing that. Do you? As well, is there some hashing benefit that is lost by my doing the reduction only once? Note to a reviewer: Please check my refcount usage in _Py_HashPointer. I am a newbie there. _Py_HashPointer just casts to a long (as before) if it fits and goes through a long if it does not (i.e. on Win64 where sizeof(long) < sizeof(void*)). The function is applied where previously a pointer was cast to a long. test_hash.py is added (see attached) to test some cases for the mentioned invariant. 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/Include/object.h ./Include/object.h *** /home/trentm/main/contrib/python/dist/src/Include/object.h Mon Apr 24 08:40:45 2000 --- ./Include/object.h Thu May 11 20:19:53 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. */ diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/object.c ./Objects/object.c *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Wed May 3 16:44:35 2000 --- ./Objects/object.c Thu May 11 20:30:57 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; diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c ./Objects/floatobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/floatobject.c Wed May 3 16:44:34 2000 --- ./Objects/floatobject.c Thu May 11 20:27:05 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; diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c ./Objects/complexobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/complexobject.c Wed May 3 16:44:34 2000 --- ./Objects/complexobject.c Thu May 11 20:48:26 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) diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/classobject.c ./Objects/classobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/classobject.c Wed May 3 16:44:34 2000 --- ./Objects/classobject.c Thu May 11 20:31:51 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; *************** *** 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 = { diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c ./Objects/funcobject.c *** /home/trentm/main/contrib/python/dist/src/Objects/funcobject.c Wed May 3 16:44:35 2000 --- ./Objects/funcobject.c Thu May 11 20:28:45 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; } diff -c3 /home/trentm/main/contrib/python/dist/src/PC/winreg.c ./PC/winreg.c *** /home/trentm/main/contrib/python/dist/src/PC/winreg.c Wed May 3 16:44:37 2000 --- ./PC/winreg.c Thu May 11 20:31:22 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); } And test_hash.py and test_hash are attached. -- Trent Mick trentm@activestate.com --huq684BweRXVnRxX Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="test_hash.py" # 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)) --huq684BweRXVnRxX Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=test_hash test_hash --huq684BweRXVnRxX-- From trentm@activestate.com Sat May 13 05:31:36 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 12 May 2000 21:31:36 -0700 Subject: [Patches] printf("%lx") -> printf("%p") for pointers : win64 cares Message-ID: <20000512213136.A6489@activestate.com> Rationale/Discussion: 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) '' >>> I believe I have found all cases of the use of "%lx" for pointers. Primarily these were for the repr() implementations of many objects and deubgging output in the various thread_*.h files. The changes do not only affect Win64 (as one would hope) because the %p formatter on *NIX (on Linux32 and Linux64 at least) seems to prepend '0x' to the hex representation of the pointer. WIn32 and Win64 do NOT prepend this. Go figure. However, does it matter that the hex output format now includes the '0x' prefix on Linux32? I.e. does Python promise the repr output to look EXACTLY the way it does? Will reasonable code out there break? If so, then that sucks. If not, then here is a patch. 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 trentm@ActiveState.com Sat May 13 06:55:26 2000 From: trentm@ActiveState.com (Trent Mick) Date: Fri, 12 May 2000 22:55:26 -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: <20000512225526.A6689@activestate.com> On Thu, May 11, 2000 at 09:54:33PM -0700, Trent Mick wrote: > diff -c3 /home/trentm/main/contrib/python/dist/src/Objects/object.c ./Objects/object.c > *** /home/trentm/main/contrib/python/dist/src/Objects/object.c Wed May 3 16:44:35 2000 > --- ./Objects/object.c Thu May 11 20:30:57 2000 > *************** > *** 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 */ > + } > + Just had a thought. I suppose that I should use the PyFPE_{START|END}_PROTECT around the middle block doing the floating point math. Correct? Trent From tim_one@email.msn.com Sat May 13 07:21:55 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 02:21:55 -0400 Subject: [Patches] printf("%lx") -> printf("%p") for pointers : win64 cares In-Reply-To: <20000512213136.A6489@activestate.com> Message-ID: <000001bfbca3$891662a0$3f2d153f@tim> [Trent Mick, patches Python to use %p for pointer printing] > ... > The changes do not only affect Win64 (as one would hope) because the > %p formatter on *NIX (on Linux32 and Linux64 at least) seems to > prepend '0x' to the hex representation of the pointer. WIn32 and Win64 > do NOT prepend this. Go figure. 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)! > However, does it matter that the hex output format now includes > the '0x' prefix on Linux32? Well, gratuitous (from a Linux32 user's POV) change can't be considered a good thing. > 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. From trentm@activestate.com Sat May 13 07:41:15 2000 From: trentm@activestate.com (Trent Mick) Date: Fri, 12 May 2000 23:41:15 -0700 Subject: [Patches] printf("%lx") -> printf("%p") for pointers : win64 cares In-Reply-To: <000001bfbca3$891662a0$3f2d153f@tim> References: <20000512213136.A6489@activestate.com> <000001bfbca3$891662a0$3f2d153f@tim> Message-ID: <20000512234115.B6689@activestate.com> On Sat, May 13, 2000 at 02:21:55AM -0400, Tim Peters wrote: > [Trent Mick, patches Python to use %p for pointer printing] > > ... > > The changes do not only affect Win64 (as one would hope) because the > > %p formatter on *NIX (on Linux32 and Linux64 at least) seems to > > prepend '0x' to the hex representation of the pointer. WIn32 and Win64 > > do NOT prepend this. Go figure. > > 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)! Do you have a suggestion for a good ANSI/ISO C reference? It might more efficient for me to read these things than me playing, making patches, and having you teach me through comments on my patch. :) > > > However, does it matter that the hex output format now includes > > the '0x' prefix on Linux32? > > Well, gratuitous (from a Linux32 user's POV) change can't be considered a > good thing. > > > 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 or will I have to #ifdef in %p usage for Win64 only until the magical C95 (is that what it will be called? can't remember the number you mentioned) comes out and solves all our problems. Actually, will the next C standard define output for a pointer printf formatter. Thanks, Trent -- Trent Mick trentm@activestate.com From tim_one@email.msn.com Sat May 13 08:03:24 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 03:03:24 -0400 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <20000511215433.A31196@activestate.com> Message-ID: <000201bfbca9$552d72c0$3f2d153f@tim> [Trent Mick] > ... > Tim, a question: Before, the float_hash algorithm that we were > discussing did the frexp-and-32-bits-at-a-time reduction magic to > the fractpart of the float and then you identified that the same > needed to be done to the intpart. > Instead of doing this twice, I just applied the reduction to > whole double (fractpart+intpart). I don't see any error in doing that. > Do you? As well, is there some hashing benefit that is lost by > my doing the reduction only once? No, no problem, looks good! The simplification makes up for the extra cost of the function call, too . From tim_one@email.msn.com Sat May 13 08:03:27 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 03:03:27 -0400 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <20000512225526.A6689@activestate.com> Message-ID: <000301bfbca9$5684c560$3f2d153f@tim> [Trent Mick] > ... > Just had a thought. I suppose that I should use the > PyFPE_{START|END}_PROTECT > around the middle block doing the floating point math. Correct? No, assuming the platform frexp never blows up (& it shouldn't, but you never know what the platform libc does with IEEE oddballs like NaNs and infinities), there's nothing in the rest of the code that can possibly blow up. All the operations are well-defined and unexceptional. The worst that can happen is that the IEEE "inexact" flag will get set -- but that happens on virtually every fp operation anyway. From Alan Klietz" This is a multi-part message in MIME format. ------=_NextPart_000_000F_01BFBC80.8A0914F0 Content-Type: text/plain; charset="Windows-1252" Content-Transfer-Encoding: 7bit I was all set to send you a cool patch to thread_nt.h that eliminates the round-trip into the kernel when acquiring an unclaimed lock on Windows NT/9x. The script runs in 25 seconds under the old method; under the new method it runs in 9 seconds. This was measured on a 450Mhz Pentium III. Basically, the patch greatly speeds up the interpreter lock. And now I find you guys did the same thing 7 days earlier! Drat. Well, my version doesn't depend on InterlockedCompareExchange(), which is not available on Win95. It also runs a bit faster (IMHO) :-) Alan Klietz Algin Technology alank@algintech.com ---------------------------------------------------------------------------- ---- #include 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_000F_01BFBC80.8A0914F0 Content-Type: application/x-tar; name="thread_nt.tar" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="thread_nt.tar" Li8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAwMDc3NyAAMDAwMDAx IAAwMDAwMDIgADAwMDAwMDAwMDAwIDA3MTA3MTcxNzM0IDAwNDY3MyAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu L3RocmVhZF9jcHUucHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAxNzc3IAAwMDAwMDEg ADAwMDAwMiAAMDAwMDAwMDIxMDAgMDcxMDcxNzE1NjIgMDA3MzY0IAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACMN CiMgVGVzdCB0aGUgQ1BVIG92ZXJoZWFkIG9mIHRoZSBpbnRlcnByZXRlciBsb2NrLg0KIyBXZSBj cmVhdGUgYSBzaW5nbGUgdGhyZWFkIHRoYXQgYnVybnMgQ1BVIHdoaWxlIHRoZSBtYWluIHRocmVh ZCB3YWl0cy4NCiMNCiMgRXhlY3V0aW9uIHRpbWUgd2l0aG91dCB0aGUgSW50ZWwgc3BpbmxvY2s6 IDI1IHNlYw0KIyBFeGVjdXRpb24gdGltZSB3aXRoIHRoZSBJbnRlbCBzcGlubG9jazogOSBzZWMN CiMNCiMgU2VlIHRocmVhZF9udC5oLlBBVENIDQojDQojIFRpbWVzIG1lYXN1cmVkIG9uIGEgNDUw TWh6IFBlbnRpdW0gSUlJDQojIDEyIE1heSAwMCBhbGFua0BhbGdpbnRlY2guY29tIA0KIw0KDQpp bXBvcnQgdGhyZWFkLHN5cw0KDQpudW10YXNrcyA9IDENCnJ1bm5pbmcgPSAwDQoNCm11dGV4ID0g dGhyZWFkLmFsbG9jYXRlX2xvY2soKQ0KZG9uZSA9IHRocmVhZC5hbGxvY2F0ZV9sb2NrKCkNCmRv bmUuYWNxdWlyZSgpDQoNCmRlZiB0YXNrKGlkZW50KToNCglnbG9iYWwgcnVubmluZw0KCXByaW50 ICdSdW5uaW5nIHRhc2sgJWQnICUgaWRlbnQNCglhID0gMQ0KCWZvciB4IGluIHhyYW5nZSgxLDUw MDAwMDApOg0KCQlhID0gYSArIDINCg0KCXByaW50ICdUYXNrICVkIGRvbmUnICUgaWRlbnQNCg0K CW11dGV4LmFjcXVpcmUoKQ0KCXJ1bm5pbmcgPSBydW5uaW5nIC0gMQ0KCWlmIHJ1bm5pbmcgPT0g MDoNCgkJZG9uZS5yZWxlYXNlKCkNCgltdXRleC5yZWxlYXNlKCkNCg0KbmV4dF9pZGVudCA9IDAN CmRlZiBuZXd0YXNrKCk6DQoJZ2xvYmFsIG5leHRfaWRlbnQsIHJ1bm5pbmcNCgltdXRleC5hY3F1 aXJlKCkNCgluZXh0X2lkZW50ID0gbmV4dF9pZGVudCArIDENCglwcmludCAnY3JlYXRpbmcgdGFz aycsIG5leHRfaWRlbnQNCgl0aHJlYWQuc3RhcnRfbmV3X3RocmVhZCh0YXNrLCAobmV4dF9pZGVu dCwpKQ0KCXJ1bm5pbmcgPSBydW5uaW5nICsgMQ0KCW11dGV4LnJlbGVhc2UoKQ0KDQpmb3IgaSBp biByYW5nZShudW10YXNrcyk6DQoJbmV3dGFzaygpDQoNCnByaW50ICd3YWl0aW5nIGZvciBhbGwg dGFza3MgdG8gY29tcGxldGUnDQpkb25lLmFjcXVpcmUoKQ0KcHJpbnQgJ2FsbCB0YXNrcyBkb25l Jw0KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC4vdGhy ZWFkX250LmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDE3NzcgADAwMDAwMSAAMDAw MDAyIAAwMDAwMDAyNzY1MCAwNzEwNzE3NzA1MiAwMDcwMzYgAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALyoqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQpD b3B5cmlnaHQgMTk5MS0xOTk1IGJ5IFN0aWNodGluZyBNYXRoZW1hdGlzY2ggQ2VudHJ1bSwgQW1z dGVyZGFtLA0KVGhlIE5ldGhlcmxhbmRzLg0KDQogICAgICAgICAgICAgICAgICAgICAgICBBbGwg UmlnaHRzIFJlc2VydmVkDQoNClBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZCBk aXN0cmlidXRlIHRoaXMgc29mdHdhcmUgYW5kIGl0cw0KZG9jdW1lbnRhdGlvbiBmb3IgYW55IHB1 cnBvc2UgYW5kIHdpdGhvdXQgZmVlIGlzIGhlcmVieSBncmFudGVkLA0KcHJvdmlkZWQgdGhhdCB0 aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhcHBlYXIgaW4gYWxsIGNvcGllcyBhbmQgdGhhdA0K Ym90aCB0aGF0IGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2UgYXBw ZWFyIGluDQpzdXBwb3J0aW5nIGRvY3VtZW50YXRpb24sIGFuZCB0aGF0IHRoZSBuYW1lcyBvZiBT dGljaHRpbmcgTWF0aGVtYXRpc2NoDQpDZW50cnVtIG9yIENXSSBvciBDb3Jwb3JhdGlvbiBmb3Ig TmF0aW9uYWwgUmVzZWFyY2ggSW5pdGlhdGl2ZXMgb3INCkNOUkkgbm90IGJlIHVzZWQgaW4gYWR2 ZXJ0aXNpbmcgb3IgcHVibGljaXR5IHBlcnRhaW5pbmcgdG8NCmRpc3RyaWJ1dGlvbiBvZiB0aGUg c29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYywgd3JpdHRlbiBwcmlvcg0KcGVybWlzc2lvbi4NCg0K V2hpbGUgQ1dJIGlzIHRoZSBpbml0aWFsIHNvdXJjZSBmb3IgdGhpcyBzb2Z0d2FyZSwgYSBtb2Rp ZmllZCB2ZXJzaW9uDQppcyBtYWRlIGF2YWlsYWJsZSBieSB0aGUgQ29ycG9yYXRpb24gZm9yIE5h dGlvbmFsIFJlc2VhcmNoIEluaXRpYXRpdmVzDQooQ05SSSkgYXQgdGhlIEludGVybmV0IGFkZHJl c3MgZnRwOi8vZnRwLnB5dGhvbi5vcmcuDQoNClNUSUNIVElORyBNQVRIRU1BVElTQ0ggQ0VOVFJV TSBBTkQgQ05SSSBESVNDTEFJTSBBTEwgV0FSUkFOVElFUyBXSVRIDQpSRUdBUkQgVE8gVEhJUyBT T0ZUV0FSRSwgSU5DTFVESU5HIEFMTCBJTVBMSUVEIFdBUlJBTlRJRVMgT0YNCk1FUkNIQU5UQUJJ TElUWSBBTkQgRklUTkVTUywgSU4gTk8gRVZFTlQgU0hBTEwgU1RJQ0hUSU5HIE1BVEhFTUFUSVND SA0KQ0VOVFJVTSBPUiBDTlJJIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIElORElSRUNUIE9S IENPTlNFUVVFTlRJQUwNCkRBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJ TkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUg0KUFJPRklUUywgV0hFVEhFUiBJTiBBTiBBQ1RJ T04gT0YgQ09OVFJBQ1QsIE5FR0xJR0VOQ0UgT1IgT1RIRVINClRPUlRJT1VTIEFDVElPTiwgQVJJ U0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1INClBFUkZPUk1BTkNF IE9GIFRISVMgU09GVFdBUkUuDQoNCioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8NCg0KLyogT3JpZ2luYWwgdmVyc2lvbiBi eSBEYWcuR3J1bmVhdUBlbHNhLnByZXNlY28uY29tbS5zZS4gKi8NCi8qIFVwZGF0ZWQgZm9yIGZh c3RlciBsb2NraW5nIGJ5IGFsYW5rQGFsZ2ludGVjaC5jb20gMTIgTWF5IDAwLiAqLw0KDQojZGVm aW5lIFdJTjMyX0xFQU5fQU5EX01FQU4gLyogZXhjbHVkZSByYXJlbHkgdXNlZCBpbmNsdWRlIGZp bGVzICovDQojaW5jbHVkZSA8d2luZG93cy5oPg0KI2luY2x1ZGUgPGxpbWl0cy5oPg0KI2luY2x1 ZGUgPHByb2Nlc3MuaD4NCg0KI2luY2x1ZGUgIm15bWFsbG9jLmgiIC8qIGZvciBQeU1lbV9ORVco KSBhbmQgUHlNZW1fREVMKCkgKi8NCg0KLyojZGVmaW5lIFBZX0RFQlVHX05UX1RIUkVBRFMqLw0K DQojaWZkZWYgUFlfREVCVUdfTlRfVEhSRUFEUw0KIyB1bmRlZiBkcHJpbnRmDQojIGRlZmluZSBk cHJpbnRmKGFyZ3MpIChwcmludGYgYXJncykNCiMgaWZuZGVmIFB5X0RFQlVHDQojICBkZWZpbmUg UHlfREVCVUcNCiMgZW5kaWYNCiNlbmRpZg0KDQoNCmxvbmcgUHlUaHJlYWRfZ2V0X3RocmVhZF9p ZGVudCh2b2lkKTsNCg0KLyoNCiAqIENoYW5nZSBhbGwgaGVhZGVycyB0byBwdXJlIEFOU0kgYXMg bm8gb25lIHdpbGwgdXNlIEsmUiBzdHlsZSBvbiBhbg0KICogTlQNCiAqLw0KDQovKg0KICogSW5p dGlhbGl6YXRpb24gb2YgdGhlIEMgcGFja2FnZSwgc2hvdWxkIG5vdCBiZSBuZWVkZWQuDQogKi8N CnN0YXRpYyB2b2lkIFB5VGhyZWFkX19pbml0X3RocmVhZCh2b2lkKQ0Kew0KfQ0KDQovKg0KICog VGhyZWFkIHN1cHBvcnQuDQogKi8NCmludCBQeVRocmVhZF9zdGFydF9uZXdfdGhyZWFkKHZvaWQg KCpmdW5jKSh2b2lkICopLCB2b2lkICphcmcpDQp7DQoJbG9uZyBydjsNCglpbnQgc3VjY2VzcyA9 IDA7DQoNCglkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9zdGFydF9uZXdfdGhyZWFkIGNhbGxlZFxu IiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpKSk7DQoJaWYgKCFpbml0aWFsaXplZCkNCgkJ UHlUaHJlYWRfaW5pdF90aHJlYWQoKTsNCg0KCXJ2ID0gX2JlZ2ludGhyZWFkKGZ1bmMsIDAsIGFy Zyk7IC8qIHVzZSBkZWZhdWx0IHN0YWNrIHNpemUgKi8NCiANCglpZiAocnYgIT0gLTEpIHsNCgkJ c3VjY2VzcyA9IDE7DQoJCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3N0YXJ0X25ld190aHJlYWQg c3VjY2VlZGVkOiAlbGRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgcnYpKTsNCgl9 DQoNCglyZXR1cm4gc3VjY2VzczsNCn0NCg0KLyoNCiAqIFJldHVybiB0aGUgdGhyZWFkIElkIGlu c3RlYWQgb2YgYW4gaGFuZGxlLiBUaGUgSWQgaXMgc2FpZCB0byB1bmlxdWVseSBpZGVudGlmeSB0 aGUNCiAqIHRocmVhZCBpbiB0aGUgc3lzdGVtDQogKi8NCmxvbmcgUHlUaHJlYWRfZ2V0X3RocmVh ZF9pZGVudCh2b2lkKQ0Kew0KCWlmICghaW5pdGlhbGl6ZWQpDQoJCVB5VGhyZWFkX2luaXRfdGhy ZWFkKCk7DQogICAgICAgIA0KCXJldHVybiBHZXRDdXJyZW50VGhyZWFkSWQoKTsNCn0NCg0Kc3Rh dGljIHZvaWQgZG9fUHlUaHJlYWRfZXhpdF90aHJlYWQoaW50IG5vX2NsZWFudXApDQp7DQoJZHBy aW50ZigoIiVsZDogUHlUaHJlYWRfZXhpdF90aHJlYWQgY2FsbGVkXG4iLCBQeVRocmVhZF9nZXRf dGhyZWFkX2lkZW50KCkpKTsNCglpZiAoIWluaXRpYWxpemVkKQ0KCQlpZiAobm9fY2xlYW51cCkN CgkJCV9leGl0KDApOw0KCQllbHNlDQoJCQlleGl0KDApOw0KCV9lbmR0aHJlYWQoKTsNCn0NCg0K dm9pZCBQeVRocmVhZF9leGl0X3RocmVhZCh2b2lkKQ0Kew0KCWRvX1B5VGhyZWFkX2V4aXRfdGhy ZWFkKDApOw0KfQ0KDQp2b2lkIFB5VGhyZWFkX19leGl0X3RocmVhZCh2b2lkKQ0Kew0KCWRvX1B5 VGhyZWFkX2V4aXRfdGhyZWFkKDEpOw0KfQ0KDQojaWZuZGVmIE5PX0VYSVRfUFJPRw0Kc3RhdGlj IHZvaWQgZG9fUHlUaHJlYWRfZXhpdF9wcm9nKGludCBzdGF0dXMsIGludCBub19jbGVhbnVwKQ0K ew0KCWRwcmludGYoKCJQeVRocmVhZF9leGl0X3Byb2coJWQpIGNhbGxlZFxuIiwgc3RhdHVzKSk7 DQoJaWYgKCFpbml0aWFsaXplZCkNCgkJaWYgKG5vX2NsZWFudXApDQoJCQlfZXhpdChzdGF0dXMp Ow0KCQllbHNlDQoJCQlleGl0KHN0YXR1cyk7DQp9DQoNCnZvaWQgUHlUaHJlYWRfZXhpdF9wcm9n KGludCBzdGF0dXMpDQp7DQoJZG9fUHlUaHJlYWRfZXhpdF9wcm9nKHN0YXR1cywgMCk7DQp9DQoN CnZvaWQgUHlUaHJlYWRfX2V4aXRfcHJvZyBfUDEoaW50IHN0YXR1cykNCnsNCglkb19QeVRocmVh ZF9leGl0X3Byb2coc3RhdHVzLCAxKTsNCn0NCiNlbmRpZiAvKiBOT19FWElUX1BST0cgKi8NCg0K LyoNCiAqIFdpbjMyIGxvY2sgc3VwcG9ydC4NCiAqIA0KICogSW1wbGVtZW50IHVzaW5nIENQVSBz cGluIGxvY2tzIGluc3RlYWQgb2Yga2VybmVsIGNhbGxzLA0KICogZm9yIHNwZWVkLg0KICoNCiAq IDEyIE1heSAwMCBhbGFua0BhbGdpbnRlY2guY29tDQogKi8NCg0KLyogSW5saW5lIG9uIEludGVs IHByb2Nlc3NvcnMgKi8NCiNpZmRlZiBfTV9JWDg2DQojIGRlZmluZSBJbnRlcmxvY2tlZEV4Y2hh bmdlIEludGVybG9ja2VkRXhjaGFuZ2UzODYNCl9pbmxpbmUgTE9ORyBJbnRlcmxvY2tlZEV4Y2hh bmdlMzg2KFBMT05HIHBsVGFyZ2V0LCBMT05HIGxWYWwpDQp7DQoJCV9fYXNtIG1vdiBlYXgsIGxW YWwNCgkJX19hc20gbW92IGVieCwgW3BsVGFyZ2V0XQ0KCQlfX2FzbSBsb2NrIHhjaGcgZWF4LCBb ZWJ4XSAgIC8qIEJhbSEgKi8NCgkJX19hc20gbW92IGxWYWwsIGVheA0KCQlyZXR1cm4gbFZhbDsN Cn0NCiNlbmRpZiAvKiBfTV9JWDg2ICovDQoNCi8qIEdyYWIgdGhlIHNwaW4gbG9jaywgeWllbGRp bmcgdGhlIENQVSBpZiBidXN5ICovDQovKiBPbiBvZGQtbnVtYmVyZWQgYXR0ZW1wdHMgMCw8MT4s Miw8Mz4sLi4gZXhwbGljaXRseSB5aWVsZCBmb3IgaHlzdGVyZXNpcyAqLw0KLyogcGVyIEJpbGwg VHV0dCAqLw0KI2RlZmluZSBQWUdSQUJXMzJMT0NLKHB3MzIsIGN1cnRocmVhZCwgbGFiZWwpIFwN CmxhYmVsOiBsQnVzeSA9IEludGVybG9ja2VkRXhjaGFuZ2UoKFBMT05HKSYocHczMiktPm1fbEJ1 c3ksIChjdXJ0aHJlYWQpKTsgXA0KCWlmIChsQnVzeSAhPSAwKSB7IFNsZWVwKGR3U2xlZXApOyBk d1NsZWVwID0gIWR3U2xlZXA7IGdvdG8gbGFiZWw7IH0NCg0KLyogRnJlZSB0aGUgc3BpbiBsb2Nr ICovDQojZGVmaW5lIFBZUkVMRUFTRVczMkxPQ0socHczMikgXA0KCUludGVybG9ja2VkRXhjaGFu Z2UoKFBMT05HKSYocHczMiktPm1fbEJ1c3ksIDApOw0KDQoNCiNkZWZpbmUgUFlfVzMyX0xPQ0tf TUFHSUMgMHhBNUI2REVGRQ0KDQovKiBXaW4zMiBsb2NrIHN0cnVjdHVyZSAqLw0KdHlwZWRlZiBz dHJ1Y3Qgew0KCURXT1JEIG1fZHdNYWdpYzsgLyogUGFyYW5vaWEgdG8gcHJldmVudCBoZWFwIHRy YXNoaW5nICovDQoJdm9sYXRpbGUgTE9ORyBtX2xCdXN5OyAvKiBQeVdpbjMyTG9jayBpcyBpbiB1 c2UgKi8NCgl2b2xhdGlsZSBMT05HIG1fbExvY2tlZDsgLyogTWFpbiBsb2NrICovDQoJdm9sYXRp bGUgTE9ORyBtX25XYWl0aW5nOyAvKiAjIG9mIHRocmVhZHMgd2FpdGluZyBvbiBsb2NrICovDQoJ SEFORExFIG1faFNlbWFwaG9yZTsgLyogRm9yIHdhaXRpbmcgdGhyZWFkcyAqLw0KfSBQeVdpbjMy TG9jazsNCg0KDQoNClB5VGhyZWFkX3R5cGVfbG9jayBQeVRocmVhZF9hbGxvY2F0ZV9sb2NrKHZv aWQpDQp7DQoJUHlXaW4zMkxvY2sqIHBXaW4zMkxvY2s7DQoNCglpZiAoIWluaXRpYWxpemVkKQ0K CQlQeVRocmVhZF9pbml0X3RocmVhZCgpOw0KDQoJLyogQWxsb2NhdGUgYW5kIGluaXRpYWxpemUg dGhlIFdpbjMyIGxvY2sgKi8NCg0KCXBXaW4zMkxvY2sgPSBQeU1lbV9ORVcoUHlXaW4zMkxvY2ss IDEpOw0KCXBXaW4zMkxvY2stPm1fZHdNYWdpYyA9IFBZX1czMl9MT0NLX01BR0lDOw0KCXBXaW4z MkxvY2stPm1fbEJ1c3kgPSAwOw0KCXBXaW4zMkxvY2stPm1fbExvY2tlZCA9IDA7DQoJcFdpbjMy TG9jay0+bV9uV2FpdGluZyA9IDA7DQoJcFdpbjMyTG9jay0+bV9oU2VtYXBob3JlID0gQ3JlYXRl U2VtYXBob3JlKE5VTEwsDQoJCQkJMSwgLyogaW5pdGlhbCB2YWx1ZSAqLyANCgkJCQkxLCAvKiBt YXggdmFsdWUgKi8NCgkJCQlOVUxMKTsNCg0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2FsbG9j YXRlX2xvY2soKSAtPiAlbHhcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgKGxvbmcp cFdpbjMyTG9jaykpOw0KDQoJcmV0dXJuIChQeVRocmVhZF90eXBlX2xvY2spIHBXaW4zMkxvY2s7 DQp9DQoNCg0Kdm9pZCBQeVRocmVhZF9mcmVlX2xvY2soUHlUaHJlYWRfdHlwZV9sb2NrIGFMb2Nr KQ0Kew0KCVB5V2luMzJMb2NrKiBwV2luMzJMb2NrOw0KDQoJZHByaW50ZigoIiVsZDogUHlUaHJl YWRfZnJlZV9sb2NrKCVseCkgY2FsbGVkXG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCks KGxvbmcpYUxvY2spKTsNCg0KCXBXaW4zMkxvY2sgPSAoUHlXaW4zMkxvY2sqKWFMb2NrOw0KDQoJ LyogQXNzZXJ0OiB0aGUgbG9jayBpcyBub3QgYWxyZWFkeSBmcmVlZCAqLw0KCWlmIChwV2luMzJM b2NrLT5tX2R3TWFnaWMgIT0gUFlfVzMyX0xPQ0tfTUFHSUMpIHsNCgkJZHByaW50ZigoIiVsZDog UHlUaHJlYWRfZnJlZV9sb2NrKCVseCkgdHJpZWQgdG8gZnJlZSBhIGZyZWVkIGxvY2shXG4iLCBQ eVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksKGxvbmcpYUxvY2spKTsNCgkJcmV0dXJuOw0KCX0N Cg0KCS8qIEFzc2VydDogdGhlIGxvY2sgaXMgbm90IGluIHVzZSAqLw0KCWlmIChwV2luMzJMb2Nr LT5tX2xMb2NrZWQgIT0gMCkgew0KCQlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9mcmVlX2xvY2so JWx4KSB0cmllZCB0byBmcmVlIGEgYnVzeSBsb2NrIG93bmVkIGJ5ICVsZCFcbiIsIFB5VGhyZWFk X2dldF90aHJlYWRfaWRlbnQoKSwobG9uZylhTG9jaywgcFdpbjMyTG9jay0+bV9sTG9ja2VkKSk7 DQoJCS8qIEZhbGwgdGhyb3VnaCBhbmQga2lsbCB0aGUgbG9jayAqLw0KCX0NCg0KCXBXaW4zMkxv Y2stPm1fZHdNYWdpYyA9IDA7DQoJQ2xvc2VIYW5kbGUocFdpbjMyTG9jay0+bV9oU2VtYXBob3Jl KTsNCglwV2luMzJMb2NrLT5tX2hTZW1hcGhvcmUgPSBOVUxMOw0KCVB5TWVtX0RFTChwV2luMzJM b2NrKTsNCn0NCg0KDQovKg0KICogUmV0dXJuIDEgb24gc3VjY2VzcyBpZiB0aGUgbG9jayB3YXMg YWNxdWlyZWQNCiAqIGFuZCAwIGlmIHRoZSBsb2NrIHdhcyBub3QgYWNxdWlyZWQuIElmIHRoZSBs b2NrIGlzIGFscmVhZHkNCiAqIGFjcXVpcmVkIGJ5IG91ciB0aHJlYWQsIHJldHVybiAwLiAgVGhl IGNhbGxlcnMgYXNzdW1lIHNlbWFudGljcw0KICogdGhhdCByZWN1cnNpdmUgbG9ja3MgYnkgdGhl IHNhbWUgdGhyZWFkIHNob3VsZCBibG9jaywNCiAqIGkuZS4sIHRoZXkgYXNzdW1lIGl0IGFjdHMg bGlrZSBhIHNlbWFwaG9yZSwgbm90IGxpa2UgYSBjcml0aWNhbCBzZWN0aW9uLg0KICoNCiAqIDEy IE1heSAwMCBhbGFua0BhbGdpbnRlY2guY29tDQogKi8NCmludCBQeVRocmVhZF9hY3F1aXJlX2xv Y2soUHlUaHJlYWRfdHlwZV9sb2NrIGFMb2NrLCBpbnQgd2FpdGZsYWcpDQp7DQoJUHlXaW4zMkxv Y2sqIHBXaW4zMkxvY2s7DQoJTE9ORyBsQnVzeTsNCglEV09SRCBkd1NsZWVwID0gMDsNCglpbnQg c3VjY2VzcyA9IDE7DQojaWZkZWYgUHlfREVCVUcNCglMT05HIGxDdXJyZW50VGhyZWFkSWQgPSBQ eVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCk7DQojZW5kaWYNCg0KCWRwcmludGYoKCIlbGQ6IFB5 VGhyZWFkX2FjcXVpcmVfbG9jayglbHgsICVkKSBjYWxsZWRcbiIsIGxDdXJyZW50VGhyZWFkSWQs IChsb25nKWFMb2NrLCB3YWl0ZmxhZykpOw0KDQoJcFdpbjMyTG9jayA9IChQeVdpbjMyTG9jayop YUxvY2s7DQoNCgkvKiBBc3NlcnQ6IHRoZSBsb2NrIGlzIG5vdCBmcmVlZCAqLw0KCWlmIChwV2lu MzJMb2NrLT5tX2R3TWFnaWMgIT0gUFlfVzMyX0xPQ0tfTUFHSUMpIHsNCgkJZHByaW50ZigoIiVs ZDogUHlUaHJlYWRfYWNxdWlyZV9sb2NrKCVseCkgdHJpZWQgdG8gYWNxdWlyZSBhIGZyZWVkIGxv Y2shXG4iLCBsQ3VycmVudFRocmVhZElkLCAobG9uZylhTG9jaykpOw0KCQlyZXR1cm4gMDsNCgl9 DQoNCmFnYWluOiANCgkvKiBTcGluIG9uIHRoZSBwV2luMzJMb2NrIHN0cnVjdCAqLw0KCVBZR1JB QlczMkxPQ0socFdpbjMyTG9jaywgMSwgbG9jazEpOw0KDQoJaWYgKCFwV2luMzJMb2NrLT5tX2xM b2NrZWQpIHsgLyogV2UgZ290IGl0ISAqLw0KCQkvKiBHcmFiIHRoZSBsb2NrICovDQoJCXBXaW4z MkxvY2stPm1fbExvY2tlZCA9IDE7IC8qIHZvbGF0aWxlICovDQoJCVBZUkVMRUFTRVczMkxPQ0so cFdpbjMyTG9jayk7DQoJfSBlbHNlIHsgLyogQWxyZWFkeSBsb2NrZWQgKi8NCgkJaWYgKCF3YWl0 ZmxhZykgeyAvKiBQb2xsIGZhaWxlZCwgYmFpbCAqLw0KCQkJUFlSRUxFQVNFVzMyTE9DSyhwV2lu MzJMb2NrKTsNCgkJCXN1Y2Nlc3MgPSAwOw0KCQl9IGVsc2UgeyAvKiBEcmF0LCB3ZSBuZWVkIHRv IGJsb2NrICovDQoJCQlEV09SRCBkd1dhaXRSZXN1bHQ7DQoNCgkJCS8qIFRlbGwgdGhlIGxvY2sg aG9sZGVyIHRvIFJlbGVhc2VTZW1hcGhvcmUoKSAqLw0KCQkJKysocFdpbjMyTG9jay0+bV9uV2Fp dGluZyk7IC8qIHZvbGF0aWxlICovDQoJCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxvY2spOw0K DQoJCQlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9hY3F1aXJlX2xvY2soJWx4KSBibG9ja2luZyBv biBsb2NrIGhlbGQgYnkgJWxkXG4iLCBsQ3VycmVudFRocmVhZElkLCBhTG9jaywgcFdpbjMyTG9j ay0+bV9sTG9ja2VkKSk7DQoNCgkJCS8qIEJsb2NrIHVudGlsIFJlbGVhc2VTZW1hcGhvcmUoKSAq Lw0KCQkJZHdXYWl0UmVzdWx0ID0gV2FpdEZvclNpbmdsZU9iamVjdChwV2luMzJMb2NrLT5tX2hT ZW1hcGhvcmUsDQoJCQkJSU5GSU5JVEUpOw0KDQoJCQkvKiBUdXJuIG9mZiBSZWxlYXNlU2VtYXBo b3JlKCkuICBNdXN0IGJlDQoJCQkgICBkb25lIGNhcmVmdWxseSB0byBhdm9pZCByYWNlcy4gKi8N CgkJCVBZR1JBQlczMkxPQ0socFdpbjMyTG9jaywgMSwgbG9jazIpOw0KCQkJLS0ocFdpbjMyTG9j ay0+bV9uV2FpdGluZyk7IC8qIHZvbGF0aWxlICovDQoJCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4z MkxvY2spOw0KDQoJCQlpZiAoZHdXYWl0UmVzdWx0ICE9IFdBSVRfT0JKRUNUXzApIHsNCgkJCQlz dWNjZXNzID0gMDsgLyogU2VtYXBob3JlIGNsb3NlZCwgYmFpbCAqLw0KCQkJfSBlbHNlIHsNCgkJ CQlnb3RvIGFnYWluOyAvKiBGaWdodCBmb3IgdGhlIGxvY2sgYWdhaW4gKi8NCgkJCX0NCgkJfQ0K CX0NCg0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2FjcXVpcmVfbG9jayglbHgsICVkKSAtPiAl ZFxuIiwNCgkJCWxDdXJyZW50VGhyZWFkSWQsKGxvbmcpYUxvY2ssIHdhaXRmbGFnLCBzdWNjZXNz KSk7DQoNCglyZXR1cm4gc3VjY2VzczsNCn0NCg0KDQovKg0KICogUmVsZWFzZSB0aGUgbG9jay4g IENhbGwgUmVsZWFzZVNlbWFwaG9yZSgpIGlmIGFuZCBvbmx5IGlmIGFub3RoZXIgdGhyZWFkDQog KiBpcyB3YWl0aW5nLg0KICogDQogKiAxMiBNYXkgMDAgYWxhbmtAYWxnaW50ZWNoLmNvbQ0KICov DQp2b2lkIFB5VGhyZWFkX3JlbGVhc2VfbG9jayhQeVRocmVhZF90eXBlX2xvY2sgYUxvY2spDQp7 DQoJUHlXaW4zMkxvY2sqIHBXaW4zMkxvY2s7DQoJTE9ORyBsQnVzeTsNCglEV09SRCBkd1NsZWVw ID0gMDsNCiNpZmRlZiBQeV9ERUJVRw0KCUxPTkcgbEN1cnJlbnRUaHJlYWRJZCA9IFB5VGhyZWFk X2dldF90aHJlYWRfaWRlbnQoKTsNCiNlbmRpZg0KDQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRf cmVsZWFzZV9sb2NrKCVseCkgY2FsbGVkXG4iLCBsQ3VycmVudFRocmVhZElkLCAobG9uZylhTG9j aykpOw0KDQoJcFdpbjMyTG9jayA9IChQeVdpbjMyTG9jayopYUxvY2s7DQoNCgkvKiBBc3NlcnQ6 IHRoZSBsb2NrIGlzIG5vdCBmcmVlZCAqLw0KCWlmIChwV2luMzJMb2NrLT5tX2R3TWFnaWMgIT0g UFlfVzMyX0xPQ0tfTUFHSUMpIHsNCgkJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfcmVsZWFzZV9s b2NrKCVseCkgdHJpZWQgdG8gcmVsZWFzZSBhIGZyZWVkIGxvY2shXG4iLCBsQ3VycmVudFRocmVh ZElkLCAobG9uZylhTG9jaykpOw0KCQlyZXR1cm47DQoJfQ0KDQoJUFlHUkFCVzMyTE9DSyhwV2lu MzJMb2NrLCAxLCBsb2NrMSk7DQoNCglpZiAoIXBXaW4zMkxvY2stPm1fbExvY2tlZCkgew0KCSAg ICAJLyogVGhlIGxvY2sgd2FzIG5vdCBhY3F1aXJlZCBpbiB0aGUgZmlyc3QgcGxhY2UsIGh1bW0u LiAqLw0KCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxvY2spOw0KCQlkcHJpbnRmKCgiJWxkOiBQ eVRocmVhZF9yZWxlYXNlX2xvY2soJWx4KSB0cmllZCB0byByZWxlYXNlIGEgbG9jayB0aGF0IHdh cyBub3QgYWNxdWlyZWQhXG4iLCBsQ3VycmVudFRocmVhZElkLCAobG9uZylhTG9jaykpOw0KCX0g ZWxzZSB7DQoJCS8qIFJlbGVhc2UgdGhlIGxvY2sgKi8NCgkJcFdpbjMyTG9jay0+bV9sTG9ja2Vk ID0gMDsgLyogdm9sYXRpbGUgKi8NCg0KCQlpZiAocFdpbjMyTG9jay0+bV9uV2FpdGluZykgeyAv KiBJZiB0aHJlYWRzIGFyZSB3YWl0aW5nICovDQoJCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxv Y2spOw0KCQkJLyogVW5ibG9jayBvbmUgd2FpdGluZyB0aHJlYWQgKi8NCgkJCVJlbGVhc2VTZW1h cGhvcmUocFdpbjMyTG9jay0+bV9oU2VtYXBob3JlLCAxLCBOVUxMKTsNCgkJfSBlbHNlIHsNCgkJ CVBZUkVMRUFTRVczMkxPQ0socFdpbjMyTG9jayk7DQoJCX0NCgl9DQoJcmV0dXJuOw0KfQ0KDQoN Ci8qDQogKiBTZW1hcGhvcmUgc3VwcG9ydCAobm90IGN1cnJlbnRseSB1c2VkKS4NCiAqLw0KUHlU aHJlYWRfdHlwZV9zZW1hIFB5VGhyZWFkX2FsbG9jYXRlX3NlbWEoaW50IHZhbHVlKQ0Kew0KCUhB TkRMRSBhU2VtYXBob3JlOw0KDQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfYWxsb2NhdGVfc2Vt YSBjYWxsZWRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSkpOw0KCWlmICghaW5pdGlh bGl6ZWQpDQoJCVB5VGhyZWFkX2luaXRfdGhyZWFkKCk7DQoNCglhU2VtYXBob3JlID0gQ3JlYXRl U2VtYXBob3JlKCBOVUxMLCAgICAgICAgICAgLyogU2VjdXJpdHkgYXR0cmlidXRlcyAgICAgICAg ICAqLw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLCAgICAgICAgICAv KiBJbml0aWFsIHZhbHVlICAgICAgICAgICAgICAgICovDQogICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgSU5UX01BWCwgICAgICAgIC8qIE1heGltdW0gdmFsdWUgICAgICAgICAgICAg ICAgKi8NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMKTsgICAgICAgICAg LyogTmFtZSBvZiBzZW1hcGhvcmUgICAgICAgICAgICAqLw0KDQoJZHByaW50ZigoIiVsZDogUHlU aHJlYWRfYWxsb2NhdGVfc2VtYSgpIC0+ICVseFxuIiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVu dCgpLCAobG9uZylhU2VtYXBob3JlKSk7DQoNCglyZXR1cm4gKFB5VGhyZWFkX3R5cGVfc2VtYSkg YVNlbWFwaG9yZTsNCn0NCg0Kdm9pZCBQeVRocmVhZF9mcmVlX3NlbWEoUHlUaHJlYWRfdHlwZV9z ZW1hIGFTZW1hcGhvcmUpDQp7DQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfZnJlZV9zZW1hKCVs eCkgY2FsbGVkXG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksIChsb25nKWFTZW1hcGhv cmUpKTsNCg0KCUNsb3NlSGFuZGxlKChIQU5ETEUpIGFTZW1hcGhvcmUpOw0KfQ0KDQovKg0KICBY WFggbXVzdCBkbyBzb21ldGhpbmcgYWJvdXQgd2FpdGZsYWcNCiAqLw0KaW50IFB5VGhyZWFkX2Rv d25fc2VtYShQeVRocmVhZF90eXBlX3NlbWEgYVNlbWFwaG9yZSwgaW50IHdhaXRmbGFnKQ0Kew0K CURXT1JEIHdhaXRSZXN1bHQ7DQoNCglkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9kb3duX3NlbWEo JWx4KSBjYWxsZWRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgKGxvbmcpYVNlbWFw aG9yZSkpOw0KDQoJd2FpdFJlc3VsdCA9IFdhaXRGb3JTaW5nbGVPYmplY3QoIChIQU5ETEUpIGFT ZW1hcGhvcmUsIElORklOSVRFKTsNCg0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2Rvd25fc2Vt YSglbHgpIHJldHVybjogJWxcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwobG9uZykg YVNlbWFwaG9yZSwgd2FpdFJlc3VsdCkpOw0KCXJldHVybiAwOw0KfQ0KDQp2b2lkIFB5VGhyZWFk X3VwX3NlbWEoUHlUaHJlYWRfdHlwZV9zZW1hIGFTZW1hcGhvcmUpDQp7DQoJUmVsZWFzZVNlbWFw aG9yZSgNCiAgICAgICAgICAgICAgICAoSEFORExFKSBhU2VtYXBob3JlLCAgICAgICAgICAgIC8q IEhhbmRsZSBvZiBzZW1hcGhvcmUgICAgICAgICAgICAgICAgICAgICAgICAgICovDQogICAgICAg ICAgICAgICAgMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBpbmNyZW1lbnQgY291 bnQgYnkgb25lICAgICAgICAgICAgICAgICAgICAgICAqLw0KICAgICAgICAgICAgICAgIE5VTEwp OyAgICAgICAgICAgICAgICAgICAgICAgICAgLyogbm90IGludGVyZXN0ZWQgaW4gcHJldmlvdXMg Y291bnQgICAgICAgICAgICAgKi8NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgIA0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3VwX3NlbWEoJWx4KVxuIiwg UHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpLCAobG9uZylhU2VtYXBob3JlKSk7DQp9DQoAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALi90aHJlYWRfbnQuaC5PTEQAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAADAwMTc3NyAAMDAwMDAxIAAwMDAwMDIgADAwMDAwMDE3MTM1IDA3MTA3MTQx MDQ2IDAwNzQ0MiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCkNvcHlyaWdodCAxOTkxLTE5OTUgYnkgU3Rp Y2h0aW5nIE1hdGhlbWF0aXNjaCBDZW50cnVtLCBBbXN0ZXJkYW0sDQpUaGUgTmV0aGVybGFuZHMu DQoNCiAgICAgICAgICAgICAgICAgICAgICAgIEFsbCBSaWdodHMgUmVzZXJ2ZWQNCg0KUGVybWlz c2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgdGhpcyBzb2Z0d2FyZSBh bmQgaXRzDQpkb2N1bWVudGF0aW9uIGZvciBhbnkgcHVycG9zZSBhbmQgd2l0aG91dCBmZWUgaXMg aGVyZWJ5IGdyYW50ZWQsDQpwcm92aWRlZCB0aGF0IHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNl IGFwcGVhciBpbiBhbGwgY29waWVzIGFuZCB0aGF0DQpib3RoIHRoYXQgY29weXJpZ2h0IG5vdGlj ZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBhcHBlYXIgaW4NCnN1cHBvcnRpbmcgZG9jdW1l bnRhdGlvbiwgYW5kIHRoYXQgdGhlIG5hbWVzIG9mIFN0aWNodGluZyBNYXRoZW1hdGlzY2gNCkNl bnRydW0gb3IgQ1dJIG9yIENvcnBvcmF0aW9uIGZvciBOYXRpb25hbCBSZXNlYXJjaCBJbml0aWF0 aXZlcyBvcg0KQ05SSSBub3QgYmUgdXNlZCBpbiBhZHZlcnRpc2luZyBvciBwdWJsaWNpdHkgcGVy dGFpbmluZyB0bw0KZGlzdHJpYnV0aW9uIG9mIHRoZSBzb2Z0d2FyZSB3aXRob3V0IHNwZWNpZmlj LCB3cml0dGVuIHByaW9yDQpwZXJtaXNzaW9uLg0KDQpXaGlsZSBDV0kgaXMgdGhlIGluaXRpYWwg c291cmNlIGZvciB0aGlzIHNvZnR3YXJlLCBhIG1vZGlmaWVkIHZlcnNpb24NCmlzIG1hZGUgYXZh aWxhYmxlIGJ5IHRoZSBDb3Jwb3JhdGlvbiBmb3IgTmF0aW9uYWwgUmVzZWFyY2ggSW5pdGlhdGl2 ZXMNCihDTlJJKSBhdCB0aGUgSW50ZXJuZXQgYWRkcmVzcyBmdHA6Ly9mdHAucHl0aG9uLm9yZy4N Cg0KU1RJQ0hUSU5HIE1BVEhFTUFUSVNDSCBDRU5UUlVNIEFORCBDTlJJIERJU0NMQUlNIEFMTCBX QVJSQU5USUVTIFdJVEgNClJFR0FSRCBUTyBUSElTIFNPRlRXQVJFLCBJTkNMVURJTkcgQUxMIElN UExJRUQgV0FSUkFOVElFUyBPRg0KTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTLCBJTiBOTyBF VkVOVCBTSEFMTCBTVElDSFRJTkcgTUFUSEVNQVRJU0NIDQpDRU5UUlVNIE9SIENOUkkgQkUgTElB QkxFIEZPUiBBTlkgU1BFQ0lBTCwgSU5ESVJFQ1QgT1IgQ09OU0VRVUVOVElBTA0KREFNQUdFUyBP UiBBTlkgREFNQUdFUyBXSEFUU09FVkVSIFJFU1VMVElORyBGUk9NIExPU1MgT0YgVVNFLCBEQVRB IE9SDQpQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5D RSBPUiBPVEhFUg0KVE9SVElPVVMgQUNUSU9OLCBBUklTSU5HIE9VVCBPRiBPUiBJTiBDT05ORUNU SU9OIFdJVEggVEhFIFVTRSBPUg0KUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS4NCg0KKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqLw0KDQovKiBUaGlzIGNvZGUgaW1wbGVtZW50ZWQgYnkgRGFnLkdydW5lYXVAZWxzYS5w cmVzZWNvLmNvbW0uc2UgKi8NCg0KI2luY2x1ZGUgPHdpbmRvd3MuaD4NCiNpbmNsdWRlIDxsaW1p dHMuaD4NCiNpbmNsdWRlIDxwcm9jZXNzLmg+DQoNCmxvbmcgUHlUaHJlYWRfZ2V0X3RocmVhZF9p ZGVudCh2b2lkKTsNCg0KLyoNCiAqIENoYW5nZSBhbGwgaGVhZGVycyB0byBwdXJlIEFOU0kgYXMg bm8gb25lIHdpbGwgdXNlIEsmUiBzdHlsZSBvbiBhbg0KICogTlQNCiAqLw0KDQovKg0KICogSW5p dGlhbGl6YXRpb24gb2YgdGhlIEMgcGFja2FnZSwgc2hvdWxkIG5vdCBiZSBuZWVkZWQuDQogKi8N CnN0YXRpYyB2b2lkIFB5VGhyZWFkX19pbml0X3RocmVhZCh2b2lkKQ0Kew0KfQ0KDQovKg0KICog VGhyZWFkIHN1cHBvcnQuDQogKi8NCmludCBQeVRocmVhZF9zdGFydF9uZXdfdGhyZWFkKHZvaWQg KCpmdW5jKSh2b2lkICopLCB2b2lkICphcmcpDQp7DQoJbG9uZyBydjsNCglpbnQgc3VjY2VzcyA9 IDA7DQoNCglkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9zdGFydF9uZXdfdGhyZWFkIGNhbGxlZFxu IiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpKSk7DQoJaWYgKCFpbml0aWFsaXplZCkNCgkJ UHlUaHJlYWRfaW5pdF90aHJlYWQoKTsNCg0KCXJ2ID0gX2JlZ2ludGhyZWFkKGZ1bmMsIDAsIGFy Zyk7IC8qIHVzZSBkZWZhdWx0IHN0YWNrIHNpemUgKi8NCiANCglpZiAocnYgIT0gLTEpIHsNCgkJ c3VjY2VzcyA9IDE7DQoJCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3N0YXJ0X25ld190aHJlYWQg c3VjY2VlZGVkOiAlbGRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgcnYpKTsNCgl9 DQoNCglyZXR1cm4gc3VjY2VzczsNCn0NCg0KLyoNCiAqIFJldHVybiB0aGUgdGhyZWFkIElkIGlu c3RlYWQgb2YgYW4gaGFuZGxlLiBUaGUgSWQgaXMgc2FpZCB0byB1bmlxdWVseSBpZGVudGlmeSB0 aGUNCiAqIHRocmVhZCBpbiB0aGUgc3lzdGVtDQogKi8NCmxvbmcgUHlUaHJlYWRfZ2V0X3RocmVh ZF9pZGVudCh2b2lkKQ0Kew0KCWlmICghaW5pdGlhbGl6ZWQpDQoJCVB5VGhyZWFkX2luaXRfdGhy ZWFkKCk7DQogICAgICAgIA0KCXJldHVybiBHZXRDdXJyZW50VGhyZWFkSWQoKTsNCn0NCg0Kc3Rh dGljIHZvaWQgZG9fUHlUaHJlYWRfZXhpdF90aHJlYWQoaW50IG5vX2NsZWFudXApDQp7DQoJZHBy aW50ZigoIiVsZDogUHlUaHJlYWRfZXhpdF90aHJlYWQgY2FsbGVkXG4iLCBQeVRocmVhZF9nZXRf dGhyZWFkX2lkZW50KCkpKTsNCglpZiAoIWluaXRpYWxpemVkKQ0KCQlpZiAobm9fY2xlYW51cCkN CgkJCV9leGl0KDApOw0KCQllbHNlDQoJCQlleGl0KDApOw0KCV9lbmR0aHJlYWQoKTsNCn0NCg0K dm9pZCBQeVRocmVhZF9leGl0X3RocmVhZCh2b2lkKQ0Kew0KCWRvX1B5VGhyZWFkX2V4aXRfdGhy ZWFkKDApOw0KfQ0KDQp2b2lkIFB5VGhyZWFkX19leGl0X3RocmVhZCh2b2lkKQ0Kew0KCWRvX1B5 VGhyZWFkX2V4aXRfdGhyZWFkKDEpOw0KfQ0KDQojaWZuZGVmIE5PX0VYSVRfUFJPRw0Kc3RhdGlj IHZvaWQgZG9fUHlUaHJlYWRfZXhpdF9wcm9nKGludCBzdGF0dXMsIGludCBub19jbGVhbnVwKQ0K ew0KCWRwcmludGYoKCJQeVRocmVhZF9leGl0X3Byb2coJWQpIGNhbGxlZFxuIiwgc3RhdHVzKSk7 DQoJaWYgKCFpbml0aWFsaXplZCkNCgkJaWYgKG5vX2NsZWFudXApDQoJCQlfZXhpdChzdGF0dXMp Ow0KCQllbHNlDQoJCQlleGl0KHN0YXR1cyk7DQp9DQoNCnZvaWQgUHlUaHJlYWRfZXhpdF9wcm9n KGludCBzdGF0dXMpDQp7DQoJZG9fUHlUaHJlYWRfZXhpdF9wcm9nKHN0YXR1cywgMCk7DQp9DQoN CnZvaWQgUHlUaHJlYWRfX2V4aXRfcHJvZyBfUDEoaW50IHN0YXR1cykNCnsNCglkb19QeVRocmVh ZF9leGl0X3Byb2coc3RhdHVzLCAxKTsNCn0NCiNlbmRpZiAvKiBOT19FWElUX1BST0cgKi8NCg0K LyoNCiAqIExvY2sgc3VwcG9ydC4gSXQgaGFzIHRvbyBiZSBpbXBsZW1lbnRlZCBhcyBzZW1hcGhv cmVzLg0KICogSSBbRGFnXSB0cmllZCB0byBpbXBsZW1lbnQgaXQgd2l0aCBtdXRleCBidXQgSSBj b3VsZCBmaW5kIGEgd2F5IHRvDQogKiB0ZWxsIHdoZXRoZXIgYSB0aHJlYWQgYWxyZWFkeSBvd24g dGhlIGxvY2sgb3Igbm90Lg0KICovDQpQeVRocmVhZF90eXBlX2xvY2sgUHlUaHJlYWRfYWxsb2Nh dGVfbG9jayh2b2lkKQ0Kew0KCUhBTkRMRSBhTG9jazsNCg0KCWRwcmludGYoKCJQeVRocmVhZF9h bGxvY2F0ZV9sb2NrIGNhbGxlZFxuIikpOw0KCWlmICghaW5pdGlhbGl6ZWQpDQoJCVB5VGhyZWFk X2luaXRfdGhyZWFkKCk7DQoNCgkJYUxvY2sgPSBDcmVhdGVTZW1hcGhvcmUoTlVMTCwgICAgICAg ICAgIC8qIFNlY3VyaXR5IGF0dHJpYnV0ZXMgICAgICAgICAgKi8NCiAgICAgICAgICAgICAgICAg ICAgICAgICAxLCAgICAgICAgICAgICAgICAgICAgIC8qIEluaXRpYWwgdmFsdWUgICAgICAgICAg ICAgICAgKi8NCiAgICAgICAgICAgICAgICAgICAgICAgICAxLCAgICAgICAgICAgICAgICAgICAg IC8qIE1heGltdW0gdmFsdWUgICAgICAgICAgICAgICAgKi8NCiAgICAgICAgICAgICAgICAgICAg ICAgICBOVUxMKTsgICAgICAgDQogIC8qIE5hbWUgb2Ygc2VtYXBob3JlICAgICAgICAgICAgKi8N Cg0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2FsbG9jYXRlX2xvY2soKSAtPiAlbHhcbiIsIFB5 VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgKGxvbmcpYUxvY2spKTsNCg0KCXJldHVybiAoUHlU aHJlYWRfdHlwZV9sb2NrKSBhTG9jazsNCn0NCg0Kdm9pZCBQeVRocmVhZF9mcmVlX2xvY2soUHlU aHJlYWRfdHlwZV9sb2NrIGFMb2NrKQ0Kew0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2ZyZWVf bG9jayglbHgpIGNhbGxlZFxuIiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpLChsb25nKWFM b2NrKSk7DQoNCglDbG9zZUhhbmRsZSgoSEFORExFKSBhTG9jayk7DQp9DQoNCi8qDQogKiBSZXR1 cm4gMSBvbiBzdWNjZXNzIGlmIHRoZSBsb2NrIHdhcyBhY3F1aXJlZA0KICoNCiAqIGFuZCAwIGlm IHRoZSBsb2NrIHdhcyBub3QgYWNxdWlyZWQuIFRoaXMgbWVhbnMgYSAwIGlzIHJldHVybmVkDQog KiBpZiB0aGUgbG9jayBoYXMgYWxyZWFkeSBiZWVuIGFjcXVpcmVkIGJ5IHRoaXMgdGhyZWFkIQ0K ICovDQppbnQgUHlUaHJlYWRfYWNxdWlyZV9sb2NrKFB5VGhyZWFkX3R5cGVfbG9jayBhTG9jaywg aW50IHdhaXRmbGFnKQ0Kew0KCWludCBzdWNjZXNzID0gMTsNCglEV09SRCB3YWl0UmVzdWx0Ow0K DQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfYWNxdWlyZV9sb2NrKCVseCwgJWQpIGNhbGxlZFxu IiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpLChsb25nKWFMb2NrLCB3YWl0ZmxhZykpOw0K DQoJd2FpdFJlc3VsdCA9IFdhaXRGb3JTaW5nbGVPYmplY3QoKEhBTkRMRSkgYUxvY2ssICh3YWl0 ZmxhZyA9PSAxID8gSU5GSU5JVEUgOiAwKSk7DQoNCglpZiAod2FpdFJlc3VsdCAhPSBXQUlUX09C SkVDVF8wKSB7DQoJCXN1Y2Nlc3MgPSAwOyAgICAvKiBXZSBmYWlsZWQgKi8NCgl9DQoNCglkcHJp bnRmKCgiJWxkOiBQeVRocmVhZF9hY3F1aXJlX2xvY2soJWx4LCAlZCkgLT4gJWRcbiIsIFB5VGhy ZWFkX2dldF90aHJlYWRfaWRlbnQoKSwobG9uZylhTG9jaywgd2FpdGZsYWcsIHN1Y2Nlc3MpKTsN Cg0KCXJldHVybiBzdWNjZXNzOw0KfQ0KDQp2b2lkIFB5VGhyZWFkX3JlbGVhc2VfbG9jayhQeVRo cmVhZF90eXBlX2xvY2sgYUxvY2spDQp7DQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfcmVsZWFz ZV9sb2NrKCVseCkgY2FsbGVkXG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksKGxvbmcp YUxvY2spKTsNCg0KCWlmICghUmVsZWFzZVNlbWFwaG9yZSgNCiAgICAgICAgICAgICAgICAgICAg ICAgIChIQU5ETEUpIGFMb2NrLCAgICAgICAgICAgICAgICAgICAgICAgICAvKiBIYW5kbGUgb2Yg c2VtYXBob3JlICAgICAgICAgICAgICAgICAgICAgICAgICAqLw0KICAgICAgICAgICAgICAgICAg ICAgICAgMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIGluY3JlbWVu dCBjb3VudCBieSBvbmUgICAgICAgICAgICAgICAgICAgICAgICovDQogICAgICAgICAgICAgICAg ICAgICAgICBOVUxMKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogbm90IGlu dGVyZXN0ZWQgaW4gcHJldmlvdXMgY291bnQgICAgICAgICAgICAgKi8NCgkJew0KCQlkcHJpbnRm KCgiJWxkOiBDb3VsZCBub3QgUHlUaHJlYWRfcmVsZWFzZV9sb2NrKCVseCkgZXJyb3I6ICVsXG4i LCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksIChsb25nKWFMb2NrLCBHZXRMYXN0RXJyb3Io KSkpOw0KCQl9DQp9DQoNCi8qDQogKiBTZW1hcGhvcmUgc3VwcG9ydC4NCiAqLw0KUHlUaHJlYWRf dHlwZV9zZW1hIFB5VGhyZWFkX2FsbG9jYXRlX3NlbWEoaW50IHZhbHVlKQ0Kew0KCUhBTkRMRSBh U2VtYXBob3JlOw0KDQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfYWxsb2NhdGVfc2VtYSBjYWxs ZWRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSkpOw0KCWlmICghaW5pdGlhbGl6ZWQp DQoJCVB5VGhyZWFkX2luaXRfdGhyZWFkKCk7DQoNCglhU2VtYXBob3JlID0gQ3JlYXRlU2VtYXBo b3JlKCBOVUxMLCAgICAgICAgICAgLyogU2VjdXJpdHkgYXR0cmlidXRlcyAgICAgICAgICAqLw0K ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLCAgICAgICAgICAvKiBJbml0 aWFsIHZhbHVlICAgICAgICAgICAgICAgICovDQogICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgSU5UX01BWCwgICAgICAgIC8qIE1heGltdW0gdmFsdWUgICAgICAgICAgICAgICAgKi8N CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMKTsgICAgICAgICAgLyogTmFt ZSBvZiBzZW1hcGhvcmUgICAgICAgICAgICAqLw0KDQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRf YWxsb2NhdGVfc2VtYSgpIC0+ICVseFxuIiwgUHlUaHJlYWRfZ2V0X3RocmVhZF9pZGVudCgpLCAo bG9uZylhU2VtYXBob3JlKSk7DQoNCglyZXR1cm4gKFB5VGhyZWFkX3R5cGVfc2VtYSkgYVNlbWFw aG9yZTsNCn0NCg0Kdm9pZCBQeVRocmVhZF9mcmVlX3NlbWEoUHlUaHJlYWRfdHlwZV9zZW1hIGFT ZW1hcGhvcmUpDQp7DQoJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfZnJlZV9zZW1hKCVseCkgY2Fs bGVkXG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksIChsb25nKWFTZW1hcGhvcmUpKTsN Cg0KCUNsb3NlSGFuZGxlKChIQU5ETEUpIGFTZW1hcGhvcmUpOw0KfQ0KDQovKg0KICBYWFggbXVz dCBkbyBzb21ldGhpbmcgYWJvdXQgd2FpdGZsYWcNCiAqLw0KaW50IFB5VGhyZWFkX2Rvd25fc2Vt YShQeVRocmVhZF90eXBlX3NlbWEgYVNlbWFwaG9yZSwgaW50IHdhaXRmbGFnKQ0Kew0KCURXT1JE IHdhaXRSZXN1bHQ7DQoNCglkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9kb3duX3NlbWEoJWx4KSBj YWxsZWRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwgKGxvbmcpYVNlbWFwaG9yZSkp Ow0KDQoJd2FpdFJlc3VsdCA9IFdhaXRGb3JTaW5nbGVPYmplY3QoIChIQU5ETEUpIGFTZW1hcGhv cmUsIElORklOSVRFKTsNCg0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX2Rvd25fc2VtYSglbHgp IHJldHVybjogJWxcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwobG9uZykgYVNlbWFw aG9yZSwgd2FpdFJlc3VsdCkpOw0KCXJldHVybiAwOw0KfQ0KDQp2b2lkIFB5VGhyZWFkX3VwX3Nl bWEoUHlUaHJlYWRfdHlwZV9zZW1hIGFTZW1hcGhvcmUpDQp7DQoJUmVsZWFzZVNlbWFwaG9yZSgN CiAgICAgICAgICAgICAgICAoSEFORExFKSBhU2VtYXBob3JlLCAgICAgICAgICAgIC8qIEhhbmRs ZSBvZiBzZW1hcGhvcmUgICAgICAgICAgICAgICAgICAgICAgICAgICovDQogICAgICAgICAgICAg ICAgMSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBpbmNyZW1lbnQgY291bnQgYnkg b25lICAgICAgICAgICAgICAgICAgICAgICAqLw0KICAgICAgICAgICAgICAgIE5VTEwpOyAgICAg ICAgICAgICAgICAgICAgICAgICAgLyogbm90IGludGVyZXN0ZWQgaW4gcHJldmlvdXMgY291bnQg ICAgICAgICAgICAgKi8NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgIA0KCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3VwX3NlbWEoJWx4KVxuIiwgUHlUaHJl YWRfZ2V0X3RocmVhZF9pZGVudCgpLCAobG9uZylhU2VtYXBob3JlKSk7DQp9DQoAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAC4vdGhyZWFkX250LmguUEFUQ0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwMDE3 NzcgADAwMDAwMSAAMDAwMDAyIAAwMDAwMDAyNTE1NSAwNzEwNzE3NzQ1MiAwMDc2NzYgAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAKioqIHRocmVhZF9udC5oLk9MRAlTYXQgTWF5IDEzIDAyOjQ3OjAwIDIwMDANCi0t LSB0aHJlYWRfbnQuaAlTYXQgTWF5IDEzIDA3OjAzOjA1IDIwMDANCioqKioqKioqKioqKioqKg0K KioqIDI5LDQwICoqKioNCiAgDQogICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi8NCiAgDQohIC8qIFRoaXMgY29kZSBpbXBs ZW1lbnRlZCBieSBEYWcuR3J1bmVhdUBlbHNhLnByZXNlY28uY29tbS5zZSAqLw0KICANCiAgI2lu Y2x1ZGUgPHdpbmRvd3MuaD4NCiAgI2luY2x1ZGUgPGxpbWl0cy5oPg0KICAjaW5jbHVkZSA8cHJv Y2Vzcy5oPg0KICANCiAgbG9uZyBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KHZvaWQpOw0KICAN CiAgLyoNCi0tLSAyOSw1NSAtLS0tDQogIA0KICAqKioqKioqKioqKioqKioqKioqKioqKioqKioq KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovDQogIA0KISAvKiBPcmlnaW5h bCB2ZXJzaW9uIGJ5IERhZy5HcnVuZWF1QGVsc2EucHJlc2Vjby5jb21tLnNlLiAqLw0KISAvKiBV cGRhdGVkIGZvciBmYXN0ZXIgbG9ja2luZyBieSBhbGFua0BhbGdpbnRlY2guY29tIDEyIE1heSAw MC4gKi8NCiAgDQorICNkZWZpbmUgV0lOMzJfTEVBTl9BTkRfTUVBTiAvKiBleGNsdWRlIHJhcmVs eSB1c2VkIGluY2x1ZGUgZmlsZXMgKi8NCiAgI2luY2x1ZGUgPHdpbmRvd3MuaD4NCiAgI2luY2x1 ZGUgPGxpbWl0cy5oPg0KICAjaW5jbHVkZSA8cHJvY2Vzcy5oPg0KICANCisgI2luY2x1ZGUgIm15 bWFsbG9jLmgiIC8qIGZvciBQeU1lbV9ORVcoKSBhbmQgUHlNZW1fREVMKCkgKi8NCisgDQorIC8q I2RlZmluZSBQWV9ERUJVR19OVF9USFJFQURTKi8NCisgDQorICNpZmRlZiBQWV9ERUJVR19OVF9U SFJFQURTDQorICMgdW5kZWYgZHByaW50Zg0KKyAjIGRlZmluZSBkcHJpbnRmKGFyZ3MpIChwcmlu dGYgYXJncykNCisgIyBpZm5kZWYgUHlfREVCVUcNCisgIyAgZGVmaW5lIFB5X0RFQlVHDQorICMg ZW5kaWYNCisgI2VuZGlmDQorIA0KKyANCiAgbG9uZyBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50 KHZvaWQpOw0KICANCiAgLyoNCioqKioqKioqKioqKioqKg0KKioqIDEyNywyMDEgKioqKg0KICAj ZW5kaWYgLyogTk9fRVhJVF9QUk9HICovDQogIA0KICAvKg0KISAgKiBMb2NrIHN1cHBvcnQuIEl0 IGhhcyB0b28gYmUgaW1wbGVtZW50ZWQgYXMgc2VtYXBob3Jlcy4NCiEgICogSSBbRGFnXSB0cmll ZCB0byBpbXBsZW1lbnQgaXQgd2l0aCBtdXRleCBidXQgSSBjb3VsZCBmaW5kIGEgd2F5IHRvDQoh ICAqIHRlbGwgd2hldGhlciBhIHRocmVhZCBhbHJlYWR5IG93biB0aGUgbG9jayBvciBub3QuDQog ICAqLw0KICBQeVRocmVhZF90eXBlX2xvY2sgUHlUaHJlYWRfYWxsb2NhdGVfbG9jayh2b2lkKQ0K ICB7DQohIAlIQU5ETEUgYUxvY2s7DQogIA0KLSAJZHByaW50ZigoIlB5VGhyZWFkX2FsbG9jYXRl X2xvY2sgY2FsbGVkXG4iKSk7DQogIAlpZiAoIWluaXRpYWxpemVkKQ0KICAJCVB5VGhyZWFkX2lu aXRfdGhyZWFkKCk7DQogIA0KISAJCWFMb2NrID0gQ3JlYXRlU2VtYXBob3JlKE5VTEwsICAgICAg ICAgICAvKiBTZWN1cml0eSBhdHRyaWJ1dGVzICAgICAgICAgICovDQohICAgICAgICAgICAgICAg ICAgICAgICAgICAxLCAgICAgICAgICAgICAgICAgICAgIC8qIEluaXRpYWwgdmFsdWUgICAgICAg ICAgICAgICAgKi8NCiEgICAgICAgICAgICAgICAgICAgICAgICAgIDEsICAgICAgICAgICAgICAg ICAgICAgLyogTWF4aW11bSB2YWx1ZSAgICAgICAgICAgICAgICAqLw0KISAgICAgICAgICAgICAg ICAgICAgICAgICAgTlVMTCk7ICAgICAgIA0KISAgIC8qIE5hbWUgb2Ygc2VtYXBob3JlICAgICAg ICAgICAgKi8NCiAgDQohIAlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9hbGxvY2F0ZV9sb2NrKCkg LT4gJWx4XG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksIChsb25nKWFMb2NrKSk7DQog IA0KISAJcmV0dXJuIChQeVRocmVhZF90eXBlX2xvY2spIGFMb2NrOw0KICB9DQogIA0KICB2b2lk IFB5VGhyZWFkX2ZyZWVfbG9jayhQeVRocmVhZF90eXBlX2xvY2sgYUxvY2spDQogIHsNCiAgCWRw cmludGYoKCIlbGQ6IFB5VGhyZWFkX2ZyZWVfbG9jayglbHgpIGNhbGxlZFxuIiwgUHlUaHJlYWRf Z2V0X3RocmVhZF9pZGVudCgpLChsb25nKWFMb2NrKSk7DQogIA0KISAJQ2xvc2VIYW5kbGUoKEhB TkRMRSkgYUxvY2spOw0KICB9DQogIA0KICAvKg0KICAgKiBSZXR1cm4gMSBvbiBzdWNjZXNzIGlm IHRoZSBsb2NrIHdhcyBhY3F1aXJlZA0KICAgKg0KISAgKiBhbmQgMCBpZiB0aGUgbG9jayB3YXMg bm90IGFjcXVpcmVkLiBUaGlzIG1lYW5zIGEgMCBpcyByZXR1cm5lZA0KISAgKiBpZiB0aGUgbG9j ayBoYXMgYWxyZWFkeSBiZWVuIGFjcXVpcmVkIGJ5IHRoaXMgdGhyZWFkIQ0KICAgKi8NCiAgaW50 IFB5VGhyZWFkX2FjcXVpcmVfbG9jayhQeVRocmVhZF90eXBlX2xvY2sgYUxvY2ssIGludCB3YWl0 ZmxhZykNCiAgew0KICAJaW50IHN1Y2Nlc3MgPSAxOw0KISAJRFdPUkQgd2FpdFJlc3VsdDsNCiEg DQohIAlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9hY3F1aXJlX2xvY2soJWx4LCAlZCkgY2FsbGVk XG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksKGxvbmcpYUxvY2ssIHdhaXRmbGFnKSk7 DQohIA0KISAJd2FpdFJlc3VsdCA9IFdhaXRGb3JTaW5nbGVPYmplY3QoKEhBTkRMRSkgYUxvY2ss ICh3YWl0ZmxhZyA9PSAxID8gSU5GSU5JVEUgOiAwKSk7DQogIA0KISAJaWYgKHdhaXRSZXN1bHQg IT0gV0FJVF9PQkpFQ1RfMCkgew0KISAJCXN1Y2Nlc3MgPSAwOyAgICAvKiBXZSBmYWlsZWQgKi8N CiAgCX0NCiAgDQohIAlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9hY3F1aXJlX2xvY2soJWx4LCAl ZCkgLT4gJWRcbiIsIFB5VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwobG9uZylhTG9jaywgd2Fp dGZsYWcsIHN1Y2Nlc3MpKTsNCiAgDQogIAlyZXR1cm4gc3VjY2VzczsNCiAgfQ0KICANCiAgdm9p ZCBQeVRocmVhZF9yZWxlYXNlX2xvY2soUHlUaHJlYWRfdHlwZV9sb2NrIGFMb2NrKQ0KICB7DQoh IAlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9yZWxlYXNlX2xvY2soJWx4KSBjYWxsZWRcbiIsIFB5 VGhyZWFkX2dldF90aHJlYWRfaWRlbnQoKSwobG9uZylhTG9jaykpOw0KICANCiEgCWlmICghUmVs ZWFzZVNlbWFwaG9yZSgNCiEgICAgICAgICAgICAgICAgICAgICAgICAgKEhBTkRMRSkgYUxvY2ss ICAgICAgICAgICAgICAgICAgICAgICAgIC8qIEhhbmRsZSBvZiBzZW1hcGhvcmUgICAgICAgICAg ICAgICAgICAgICAgICAgICovDQohICAgICAgICAgICAgICAgICAgICAgICAgIDEsICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBpbmNyZW1lbnQgY291bnQgYnkgb25lICAg ICAgICAgICAgICAgICAgICAgICAqLw0KISAgICAgICAgICAgICAgICAgICAgICAgICBOVUxMKSkg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogbm90IGludGVyZXN0ZWQgaW4gcHJl dmlvdXMgY291bnQgICAgICAgICAgICAgKi8NCiEgCQl7DQohIAkJZHByaW50ZigoIiVsZDogQ291 bGQgbm90IFB5VGhyZWFkX3JlbGVhc2VfbG9jayglbHgpIGVycm9yOiAlbFxuIiwgUHlUaHJlYWRf Z2V0X3RocmVhZF9pZGVudCgpLCAobG9uZylhTG9jaywgR2V0TGFzdEVycm9yKCkpKTsNCiAgCQl9 DQogIH0NCiAgDQogIC8qDQohICAqIFNlbWFwaG9yZSBzdXBwb3J0Lg0KICAgKi8NCiAgUHlUaHJl YWRfdHlwZV9zZW1hIFB5VGhyZWFkX2FsbG9jYXRlX3NlbWEoaW50IHZhbHVlKQ0KICB7DQotLS0g MTQyLDM2OSAtLS0tDQogICNlbmRpZiAvKiBOT19FWElUX1BST0cgKi8NCiAgDQogIC8qDQohICAq IFdpbjMyIGxvY2sgc3VwcG9ydC4NCiEgICogDQohICAqIEltcGxlbWVudCB1c2luZyBDUFUgc3Bp biBsb2NrcyBpbnN0ZWFkIG9mIGtlcm5lbCBjYWxscywNCiEgICogZm9yIHNwZWVkLg0KISAgKg0K ISAgKiAxMiBNYXkgMDAgYWxhbmtAYWxnaW50ZWNoLmNvbQ0KICAgKi8NCisgDQorIC8qIElubGlu ZSBvbiBJbnRlbCBwcm9jZXNzb3JzICovDQorICNpZmRlZiBfTV9JWDg2DQorICMgZGVmaW5lIElu dGVybG9ja2VkRXhjaGFuZ2UgSW50ZXJsb2NrZWRFeGNoYW5nZTM4Ng0KKyBfaW5saW5lIExPTkcg SW50ZXJsb2NrZWRFeGNoYW5nZTM4NihQTE9ORyBwbFRhcmdldCwgTE9ORyBsVmFsKQ0KKyB7DQor IAkJX19hc20gbW92IGVheCwgbFZhbA0KKyAJCV9fYXNtIG1vdiBlYngsIFtwbFRhcmdldF0NCisg CQlfX2FzbSBsb2NrIHhjaGcgZWF4LCBbZWJ4XSAgIC8qIEJhbSEgKi8NCisgCQlfX2FzbSBtb3Yg bFZhbCwgZWF4DQorIAkJcmV0dXJuIGxWYWw7DQorIH0NCisgI2VuZGlmIC8qIF9NX0lYODYgKi8N CisgDQorIC8qIEdyYWIgdGhlIHNwaW4gbG9jaywgeWllbGRpbmcgdGhlIENQVSBpZiBidXN5ICov DQorIC8qIE9uIG9kZC1udW1iZXJlZCBhdHRlbXB0cyAwLDwxPiwyLDwzPiwuLiBleHBsaWNpdGx5 IHlpZWxkIGZvciBoeXN0ZXJlc2lzICovDQorIC8qIHBlciBCaWxsIFR1dHQgKi8NCisgI2RlZmlu ZSBQWUdSQUJXMzJMT0NLKHB3MzIsIGN1cnRocmVhZCwgbGFiZWwpIFwNCisgbGFiZWw6IGxCdXN5 ID0gSW50ZXJsb2NrZWRFeGNoYW5nZSgoUExPTkcpJihwdzMyKS0+bV9sQnVzeSwgKGN1cnRocmVh ZCkpOyBcDQorIAlpZiAobEJ1c3kgIT0gMCkgeyBTbGVlcChkd1NsZWVwKTsgZHdTbGVlcCA9ICFk d1NsZWVwOyBnb3RvIGxhYmVsOyB9DQorIA0KKyAvKiBGcmVlIHRoZSBzcGluIGxvY2sgKi8NCisg I2RlZmluZSBQWVJFTEVBU0VXMzJMT0NLKHB3MzIpIFwNCisgCUludGVybG9ja2VkRXhjaGFuZ2Uo KFBMT05HKSYocHczMiktPm1fbEJ1c3ksIDApOw0KKyANCisgDQorICNkZWZpbmUgUFlfVzMyX0xP Q0tfTUFHSUMgMHhBNUI2REVGRQ0KKyANCisgLyogV2luMzIgbG9jayBzdHJ1Y3R1cmUgKi8NCisg dHlwZWRlZiBzdHJ1Y3Qgew0KKyAJRFdPUkQgbV9kd01hZ2ljOyAvKiBQYXJhbm9pYSB0byBwcmV2 ZW50IGhlYXAgdHJhc2hpbmcgKi8NCisgCXZvbGF0aWxlIExPTkcgbV9sQnVzeTsgLyogUHlXaW4z MkxvY2sgaXMgaW4gdXNlICovDQorIAl2b2xhdGlsZSBMT05HIG1fbExvY2tlZDsgLyogTWFpbiBs b2NrICovDQorIAl2b2xhdGlsZSBMT05HIG1fbldhaXRpbmc7IC8qICMgb2YgdGhyZWFkcyB3YWl0 aW5nIG9uIGxvY2sgKi8NCisgCUhBTkRMRSBtX2hTZW1hcGhvcmU7IC8qIEZvciB3YWl0aW5nIHRo cmVhZHMgKi8NCisgfSBQeVdpbjMyTG9jazsNCisgDQorIA0KKyANCiAgUHlUaHJlYWRfdHlwZV9s b2NrIFB5VGhyZWFkX2FsbG9jYXRlX2xvY2sodm9pZCkNCiAgew0KISAJUHlXaW4zMkxvY2sqIHBX aW4zMkxvY2s7DQogIA0KICAJaWYgKCFpbml0aWFsaXplZCkNCiAgCQlQeVRocmVhZF9pbml0X3Ro cmVhZCgpOw0KICANCiEgCS8qIEFsbG9jYXRlIGFuZCBpbml0aWFsaXplIHRoZSBXaW4zMiBsb2Nr ICovDQohIA0KISAJcFdpbjMyTG9jayA9IFB5TWVtX05FVyhQeVdpbjMyTG9jaywgMSk7DQohIAlw V2luMzJMb2NrLT5tX2R3TWFnaWMgPSBQWV9XMzJfTE9DS19NQUdJQzsNCiEgCXBXaW4zMkxvY2st Pm1fbEJ1c3kgPSAwOw0KISAJcFdpbjMyTG9jay0+bV9sTG9ja2VkID0gMDsNCiEgCXBXaW4zMkxv Y2stPm1fbldhaXRpbmcgPSAwOw0KISAJcFdpbjMyTG9jay0+bV9oU2VtYXBob3JlID0gQ3JlYXRl U2VtYXBob3JlKE5VTEwsDQohIAkJCQkxLCAvKiBpbml0aWFsIHZhbHVlICovIA0KISAJCQkJMSwg LyogbWF4IHZhbHVlICovDQohIAkJCQlOVUxMKTsNCiAgDQohIAlkcHJpbnRmKCgiJWxkOiBQeVRo cmVhZF9hbGxvY2F0ZV9sb2NrKCkgLT4gJWx4XG4iLCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50 KCksIChsb25nKXBXaW4zMkxvY2spKTsNCiAgDQohIAlyZXR1cm4gKFB5VGhyZWFkX3R5cGVfbG9j aykgcFdpbjMyTG9jazsNCiAgfQ0KICANCisgDQogIHZvaWQgUHlUaHJlYWRfZnJlZV9sb2NrKFB5 VGhyZWFkX3R5cGVfbG9jayBhTG9jaykNCiAgew0KKyAJUHlXaW4zMkxvY2sqIHBXaW4zMkxvY2s7 DQorIA0KICAJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfZnJlZV9sb2NrKCVseCkgY2FsbGVkXG4i LCBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCksKGxvbmcpYUxvY2spKTsNCiAgDQohIAlwV2lu MzJMb2NrID0gKFB5V2luMzJMb2NrKilhTG9jazsNCiEgDQohIAkvKiBBc3NlcnQ6IHRoZSBsb2Nr IGlzIG5vdCBhbHJlYWR5IGZyZWVkICovDQohIAlpZiAocFdpbjMyTG9jay0+bV9kd01hZ2ljICE9 IFBZX1czMl9MT0NLX01BR0lDKSB7DQohIAkJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfZnJlZV9s b2NrKCVseCkgdHJpZWQgdG8gZnJlZSBhIGZyZWVkIGxvY2shXG4iLCBQeVRocmVhZF9nZXRfdGhy ZWFkX2lkZW50KCksKGxvbmcpYUxvY2spKTsNCiEgCQlyZXR1cm47DQohIAl9DQohIA0KISAJLyog QXNzZXJ0OiB0aGUgbG9jayBpcyBub3QgaW4gdXNlICovDQohIAlpZiAocFdpbjMyTG9jay0+bV9s TG9ja2VkICE9IDApIHsNCiEgCQlkcHJpbnRmKCgiJWxkOiBQeVRocmVhZF9mcmVlX2xvY2soJWx4 KSB0cmllZCB0byBmcmVlIGEgYnVzeSBsb2NrIG93bmVkIGJ5ICVsZCFcbiIsIFB5VGhyZWFkX2dl dF90aHJlYWRfaWRlbnQoKSwobG9uZylhTG9jaywgcFdpbjMyTG9jay0+bV9sTG9ja2VkKSk7DQoh IAkJLyogRmFsbCB0aHJvdWdoIGFuZCBraWxsIHRoZSBsb2NrICovDQohIAl9DQohIA0KISAJcFdp bjMyTG9jay0+bV9kd01hZ2ljID0gMDsNCiEgCUNsb3NlSGFuZGxlKHBXaW4zMkxvY2stPm1faFNl bWFwaG9yZSk7DQohIAlwV2luMzJMb2NrLT5tX2hTZW1hcGhvcmUgPSBOVUxMOw0KISAJUHlNZW1f REVMKHBXaW4zMkxvY2spOw0KICB9DQogIA0KKyANCiAgLyoNCiAgICogUmV0dXJuIDEgb24gc3Vj Y2VzcyBpZiB0aGUgbG9jayB3YXMgYWNxdWlyZWQNCisgICogYW5kIDAgaWYgdGhlIGxvY2sgd2Fz IG5vdCBhY3F1aXJlZC4gSWYgdGhlIGxvY2sgaXMgYWxyZWFkeQ0KKyAgKiBhY3F1aXJlZCBieSBv dXIgdGhyZWFkLCByZXR1cm4gMC4gIFRoZSBjYWxsZXJzIGFzc3VtZSBzZW1hbnRpY3MNCisgICog dGhhdCByZWN1cnNpdmUgbG9ja3MgYnkgdGhlIHNhbWUgdGhyZWFkIHNob3VsZCBibG9jaywNCisg ICogaS5lLiwgdGhleSBhc3N1bWUgaXQgYWN0cyBsaWtlIGEgc2VtYXBob3JlLCBub3QgbGlrZSBh IGNyaXRpY2FsIHNlY3Rpb24uDQogICAqDQohICAqIDEyIE1heSAwMCBhbGFua0BhbGdpbnRlY2gu Y29tDQogICAqLw0KICBpbnQgUHlUaHJlYWRfYWNxdWlyZV9sb2NrKFB5VGhyZWFkX3R5cGVfbG9j ayBhTG9jaywgaW50IHdhaXRmbGFnKQ0KICB7DQorIAlQeVdpbjMyTG9jayogcFdpbjMyTG9jazsN CisgCUxPTkcgbEJ1c3k7DQorIAlEV09SRCBkd1NsZWVwID0gMDsNCiAgCWludCBzdWNjZXNzID0g MTsNCiEgI2lmZGVmIFB5X0RFQlVHDQohIAlMT05HIGxDdXJyZW50VGhyZWFkSWQgPSBQeVRocmVh ZF9nZXRfdGhyZWFkX2lkZW50KCk7DQohICNlbmRpZg0KISANCiEgCWRwcmludGYoKCIlbGQ6IFB5 VGhyZWFkX2FjcXVpcmVfbG9jayglbHgsICVkKSBjYWxsZWRcbiIsIGxDdXJyZW50VGhyZWFkSWQs IChsb25nKWFMb2NrLCB3YWl0ZmxhZykpOw0KISANCiEgCXBXaW4zMkxvY2sgPSAoUHlXaW4zMkxv Y2sqKWFMb2NrOw0KISANCiEgCS8qIEFzc2VydDogdGhlIGxvY2sgaXMgbm90IGZyZWVkICovDQoh IAlpZiAocFdpbjMyTG9jay0+bV9kd01hZ2ljICE9IFBZX1czMl9MT0NLX01BR0lDKSB7DQohIAkJ ZHByaW50ZigoIiVsZDogUHlUaHJlYWRfYWNxdWlyZV9sb2NrKCVseCkgdHJpZWQgdG8gYWNxdWly ZSBhIGZyZWVkIGxvY2shXG4iLCBsQ3VycmVudFRocmVhZElkLCAobG9uZylhTG9jaykpOw0KISAJ CXJldHVybiAwOw0KISAJfQ0KICANCiEgYWdhaW46IA0KISAJLyogU3BpbiBvbiB0aGUgcFdpbjMy TG9jayBzdHJ1Y3QgKi8NCiEgCVBZR1JBQlczMkxPQ0socFdpbjMyTG9jaywgMSwgbG9jazEpOw0K ISANCiEgCWlmICghcFdpbjMyTG9jay0+bV9sTG9ja2VkKSB7IC8qIFdlIGdvdCBpdCEgKi8NCiEg CQkvKiBHcmFiIHRoZSBsb2NrICovDQohIAkJcFdpbjMyTG9jay0+bV9sTG9ja2VkID0gMTsgLyog dm9sYXRpbGUgKi8NCiEgCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxvY2spOw0KISAJfSBlbHNl IHsgLyogQWxyZWFkeSBsb2NrZWQgKi8NCiEgCQlpZiAoIXdhaXRmbGFnKSB7IC8qIFBvbGwgZmFp bGVkLCBiYWlsICovDQohIAkJCVBZUkVMRUFTRVczMkxPQ0socFdpbjMyTG9jayk7DQohIAkJCXN1 Y2Nlc3MgPSAwOw0KISAJCX0gZWxzZSB7IC8qIERyYXQsIHdlIG5lZWQgdG8gYmxvY2sgKi8NCiEg CQkJRFdPUkQgZHdXYWl0UmVzdWx0Ow0KISANCiEgCQkJLyogVGVsbCB0aGUgbG9jayBob2xkZXIg dG8gUmVsZWFzZVNlbWFwaG9yZSgpICovDQohIAkJCSsrKHBXaW4zMkxvY2stPm1fbldhaXRpbmcp OyAvKiB2b2xhdGlsZSAqLw0KISAJCQlQWVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxvY2spOw0KISAN CiEgCQkJZHByaW50ZigoIiVsZDogUHlUaHJlYWRfYWNxdWlyZV9sb2NrKCVseCkgYmxvY2tpbmcg b24gbG9jayBoZWxkIGJ5ICVsZFxuIiwgbEN1cnJlbnRUaHJlYWRJZCwgYUxvY2ssIHBXaW4zMkxv Y2stPm1fbExvY2tlZCkpOw0KISANCiEgCQkJLyogQmxvY2sgdW50aWwgUmVsZWFzZVNlbWFwaG9y ZSgpICovDQohIAkJCWR3V2FpdFJlc3VsdCA9IFdhaXRGb3JTaW5nbGVPYmplY3QocFdpbjMyTG9j ay0+bV9oU2VtYXBob3JlLA0KISAJCQkJSU5GSU5JVEUpOw0KISANCiEgCQkJLyogVHVybiBvZmYg UmVsZWFzZVNlbWFwaG9yZSgpLiAgTXVzdCBiZQ0KISAJCQkgICBkb25lIGNhcmVmdWxseSB0byBh dm9pZCByYWNlcy4gKi8NCiEgCQkJUFlHUkFCVzMyTE9DSyhwV2luMzJMb2NrLCAxLCBsb2NrMik7 DQohIAkJCS0tKHBXaW4zMkxvY2stPm1fbldhaXRpbmcpOyAvKiB2b2xhdGlsZSAqLw0KISAJCQlQ WVJFTEVBU0VXMzJMT0NLKHBXaW4zMkxvY2spOw0KISANCiEgCQkJaWYgKGR3V2FpdFJlc3VsdCAh PSBXQUlUX09CSkVDVF8wKSB7DQohIAkJCQlzdWNjZXNzID0gMDsgLyogU2VtYXBob3JlIGNsb3Nl ZCwgYmFpbCAqLw0KISAJCQl9IGVsc2Ugew0KISAJCQkJZ290byBhZ2FpbjsgLyogRmlnaHQgZm9y IHRoZSBsb2NrIGFnYWluICovDQohIAkJCX0NCiEgCQl9DQogIAl9DQogIA0KISAJZHByaW50Zigo IiVsZDogUHlUaHJlYWRfYWNxdWlyZV9sb2NrKCVseCwgJWQpIC0+ICVkXG4iLA0KISAJCQlsQ3Vy cmVudFRocmVhZElkLChsb25nKWFMb2NrLCB3YWl0ZmxhZywgc3VjY2VzcykpOw0KICANCiAgCXJl dHVybiBzdWNjZXNzOw0KICB9DQogIA0KKyANCisgLyoNCisgICogUmVsZWFzZSB0aGUgbG9jay4g IENhbGwgUmVsZWFzZVNlbWFwaG9yZSgpIGlmIGFuZCBvbmx5IGlmIGFub3RoZXIgdGhyZWFkDQor ICAqIGlzIHdhaXRpbmcuDQorICAqIA0KKyAgKiAxMiBNYXkgMDAgYWxhbmtAYWxnaW50ZWNoLmNv bQ0KKyAgKi8NCiAgdm9pZCBQeVRocmVhZF9yZWxlYXNlX2xvY2soUHlUaHJlYWRfdHlwZV9sb2Nr IGFMb2NrKQ0KICB7DQohIAlQeVdpbjMyTG9jayogcFdpbjMyTG9jazsNCiEgCUxPTkcgbEJ1c3k7 DQohIAlEV09SRCBkd1NsZWVwID0gMDsNCiEgI2lmZGVmIFB5X0RFQlVHDQohIAlMT05HIGxDdXJy ZW50VGhyZWFkSWQgPSBQeVRocmVhZF9nZXRfdGhyZWFkX2lkZW50KCk7DQohICNlbmRpZg0KISAN CiEgCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3JlbGVhc2VfbG9jayglbHgpIGNhbGxlZFxuIiwg bEN1cnJlbnRUaHJlYWRJZCwgKGxvbmcpYUxvY2spKTsNCiEgDQohIAlwV2luMzJMb2NrID0gKFB5 V2luMzJMb2NrKilhTG9jazsNCiEgDQohIAkvKiBBc3NlcnQ6IHRoZSBsb2NrIGlzIG5vdCBmcmVl ZCAqLw0KISAJaWYgKHBXaW4zMkxvY2stPm1fZHdNYWdpYyAhPSBQWV9XMzJfTE9DS19NQUdJQykg ew0KISAJCWRwcmludGYoKCIlbGQ6IFB5VGhyZWFkX3JlbGVhc2VfbG9jayglbHgpIHRyaWVkIHRv IHJlbGVhc2UgYSBmcmVlZCBsb2NrIVxuIiwgbEN1cnJlbnRUaHJlYWRJZCwgKGxvbmcpYUxvY2sp KTsNCiEgCQlyZXR1cm47DQohIAl9DQogIA0KISAJUFlHUkFCVzMyTE9DSyhwV2luMzJMb2NrLCAx LCBsb2NrMSk7DQohIA0KISAJaWYgKCFwV2luMzJMb2NrLT5tX2xMb2NrZWQpIHsNCiEgCSAgICAJ LyogVGhlIGxvY2sgd2FzIG5vdCBhY3F1aXJlZCBpbiB0aGUgZmlyc3QgcGxhY2UsIGh1bW0uLiAq Lw0KISAJCVBZUkVMRUFTRVczMkxPQ0socFdpbjMyTG9jayk7DQohIAkJZHByaW50ZigoIiVsZDog UHlUaHJlYWRfcmVsZWFzZV9sb2NrKCVseCkgdHJpZWQgdG8gcmVsZWFzZSBhIGxvY2sgdGhhdCB3 YXMgbm90IGFjcXVpcmVkIVxuIiwgbEN1cnJlbnRUaHJlYWRJZCwgKGxvbmcpYUxvY2spKTsNCiEg CX0gZWxzZSB7DQohIAkJLyogUmVsZWFzZSB0aGUgbG9jayAqLw0KISAJCXBXaW4zMkxvY2stPm1f bExvY2tlZCA9IDA7IC8qIHZvbGF0aWxlICovDQohIA0KISAJCWlmIChwV2luMzJMb2NrLT5tX25X YWl0aW5nKSB7IC8qIElmIHRocmVhZHMgYXJlIHdhaXRpbmcgKi8NCiEgCQkJUFlSRUxFQVNFVzMy TE9DSyhwV2luMzJMb2NrKTsNCiEgCQkJLyogVW5ibG9jayBvbmUgd2FpdGluZyB0aHJlYWQgKi8N CiEgCQkJUmVsZWFzZVNlbWFwaG9yZShwV2luMzJMb2NrLT5tX2hTZW1hcGhvcmUsIDEsIE5VTEwp Ow0KISAJCX0gZWxzZSB7DQohIAkJCVBZUkVMRUFTRVczMkxPQ0socFdpbjMyTG9jayk7DQogIAkJ fQ0KKyAJfQ0KKyAJcmV0dXJuOw0KICB9DQogIA0KKyANCiAgLyoNCiEgICogU2VtYXBob3JlIHN1 cHBvcnQgKG5vdCBjdXJyZW50bHkgdXNlZCkuDQogICAqLw0KICBQeVRocmVhZF90eXBlX3NlbWEg UHlUaHJlYWRfYWxsb2NhdGVfc2VtYShpbnQgdmFsdWUpDQogIHsNCgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== ------=_NextPart_000_000F_01BFBC80.8A0914F0-- From tim_one@email.msn.com Sat May 13 08:23:55 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 03:23:55 -0400 Subject: [Patches] printf("%lx") -> printf("%p") for pointers : win64 cares In-Reply-To: <20000512234115.B6689@activestate.com> Message-ID: <000501bfbcac$329b5260$3f2d153f@tim> [Trent Mick] > Do you have a suggestion for a good ANSI/ISO C reference? The sad truth is hinted at here (among many other places; this is just the first FAQ reference I hit): http://www.eskimo.com/~scs/C-faq/q11.2.html ISO and ANSI derive a lot of income from selling standards, and ISO in particular refuses to make any standard available over the web until it's obsolete. And there's really no substitute for having the actual standard in hand. Expect to fork out a few hundred bucks for a current "big" ISO standard. > It might more efficient for me to read these things than me > playing, making patches, and having you teach me through > comments on my patch. :) It would actually be more efficient for *me* -- standards are written in a strange language that only looks like English until you try to understand them. I only know this stuff because I worked on a C compiler in a previous life. > ... > Given that %p is "implementation defined" do you see this patch > going in I'd put it in, if I were Guido. > or will I have to #ifdef in %p usage for Win64 only until > the magical C95 (is that what it will be called? Another irritating possibility is to write your own function to convert a void* to a hex string. Then the #ifdef'ing would be needed only inside that. > ... > Actually, will the next C standard define output for a pointer > printf formatter. Doubt it, but don't know. I haven't worked on a C compiler in over 5 years, and I certainly don't spend my own money on C standards <0.5 wink>. From tim_one@email.msn.com Sat May 13 09:08:53 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 04:08:53 -0400 Subject: [Patches] introducing math.rint In-Reply-To: <200005121518.LAA07320@eric.cnri.reston.va.us> Message-ID: <000801bfbcb2$7b29c9c0$3f2d153f@tim> [Guido, about rint] > Not to worry, I've already added the necessary magic to the configure > script. Are you sure you want to? While I expect that the existence of some functions in the OS module depends on the platform, I'm really dubious about extending that to other modules, and it's especially dubious in a module like math. I learned today that Windows doesn't support "rint" either -- this is a function that apparently exists (at least under that name) only on some unknown subset of Unix derivatives. > (PS Tim, did you get a chance to look at the second installment of the > cmarh.acosh/asinh patches?) No, it's way back in my inbox, and I don't expect to get to it this month. However, if I had the hours it would take to look at this carefully, I would probably conclude that all the complex transcendentals suffer deep numeric problems (the ones I looked at so far are certainly fragile as eggshells!). On that basis, if the new patch isn't obviously broken, it's probably no worse than what it's replacing, and at least one motivated user thinks it's a lot better <0.5 wink>. From fw@deneb.cygnus.argh.org Sat May 13 10:53:03 2000 From: fw@deneb.cygnus.argh.org (Florian Weimer) Date: 13 May 2000 11:53:03 +0200 Subject: [Patches] Update for top-level README file Message-ID: <87aehuwzcw.fsf@deneb.cygnus.argh.org> --=-=-= The top-level README file contains outdated information on reporting bugs. I replaced it with instructions from the Python web site. (No Contribution Release Form here because the information is probably copyrighted by the python.org webmaster, and not by me.) --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=python-readme.diff Index: README =================================================================== RCS file: /projects/cvsroot/python/dist/src/README,v retrieving revision 1.85 diff -u -r1.85 README --- README 2000/04/11 17:11:09 1.85 +++ README 2000/05/13 09:40:27 @@ -725,11 +725,18 @@ Bug reports ----------- -Bugs are best reported to the comp.lang.python newsgroup (or the -Python mailing list) -- see the section "Newsgroups" above. Before -posting, check the newsgroup archives (see above) to see if your bug -has already been reported! If you don't want to go public, send them -to me: . +Bugs are best reported by filling out the web form at: + + http://www.python.org/python-bugs?newbug=1 + +Before reporting a bug, please read the advice at: + + http://www.python.org/search/search_bugs.html + +If you can't use the web bug submission form, mail your bugs to +bugs-py@python.org. Please include the following information in the +body of your email: your email address; your full name; the Python +version you're using; the operating system you're using; a detailed Questions --=-=-=-- From fw@deneb.cygnus.argh.org Sat May 13 10:49:56 2000 From: fw@deneb.cygnus.argh.org (Florian Weimer) Date: 13 May 2000 11:49:56 +0200 Subject: [Patches] Objects/unicodeobject.c(PyUnicode_DecodeUTF8): Fix error handling Message-ID: <87em76wzi3.fsf@deneb.cygnus.argh.org> --=-=-= The attached patch fixes error handling and improves the treatment of invalid characters in "replace" mode. Now, an incomplete or otherwise invalid UTF-8 sequence generates exactly one replacement character. As a result, the Python UTF-8 decoder now passes Markus Kuhn's UTF-8 stress test. 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. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=python-utf8.diff Index: unicodeobject.c =================================================================== RCS file: /projects/cvsroot/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/05/13 09:32:13 @@ -582,7 +582,8 @@ #define UTF8_ERROR(details) do { \ if (utf8_decoding_error(&s, &p, errors, details)) \ goto onError; \ - continue; \ + else \ + goto nextCharacter; \ } while (0) PyObject *PyUnicode_DecodeUTF8(const char *s, @@ -631,31 +632,48 @@ break; case 2: - if ((s[1] & 0xc0) != 0x80) + if ((s[1] & 0xc0) != 0x80) { UTF8_ERROR("invalid data"); + } ch = ((s[0] & 0x1f) << 6) + (s[1] & 0x3f); - if (ch < 0x80) + if (ch < 0x80) { + /* Skip rest of this sequence. */ + s++; UTF8_ERROR("illegal encoding"); - else + } else *p++ = ch; break; case 3: if ((s[1] & 0xc0) != 0x80 || - (s[2] & 0xc0) != 0x80) + (s[2] & 0xc0) != 0x80) { + /* Skip character which likely belongs to this sequence. */ + if ((s[1] & 0xc0) == 0x80) { + s++; + } UTF8_ERROR("invalid data"); + } ch = ((s[0] & 0x0f) << 12) + ((s[1] & 0x3f) << 6) + (s[2] & 0x3f); - if (ch < 0x800 || (ch >= 0xd800 && ch < 0xe000)) + if (ch < 0x800 || (ch >= 0xd800 && ch < 0xe000)) { + /* Skip rest of this sequence. */ + s += 2; UTF8_ERROR("illegal encoding"); - else + } else *p++ = ch; break; default: /* Other sizes are only needed for UCS-4 */ - UTF8_ERROR("unsupported Unicode code range"); + /* Skip over these characters. */ + s++; + while (s < e && ((*s & 0xc0) == 0x80)) s++; + /* UTF8_ERROR will skip one character. */ + s--; + UTF8_ERROR("unsupported Unicode code range"); } s += n; + + nextCharacter: } /* Adjust length */ --=-=-=-- From mal@lemburg.com Sat May 13 11:17:42 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sat, 13 May 2000 12:17:42 +0200 Subject: [Patches] getpath patch Message-ID: <391D2BC6.95E4FD3E@lemburg.com> Patch Set Contents: ------------------- Modules/getpath.c: Landmark changed to os.py. Setting PYTHONHOME now unconditionally sets sys.prefix (and sys.exec_prefix). No further checks are done whether the standard lib can be found in that location or not. This is in sync with the PC subdir getpath implementations. PC/getpathp.c: Landmark changed to os.py. PC/os2vacpp/getpathp.c: Landmark changed to os.py. -- Note: Python will dump core if it cannot find the exceptions module. Perhaps we should add a builtin _exceptions module (basically a frozen exceptions.py) which is then used as fallback solution ?! _____________________________________________________________________ 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/ From mal@lemburg.com Sat May 13 11:19:13 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sat, 13 May 2000 12:19:13 +0200 Subject: [Patches] getpath patch References: <391D2BC6.95E4FD3E@lemburg.com> Message-ID: <391D2C21.598AE6EC@lemburg.com> This is a multi-part message in MIME format. --------------D80529A8D764084264ADC2DC Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Forgot the attachment... -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ --------------D80529A8D764084264ADC2DC Content-Type: text/plain; charset=us-ascii; name="getpath.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="getpath.patch" diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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/getpath.c Python+Unicode/Modules/getpath.c --- CVS-Python/Modules/getpath.c Mon May 8 15:13:50 2000 +++ Python+Unicode/Modules/getpath.c Sat May 13 11:20:32 2000 @@ -87,7 +87,7 @@ * Modules/Setup. If the landmark is found, we're done. * * For the remaining steps, the prefix landmark will always be - * lib/python$VERSION/string.py and the exec_prefix will always be + * lib/python$VERSION/os.py and the exec_prefix will always be * lib/python$VERSION/lib-dynload, where $VERSION is Python's version * number as supplied by the Makefile. Note that this means that no more * build directory checking is performed; if the first step did not find @@ -150,7 +150,7 @@ #endif #ifndef LANDMARK -#define LANDMARK "string.py" +#define LANDMARK "os.py" #endif static char prefix[MAXPATHLEN+1]; @@ -265,6 +265,18 @@ int n; char *vpath; + /* If PYTHONHOME is set, we believe it unconditionally */ + if (home) { + char *delim; + strcpy(prefix, home); + delim = strchr(prefix, DELIM); + if (delim) + *delim = '\0'; + joinpath(prefix, lib_python); + joinpath(prefix, LANDMARK); + return 1; + } + /* Check to see if argv[0] is in the build directory */ strcpy(prefix, argv0_path); joinpath(prefix, "Modules/Setup"); @@ -290,19 +302,6 @@ return -1; } - if (home) { - /* Check $PYTHONHOME */ - char *delim; - strcpy(prefix, home); - delim = strchr(prefix, DELIM); - if (delim) - *delim = '\0'; - joinpath(prefix, lib_python); - joinpath(prefix, LANDMARK); - if (ismodule(prefix)) - return 1; - } - /* Search from argv0_path, until root is found */ strcpy(prefix, argv0_path); do { @@ -334,16 +333,8 @@ { int n; - /* Check to see if argv[0] is in the build directory */ - strcpy(exec_prefix, argv0_path); - joinpath(exec_prefix, "Modules/Setup"); - if (isfile(exec_prefix)) { - reduce(exec_prefix); - return -1; - } - + /* If PYTHONHOME is set, we believe it unconditionally */ if (home) { - /* Check $PYTHONHOME */ char *delim; delim = strchr(home, DELIM); if (delim) @@ -352,8 +343,15 @@ strcpy(exec_prefix, home); joinpath(exec_prefix, lib_python); joinpath(exec_prefix, "lib-dynload"); - if (isdir(exec_prefix)) return 1; + } + + /* Check to see if argv[0] is in the build directory */ + strcpy(exec_prefix, argv0_path); + joinpath(exec_prefix, "Modules/Setup"); + if (isfile(exec_prefix)) { + reduce(exec_prefix); + return -1; } /* Search from argv0_path, until root is found */ diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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/PC/getpathp.c Python+Unicode/PC/getpathp.c --- CVS-Python/PC/getpathp.c Thu Mar 30 21:45:39 2000 +++ Python+Unicode/PC/getpathp.c Sat May 13 11:07:50 2000 @@ -53,7 +53,7 @@ * We attempt to locate the "Python Home" - if the PYTHONHOME env var is set, we believe it. Otherwise, we use the path of our host .EXE's - to try and locate our "landmark" (lib\\string.py) and deduce our home. + to try and locate our "landmark" (lib\\os.py) and deduce our home. - If we DO have a Python Home: The relevant sub-directories (Lib, plat-win, lib-tk, etc) are based on the Python Home - If we DO NOT have a Python Home, the core Python Path is @@ -110,7 +110,7 @@ */ #ifndef LANDMARK -#define LANDMARK "lib\\string.py" +#define LANDMARK "lib\\os.py" #endif static char prefix[MAXPATHLEN+1]; diff -u -rbP -x *.o -x *.pyc -x Makefile -x *~ -x *.so -x add2lib -x pgen -x buildno -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/PC/os2vacpp/getpathp.c Python+Unicode/PC/os2vacpp/getpathp.c --- CVS-Python/PC/os2vacpp/getpathp.c Mon Jul 27 15:49:04 1998 +++ Python+Unicode/PC/os2vacpp/getpathp.c Sat May 13 11:08:02 2000 @@ -68,14 +68,14 @@ * * Otherwise, if there is a PYTHONPATH environment variable, we return that. * - * Otherwise we try to find $progpath/lib/string.py, and if found, then + * Otherwise we try to find $progpath/lib/os.py, and if found, then * root is $progpath/lib, and we return Python path as compiled PYTHONPATH * with all "./lib" replaced by $root (as above). * */ #ifndef LANDMARK -#define LANDMARK "lib\\string.py" +#define LANDMARK "lib\\os.py" #endif static char prefix[MAXPATHLEN+1]; Binary files CVS-Python/core and Python+Unicode/core differ Binary files CVS-Python/core and Python+Unicode/core differ --------------D80529A8D764084264ADC2DC-- From mal@lemburg.com Sat May 13 11:40:04 2000 From: mal@lemburg.com (M.-A. Lemburg) Date: Sat, 13 May 2000 12:40:04 +0200 Subject: [Patches] Objects/unicodeobject.c(PyUnicode_DecodeUTF8): Fix error handling References: <87em76wzi3.fsf@deneb.cygnus.argh.org> Message-ID: <391D3104.E43D0325@lemburg.com> Florian Weimer wrote: > > The attached patch fixes error handling and improves the treatment of > invalid characters in "replace" mode. Now, an incomplete or otherwise > invalid UTF-8 sequence generates exactly one replacement character. > As a result, the Python UTF-8 decoder now passes Markus Kuhn's UTF-8 > stress test. Looks good :-) -- Marc-Andre Lemburg ______________________________________________________________________ Business: http://www.lemburg.com/ Python Pages: http://www.lemburg.com/python/ From Vladimir.Marangozov@inrialpes.fr Sat May 13 17:29:45 2000 From: Vladimir.Marangozov@inrialpes.fr (Vladimir Marangozov) Date: Sat, 13 May 2000 18:29:45 +0200 (CEST) Subject: [Patches] marshalling recursive objects In-Reply-To: <200005121748.NAA07903@eric.cnri.reston.va.us> from "Guido van Rossum" at May 12, 2000 01:48:56 PM Message-ID: <200005131629.SAA03990@python.inrialpes.fr> Guido van Rossum wrote: > > I'm not sure I like it to write different marshalling strings for data > structures that aren't recursive. > > Here's an example: > > >>> a = [] > >>> b = [a,a,a] > >>> marshal.dumps(b) > '[\003\000\000\000[\000\000\000\000o\001\000\000\000o\001\000\000\000' > >>> > > Before your patch, this produced: > > '[\003\000\000\000[\000\000\000\000[\000\000\000\000[\000\000\000\000' > > ... > > I'm not sure how to fix it -- if the easiest solution is to raise an > exception for recursive objects, that's fine. (It's a heck of a lot > better than Memory fault!) Agreed. Both of these can be implemented: 1) Handle recursions by preserving the current rules, i.e. add additional processing for recursions only (the 'o' type). This preserves backwards compatibility, but marshalled recursion objects in the new version won't be readable by older versions. I actually implemented this one. >>> a = [] >>> b = [a,a,a] >>> marshal.dumps(b) '[\003\000\000\000[\000\000\000\000[\000\000\000\000[\000\000\000\000' >>> >>> a.append(b) >>> marshal.dumps(b) '[\003\000\000\000[\001\000\000\000o\000\000\000\000[\001\000\000\000o\000\000\000\000[\001\000\000\000o\000\000\000\000' 2) Remain conservative and raise a "recursive object cannot be marshalled" exception. Which one is better? -- Vladimir MARANGOZOV | Vladimir.Marangozov@inrialpes.fr http://sirac.inrialpes.fr/~marangoz | tel:(+33-4)76615277 fax:76615252 From guido@python.org Sat May 13 21:50:08 2000 From: guido@python.org (Guido van Rossum) Date: Sat, 13 May 2000 16:50:08 -0400 Subject: [Patches] introducing math.rint In-Reply-To: Your message of "Sat, 13 May 2000 04:08:53 EDT." <000801bfbcb2$7b29c9c0$3f2d153f@tim> References: <000801bfbcb2$7b29c9c0$3f2d153f@tim> Message-ID: <200005132050.QAA09179@eric.cnri.reston.va.us> > [Guido, about rint] > > Not to worry, I've already added the necessary magic to the configure > > script. > > Are you sure you want to? While I expect that the existence of some > functions in the OS module depends on the platform, I'm really dubious about > extending that to other modules, and it's especially dubious in a module > like math. I learned today that Windows doesn't support "rint" either -- > this is a function that apparently exists (at least under that name) only on > some unknown subset of Unix derivatives. Peter clearly wants to use rint(). It exists on his platform. Why should we deny it to him? (I added a note to the documentation that it's not available on all platforms.) Also, how hard would it be to provide a reasonable approximation on platforms that don't have it? Assuming the default rounding settings, it seems to round to the nearest integer where if you're exactly halfway it rounds to the nearest *even* integer. I know we can't know the actual IEEE754 rounding mode, but as Python does not provide access to it, it's likely that it's the default mode, right? > > (PS Tim, did you get a chance to look at the second installment of the > > cmarh.acosh/asinh patches?) > > No, it's way back in my inbox, and I don't expect to get to it this month. > However, if I had the hours it would take to look at this carefully, I would > probably conclude that all the complex transcendentals suffer deep numeric > problems (the ones I looked at so far are certainly fragile as eggshells!). > On that basis, if the new patch isn't obviously broken, it's probably no > worse than what it's replacing, and at least one motivated user thinks it's > a lot better <0.5 wink>. Sigh. I'll see what I can do. --Guido van Rossum (home page: http://www.python.org/~guido/) From guido@python.org Sat May 13 22:01:21 2000 From: guido@python.org (Guido van Rossum) Date: Sat, 13 May 2000 17:01:21 -0400 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: Your message of "Sat, 13 May 2000 03:03:27 EDT." <000301bfbca9$5684c560$3f2d153f@tim> References: <000301bfbca9$5684c560$3f2d153f@tim> Message-ID: <200005132101.RAA09195@eric.cnri.reston.va.us> > [Trent Mick] > > ... > > Just had a thought. I suppose that I should use the > > PyFPE_{START|END}_PROTECT > > around the middle block doing the floating point math. Correct? [Tim] > No, assuming the platform frexp never blows up (& it shouldn't, but you > never know what the platform libc does with IEEE oddballs like NaNs and > infinities), there's nothing in the rest of the code that can possibly blow > up. All the operations are well-defined and unexceptional. The worst that > can happen is that the IEEE "inexact" flag will get set -- but that happens > on virtually every fp operation anyway. I didn't write the PyFPE_ patches, but I believe they were done by someone whose experience told him *never* to trust that a FP operation won't raise SIGFPE. He put them around almost anything that manipulates floating point. On the other hand. he left the frexp() call in mathmodule.c alone. --Guido van Rossum (home page: http://www.python.org/~guido/) From bwarsaw@python.org Sat May 13 22:32:58 2000 From: bwarsaw@python.org (Barry A. Warsaw) Date: Sat, 13 May 2000 17:32:58 -0400 (EDT) Subject: [Patches] getpath patch References: <391D2BC6.95E4FD3E@lemburg.com> Message-ID: <14621.51722.55005.715667@anthem.cnri.reston.va.us> >>>>> "M" == M writes: MAL> Note: Python will dump core if it cannot find the exceptions MAL> module. Perhaps we should add a builtin _exceptions module MAL> (basically a frozen exceptions.py) which is then used as MAL> fallback solution ?! That's a good idea. From Fredrik Lundh" Message-ID: <001501bfbd23$cc45e160$34aab5d4@hagrid> MAL wrote: > Note: Python will dump core if it cannot find the exceptions > module. Perhaps we should add a builtin _exceptions module > (basically a frozen exceptions.py) which is then used as > fallback solution ?! or use this one: http://w1.132.telia.com/~u13208596/exceptions.htm From tim_one@email.msn.com Sun May 14 03:38:21 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 22:38:21 -0400 Subject: [Patches] introducing math.rint In-Reply-To: <200005132050.QAA09179@eric.cnri.reston.va.us> Message-ID: <000101bfbd4d$78177d40$3ca2143f@tim> [Guido] > Peter clearly wants to use rint(). It exists on his platform. Why > should we deny it to him? (I added a note to the documentation that > it's not available on all platforms.) The argument against is that it makes writing portable code that much harder; portability in this sense is something a math module user never has to worry about today. "Slippery slope" applies here too: there are dozens and dozens of platform-specific functions that could just as well be added to the math module. For example, I *definitely* want to use _chgsign, _controlfp, _copysign, _finite, _fpclass, _isnan and _nextafter, most of which are recommend by 754 too and all of which are supported directly on *my* platform (that's Windows, today ). Should Python grow all of those too? If yes to rint, why no to any other random platform function? > Also, how hard would it be to provide a reasonable approximation on > platforms that don't have it? I've already posted (Python) code to do that to c.l.py, where Peter started a rint thread. Fredrik has too. Unfortunately, I know of no way to write /F's clever code in C that will generate correct code under all common compilers ("extended precision" will kill it on Intel chips, and overly aggressive optimization on others). > Assuming the default rounding settings, it seems to round to the > nearest integer where if you're exactly halfway it rounds to the > nearest *even* integer. I know we can't know the actual IEEE754 > rounding mode, but as Python does not provide access to it, it's > likely that it's the default mode, right? Extremely likely. It's easy to figure out regardless (just add a few things and look at the result), but, meaning no offense to Peter, he doesn't appear to be aware of any of the subtleties actually embodied by his platform rint. If you force nearest/even, it does not match the platform rint. If you don't force it, it's harder to write, and makes less sense in *Python* because Python provides no means to set rounding mode. The rint I implemented at KSR supported an optional second argument, to specify which of the six behaviors you wanted (i.e., to minus infinity, to plus infinity, to zero, to nearest/even, the non-754 "add a half and chop", or follow the current 754 rounding-mode setting); but this was easy to implement there because the *hardware* supported all six directly! BTW, I'm having a hard time understanding why you're eager to jump into brand new pits when 1.6 is already behind schedule . From tim_one@email.msn.com Sun May 14 03:38:17 2000 From: tim_one@email.msn.com (Tim Peters) Date: Sat, 13 May 2000 22:38:17 -0400 Subject: [Patches] fix hashing take#2 (was: fix float_hash and complex_hash for 64-bit *nix) In-Reply-To: <200005132101.RAA09195@eric.cnri.reston.va.us> Message-ID: <000001bfbd4d$765b7560$3ca2143f@tim> [Guido] > I didn't write the PyFPE_ patches, Well, that one's obvious: a bunch of macros and setjmps and platform #ifdef'ed code to *provoke* an ill-defined signal <0.5 wink>? This whole subsystem is a strained attempt to pretend 754 "never happened", by striving to make every platform pretend it's a particular pre-754 flavor of Unix. The less this spreads, the better . > but I believe they were done by someone whose experience told > him *never* to trust that a FP operation won't raise SIGFPE. He put > them around almost anything that manipulates floating point. Appears to me that all existing uses of PyFPE_START_PROTECT etc bracket code where nothing is known about the input(s), and indeed any exception whatsoever may happen then. But in the hashing code, after frexp we know for certain that the double we're manipulating has absolute value < 1.0, and it's trivially (honest -- this is obvious from inspection) provable a priori that all following operations on that cannot raise any IEEE exception other than "inexact result". So clogging it with macros would bloat the generated code and slow it down while buying nothing in return. From peter@schneider-kamp.de Sun May 14 12:23:40 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Sun, 14 May 2000 13:23:40 +0200 Subject: [Patches] array.{index,count,remove} Message-ID: <391E8CBC.C78DE5A0@stud.ntnu.no> This is a multi-part message in MIME format. --------------1F8F8C92A9D72DEE76E9CB8C Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Problem: 4.17. Implement array.array.{index,remove,count} [tim_one@email.msn.com] array.array objects currently don't support list's index, remove or count methods, but could . Later: array.array doesn't support the new(er) list.pop() either, although that one is still (1.5.2a1) experimental. Edit this entry / Log info / Last changed on Wed Oct 7 18:43:34 1998 by Tim Peters Solution: adapt listindex,listremove and listcount to arrays I chose rather to adapt all three than to build on index 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 --------------1F8F8C92A9D72DEE76E9CB8C Content-Type: text/plain; charset=us-ascii; name="array.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="array.patch" diff -c --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 Sun May 14 12:37:07 2000 *************** *** 67,72 **** --- 67,79 ---- a[1:-1] = a if a != array.array(type, "aabcdee"): raise TestFailed, "array(%s) self-slice-assign (cntr)" % `type` + if a.index("e") != 5: + raise TestFailed, "array(%s) index-test" % `type` + if a.count("a") != 2: + raise TestFailed, "array(%s) count-test" % `type` + a.remove("e") + if a != array.array(type, "aabcde"): + raise TestFailed, "array(%s) remove-test" % `type` else: a = array.array(type, [1, 2, 3, 4, 5]) a[:-1] = a *************** *** 80,85 **** --- 87,99 ---- 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.index(5) != 5: + raise TestFailed, "array(%s) index-test" % `type` + if a.count(1) != 2: + raise TestFailed, "array(%s) count-test" % `type` + a.remove(5) + if a != array.array(type, [1, 1, 2, 3, 4, 5]): + raise TestFailed, "array(%s) remove-test" % `type` main() diff -c --recursive python/dist/src/Modules/arraymodule.c python-mod/dist/src/Modules/arraymodule.c *** python/dist/src/Modules/arraymodule.c Thu May 4 01:44:31 2000 --- python-mod/dist/src/Modules/arraymodule.c Sun May 14 12:23:36 2000 *************** *** 699,704 **** --- 699,784 ---- } 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."; + + 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."; + + static PyObject * + array_remove(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) { + 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."; + + static PyObject * array_insert(self, args) arrayobject *self; PyObject *args; *************** *** 845,924 **** \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 - static PyObject * - array_remove(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) { - 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 * array_fromfile(self, args) arrayobject *self; --- 925,930 ---- *************** *** 1142,1157 **** {"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}, --- 1148,1163 ---- {"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}, {"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}, {"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}, diff -c --recursive python/dist/src/Modules/timemodule.c python-mod/dist/src/Modules/timemodule.c *** python/dist/src/Modules/timemodule.c Tue May 9 21:52:40 2000 --- python-mod/dist/src/Modules/timemodule.c Fri May 12 12:41:39 2000 *************** *** 439,445 **** if (!PyArg_ParseTuple(args, "s|s:strptime", &buf, &fmt)) return NULL; memset((ANY *) &tm, '\0', sizeof(tm)); ! s = strptime(buf, fmt, &tm); if (s == NULL) { PyErr_SetString(PyExc_ValueError, "format mismatch"); return NULL; --- 439,445 ---- if (!PyArg_ParseTuple(args, "s|s:strptime", &buf, &fmt)) return NULL; memset((ANY *) &tm, '\0', sizeof(tm)); ! s = (char*)strptime(buf, fmt, &tm); if (s == NULL) { PyErr_SetString(PyExc_ValueError, "format mismatch"); return NULL; --------------1F8F8C92A9D72DEE76E9CB8C-- From peter@schneider-kamp.de Sun May 14 13:22:12 2000 From: peter@schneider-kamp.de (Peter Schneider-Kamp) Date: Sun, 14 May 2000 14:22:12 +0200 Subject: [Patches] array.pop Message-ID: <391E9A74.9064FCDD@stud.ntnu.no> This is a multi-part message in MIME format. --------------CF1A8F54BE8A656EF3130EA1 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Problem: Later: array.array doesn't support the new(er) list.pop() either, although that one is still (1.5.2a1) experimental. Edit this entry / Log info / Last changed on Wed Oct 7 18:43:34 1998 by Tim Peters Solution: adapt listpop to arrays 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 --------------CF1A8F54BE8A656EF3130EA1 Content-Type: text/plain; charset=us-ascii; name="array.pop.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="array.pop.patch" diff -c --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 Sun May 14 12:45:40 2000 --- python-mod/dist/src/Lib/test/test_array.py Sun May 14 14:12:28 2000 *************** *** 74,79 **** --- 74,89 ---- a.remove("e") if a != array.array(type, "aabcde"): raise TestFailed, "array(%s) remove-test" % `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.pop() + a.pop() + a.pop() + a.pop() + if a != array.array(type): + raise TestFailed, "array(%s) pop-test" % `type` else: a = array.array(type, [1, 2, 3, 4, 5]) a[:-1] = a *************** *** 94,99 **** --- 104,119 ---- a.remove(5) if a != array.array(type, [1, 1, 2, 3, 4, 5]): raise TestFailed, "array(%s) remove-test" % `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.pop() + a.pop() + a.pop() + a.pop() + if a != array.array(type): + raise TestFailed, "array(%s) pop-test" % `type` main() diff -c --recursive python/dist/src/Modules/arraymodule.c python-mod/dist/src/Modules/arraymodule.c *** python/dist/src/Modules/arraymodule.c Sun May 14 12:45:40 2000 --- python-mod/dist/src/Modules/arraymodule.c Sun May 14 14:09:16 2000 *************** *** 779,784 **** --- 779,818 ---- Remove the first occurence of x in the array."; 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_insert(self, args) arrayobject *self; PyObject *args; *************** *** 1154,1159 **** --- 1188,1194 ---- {"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}, --------------CF1A8F54BE8A656EF3130EA1-- From tim_one@email.msn.com Mon May 15 08:35:00 2000 From: tim_one@email.msn.com (Tim Peters) Date: Mon, 15 May 2000 03:35:00 -0400 Subject: [Patches] Augmented assignment In-Reply-To: Message-ID: <000401bfbe40$135e6140$b82d153f@tim> [Michael Hudson] > After a resounding silence on comp.lang.python, I thought I'd try > here. My silence should be interpreted as hearty encouragement! This is one of those things so *interesting* that I can't make time to comment on it <0.1 wink>. > ... > I have taken the Common Lisp approach of evaluating things as little as > possible; so in the expression > > e1[e2] += e3 > > each of e3, e1 and e2 are evaluated (in that order) once, though > obviously the result of e1 has both BINARY_SUBSCR and STORE_SUBSCR > done to it. "only once" is the only way it will ever get in, so that part is dead right. Guido never wrote down his order-of-evaluation rules, but I'm going to channel him here and just decree that you got that part right too . > The stack gymnastics required to pull this off look like an attempt to > generate S_3 given a 3-cycle (ROT_THREE) and a 2-cycle (ROT_TWO), so the > resulting code could be much simplified with a couple of well chosen > stack manipulation opcodes. Good idea. > ... > Comments, flames, etc welcome, but I'm not subscribed to patches, so > I'd appreciate being Cc-ed on any responses. I predict you're going to be totally ignored in the rush to finish 1.6 -- and IMO there are already too many "big" changes getting introduced so late in the release cycle. Just don't let that discourage you! > ... > And, I don't expect the patch to go in in this form ... It probably won't go in before a means to allow overloading += etc (distinct from __add__ etc) is also implemented. That is, if the NumPy folks can't overload += to do in-place mutation of the LHS, you're not going to get enough political clout to overcome Guido's frown . From trentm@activestate.com Mon May 15 22:09:44 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 15 May 2000 14:09:44 -0700 Subject: [Patches] fix array module bug introduced by overflow checking (was:[Python-Dev] hey, who broke the array module?) In-Reply-To: <006e01bfbd06$6ba21120$34aab5d4@hagrid> References: <006e01bfbd06$6ba21120$34aab5d4@hagrid> Message-ID: <20000515140944.B20418@activestate.com> Discussion: Recent 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. The unmatching signed and unsigned format specifier for array.array() had to be fixed to allow setting values in their full range. 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: diff -c3 /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c Wed May 3 16:44:31 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c Mon May 15 13:34:01 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 [] = diff -c3 /home/trentm/main/contrib/python/dist/src/Lib/test/test_array.py /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_array.py *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_array.py Thu Jul 16 08:31:43 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_array.py Mon May 15 14:06:56 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) - 1.0) ! unsignedLowerLimit = 0 ! unsignedUpperLimit = long(pow(2, a.itemsize * 8) - 1.0) ! testoverflow(type, signedLowerLimit, signedUpperLimit) ! testoverflow(type.upper(), unsignedLowerLimit, unsignedUpperLimit) ! ! ! main() ! -- Trent Mick trentm@activestate.com From trentm@activestate.com Mon May 15 22:09:44 2000 From: trentm@activestate.com (Trent Mick) Date: Mon, 15 May 2000 14:09:44 -0700 Subject: [Patches] fix array module bug introduced by overflow checking, take #2 (was:[Python-Dev] hey, who broke the array module?) In-Reply-To: <006e01bfbd06$6ba21120$34aab5d4@hagrid> References: <006e01bfbd06$6ba21120$34aab5d4@hagrid> Message-ID: <20000515140944.B20418@activestate.com> Oops. The last patch had a small floating-point addition limitation in the test suite on 64-bit platforms. Please ignore the last patch submission and use this one instead. Discussion: Recent 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. The unmatching signed and unsigned format specifier for array.array() had to be fixed to allow setting values in their full range. 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: diff -c3 /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c *** /home/trentm/main/contrib/python/dist/src/Modules/arraymodule.c Wed May 3 16:44:31 2000 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Modules/arraymodule.c Mon May 15 13:34:01 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 [] = *************** *** 937,943 **** 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 */ *************** *** 955,961 **** 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; *************** *** 990,997 **** return NULL; } if (self->ob_size > 0) { ! if ((int)fwrite(self->ob_item, self->ob_descr->itemsize, ! self->ob_size, fp) != self->ob_size) { PyErr_SetFromErrno(PyExc_IOError); clearerr(fp); return NULL; --- 1075,1082 ---- return NULL; } if (self->ob_size > 0) { ! if (fwrite(self->ob_item, self->ob_descr->itemsize, ! self->ob_size, fp) != (size_t)self->ob_size) { PyErr_SetFromErrno(PyExc_IOError); clearerr(fp); return NULL; diff -c3 /home/trentm/main/contrib/python/dist/src/Lib/test/test_array.py /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_array.py *** /home/trentm/main/contrib/python/dist/src/Lib/test/test_array.py Thu Jul 16 08:31:43 1998 --- /home/trentm/main/Apps/Perlium/Python/dist/src/Lib/test/test_array.py Mon May 15 15:06:00 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 matt@cgibuilder.com Tue May 16 08:17:08 2000 From: matt@cgibuilder.com (Matt Wimer) Date: Tue, 16 May 2000 01:17:08 -0600 Subject: [Patches] crypt.salt() Message-ID: <20000516011708.A28755@cgibuilder.com> --7JfCtLOvnd9MIVvH Content-Type: text/plain; charset=us-ascii Content-Disposition: inline I'll make this short. The crypt module requires a salt value that the user currently has to gen. I added crypt.salt() function that does this for them. It currently isn't much but its setup to scale to the current system. STD: 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 attached. --matt wimer --7JfCtLOvnd9MIVvH Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="crypt-salt.patch" *** Python-1.6a2/Modules/cryptmodule.c Tue Feb 1 13:12:39 2000 --- Python-1.6a2-patched/Modules/cryptmodule.c Tue May 16 01:12:51 2000 *************** *** 9,14 **** --- 9,90 ---- /* Module crypt */ + /* SALTING the crypt() is system dependant. Let them use crypt.salt() + * to do the salting. */ + + + /* README: + * Salts can look like [suffix]. I define the + * suffix to take OSOFFSET amount of space. And the rest + * of the salt to be the salt size. + * + * OpenBSD has a suffix of $12$ in its blowfish + * crypt(3). This current code will be able to scale up + * to meat these chalanges as people become more interested + * in python for thier platform. + */ + + #define OSOFFSET (0) /* No offset define yet. */ + #define SALTSIZE (2) /* Pretend 2 is good enough. */ + + /* The salt chars possible. Broken up so you can see they are corret. */ + static char salter[] = + "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "./"; /* These are possible as well. */ + + /* Each system has its own salter type for specifing + * long crypted passwds. We'll just define that crypt.salt() + * generated the standard two letter salt if we can't guess + * the correct salter to use. + */ + static PyObject * crypt_salt(self, args) + PyObject *self, *args; + { + char salt [OSOFFSET + SALTSIZE]; /* Size is system dependant. */ + int cur; /* The current offset into salter[]. */ + int i; /* Iterate don the SALTSIZE. */ + + extern int rand(void); /* Bad rand num generator. */ + extern void srand(unsigned int seed); /* Seeder for rand(3). */ + extern time_t time(time_t *t); /* Helper for the seed. */ + + + + /* Not very good seed, but should be better than most people, + * well create. 'Just another sign of the times.' */ + srand ( time(NULL) ); + + /* This is where the os dependant salt code should go. + * But it's not yet impelented... */ + + for (i = 0; i < SALTSIZE; i++) { + /* Make sure that the char we pick falls into the array + * bounds of salter[]. */ + cur = rand () % sizeof (salter); + + /* Fill in the salt with the current chosen char. */ + salt[OSOFFSET + i] = salter[cur]; + } + + /* There is no way to error that i can see. */ + return PyString_FromString (salt); + } + + static char crypt_salt__doc__[] = "\ + salt() -> string\n\ + word will be the system default salt value that should be passed\n\ + to crypt() so that you will get the best encryped password for\n\ + your system. This offloads the salt generation into one easily\n\ + maintained function."; + + + /* Call the sys crypt to do the cript, it should accept standard + * 2 char salts as well as os depandant salts as create by + * crypt.salt(). */ + + static PyObject *crypt_crypt(self, args) PyObject *self, *args; { *************** *** 33,38 **** --- 109,115 ---- static PyMethodDef crypt_methods[] = { {"crypt", crypt_crypt, 0, crypt_crypt__doc__}, + {"salt", crypt_salt, 0, crypt_salt__doc__}, {NULL, NULL} /* sentinel */ }; --7JfCtLOvnd9MIVvH-- From guido@python.org Tue May 16 11:14:28 2000 From: guido@python.org (Guido van Rossum) Date: Tue, 16 May 2000 06:14:28 -0400 Subject: [Patches] crypt.salt() In-Reply-To: Your message of "Tue, 16 May 2000 01:17:08 MDT." <20000516011708.A28755@cgibuilder.com> References: <20000516011708.A28755@cgibuilder.com> Message-ID: <200005161014.GAA12281@eric.cnri.reston.va.us> > I'll make this short. The crypt module requires a salt > value that the user currently has to gen. I added > crypt.salt() function that does this for them. It > currently isn't much but its setup to scale to the > current system. This has been suggested before, but I don't like it. First of all, by calling srand() you may upset another random sequence that another C module might be in the middle of. Furthermore, the rand() generator isn't cryptographically very strong (to put it mildly), so you're generating salts that someone else could predict. Next, how often are you creating new passwords with a Python script? And if you are, and you don'y care about the strength of your password generator, how hard is it to write the corresponding Python code? --Guido van Rossum (home page: http://www.python.org/~guido/) From gstein@lyra.org Tue May 16 19:58:23 2000 From: gstein@lyra.org (Greg Stein) Date: Tue, 16 May 2000 11:58:23 -0700 (PDT) Subject: [Patches] crypt.salt() In-Reply-To: <200005161014.GAA12281@eric.cnri.reston.va.us> Message-ID: On Tue, 16 May 2000, Guido van Rossum wrote: > > I'll make this short. The crypt module requires a salt > > value that the user currently has to gen. I added > > crypt.salt() function that does this for them. It > > currently isn't much but its setup to scale to the > > current system. > > This has been suggested before, but I don't like it. > > First of all, by calling srand() you may upset another random sequence > that another C module might be in the middle of. I was going to mention the same thing. It also appears that you don't null-terminate the salt string before passing it to PyString_FromString. > Furthermore, the > rand() generator isn't cryptographically very strong (to put it > mildly), so you're generating salts that someone else could predict. > Next, how often are you creating new passwords with a Python script? > And if you are, and you don'y care about the strength of your password > generator, how hard is it to write the corresponding Python code? And Guido provides the ultimate nix: this function is just way too easy to write in Python. I don't see a need to write it in C code. Cheers, -g -- Greg Stein, http://www.lyra.org/ From ragnark@vestdata.no Sat May 20 19:55:40 2000 From: ragnark@vestdata.no (=?iso-8859-1?Q?Ragnar_Kj=F8rstad?=) Date: Sat, 20 May 2000 20:55:40 +0200 Subject: [Patches] Patch to make tempfile return random filenames Message-ID: <20000520205540.C11635@vestdata.no> --a8Wt8u1KmwUX3Y2C Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit This patch changes tempfile to return a random filename. The reason for then change is that predictable filenames can be a security-problem, because other users can make symlinks thus causing you to overwrite one of your own files. A side-effect is that the filename will be uniq without the need for a counter, and thus removing the problem of filenames not beeing uniq after a fork. The filenames would also be uniq without the pid-part, but I left it there because it's practical for debugging and such. -- Ragnar Kjørstad --a8Wt8u1KmwUX3Y2C Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=disclamer 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. --a8Wt8u1KmwUX3Y2C Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="tempfile.random.patch" Index: src/Doc/lib/libtempfile.tex =================================================================== RCS file: /projects/cvsroot/python/dist/src/Doc/lib/libtempfile.tex,v retrieving revision 1.12 diff -c -r1.12 libtempfile.tex *** libtempfile.tex 1999/04/21 17:01:15 1.12 --- libtempfile.tex 2000/05/20 18:50:45 *************** *** 18,25 **** \begin{funcdesc}{mktemp}{} Return a unique temporary filename. This is an absolute pathname of a ! file that does not exist at the time the call is made. No two calls ! will return the same filename. \end{funcdesc} The module uses two global variables that tell it how to construct a --- 18,24 ---- \begin{funcdesc}{mktemp}{} Return a unique temporary filename. This is an absolute pathname of a ! randomly generated filename \end{funcdesc} The module uses two global variables that tell it how to construct a *************** *** 43,52 **** \var{pid} is the current process ID (on \UNIX{}), or \file{tmp} (all other systems). \end{datadesc} - - \strong{Warning:} if a \UNIX{} process uses \code{mktemp()}, then - calls \function{fork()} and both parent and child continue to use - \function{mktemp()}, the processes will generate conflicting temporary - names. To resolve this, the child process should assign \code{None} to - \code{template}, to force recomputing the default on the next call - to \function{mktemp()}. --- 42,44 ---- Index: src/Lib/tempfile.py =================================================================== RCS file: /projects/cvsroot/python/dist/src/Lib/tempfile.py,v retrieving revision 1.21 diff -c -r1.21 tempfile.py *** tempfile.py 2000/04/24 13:28:02 1.21 --- tempfile.py 2000/05/20 18:50:46 *************** *** 6,11 **** --- 6,12 ---- import os + import random # Parameters that the caller may set to override the defaults *************** *** 92,112 **** return template - # Counter for generating unique names - - counter = 0 - - def mktemp(suffix=""): """User-callable function to return a unique temporary file name.""" - global counter dir = gettempdir() pre = gettempprefix() ! while 1: ! counter = counter + 1 ! file = os.path.join(dir, pre + `counter` + suffix) ! if not os.path.exists(file): ! return file class TemporaryFileWrapper: --- 93,104 ---- return template def mktemp(suffix=""): """User-callable function to return a unique temporary file name.""" dir = gettempdir() pre = gettempprefix() ! rand = str(random.randit(0, 1000000)) ! file = os.path.join(dir, pre + rand + suffix) class TemporaryFileWrapper: --a8Wt8u1KmwUX3Y2C-- From akuchlin@mems-exchange.org Sat May 20 20:02:05 2000 From: akuchlin@mems-exchange.org (Andrew M. Kuchling) Date: Sat, 20 May 2000 15:02:05 -0400 (EDT) Subject: [Patches] Patch to make tempfile return random filenames In-Reply-To: <20000520205540.C11635@vestdata.no> References: <20000520205540.C11635@vestdata.no> Message-ID: <14630.57645.342237.57115@amarok.cnri.reston.va.us> Ragnar Kj=F8rstad writes: >! rand =3D str(random.randit(0, 1000000)) Um, I think the above line is a typo for random.randint. --amk From ragnark@vestdata.no Sat May 20 20:04:49 2000 From: ragnark@vestdata.no (=?iso-8859-1?Q?Ragnar_Kj=F8rstad?=) Date: Sat, 20 May 2000 21:04:49 +0200 Subject: [Patches] Patch to make tempfile return random filenames In-Reply-To: <14630.57645.342237.57115@amarok.cnri.reston.va.us>; from Andrew M. Kuchling on Sat, May 20, 2000 at 03:02:05PM -0400 References: <20000520205540.C11635@vestdata.no> <14630.57645.342237.57115@amarok.cnri.reston.va.us> Message-ID: <20000520210449.D11635@vestdata.no> On Sat, May 20, 2000 at 03:02:05PM -0400, Andrew M. Kuchling wrote: > Ragnar Kjørstad writes: > >! rand = str(random.randit(0, 1000000)) > > Um, I think the above line is a typo for random.randint. You're right. Sorry for the inconvinience. -- Ragnar Kjørstad From cg@cdegroot.com Sun May 21 10:26:09 2000 From: cg@cdegroot.com (Cees de Groot) Date: Sun, 21 May 2000 11:26:09 +0200 Subject: [Patches] sgmllib patch: handle specials Message-ID: <200005210926.LAA05080@alpha.cdg.acriter.nl> --==_Exmh_358495615P Content-Type: text/plain; charset=us-ascii For SGMLtools, I need to access the DTD of an SGML document. sgmllib doesn't handle this out-of-the-box, but it does know about the "" construct - there's a pattern for it, but that seems to be only used to make sure that literals don't end too early. The patch adds an overridable method handle_special(self, data) which receives the contents of constructs; this allows subclasses to look for document type declarations and other interesting tidbits. Regards, Cees ---- 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. ---- *** /usr/lib/python/sgmllib.py Tue Nov 9 13:22:27 1999 --- sgmllib.py Sun May 21 11:10:21 2000 *************** *** 30,36 **** piclose = re.compile('>') endtagopen = re.compile('a-zA-Z]') endbracket = re.compile('[<>]') ! special = re.compile(']*>') commentopen = re.compile('