From bba59fdb64a0f2d628d3021fa6062d4543714759 Mon Sep 17 00:00:00 2001 From: jbj Date: Sat, 17 May 2003 19:27:47 +0000 Subject: [PATCH] Create python bindings. CVS patchset: 6856 CVS date: 2003/05/17 19:27:47 --- beecrypt/Makefile.am | 2 +- beecrypt/configure.ac | 2 + beecrypt/python/.cvsignore | 7 + beecrypt/python/Makefile.am | 40 + beecrypt/python/_bc-py.c | 100 ++ beecrypt/python/debug-py.c | 63 + beecrypt/python/mpw-py.c | 2349 ++++++++++++++++++++++++++++++++++ beecrypt/python/mpw-py.h | 40 + beecrypt/python/rng-py.c | 330 +++++ beecrypt/python/rng-py.h | 25 + beecrypt/python/test/.cvsignore | 3 + beecrypt/python/test/Makefile.am | 17 + beecrypt/python/test/test_all.py | 59 + beecrypt/python/test/test_methods.py | 322 +++++ beecrypt/python/test/unittest.py | 759 +++++++++++ 15 files changed, 4117 insertions(+), 1 deletion(-) create mode 100644 beecrypt/python/.cvsignore create mode 100644 beecrypt/python/Makefile.am create mode 100644 beecrypt/python/_bc-py.c create mode 100644 beecrypt/python/debug-py.c create mode 100644 beecrypt/python/mpw-py.c create mode 100644 beecrypt/python/mpw-py.h create mode 100644 beecrypt/python/rng-py.c create mode 100644 beecrypt/python/rng-py.h create mode 100644 beecrypt/python/test/.cvsignore create mode 100644 beecrypt/python/test/Makefile.am create mode 100644 beecrypt/python/test/test_all.py create mode 100644 beecrypt/python/test/test_methods.py create mode 100644 beecrypt/python/test/unittest.py diff --git a/beecrypt/Makefile.am b/beecrypt/Makefile.am index 88f1a44..c79b9be 100644 --- a/beecrypt/Makefile.am +++ b/beecrypt/Makefile.am @@ -36,7 +36,7 @@ AUTOMAKE_OPTIONS = gnu check-news no-dependencies LINT = splint -SUBDIRS = docs gas masm mwerks tests +SUBDIRS = docs gas masm mwerks python tests SUFFIXES = .s diff --git a/beecrypt/configure.ac b/beecrypt/configure.ac index 3f6f75a..f2ee080 100644 --- a/beecrypt/configure.ac +++ b/beecrypt/configure.ac @@ -669,5 +669,7 @@ AC_CONFIG_FILES([Makefile gas/Makefile masm/Makefile mwerks/Makefile + python/Makefile + python/test/Makefile tests/Makefile]) AC_OUTPUT diff --git a/beecrypt/python/.cvsignore b/beecrypt/python/.cvsignore new file mode 100644 index 0000000..88b36fb --- /dev/null +++ b/beecrypt/python/.cvsignore @@ -0,0 +1,7 @@ +.deps +.libs +Makefile +Makefile.in +*.la +*.lo +*.pyc diff --git a/beecrypt/python/Makefile.am b/beecrypt/python/Makefile.am new file mode 100644 index 0000000..c884448 --- /dev/null +++ b/beecrypt/python/Makefile.am @@ -0,0 +1,40 @@ +# Makefile for rpm library. + +AUTOMAKE_OPTIONS = 1.4 foreign + +LINT = splint + +PYVER= 2.2 + +pylibdir = $(shell python -c 'import sys; print sys.path[1]') +pyincdir = $(prefix)/include/python${PYVER} + +EXTRA_DIST = bcdebug-py.c + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(pyincdir) + +noinst_HEADERS = mpw-py.h rng-py.h + +mylibs= $(top_builddir)/.libs/libbeecrypt.so + +LDADD = + +pythondir = $(pylibdir)/site-packages +python_PROGRAMS = _bc.so + +_bc_so_SOURCES = _bc-py.c +_bc_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,_bc.so + +noinst_LTLIBRARIES = libbc.la +libbc_la_SOURCES = mpw-py.c rng-py.c + +_bc.so$(EXEEXT): $(_bc_so_OBJECTS) $(libbc_la_OBJECTS) + $(CC) -o $@ $(_bc_so_OBJECTS) $(libbc_la_OBJECTS) $(_bc_so_LDFLAGS) + +splint_srcs = _bc-py.c $(libbc_la_sources) + +.PHONY: lint +lint: + $(LINT) $(DEFS) $(INCLUDES) $(splint_srcs) diff --git a/beecrypt/python/_bc-py.c b/beecrypt/python/_bc-py.c new file mode 100644 index 0000000..2074d1c --- /dev/null +++ b/beecrypt/python/_bc-py.c @@ -0,0 +1,100 @@ +/** \ingroup py_c + * \file python/_bc-py.c + */ + +#define _REENTRANT 1 /* XXX config.h collides with pyconfig.h */ +#include "system.h" + +#include "Python.h" +#ifdef __LCLINT__ +#undef PyObject_HEAD +#define PyObject_HEAD int _PyObjectHead; +#endif + +#include "mpw-py.h" +#include "rng-py.h" + +#include "debug.h" + +#ifdef __LCLINT__ +#undef PyObject_HEAD +#define PyObject_HEAD int _PyObjectHead +#endif + +/** + */ +PyObject * py_bcError; + +/** + */ +static PyMethodDef _bcModuleMethods[] = { + { NULL } +} ; + +/** + */ +static char _bc__doc__[] = +""; + +void init_bc(void); /* XXX eliminate gcc warning */ +/** + */ +void init_bc(void) +{ + PyObject *d, *m; +#ifdef NOTYET + PyObject *o, *dict; + int i; +#endif + + if (PyType_Ready(&mpw_Type) < 0) return; + if (PyType_Ready(&rng_Type) < 0) return; + + m = Py_InitModule3("_bc", _bcModuleMethods, _bc__doc__); + if (m == NULL) + return; + + d = PyModule_GetDict(m); + + py_bcError = PyErr_NewException("_bc.error", NULL, NULL); + if (py_bcError != NULL) + PyDict_SetItemString(d, "error", py_bcError); + + Py_INCREF(&mpw_Type); + PyModule_AddObject(m, "mpw", (PyObject *) &mpw_Type); + + Py_INCREF(&rng_Type); + PyModule_AddObject(m, "rng", (PyObject *) &rng_Type); + +#ifdef NOTYET + dict = PyDict_New(); + + for (i = 0; i < _bcTagTableSize; i++) { + tag = PyInt_FromLong(_bcTagTable[i].val); + PyDict_SetItemString(d, (char *) _bcTagTable[i].name, tag); + Py_DECREF(tag); + PyDict_SetItem(dict, tag, o=PyString_FromString(_bcTagTable[i].name + 7)); + Py_DECREF(o); + } + + while (extensions->name) { + if (extensions->type == HEADER_EXT_TAG) { + (const struct headerSprintfExtension *) ext = extensions; + PyDict_SetItemString(d, (char *) extensions->name, o=PyCObject_FromVoidPtr(ext, NULL)); + Py_DECREF(o); + PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7)); + Py_DECREF(o); + } + extensions++; + } + + PyDict_SetItemString(d, "tagnames", dict); + Py_DECREF(dict); + +#define REGISTER_ENUM(val) \ + PyDict_SetItemString(d, #val, o=PyInt_FromLong( val )); \ + Py_DECREF(o); + +#endif + +} diff --git a/beecrypt/python/debug-py.c b/beecrypt/python/debug-py.c new file mode 100644 index 0000000..06aa932 --- /dev/null +++ b/beecrypt/python/debug-py.c @@ -0,0 +1,63 @@ + +/*@unchecked@*/ +extern PyTypeObject PyCode_Type; +/*@unchecked@*/ +extern PyTypeObject PyDictIter_Type; +/*@unchecked@*/ +extern PyTypeObject PyFrame_Type; + +#include "mpw-py.h" /* XXX debug only */ +#include "rng-py.h" /* XXX debug only */ + +/** + */ +static const char * lbl(void * s) + /*@*/ +{ + PyObject * o = s; + + if (o == NULL) return "null"; + + if (o == Py_None) return "None"; + + if (o->ob_type == &PyType_Type) return o->ob_type->tp_name; + + if (o->ob_type == &PyBaseObject_Type) return "BaseObj"; + if (o->ob_type == &PyBuffer_Type) return "Buffer"; + if (o->ob_type == &PyCFunction_Type) return "CFunction"; + if (o->ob_type == &PyCObject_Type) return "CObject"; + if (o->ob_type == &PyCell_Type) return "Cell"; + if (o->ob_type == &PyClass_Type) return "Class"; + if (o->ob_type == &PyClassMethod_Type) return "ClassMethod"; + if (o->ob_type == &PyStaticMethod_Type) return "StaticMethod"; + if (o->ob_type == &PyCode_Type) return "Code"; + if (o->ob_type == &PyComplex_Type) return "Complex"; + if (o->ob_type == &PyDict_Type) return "Dict"; + if (o->ob_type == &PyDictIter_Type) return "DictIter"; + if (o->ob_type == &PyFile_Type) return "File"; + if (o->ob_type == &PyFloat_Type) return "Float"; + if (o->ob_type == &PyFrame_Type) return "Frame"; + if (o->ob_type == &PyFunction_Type) return "Function"; + if (o->ob_type == &PyInstance_Type) return "Instance"; + if (o->ob_type == &PyInt_Type) return "Int"; + if (o->ob_type == &PyList_Type) return "List"; + if (o->ob_type == &PyLong_Type) return "Long"; + if (o->ob_type == &PyMethod_Type) return "Method"; + if (o->ob_type == &PyWrapperDescr_Type) return "WrapperDescr"; + if (o->ob_type == &PyProperty_Type) return "Property"; + if (o->ob_type == &PyModule_Type) return "Module"; + if (o->ob_type == &PyRange_Type) return "Range"; + if (o->ob_type == &PySeqIter_Type) return "SeqIter"; + if (o->ob_type == &PyCallIter_Type) return "CallIter"; + if (o->ob_type == &PySlice_Type) return "Slice"; + if (o->ob_type == &PyString_Type) return "String"; + if (o->ob_type == &PySuper_Type) return "Super"; + if (o->ob_type == &PyTuple_Type) return "Tuple"; + if (o->ob_type == &PyType_Type) return "Type"; + if (o->ob_type == &PyUnicode_Type) return "Unicode"; + + if (o->ob_type == &mpw_Type) return "mpw"; + if (o->ob_type == &rng_Type) return "rng"; + + return "Unknown"; +} diff --git a/beecrypt/python/mpw-py.c b/beecrypt/python/mpw-py.c new file mode 100644 index 0000000..b2b51e1 --- /dev/null +++ b/beecrypt/python/mpw-py.c @@ -0,0 +1,2349 @@ +/** \ingroup py_c + * \file python/mpw-py.c + */ + +#define _REENTRANT 1 /* XXX config.h collides with pyconfig.h */ +#define _GNU_SOURCE /* XXX pick up stpcpy et al */ +#include "system.h" + +#include "Python.h" +#include "longintrepr.h" + +#ifdef __LCLINT__ +#undef PyObject_HEAD +#define PyObject_HEAD int _PyObjectHead; +#endif + +#include "mpw-py.h" +#include "rng-py.h" + +#include "debug-py.c" + +#include "debug.h" + +#define ABS(_x) ((_x) < 0 ? -(_x) : (_x)) +#if !defined(MAX) +#define MAX(x, y) ((x) < (y) ? (y) : (x)) +#endif +#if !defined(MIN) +#define MIN(x, y) ((x) > (y) ? (y) : (x)) +#endif + +#define MPBITCNT(_s, _d) (MP_WORDS_TO_BITS(_s) - mpmszcnt((_s), (_d))) + +#define BITS_TO_DIGITS(_b) (((_b) + SHIFT - 1)/SHIFT) +#define DIGITS_TO_BITS(_d) ((_d) * SHIFT) + +/*@unchecked@*/ +static int _ie = 0x44332211; +/*@unchecked@*/ +static union _dendian { +/*@unused@*/ + int i; + char b[4]; +} *_endian = (union _dendian *)&_ie; +#define IS_BIG_ENDIAN() (_endian->b[0] == '\x44') +#define IS_LITTLE_ENDIAN() (_endian->b[0] == '\x11') + +/*@unchecked@*/ +static int _mpw_debug = 0; + +/*@unchecked@*/ /*@observer@*/ +static const char *initialiser_name = ""; + +/*@unchecked@*/ /*@observer@*/ +static const struct { + /* Number of digits in the conversion base that always fits in an mp_limb_t. + For example, for base 10 on a machine where a mp_limb_t has 32 bits this + is 9, since 10**9 is the largest number that fits into a mp_limb_t. */ + int chars_per_limb; + + /* log(2)/log(conversion_base) */ + double chars_per_bit_exactly; + + /* base**chars_per_limb, i.e. the biggest number that fits a word, built by + factors of base. Exception: For 2, 4, 8, etc, big_base is log2(base), + i.e. the number of bits used to represent each digit in the base. */ + unsigned int big_base; + + /* A BITS_PER_MP_LIMB bit approximation to 1/big_base, represented as a + fixed-point number. Instead of dividing by big_base an application can + choose to multiply by big_base_inverted. */ + unsigned int big_base_inverted; +} mp_bases[257] = { + /* 0 */ {0, 0.0, 0, 0}, + /* 1 */ {0, 1e37, 0, 0}, + /* 2 */ {32, 1.0000000000000000, 0x1, 0x0}, + /* 3 */ {20, 0.6309297535714574, 0xcfd41b91, 0x3b563c24}, + /* 4 */ {16, 0.5000000000000000, 0x2, 0x0}, + /* 5 */ {13, 0.4306765580733931, 0x48c27395, 0xc25c2684}, + /* 6 */ {12, 0.3868528072345416, 0x81bf1000, 0xf91bd1b6}, + /* 7 */ {11, 0.3562071871080222, 0x75db9c97, 0x1607a2cb}, + /* 8 */ {10, 0.3333333333333333, 0x3, 0x0}, + /* 9 */ {10, 0.3154648767857287, 0xcfd41b91, 0x3b563c24}, + /* 10 */ {9, 0.3010299956639812, 0x3b9aca00, 0x12e0be82}, + /* 11 */ {9, 0.2890648263178878, 0x8c8b6d2b, 0xd24cde04}, + /* 12 */ {8, 0.2789429456511298, 0x19a10000, 0x3fa39ab5}, + /* 13 */ {8, 0.2702381544273197, 0x309f1021, 0x50f8ac5f}, + /* 14 */ {8, 0.2626495350371935, 0x57f6c100, 0x74843b1e}, + /* 15 */ {8, 0.2559580248098155, 0x98c29b81, 0xad0326c2}, + /* 16 */ {8, 0.2500000000000000, 0x4, 0x0}, + /* 17 */ {7, 0.2446505421182260, 0x18754571, 0x4ef0b6bd}, + /* 18 */ {7, 0.2398124665681314, 0x247dbc80, 0xc0fc48a1}, + /* 19 */ {7, 0.2354089133666382, 0x3547667b, 0x33838942}, + /* 20 */ {7, 0.2313782131597592, 0x4c4b4000, 0xad7f29ab}, + /* 21 */ {7, 0.2276702486969530, 0x6b5a6e1d, 0x313c3d15}, + /* 22 */ {7, 0.2242438242175754, 0x94ace180, 0xb8cca9e0}, + /* 23 */ {7, 0.2210647294575037, 0xcaf18367, 0x42ed6de9}, + /* 24 */ {6, 0.2181042919855316, 0xb640000, 0x67980e0b}, + /* 25 */ {6, 0.2153382790366965, 0xe8d4a51, 0x19799812}, + /* 26 */ {6, 0.2127460535533632, 0x1269ae40, 0xbce85396}, + /* 27 */ {6, 0.2103099178571525, 0x17179149, 0x62c103a9}, + /* 28 */ {6, 0.2080145976765095, 0x1cb91000, 0x1d353d43}, + /* 29 */ {6, 0.2058468324604344, 0x23744899, 0xce1decea}, + /* 30 */ {6, 0.2037950470905062, 0x2b73a840, 0x790fc511}, + /* 31 */ {6, 0.2018490865820999, 0x34e63b41, 0x35b865a0}, + /* 32 */ {6, 0.2000000000000000, 0x5, 0x0}, + /* 33 */ {6, 0.1982398631705605, 0x4cfa3cc1, 0xa9aed1b3}, + /* 34 */ {6, 0.1965616322328226, 0x5c13d840, 0x63dfc229}, + /* 35 */ {6, 0.1949590218937863, 0x6d91b519, 0x2b0fee30}, + /* 36 */ {6, 0.1934264036172708, 0x81bf1000, 0xf91bd1b6}, + /* 37 */ {6, 0.1919587200065601, 0x98ede0c9, 0xac89c3a9}, + /* 38 */ {6, 0.1905514124267734, 0xb3773e40, 0x6d2c32fe}, + /* 39 */ {6, 0.1892003595168700, 0xd1bbc4d1, 0x387907c9}, + /* 40 */ {6, 0.1879018247091076, 0xf4240000, 0xc6f7a0b}, + /* 41 */ {5, 0.1866524112389434, 0x6e7d349, 0x28928154}, + /* 42 */ {5, 0.1854490234153689, 0x7ca30a0, 0x6e8629d}, + /* 43 */ {5, 0.1842888331487062, 0x8c32bbb, 0xd373dca0}, + /* 44 */ {5, 0.1831692509136336, 0x9d46c00, 0xa0b17895}, + /* 45 */ {5, 0.1820879004699383, 0xaffacfd, 0x746811a5}, + /* 46 */ {5, 0.1810425967800402, 0xc46bee0, 0x4da6500f}, + /* 47 */ {5, 0.1800313266566926, 0xdab86ef, 0x2ba23582}, + /* 48 */ {5, 0.1790522317510414, 0xf300000, 0xdb20a88}, + /* 49 */ {5, 0.1781035935540111, 0x10d63af1, 0xe68d5ce4}, + /* 50 */ {5, 0.1771838201355579, 0x12a05f20, 0xb7cdfd9d}, + /* 51 */ {5, 0.1762914343888821, 0x1490aae3, 0x8e583933}, + /* 52 */ {5, 0.1754250635819545, 0x16a97400, 0x697cc3ea}, + /* 53 */ {5, 0.1745834300480449, 0x18ed2825, 0x48a5ca6c}, + /* 54 */ {5, 0.1737653428714400, 0x1b5e4d60, 0x2b52db16}, + /* 55 */ {5, 0.1729696904450771, 0x1dff8297, 0x111586a6}, + /* 56 */ {5, 0.1721954337940981, 0x20d38000, 0xf31d2b36}, + /* 57 */ {5, 0.1714416005739134, 0x23dd1799, 0xc8d76d19}, + /* 58 */ {5, 0.1707072796637201, 0x271f35a0, 0xa2cb1eb4}, + /* 59 */ {5, 0.1699916162869140, 0x2a9ce10b, 0x807c3ec3}, + /* 60 */ {5, 0.1692938075987814, 0x2e593c00, 0x617ec8bf}, + /* 61 */ {5, 0.1686130986895011, 0x3257844d, 0x45746cbe}, + /* 62 */ {5, 0.1679487789570419, 0x369b13e0, 0x2c0aa273}, + /* 63 */ {5, 0.1673001788101741, 0x3b27613f, 0x14f90805}, + /* 64 */ {5, 0.1666666666666667, 0x6, 0x0}, + /* 65 */ {5, 0.1660476462159378, 0x4528a141, 0xd9cf0829}, + /* 66 */ {5, 0.1654425539190583, 0x4aa51420, 0xb6fc4841}, + /* 67 */ {5, 0.1648508567221603, 0x50794633, 0x973054cb}, + /* 68 */ {5, 0.1642720499620502, 0x56a94400, 0x7a1dbe4b}, + /* 69 */ {5, 0.1637056554452156, 0x5d393975, 0x5f7fcd7f}, + /* 70 */ {5, 0.1631512196835108, 0x642d7260, 0x47196c84}, + /* 71 */ {5, 0.1626083122716342, 0x6b8a5ae7, 0x30b43635}, + /* 72 */ {5, 0.1620765243931223, 0x73548000, 0x1c1fa5f6}, + /* 73 */ {5, 0.1615554674429964, 0x7b908fe9, 0x930634a}, + /* 74 */ {5, 0.1610447717564444, 0x84435aa0, 0xef7f4a3c}, + /* 75 */ {5, 0.1605440854340214, 0x8d71d25b, 0xcf5552d2}, + /* 76 */ {5, 0.1600530732548213, 0x97210c00, 0xb1a47c8e}, + /* 77 */ {5, 0.1595714156699382, 0xa1563f9d, 0x9634b43e}, + /* 78 */ {5, 0.1590988078692941, 0xac16c8e0, 0x7cd3817d}, + /* 79 */ {5, 0.1586349589155960, 0xb768278f, 0x65536761}, + /* 80 */ {5, 0.1581795909397823, 0xc3500000, 0x4f8b588e}, + /* 81 */ {5, 0.1577324383928644, 0xcfd41b91, 0x3b563c24}, + /* 82 */ {5, 0.1572932473495469, 0xdcfa6920, 0x28928154}, + /* 83 */ {5, 0.1568617748594410, 0xeac8fd83, 0x1721bfb0}, + /* 84 */ {5, 0.1564377883420715, 0xf9461400, 0x6e8629d}, + /* 85 */ {4, 0.1560210650222250, 0x31c84b1, 0x491cc17c}, + /* 86 */ {4, 0.1556113914024939, 0x342ab10, 0x3a11d83b}, + /* 87 */ {4, 0.1552085627701551, 0x36a2c21, 0x2be074cd}, + /* 88 */ {4, 0.1548123827357682, 0x3931000, 0x1e7a02e7}, + /* 89 */ {4, 0.1544226628011101, 0x3bd5ee1, 0x11d10edd}, + /* 90 */ {4, 0.1540392219542636, 0x3e92110, 0x5d92c68}, + /* 91 */ {4, 0.1536618862898642, 0x4165ef1, 0xf50dbfb2}, + /* 92 */ {4, 0.1532904886526781, 0x4452100, 0xdf9f1316}, + /* 93 */ {4, 0.1529248683028321, 0x4756fd1, 0xcb52a684}, + /* 94 */ {4, 0.1525648706011593, 0x4a75410, 0xb8163e97}, + /* 95 */ {4, 0.1522103467132434, 0x4dad681, 0xa5d8f269}, + /* 96 */ {4, 0.1518611533308632, 0x5100000, 0x948b0fcd}, + /* 97 */ {4, 0.1515171524096389, 0x546d981, 0x841e0215}, + /* 98 */ {4, 0.1511782109217764, 0x57f6c10, 0x74843b1e}, + /* 99 */ {4, 0.1508442006228941, 0x5b9c0d1, 0x65b11e6e}, + /* 100 */ {4, 0.1505149978319906, 0x5f5e100, 0x5798ee23}, + /* 101 */ {4, 0.1501904832236880, 0x633d5f1, 0x4a30b99b}, + /* 102 */ {4, 0.1498705416319474, 0x673a910, 0x3d6e4d94}, + /* 103 */ {4, 0.1495550618645152, 0x6b563e1, 0x314825b0}, + /* 104 */ {4, 0.1492439365274121, 0x6f91000, 0x25b55f2e}, + /* 105 */ {4, 0.1489370618588283, 0x73eb721, 0x1aadaccb}, + /* 106 */ {4, 0.1486343375718350, 0x7866310, 0x10294ba2}, + /* 107 */ {4, 0.1483356667053617, 0x7d01db1, 0x620f8f6}, + /* 108 */ {4, 0.1480409554829326, 0x81bf100, 0xf91bd1b6}, + /* 109 */ {4, 0.1477501131786861, 0x869e711, 0xe6d37b2a}, + /* 110 */ {4, 0.1474630519902391, 0x8ba0a10, 0xd55cff6e}, + /* 111 */ {4, 0.1471796869179852, 0x90c6441, 0xc4ad2db2}, + /* 112 */ {4, 0.1468999356504447, 0x9610000, 0xb4b985cf}, + /* 113 */ {4, 0.1466237184553111, 0x9b7e7c1, 0xa5782bef}, + /* 114 */ {4, 0.1463509580758620, 0xa112610, 0x96dfdd2a}, + /* 115 */ {4, 0.1460815796324244, 0xa6cc591, 0x88e7e509}, + /* 116 */ {4, 0.1458155105286054, 0xacad100, 0x7b8813d3}, + /* 117 */ {4, 0.1455526803620167, 0xb2b5331, 0x6eb8b595}, + /* 118 */ {4, 0.1452930208392429, 0xb8e5710, 0x627289db}, + /* 119 */ {4, 0.1450364656948130, 0xbf3e7a1, 0x56aebc07}, + /* 120 */ {4, 0.1447829506139581, 0xc5c1000, 0x4b66dc33}, + /* 121 */ {4, 0.1445324131589439, 0xcc6db61, 0x4094d8a3}, + /* 122 */ {4, 0.1442847926987864, 0xd345510, 0x3632f7a5}, + /* 123 */ {4, 0.1440400303421672, 0xda48871, 0x2c3bd1f0}, + /* 124 */ {4, 0.1437980688733776, 0xe178100, 0x22aa4d5f}, + /* 125 */ {4, 0.1435588526911310, 0xe8d4a51, 0x19799812}, + /* 126 */ {4, 0.1433223277500932, 0xf05f010, 0x10a523e5}, + /* 127 */ {4, 0.1430884415049874, 0xf817e01, 0x828a237}, + /* 128 */ {4, 0.1428571428571428, 0x7, 0x0}, + /* 129 */ {4, 0.1426283821033600, 0x10818201, 0xf04ec452}, + /* 130 */ {4, 0.1424021108869747, 0x11061010, 0xe136444a}, + /* 131 */ {4, 0.1421782821510107, 0x118db651, 0xd2af9589}, + /* 132 */ {4, 0.1419568500933153, 0x12188100, 0xc4b42a83}, + /* 133 */ {4, 0.1417377701235801, 0x12a67c71, 0xb73dccf5}, + /* 134 */ {4, 0.1415209988221527, 0x1337b510, 0xaa4698c5}, + /* 135 */ {4, 0.1413064939005528, 0x13cc3761, 0x9dc8f729}, + /* 136 */ {4, 0.1410942141636095, 0x14641000, 0x91bf9a30}, + /* 137 */ {4, 0.1408841194731412, 0x14ff4ba1, 0x86257887}, + /* 138 */ {4, 0.1406761707131039, 0x159df710, 0x7af5c98c}, + /* 139 */ {4, 0.1404703297561400, 0x16401f31, 0x702c01a0}, + /* 140 */ {4, 0.1402665594314587, 0x16e5d100, 0x65c3ceb1}, + /* 141 */ {4, 0.1400648234939879, 0x178f1991, 0x5bb91502}, + /* 142 */ {4, 0.1398650865947379, 0x183c0610, 0x5207ec23}, + /* 143 */ {4, 0.1396673142523192, 0x18eca3c1, 0x48ac9c19}, + /* 144 */ {4, 0.1394714728255649, 0x19a10000, 0x3fa39ab5}, + /* 145 */ {4, 0.1392775294872041, 0x1a592841, 0x36e98912}, + /* 146 */ {4, 0.1390854521985406, 0x1b152a10, 0x2e7b3140}, + /* 147 */ {4, 0.1388952096850913, 0x1bd51311, 0x2655840b}, + /* 148 */ {4, 0.1387067714131417, 0x1c98f100, 0x1e7596ea}, + /* 149 */ {4, 0.1385201075671774, 0x1d60d1b1, 0x16d8a20d}, + /* 150 */ {4, 0.1383351890281539, 0x1e2cc310, 0xf7bfe87}, + /* 151 */ {4, 0.1381519873525671, 0x1efcd321, 0x85d2492}, + /* 152 */ {4, 0.1379704747522905, 0x1fd11000, 0x179a9f4}, + /* 153 */ {4, 0.1377906240751463, 0x20a987e1, 0xf59e80eb}, + /* 154 */ {4, 0.1376124087861776, 0x21864910, 0xe8b768db}, + /* 155 */ {4, 0.1374358029495937, 0x226761f1, 0xdc39d6d5}, + /* 156 */ {4, 0.1372607812113589, 0x234ce100, 0xd021c5d1}, + /* 157 */ {4, 0.1370873187823978, 0x2436d4d1, 0xc46b5e37}, + /* 158 */ {4, 0.1369153914223921, 0x25254c10, 0xb912f39c}, + /* 159 */ {4, 0.1367449754241439, 0x26185581, 0xae150294}, + /* 160 */ {4, 0.1365760475984821, 0x27100000, 0xa36e2eb1}, + /* 161 */ {4, 0.1364085852596902, 0x280c5a81, 0x991b4094}, + /* 162 */ {4, 0.1362425662114337, 0x290d7410, 0x8f19241e}, + /* 163 */ {4, 0.1360779687331669, 0x2a135bd1, 0x8564e6b7}, + /* 164 */ {4, 0.1359147715670014, 0x2b1e2100, 0x7bfbb5b4}, + /* 165 */ {4, 0.1357529539050150, 0x2c2dd2f1, 0x72dadcc8}, + /* 166 */ {4, 0.1355924953769864, 0x2d428110, 0x69ffc498}, + /* 167 */ {4, 0.1354333760385373, 0x2e5c3ae1, 0x6167f154}, + /* 168 */ {4, 0.1352755763596663, 0x2f7b1000, 0x5911016e}, + /* 169 */ {4, 0.1351190772136599, 0x309f1021, 0x50f8ac5f}, + /* 170 */ {4, 0.1349638598663645, 0x31c84b10, 0x491cc17c}, + /* 171 */ {4, 0.1348099059658080, 0x32f6d0b1, 0x417b26d8}, + /* 172 */ {4, 0.1346571975321549, 0x342ab100, 0x3a11d83b}, + /* 173 */ {4, 0.1345057169479844, 0x3563fc11, 0x32dee622}, + /* 174 */ {4, 0.1343554469488779, 0x36a2c210, 0x2be074cd}, + /* 175 */ {4, 0.1342063706143054, 0x37e71341, 0x2514bb58}, + /* 176 */ {4, 0.1340584713587979, 0x39310000, 0x1e7a02e7}, + /* 177 */ {4, 0.1339117329233981, 0x3a8098c1, 0x180ea5d0}, + /* 178 */ {4, 0.1337661393673756, 0x3bd5ee10, 0x11d10edd}, + /* 179 */ {4, 0.1336216750601996, 0x3d311091, 0xbbfb88e}, + /* 180 */ {4, 0.1334783246737591, 0x3e921100, 0x5d92c68}, + /* 181 */ {4, 0.1333360731748201, 0x3ff90031, 0x1c024c}, + /* 182 */ {4, 0.1331949058177136, 0x4165ef10, 0xf50dbfb2}, + /* 183 */ {4, 0.1330548081372441, 0x42d8eea1, 0xea30efa3}, + /* 184 */ {4, 0.1329157659418126, 0x44521000, 0xdf9f1316}, + /* 185 */ {4, 0.1327777653067443, 0x45d16461, 0xd555c0c9}, + /* 186 */ {4, 0.1326407925678156, 0x4756fd10, 0xcb52a684}, + /* 187 */ {4, 0.1325048343149731, 0x48e2eb71, 0xc193881f}, + /* 188 */ {4, 0.1323698773862368, 0x4a754100, 0xb8163e97}, + /* 189 */ {4, 0.1322359088617821, 0x4c0e0f51, 0xaed8b724}, + /* 190 */ {4, 0.1321029160581950, 0x4dad6810, 0xa5d8f269}, + /* 191 */ {4, 0.1319708865228925, 0x4f535d01, 0x9d15039d}, + /* 192 */ {4, 0.1318398080287045, 0x51000000, 0x948b0fcd}, + /* 193 */ {4, 0.1317096685686114, 0x52b36301, 0x8c394d1d}, + /* 194 */ {4, 0.1315804563506306, 0x546d9810, 0x841e0215}, + /* 195 */ {4, 0.1314521597928493, 0x562eb151, 0x7c3784f8}, + /* 196 */ {4, 0.1313247675185968, 0x57f6c100, 0x74843b1e}, + /* 197 */ {4, 0.1311982683517524, 0x59c5d971, 0x6d02985d}, + /* 198 */ {4, 0.1310726513121843, 0x5b9c0d10, 0x65b11e6e}, + /* 199 */ {4, 0.1309479056113158, 0x5d796e61, 0x5e8e5c64}, + /* 200 */ {4, 0.1308240206478128, 0x5f5e1000, 0x5798ee23}, + /* 201 */ {4, 0.1307009860033912, 0x614a04a1, 0x50cf7bde}, + /* 202 */ {4, 0.1305787914387386, 0x633d5f10, 0x4a30b99b}, + /* 203 */ {4, 0.1304574268895465, 0x65383231, 0x43bb66bd}, + /* 204 */ {4, 0.1303368824626505, 0x673a9100, 0x3d6e4d94}, + /* 205 */ {4, 0.1302171484322746, 0x69448e91, 0x374842ee}, + /* 206 */ {4, 0.1300982152363760, 0x6b563e10, 0x314825b0}, + /* 207 */ {4, 0.1299800734730872, 0x6d6fb2c1, 0x2b6cde75}, + /* 208 */ {4, 0.1298627138972530, 0x6f910000, 0x25b55f2e}, + /* 209 */ {4, 0.1297461274170591, 0x71ba3941, 0x2020a2c5}, + /* 210 */ {4, 0.1296303050907487, 0x73eb7210, 0x1aadaccb}, + /* 211 */ {4, 0.1295152381234257, 0x7624be11, 0x155b891f}, + /* 212 */ {4, 0.1294009178639407, 0x78663100, 0x10294ba2}, + /* 213 */ {4, 0.1292873358018581, 0x7aafdeb1, 0xb160fe9}, + /* 214 */ {4, 0.1291744835645007, 0x7d01db10, 0x620f8f6}, + /* 215 */ {4, 0.1290623529140715, 0x7f5c3a21, 0x14930ef}, + /* 216 */ {4, 0.1289509357448472, 0x81bf1000, 0xf91bd1b6}, + /* 217 */ {4, 0.1288402240804449, 0x842a70e1, 0xefdcb0c7}, + /* 218 */ {4, 0.1287302100711566, 0x869e7110, 0xe6d37b2a}, + /* 219 */ {4, 0.1286208859913518, 0x891b24f1, 0xddfeb94a}, + /* 220 */ {4, 0.1285122442369443, 0x8ba0a100, 0xd55cff6e}, + /* 221 */ {4, 0.1284042773229231, 0x8e2ef9d1, 0xcceced50}, + /* 222 */ {4, 0.1282969778809442, 0x90c64410, 0xc4ad2db2}, + /* 223 */ {4, 0.1281903386569819, 0x93669481, 0xbc9c75f9}, + /* 224 */ {4, 0.1280843525090381, 0x96100000, 0xb4b985cf}, + /* 225 */ {4, 0.1279790124049077, 0x98c29b81, 0xad0326c2}, + /* 226 */ {4, 0.1278743114199984, 0x9b7e7c10, 0xa5782bef}, + /* 227 */ {4, 0.1277702427352035, 0x9e43b6d1, 0x9e1771a9}, + /* 228 */ {4, 0.1276667996348261, 0xa1126100, 0x96dfdd2a}, + /* 229 */ {4, 0.1275639755045533, 0xa3ea8ff1, 0x8fd05c41}, + /* 230 */ {4, 0.1274617638294791, 0xa6cc5910, 0x88e7e509}, + /* 231 */ {4, 0.1273601581921740, 0xa9b7d1e1, 0x8225759d}, + /* 232 */ {4, 0.1272591522708010, 0xacad1000, 0x7b8813d3}, + /* 233 */ {4, 0.1271587398372755, 0xafac2921, 0x750eccf9}, + /* 234 */ {4, 0.1270589147554692, 0xb2b53310, 0x6eb8b595}, + /* 235 */ {4, 0.1269596709794558, 0xb5c843b1, 0x6884e923}, + /* 236 */ {4, 0.1268610025517973, 0xb8e57100, 0x627289db}, + /* 237 */ {4, 0.1267629036018709, 0xbc0cd111, 0x5c80c07b}, + /* 238 */ {4, 0.1266653683442337, 0xbf3e7a10, 0x56aebc07}, + /* 239 */ {4, 0.1265683910770258, 0xc27a8241, 0x50fbb19b}, + /* 240 */ {4, 0.1264719661804097, 0xc5c10000, 0x4b66dc33}, + /* 241 */ {4, 0.1263760881150453, 0xc91209c1, 0x45ef7c7c}, + /* 242 */ {4, 0.1262807514205999, 0xcc6db610, 0x4094d8a3}, + /* 243 */ {4, 0.1261859507142915, 0xcfd41b91, 0x3b563c24}, + /* 244 */ {4, 0.1260916806894653, 0xd3455100, 0x3632f7a5}, + /* 245 */ {4, 0.1259979361142023, 0xd6c16d31, 0x312a60c3}, + /* 246 */ {4, 0.1259047118299582, 0xda488710, 0x2c3bd1f0}, + /* 247 */ {4, 0.1258120027502338, 0xdddab5a1, 0x2766aa45}, + /* 248 */ {4, 0.1257198038592741, 0xe1781000, 0x22aa4d5f}, + /* 249 */ {4, 0.1256281102107963, 0xe520ad61, 0x1e06233c}, + /* 250 */ {4, 0.1255369169267456, 0xe8d4a510, 0x19799812}, + /* 251 */ {4, 0.1254462191960791, 0xec940e71, 0x15041c33}, + /* 252 */ {4, 0.1253560122735751, 0xf05f0100, 0x10a523e5}, + /* 253 */ {4, 0.1252662914786691, 0xf4359451, 0xc5c2749}, + /* 254 */ {4, 0.1251770521943144, 0xf817e010, 0x828a237}, + /* 255 */ {4, 0.1250882898658681, 0xfc05fc01, 0x40a1423}, + /* 256 */ {4, 0.1250000000000000, 0x8, 0x0}, +}; + +static void prtmpw(const char * msg, mpwObject * x) + /*@global stderr, fileSystem @*/ + /*@modifies stderr, fileSystem @*/ +{ +fprintf(stderr, "%5.5s %p[%d]:\t", msg, MPW_DATA(x), MPW_SIZE(x)), mpfprintln(stderr, MPW_SIZE(x), MPW_DATA(x)); +} + +static size_t +mpsizeinbase(size_t xsize, mpw* xdata, size_t base) + /*@*/ +{ + size_t nbits; + size_t res; + + if (xsize == 0) + return 1; + + /* XXX assumes positive integer. */ + nbits = MP_WORDS_TO_BITS(xsize) - mpmszcnt(xsize, xdata); + if ((base & (base-1)) == 0) { /* exact power of 2 */ + size_t lbits = mp_bases[base].big_base; + res = (nbits + (lbits - 1)) / lbits; + } else { + res = (nbits * mp_bases[base].chars_per_bit_exactly) + 1; + } +if (_mpw_debug < -1) +fprintf(stderr, "*** mpsizeinbase(%p[%d], %d) res %u\n", xdata, xsize, base, (unsigned)res); + return res; +} + +#ifdef DYING +/*@-boundswrite@*/ +static void myndivmod(mpw* result, size_t xsize, const mpw* xdata, size_t ysize, const mpw* ydata, register mpw* workspace) +{ + /* result must be xsize+1 in length */ + /* workspace must be ysize+1 in length */ + /* expect ydata to be normalized */ + mpw q; + mpw msw = *ydata; + size_t qsize = xsize-ysize; + + *result = (mpge(ysize, xdata, ydata) ? 1 : 0); + mpcopy(xsize, result+1, xdata); + if (*result) + (void) mpsub(ysize, result+1, ydata); + result++; + + while (qsize--) + { + q = mppndiv(result[0], result[1], msw); + +/*@-evalorder@*/ + *workspace = mpsetmul(ysize, workspace+1, ydata, q); +/*@=evalorder@*/ + + while (mplt(ysize+1, result, workspace)) + { + (void) mpsubx(ysize+1, workspace, ysize, ydata); + q--; + } + (void) mpsub(ysize+1, result, workspace); + *(result++) = q; + } +} +/*@=boundswrite@*/ +#endif + +static char * +mpstr(char * t, size_t nt, size_t size, mpw* data, mpw base) + /*@modifies t @*/ +{ + static char bchars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + size_t asize = size + 1; + mpw* adata = alloca(asize * sizeof(*adata)); + size_t anorm; + mpw* zdata = alloca((asize+1) * sizeof(*zdata)); + mpw* wksp = alloca((1+1) * sizeof(*wksp)); + size_t result; + +if (_mpw_debug < -1) +fprintf(stderr, "*** mpstr(%p[%d], %p[%d], %d):\t", t, nt, data, size, base), mpfprintln(stderr, size, data); + + mpsetx(asize, adata, size, data); + + t[nt] = '\0'; + while (nt--) { + + mpndivmod(zdata, asize, adata, 1, &base, wksp); + +if (_mpw_debug < -1) { +fprintf(stderr, " a %p[%d]:\t", adata, asize), mpfprintln(stderr, asize, adata); +fprintf(stderr, " z %p[%d]:\t", zdata, asize+1), mpfprintln(stderr, asize+1, zdata); +} + result = zdata[asize]; + t[nt] = bchars[result]; + + if (mpz(asize, zdata)) + break; + + anorm = asize - mpsize(asize, zdata); + if (anorm < asize) + asize -= anorm; + mpsetx(asize+1, adata, asize, zdata+anorm); + asize++; + } + /* XXX Fill leading zeroes (if any). */ + while (nt--) + t[nt] = '0'; + return t; +} + +static PyObject * +mpw_format(mpwObject * z, size_t base, int addL) + /*@modifies t @*/ +{ + size_t zsize = MPW_SIZE(z); + mpw* zdata = MPW_DATA(z); + PyStringObject * so; + size_t i; + size_t nt; + size_t size; + mpw* data; + char * t, * te; + char prefix[5]; + char * tcp = prefix; + int sign; + + if (z == NULL || !mpw_Check(z)) { + PyErr_BadInternalCall(); + return NULL; + } + +if (_mpw_debug < -1) +fprintf(stderr, "*** mpw_format(%p,%d,%d):\t", z, base, addL), mpfprintln(stderr, zsize, zdata); + + assert(base >= 2 && base <= 36); + + i = 0; + if (addL && initialiser_name != NULL) + i = strlen(initialiser_name) + 2; /* e.g. 'mpw(' + ')' */ + + sign = z->ob_size; + nt = MPBITCNT(zsize, zdata); + if (nt == 0) { + base = 10; /* '0' in every base, right */ + nt = 1; + size = 1; + data = alloca(size * sizeof(*data)); + *data = 0; + } else if (sign < 0) { + *tcp++ = '-'; + i += 1; /* space to hold '-' */ + size = MP_ROUND_B2W(nt); + data = zdata + (zsize - size); + } else { + size = MP_ROUND_B2W(nt); + data = zdata + (zsize - size); + } + + if (addL && size > 1) + i++; /* space for 'L' suffix */ + + nt = mpsizeinbase(size, data, base); + i += nt; + + if (base == 16) { + *tcp++ = '0'; + *tcp++ = 'x'; + i += 2; /* space to hold '0x' */ + } else if (base == 8) { + *tcp++ = '0'; + i += 1; /* space to hold the extra '0' */ + } else if (base > 10) { + *tcp++ = '0' + base / 10; + *tcp++ = '0' + base % 10; + *tcp++ = '#'; + i += 3; /* space to hold e.g. '12#' */ + } else if (base < 10) { + *tcp++ = '0' + base; + *tcp++ = '#'; + i += 2; /* space to hold e.g. '6#' */ + } + + so = (PyStringObject *)PyString_FromStringAndSize((char *)0, i); + if (so == NULL) + return NULL; + + /* get the beginning of the string memory and start copying things */ + te = PyString_AS_STRING(so); + if (addL && initialiser_name != NULL && *initialiser_name != '\0') { + te = stpcpy(te, initialiser_name); + *te++ = '('; /*')'*/ + } + + /* copy the already prepared prefix; e.g. sign and base indicator */ + *tcp = '\0'; + t = te = stpcpy(te, prefix); + + (void) mpstr(te, nt, size, data, base); + + /* Nuke leading zeroes. */ + nt = 0; + while (t[nt] == '0') + nt++; + if (t[nt] == '\0') /* all zeroes special case. */ + nt--; + if (nt > 0) + do { + *t = t[nt]; + } while (*t++ != '\0'); + + te += strlen(te); + + if (addL) { + if (size > 1) + *te++ = 'L'; + if (initialiser_name != NULL && *initialiser_name != '\0') + *te++ = /*'('*/ ')'; + } + *te = '\0'; + + assert(te - PyString_AS_STRING(so) <= i); + + if (te - PyString_AS_STRING(so) != i) + so->ob_size -= i - (te - PyString_AS_STRING(so)); + + return (PyObject *)so; +} + +/** + * Precomputes the sliding window table for computing powers of x. + * + * Sliding Window Exponentiation, Algorithm 14.85 in "Handbook of Applied Cryptography". + * + * First of all, the table with the powers of g can be reduced by + * about half; the even powers don't need to be accessed or stored. + * + * Get up to K bits starting with a one, if we have that many still available. + * + * Do the number of squarings of A in the first column, then multiply by + * the value in column two, and finally do the number of squarings in + * column three. + * + * This table can be used for K=2,3,4 and can be extended. + * + * +\verbatim + 0 : - | - | - + 1 : 1 | g1 @ 0 | 0 + 10 : 1 | g1 @ 0 | 1 + 11 : 2 | g3 @ 1 | 0 + 100 : 1 | g1 @ 0 | 2 + 101 : 3 | g5 @ 2 | 0 + 110 : 2 | g3 @ 1 | 1 + 111 : 3 | g7 @ 3 | 0 + 1000 : 1 | g1 @ 0 | 3 + 1001 : 4 | g9 @ 4 | 0 + 1010 : 3 | g5 @ 2 | 1 + 1011 : 4 | g11 @ 5 | 0 + 1100 : 2 | g3 @ 1 | 2 + 1101 : 4 | g13 @ 6 | 0 + 1110 : 3 | g7 @ 3 | 1 + 1111 : 4 | g15 @ 7 | 0 +\endverbatim + * + */ +static void mpslide(size_t xsize, const mpw* xdata, + size_t size, /*@out@*/ mpw* slide) + /*@modifies slide @*/ +{ + size_t rsize = (xsize > size ? xsize : size); + mpw* result = alloca(2 * rsize * sizeof(*result)); + + mpsqr(result, xsize, xdata); /* x^2 temp */ + mpsetx(size, slide, xsize+xsize, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^2:\t"), mpfprintln(stderr, size, slide); + mpmul(result, xsize, xdata, size, slide); /* x^3 */ + mpsetx(size, slide+size, xsize+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^3:\t"), mpfprintln(stderr, size, slide+size); + mpmul(result, size, slide, size, slide+size); /* x^5 */ + mpsetx(size, slide+2*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^5:\t"), mpfprintln(stderr, size, slide+2*size); + mpmul(result, size, slide, size, slide+2*size); /* x^7 */ + mpsetx(size, slide+3*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^7:\t"), mpfprintln(stderr, size, slide+3*size); + mpmul(result, size, slide, size, slide+3*size); /* x^9 */ + mpsetx(size, slide+4*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^9:\t"), mpfprintln(stderr, size, slide+4*size); + mpmul(result, size, slide, size, slide+4*size); /* x^11 */ + mpsetx(size, slide+5*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^11:\t"), mpfprintln(stderr, size, slide+5*size); + mpmul(result, size, slide, size, slide+5*size); /* x^13 */ + mpsetx(size, slide+6*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^13:\t"), mpfprintln(stderr, size, slide+6*size); + mpmul(result, size, slide, size, slide+6*size); /* x^15 */ + mpsetx(size, slide+7*size, size+size, result); +if (_mpw_debug < 0) +fprintf(stderr, "\t x^15:\t"), mpfprintln(stderr, size, slide+7*size); + mpsetx(size, slide, xsize, xdata); /* x^1 */ +if (_mpw_debug < 0) +fprintf(stderr, "\t x^1:\t"), mpfprintln(stderr, size, slide); +} + +/*@observer@*/ /*@unchecked@*/ +static byte mpslide_presq[16] = +{ 0, 1, 1, 2, 1, 3, 2, 3, 1, 4, 3, 4, 2, 4, 3, 4 }; + +/*@observer@*/ /*@unchecked@*/ +static byte mpslide_mulg[16] = +{ 0, 0, 0, 1, 0, 2, 1, 3, 0, 4, 2, 5, 1, 6, 3, 7 }; + +/*@observer@*/ /*@unchecked@*/ +static byte mpslide_postsq[16] = +{ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + +/** + * Exponentiation with precomputed sliding window table. + */ +/*@-boundsread@*/ +static void mpnpowsld_w(mpnumber* n, size_t size, const mpw* slide, + size_t psize, const mpw* pdata) + /*@modifies n @*/ +{ + size_t rsize = (n->size > size ? n->size : size); + mpw* rdata = alloca(2 * rsize * sizeof(*rdata)); + short lbits = 0; + short kbits = 0; + byte s; + mpw temp; + short count; + +if (_mpw_debug < 0) +fprintf(stderr, "npowsld: p\t"), mpfprintln(stderr, psize, pdata); + /* 2. A = 1, i = t. */ + mpzero(n->size, n->data); + n->data[n->size-1] = 1; + + /* Find first bit set in exponent. */ + temp = *pdata; + count = 8 * sizeof(temp); + while (count != 0) { + if (temp & MP_MSBMASK) + break; + temp <<= 1; + count--; + } + + while (psize) { + while (count != 0) { + + /* Shift next bit of exponent into sliding window. */ + kbits <<= 1; + if (temp & MP_MSBMASK) + kbits++; + + /* On 1st non-zero in window, try to collect K bits. */ + if (kbits != 0) { + if (lbits != 0) + lbits++; + else if (temp & MP_MSBMASK) + lbits = 1; + else + {}; + + /* If window is full, then compute and clear window. */ + if (lbits == 4) { +if (_mpw_debug < 0) +fprintf(stderr, "*** #1 lbits %d kbits %d\n", lbits, kbits); + for (s = mpslide_presq[kbits]; s > 0; s--) { + mpsqr(rdata, n->size, n->data); + mpsetx(n->size, n->data, 2*n->size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\t pre1:\t"), mpfprintln(stderr, n->size, n->data); + } + + mpmul(rdata, n->size, n->data, + size, slide+mpslide_mulg[kbits]*size); + mpsetx(n->size, n->data, n->size+size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\t mul1:\t"), mpfprintln(stderr, n->size, n->data); + + for (s = mpslide_postsq[kbits]; s > 0; s--) { + mpsqr(rdata, n->size, n->data); + mpsetx(n->size, n->data, 2*n->size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\tpost1:\t"), mpfprintln(stderr, n->size, n->data); + } + + lbits = kbits = 0; + } + } else { + mpsqr(rdata, n->size, n->data); + mpsetx(n->size, n->data, 2*n->size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\t sqr:\t"), mpfprintln(stderr, n->size, n->data); + } + + temp <<= 1; + count--; + } + if (--psize) { + count = 8 * sizeof(temp); + temp = *(pdata++); + } + } + + if (kbits != 0) { +if (_mpw_debug < 0) +fprintf(stderr, "*** #1 lbits %d kbits %d\n", lbits, kbits); + for (s = mpslide_presq[kbits]; s > 0; s--) { + mpsqr(rdata, n->size, n->data); + mpsetx(n->size, n->data, 2*n->size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\t pre2:\t"), mpfprintln(stderr, n->size, n->data); + } + + mpmul(rdata, n->size, n->data, + size, slide+mpslide_mulg[kbits]*size); + mpsetx(n->size, n->data, n->size+size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\t mul2:\t"), mpfprintln(stderr, n->size, n->data); + + for (s = mpslide_postsq[kbits]; s > 0; s--) { + mpsqr(rdata, n->size, n->data); + mpsetx(n->size, n->data, 2*n->size, rdata); +if (_mpw_debug < 0) +fprintf(stderr, "\tpost2:\t"), mpfprintln(stderr, n->size, n->data); + } + } +} +/*@=boundsread@*/ + +/** + * mpnpow_w + * + * Uses sliding window exponentiation; needs extra storage: + * if K=3, needs 4*size, if K=4, needs 8*size + */ +/*@-boundsread@*/ +static void mpnpow_w(mpnumber* n, size_t xsize, const mpw* xdata, + size_t psize, const mpw* pdata) + /*@modifies n @*/ +{ + size_t xbits = MPBITCNT(xsize, xdata); + size_t pbits = MPBITCNT(psize, pdata); + size_t nbits; + mpw *slide; + size_t nsize; + size_t size; + + /* Special case: 0**P and X**(-P) */ + if (xbits == 0 || (psize > 0 && mpmsbset(psize, pdata))) { + mpnsetw(n, 0); + return; + } + /* Special case: X**0 and 1**P */ + if (pbits == 0 || mpisone(xsize, xdata)) { + mpnsetw(n, 1); + return; + } + + /* Normalize (to mpw boundary) exponent. */ + pdata += psize - MP_ROUND_B2W(pbits); + psize -= MP_BITS_TO_WORDS(pbits); + + /* Calculate size of result. */ + if (xbits == 0) xbits = 1; + nbits = (*pdata) * xbits; + nsize = MP_ROUND_B2W(nbits); + + /* XXX Add 1 word to carry sign bit */ + if (!mpmsbset(xsize, xdata) && (nbits & (MP_WBITS - 1)) == 0) + nsize++; + + size = MP_ROUND_B2W(15 * xbits); + +if (_mpw_debug < 0) +fprintf(stderr, "*** pbits %d xbits %d nsize %d size %d\n", pbits, xbits, nsize, size); + mpnsize(n, nsize); + + /* 1. Precompute odd powers of x (up to 2**K). */ + slide = (mpw*) alloca( (8*size) * sizeof(mpw)); + + mpslide(xsize, xdata, size, slide); + + /*@-internalglobs -mods@*/ /* noisy */ + mpnpowsld_w(n, size, slide, psize, pdata); + /*@=internalglobs =mods@*/ + +} +/*@=boundsread@*/ + +/* ---------- */ + +mpwObject * +mpw_New(int ob_size) + /*@*/ +{ + size_t size = ABS(ob_size); + mpwObject * z; + + /* XXX Make sure that 0 has allocated space. */ + if (size == 0) + size++; + z = PyObject_NEW_VAR(mpwObject, &mpw_Type, size); + if (z == NULL) + return NULL; + + z->ob_size = ob_size; + + if (size > 0) + memset(&z->data, 0, size * sizeof(*z->data)); + + return z; +} + +static mpwObject * +mpw_Copy(mpwObject *a) + /*@*/ +{ + mpwObject * z; + + z = mpw_FromMPW(MPW_SIZE(a), MPW_DATA(a), 1); + if (z != NULL) + z->ob_size = a->ob_size; + return z; +} + +static mpwObject * +mpw_FromLong(long ival) + /*@*/ +{ + mpwObject * z = mpw_New(1); + + if (z == NULL) + return NULL; + + if (ival < 0) { + z->ob_size = -z->ob_size; + ival = -ival; + } + z->data[0] = (mpw) ival; + + return z; +} + +static mpwObject * +mpw_FromDouble(double dval) +{ + mpwObject * z = mpw_New(1); + + if (z == NULL) + return NULL; + + if (dval < 0) { + z->ob_size = -z->ob_size; + dval = -dval; + } + z->data[0] = (mpw) dval; + + return z; +} + +#ifdef NOTYET +static mpwObject * +mpw_FromString(const char * str, char ** sep, int base) + /*@*/ +{ + const char * s = str, * se; + mpwObject * z = NULL; + mpw zbase, zval; + int sign = 1; + int ndigits; + + if ((base != 0 && base < 2) || base > 36) { + PyErr_SetString(PyExc_ValueError, "mpw() arg 2 must be >= 2 and <= 36"); + return NULL; + } + while (*s != '\0' && isspace(Py_CHARMASK(*s))) + s++; + if (*s == '+') + ++s; + else if (*s == '-') { + ++s; + sign = -1; + } + while (*s != '\0' && isspace(Py_CHARMASK(*s))) + s++; + if (base == 0) { + if (s[0] != '0') + base = 10; + else if (s[1] == 'x' || s[1] == 'X') + base = 16; + else + base = 8; + } + if (base == 16 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + s += 2; + + /* Validate characters as digits of base. */ + for (se = s; *se != '\0'; se++) { + int k; + + if (*se <= '9') + k = *se - '0'; + else if (*se >= 'a') + k = *se - 'a' + 10; + else if (*se >= 'A') + k = *se - 'A' + 10; + else + k = -1; + if (k < 0 || k >= base) + break; + } + if (se == s) + goto onError; + + ndigits = (se - s); + + if (*se == 'L' || *se == 'l') + se++; + while (*se && isspace(Py_CHARMASK(*se))) + se++; + if (sep) + *sep = se; + if (*se != '\0') + goto onError; + + /* Allocate mpw. */ + + /* Convert digit string. */ + zbase = base; + for (se = s; *se != '\0'; se++) { + if (*se <= '9') + zval = *se - '0'; + else if (*se >= 'a') + zval = *se - 'a' + 10; + else if (*se >= 'A') + zval = *se - 'A' + 10; + } + + if (sign < 0 && z != NULL && z->ob_size != 0) + z->ob_size = -(z->ob_size); + + return z; + +onError: + PyErr_Format(PyExc_ValueError, "invalid literal for mpw(): %.200s", str); + Py_XDECREF(z); + return NULL; +} +#endif + +static mpwObject * +mpw_FromHEX(const char * hex) + /*@*/ +{ + size_t len = strlen(hex); + size_t size = MP_NIBBLES_TO_WORDS(len + MP_WNIBBLES - 1); + mpwObject * z = mpw_New(size); + + if (z != NULL && size > 0) + hs2ip(MPW_DATA(z), size, hex, len); + + return z; +} + +mpwObject * +mpw_FromMPW(size_t size, mpw* data, int normalize) +{ + mpwObject * z; + + if (normalize) { + size_t norm = size - MP_ROUND_B2W(MPBITCNT(size, data)); + if (norm > 0 && norm < size) { + size -= norm; + data += norm; + } + } + + z = mpw_New(size); + if (z == NULL) + return NULL; + + if (size > 0) + memcpy(&z->data, data, size * sizeof(*z->data)); + + return z; +} + +static mpwObject * +mpw_FromLongObject(PyLongObject *lo) + /*@*/ +{ + mpwObject * z; + int lsize = ABS(lo->ob_size); + int lbits = DIGITS_TO_BITS(lsize); + size_t zsize = MP_BITS_TO_WORDS(lbits) + 1; + mpw* zdata; + unsigned char * zb; + size_t nzb; + int is_littleendian = 0; + int is_signed = 0; + + lsize = zsize; + if (lo->ob_size < 0) + lsize = -lsize; + z = mpw_New(lsize); + if (z == NULL) + return NULL; + + zdata = MPW_DATA(z); + zb = (unsigned char *) zdata; + nzb = MP_WORDS_TO_BYTES(zsize); + + /* Grab long as big-endian unsigned octets. */ + if (_PyLong_AsByteArray(lo, zb, nzb, is_littleendian, is_signed)) { + Py_DECREF(z); + return NULL; + } + + /* Endian swap zdata's mpw elements. */ + if (IS_LITTLE_ENDIAN()) { + mpw w = 0; + int zx = 0; + while (nzb) { + w <<= 8; + w |= *zb++; + nzb--; + if ((nzb % MP_WBYTES) == 0) { + zdata[zx++] = w; + w = 0; + } + } + } + + return z; +} + +/* ---------- */ + +static void +mpw_dealloc(/*@only@*/mpwObject * s) + /*@modifies s @*/ +{ +if (_mpw_debug < -1) +fprintf(stderr, "*** mpw_dealloc(%p[%s])\n", s, lbl(s)); + + PyObject_Del(s); +} + +static int +mpw_compare(mpwObject * a, mpwObject * b) + /*@*/ +{ + size_t asize = MPW_SIZE(a); + mpw* adata = MPW_DATA(a); + size_t bsize = MPW_SIZE(b); + mpw* bdata = MPW_DATA(b); + int ret; + + if (mpeqx(asize, adata, bsize, bdata)) + ret = 0; + else if (mpgtx(asize, adata, bsize, bdata)) + ret = 1; + else + ret = -1; + +if (_mpw_debug) +fprintf(stderr, "*** mpw_compare(%p[%s],%p[%s]) ret %d\n", a, lbl(a), b, lbl(b), ret); + return ret; +} + +static PyObject * +mpw_repr(mpwObject * a) + /*@*/ +{ + PyObject * so = mpw_format(a, 10, 1); +if (_mpw_debug && so != NULL) +fprintf(stderr, "*** mpw_repr(%p): \"%s\"\n", a, PyString_AS_STRING(so)); + return so; +} + +/** \ingroup py_c + */ +static PyObject * +mpw_str(mpwObject * a) + /*@*/ +{ + PyObject * so = mpw_format(a, 10, 0); +if (so != NULL && _mpw_debug < -1) +fprintf(stderr, "*** mpw_str(%p): \"%s\"\n", a, PyString_AS_STRING(so)); + return so; +} + +#ifdef DYING +/** \ingroup py_c + */ +static int mpw_init(mpwObject * z, PyObject *args, PyObject *kwds) + /*@modifies s @*/ +{ + PyObject * o = NULL; + long l = 0; + + if (!PyArg_ParseTuple(args, "|O:Cvt", &o)) return -1; + + if (o == NULL) { + mpnsetw(&z->n, l); + } else if (PyInt_Check(o)) { + l = PyInt_AsLong(o); + mpnsetw(&z->n, l); + } else if (PyLong_Check(o)) { + PyLongObject *lo = (PyLongObject *)o; + int lsize = ABS(lo->ob_size); + int lbits = DIGITS_TO_BITS(lsize); + size_t zsize = MP_BITS_TO_WORDS(lbits) + 1; + mpw* zdata = alloca(zsize * sizeof(*zdata)); + unsigned char * zb = (unsigned char *) zdata; + size_t nzb = MP_WORDS_TO_BYTES(zsize); + int is_littleendian = 0; + int is_signed = 1; + + /* Grab long as big-endian signed octets. */ + if (_PyLong_AsByteArray(lo, zb, nzb, is_littleendian, is_signed)) + return -1; + + /* Endian swap zdata's mpw elements. */ + if (IS_LITTLE_ENDIAN()) { + mpw w = 0; + int zx = 0; + while (nzb) { + w <<= 8; + w |= *zb++; + nzb--; + if ((nzb % MP_WBYTES) == 0) { + zdata[zx++] = w; + w = 0; + } + } + } + mpnset(&z->n, zsize, zdata); + } else if (PyFloat_Check(o)) { + double d = PyFloat_AsDouble(o); + /* XXX TODO: check for overflow/underflow. */ + l = (long) (d + 0.5); + mpnsetw(&z->n, l); + } else if (PyString_Check(o)) { + const unsigned char * hex = PyString_AsString(o); + /* XXX TODO: check for hex. */ + mpnsethex(&z->n, hex); + } else if (mpw_Check(o)) { + mpwObject *a = (mpwObject *)o; + mpncopy(&z->n, &a->n); + } else { + PyErr_SetString(PyExc_TypeError, "non-numeric coercion failed (mpw_init)"); + return -1; + } + +if (_mpw_debug) +fprintf(stderr, "*** mpw_init(%p[%s],%p[%s],%p[%s]):\t", z, lbl(z), args, lbl(args), kwds, lbl(kwds)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return 0; +} +#endif + +/** \ingroup py_c + */ +static void mpw_free(/*@only@*/ mpwObject * s) + /*@modifies s @*/ +{ +if (_mpw_debug) +fprintf(stderr, "*** mpw_free(%p[%s])\n", s, lbl(s)); + PyObject_Del(s); +} + +/** \ingroup py_c + * Convert integer to mpw. + */ +static mpwObject * +mpw_i2mpw(PyObject * o) + /*@modifies o @*/ +{ + if (mpw_Check(o)) { + Py_INCREF(o); + return (mpwObject *)o; + } + if (PyInt_Check(o)) + return mpw_FromLong(PyInt_AsLong(o)); + else if (PyLong_Check(o)) + return mpw_FromLongObject((PyLongObject *)o); + else if (PyFloat_Check(o)) + return mpw_FromDouble(PyFloat_AsDouble(o)); + else if (PyString_Check(o)) + return mpw_FromHEX(PyString_AS_STRING(o)); + + PyErr_SetString(PyExc_TypeError, "number coercion (to mpwObject) failed"); + return NULL; +} + +static PyObject * +mpw_new(PyTypeObject *type, PyObject *args, PyObject *kwds) + /*@*/ +{ + mpwObject *z; + + if (type != &mpw_Type) { + mpwObject *tz; + size_t size; + + assert(PyType_IsSubtype(type, &mpw_Type)); + tz = (mpwObject *)mpw_new(&mpw_Type, args, kwds); + if (tz == NULL) + return NULL; + + size = ABS(tz->ob_size); + z = (mpwObject *) type->tp_alloc(type, size); + if (z == NULL) + return NULL; + + z->ob_size = tz->ob_size; + if (size > 0) + memcpy(&z->data, &tz->data, size * sizeof(*z->data)); + Py_DECREF(tz); + } else { + PyObject * x = NULL; + int base = -909; + static char *kwlist[] = {"x", "base", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:mpw", kwlist, &x, &base)) + return NULL; + + if (x != NULL) { + /* XXX make sure new instance, not old reference. */ + if (mpw_Check(x)) { + mpwObject *zo = (mpwObject *)x; + z = mpw_Copy(zo); + } else + z = mpw_i2mpw(x); + } else + z = mpw_FromLong(0); + } + +if (_mpw_debug < -1) +fprintf(stderr, "*** mpw_new(%p[%s],%p[%s],%p[%s])\t", type, lbl(type), args, lbl(args), kwds, lbl(kwds)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +/** \ingroup py_c + * Compute 2 argument operations. + */ +static PyObject * +mpw_ops2(const char *fname, char op, mpwObject *x, mpwObject *m) + /*@*/ +{ + mpwObject * z = NULL; + size_t xsize; + mpw* xdata; + size_t msize; + mpw* mdata; + size_t mnorm; + size_t asize; + mpw* adata; + size_t bsize; + mpw* bdata; + size_t shift; + size_t zsize; + mpw* zdata; + mpw* wksp; + mpbarrett b; + int carry; + int zsign = 0; + + mpbzero(&b); + if (x == NULL || m == NULL) + goto exit; + + xsize = MPW_SIZE(x); + xdata = MPW_DATA(x); + msize = MPW_SIZE(m); + mdata = MPW_DATA(m); + mnorm = msize - mpsize(msize, mdata); + if (mnorm > 0 && mnorm < msize) { + msize -= mnorm; + mdata += mnorm; + } + +if (_mpw_debug < 0) { +prtmpw("a", x); +prtmpw("b", m); +} + + switch (op) { + default: + goto exit; + /*@notreached@*/ break; + case '+': + zsize = MAX(xsize, msize) + 1; + zdata = alloca(zsize * sizeof(*zdata)); + mpsetx(zsize, zdata, xsize, xdata); + if (x->ob_size < 0) { + zsign = 1; + if (m->ob_size < 0) { + carry = mpaddx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "add --: carry\n"); + *zdata = 1; + } + } else { + carry = mpsubx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "add -+: borrow\n"); + *zdata = MP_ALLMASK; + mpneg(zsize, zdata); + zsign = 0; + } + } + } else { + zsign = 0; + if (m->ob_size < 0) { + carry = mpsubx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "add +-: borrow\n"); + *zdata = MP_ALLMASK; + mpneg(zsize, zdata); + zsign = 1; + } + } else { + carry = mpaddx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "add ++: carry\n"); + *zdata = 1; + } + } + } + z = mpw_FromMPW(zsize, zdata, 1); + if (zsign) + z->ob_size = -z->ob_size; + break; + case '-': + zsize = MAX(xsize, msize) + 1; + zdata = alloca(zsize * sizeof(*zdata)); + mpsetx(zsize, zdata, xsize, xdata); + if (x->ob_size < 0) { + zsign = 1; + if (m->ob_size < 0) { + carry = mpsubx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "sub --: borrow\n"); + *zdata = MP_ALLMASK; + mpneg(zsize, zdata); + zsign = 0; + } + } else { + carry = mpaddx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "sub -+: carry\n"); + *zdata = 1; + } + } + } else { + zsign = 0; + if (m->ob_size < 0) { + carry = mpaddx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "sub +-: carry\n"); + *zdata = 1; + } + } else { + carry = mpsubx(zsize-1, zdata+1, msize, mdata); + if (carry) { +if (_mpw_debug) +fprintf(stderr, "sub ++: borrow\n"); + *zdata = MP_ALLMASK; + mpneg(zsize, zdata); + zsign = 1; + } + } + } + z = mpw_FromMPW(zsize-1, zdata+1, 1); + if (zsign) + z->ob_size = -z->ob_size; + break; + case '*': + zsize = xsize + msize; + zdata = alloca(zsize * sizeof(*zdata)); + zsign = x->ob_size * m->ob_size; + mpmul(zdata, xsize, xdata, msize, mdata); + z = mpw_FromMPW(zsize, zdata, 1); + if (zsign < 0) + z->ob_size = -z->ob_size; + break; + case '/': + asize = xsize+1; + adata = alloca(asize * sizeof(*adata)); + mpsetx(asize, adata, xsize, xdata); + bsize = msize; + bdata = alloca(bsize * sizeof(*bdata)); + mpsetx(bsize, bdata, msize, mdata); + + zsize = asize + 1; + zdata = alloca(zsize * sizeof(*zdata)); + zsign = x->ob_size * m->ob_size; + wksp = alloca((bsize+1) * sizeof(*wksp)); + + shift = mpnorm(bsize, bdata); + mplshift(asize, adata, shift); + mpndivmod(zdata, asize, adata, bsize, bdata, wksp); + + zsize -= bsize; + + if (zsign < 0) + (void) mpaddw(zsize, zdata, (mpw)1); + + z = mpw_FromMPW(zsize, zdata, 1); + if (zsign < 0) + z->ob_size = -z->ob_size; + break; + case '%': + asize = xsize+1; + adata = alloca(asize * sizeof(*adata)); + mpsetx(asize, adata, xsize, xdata); + bsize = msize; + bdata = mdata; + + zsize = asize; + zdata = alloca(zsize * sizeof(*zdata)); + zsign = x->ob_size * m->ob_size; + wksp = alloca((bsize+1) * sizeof(*wksp)); + + mpnmod(zdata, asize, adata, bsize, bdata, wksp); + + if (zsign < 0) { + if (m->ob_size < 0) { + (void) mpsubx(zsize, zdata, bsize, bdata); + mpneg(zsize, zdata); + } else { + zsign = 0; + mpneg(zsize, zdata); + (void) mpaddx(zsize, zdata, bsize, bdata); + } + } + z = mpw_FromMPW(zsize, zdata, 1); + if (zsign < 0) { + z->ob_size = -z->ob_size; + } else if (zsign > 0) { + if (x->ob_size < 0) + z->ob_size = -z->ob_size; + } + break; + case '<': + /* XXX FIXME: enlarge? negative count? sign?. */ + shift = (size_t) (msize == 1 ? mdata[0] : 0); + z = mpw_FromMPW(xsize, xdata, 0); + if (shift > 0) + mplshift(MPW_SIZE(z), MPW_DATA(z), shift); + break; + case '>': + /* XXX FIXME: enlarge? negative count? sign?. */ + shift = (size_t) (msize == 1 ? mdata[0] : 0); + z = mpw_FromMPW(xsize, xdata, 0); + if (shift > 0) + mprshift(MPW_SIZE(z), MPW_DATA(z), shift); + break; + case '&': + /* XXX reset to original size for now. */ + msize = MPW_SIZE(m); + mdata = MPW_DATA(m); + if (xsize <= msize) { + z = mpw_FromMPW(xsize, xdata, 0); + mpand(MPW_SIZE(z), MPW_DATA(z), mdata + (msize - xsize)); + } else { + z = mpw_FromMPW(msize, mdata, 0); + mpand(MPW_SIZE(z), MPW_DATA(z), xdata + (xsize - msize)); + } + break; + case '|': + /* XXX reset to original size for now. */ + msize = MPW_SIZE(m); + mdata = MPW_DATA(m); + if (xsize <= msize) { + z = mpw_FromMPW(xsize, xdata, 0); + mpor(MPW_SIZE(z), MPW_DATA(z), mdata + (msize - xsize)); + } else { + z = mpw_FromMPW(msize, mdata, 0); + mpor(MPW_SIZE(z), MPW_DATA(z), xdata + (xsize - msize)); + } + break; + case '^': + /* XXX reset to original size for now. */ + msize = MPW_SIZE(m); + mdata = MPW_DATA(m); + if (xsize <= msize) { + z = mpw_FromMPW(xsize, xdata, 0); + mpxor(MPW_SIZE(z), MPW_DATA(z), mdata + (msize - xsize)); + } else { + z = mpw_FromMPW(msize, mdata, 0); + mpxor(MPW_SIZE(z), MPW_DATA(z), xdata + (xsize - msize)); + } + break; + case 'P': + { mpnumber zn; + + mpnzero(&zn); + if (msize == 0 || (msize == 1 && *mdata == 0)) + mpnsetw(&zn, 1); + else if (mpz(xsize, xdata) || m->ob_size < 0) + mpnsetw(&zn, 0); + else { + zsign = (x->ob_size > 0 || mpeven(msize, mdata)) ? 1 : -1; + mpnpow_w(&zn, xsize, xdata, msize, mdata); + } + z = mpw_FromMPW(zn.size, zn.data, 1); + mpnfree(&zn); + if (zsign < 0) + z->ob_size = -z->ob_size; + } break; + case 'G': + wksp = alloca((xsize) * sizeof(*wksp)); + z = mpw_New(msize); + mpgcd_w(xsize, xdata, mdata, MPW_DATA(z), wksp); + break; + case 'I': + wksp = alloca(6*(msize+1)*sizeof(*wksp)); + mpbset(&b, msize, mdata); + z = mpw_New(msize); + mpbinv_w(&b, xsize, xdata, MPW_DATA(z), wksp); + break; +#ifdef DYING + case 'R': + { rngObject * r = ((rngObject *)x); + + wksp = alloca(msize*sizeof(*wksp)); + mpbset(&b, msize, mdata); + z = mpw_New(msize); + mpbrnd_w(&b, &r->rngc, MPW_DATA(z), wksp); + } break; +#endif + case 'S': + wksp = alloca((4*msize+2)*sizeof(*wksp)); + mpbset(&b, msize, mdata); + z = mpw_New(msize); + mpbsqrmod_w(&b, xsize, xdata, MPW_DATA(z), wksp); + break; + } + +if (_mpw_debug) +fprintf(stderr, "*** mpw_%s %p[%d]\t", fname, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + +exit: + mpbfree(&b); + Py_XDECREF(x); + Py_XDECREF(m); + return (PyObject *)z; +} + +/** \ingroup py_c + * Compute 3 argument operations. + */ +static PyObject * +mpw_ops3(const char *fname, char op, + mpwObject *x, mpwObject *y, mpwObject *m) + /*@*/ +{ + mpwObject * z = NULL; + size_t xsize; + mpw* xdata; + size_t ysize; + mpw* ydata; + size_t msize; + mpw* mdata; + size_t zsize; + mpw* zdata; + mpbarrett b; + mpw* wksp; + + mpbzero(&b); + if (x == NULL || y == NULL || m == NULL) + goto exit; + +if (_mpw_debug < 0) { +prtmpw("a", x); +prtmpw("b", y); +prtmpw("c", m); +} + + xsize = MPW_SIZE(x); + xdata = MPW_DATA(x); + ysize = MPW_SIZE(y); + ydata = MPW_DATA(y); + msize = MPW_SIZE(m); + mdata = MPW_DATA(m); + + mpbset(&b, msize, mdata); + + zsize = b.size; + zdata = alloca(zsize * sizeof(*zdata)); + wksp = alloca((4*zsize+2)*sizeof(*wksp)); + + switch (op) { + case '/': + case '%': + default: + goto exit; + /*@notreached@*/ break; + case '+': + fname = "Addm"; + mpbaddmod_w(&b, xsize, xdata, ysize, ydata, zdata, wksp); + break; + case '-': + fname = "Subm"; + mpbsubmod_w(&b, xsize, xdata, ysize, ydata, zdata, wksp); + break; + case '*': + fname = "Mulm"; + mpbmulmod_w(&b, xsize, xdata, ysize, ydata, zdata, wksp); + break; + case 'P': + fname = "Powm"; + mpbpowmod_w(&b, xsize, xdata, ysize, ydata, zdata, wksp); + break; + } + + z = mpw_FromMPW(zsize, zdata, 1); + +if (_mpw_debug < 0) +fprintf(stderr, "*** mpw_%s %p[%d]\t", fname, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + +exit: + mpbfree(&b); + Py_XDECREF(x); + Py_XDECREF(y); + Py_XDECREF(m); + return (PyObject *)z; +} + +/* ---------- */ + +/** \ingroup py_c + */ +static PyObject * +mpw_Debug(/*@unused@*/ mpwObject * s, PyObject * args) + /*@globals _Py_NoneStruct @*/ + /*@modifies _Py_NoneStruct @*/ +{ + if (!PyArg_ParseTuple(args, "i:Debug", &_mpw_debug)) return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +/** \ingroup py_c + * Compute gcd(x, y). + */ +static PyObject * +mpw_Gcd(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * mo; + + if (!PyArg_ParseTuple(args, "OO:Gcd", &xo, &mo)) return NULL; + return mpw_ops2("Gcd", 'G', mpw_i2mpw(xo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute inverse (modulo m) of x. + */ +static PyObject * +mpw_Invm(/*@unused@*/ mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * mo; + + if (!PyArg_ParseTuple(args, "OO:Invm", &xo, &mo)) return NULL; + return mpw_ops2("Invm", 'I', mpw_i2mpw(xo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute x*x (modulo m). + */ +static PyObject * +mpw_Sqrm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * mo; + + if (!PyArg_ParseTuple(args, "OO:Sqrm", &xo, &mo)) return NULL; + return mpw_ops2("Sqrm", 'S', mpw_i2mpw(xo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute x+y (modulo m). + */ +static PyObject * +mpw_Addm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * yo, * mo; + + if (!PyArg_ParseTuple(args, "OOO:Addm", &xo, &yo, &mo)) return NULL; + return mpw_ops3("Addm", '+', + mpw_i2mpw(xo), mpw_i2mpw(yo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute x-y (modulo m). + */ +static PyObject * +mpw_Subm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * yo, * mo; + + if (!PyArg_ParseTuple(args, "OOO:Subm", &xo, &yo, &mo)) return NULL; + return mpw_ops3("Subm", '-', + mpw_i2mpw(xo), mpw_i2mpw(yo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute x*y (modulo m). + */ +static PyObject * +mpw_Mulm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * yo, * mo; + + if (!PyArg_ParseTuple(args, "OOO:Mulm", &xo, &yo, &mo)) return NULL; + return mpw_ops3("Mulm", '*', + mpw_i2mpw(xo), mpw_i2mpw(yo), mpw_i2mpw(mo)); +} + +/** \ingroup py_c + * Compute x**y (modulo m). + */ +static PyObject * +mpw_Powm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * yo, * mo; + + if (!PyArg_ParseTuple(args, "OOO:Powm", &xo, &yo, &mo)) return NULL; + return mpw_ops3("Powm", 'P', + mpw_i2mpw(xo), mpw_i2mpw(yo), mpw_i2mpw(mo)); +} + +#ifdef DYNING +/** \ingroup py_c + * Return random number 1 < r < b-1. + */ +static PyObject * +mpw_Rndm(mpwObject * s, PyObject * args) + /*@*/ +{ + PyObject * xo, * mo; + + if (!PyArg_ParseTuple(args, "OO:Rndm", &mo, &xo)) return NULL; + if (!is_rng(xo)) { + PyErr_SetString(PyExc_TypeError, "mpw.rndm() requires rng_Type argument"); + return NULL; + } + return mpw_ops2("Rndm", 'R', (mpwObject*)xo, mpw_i2mpw(mo)); +} +#endif + +/*@-fullinitblock@*/ +/*@unchecked@*/ /*@observer@*/ +static struct PyMethodDef mpw_methods[] = { + {"Debug", (PyCFunction)mpw_Debug, METH_VARARGS, + NULL}, + {"gcd", (PyCFunction)mpw_Gcd, METH_VARARGS, + NULL}, + {"invm", (PyCFunction)mpw_Invm, METH_VARARGS, + NULL}, + {"sqrm", (PyCFunction)mpw_Sqrm, METH_VARARGS, + NULL}, + {"addm", (PyCFunction)mpw_Addm, METH_VARARGS, + NULL}, + {"subm", (PyCFunction)mpw_Subm, METH_VARARGS, + NULL}, + {"mulm", (PyCFunction)mpw_Mulm, METH_VARARGS, + NULL}, + {"powm", (PyCFunction)mpw_Powm, METH_VARARGS, + NULL}, +#ifdef DYING + {"rndm", (PyCFunction)mpw_Rndm, METH_VARARGS, + NULL}, +#endif + {NULL, NULL} /* sentinel */ +}; +/*@=fullinitblock@*/ + +static PyObject * mpw_getattro(PyObject * o, PyObject * n) + /*@*/ +{ + return PyObject_GenericGetAttr(o, n); +} + +static int mpw_setattro(PyObject * o, PyObject * n, PyObject * v) + /*@*/ +{ + return PyObject_GenericSetAttr(o, n, v); +} + +/* ---------- */ + +static PyObject * +mpw_add(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("add", '+', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_sub(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("sub", '-', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_mul(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("mul", '*', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_div(PyObject * a, PyObject * w) + /*@*/ +{ + mpwObject * b = mpw_i2mpw(w); + + if (mpz(MPW_SIZE(b), MPW_DATA(b))) { + Py_DECREF(b); + PyErr_SetString(PyExc_ZeroDivisionError, "mpw_divide by zero"); + return NULL; + } + return mpw_ops2("div", '/', mpw_i2mpw(a), b); +} + +static PyObject * +mpw_classic_div(PyObject * a, PyObject * b) + /*@*/ +{ + if (Py_DivisionWarningFlag && + PyErr_Warn(PyExc_DeprecationWarning, "classic long division") < 0) + return NULL; + return mpw_div(a, b); +} + +static PyObject * +mpw_mod(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("rem", '%', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_divmod(PyObject * v, PyObject * w) + /*@*/ +{ + PyObject * z = NULL; + mpwObject * q = NULL; + mpwObject * r = NULL; + mpwObject * a = mpw_i2mpw(v); + size_t asize; + mpw* adata; + size_t anorm; + mpwObject * b = mpw_i2mpw(w); + size_t bsize; + mpw* bdata; + size_t bnorm; + size_t zsize; + mpw* zdata; + mpw* wksp; + int qsign = 0; + + if (a == NULL || b == NULL) + goto exit; + + asize = MPW_SIZE(a); + adata = MPW_DATA(a); + anorm = mpsize(asize, adata); + bsize = MPW_SIZE(b); + bdata = MPW_DATA(b); + bnorm = mpsize(bsize, bdata); + + if (mpz(bsize, bdata)) { + PyErr_SetString(PyExc_ZeroDivisionError, "mpw_divmod by zero"); + goto exit; + } + + if (anorm < asize) { + asize -= anorm; + adata += anorm; + } + zsize = asize + 1; + zdata = alloca(zsize * sizeof(*zdata)); + if (bnorm < bsize) { + bsize -= bnorm; + bdata += bnorm; + } + qsign = a->ob_size * b->ob_size; + wksp = alloca((bsize+1) * sizeof(*wksp)); + + mpndivmod(zdata, asize, adata, bsize, bdata, wksp); + +if (_mpw_debug < 0) { +fprintf(stderr, " a %p[%d]:\t", adata, asize), mpfprintln(stderr, asize, adata); +fprintf(stderr, " b %p[%d]:\t", bdata, bsize), mpfprintln(stderr, bsize, bdata); +fprintf(stderr, " z %p[%d]:\t", zdata, zsize), mpfprintln(stderr, zsize, zdata); +} + + zsize -= bsize; + r = mpw_FromMPW(bsize, zdata+zsize, 1); + if (r == NULL) + goto exit; + if (qsign < 0) { + if (b->ob_size < 0) { + (void) mpsubx(MPW_SIZE(r), MPW_DATA(r), bsize, bdata); + mpneg(MPW_SIZE(r), MPW_DATA(r)); + } else { + mpneg(MPW_SIZE(r), MPW_DATA(r)); + (void) mpaddx(MPW_SIZE(r), MPW_DATA(r), bsize, bdata); + } + (void) mpaddw(zsize, zdata, (mpw)1); + } + if (b->ob_size < 0) + r->ob_size = -r->ob_size; + + q = mpw_FromMPW(zsize, zdata, 1); + if (q == NULL) { + Py_DECREF(r); + goto exit; + } + if (qsign < 0) + q->ob_size = -q->ob_size; + +if (_mpw_debug) { +prtmpw("q", q); +prtmpw("r", r); +fprintf(stderr, "*** mpw_divmod(%p,%p)\n", a, b); +} + if ((z = PyTuple_New(2)) == NULL) { + Py_DECREF(q); + Py_DECREF(r); + goto exit; + } + + (void) PyTuple_SetItem(z, 0, (PyObject *)q); + (void) PyTuple_SetItem(z, 1, (PyObject *)r); + +exit: + Py_XDECREF(a); + Py_XDECREF(b); + return (PyObject *)z; +} + +static PyObject * +mpw_pow(PyObject * a, PyObject * b, PyObject * c) + /*@*/ +{ + if (c != Py_None) + return mpw_ops3("Powm", 'P', mpw_i2mpw(a), mpw_i2mpw(b), mpw_i2mpw(c)); + else + return mpw_ops2("pow", 'P', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_neg(mpwObject * a) + /*@*/ +{ + mpwObject *z; + + if (a->ob_size == 0 && mpw_CheckExact(a)) { + /* -0 == 0 */ + Py_INCREF(a); + z = a; + } else { + z = mpw_Copy(a); + if (z != NULL) + z->ob_size = -(a->ob_size); + } + +if (z != NULL && _mpw_debug) +fprintf(stderr, "*** mpw_neg %p[%d]\t", MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +static PyObject * +mpw_pos(mpwObject * a) + /*@*/ +{ + mpwObject *z; + + if (mpw_CheckExact(a)) { + Py_INCREF(a); + z = a; + } else + z = mpw_Copy(a); + +if (z != NULL && _mpw_debug) +fprintf(stderr, "*** mpw_pos %p[%d]\t", MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +static PyObject * +mpw_abs(mpwObject * a) + /*@*/ +{ + mpwObject * z; + + if (a->ob_size < 0) + z = (mpwObject *)mpw_neg(a); + else + z = (mpwObject *)mpw_pos(a); + +if (z != NULL && _mpw_debug) +fprintf(stderr, "*** mpw_abs %p[%d]\t", MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +static int +mpw_nonzero(mpwObject * a) + /*@*/ +{ + return ABS(a->ob_size) != 0; +} + +static PyObject * +mpw_invert(mpwObject * a) + /*@*/ +{ + /* Implement ~z as -(z+1) */ + mpwObject * z = mpw_Copy(a); + + if (z != NULL) { + mpw val = 1; + int carry; + + carry = mpaddx(MPW_SIZE(z), MPW_DATA(z), 1, &val); + z->ob_size = -(a->ob_size); + } + return (PyObject *)z; +} + +static PyObject * +mpw_lshift(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("lshift", '<', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_rshift(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("rshift", '>', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_and(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("and", '&', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_xor(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("xor", '^', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static PyObject * +mpw_or(PyObject * a, PyObject * b) + /*@*/ +{ + return mpw_ops2("or", '|', mpw_i2mpw(a), mpw_i2mpw(b)); +} + +static int +mpw_coerce(PyObject ** pv, PyObject ** pw) + /*@modifies *pv, *pw @*/ +{ + +if (_mpw_debug) +fprintf(stderr, "*** mpw_coerce(%p[%s],%p[%s])\n", pv, lbl(*pv), pw, lbl(*pw)); + + if (mpw_Check(*pw)) + Py_INCREF(*pw); + else if (PyInt_Check(*pw)) + *pw = (PyObject *) mpw_FromLong(PyInt_AsLong(*pw)); + else if (PyLong_Check(*pw)) + *pw = (PyObject *) mpw_FromLongObject((PyLongObject *)(*pw)); + else if (PyFloat_Check(*pw)) + *pw = (PyObject *) mpw_FromDouble(PyFloat_AsDouble(*pw)); + else if (PyString_Check(*pw)) + *pw = (PyObject *) mpw_FromHEX(PyString_AS_STRING(*pw)); + else { + PyErr_SetString(PyExc_TypeError, "non-numeric coercion failed (mpw_coerce)"); + return 1; + } + + Py_INCREF(*pv); + return 0; +} + +static PyObject * +mpw_int(mpwObject * a) + /*@*/ +{ + size_t anorm = MPW_SIZE(a) - MP_ROUND_B2W(MPBITCNT(MPW_SIZE(a), MPW_DATA(a))); + size_t asize = MPW_SIZE(a) - anorm; + mpw* adata = MPW_DATA(a) + anorm; + long ival = 0; + + if (asize > 1) { + PyErr_SetString(PyExc_ValueError, "mpw_int: arg too long to convert"); + return NULL; + } + if (asize == 1) + ival = adata[0]; + if (a->ob_size < 0) + ival = -ival; + + return Py_BuildValue("i", ival); +} + +static PyObject * +mpw_long(mpwObject * a) + /*@*/ +{ + size_t abits = MPBITCNT(MPW_SIZE(a), MPW_DATA(a)); + size_t anorm = MPW_SIZE(a) - MP_ROUND_B2W(abits); + size_t asize = MPW_SIZE(a) - anorm; + mpw* adata = MPW_DATA(a) + anorm; + size_t zsize = asize; + mpw* zdata = alloca(zsize * sizeof(*zdata)); + int lsize = BITS_TO_DIGITS(abits); + PyLongObject *lo = _PyLong_New(lsize); + int digx; + + if (lo == NULL) + return NULL; + + mpcopy(asize, zdata, adata); + + for (digx = 0; digx < lsize; digx++) { + lo->ob_digit[digx] = zdata[zsize - 1] & MASK; + mprshift(zsize, zdata, SHIFT); + } + + while (digx > 0 && lo->ob_digit[digx-1] == 0) + digx--; + lo->ob_size = (a->ob_size >= 0 ? digx : -digx); + + return (PyObject *)lo; +} + +static PyObject * +mpw_float(mpwObject * a) + /*@*/ +{ + PyObject * so = mpw_format(a, 10, 0); + char * s, * se; + double d; + + if (so == NULL) + return NULL; + s = PyString_AS_STRING(so); + se = NULL; + d = strtod(s, &se); + +if (_mpw_debug) +fprintf(stderr, "*** mpw_float(%p): s %p \"%s\" se %p d %g\n", a, s, s, se, d); + Py_DECREF(so); + + return Py_BuildValue("d", d); +} + +static PyObject * +mpw_oct(mpwObject * a) + /*@*/ +{ + return mpw_format(a, 8, 1); +} + +static PyObject * +mpw_hex(mpwObject * a) + /*@*/ +{ + return mpw_format(a, 16, 1); +} + +static PyNumberMethods mpw_as_number = { + (binaryfunc) mpw_add, /* nb_add */ + (binaryfunc) mpw_sub, /* nb_subtract */ + (binaryfunc) mpw_mul, /* nb_multiply */ + (binaryfunc) mpw_classic_div, /* nb_divide */ + (binaryfunc) mpw_mod, /* nb_remainder */ + (binaryfunc) mpw_divmod, /* nb_divmod */ + (ternaryfunc) mpw_pow, /* nb_power */ + (unaryfunc) mpw_neg, /* nb_negative */ + (unaryfunc) mpw_pos, /* nb_positive */ + (unaryfunc) mpw_abs, /* nb_absolute */ + (inquiry) mpw_nonzero, /* nb_nonzero */ + (unaryfunc) mpw_invert, /* nb_invert */ + (binaryfunc) mpw_lshift, /* nb_lshift */ + (binaryfunc) mpw_rshift, /* nb_rshift */ + (binaryfunc) mpw_and, /* nb_and */ + (binaryfunc) mpw_xor, /* nb_xor */ + (binaryfunc) mpw_or, /* nb_or */ + (coercion) mpw_coerce, /* nb_coerce */ + + (unaryfunc) mpw_int, /* nb_int */ + (unaryfunc) mpw_long, /* nb_long */ + (unaryfunc) mpw_float, /* nb_float */ + (unaryfunc) mpw_oct, /* nb_oct */ + (unaryfunc) mpw_hex, /* nb_hex */ + + /* Added in release 2.0 */ + (binaryfunc) 0, /* nb_inplace_add */ + (binaryfunc) 0, /* nb_inplace_subtract */ + (binaryfunc) 0, /* nb_inplace_multiply */ + (binaryfunc) 0, /* nb_inplace_divide */ + (binaryfunc) 0, /* nb_inplace_remainder */ + (ternaryfunc)0, /* nb_inplace_power */ + (binaryfunc) 0, /* nb_inplace_lshift */ + (binaryfunc) 0, /* nb_inplace_rshift */ + (binaryfunc) 0, /* nb_inplace_and */ + (binaryfunc) 0, /* nb_inplace_xor */ + (binaryfunc) 0, /* nb_inplace_or */ + + /* Added in release 2.2 */ + /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ + (binaryfunc) mpw_div, /* nb_floor_divide */ + (binaryfunc) 0, /* nb_true_divide */ + (binaryfunc) 0, /* nb_inplace_floor_divide */ + (binaryfunc) 0 /* nb_inplace_true_divide */ + +}; + +/* ---------- */ + +/** + */ +/*@unchecked@*/ /*@observer@*/ +static char mpw_doc[] = +""; + +/*@-fullinitblock@*/ +PyTypeObject mpw_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "_bc.mpw", /* tp_name */ + sizeof(mpwObject) - sizeof(mpw),/* tp_basicsize */ + sizeof(mpw), /* tp_itemsize */ + /* methods */ + (destructor) mpw_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc) mpw_compare, /* tp_compare */ + (reprfunc) mpw_repr, /* tp_repr */ + &mpw_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc) mpw_str, /* tp_str */ + (getattrofunc) mpw_getattro, /* tp_getattro */ + (setattrofunc) mpw_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + mpw_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + mpw_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc) mpw_new, /* tp_new */ + (destructor) mpw_free, /* tp_free */ + 0, /* tp_is_gc */ +}; +/*@=fullinitblock@*/ + +/* ---------- */ diff --git a/beecrypt/python/mpw-py.h b/beecrypt/python/mpw-py.h new file mode 100644 index 0000000..2ef9707 --- /dev/null +++ b/beecrypt/python/mpw-py.h @@ -0,0 +1,40 @@ +#ifndef H_MPW_PY +#define H_MPW_PY + +/** \ingroup py_c + * \file python/mpw-py.h + */ +#include "mp.h" + +/** + */ +typedef struct mpwObject_s { + PyObject_HEAD + int ob_size; + mpw data[1]; +} mpwObject; + +/** + */ +/*@unchecked@*/ +extern PyTypeObject mpw_Type; + +#define mpw_Check(_o) PyObject_TypeCheck((_o), &mpw_Type) +#define mpw_CheckExact(_o) ((_o)->ob_type == &mpw_Type) + +#define MP_ROUND_B2W(_b) MP_BITS_TO_WORDS((_b) + MP_WBITS - 1) + +#define MPW_SIZE(_a) (size_t)((_a)->ob_size < 0 ? -(_a)->ob_size : (_a)->ob_size) +#define MPW_DATA(_a) ((_a)->data) + +/** + */ +mpwObject * mpw_New(int ob_size) + /*@*/; + +/** + */ +mpwObject * mpw_FromMPW(size_t size, mpw* data, int normalize) + /*@*/; + +#endif diff --git a/beecrypt/python/rng-py.c b/beecrypt/python/rng-py.c new file mode 100644 index 0000000..a5b2a86 --- /dev/null +++ b/beecrypt/python/rng-py.c @@ -0,0 +1,330 @@ +/** \ingroup py_c + * \file python/rng-py.c + */ + +#define _REENTRANT 1 /* XXX config.h collides with pyconfig.h */ +#include "system.h" + +#include "Python.h" +#ifdef __LCLINT__ +#undef PyObject_HEAD +#define PyObject_HEAD int _PyObjectHead; +#endif + +#include "rng-py.h" + +#include "debug-py.c" + +#include "debug.h" + +/*@unchecked@*/ +static int _rng_debug = 0; + +/*@unchecked@*/ /*@observer@*/ +static const char initialiser_name[] = "_bc.rng"; + +/* ---------- */ + +static void +rng_dealloc(rngObject * s) + /*@modifies s @*/ +{ +if (_rng_debug < -1) +fprintf(stderr, "*** rng_dealloc(%p)\n", s); + +/*@-modobserver@*/ + randomGeneratorContextFree(&s->rngc); +/*@=modobserver@*/ + mpbfree(&s->b); + PyObject_Del(s); +} + +static int +rng_print(rngObject * s, FILE * fp, /*@unused@*/ int flags) + /*@globals fileSystem @*/ + /*@modifies fileSystem @*/ +{ +if (_rng_debug < -1) +fprintf(stderr, "*** rng_print(%p)\n", s); + return 0; +} + +/** \ingroup py_c + */ +static int rng_init(rngObject * s, PyObject *args, PyObject *kwds) + /*@modifies s @*/ +{ + PyObject * o = NULL; + const randomGenerator* rng = NULL; + + if (!PyArg_ParseTuple(args, "|O:Cvt", &o)) return -1; + + if (o) { + /* XXX "FIPS 186" or "Mersenne Twister" */ + if (PyString_Check(o)) + rng = randomGeneratorFind(PyString_AsString(o)); + } + + if (rng == NULL) + rng = randomGeneratorDefault(); + +/*@-modobserver@*/ + if (randomGeneratorContextInit(&s->rngc, rng) != 0) + return -1; +/*@=modobserver@*/ + mpbzero(&s->b); + +if (_rng_debug) +fprintf(stderr, "*** rng_init(%p[%s],%p[%s],%p[%s])\n", s, lbl(s), args, lbl(args), kwds, lbl(kwds)); + + return 0; +} + +/** \ingroup py_c + */ +static void rng_free(/*@only@*/ rngObject * s) + /*@modifies s @*/ +{ +if (_rng_debug) +fprintf(stderr, "*** rng_free(%p[%s])\n", s, lbl(s)); +/*@-modobserver@*/ + randomGeneratorContextFree(&s->rngc); +/*@=modobserver@*/ + mpbfree(&s->b); + PyObject_Del(s); +} + +/** \ingroup py_c + */ +static PyObject * rng_alloc(PyTypeObject * subtype, int nitems) + /*@*/ +{ + PyObject * ns = PyType_GenericAlloc(subtype, nitems); + +if (_rng_debug) +fprintf(stderr, "*** rng_alloc(%p[%s},%d) ret %p[%s]\n", subtype, lbl(subtype), nitems, ns, lbl(ns)); + return (PyObject *) ns; +} + +static PyObject * +rng_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds) + /*@*/ +{ + PyObject * ns = (PyObject *) PyObject_New(rngObject, &rng_Type); + +if (_rng_debug < -1) +fprintf(stderr, "*** rng_new(%p[%s],%p[%s],%p[%s]) ret %p[%s]\n", subtype, lbl(subtype), args, lbl(args), kwds, lbl(kwds), ns, lbl(ns)); + return ns; +} + +static rngObject * +rng_New(void) +{ + rngObject * ns = PyObject_New(rngObject, &rng_Type); + + return ns; +} + +/* ---------- */ + +/** \ingroup py_c + */ +static PyObject * +rng_Debug(/*@unused@*/ rngObject * s, PyObject * args) + /*@globals _Py_NoneStruct @*/ + /*@modifies _Py_NoneStruct @*/ +{ + if (!PyArg_ParseTuple(args, "i:Debug", &_rng_debug)) return NULL; + +if (_rng_debug < 0) +fprintf(stderr, "*** rng_Debug(%p)\n", s); + + Py_INCREF(Py_None); + return Py_None; +} + +/** \ingroup py_c + */ +static PyObject * +rng_Seed(rngObject * s, PyObject * args) + /*@globals _Py_NoneStruct @*/ + /*@modifies _Py_NoneStruct @*/ +{ + PyObject * o; + randomGeneratorContext* rc = &s->rngc; + mpwObject *z; + + if (!PyArg_ParseTuple(args, "O:Seed", &o)) return NULL; + + if (!mpw_Check(o) || MPW_SIZE(z = (mpwObject*)o) > 0) + return NULL; + + rc->rng->seed(rc->param, (byte*) MPW_DATA(z), MPW_SIZE(z)); + +if (_rng_debug < 0) +fprintf(stderr, "*** rng_Seed(%p)\n", s); + + Py_INCREF(Py_None); + return Py_None; +} + +/** \ingroup py_c + */ +static PyObject * +rng_Next(rngObject * s, PyObject * args) + /*@*/ +{ + PyObject * o = NULL; + randomGeneratorContext* rc = &s->rngc; + mpbarrett* b = &s->b; + mpwObject *z; + + if (!PyArg_ParseTuple(args, "|O:Next", &o)) return NULL; + + if (o) { + if (mpw_Check(o) && MPW_SIZE(z = (mpwObject*)o) > 0) { + b = alloca(sizeof(*b)); + mpbzero(b); + /* XXX z probably needs normalization here. */ + mpbset(b, MPW_SIZE(z), MPW_DATA(z)); + } else + ; /* XXX error? */ + } + + if (b == NULL || b->size == 0 || b->modl == NULL) { + z = mpw_New(1); + rc->rng->next(rc->param, (byte*) MPW_DATA(z), sizeof(*MPW_DATA(z))); + } else { + mpw* wksp = alloca(b->size * sizeof(*wksp)); + z = mpw_New(b->size); + mpbrnd_w(b, rc, MPW_DATA(z), wksp); + } + +if (_rng_debug) +fprintf(stderr, "*** rng_Next(%p) %p[%d]\t", s, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +/** \ingroup py_c + */ +static PyObject * +rng_Prime(rngObject * s, PyObject * args) + /*@*/ +{ + randomGeneratorContext* rc = &s->rngc; + unsigned pbits = 160; + int trials = -1; + size_t psize; + mpbarrett* b; + mpw *temp; + mpwObject *z; + + if (!PyArg_ParseTuple(args, "|ii:Prime", &pbits, &trials)) return NULL; + + psize = MP_ROUND_B2W(pbits); + temp = alloca((8*psize+2) * sizeof(*temp)); + + b = alloca(sizeof(*b)); + mpbzero(b); + + if (trials <= 2) + trials = mpptrials(pbits); +#if 1 + mpprnd_w(b, rc, pbits, trials, (const mpnumber*) 0, temp); +#else + mpprndsafe_w(b, rc, pbits, trials, temp); +#endif + + z = mpw_FromMPW(b->size, b->modl, 1); +if (z != NULL && _rng_debug) +fprintf(stderr, "*** rng_Prime(%p) %p[%d]\t", s, MPW_DATA(z), MPW_SIZE(z)), mpfprintln(stderr, MPW_SIZE(z), MPW_DATA(z)); + + return (PyObject *)z; +} + +/*@-fullinitblock@*/ +/*@unchecked@*/ /*@observer@*/ +static struct PyMethodDef rng_methods[] = { + {"Debug", (PyCFunction)rng_Debug, METH_VARARGS, + NULL}, + {"seed", (PyCFunction)rng_Seed, METH_VARARGS, + NULL}, + {"next", (PyCFunction)rng_Next, METH_VARARGS, + NULL}, + {"prime", (PyCFunction)rng_Prime, METH_VARARGS, + NULL}, + {NULL, NULL} /* sentinel */ +}; +/*@=fullinitblock@*/ + +static PyObject * rng_getattro(PyObject * o, PyObject * n) + /*@*/ +{ + return PyObject_GenericGetAttr(o, n); +} + +static int rng_setattro(PyObject * o, PyObject * n, PyObject * v) + /*@*/ +{ + return PyObject_GenericSetAttr(o, n, v); +} + +/* ---------- */ + +/** + */ +/*@unchecked@*/ /*@observer@*/ +static char rng_doc[] = +""; + +/*@-fullinitblock@*/ +PyTypeObject rng_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "_bc.rng", /* tp_name */ + sizeof(rngObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) rng_dealloc, /* tp_dealloc */ + (printfunc) rng_print, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + (getattrofunc) rng_getattro, /* tp_getattro */ + (setattrofunc) rng_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + rng_doc, /* tp_doc */ +#if Py_TPFLAGS_HAVE_ITER + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)0, /* tp_iter */ + (iternextfunc)0, /* tp_iternext */ + rng_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc) rng_init, /* tp_init */ + (allocfunc) rng_alloc, /* tp_alloc */ + (newfunc) rng_new, /* tp_new */ + (destructor) rng_free, /* tp_free */ + 0, /* tp_is_gc */ +#endif +}; +/*@=fullinitblock@*/ + +/* ---------- */ diff --git a/beecrypt/python/rng-py.h b/beecrypt/python/rng-py.h new file mode 100644 index 0000000..70a99c5 --- /dev/null +++ b/beecrypt/python/rng-py.h @@ -0,0 +1,25 @@ +#ifndef H_RNG_PY +#define H_RNG_PY + +/** \ingroup py_c + * \file python/rng-py.h + */ +#include "beecrypt.h" +#include "mpprime.h" + +/** + */ +typedef struct rngObject_s { + PyObject_HEAD + PyObject *md_dict; /*!< to look like PyModuleObject */ + randomGeneratorContext rngc; + mpbarrett b; +} rngObject; + +/** + */ +/*@unchecked@*/ +extern PyTypeObject rng_Type; +#define is_rng(o) ((o)->ob_type == &rng_Type) + +#endif diff --git a/beecrypt/python/test/.cvsignore b/beecrypt/python/test/.cvsignore new file mode 100644 index 0000000..12664c7 --- /dev/null +++ b/beecrypt/python/test/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +*.pyc diff --git a/beecrypt/python/test/Makefile.am b/beecrypt/python/test/Makefile.am new file mode 100644 index 0000000..b2c978a --- /dev/null +++ b/beecrypt/python/test/Makefile.am @@ -0,0 +1,17 @@ +# Makefile for rpm library. + +AUTOMAKE_OPTIONS = 1.4 foreign + +PYVER= 2.2 + +pylibdir = $(shell python -c 'import sys; print sys.path[1]') +VALGRIND = # valgrind --verbose --leak-check=yes + +EXTRA_DIST = \ + test_all.py test_methods.py \ + unittest.py + +all: + +check: + $(VALGRIND) python test_all.py verbose diff --git a/beecrypt/python/test/test_all.py b/beecrypt/python/test/test_all.py new file mode 100644 index 0000000..86ae194 --- /dev/null +++ b/beecrypt/python/test/test_all.py @@ -0,0 +1,59 @@ +"""Run all test cases. +""" + +import sys +import os +import unittest + +verbose = 0 +if 'verbose' in sys.argv: + verbose = 1 + sys.argv.remove('verbose') + +if 'silent' in sys.argv: # take care of old flag, just in case + verbose = 0 + sys.argv.remove('silent') + + +def print_versions(): + from _bc import mpw + print + print '-=' * 38 + print 'python version: %s' % sys.version + print 'My pid: %s' % os.getpid() + print '-=' * 38 + + +class PrintInfoFakeTest(unittest.TestCase): + def testPrintVersions(self): + print_versions() + + +# This little hack is for when this module is run as main and all the +# other modules import it so they will still be able to get the right +# verbose setting. It's confusing but it works. +import test_all +test_all.verbose = verbose + + +def suite(): + test_modules = [ + 'test_methods', + ] + + alltests = unittest.TestSuite() + for name in test_modules: + module = __import__(name) + alltests.addTest(module.test_suite()) + return alltests + + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(PrintInfoFakeTest)) + return suite + + +if __name__ == '__main__': + print_versions() + unittest.main(defaultTest='suite') diff --git a/beecrypt/python/test/test_methods.py b/beecrypt/python/test/test_methods.py new file mode 100644 index 0000000..37a22bc --- /dev/null +++ b/beecrypt/python/test/test_methods.py @@ -0,0 +1,322 @@ +""" +Basic TestCases for BTree and hash DBs, with and without a DBEnv, with +various DB flags, etc. +""" + +import unittest + +from _bc import mpw + +from test_all import verbose + +DASH = '-' + +Methods = ( '__add__', '__sub__', '__mul__', '__div__', '__mod__', '__lshift__', '__rshift__', '__and__', '__xor__', '__or__') + +class Factory(object): + def __init__(self, false_self, method_name): + self.false_self = false_self + self.method_name = method_name + + def __call__(self, val): + xself = long(self.false_self) + yself = int(self.false_self) + xm = long.__getattribute__(xself, self.method_name) + ym = mpw.__getattribute__(yself, self.method_name) + xa = xm(long(val)) + ya = ym(int(val)) + print " Comparing", xa, ya + assert xa == ya + return xa + +class Long(long): + def __getattribute__(self, name): + print "__getattribute__ ~%s~" % name + if name not in ('__add__', '__sub__'): + return long.getattr(self, name) + return Factory(self, name) + +#a1 = Bar(1) +#a2 = Bar(2) +#print a1.__add__(a2) +#print "Done" +#print a1 + a2 + +#---------------------------------------------------------------------- + +class BasicTestCase(unittest.TestCase): + a = 0x0000000987654321L + b = 0x0000000000000010L + c = 0x0fedcba000000000L + lo = 2 + hi = 200 + t = 10 + + def setUp(self): + mpw().Debug(0) + pass + + def tearDown(self): + mpw().Debug(0) + pass + + #---------------------------------------- + + def test01_SimpleMethods(self): + if verbose: + print '\n', '-=' * 30 + print "Running %s.test01_SimpleMethods..." % \ + self.__class__.__name__ + print "\ta:\t%s\t%s\t0x%x" % (type(self.a), self.a, self.a) + print "\tb:\t%s\t%s\t0x%x" % (type(self.b), self.b, self.b) + print "\tc:\t%s\t%s\t0x%x" % (type(self.c), self.c, self.c) + + wa = mpw(self.a) + wb = mpw(self.b) + wc = mpw(self.c) +# xa - Long(self.a) +# xb = Long(self.b) +# xc = Long(self.c) + za = long(self.a) + zb = long(self.b) + zc = long(self.c) + + print "__int__:\t", int(wb), "\t", int(zb) + assert int(wb) == int(zb) + print "__long__:\t", long(wa), "\t", long(za) + assert long(wb) == long(zb) + print "__float__:\t", float(wa), "\t", float(za) + assert float(wb) == float(zb) + + zs = hex(za) + print "__hex__:\t", hex(wa), "\t", zs + assert hex(wa) == zs + zs = oct(za) + print "__oct__:\t", oct(wa), "\t", zs + assert oct(wa) == zs + + print "__neg__:\t", (-wa), "\t", long(-za) + print "__pos__:\t", (+wa), "\t", long(+za) + print "__abs__:\t", abs(wa), "\t", long(abs(za)) + print "__invert__:\t", (~wa), "\t", long(~za) + + print "__add__:\t", (wa + wb), "\t", long(za + zb) + print "__sub__:\t", (wa - wb), "\t", long(za - zb) + print "__mul__:\t", (wa * wb), "\t", long(za * zb) + print "__div__:\t", (wa / wb), "\t", long(za / zb) + print "__mod__:\t", (wa % wb), "\t", long(za % zb) + + wq, wr = divmod(wa, wb) + zq, zr = divmod(za, zb) + print "__divmod__ q:\t", wq, "\t", long(zq) + print "__divmod__ r:\t", wr, "\t", long(zr) + + print "__pow__:\t", (wb ** wb), "\t", long(zb ** zb) + + print "__lshift__:\t", (wa << wb), "\t", long(za << zb) + print "__rshift__:\t", (wa >> wb), "\t", long(za >> zb) + print "__and__:\t", (wa & wc), "\t", long(za & zc) + print "__xor__:\t", (wa ^ wa), "\t", long(za ^ za) + print "__or__:\t", (wa | wc), "\t", long(za | zc) + +# print mpw.__complex__(b) +# print mpw.__coerce__(b, i) + + del wa + del wb + del wc + del za + del zb + del zc + pass + + #---------------------------------------- + def test02_CarryBorrow(self): + if verbose: + print '\n', '-=' * 30 + print "Running %s.test02_CarryBorrow..." % \ + self.__class__.__name__ + a = 0x7fffffff + wa = -mpw(a); wa = wa+wa + za = -long(a); za = za+za + wb = -mpw(1) + zb = -long(1) + wc = mpw(1) + zc = long(1) + wd = mpw(a); wd = wd+wd + zd = long(a); zd = zd+zd + print "add --:\t", (wa+wa), "\t", (za+za) + print "add -+:\t", (wb+wd), "\t", (zb+zd) + print "add +-:\t", (wc+wa), "\t", (zc+za) + print "add ++:\t", (wd+wd), "\t", (zd+zd) + print "sub --:\t", (wb-wa), "\t", (zb-za) +# print "sub -+:\t", (wb-wd), "\t", (zb-zd) +# print "sub +-:\t", (wc-wa), "\t", (zc-za) + print "sub ++:\t", (wc-wd), "\t", (zc-zd) + pass + + #---------------------------------------- + def test03_Signs(self): + if verbose: + print '\n', '-=' * 30 + print "Running %s.test03_Signs..." % \ + self.__class__.__name__ + wpa = mpw(13) + wma = -wpa + wpb = wpa - 3 + wmb = -wpb + zpa = long(13) + zma = -zpa + zpb = zpa - 3 + zmb = -zpb + print "add --:\t", (wma+wmb), "\t", (zma+zmb) + print "add -+:\t", (wma+wpb), "\t", (zma+zpb) + print "add +-:\t", (wpa+wmb), "\t", (zpa+zmb) + print "add ++:\t", (wpa+wpb), "\t", (zpa+zpb) + + print "sub --:\t", (wma-wmb), "\t", (zma-zmb) + print "sub -+:\t", (wma-wpb), "\t", (zma-zpb) + print "sub +-:\t", (wpa-wmb), "\t", (zpa-zmb) + print "sub ++:\t", (wpa-wpb), "\t", (zpa-zpb) + print "sub --:\t", (wmb-wma), "\t", (zmb-zma) + print "sub -+:\t", (wmb-wpa), "\t", (zmb-zpa) + print "sub +-:\t", (wpb-wma), "\t", (zpb-zma) + print "sub ++:\t", (wpb-wpa), "\t", (zpb-zpa) + + print "mul --:\t", (wma*wmb), "\t", (zma*zmb) + print "mul -+:\t", (wma*wpb), "\t", (zma*zpb) + print "mul +-:\t", (wpa*wmb), "\t", (zpa*zmb) + print "mul ++:\t", (wpa*wpb), "\t", (zpa*zpb) + + print "div --:\t", (wma/wmb), "\t", (zma/zmb) + print "div -+:\t", (wma/wpb), "\t", (zma/zpb) + print "div +-:\t", (wpa/wmb), "\t", (zpa/zmb) + print "div ++:\t", (wpa/wpb), "\t", (zpa/zpb) + print "div --:\t", (wmb/wma), "\t", (zmb/zma) + print "div -+:\t", (wmb/wpa), "\t", (zmb/zpa) + print "div +-:\t", (wpb/wma), "\t", (zpb/zma) + print "div ++:\t", (wpb/wpa), "\t", (zpb/zpa) + + print "pow --:\t", (wma**wmb), "\t", (zma**zmb) + print "pow -+:\t", (wma**wpb), "\t", (zma**zpb) + print "pow +-:\t", (wpa**wmb), "\t", (zpa**zmb) + print "pow ++:\t", (wpa**wpb), "\t", (zpa**zpb) + print "pow --:\t", (wmb**wma), "\t", (zmb**zma) + print "pow -+:\t", (wmb**wpa), "\t", (zmb**zpa) + print "pow +-:\t", (wpb**wma), "\t", (zpb**zma) + print "pow ++:\t", (wpb**wpa), "\t", (zpb**zpa) + +# wpa = mpw(13) +# wma = -wpa +# wpb = wpa - 3 +# wmb = -wpb +# zpa = long(13) +# zma = -zpa +# zpb = zpa - 3 +# zmb = -zpb + print "mod --:\t", (wma%wmb), "\t", (zma%zmb) + print "mod -+:\t", (wma%wpb), "\t", (zma%zpb) + print "mod +-:\t", (wpa%wmb), "\t", (zpa%zmb) + print "mod ++:\t", (wpa%wpb), "\t", (zpa%zpb) + print "mod --:\t", (wmb%wma), "\t", (zmb%zma) + print "mod -+:\t", (wmb%wpa), "\t", (zmb%zpa) + print "mod +-:\t", (wpb%wma), "\t", (zpb%zma) + print "mod ++:\t", (wpb%wpa), "\t", (zpb%zpa) + + print "rem --:\t", divmod(wma, wmb), "\t", divmod(zma, zmb) + print "rem -+:\t", divmod(wma, wpb), "\t", divmod(zma, zpb) + print "rem +-:\t", divmod(wpa, wmb), "\t", divmod(zpa, zmb) + print "rem ++:\t", divmod(wpa, wpb), "\t", divmod(zpa, zpb) + print "rem --:\t", divmod(wmb, wma), "\t", divmod(zmb, zma) + print "rem -+:\t", divmod(wmb, wpa), "\t", divmod(zmb, zpa) + print "rem +-:\t", divmod(wpb, wma), "\t", divmod(zpb, zma) + print "rem ++:\t", divmod(wpb, wpa), "\t", divmod(zpb, zpa) + pass + + #---------------------------------------- + def test04_KnuthPoly(self): + self.t = 8 + tfmt = "%o" + if verbose: + print '\n', '-=' * 30 + print "Running %s.test04_KnuthPoly..." % \ + self.__class__.__name__ + print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi) + tm1 = tfmt % (self.t - 1) + tm2 = tfmt % (self.t - 2) + for m in range(self.lo,self.hi): + for n in range(m+1,self.hi+1): + wt = mpw(self.t) + wa = (wt**m - 1) * (wt**n - 1) + ws = tfmt % long(wa) + zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1" + if ws != zs: + print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws) + assert ws == zs + + self.t = 10 + tfmt = "%d" + if verbose: + print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi) + tm1 = tfmt % (self.t - 1) + tm2 = tfmt % (self.t - 2) + for m in range(self.lo,self.hi): + for n in range(m+1,self.hi+1): + wt = mpw(self.t) + wa = (wt**m - 1) * (wt**n - 1) + ws = tfmt % long(wa) + zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1" + if ws != zs: + print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws) + assert ws == zs + + self.t = 16 + tfmt = "%x" + if verbose: + print "\t(%d**m - 1) * (%d**n - 1), m,n in [%d,%d)" % (self.t,self.t,self.lo,self.hi) + tm1 = tfmt % (self.t - 1) + tm2 = tfmt % (self.t - 2) + for m in range(self.lo,self.hi): + for n in range(m+1,self.hi+1): + wt = mpw(self.t) + wa = (wt**m - 1) * (wt**n - 1) + ws = tfmt % long(wa) + zs = tm1 * (m - 1) + tm2 + tm1 * (n - m) + "0" * (m - 1) + "1" + if ws != zs: + print "(%d**%d - 1) * (%d**%d - 1)\t%s" % (self.t,m,self.t,n,ws) + assert ws == zs + pass + + #---------------------------------------- + def test05_IterativePowers(self): + if verbose: + print '\n', '-=' * 30 + print "Running %s.test05_IterativePowers..." % \ + self.__class__.__name__ + print "\t(m**n)/(m**(n-1)) == m for m,n in [%d,%d)" % (self.lo,self.hi) + for m in range(self.lo,self.hi): + wa = mpw(m) + wd = wa + for n in range(self.lo,self.hi): + wc = wa**n + we = wc/wd + if we != m: + print m, '^', n, '=', we + assert we == m + if wc != 0: + wd = wc + pass + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + +def test_suite(): + suite = unittest.TestSuite() + + suite.addTest(unittest.makeSuite(BasicTestCase)) + + return suite + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/beecrypt/python/test/unittest.py b/beecrypt/python/test/unittest.py new file mode 100644 index 0000000..d31e251 --- /dev/null +++ b/beecrypt/python/test/unittest.py @@ -0,0 +1,759 @@ +#!/usr/bin/env python +''' +Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's +Smalltalk testing framework. + +This module contains the core framework classes that form the basis of +specific test cases and suites (TestCase, TestSuite etc.), and also a +text-based utility class for running the tests and reporting the results + (TextTestRunner). + +Simple usage: + + import unittest + + class IntegerArithmenticTestCase(unittest.TestCase): + def testAdd(self): ## test method names begin 'test*' + self.assertEquals((1 + 2), 3) + self.assertEquals(0 + 1, 1) + def testMultiply(self): + self.assertEquals((0 * 10), 0) + self.assertEquals((5 * 8), 40) + + if __name__ == '__main__': + unittest.main() + +Further information is available in the bundled documentation, and from + + http://pyunit.sourceforge.net/ + +Copyright (c) 1999, 2000, 2001 Steve Purcell +This module is free software, and you may redistribute it and/or modify +it under the same terms as Python itself, so long as this copyright message +and disclaimer are retained in their original form. + +IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +''' + +__author__ = "Steve Purcell" +__email__ = "stephen_purcell at yahoo dot com" +__version__ = "#Revision: 1.46 $"[11:-2] + +import time +import sys +import traceback +import string +import os +import types + +############################################################################## +# Test framework core +############################################################################## + +# All classes defined herein are 'new-style' classes, allowing use of 'super()' +__metaclass__ = type + +def _strclass(cls): + return "%s.%s" % (cls.__module__, cls.__name__) + +class TestResult: + """Holder for test result information. + + Test results are automatically managed by the TestCase and TestSuite + classes, and do not need to be explicitly manipulated by writers of tests. + + Each instance holds the total number of tests run, and collections of + failures and errors that occurred among those test runs. The collections + contain tuples of (testcase, exceptioninfo), where exceptioninfo is the + formatted traceback of the error that occurred. + """ + def __init__(self): + self.failures = [] + self.errors = [] + self.testsRun = 0 + self.shouldStop = 0 + + def startTest(self, test): + "Called when the given test is about to be run" + self.testsRun = self.testsRun + 1 + + def stopTest(self, test): + "Called when the given test has been run" + pass + + def addError(self, test, err): + """Called when an error has occurred. 'err' is a tuple of values as + returned by sys.exc_info(). + """ + self.errors.append((test, self._exc_info_to_string(err))) + + def addFailure(self, test, err): + """Called when an error has occurred. 'err' is a tuple of values as + returned by sys.exc_info().""" + self.failures.append((test, self._exc_info_to_string(err))) + + def addSuccess(self, test): + "Called when a test has completed successfully" + pass + + def wasSuccessful(self): + "Tells whether or not this result was a success" + return len(self.failures) == len(self.errors) == 0 + + def stop(self): + "Indicates that the tests should be aborted" + self.shouldStop = 1 + + def _exc_info_to_string(self, err): + """Converts a sys.exc_info()-style tuple of values into a string.""" + return string.join(traceback.format_exception(*err), '') + + def __repr__(self): + return "<%s run=%i errors=%i failures=%i>" % \ + (_strclass(self.__class__), self.testsRun, len(self.errors), + len(self.failures)) + + +class TestCase: + """A class whose instances are single test cases. + + By default, the test code itself should be placed in a method named + 'runTest'. + + If the fixture may be used for many test cases, create as + many test methods as are needed. When instantiating such a TestCase + subclass, specify in the constructor arguments the name of the test method + that the instance is to execute. + + Test authors should subclass TestCase for their own tests. Construction + and deconstruction of the test's environment ('fixture') can be + implemented by overriding the 'setUp' and 'tearDown' methods respectively. + + If it is necessary to override the __init__ method, the base class + __init__ method must always be called. It is important that subclasses + should not change the signature of their __init__ method, since instances + of the classes are instantiated automatically by parts of the framework + in order to be run. + """ + + # This attribute determines which exception will be raised when + # the instance's assertion methods fail; test methods raising this + # exception will be deemed to have 'failed' rather than 'errored' + + failureException = AssertionError + + def __init__(self, methodName='runTest'): + """Create an instance of the class that will use the named test + method when executed. Raises a ValueError if the instance does + not have a method with the specified name. + """ + try: + self.__testMethodName = methodName + testMethod = getattr(self, methodName) + self.__testMethodDoc = testMethod.__doc__ + except AttributeError: + raise ValueError, "no such test method in %s: %s" % \ + (self.__class__, methodName) + + def setUp(self): + "Hook method for setting up the test fixture before exercising it." + pass + + def tearDown(self): + "Hook method for deconstructing the test fixture after testing it." + pass + + def countTestCases(self): + return 1 + + def defaultTestResult(self): + return TestResult() + + def shortDescription(self): + """Returns a one-line description of the test, or None if no + description has been provided. + + The default implementation of this method returns the first line of + the specified test method's docstring. + """ + doc = self.__testMethodDoc + return doc and string.strip(string.split(doc, "\n")[0]) or None + + def id(self): + return "%s.%s" % (_strclass(self.__class__), self.__testMethodName) + + def __str__(self): + return "%s (%s)" % (self.__testMethodName, _strclass(self.__class__)) + + def __repr__(self): + return "<%s testMethod=%s>" % \ + (_strclass(self.__class__), self.__testMethodName) + + def run(self, result=None): + return self(result) + + def __call__(self, result=None): + if result is None: result = self.defaultTestResult() + result.startTest(self) + testMethod = getattr(self, self.__testMethodName) + try: + try: + self.setUp() + except KeyboardInterrupt: + raise + except: + result.addError(self, self.__exc_info()) + return + + ok = 0 + try: + testMethod() + ok = 1 + except self.failureException, e: + result.addFailure(self, self.__exc_info()) + except KeyboardInterrupt: + raise + except: + result.addError(self, self.__exc_info()) + + try: + self.tearDown() + except KeyboardInterrupt: + raise + except: + result.addError(self, self.__exc_info()) + ok = 0 + if ok: result.addSuccess(self) + finally: + result.stopTest(self) + + def debug(self): + """Run the test without collecting errors in a TestResult""" + self.setUp() + getattr(self, self.__testMethodName)() + self.tearDown() + + def __exc_info(self): + """Return a version of sys.exc_info() with the traceback frame + minimised; usually the top level of the traceback frame is not + needed. + """ + exctype, excvalue, tb = sys.exc_info() + if sys.platform[:4] == 'java': ## tracebacks look different in Jython + return (exctype, excvalue, tb) + newtb = tb.tb_next + if newtb is None: + return (exctype, excvalue, tb) + return (exctype, excvalue, newtb) + + def fail(self, msg=None): + """Fail immediately, with the given message.""" + raise self.failureException, msg + + def failIf(self, expr, msg=None): + "Fail the test if the expression is true." + if expr: raise self.failureException, msg + + def failUnless(self, expr, msg=None): + """Fail the test unless the expression is true.""" + if not expr: raise self.failureException, msg + + def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): + """Fail unless an exception of class excClass is thrown + by callableObj when invoked with arguments args and keyword + arguments kwargs. If a different type of exception is + thrown, it will not be caught, and the test case will be + deemed to have suffered an error, exactly as for an + unexpected exception. + """ + try: + callableObj(*args, **kwargs) + except excClass: + return + else: + if hasattr(excClass,'__name__'): excName = excClass.__name__ + else: excName = str(excClass) + raise self.failureException, excName + + def failUnlessEqual(self, first, second, msg=None): + """Fail if the two objects are unequal as determined by the '==' + operator. + """ + if not first == second: + raise self.failureException, \ + (msg or '%s != %s' % (`first`, `second`)) + + def failIfEqual(self, first, second, msg=None): + """Fail if the two objects are equal as determined by the '==' + operator. + """ + if first == second: + raise self.failureException, \ + (msg or '%s == %s' % (`first`, `second`)) + + def failUnlessAlmostEqual(self, first, second, places=7, msg=None): + """Fail if the two objects are unequal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero. + + Note that decimal places (from zero) is usually not the same + as significant digits (measured from the most signficant digit). + """ + if round(second-first, places) != 0: + raise self.failureException, \ + (msg or '%s != %s within %s places' % (`first`, `second`, `places` )) + + def failIfAlmostEqual(self, first, second, places=7, msg=None): + """Fail if the two objects are equal as determined by their + difference rounded to the given number of decimal places + (default 7) and comparing to zero. + + Note that decimal places (from zero) is usually not the same + as significant digits (measured from the most signficant digit). + """ + if round(second-first, places) == 0: + raise self.failureException, \ + (msg or '%s == %s within %s places' % (`first`, `second`, `places`)) + + assertEqual = assertEquals = failUnlessEqual + + assertNotEqual = assertNotEquals = failIfEqual + + assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual + + assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual + + assertRaises = failUnlessRaises + + assert_ = failUnless + + + +class TestSuite: + """A test suite is a composite test consisting of a number of TestCases. + + For use, create an instance of TestSuite, then add test case instances. + When all tests have been added, the suite can be passed to a test + runner, such as TextTestRunner. It will run the individual test cases + in the order in which they were added, aggregating the results. When + subclassing, do not forget to call the base class constructor. + """ + def __init__(self, tests=()): + self._tests = [] + self.addTests(tests) + + def __repr__(self): + return "<%s tests=%s>" % (_strclass(self.__class__), self._tests) + + __str__ = __repr__ + + def countTestCases(self): + cases = 0 + for test in self._tests: + cases = cases + test.countTestCases() + return cases + + def addTest(self, test): + self._tests.append(test) + + def addTests(self, tests): + for test in tests: + self.addTest(test) + + def run(self, result): + return self(result) + + def __call__(self, result): + for test in self._tests: + if result.shouldStop: + break + test(result) + return result + + def debug(self): + """Run the tests without collecting errors in a TestResult""" + for test in self._tests: test.debug() + + +class FunctionTestCase(TestCase): + """A test case that wraps a test function. + + This is useful for slipping pre-existing test functions into the + PyUnit framework. Optionally, set-up and tidy-up functions can be + supplied. As with TestCase, the tidy-up ('tearDown') function will + always be called if the set-up ('setUp') function ran successfully. + """ + + def __init__(self, testFunc, setUp=None, tearDown=None, + description=None): + TestCase.__init__(self) + self.__setUpFunc = setUp + self.__tearDownFunc = tearDown + self.__testFunc = testFunc + self.__description = description + + def setUp(self): + if self.__setUpFunc is not None: + self.__setUpFunc() + + def tearDown(self): + if self.__tearDownFunc is not None: + self.__tearDownFunc() + + def runTest(self): + self.__testFunc() + + def id(self): + return self.__testFunc.__name__ + + def __str__(self): + return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__) + + def __repr__(self): + return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc) + + def shortDescription(self): + if self.__description is not None: return self.__description + doc = self.__testFunc.__doc__ + return doc and string.strip(string.split(doc, "\n")[0]) or None + + + +############################################################################## +# Locating and loading tests +############################################################################## + +class TestLoader: + """This class is responsible for loading tests according to various + criteria and returning them wrapped in a Test + """ + testMethodPrefix = 'test' + sortTestMethodsUsing = cmp + suiteClass = TestSuite + + def loadTestsFromTestCase(self, testCaseClass): + """Return a suite of all tests cases contained in testCaseClass""" + return self.suiteClass(map(testCaseClass, + self.getTestCaseNames(testCaseClass))) + + def loadTestsFromModule(self, module): + """Return a suite of all tests cases contained in the given module""" + tests = [] + for name in dir(module): + obj = getattr(module, name) + if (isinstance(obj, (type, types.ClassType)) and + issubclass(obj, TestCase)): + tests.append(self.loadTestsFromTestCase(obj)) + return self.suiteClass(tests) + + def loadTestsFromName(self, name, module=None): + """Return a suite of all tests cases given a string specifier. + + The name may resolve either to a module, a test case class, a + test method within a test case class, or a callable object which + returns a TestCase or TestSuite instance. + + The method optionally resolves the names relative to a given module. + """ + parts = string.split(name, '.') + if module is None: + if not parts: + raise ValueError, "incomplete test name: %s" % name + else: + parts_copy = parts[:] + while parts_copy: + try: + module = __import__(string.join(parts_copy,'.')) + break + except ImportError: + del parts_copy[-1] + if not parts_copy: raise + parts = parts[1:] + obj = module + for part in parts: + obj = getattr(obj, part) + + import unittest + if type(obj) == types.ModuleType: + return self.loadTestsFromModule(obj) + elif (isinstance(obj, (type, types.ClassType)) and + issubclass(obj, unittest.TestCase)): + return self.loadTestsFromTestCase(obj) + elif type(obj) == types.UnboundMethodType: + return obj.im_class(obj.__name__) + elif callable(obj): + test = obj() + if not isinstance(test, unittest.TestCase) and \ + not isinstance(test, unittest.TestSuite): + raise ValueError, \ + "calling %s returned %s, not a test" % (obj,test) + return test + else: + raise ValueError, "don't know how to make test from: %s" % obj + + def loadTestsFromNames(self, names, module=None): + """Return a suite of all tests cases found using the given sequence + of string specifiers. See 'loadTestsFromName()'. + """ + suites = [] + for name in names: + suites.append(self.loadTestsFromName(name, module)) + return self.suiteClass(suites) + + def getTestCaseNames(self, testCaseClass): + """Return a sorted sequence of method names found within testCaseClass + """ + testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p, + dir(testCaseClass)) + for baseclass in testCaseClass.__bases__: + for testFnName in self.getTestCaseNames(baseclass): + if testFnName not in testFnNames: # handle overridden methods + testFnNames.append(testFnName) + if self.sortTestMethodsUsing: + testFnNames.sort(self.sortTestMethodsUsing) + return testFnNames + + + +defaultTestLoader = TestLoader() + + +############################################################################## +# Patches for old functions: these functions should be considered obsolete +############################################################################## + +def _makeLoader(prefix, sortUsing, suiteClass=None): + loader = TestLoader() + loader.sortTestMethodsUsing = sortUsing + loader.testMethodPrefix = prefix + if suiteClass: loader.suiteClass = suiteClass + return loader + +def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): + return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) + +def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): + return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) + +def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): + return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) + + +############################################################################## +# Text UI +############################################################################## + +class _WritelnDecorator: + """Used to decorate file-like objects with a handy 'writeln' method""" + def __init__(self,stream): + self.stream = stream + + def __getattr__(self, attr): + return getattr(self.stream,attr) + + def writeln(self, *args): + if args: self.write(*args) + self.write('\n') # text-mode streams translate to \r\n if needed + + +class _TextTestResult(TestResult): + """A test result class that can print formatted text results to a stream. + + Used by TextTestRunner. + """ + separator1 = '=' * 70 + separator2 = '-' * 70 + + def __init__(self, stream, descriptions, verbosity): + TestResult.__init__(self) + self.stream = stream + self.showAll = verbosity > 1 + self.dots = verbosity == 1 + self.descriptions = descriptions + + def getDescription(self, test): + if self.descriptions: + return test.shortDescription() or str(test) + else: + return str(test) + + def startTest(self, test): + TestResult.startTest(self, test) + if self.showAll: + self.stream.write(self.getDescription(test)) + self.stream.write(" ... ") + + def addSuccess(self, test): + TestResult.addSuccess(self, test) + if self.showAll: + self.stream.writeln("ok") + elif self.dots: + self.stream.write('.') + + def addError(self, test, err): + TestResult.addError(self, test, err) + if self.showAll: + self.stream.writeln("ERROR") + elif self.dots: + self.stream.write('E') + + def addFailure(self, test, err): + TestResult.addFailure(self, test, err) + if self.showAll: + self.stream.writeln("FAIL") + elif self.dots: + self.stream.write('F') + + def printErrors(self): + if self.dots or self.showAll: + self.stream.writeln() + self.printErrorList('ERROR', self.errors) + self.printErrorList('FAIL', self.failures) + + def printErrorList(self, flavour, errors): + for test, err in errors: + self.stream.writeln(self.separator1) + self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) + self.stream.writeln(self.separator2) + self.stream.writeln("%s" % err) + + +class TextTestRunner: + """A test runner class that displays results in textual form. + + It prints out the names of tests as they are run, errors as they + occur, and a summary of the results at the end of the test run. + """ + def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): + self.stream = _WritelnDecorator(stream) + self.descriptions = descriptions + self.verbosity = verbosity + + def _makeResult(self): + return _TextTestResult(self.stream, self.descriptions, self.verbosity) + + def run(self, test): + "Run the given test case or test suite." + result = self._makeResult() + startTime = time.time() + test(result) + stopTime = time.time() + timeTaken = float(stopTime - startTime) + result.printErrors() + self.stream.writeln(result.separator2) + run = result.testsRun + self.stream.writeln("Ran %d test%s in %.3fs" % + (run, run != 1 and "s" or "", timeTaken)) + self.stream.writeln() + if not result.wasSuccessful(): + self.stream.write("FAILED (") + failed, errored = map(len, (result.failures, result.errors)) + if failed: + self.stream.write("failures=%d" % failed) + if errored: + if failed: self.stream.write(", ") + self.stream.write("errors=%d" % errored) + self.stream.writeln(")") + else: + self.stream.writeln("OK") + return result + + + +############################################################################## +# Facilities for running tests from the command line +############################################################################## + +class TestProgram: + """A command-line program that runs a set of tests; this is primarily + for making test modules conveniently executable. + """ + USAGE = """\ +Usage: %(progName)s [options] [test] [...] + +Options: + -h, --help Show this message + -v, --verbose Verbose output + -q, --quiet Minimal output + +Examples: + %(progName)s - run default set of tests + %(progName)s MyTestSuite - run suite 'MyTestSuite' + %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething + %(progName)s MyTestCase - run all 'test*' test methods + in MyTestCase +""" + def __init__(self, module='__main__', defaultTest=None, + argv=None, testRunner=None, testLoader=defaultTestLoader): + if type(module) == type(''): + self.module = __import__(module) + for part in string.split(module,'.')[1:]: + self.module = getattr(self.module, part) + else: + self.module = module + if argv is None: + argv = sys.argv + self.verbosity = 1 + self.defaultTest = defaultTest + self.testRunner = testRunner + self.testLoader = testLoader + self.progName = os.path.basename(argv[0]) + self.parseArgs(argv) + self.runTests() + + def usageExit(self, msg=None): + if msg: print msg + print self.USAGE % self.__dict__ + sys.exit(2) + + def parseArgs(self, argv): + import getopt + try: + options, args = getopt.getopt(argv[1:], 'hHvq', + ['help','verbose','quiet']) + for opt, value in options: + if opt in ('-h','-H','--help'): + self.usageExit() + if opt in ('-q','--quiet'): + self.verbosity = 0 + if opt in ('-v','--verbose'): + self.verbosity = 2 + if len(args) == 0 and self.defaultTest is None: + self.test = self.testLoader.loadTestsFromModule(self.module) + return + if len(args) > 0: + self.testNames = args + else: + self.testNames = (self.defaultTest,) + self.createTests() + except getopt.error, msg: + self.usageExit(msg) + + def createTests(self): + self.test = self.testLoader.loadTestsFromNames(self.testNames, + self.module) + + def runTests(self): + if self.testRunner is None: + self.testRunner = TextTestRunner(verbosity=self.verbosity) + result = self.testRunner.run(self.test) + sys.exit(not result.wasSuccessful()) + +main = TestProgram + + +############################################################################## +# Executing this module from the command line +############################################################################## + +if __name__ == "__main__": + main(module=None) -- 2.7.4