blob: 966c8ba4f1219688d23e6b359322ed66954af513 [file] [log] [blame]
Guido van Rossum2a70a3a2000-03-10 23:10:21 +00001/* ------------------------------------------------------------------------
2
3 unicodedata -- Provides access to the Unicode 3.0 data base.
4
5 Data was extracted from the Unicode 3.0 UnicodeData.txt file.
6
Fredrik Lundhcfcea492000-09-25 08:07:06 +00007 Written by Marc-Andre Lemburg (mal@lemburg.com).
8 Modified for Python 2.0 by Fredrik Lundh (fredrik@pythonware.com)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +00009
Fredrik Lundhcfcea492000-09-25 08:07:06 +000010 Copyright (c) Corporation for National Research Initiatives.
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000011
12 ------------------------------------------------------------------------ */
13
14#include "Python.h"
Fredrik Lundh06d12682001-01-24 07:59:11 +000015#include "ucnhash.h"
16
17/* character properties */
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000018
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000019typedef struct {
20 const unsigned char category; /* index into
21 _PyUnicode_CategoryNames */
22 const unsigned char combining; /* combining class value 0 - 255 */
23 const unsigned char bidirectional; /* index into
24 _PyUnicode_BidirectionalNames */
25 const unsigned char mirrored; /* true if mirrored in bidir mode */
26} _PyUnicode_DatabaseRecord;
27
28/* data file generated by Tools/unicode/makeunicodedata.py */
29#include "unicodedata_db.h"
30
31static const _PyUnicode_DatabaseRecord*
Fredrik Lundhb95896b2001-02-18 22:06:17 +000032_getrecord(PyUnicodeObject* v)
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000033{
34 int code;
35 int index;
36
37 code = (int) *PyUnicode_AS_UNICODE(v);
38
39 if (code < 0 || code >= 65536)
40 index = 0;
41 else {
42 index = index1[(code>>SHIFT)];
43 index = index2[(index<<SHIFT)+(code&((1<<SHIFT)-1))];
44 }
45
46 return &_PyUnicode_Database_Records[index];
47}
48
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000049/* --- Module API --------------------------------------------------------- */
50
51static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000052unicodedata_decimal(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000053{
54 PyUnicodeObject *v;
55 PyObject *defobj = NULL;
56 long rc;
57
Fredrik Lundh06d12682001-01-24 07:59:11 +000058 if (!PyArg_ParseTuple(args, "O!|O:decimal", &PyUnicode_Type, &v, &defobj))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000059 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000060 if (PyUnicode_GET_SIZE(v) != 1) {
61 PyErr_SetString(PyExc_TypeError,
62 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000063 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000064 }
65 rc = Py_UNICODE_TODECIMAL(*PyUnicode_AS_UNICODE(v));
66 if (rc < 0) {
67 if (defobj == NULL) {
68 PyErr_SetString(PyExc_ValueError,
69 "not a decimal");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000070 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000071 }
72 else {
73 Py_INCREF(defobj);
74 return defobj;
75 }
76 }
77 return PyInt_FromLong(rc);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000078}
79
80static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000081unicodedata_digit(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000082{
83 PyUnicodeObject *v;
84 PyObject *defobj = NULL;
85 long rc;
86
Fredrik Lundh06d12682001-01-24 07:59:11 +000087 if (!PyArg_ParseTuple(args, "O!|O:digit", &PyUnicode_Type, &v, &defobj))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000088 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000089 if (PyUnicode_GET_SIZE(v) != 1) {
90 PyErr_SetString(PyExc_TypeError,
91 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000092 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000093 }
94 rc = Py_UNICODE_TODIGIT(*PyUnicode_AS_UNICODE(v));
95 if (rc < 0) {
96 if (defobj == NULL) {
Fredrik Lundh06d12682001-01-24 07:59:11 +000097 PyErr_SetString(PyExc_ValueError, "not a digit");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +000098 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +000099 }
100 else {
101 Py_INCREF(defobj);
102 return defobj;
103 }
104 }
105 return PyInt_FromLong(rc);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000106}
107
108static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000109unicodedata_numeric(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000110{
111 PyUnicodeObject *v;
112 PyObject *defobj = NULL;
113 double rc;
114
Fredrik Lundh06d12682001-01-24 07:59:11 +0000115 if (!PyArg_ParseTuple(args, "O!|O:numeric", &PyUnicode_Type, &v, &defobj))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000116 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000117 if (PyUnicode_GET_SIZE(v) != 1) {
118 PyErr_SetString(PyExc_TypeError,
119 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000120 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000121 }
122 rc = Py_UNICODE_TONUMERIC(*PyUnicode_AS_UNICODE(v));
123 if (rc < 0) {
124 if (defobj == NULL) {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000125 PyErr_SetString(PyExc_ValueError, "not a numeric character");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000126 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000127 }
128 else {
129 Py_INCREF(defobj);
130 return defobj;
131 }
132 }
133 return PyFloat_FromDouble(rc);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000134}
135
136static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000137unicodedata_category(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000138{
139 PyUnicodeObject *v;
140 int index;
141
142 if (!PyArg_ParseTuple(args, "O!:category",
143 &PyUnicode_Type, &v))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000144 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000145 if (PyUnicode_GET_SIZE(v) != 1) {
146 PyErr_SetString(PyExc_TypeError,
147 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000148 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000149 }
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000150 index = (int) _getrecord(v)->category;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000151 return PyString_FromString(_PyUnicode_CategoryNames[index]);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000152}
153
154static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000155unicodedata_bidirectional(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000156{
157 PyUnicodeObject *v;
158 int index;
159
160 if (!PyArg_ParseTuple(args, "O!:bidirectional",
161 &PyUnicode_Type, &v))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000162 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000163 if (PyUnicode_GET_SIZE(v) != 1) {
164 PyErr_SetString(PyExc_TypeError,
165 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000166 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000167 }
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000168 index = (int) _getrecord(v)->bidirectional;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000169 return PyString_FromString(_PyUnicode_BidirectionalNames[index]);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000170}
171
172static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000173unicodedata_combining(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000174{
175 PyUnicodeObject *v;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000176
177 if (!PyArg_ParseTuple(args, "O!:combining",
178 &PyUnicode_Type, &v))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000179 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000180 if (PyUnicode_GET_SIZE(v) != 1) {
181 PyErr_SetString(PyExc_TypeError,
182 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000183 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000184 }
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000185 return PyInt_FromLong((int) _getrecord(v)->combining);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000186}
187
188static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000189unicodedata_mirrored(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000190{
191 PyUnicodeObject *v;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000192
193 if (!PyArg_ParseTuple(args, "O!:mirrored",
194 &PyUnicode_Type, &v))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000195 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000196 if (PyUnicode_GET_SIZE(v) != 1) {
197 PyErr_SetString(PyExc_TypeError,
198 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000199 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000200 }
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000201 return PyInt_FromLong((int) _getrecord(v)->mirrored);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000202}
203
204static PyObject *
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000205unicodedata_decomposition(PyObject *self, PyObject *args)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000206{
207 PyUnicodeObject *v;
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000208 char decomp[256];
209 int code, index, count, i;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000210
211 if (!PyArg_ParseTuple(args, "O!:decomposition",
212 &PyUnicode_Type, &v))
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000213 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000214 if (PyUnicode_GET_SIZE(v) != 1) {
215 PyErr_SetString(PyExc_TypeError,
216 "need a single Unicode character as parameter");
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000217 return NULL;
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000218 }
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000219
220 code = (int) *PyUnicode_AS_UNICODE(v);
221
222 if (code < 0 || code >= 65536)
223 index = 0;
224 else {
225 index = decomp_index1[(code>>DECOMP_SHIFT)];
226 index = decomp_index2[(index<<DECOMP_SHIFT)+
227 (code&((1<<DECOMP_SHIFT)-1))];
228 }
229
Tim Peters69b83b12001-11-30 07:23:05 +0000230 /* high byte is number of hex bytes (usually one or two), low byte
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000231 is prefix code (from*/
232 count = decomp_data[index] >> 8;
233
234 /* XXX: could allocate the PyString up front instead
235 (strlen(prefix) + 5 * count + 1 bytes) */
236
237 /* copy prefix */
238 i = strlen(decomp_prefix[decomp_data[index] & 255]);
239 memcpy(decomp, decomp_prefix[decomp_data[index] & 255], i);
240
241 while (count-- > 0) {
242 if (i)
243 decomp[i++] = ' ';
Tim Peters69b83b12001-11-30 07:23:05 +0000244 assert((size_t)i < sizeof(decomp));
245 PyOS_snprintf(decomp + i, sizeof(decomp) - i, "%04X",
246 decomp_data[++index]);
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000247 i += strlen(decomp + i);
248 }
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000249
Fredrik Lundh7b7dd102001-01-21 22:41:08 +0000250 decomp[i] = '\0';
251
252 return PyString_FromString(decomp);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000253}
254
Fredrik Lundh06d12682001-01-24 07:59:11 +0000255/* -------------------------------------------------------------------- */
256/* unicode character name tables */
257
258/* data file generated by Tools/unicode/makeunicodedata.py */
259#include "unicodename_db.h"
260
261/* -------------------------------------------------------------------- */
262/* database code (cut and pasted from the unidb package) */
263
264static unsigned long
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000265_gethash(const char *s, int len, int scale)
Fredrik Lundh06d12682001-01-24 07:59:11 +0000266{
267 int i;
268 unsigned long h = 0;
269 unsigned long ix;
270 for (i = 0; i < len; i++) {
271 h = (h * scale) + (unsigned char) toupper(s[i]);
272 ix = h & 0xff000000;
273 if (ix)
274 h = (h ^ ((ix>>24) & 0xff)) & 0x00ffffff;
275 }
276 return h;
277}
278
279static int
Andrew MacIntyre74a3bec2002-06-13 11:55:14 +0000280_getucname(Py_UCS4 code, char* buffer, int buflen)
Fredrik Lundh06d12682001-01-24 07:59:11 +0000281{
282 int offset;
283 int i;
284 int word;
285 unsigned char* w;
286
Fred Drake6a16ea02001-07-19 21:11:13 +0000287 if (code >= 65536)
Fredrik Lundh06d12682001-01-24 07:59:11 +0000288 return 0;
289
290 /* get offset into phrasebook */
291 offset = phrasebook_offset1[(code>>phrasebook_shift)];
292 offset = phrasebook_offset2[(offset<<phrasebook_shift) +
293 (code&((1<<phrasebook_shift)-1))];
294 if (!offset)
295 return 0;
296
297 i = 0;
298
299 for (;;) {
300 /* get word index */
301 word = phrasebook[offset] - phrasebook_short;
302 if (word >= 0) {
303 word = (word << 8) + phrasebook[offset+1];
304 offset += 2;
305 } else
306 word = phrasebook[offset++];
307 if (i) {
308 if (i > buflen)
309 return 0; /* buffer overflow */
310 buffer[i++] = ' ';
311 }
312 /* copy word string from lexicon. the last character in the
313 word has bit 7 set. the last word in a string ends with
314 0x80 */
315 w = lexicon + lexicon_offset[word];
316 while (*w < 128) {
317 if (i >= buflen)
318 return 0; /* buffer overflow */
319 buffer[i++] = *w++;
320 }
321 if (i >= buflen)
322 return 0; /* buffer overflow */
323 buffer[i++] = *w & 127;
324 if (*w == 128)
325 break; /* end of word */
326 }
327
328 return 1;
329}
330
331static int
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000332_cmpname(int code, const char* name, int namelen)
Fredrik Lundh06d12682001-01-24 07:59:11 +0000333{
334 /* check if code corresponds to the given name */
335 int i;
336 char buffer[NAME_MAXLEN];
Andrew MacIntyre74a3bec2002-06-13 11:55:14 +0000337 if (!_getucname(code, buffer, sizeof(buffer)))
Fredrik Lundh06d12682001-01-24 07:59:11 +0000338 return 0;
339 for (i = 0; i < namelen; i++) {
340 if (toupper(name[i]) != buffer[i])
341 return 0;
342 }
343 return buffer[namelen] == '\0';
344}
345
346static int
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000347_getcode(const char* name, int namelen, Py_UCS4* code)
Fredrik Lundh06d12682001-01-24 07:59:11 +0000348{
349 unsigned int h, v;
350 unsigned int mask = code_size-1;
351 unsigned int i, incr;
352
353 /* the following is the same as python's dictionary lookup, with
354 only minor changes. see the makeunicodedata script for more
355 details */
356
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000357 h = (unsigned int) _gethash(name, namelen, code_magic);
Fredrik Lundh06d12682001-01-24 07:59:11 +0000358 i = (~h) & mask;
359 v = code_hash[i];
360 if (!v)
361 return 0;
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000362 if (_cmpname(v, name, namelen)) {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000363 *code = v;
364 return 1;
365 }
366 incr = (h ^ (h >> 3)) & mask;
367 if (!incr)
368 incr = mask;
369 for (;;) {
370 i = (i + incr) & mask;
371 v = code_hash[i];
372 if (!v)
Fredrik Lundhae763672001-02-18 11:41:49 +0000373 return 0;
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000374 if (_cmpname(v, name, namelen)) {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000375 *code = v;
376 return 1;
377 }
378 incr = incr << 1;
379 if (incr > mask)
380 incr = incr ^ code_poly;
381 }
382}
383
384static const _PyUnicode_Name_CAPI hashAPI =
385{
386 sizeof(_PyUnicode_Name_CAPI),
Andrew MacIntyre74a3bec2002-06-13 11:55:14 +0000387 _getucname,
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000388 _getcode
Fredrik Lundh06d12682001-01-24 07:59:11 +0000389};
390
391/* -------------------------------------------------------------------- */
392/* Python bindings */
393
394static PyObject *
395unicodedata_name(PyObject* self, PyObject* args)
396{
397 char name[NAME_MAXLEN];
398
399 PyUnicodeObject* v;
400 PyObject* defobj = NULL;
401 if (!PyArg_ParseTuple(args, "O!|O:name", &PyUnicode_Type, &v, &defobj))
402 return NULL;
403
404 if (PyUnicode_GET_SIZE(v) != 1) {
405 PyErr_SetString(PyExc_TypeError,
406 "need a single Unicode character as parameter");
407 return NULL;
408 }
409
Andrew MacIntyre74a3bec2002-06-13 11:55:14 +0000410 if (!_getucname((Py_UCS4) *PyUnicode_AS_UNICODE(v),
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000411 name, sizeof(name))) {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000412 if (defobj == NULL) {
413 PyErr_SetString(PyExc_ValueError, "no such name");
414 return NULL;
415 }
416 else {
417 Py_INCREF(defobj);
418 return defobj;
419 }
420 }
421
422 return Py_BuildValue("s", name);
423}
424
425static PyObject *
426unicodedata_lookup(PyObject* self, PyObject* args)
427{
428 Py_UCS4 code;
429 Py_UNICODE str[1];
430
431 char* name;
432 int namelen;
433 if (!PyArg_ParseTuple(args, "s#:lookup", &name, &namelen))
434 return NULL;
435
Fredrik Lundhb95896b2001-02-18 22:06:17 +0000436 if (!_getcode(name, namelen, &code)) {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000437 PyErr_SetString(PyExc_KeyError, "undefined character name");
438 return NULL;
439 }
440
441 str[0] = (Py_UNICODE) code;
442 return PyUnicode_FromUnicode(str, 1);
443}
444
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000445/* XXX Add doc strings. */
446
447static PyMethodDef unicodedata_functions[] = {
Fredrik Lundh06d12682001-01-24 07:59:11 +0000448 {"decimal", unicodedata_decimal, METH_VARARGS},
449 {"digit", unicodedata_digit, METH_VARARGS},
450 {"numeric", unicodedata_numeric, METH_VARARGS},
451 {"category", unicodedata_category, METH_VARARGS},
452 {"bidirectional", unicodedata_bidirectional, METH_VARARGS},
453 {"combining", unicodedata_combining, METH_VARARGS},
454 {"mirrored", unicodedata_mirrored, METH_VARARGS},
455 {"decomposition",unicodedata_decomposition, METH_VARARGS},
456 {"name", unicodedata_name, METH_VARARGS},
457 {"lookup", unicodedata_lookup, METH_VARARGS},
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000458 {NULL, NULL} /* sentinel */
459};
460
Martin v. Löwis14f8b4c2002-06-13 20:33:02 +0000461PyDoc_STRVAR(unicodedata_docstring, "unicode character database");
Fredrik Lundh06d12682001-01-24 07:59:11 +0000462
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000463DL_EXPORT(void)
Thomas Woutersf3f33dc2000-07-21 06:00:07 +0000464initunicodedata(void)
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000465{
Fred Drakea2bd8d32002-04-03 21:39:26 +0000466 PyObject *m, *v;
Fredrik Lundh06d12682001-01-24 07:59:11 +0000467
Fred Drakef585bef2001-03-03 19:41:55 +0000468 m = Py_InitModule3(
469 "unicodedata", unicodedata_functions, unicodedata_docstring);
Fredrik Lundh06d12682001-01-24 07:59:11 +0000470 if (!m)
471 return;
472
Fredrik Lundh06d12682001-01-24 07:59:11 +0000473 /* Export C API */
474 v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL);
Fred Drakea2bd8d32002-04-03 21:39:26 +0000475 if (v != NULL)
476 PyModule_AddObject(m, "ucnhash_CAPI", v);
Guido van Rossum2a70a3a2000-03-10 23:10:21 +0000477}