1/*
2 * Manual wrapper for varadic functions for CFCalendar.
3 *
4 * These functions have a non-printf format string. Because all variadic
5 * arguments are integers and the number of arguments is trivially derived
6 * from the format string these implementations are fairly trivial.
7 */
8#include <Python.h>
9#include "pyobjc-api.h"
10
11#import <CoreFoundation/CoreFoundation.h>
12
13static PyObject*
14mod_CFCalendarAddComponents(
15	PyObject* self __attribute__((__unused__)),
16	PyObject* args)
17{
18	CFCalendarRef calendar;
19	CFAbsoluteTime at;
20	CFOptionFlags flags;
21	char* componentDesc;
22	int params[10];
23	Boolean result;
24	int r;
25
26	if (PyTuple_Size(args) < 4) {
27		PyErr_Format(PyExc_TypeError,
28			"Expecting at least 4 arguments, got %"
29			PY_FORMAT_SIZE_T "d", PyTuple_Size(args));
30		return NULL;
31	}
32
33	r = PyObjC_PythonToObjC(@encode(CFCalendarRef),
34		PyTuple_GET_ITEM(args, 0), &calendar);
35	if (r == -1) {
36		return NULL;
37	}
38
39	r = PyObjC_PythonToObjC(@encode(CFAbsoluteTime),
40		PyTuple_GET_ITEM(args, 1), &at);
41	if (r == -1) {
42		return NULL;
43	}
44
45	r = PyObjC_PythonToObjC(@encode(CFOptionFlags),
46		PyTuple_GET_ITEM(args, 2), &flags);
47	if (r == -1) {
48		return NULL;
49	}
50
51	r = PyObjC_PythonToObjC(@encode(char*),
52		PyTuple_GET_ITEM(args, 3), &componentDesc);
53	if (r == -1) {
54		return NULL;
55	}
56
57	if (PyTuple_Size(args) != 4 + strlen(componentDesc)) {
58		PyErr_Format(PyExc_TypeError,
59			"Expecting %" PY_FORMAT_SIZE_T "d arguments, got %"
60			PY_FORMAT_SIZE_T "d", 4 + strlen(componentDesc),
61			PyTuple_Size(args));
62		return NULL;
63	}
64	if (PyTuple_Size(args) > 4 + 10) {
65		PyErr_SetString(PyExc_TypeError,
66			"At most 10 characters supported in componentDesc");
67		return NULL;
68	}
69
70	Py_ssize_t i, len;
71
72	len = strlen(componentDesc);
73	for (i = 0; i < len; i++) {
74		r = PyObjC_PythonToObjC(@encode(int),
75			PyTuple_GET_ITEM(args, 4 + i), params + i);
76		if (r == -1) {
77			return NULL;
78		}
79	}
80
81	result = FALSE;
82	PyObjC_DURING
83		result = CFCalendarAddComponents(
84			calendar, &at, flags, componentDesc,
85			params[0], params[1], params[2], params[3],
86			params[4], params[5], params[6], params[7],
87			params[8], params[9]);
88
89	PyObjC_HANDLER
90		PyObjCErr_FromObjC(localException);
91
92	PyObjC_ENDHANDLER
93
94	if (PyErr_Occurred()) {
95		return NULL;
96	}
97
98	PyObject* b = PyBool_FromLong(result);
99	if (b  == NULL) {
100		return NULL;
101	}
102	PyObject* a = PyObjC_ObjCToPython(@encode(CFAbsoluteTime), &at);
103	if (a == NULL) {
104		Py_DECREF(b);
105		return NULL;
106	}
107
108	return Py_BuildValue("NN", b, a);
109}
110
111
112static PyObject*
113mod_CFCalendarComposeAbsoluteTime(
114	PyObject* self __attribute__((__unused__)),
115	PyObject* args)
116{
117	CFCalendarRef calendar;
118	CFAbsoluteTime at;
119	char* componentDesc;
120	int params[10];
121	Boolean result;
122	int r;
123
124	if (PyTuple_Size(args) < 3) {
125		PyErr_Format(PyExc_TypeError,
126			"Expecting at least 3 arguments, got %"
127			PY_FORMAT_SIZE_T "d", PyTuple_Size(args));
128		return NULL;
129	}
130
131	r = PyObjC_PythonToObjC(@encode(CFCalendarRef),
132		PyTuple_GET_ITEM(args, 0), &calendar);
133	if (r == -1) {
134		return NULL;
135	}
136
137	if (PyTuple_GET_ITEM(args, 1) != Py_None) {
138		PyErr_SetString(PyExc_TypeError, "placeholder for 'at' must be None");
139		return NULL;
140	}
141
142	r = PyObjC_PythonToObjC(@encode(char*),
143		PyTuple_GET_ITEM(args, 2), &componentDesc);
144	if (r == -1) {
145		return NULL;
146	}
147
148	if (PyTuple_Size(args) != 3 + strlen(componentDesc)) {
149		PyErr_Format(PyExc_TypeError,
150			"Expecting %" PY_FORMAT_SIZE_T "d arguments, got %"
151			PY_FORMAT_SIZE_T "d", 3 + strlen(componentDesc),
152			PyTuple_Size(args));
153		return NULL;
154	}
155	if (PyTuple_Size(args) > 3 + 10) {
156		PyErr_SetString(PyExc_TypeError,
157			"At most 10 characters supported in componentDesc");
158		return NULL;
159	}
160
161	Py_ssize_t i, len;
162
163	len = strlen(componentDesc);
164	for (i = 0; i < len; i++) {
165		r = PyObjC_PythonToObjC(@encode(int),
166			PyTuple_GET_ITEM(args, 3 + i), params + i);
167		if (r == -1) {
168			return NULL;
169		}
170	}
171
172	result = FALSE;
173	PyObjC_DURING
174		result = CFCalendarComposeAbsoluteTime(
175			calendar, &at, componentDesc,
176			params[0], params[1], params[2], params[3],
177			params[4], params[5], params[6], params[7],
178			params[8], params[9]);
179
180	PyObjC_HANDLER
181		PyObjCErr_FromObjC(localException);
182
183	PyObjC_ENDHANDLER
184
185	if (PyErr_Occurred()) {
186		return NULL;
187	}
188
189	PyObject* b = PyBool_FromLong(result);
190	if (b  == NULL) {
191		return NULL;
192	}
193	PyObject* a = PyObjC_ObjCToPython(@encode(CFAbsoluteTime), &at);
194	if (a == NULL) {
195		Py_DECREF(b);
196		return NULL;
197	}
198
199	return Py_BuildValue("NN", b, a);
200}
201
202static PyObject*
203mod_CFCalendarDecomposeAbsoluteTime(
204	PyObject* self __attribute__((__unused__)),
205	PyObject* args)
206{
207	CFCalendarRef calendar;
208	CFAbsoluteTime at;
209	char* componentDesc;
210	int params[10];
211	Boolean result;
212	int r;
213
214	if (PyTuple_Size(args) < 3) {
215		PyErr_Format(PyExc_TypeError,
216			"Expecting at least 3 arguments, got %"
217			PY_FORMAT_SIZE_T "d", PyTuple_Size(args));
218		return NULL;
219	}
220
221	r = PyObjC_PythonToObjC(@encode(CFCalendarRef),
222		PyTuple_GET_ITEM(args, 0), &calendar);
223	if (r == -1) {
224		return NULL;
225	}
226
227	r = PyObjC_PythonToObjC(@encode(CFAbsoluteTime),
228		PyTuple_GET_ITEM(args, 1), &at);
229	if (r == -1) {
230		return NULL;
231	}
232
233	r = PyObjC_PythonToObjC(@encode(char*),
234		PyTuple_GET_ITEM(args, 2), &componentDesc);
235	if (r == -1) {
236		return NULL;
237	}
238
239	if (strlen(componentDesc) > 10) {
240		PyErr_SetString(PyExc_TypeError,
241			"At most 10 characters supported in componentDesc");
242		return NULL;
243	}
244
245	if (PyTuple_Size(args) != 3) {
246		if (PyTuple_Size(args) != 3 + strlen(componentDesc)) {
247			PyErr_Format(PyExc_TypeError,
248				"Expecting %" PY_FORMAT_SIZE_T "d arguments, got %"
249				PY_FORMAT_SIZE_T "d", 3 + strlen(componentDesc),
250				PyTuple_Size(args));
251			return NULL;
252		}
253
254		Py_ssize_t i, len;
255
256		len = strlen(componentDesc);
257		for (i = 0; i < len; i++) {
258			if (PyTuple_GET_ITEM(args, 3 + i) != Py_None) {
259				PyErr_SetString(PyExc_ValueError,
260					"Bad placeholder value");
261				return NULL;
262			}
263		}
264	}
265
266	result = FALSE;
267	PyObjC_DURING
268		result = CFCalendarDecomposeAbsoluteTime(
269			calendar, at, componentDesc,
270			&params[0], &params[1], &params[2], &params[3],
271			&params[4], &params[5], &params[6], &params[7],
272			&params[8], &params[9]);
273
274	PyObjC_HANDLER
275		PyObjCErr_FromObjC(localException);
276
277	PyObjC_ENDHANDLER
278
279	if (PyErr_Occurred()) {
280		return NULL;
281	}
282
283	PyObject *rv = PyTuple_New(1 + strlen(componentDesc));
284	if (rv == NULL) {
285		return NULL;
286	}
287
288	PyObject* b = PyBool_FromLong(result);
289	if (b  == NULL) {
290		return NULL;
291	}
292	PyTuple_SET_ITEM(rv, 0, b);
293
294	Py_ssize_t i, len;
295	len = strlen(componentDesc);
296	for (i = 0; i < len; i++) {
297		PyObject* v = PyInt_FromLong(params[i]);
298		if (v == NULL) {
299			Py_DECREF(rv);
300			return NULL;
301		}
302		PyTuple_SET_ITEM(rv, i+1, v);
303	}
304	return rv;
305}
306
307
308static PyObject*
309mod_CFCalendarGetComponentDifference(
310	PyObject* self __attribute__((__unused__)),
311	PyObject* args)
312{
313	CFCalendarRef calendar;
314	CFAbsoluteTime startingAt;
315	CFAbsoluteTime resultAt;
316	CFOptionFlags options;
317	char* componentDesc;
318	int params[10];
319	Boolean result;
320	int r;
321
322	if (PyTuple_Size(args) < 5) {
323		PyErr_Format(PyExc_TypeError,
324			"Expecting at least 5 arguments, got %"
325			PY_FORMAT_SIZE_T "d", PyTuple_Size(args));
326		return NULL;
327	}
328
329	r = PyObjC_PythonToObjC(@encode(CFCalendarRef),
330		PyTuple_GET_ITEM(args, 0), &calendar);
331	if (r == -1) {
332		return NULL;
333	}
334
335	r = PyObjC_PythonToObjC(@encode(CFAbsoluteTime),
336		PyTuple_GET_ITEM(args, 1), &startingAt);
337	if (r == -1) {
338		return NULL;
339	}
340
341	r = PyObjC_PythonToObjC(@encode(CFAbsoluteTime),
342		PyTuple_GET_ITEM(args, 2), &resultAt);
343	if (r == -1) {
344		return NULL;
345	}
346
347	r = PyObjC_PythonToObjC(@encode(CFOptionFlags),
348		PyTuple_GET_ITEM(args, 3), &options);
349	if (r == -1) {
350		return NULL;
351	}
352
353	r = PyObjC_PythonToObjC(@encode(char*),
354		PyTuple_GET_ITEM(args, 4), &componentDesc);
355	if (r == -1) {
356		return NULL;
357	}
358
359	if (strlen(componentDesc) > 10) {
360		PyErr_SetString(PyExc_TypeError,
361			"At most 10 characters supported in componentDesc");
362		return NULL;
363	}
364
365	if (PyTuple_Size(args) != 5) {
366		if (PyTuple_Size(args) != 5 + strlen(componentDesc)) {
367			PyErr_Format(PyExc_TypeError,
368				"Expecting %" PY_FORMAT_SIZE_T "d arguments, got %"
369				PY_FORMAT_SIZE_T "d", 3 + strlen(componentDesc),
370				PyTuple_Size(args));
371			return NULL;
372		}
373
374		Py_ssize_t i, len;
375
376		len = strlen(componentDesc);
377		for (i = 0; i < len; i++) {
378			if (PyTuple_GET_ITEM(args, 5 + i) != Py_None) {
379				PyErr_SetString(PyExc_ValueError,
380					"Bad placeholder value");
381				return NULL;
382			}
383		}
384	}
385
386	result = FALSE;
387	PyObjC_DURING
388		result = CFCalendarGetComponentDifference(
389			calendar, startingAt, resultAt, options,
390			componentDesc,
391			&params[0], &params[1], &params[2], &params[3],
392			&params[4], &params[5], &params[6], &params[7],
393			&params[8], &params[9]);
394
395	PyObjC_HANDLER
396		PyObjCErr_FromObjC(localException);
397
398	PyObjC_ENDHANDLER
399
400	if (PyErr_Occurred()) {
401		return NULL;
402	}
403
404	PyObject *rv = PyTuple_New(1 + strlen(componentDesc));
405	if (rv == NULL) {
406		return NULL;
407	}
408
409	PyObject* b = PyBool_FromLong(result);
410	if (b  == NULL) {
411		return NULL;
412	}
413	PyTuple_SET_ITEM(rv, 0, b);
414
415	Py_ssize_t i, len;
416	len = strlen(componentDesc);
417	for (i = 0; i < len; i++) {
418		PyObject* v = PyInt_FromLong(params[i]);
419		if (v == NULL) {
420			Py_DECREF(rv);
421			return NULL;
422		}
423		PyTuple_SET_ITEM(rv, i+1, v);
424	}
425	return rv;
426}
427
428static PyMethodDef mod_methods[] = {
429        {
430		"CFCalendarAddComponents",
431		(PyCFunction)mod_CFCalendarAddComponents,
432		METH_VARARGS,
433		NULL
434	},
435        {
436		"CFCalendarComposeAbsoluteTime",
437		(PyCFunction)mod_CFCalendarComposeAbsoluteTime,
438		METH_VARARGS,
439		NULL
440	},
441        {
442		"CFCalendarDecomposeAbsoluteTime",
443		(PyCFunction)mod_CFCalendarDecomposeAbsoluteTime,
444		METH_VARARGS,
445		NULL
446	},
447        {
448		"CFCalendarGetComponentDifference",
449		(PyCFunction)mod_CFCalendarGetComponentDifference,
450		METH_VARARGS,
451		NULL
452	},
453	{ 0, 0, 0, 0 } /* sentinel */
454};
455
456void init_CFCalendar(void);
457void init_CFCalendar(void)
458{
459	PyObject* m = Py_InitModule4("_CFCalendar", mod_methods, "", NULL,
460	PYTHON_API_VERSION);
461
462	PyObjC_ImportAPI(m);
463}
464