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