1/*
2 * Minimal support for the C-type NSDecimal
3 *
4 * There is no implicit conversion to/from Python numbers, because NSDecimal
5 * numbers behave differently from Python numbers (explicit rounding)
6 *
7 * - number methods
8 *   NSDecimal objects support +, -, *, /, +=, -=, *= and /=, which directly
9 *   correspond with NSDecimal* functions with the NSRoundPlain argument.
10 *   They also support unary -, unary + and abs, with the obvious semantics.
11 */
12#include "Python.h"
13#include "pyobjc-api.h"
14
15#ifndef  _C_CONST
16#define _C_CONST    'r'
17#endif
18
19#import <Foundation/Foundation.h>
20
21typedef struct {
22	PyObject_HEAD
23	NSDecimal value;
24	NSDecimalNumber *objc_value;
25} DecimalObject;
26
27#define Decimal_Value(v) ((DecimalObject*)(v))->value
28
29static PyObject* Decimal_New(NSDecimal* aDecimal);
30static PyObject* decimal_repr(PyObject* self);
31static PyObject* decimal_richcompare(PyObject* self, PyObject* other, int type);
32static void decimal_dealloc(PyObject* self);
33static int decimal_init(PyObject* self, PyObject* args, PyObject* kwds);
34static PyObject* decimal_new(PyTypeObject* type, PyObject* args, PyObject* kwds);
35static PyObject* decimal_asint(PyObject* self);
36static PyObject* decimal_asfloat(PyObject* self);
37static PyObject* decimal_add(PyObject* left, PyObject* right);
38static PyObject* decimal_subtract(PyObject* left, PyObject* right);
39static PyObject* decimal_multiply(PyObject* left, PyObject* right);
40static PyObject* decimal_divide(PyObject* left, PyObject* right);
41static PyObject* decimal_power(PyObject* left, PyObject* right, PyObject* power);
42static int decimal_nonzero(PyObject* self);
43static int decimal_coerce(PyObject** l, PyObject** r);
44static PyObject* decimal_inplace_add(PyObject* left, PyObject* right);
45static PyObject* decimal_inplace_subtract(PyObject* left, PyObject* right);
46static PyObject* decimal_inplace_multiply(PyObject* left, PyObject* right);
47static PyObject* decimal_inplace_divide(PyObject* left, PyObject* right);
48static PyObject* decimal_positive(PyObject* self);
49static PyObject* decimal_negative(PyObject* self);
50static PyObject* decimal_absolute(PyObject* self);
51
52static PyNumberMethods decimal_asnumber = {
53	decimal_add,			/* nb_add */
54	decimal_subtract,		/* nb_subtract */
55	decimal_multiply,		/* nb_multiply */
56	decimal_divide,			/* nb_divide */
57	NULL,				/* nb_remainder */
58	NULL,				/* nb_divmod */
59	decimal_power,			/* nb_power */
60	decimal_negative,		/* nb_negative */
61	decimal_positive,		/* nb_positive */
62	decimal_absolute,		/* nb_absolute */
63	decimal_nonzero,		/* nb_nonzero */
64	NULL,				/* nb_invert */
65	NULL,				/* nb_lshift */
66	NULL,				/* nb_rshift */
67	NULL,				/* nb_and */
68	NULL,				/* nb_xor */
69	NULL,				/* nb_or */
70	decimal_coerce,			/* nb_coerce */
71	NULL,				/* nb_int */
72	NULL,				/* nb_long */
73	NULL,				/* nb_float */
74	NULL,				/* nb_oct */
75	NULL,				/* nb_hex */
76	decimal_inplace_add,		/* nb_inplace_add */
77	decimal_inplace_subtract,	/* nb_inplace_subtract */
78	decimal_inplace_multiply,	/* nb_inplace_multiply */
79	decimal_inplace_divide,		/* nb_inplace_divide */
80	NULL,				/* nb_inplace_remainder */
81	NULL,				/* nb_inplace_power */
82	NULL,				/* nb_inplace_lshift */
83	NULL,				/* nb_inplace_rshift */
84	NULL,				/* nb_inplace_and */
85	NULL,				/* nb_inplace_xor */
86	NULL,				/* nb_inplace_or */
87	NULL,				/* nb_floor_divide */
88	NULL,				/* nb_true_divide */
89	NULL,				/* nb_inplace_floor_divide */
90	NULL				/* nb_inplace_true_divide */
91#if (PY_VERSION_HEX >= 0x02050000)
92	,NULL				/* nb_index */
93#endif
94};
95
96static NSDecimalNumber *
97Decimal_ObjCValue(PyObject *self) {
98	DecimalObject *pyself = (DecimalObject *)self;
99	NSDecimalNumber *res = pyself->objc_value;
100	if (!res) {
101		res = pyself->objc_value = [[NSDecimalNumber alloc] initWithDecimal:Decimal_Value(self)];
102	}
103	return res;
104}
105
106static PyObject *decimal_get__pyobjc_object__(PyObject *self, void *closure __attribute__((__unused__))) {
107	PyObject *rval = PyObjCObject_New(Decimal_ObjCValue(self), 0, YES);
108	return rval;
109}
110
111static PyGetSetDef decimal_getseters[] = {
112	{
113		"__pyobjc_object__",
114		(getter)decimal_get__pyobjc_object__, NULL,
115		"NSDecimalNumber instance",
116		NULL
117	},
118	{
119		NULL,
120		NULL, NULL,
121		NULL,
122		NULL
123	}
124};
125
126static PyMethodDef decimal_methods[] = {
127	{
128		"as_int",
129		(PyCFunction)decimal_asint,
130		METH_NOARGS,
131		"Convert decimal to a Python int"
132	},
133	{
134		"as_float",
135		(PyCFunction)decimal_asfloat,
136		METH_NOARGS,
137		"Convert decimal to a Python float"
138	},
139	{
140		NULL,
141		NULL,
142		0,
143		NULL
144	}
145};
146
147static PyObject*
148decimal_getattro(PyObject *o, PyObject *attr_name)
149{
150	PyObject *res;
151	res = PyObject_GenericGetAttr(o, attr_name);
152	if (res == NULL) {
153		PyObject *tmp;
154		PyErr_Clear();
155		tmp = decimal_get__pyobjc_object__(o, NULL);
156		res = PyObject_GenericGetAttr(tmp, attr_name);
157		Py_XDECREF(tmp);
158	}
159	return res;
160}
161
162static PyTypeObject Decimal_Type = {
163	PyObject_HEAD_INIT(NULL)
164	0,					/* ob_size */
165	"Foundation.NSDecimal",			/* tp_name */
166	sizeof (DecimalObject),			/* tp_basicsize */
167	0,					/* tp_itemsize */
168	/* methods */
169	decimal_dealloc,			/* tp_dealloc */
170	0,					/* tp_print */
171	0,					/* tp_getattr */
172	0,					/* tp_setattr */
173	0,					/* tp_compare */
174	decimal_repr,				/* tp_repr */
175	&decimal_asnumber,			/* tp_as_number */
176	0,					/* tp_as_sequence */
177	0,					/* tp_as_mapping */
178	0,					/* tp_hash */
179	0,					/* tp_call */
180	decimal_repr,				/* tp_str */
181	decimal_getattro,			/* tp_getattro */
182	PyObject_GenericSetAttr,		/* tp_setattro */
183	0,					/* tp_as_buffer */
184	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_RICHCOMPARE | Py_TPFLAGS_HAVE_INPLACEOPS, /* tp_flags */
185	"NSDecimal wrapper",			/* tp_doc */
186	0,					/* tp_traverse */
187	0,					/* tp_clear */
188	decimal_richcompare,			/* tp_richcompare */
189	0,					/* tp_weaklistoffset */
190	0,					/* tp_iter */
191	0,					/* tp_iternext */
192	decimal_methods,			/* tp_methods */
193	0,					/* tp_members */
194	decimal_getseters,			/* tp_getset */
195	0,					/* tp_base */
196	0,					/* tp_dict */
197	0,					/* tp_descr_get */
198	0,					/* tp_descr_set */
199	0,					/* tp_dictoffset */
200	0,					/* tp_init */
201	0,					/* tp_alloc */
202	decimal_new,				/* tp_new */
203	0,					/* tp_free */
204	0,					/* tp_is_gc */
205	0,					/* tp_bases */
206	0,					/* tp_mro */
207	0,					/* tp_cache */
208	0,					/* tp_subclasses */
209	0					/* tp_weaklist */
210#if PY_VERSION_HEX >= 0x020300A2
211	, 0,					/* tp_del */
212#endif
213};
214
215#define Decimal_Check(obj) PyObject_TypeCheck(obj, &Decimal_Type)
216
217static void DecimalFromString(NSDecimal* aDecimal, NSString* aString, void* locale __attribute__((__unused__)))
218{
219	NSDecimalNumber* num;
220
221	num = [[NSDecimalNumber alloc] initWithString:aString];
222	*aDecimal = [num decimalValue];
223	[num release];
224}
225
226static void DecimalFromComponents(NSDecimal* aDecimal, unsigned long long mantissa, unsigned short exponent, BOOL negative)
227{
228	NSDecimalNumber* num;
229
230	num = [[NSDecimalNumber alloc]
231			initWithMantissa:mantissa
232			exponent:exponent
233			isNegative:negative];
234
235	*aDecimal = [num decimalValue];
236	[num release];
237}
238
239static PyObject*
240decimal_new(PyTypeObject* type __attribute__((__unused__)), PyObject* args, PyObject* kwds)
241{
242	DecimalObject* self;
243
244
245	self = PyObject_New(DecimalObject, &Decimal_Type);
246	if (self == NULL) {
247	    return PyErr_NoMemory();
248	}
249
250	memset(&self->value, 0, sizeof(self->value));
251	self->objc_value = nil;
252	if ((args == NULL || PyTuple_Size(args) == 0) && (kwds == NULL || PyDict_Size(kwds) == 0)) {
253		DecimalFromComponents(&self->value, 0, 0, 0);
254		return (PyObject*)self;
255	}
256	if (decimal_init((PyObject*)self, args, kwds) == -1) {
257		Py_DECREF(self);
258		self = NULL;
259		return NULL;
260	}
261	return (PyObject*)self;
262}
263
264static void
265decimal_dealloc(PyObject* self)
266{
267	[((DecimalObject *)self)->objc_value release];
268	PyObject_Free(self);
269}
270
271
272static int
273decimal_init(PyObject* self, PyObject* args, PyObject* kwds)
274{
275static char* keywords[] = { "mantissa", "exponent", "isNegative", NULL };
276static char* keywords2[] = { "string", NULL };
277	PyObject* pyMantissa;
278	PyObject* pyExponent;
279	PyObject* pyNegative;
280	BOOL negative;
281	unsigned long long mantissa;
282	short int exponent;
283
284	((DecimalObject*)self)->objc_value = nil;
285
286	if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO", keywords, &pyMantissa, &pyExponent, &pyNegative)) {
287		PyObject* pyValue;
288		NSString* volatile stringVal;
289
290		PyErr_Clear();
291		if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", keywords2, &pyValue)) {
292			PyErr_SetString(PyExc_TypeError,
293			    "NSDecimal(stringValue) or NSDecimal(mantissa, exponent, isNegative)");
294			return -1;
295		}
296		if (PyInt_Check(pyValue)) {
297			long lng = PyInt_AsLong(pyValue);
298			if (lng < 0) {
299				mantissa = -lng;
300				exponent = 0;
301				negative = YES;
302			} else{
303				mantissa = lng;
304				exponent = 0;
305				negative = NO;
306			}
307
308			DecimalFromComponents(&Decimal_Value(self),
309				mantissa, exponent, negative);
310			return 0;
311		} else if (PyLong_Check(pyValue)) {
312			mantissa = PyLong_AsUnsignedLongLong(pyValue);
313			if (PyErr_Occurred()) {
314				long long lng;
315				PyErr_Clear();
316				lng = PyLong_AsLongLong(pyValue);
317				if (PyErr_Occurred()) {
318					return -1;
319				}
320				if (lng < 0) {
321					mantissa = -lng;
322					exponent = 0;
323					negative = YES;
324				} else {
325					mantissa = lng;
326					exponent = 0;
327					negative = NO;
328				}
329				DecimalFromComponents(&Decimal_Value(self),
330					mantissa, exponent, negative);
331				return 0;
332			} else {
333				DecimalFromComponents(&Decimal_Value(self),
334					mantissa, 0, NO);
335				return 0;
336			}
337		} else if (PyFloat_Check(pyValue)) {
338			/* Explicit conversion from float to NSDecimal
339			 * first convert the float to a string using repr, that
340			 * is easier than extracting the components of the
341			 * float.
342			 */
343			PyObject* strVal = PyObject_Repr(pyValue);
344			PyObject* uniVal = NULL;
345
346			if (strVal == NULL) return -1;
347
348			uniVal = PyUnicode_FromEncodedObject(strVal, "ascii", "strict");
349			Py_DECREF(strVal);
350
351			if (uniVal == NULL) return -1;
352
353			stringVal = PyObjC_PythonToId(uniVal);
354			Py_DECREF(uniVal);
355
356			PyObjC_DURING
357				DecimalFromString(&Decimal_Value(self), stringVal, NULL);
358			PyObjC_HANDLER
359				PyObjCErr_FromObjC(localException);
360			PyObjC_ENDHANDLER
361
362			if (PyErr_Occurred()) return -1;
363			return 0;
364
365
366		} else if (PyObjCObject_Check(pyValue)) {
367			NSObject* value = PyObjC_PythonToId(pyValue);
368			if ([value isKindOfClass:[NSDecimalNumber class]]) {
369				((DecimalObject*)self)->value = [
370					(NSDecimalNumber*)value decimalValue
371				];
372
373				((DecimalObject*)self)->objc_value =
374					(NSDecimalNumber*)value;
375				[value retain];
376				return 0;
377			}
378			PyErr_Format(PyExc_TypeError, "cannot convert object of %s to NSDecimal", pyValue->ob_type->tp_name);
379			return -1;
380		} else if (!PyString_Check(pyValue) && !PyUnicode_Check(pyValue)) {
381			PyErr_Format(PyExc_TypeError, "cannot convert object of %s to NSDecimal", pyValue->ob_type->tp_name);
382			return -1;
383		}
384
385		stringVal = PyObjC_PythonToId(pyValue);
386		PyObjC_DURING
387			DecimalFromString(&Decimal_Value(self), stringVal, NULL);
388		PyObjC_HANDLER
389			PyObjCErr_FromObjC(localException);
390		PyObjC_ENDHANDLER
391
392		if (PyErr_Occurred()) return -1;
393		return 0;
394
395	}
396
397	negative = PyObject_IsTrue(pyNegative);
398	if (PyObjC_PythonToObjC(@encode(short int), pyExponent, &exponent) == -1) {
399		return -1;
400	}
401
402	if (PyObjC_PythonToObjC(@encode(unsigned long long), pyMantissa, &mantissa) == -1) {
403		return -1;
404	}
405
406
407	DecimalFromComponents(&Decimal_Value(self),
408		mantissa,
409		exponent,
410		negative);
411
412	return 0;
413}
414
415static PyObject*
416decimal_richcompare(PyObject* self, PyObject* other, int type)
417{
418	NSComparisonResult res;
419
420	if (!Decimal_Check(other)) {
421		if (type == Py_EQ) {
422			return PyBool_FromLong(0);
423		}
424		PyErr_Format(PyExc_TypeError,
425			"Cannot compare NSDecimal and %s",
426			other->ob_type->tp_name);
427		return NULL;
428	}
429
430	res = NSDecimalCompare(&Decimal_Value(self), &Decimal_Value(other));
431
432	switch (type) {
433	case Py_LT: return PyBool_FromLong(res ==  NSOrderedAscending);
434	case Py_LE: return PyBool_FromLong(res != NSOrderedDescending);
435	case Py_EQ: return PyBool_FromLong(res == NSOrderedSame);
436	case Py_NE: return PyBool_FromLong(res != NSOrderedSame);
437	case Py_GE: return PyBool_FromLong(res != NSOrderedAscending);
438	case Py_GT: return PyBool_FromLong(res == NSOrderedDescending);
439	default:
440		    PyErr_SetString(PyExc_TypeError,
441				  "Bad comparison arg");
442		    return NULL;
443	}
444}
445
446
447static PyObject* decimal_asint(PyObject* self)
448{
449	NSDecimalNumber* tmp = Decimal_ObjCValue(self);
450	return PyInt_FromLong([tmp longValue]);
451}
452
453static PyObject* decimal_asfloat(PyObject* self)
454{
455	NSDecimalNumber* tmp = Decimal_ObjCValue(self);
456	return PyFloat_FromDouble([tmp doubleValue]);
457}
458
459static PyObject* decimal_power(
460	PyObject* left __attribute__((__unused__)),
461	PyObject* right __attribute__((__unused__)),
462	PyObject* extra __attribute__((__unused__)))
463{
464	PyErr_SetString(PyExc_TypeError,
465		"pow() and ** are not supported for NSDecimal");
466	return NULL;
467}
468
469static PyObject* decimal_add(PyObject* left, PyObject* right)
470{
471	NSDecimal  result;
472	NSCalculationError err;
473
474	err = NSDecimalAdd(&result,
475			&Decimal_Value(left),
476			&Decimal_Value(right),
477			NSRoundPlain);
478	if (err == NSCalculationOverflow) {
479		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
480		return NULL;
481	} else if (err == NSCalculationUnderflow) {
482		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
483		return NULL;
484	} else  {
485		NSDecimalCompact(&result);
486		return Decimal_New(&result);
487	}
488}
489
490static PyObject* decimal_subtract(PyObject* left, PyObject* right)
491{
492	NSDecimal  result;
493	NSCalculationError err;
494
495	err = NSDecimalSubtract(&result,
496			&Decimal_Value(left),
497			&Decimal_Value(right),
498			NSRoundPlain);
499	if (err == NSCalculationOverflow) {
500		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
501		return NULL;
502	} else if (err == NSCalculationUnderflow) {
503		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
504		return NULL;
505	} else  {
506		NSDecimalCompact(&result);
507		return Decimal_New(&result);
508	}
509}
510
511static PyObject* decimal_multiply(PyObject* left, PyObject* right)
512{
513	NSDecimal  result;
514	NSCalculationError err;
515
516	err = NSDecimalMultiply(&result,
517			&Decimal_Value(left),
518			&Decimal_Value(right),
519			NSRoundPlain);
520	if (err == NSCalculationOverflow) {
521		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
522		return NULL;
523	} else if (err == NSCalculationUnderflow) {
524		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
525		return NULL;
526	} else  {
527		NSDecimalCompact(&result);
528		return Decimal_New(&result);
529	}
530}
531
532static PyObject* decimal_divide(PyObject* left, PyObject* right)
533{
534	NSDecimal  result;
535	NSCalculationError err;
536
537	err = NSDecimalDivide(&result,
538			&Decimal_Value(left),
539			&Decimal_Value(right),
540			NSRoundPlain);
541	if (err == NSCalculationOverflow) {
542		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
543		return NULL;
544	} else if (err == NSCalculationUnderflow) {
545		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
546		return NULL;
547	} else  {
548		NSDecimalCompact(&result);
549		return Decimal_New(&result);
550	}
551}
552
553static PyObject* decimal_inplace_add(PyObject* left, PyObject* right)
554{
555	NSDecimal  result;
556	NSCalculationError err;
557	int r = decimal_coerce(&left, &right);
558	if (r == 1) {
559		PyErr_Format(PyExc_TypeError,
560			"unsupported operand type(s) for +=: '%s' and '%s'",
561			left->ob_type->tp_name,
562			right->ob_type->tp_name);
563		return NULL;
564	}
565
566	err = NSDecimalAdd(&result,
567			&Decimal_Value(left),
568			&Decimal_Value(right),
569			NSRoundPlain);
570	if (err == NSCalculationOverflow) {
571		Py_DECREF(left); Py_DECREF(right);
572		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
573		return NULL;
574	} else if (err == NSCalculationUnderflow) {
575		Py_DECREF(left); Py_DECREF(right);
576		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
577		return NULL;
578	} else  {
579		Py_DECREF(right);
580		NSDecimalCompact(&result);
581		Decimal_Value(left) = result;
582		return left;
583	}
584}
585
586static PyObject* decimal_inplace_subtract(PyObject* left, PyObject* right)
587{
588	NSDecimal  result;
589	NSCalculationError err;
590	int r = decimal_coerce(&left, &right);
591	if (r == 1) {
592		PyErr_Format(PyExc_TypeError,
593			"unsupported operand type(s) for -=: '%s' and '%s'",
594			left->ob_type->tp_name,
595			right->ob_type->tp_name);
596		return NULL;
597	}
598
599	err = NSDecimalSubtract(&result,
600			&Decimal_Value(left),
601			&Decimal_Value(right),
602			NSRoundPlain);
603	if (err == NSCalculationOverflow) {
604		Py_DECREF(left); Py_DECREF(right);
605		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
606		return NULL;
607	} else if (err == NSCalculationUnderflow) {
608		Py_DECREF(left); Py_DECREF(right);
609		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
610		return NULL;
611	} else  {
612		Py_DECREF(right);
613		NSDecimalCompact(&result);
614		Decimal_Value(left) = result;
615		return left;
616	}
617}
618
619static PyObject* decimal_inplace_multiply(PyObject* left, PyObject* right)
620{
621	NSDecimal  result;
622	NSCalculationError err;
623	int r = decimal_coerce(&left, &right);
624	if (r == 1) {
625		PyErr_Format(PyExc_TypeError,
626			"unsupported operand type(s) for *=: '%s' and '%s'",
627			left->ob_type->tp_name,
628			right->ob_type->tp_name);
629		return NULL;
630	}
631
632	err = NSDecimalMultiply(&result,
633			&Decimal_Value(left),
634			&Decimal_Value(right),
635			NSRoundPlain);
636	if (err == NSCalculationOverflow) {
637		Py_DECREF(left); Py_DECREF(right);
638		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
639		return NULL;
640	} else if (err == NSCalculationUnderflow) {
641		Py_DECREF(left); Py_DECREF(right);
642		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
643		return NULL;
644	} else  {
645		Py_DECREF(right);
646		NSDecimalCompact(&result);
647		Decimal_Value(left) = result;
648		return left;
649	}
650}
651
652static PyObject* decimal_inplace_divide(PyObject* left, PyObject* right)
653{
654	NSDecimal  result;
655	NSCalculationError err;
656	int r = decimal_coerce(&left, &right);
657	if (r == 1) {
658		PyErr_Format(PyExc_TypeError,
659			"unsupported operand type(s) for /=: '%s' and '%s'",
660			left->ob_type->tp_name,
661			right->ob_type->tp_name);
662		return NULL;
663	}
664
665	err = NSDecimalDivide(&result,
666			&Decimal_Value(left),
667			&Decimal_Value(right),
668			NSRoundPlain);
669	if (err == NSCalculationOverflow) {
670		Py_DECREF(left); Py_DECREF(right);
671		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
672		return NULL;
673	} else if (err == NSCalculationUnderflow) {
674		Py_DECREF(left); Py_DECREF(right);
675		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
676		return NULL;
677	} else  {
678		Py_DECREF(right);
679		NSDecimalCompact(&result);
680		Decimal_Value(left) = result;
681		return left;
682	}
683}
684
685static int decimal_nonzero(PyObject* self)
686{
687	NSDecimal zero;
688
689	DecimalFromComponents(&zero, 0, 0, 0);
690
691	return NSDecimalCompare(&zero, &Decimal_Value(self)) == NSOrderedSame;
692}
693
694static PyObject* decimal_positive(PyObject* self)
695{
696	Py_INCREF(self);
697	return self;
698}
699
700static PyObject* decimal_negative(PyObject* self)
701{
702	NSDecimal  result;
703	NSCalculationError err;
704	NSDecimal  zero;
705	DecimalFromComponents(&zero, 0, 0, 0);
706
707	err = NSDecimalSubtract(&result,
708			&zero,
709			&Decimal_Value(self),
710			NSRoundPlain);
711	if (err == NSCalculationOverflow) {
712		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
713		return NULL;
714	} else if (err == NSCalculationUnderflow) {
715		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
716		return NULL;
717	} else  {
718		NSDecimalCompact(&result);
719		return Decimal_New(&result);
720	}
721}
722
723static PyObject* decimal_absolute(PyObject* self)
724{
725	NSDecimal  result;
726	NSCalculationError err;
727	NSDecimal  zero;
728	DecimalFromComponents(&zero, 0, 0, 0);
729
730
731	switch (NSDecimalCompare(&zero, &Decimal_Value(self))) {
732	case NSOrderedSame:
733	case NSOrderedAscending:
734		/* self >= 0 */
735		Py_INCREF(self);
736		return self;
737
738	case NSOrderedDescending: ;
739	}
740
741
742	err = NSDecimalSubtract(&result,
743			&zero,
744			&Decimal_Value(self),
745			NSRoundPlain);
746	if (err == NSCalculationOverflow) {
747		PyErr_SetString(PyExc_OverflowError, "Numeric overflow");
748		return NULL;
749	} else if (err == NSCalculationUnderflow) {
750		PyErr_SetString(PyExc_OverflowError, "Numeric underflow");
751		return NULL;
752	} else  {
753		NSDecimalCompact(&result);
754		return Decimal_New(&result);
755	}
756}
757
758static int decimal_coerce(PyObject** l, PyObject** r)
759{
760	PyObject* right = NULL;
761	PyObject* left = NULL;
762	PyObject* args = NULL;
763	int res;
764
765	if (Decimal_Check(*l) && Decimal_Check(*r)) {
766		Py_INCREF(*l);
767		Py_INCREF(*r);
768		return 0;
769	}
770
771	if (!Decimal_Check(*l)) {
772		/* The test is needed to avoid silently converting strings */
773		if (PyString_Check(*l) || PyUnicode_Check(*l) || PyFloat_Check(*l)) goto error;
774
775		left = (PyObject*)PyObject_New(DecimalObject, &Decimal_Type);
776		if (left == NULL) goto error;
777
778		args = Py_BuildValue("(O)", *l);
779		if (args == NULL) goto error;
780
781		res = decimal_init(left, args, NULL);
782		if (res == -1) goto error;
783
784		Py_DECREF(args); args = NULL;
785	}
786
787	if (!Decimal_Check(*r)) {
788		/* The test is needed to avoid silently converting strings */
789		if (PyString_Check(*r) || PyUnicode_Check(*r) || PyFloat_Check(*r)) goto error;
790
791		right = (PyObject*)PyObject_New(DecimalObject, &Decimal_Type);
792		if (right == NULL) goto error;
793
794		args = Py_BuildValue("(O)", *r);
795		if (args == NULL) goto error;
796
797		res = decimal_init(right, args, NULL);
798		if (res == -1) goto error;
799
800		Py_DECREF(args); args = NULL;
801	}
802
803	if (left != NULL) {
804		*l = left;
805	} else {
806		Py_INCREF(*l);
807	}
808
809	if (right != NULL) {
810		*r = right;
811	} else {
812		Py_INCREF(*r);
813	}
814
815	return 0;
816
817error:
818	Py_XDECREF(args);
819	Py_XDECREF(left);
820	Py_XDECREF(right);
821	return 1;
822}
823
824static PyObject*
825decimal_repr(PyObject* self)
826{
827	NSString* val = NSDecimalString(&Decimal_Value(self), NULL);
828	PyObject* tmp =  PyObjC_IdToPython(val);
829	PyObject* repr = PyObject_Str(tmp);
830	Py_DECREF(tmp);
831	return repr;
832}
833
834static inline int
835Decimal_Convert(PyObject* self, void* val)
836{
837	if (Decimal_Check(self)) {
838		 *(NSDecimal**)val = &Decimal_Value(self);
839		 return 1;
840	}
841	PyErr_SetString(PyExc_TypeError, "Expecting an NSDecimal");
842	return 0;
843}
844
845
846static PyObject*
847Decimal_New(NSDecimal* aDecimal)
848{
849	DecimalObject* result;
850
851	result = PyObject_New(DecimalObject, &Decimal_Type);
852	if (result == NULL) return NULL;
853
854	result->objc_value = nil;
855	result->value = *aDecimal;
856	return (PyObject*)result;
857}
858
859
860
861
862static PyMethodDef _methods[] = {
863	{ 0, 0, 0, 0 } /* sentinel */
864};
865
866static PyObject*
867pythonify_nsdecimal(void* value)
868{
869	return Decimal_New((NSDecimal*)value);
870}
871
872static int depythonify_nsdecimal(PyObject* value, void* out)
873{
874	return Decimal_Convert(value, out) == 1 ? 0 : -1;
875}
876
877static PyObject*
878call_NSDecimalNumber_decimalWithDecimal_(
879	PyObject* method, PyObject* self, PyObject* arguments)
880{
881	struct objc_super super;
882	NSDecimal* aDecimal;
883	id res;
884
885	if  (!PyArg_ParseTuple(arguments, "O&", Decimal_Convert, &aDecimal)) {
886		return NULL;
887	}
888
889	PyObjC_DURING
890		PyObjC_InitSuperCls(&super,
891			  PyObjCSelector_GetClass(method),
892			  PyObjCClass_GetClass(self));
893
894		res = objc_msgSendSuper(&super,
895				PyObjCSelector_GetSelector(method),
896				*aDecimal);
897	PyObjC_HANDLER
898		PyObjCErr_FromObjC(localException);
899		res = nil;
900	PyObjC_ENDHANDLER
901
902	if (res == nil && PyErr_Occurred()) {
903		return NULL;
904	}
905
906	return PyObjC_IdToPython(res);
907}
908
909static PyObject*
910call_NSDecimalNumber_initWithDecimal_(
911	PyObject* method, PyObject* self, PyObject* arguments)
912{
913	struct objc_super super;
914	NSDecimal* aDecimal;
915	id res;
916
917	if  (!PyArg_ParseTuple(arguments, "O&", Decimal_Convert, &aDecimal)) {
918		return NULL;
919	}
920
921	PyObjC_DURING
922		PyObjC_InitSuper(&super,
923			PyObjCSelector_GetClass(method),
924			PyObjCObject_GetObject(self));
925
926		res = objc_msgSendSuper(&super,
927				PyObjCSelector_GetSelector(method),
928				*aDecimal);
929	PyObjC_HANDLER
930		PyObjCErr_FromObjC(localException);
931		res = nil;
932	PyObjC_ENDHANDLER
933
934	if (res == nil && PyErr_Occurred()) {
935		return NULL;
936	}
937
938	return PyObjC_IdToPython(res);
939}
940
941static void
942imp_NSDecimalNumber_initWithDecimal_(
943	void* cif __attribute__((__unused__)),
944	void* resp,
945	void** args,
946	void* callable)
947{
948	id self = *(id*)args[0];
949	//SEL _meth = *(SEL*)args[1];
950	NSDecimal aDecimal = *(NSDecimal*)args[2];
951	id* pretval  = (id*)resp;
952
953	PyObject* result = NULL;
954	PyObject* arglist = NULL;
955	PyObject* v = NULL;
956	PyObject* pyself = NULL;
957	int cookie = 0;
958
959	PyGILState_STATE state = PyGILState_Ensure();
960
961	arglist = PyTuple_New(2);
962	if (arglist == NULL) goto error;
963
964	pyself = PyObjCObject_NewTransient(self, &cookie);
965	if (pyself == NULL) goto error;
966	PyTuple_SetItem(arglist, 0, pyself);
967	Py_INCREF(pyself);
968
969	v = Decimal_New(&aDecimal);
970	if (v == NULL) goto error;
971	PyTuple_SetItem(arglist, 1, v);
972
973	result = PyObject_Call((PyObject*)callable, arglist, NULL);
974	Py_DECREF(arglist); arglist = NULL;
975	PyObjCObject_ReleaseTransient(pyself, cookie); pyself = NULL;
976	if (result == NULL) goto error;
977
978	*pretval = PyObjC_PythonToId(result);
979	Py_DECREF(result);
980	PyGILState_Release(state);
981	return;
982
983error:
984	*pretval = nil;
985	Py_XDECREF(arglist);
986	if (pyself) {
987		PyObjCObject_ReleaseTransient(pyself, cookie);
988	}
989	PyObjCErr_ToObjCWithGILState(&state);
990}
991
992static PyObject*
993call_NSDecimalNumber_decimalValue(
994	PyObject* method, PyObject* self, PyObject* arguments)
995{
996	struct objc_super super;
997	NSDecimal aDecimal;
998	if  (!PyArg_ParseTuple(arguments, "")) {
999		return NULL;
1000	}
1001
1002	PyObjC_DURING
1003		PyObjC_InitSuper(&super,
1004			PyObjCSelector_GetClass(method),
1005			PyObjCObject_GetObject(self));
1006
1007#if defined(__i386__)
1008		/* The call below doesn't work on i386, I'm not sure why.
1009 	         * Because nobody will every subclass NSDecimalNumber this is not
1010		 * really a problem.
1011		 */
1012		aDecimal = [PyObjCObject_GetObject(self) decimalValue];
1013#else
1014		((void(*)(void*, struct objc_super*, SEL))objc_msgSendSuper_stret)(&aDecimal, &super,
1015				PyObjCSelector_GetSelector(method));
1016#endif
1017
1018	PyObjC_HANDLER
1019		PyObjCErr_FromObjC(localException);
1020	PyObjC_ENDHANDLER
1021
1022	if (PyErr_Occurred()) {
1023		return NULL;
1024	}
1025
1026	return Decimal_New(&aDecimal);
1027}
1028
1029static void
1030imp_NSDecimalNumber_decimalValue(
1031	void* cif __attribute__((__unused__)),
1032	void* resp,
1033	void** args,
1034	void* callable)
1035{
1036	id self = *(id*)args[0];
1037	//SEL _meth = *(SEL*)args[1];
1038	NSDecimal* pretval = (NSDecimal*)resp;
1039	NSDecimal* res;
1040
1041	PyObject* result = NULL;
1042	PyObject* arglist = NULL;
1043	PyObject* v = NULL;
1044	PyObject* pyself = NULL;
1045	int cookie = 0;
1046
1047	PyGILState_STATE state = PyGILState_Ensure();
1048
1049	arglist = PyTuple_New(1);
1050	if (arglist == NULL) goto error;
1051
1052	v = PyObjC_IdToPython(self);
1053	if (v == NULL) goto error;
1054	PyTuple_SetItem(arglist, 0,  v);
1055
1056	result = PyObject_Call((PyObject*)callable, arglist, NULL);
1057	Py_DECREF(arglist); arglist = NULL;
1058	PyObjCObject_ReleaseTransient(pyself, cookie); pyself = NULL;
1059	if (result == NULL) goto error;
1060
1061	Decimal_Convert(result, &res);
1062	*pretval = *res;
1063	Py_DECREF(result);
1064	PyGILState_Release(state);
1065	return;
1066
1067error:
1068	Py_XDECREF(arglist);
1069	if (pyself) {
1070		PyObjCObject_ReleaseTransient(pyself, cookie);
1071	}
1072	PyObjCErr_ToObjCWithGILState(&state);
1073}
1074
1075
1076PyDoc_STRVAR(_NSDecimal_doc, "_NSDecimal provides a wrapper for NSDecimal");
1077
1078void init_NSDecimal(void);
1079
1080void init_NSDecimal(void)
1081{
1082	PyObject* m;
1083	PyType_Ready(&Decimal_Type);
1084
1085	m = Py_InitModule4("_NSDecimal", _methods, _NSDecimal_doc,
1086			NULL, PYTHON_API_VERSION);
1087
1088
1089	if (m == NULL) {
1090		return;
1091	}
1092
1093	if (PyObjC_ImportAPI(m) < 0) {
1094		printf("Importing objc failed\n");
1095		return;
1096	}
1097
1098	PyModule_AddObject(m, "NSDecimal", (PyObject*)&Decimal_Type);
1099
1100	PyObjCPointerWrapper_Register(@encode(NSDecimal*),
1101			pythonify_nsdecimal,
1102			depythonify_nsdecimal);
1103
1104	PyObjCPointerWrapper_Register(@encode(const NSDecimal*),
1105			pythonify_nsdecimal,
1106			depythonify_nsdecimal);
1107
1108	/* Also register some variations of the encoded name because NSDecimal
1109         * doesn't have a struct tag and the metadata generators make up one
1110         * when creating the metadata.
1111         */
1112        if (@encode(NSDecimal)[1] == '?') {
1113		char buffer[1024];
1114
1115		buffer[0] = _C_CONST;
1116		buffer[1] = _C_PTR;
1117		buffer[2] = _C_STRUCT_B;
1118
1119	        snprintf(buffer+3, sizeof(buffer) - 3, "_NSDecimal");
1120	        snprintf(buffer+2+sizeof("_NSDecimal"),
1121				sizeof(buffer)-2-sizeof("_NSDecimal"),
1122				@encode(NSDecimal) + 2);
1123
1124		PyObjCPointerWrapper_Register(buffer+1,
1125				pythonify_nsdecimal,
1126				depythonify_nsdecimal);
1127
1128		PyObjCPointerWrapper_Register(buffer,
1129				pythonify_nsdecimal,
1130				depythonify_nsdecimal);
1131       	}
1132
1133
1134	Class classNSDecimalNumber = objc_lookUpClass("NSDecimalNumber");
1135	Class classNSNumber = objc_lookUpClass("NSNumber");
1136
1137	if (PyObjC_RegisterMethodMapping(
1138			classNSDecimalNumber,
1139			@selector(initWithDecimal:),
1140			call_NSDecimalNumber_initWithDecimal_,
1141			imp_NSDecimalNumber_initWithDecimal_) < 0) {
1142		return;
1143	}
1144
1145	Class classNSDecimalNumberPlaceholder = objc_lookUpClass("NSDecimalNumberPlaceholder");
1146	if (classNSDecimalNumberPlaceholder != nil) {
1147		if (PyObjC_RegisterMethodMapping(
1148			classNSDecimalNumberPlaceholder,
1149			@selector(initWithDecimal:),
1150			call_NSDecimalNumber_initWithDecimal_,
1151			imp_NSDecimalNumber_initWithDecimal_) < 0) {
1152
1153			return;
1154		}
1155	}
1156
1157	if (PyObjC_RegisterMethodMapping(
1158			classNSDecimalNumber,
1159			@selector(decimalNumberWithDecimal:),
1160			call_NSDecimalNumber_decimalWithDecimal_,
1161			imp_NSDecimalNumber_initWithDecimal_) < 0) {
1162		return;
1163	}
1164
1165	if (PyObjC_RegisterMethodMapping(
1166			classNSNumber,
1167			@selector(decimalValue),
1168			call_NSDecimalNumber_decimalValue,
1169			imp_NSDecimalNumber_decimalValue) < 0) {
1170		return;
1171	}
1172}
1173