1 /*
2 Author: Michael Droettboom
3 mdroe@stsci.edu
4 */
5
6 #define NO_IMPORT_ARRAY
7
8 /* util.h must be imported first */
9 #include "astropy_wcs/pyutil.h"
10
11 #include "astropy_wcs/docstrings.h"
12
13 #include "wcsfix.h"
14 #include "wcshdr.h"
15 #include "wcsprintf.h"
16 #include "wcsunits.h"
17
18 /*@null@*/ static INLINE PyObject*
_PyArrayProxy_New(PyObject * self,int nd,const npy_intp * dims,int typenum,const void * data,const int flags)19 _PyArrayProxy_New(
20 /*@shared@*/ PyObject* self,
21 int nd,
22 const npy_intp* dims,
23 int typenum,
24 const void* data,
25 const int flags) {
26
27 PyArray_Descr* type_descr = NULL;
28 PyObject* result = NULL;
29
30 type_descr = (PyArray_Descr*)PyArray_DescrFromType(typenum);
31 if (type_descr == NULL) {
32 return NULL;
33 }
34
35 result = (PyObject*)PyArray_NewFromDescr(
36 &PyArray_Type,
37 type_descr,
38 nd, (npy_intp*)dims,
39 NULL,
40 (void*)data,
41 NPY_ARRAY_C_CONTIGUOUS | flags,
42 NULL);
43
44 if (result == NULL) {
45 return NULL;
46 }
47 Py_INCREF(self);
48 PyArray_SetBaseObject((PyArrayObject *)result, self);
49 return result;
50 }
51
52 /*@null@*/ PyObject*
PyArrayProxy_New(PyObject * self,int nd,const npy_intp * dims,int typenum,const void * data)53 PyArrayProxy_New(
54 /*@shared@*/ PyObject* self,
55 int nd,
56 const npy_intp* dims,
57 int typenum,
58 const void* data) {
59
60 return _PyArrayProxy_New(self, nd, dims, typenum, data, NPY_ARRAY_WRITEABLE);
61 }
62
63 /*@null@*/ PyObject*
PyArrayReadOnlyProxy_New(PyObject * self,int nd,const npy_intp * dims,int typenum,const void * data)64 PyArrayReadOnlyProxy_New(
65 /*@shared@*/ PyObject* self,
66 int nd,
67 const npy_intp* dims,
68 int typenum,
69 const void* data) {
70
71 return _PyArrayProxy_New(self, nd, dims, typenum, data, 0);
72 }
73
74 void
preoffset_array(PyArrayObject * array,int value)75 preoffset_array(
76 PyArrayObject* array,
77 int value) {
78
79 npy_intp size;
80 double *data;
81
82 if (value == 1) {
83 return;
84 }
85
86 size = PyArray_Size((PyObject*)array);
87 data = (double*)PyArray_DATA(array);
88 offset_c_array(data, size, (double)(1 - value));
89 }
90
91 void
unoffset_array(PyArrayObject * array,int value)92 unoffset_array(
93 PyArrayObject* array,
94 int value) {
95
96 npy_intp size;
97 double *data;
98
99 if (value == 1) {
100 return;
101 }
102
103 size = PyArray_Size((PyObject*)array);
104 data = (double*)PyArray_DATA(array);
105 offset_c_array(data, size, (double)-(1 - value));
106 }
107
108 void
copy_array_to_c_double(PyArrayObject * array,double * dest)109 copy_array_to_c_double(
110 PyArrayObject* array,
111 double* dest) {
112
113 npy_intp size = 1;
114 double* data = NULL;
115
116 size = PyArray_Size((PyObject*)array);
117 data = (double*)PyArray_DATA(array);
118
119 memcpy(dest, data, size * sizeof(double));
120 }
121
122 void
copy_array_to_c_int(PyArrayObject * array,int * dest)123 copy_array_to_c_int(
124 PyArrayObject* array,
125 int* dest) {
126
127 npy_intp size = 1;
128 int* data = NULL;
129
130 size = PyArray_Size((PyObject*)array);
131 data = (int*)PyArray_DATA(array);
132
133 memcpy(dest, data, size * sizeof(int));
134 }
135
136 int
is_null(void * p)137 is_null(
138 /*@null@*/ void *p) {
139
140 if (p == NULL) {
141 PyErr_SetString(PyExc_AssertionError, "Underlying object is NULL.");
142 return 1;
143 }
144 return 0;
145 }
146
147 /* wcslib represents undefined values using its own special constant,
148 UNDEFINED. To be consistent with the Pythonic way of doing things,
149 it's nicer to represent undefined values using NaN. Unfortunately,
150 in order to get nice mutable arrays in Python, Python must be able
151 to edit the wcsprm values directly. The solution is to store NaNs
152 in the struct "canonically", but convert those NaNs to/from
153 UNDEFINED around every call into a wcslib function. It's not as
154 computationally expensive as it sounds, as all these arrays are
155 quite small.
156 */
157
158 static INLINE void
wcsprm_fix_values(struct wcsprm * x,value_fixer_t value_fixer)159 wcsprm_fix_values(
160 struct wcsprm* x,
161 value_fixer_t value_fixer) {
162
163 unsigned int naxis = (unsigned int)x->naxis;
164
165 value_fixer(x->cd, naxis * naxis);
166 value_fixer(x->cdelt, naxis);
167 value_fixer(x->crder, naxis);
168 value_fixer(x->crota, naxis);
169 value_fixer(x->crpix, naxis);
170 value_fixer(x->crval, naxis);
171 value_fixer(x->csyer, naxis);
172 value_fixer(&x->equinox, 1);
173 value_fixer(&x->latpole, 1);
174 value_fixer(&x->lonpole, 1);
175 value_fixer(&x->mjdavg, 1);
176 value_fixer(&x->mjdobs, 1);
177 value_fixer(x->obsgeo, 6);
178 value_fixer(&x->cel.phi0, 1);
179 value_fixer(&x->restfrq, 1);
180 value_fixer(&x->restwav, 1);
181 value_fixer(&x->cel.theta0, 1);
182 value_fixer(&x->velangl, 1);
183 value_fixer(&x->velosys, 1);
184 value_fixer(&x->zsource, 1);
185 value_fixer(x->czphs, naxis);
186 value_fixer(x->cperi, naxis);
187 value_fixer(x->mjdref, 2);
188 value_fixer(&x->mjdbeg, 1);
189 value_fixer(&x->mjdend, 1);
190 value_fixer(&x->jepoch, 1);
191 value_fixer(&x->bepoch, 1);
192 value_fixer(&x->tstart, 1);
193 value_fixer(&x->tstop, 1);
194 value_fixer(&x->xposure, 1);
195 value_fixer(&x->timsyer, 1);
196 value_fixer(&x->timrder, 1);
197 value_fixer(&x->timedel, 1);
198 value_fixer(&x->timepixr, 1);
199 value_fixer(&x->timeoffs, 1);
200 value_fixer(&x->telapse, 1);
201 }
202
203 void
wcsprm_c2python(struct wcsprm * x)204 wcsprm_c2python(
205 /*@null@*/ struct wcsprm* x) {
206
207 if (x != NULL) {
208 wcsprm_fix_values(x, &undefined2nan);
209 }
210 }
211
212 void
wcsprm_python2c(struct wcsprm * x)213 wcsprm_python2c(
214 /*@null@*/ struct wcsprm* x) {
215
216 if (x != NULL) {
217 wcsprm_fix_values(x, &nan2undefined);
218 }
219 }
220
221 /***************************************************************************
222 * Exceptions *
223 ***************************************************************************/
224
225 PyObject* WcsExc_Wcs;
226 PyObject* WcsExc_SingularMatrix;
227 PyObject* WcsExc_InconsistentAxisTypes;
228 PyObject* WcsExc_InvalidTransform;
229 PyObject* WcsExc_InvalidCoordinate;
230 PyObject* WcsExc_NoSolution;
231 PyObject* WcsExc_InvalidSubimageSpecification;
232 PyObject* WcsExc_NonseparableSubimageCoordinateSystem;
233 PyObject* WcsExc_NoWcsKeywordsFound;
234 PyObject* WcsExc_InvalidTabularParameters;
235
236 /* This is an array mapping the wcs status codes to Python exception
237 * types. The exception string is stored as part of wcslib itself in
238 * wcs_errmsg.
239 */
240 PyObject** wcs_errexc[14];
241
242 static PyObject*
_new_exception_with_doc(char * name,char * doc,PyObject * base)243 _new_exception_with_doc(char *name, char *doc, PyObject *base)
244 {
245 return PyErr_NewExceptionWithDoc(name, doc, base, NULL);
246 }
247
248 #define DEFINE_EXCEPTION(exc) \
249 WcsExc_##exc = _new_exception_with_doc( \
250 "astropy.wcs._wcs." #exc "Error", \
251 doc_##exc, \
252 WcsExc_Wcs); \
253 if (WcsExc_##exc == NULL) \
254 return 1; \
255 PyModule_AddObject(m, #exc "Error", WcsExc_##exc); \
256
257 int
_define_exceptions(PyObject * m)258 _define_exceptions(
259 PyObject* m) {
260
261 WcsExc_Wcs = _new_exception_with_doc(
262 "astropy.wcs._wcs.WcsError",
263 doc_WcsError,
264 PyExc_ValueError);
265 if (WcsExc_Wcs == NULL) {
266 return 1;
267 }
268 PyModule_AddObject(m, "WcsError", WcsExc_Wcs);
269
270 DEFINE_EXCEPTION(SingularMatrix);
271 DEFINE_EXCEPTION(InconsistentAxisTypes);
272 DEFINE_EXCEPTION(InvalidTransform);
273 DEFINE_EXCEPTION(InvalidCoordinate);
274 DEFINE_EXCEPTION(NoSolution);
275 DEFINE_EXCEPTION(InvalidSubimageSpecification);
276 DEFINE_EXCEPTION(NonseparableSubimageCoordinateSystem);
277 DEFINE_EXCEPTION(NoWcsKeywordsFound);
278 DEFINE_EXCEPTION(InvalidTabularParameters);
279 return 0;
280 }
281
282 const char*
wcslib_get_error_message(int status)283 wcslib_get_error_message(int status) {
284 return wcs_errmsg[status];
285 }
286
287 void
wcserr_to_python_exc(const struct wcserr * err)288 wcserr_to_python_exc(const struct wcserr *err) {
289 PyObject *exc;
290 if (err == NULL) {
291 PyErr_SetString(PyExc_RuntimeError, "NULL error object in wcslib");
292 } else {
293 if (err->status > 0 && err->status <= WCS_ERRMSG_MAX) {
294 exc = *wcs_errexc[err->status];
295 } else {
296 exc = PyExc_RuntimeError;
297 }
298 /* This is technically not thread-safe -- make sure we have the GIL */
299 wcsprintf_set(NULL);
300 wcserr_prt(err, "");
301 PyErr_SetString(exc, wcsprintf_buf());
302 }
303 }
304
305 void
wcs_to_python_exc(const struct wcsprm * wcs)306 wcs_to_python_exc(const struct wcsprm *wcs) {
307 PyObject* exc;
308 const struct wcserr *err = wcs->err;
309 if (err == NULL) {
310 PyErr_SetString(PyExc_RuntimeError, "NULL error object in wcslib");
311 } else {
312 if (err->status > 0 && err->status < WCS_ERRMSG_MAX) {
313 exc = *wcs_errexc[err->status];
314 } else {
315 exc = PyExc_RuntimeError;
316 }
317 /* This is technically not thread-safe -- make sure we have the GIL */
318 wcsprintf_set(NULL);
319 wcsperr(wcs, "");
320 PyErr_SetString(exc, wcsprintf_buf());
321 }
322 }
323
324 void
wcserr_fix_to_python_exc(const struct wcserr * err)325 wcserr_fix_to_python_exc(const struct wcserr *err) {
326 PyObject *exc;
327 if (err == NULL) {
328 PyErr_SetString(PyExc_RuntimeError, "NULL error object in wcslib");
329 } else {
330 if (err->status > 0 && err->status <= FIXERR_NO_REF_PIX_VAL) {
331 exc = PyExc_ValueError;
332 } else {
333 exc = PyExc_RuntimeError;
334 }
335 /* This is technically not thread-safe -- make sure we have the GIL */
336 wcsprintf_set(NULL);
337 wcserr_prt(err, "");
338 PyErr_SetString(exc, wcsprintf_buf());
339 }
340 }
341
342 void
wcshdr_err_to_python_exc(int status,const struct wcsprm * wcs)343 wcshdr_err_to_python_exc(int status, const struct wcsprm *wcs) {
344 /* Add error to wcslib error buffer */
345 wcsperr(wcs, NULL);
346 if (status > 0 && status != WCSHDRERR_PARSER) {
347 PyErr_Format(
348 PyExc_MemoryError,
349 "Memory allocation error:\n%s",
350 wcsprintf_buf()
351 );
352 } else {
353 PyErr_Format(
354 PyExc_ValueError,
355 "Internal error in wcslib header parser:\n %s",
356 wcsprintf_buf()
357 );
358 }
359 }
360
361
362 /***************************************************************************
363 Property helpers
364 ***************************************************************************/
365
366 #define SHAPE_STR_LEN 2048
367
368 /* Helper function to display the desired shape of an array as a
369 string, eg. 2x2 */
370 static void
shape_to_string(int ndims,const npy_intp * dims,char * str)371 shape_to_string(
372 int ndims,
373 const npy_intp* dims,
374 char* str /* [SHAPE_STR_LEN] */) {
375
376 int i;
377 char value[32]; /* More than large enough to hold string rep of a
378 64-bit integer (way overkill) */
379
380 if (ndims > 3) {
381 strncpy(str, "ERROR", 6);
382 return;
383 }
384
385 str[0] = 0;
386 for (i = 0; i < ndims; ++i) {
387 snprintf(value, 32, "%d", (int)dims[i]);
388 strncat(str, value, 32);
389 if (i != ndims - 1) {
390 strncat(str, "x", 2);
391 }
392 }
393 }
394
395 /* get_string is inlined */
396
397 int
set_string(const char * propname,PyObject * value,char * dest,Py_ssize_t maxlen)398 set_string(
399 const char* propname,
400 PyObject* value,
401 char* dest,
402 Py_ssize_t maxlen) {
403
404 char* buffer;
405 Py_ssize_t len;
406 PyObject* ascii_obj = NULL;
407 int result = -1;
408
409 if (check_delete(propname, value)) {
410 return -1;
411 }
412
413 if (PyUnicode_Check(value)) {
414 ascii_obj = PyUnicode_AsASCIIString(value);
415 if (ascii_obj == NULL) {
416 goto end;
417 }
418 if (PyBytes_AsStringAndSize(ascii_obj, &buffer, &len) == -1) {
419 goto end;
420 }
421 } else if (PyBytes_Check(value)) {
422 if (PyBytes_AsStringAndSize(value, &buffer, &len) == -1) {
423 goto end;
424 }
425 } else {
426 PyErr_SetString(PyExc_TypeError, "value must be bytes or unicode");
427 goto end;
428 }
429
430 if (len > maxlen) {
431 PyErr_Format(
432 PyExc_ValueError,
433 "'%s' must be less than %u characters",
434 propname,
435 (unsigned int)maxlen);
436 goto end;
437 }
438
439 strncpy(dest, buffer, (size_t)maxlen);
440
441 result = 0;
442
443 end:
444 Py_XDECREF(ascii_obj);
445
446 return result;
447 }
448
449 /* get_bool is inlined */
450
451 int
set_bool(const char * propname,PyObject * value,int * dest)452 set_bool(
453 const char* propname,
454 PyObject* value,
455 int* dest) {
456
457 if (check_delete(propname, value)) {
458 return -1;
459 }
460
461 *dest = PyObject_IsTrue(value);
462
463 return 0;
464 }
465
466 /* get_int is inlined */
467
468 int
set_int(const char * propname,PyObject * value,int * dest)469 set_int(
470 const char* propname,
471 PyObject* value,
472 int* dest) {
473 long value_int;
474
475 if (check_delete(propname, value)) {
476 return -1;
477 }
478
479 value_int = PyLong_AsLong(value);
480 if (value_int == -1 && PyErr_Occurred()) {
481 return -1;
482 }
483
484 if ((unsigned long)value_int > 0x7fffffff) {
485 PyErr_SetString(PyExc_OverflowError, "integer value too large");
486 return -1;
487 }
488
489 *dest = (int)value_int;
490
491 return 0;
492 }
493
494 /* get_double is inlined */
495
496 int
set_double(const char * propname,PyObject * value,double * dest)497 set_double(
498 const char* propname,
499 PyObject* value,
500 double* dest) {
501
502 if (check_delete(propname, value)) {
503 return -1;
504 }
505
506 *dest = PyFloat_AsDouble(value);
507
508 if (PyErr_Occurred()) {
509 return -1;
510 } else {
511 return 0;
512 }
513 }
514
515 /* get_double_array is inlined */
516
517 int
set_double_array(const char * propname,PyObject * value,int ndims,const npy_intp * dims,double * dest)518 set_double_array(
519 const char* propname,
520 PyObject* value,
521 int ndims,
522 const npy_intp* dims,
523 double* dest) {
524
525 PyArrayObject* value_array = NULL;
526 npy_int i = 0;
527 char shape_str[SHAPE_STR_LEN];
528
529 if (check_delete(propname, value)) {
530 return -1;
531 }
532
533 value_array = (PyArrayObject*)PyArray_ContiguousFromAny(value, NPY_DOUBLE,
534 ndims, ndims);
535 if (value_array == NULL) {
536 return -1;
537 }
538
539 if (dims != NULL) {
540 for (i = 0; i < ndims; ++i) {
541 if (PyArray_DIM(value_array, i) != dims[i]) {
542 shape_to_string(ndims, dims, shape_str);
543 PyErr_Format(
544 PyExc_ValueError,
545 "'%s' array is the wrong shape, must be %s",
546 propname, shape_str);
547 Py_DECREF(value_array);
548 return -1;
549 }
550 }
551 }
552
553 copy_array_to_c_double(value_array, dest);
554
555 Py_DECREF(value_array);
556
557 return 0;
558 }
559
560 int
set_int_array(const char * propname,PyObject * value,int ndims,const npy_intp * dims,int * dest)561 set_int_array(
562 const char* propname,
563 PyObject* value,
564 int ndims,
565 const npy_intp* dims,
566 int* dest) {
567 PyArrayObject* value_array = NULL;
568 npy_int i = 0;
569 char shape_str[SHAPE_STR_LEN];
570
571 if (check_delete(propname, value)) {
572 return -1;
573 }
574
575 value_array = (PyArrayObject*)PyArray_ContiguousFromAny(value, NPY_INT,
576 ndims, ndims);
577 if (value_array == NULL) {
578 return -1;
579 }
580
581 if (dims != NULL) {
582 for (i = 0; i < ndims; ++i) {
583 if (PyArray_DIM(value_array, i) != dims[i]) {
584 shape_to_string(ndims, dims, shape_str);
585 PyErr_Format(
586 PyExc_ValueError,
587 "'%s' array is the wrong shape, must be %s",
588 propname, shape_str);
589 Py_DECREF(value_array);
590 return -1;
591 }
592 }
593 }
594
595 copy_array_to_c_int(value_array, dest);
596
597 Py_DECREF(value_array);
598
599 return 0;
600 }
601
602 /* get_str_list is inlined */
603
604 int
set_str_list(const char * propname,PyObject * value,Py_ssize_t len,Py_ssize_t maxlen,char (* dest)[72])605 set_str_list(
606 const char* propname,
607 PyObject* value,
608 Py_ssize_t len,
609 Py_ssize_t maxlen,
610 char (*dest)[72]) {
611
612 PyObject* str = NULL;
613 Py_ssize_t input_len;
614 Py_ssize_t i = 0;
615
616 if (check_delete(propname, value)) {
617 return -1;
618 }
619
620 if (maxlen == 0) {
621 maxlen = 68;
622 }
623
624 if (!PySequence_Check(value)) {
625 PyErr_Format(
626 PyExc_TypeError,
627 "'%s' must be a sequence of strings",
628 propname);
629 return -1;
630 }
631
632 if (PySequence_Size(value) != len) {
633 PyErr_Format(
634 PyExc_ValueError,
635 "len(%s) must be %u",
636 propname,
637 (unsigned int)len);
638 return -1;
639 }
640
641 /* We go through the list twice, once to verify that the list is
642 in the correct format, and then again to do the data copy. This
643 way, we won't partially copy the contents and then throw an
644 exception. */
645 for (i = 0; i < len; ++i) {
646 str = PySequence_GetItem(value, i);
647 if (str == NULL) {
648 return -1;
649 }
650
651 if (!(PyBytes_CheckExact(str) || PyUnicode_CheckExact(str))) {
652 PyErr_Format(
653 PyExc_TypeError,
654 "'%s' must be a sequence of bytes or strings",
655 propname);
656 Py_DECREF(str);
657 return -1;
658 }
659
660 input_len = PySequence_Size(str);
661 if (input_len > maxlen) {
662 PyErr_Format(
663 PyExc_ValueError,
664 "Each entry in '%s' must be less than %u characters",
665 propname, (unsigned int)maxlen);
666 Py_DECREF(str);
667 return -1;
668 } else if (input_len == -1) {
669 Py_DECREF(str);
670 return -1;
671 }
672
673 Py_DECREF(str);
674 }
675
676 for (i = 0; i < len; ++i) {
677 str = PySequence_GetItem(value, i);
678 if (str == NULL) {
679 /* Theoretically, something has gone really wrong here, since
680 we've already verified the list. */
681 PyErr_Clear();
682 PyErr_Format(
683 PyExc_RuntimeError,
684 "Input values have changed underneath us. Something is seriously wrong.");
685 return -1;
686 }
687
688 if (set_string(propname, str, dest[i], maxlen)) {
689 PyErr_Clear();
690 PyErr_Format(
691 PyExc_RuntimeError,
692 "Input values have changed underneath us. Something is seriously wrong.");
693 Py_DECREF(str);
694 return -1;
695 }
696
697 Py_DECREF(str);
698 }
699
700 return 0;
701 }
702
703
704 /*@null@*/ PyObject*
get_pscards(const char * propname,struct pscard * ps,int nps)705 get_pscards(
706 /*@unused@*/ const char* propname,
707 struct pscard* ps,
708 int nps) {
709
710 PyObject* result = NULL;
711 PyObject* subresult = NULL;
712 Py_ssize_t i = 0;
713
714 if (nps < 0) {
715 nps = 0;
716 }
717
718 result = PyList_New((Py_ssize_t)nps);
719 if (result == NULL) {
720 return NULL;
721 }
722
723 if (nps && ps == NULL) {
724 PyErr_SetString(PyExc_MemoryError, "NULL pointer");
725 return NULL;
726 }
727
728 for (i = 0; i < (Py_ssize_t)nps; ++i) {
729 subresult = Py_BuildValue("iis", ps[i].i, ps[i].m, ps[i].value);
730 if (subresult == NULL) {
731 Py_DECREF(result);
732 return NULL;
733 }
734
735 if (PyList_SetItem(result, i, subresult)) {
736 Py_DECREF(subresult);
737 Py_DECREF(result);
738 return NULL;
739 }
740 }
741
742 return result;
743 }
744
745 int
set_pscards(const char * propname,PyObject * value,struct pscard ** ps,int * nps,int * npsmax)746 set_pscards(
747 /*@unused@*/ const char* propname,
748 PyObject* value,
749 struct pscard** ps,
750 int *nps,
751 int *npsmax) {
752
753 PyObject* subvalue = NULL;
754 Py_ssize_t i = 0;
755 Py_ssize_t size = 0;
756 int ival = 0;
757 int mval = 0;
758 const char* strvalue = 0;
759 void* newmem = NULL;
760
761 if (!PySequence_Check(value))
762 return -1;
763 size = PySequence_Size(value);
764 if (size > 0x7fffffff) {
765 /* Must be a 32-bit size */
766 return -1;
767 }
768
769 if (size > (Py_ssize_t)*npsmax) {
770 newmem = malloc(sizeof(struct pscard) * size);
771 if (newmem == NULL) {
772 PyErr_SetString(PyExc_MemoryError, "Could not allocate memory.");
773 return -1;
774 }
775 free(*ps);
776 *ps = newmem;
777 *npsmax = (int)size;
778 }
779
780 /* Verify the entire list for correct types first, so we don't have
781 to undo anything copied into the canonical array. */
782 for (i = 0; i < size; ++i) {
783 subvalue = PySequence_GetItem(value, i);
784 if (subvalue == NULL) {
785 return -1;
786 }
787 if (!PyArg_ParseTuple(subvalue, "iis", &ival, &mval, &strvalue)) {
788 Py_DECREF(subvalue);
789 return -1;
790 }
791 Py_DECREF(subvalue);
792 }
793
794 for (i = 0; i < size; ++i) {
795 subvalue = PySequence_GetItem(value, i);
796 if (subvalue == NULL) {
797 return -1;
798 }
799 if (!PyArg_ParseTuple(subvalue, "iis", &ival, &mval, &strvalue)) {
800 Py_DECREF(subvalue);
801 return -1;
802 }
803 Py_DECREF(subvalue);
804
805 (*ps)[i].i = ival;
806 (*ps)[i].m = mval;
807 strncpy((*ps)[i].value, strvalue, 72);
808 (*ps)[i].value[71] = '\0';
809 (*nps) = (int)(i + 1);
810 }
811
812 return 0;
813 }
814
815 /*@null@*/ PyObject*
get_pvcards(const char * propname,struct pvcard * pv,int npv)816 get_pvcards(
817 /*@unused@*/ const char* propname,
818 struct pvcard* pv,
819 int npv) {
820
821 PyObject* result = NULL;
822 PyObject* subresult = NULL;
823 Py_ssize_t i = 0;
824
825 if (npv < 0) {
826 npv = 0;
827 }
828
829 result = PyList_New((Py_ssize_t)npv);
830 if (result == NULL) {
831 return NULL;
832 }
833
834 if (npv && pv == NULL) {
835 PyErr_SetString(PyExc_MemoryError, "NULL pointer");
836 return NULL;
837 }
838
839 for (i = 0; i < (Py_ssize_t)npv; ++i) {
840 subresult = Py_BuildValue("iid", pv[i].i, pv[i].m, pv[i].value);
841 if (subresult == NULL) {
842 Py_DECREF(result);
843 return NULL;
844 }
845
846 if (PyList_SetItem(result, i, subresult)) {
847 Py_DECREF(subresult);
848 Py_DECREF(result);
849 return NULL;
850 }
851 }
852
853 return result;
854 }
855
856 int
set_pvcards(const char * propname,PyObject * value,struct pvcard ** pv,int * npv,int * npvmax)857 set_pvcards(
858 /*@propname@*/ const char* propname,
859 PyObject* value,
860 struct pvcard** pv,
861 int *npv,
862 int *npvmax) {
863
864 PyObject* fastseq = NULL;
865 struct pvcard* newmem = NULL;
866 Py_ssize_t size;
867 int ret = -1;
868 int i;
869
870 fastseq = PySequence_Fast(value, "Expected sequence type");
871 if (!fastseq)
872 goto done;
873
874 size = PySequence_Fast_GET_SIZE(value);
875 newmem = malloc(sizeof(struct pvcard) * size);
876
877 /* Raise exception if size is nonzero but newmem
878 * could not be allocated. */
879 if (size && !newmem) {
880 PyErr_SetString(PyExc_MemoryError, "Could not allocate memory.");
881 return -1;
882 }
883
884 for (i = 0; i < size; ++i)
885 {
886 if (!PyArg_ParseTuple(PySequence_Fast_GET_ITEM(value, i), "iid",
887 &newmem[i].i, &newmem[i].m, &newmem[i].value))
888 {
889 goto done;
890 }
891 }
892
893 if (size <= (Py_ssize_t)*npvmax) {
894 memcpy(*pv, newmem, sizeof(struct pvcard) * size);
895 } else { /* (size > (Py_ssize_t)*npvmax) */
896 free(*pv);
897 *npv = (int)size;
898 *pv = newmem;
899 newmem = NULL;
900 }
901 *npv = (int)size;
902
903 ret = 0;
904 done:
905 Py_XDECREF(fastseq);
906 free(newmem);
907 return ret;
908 }
909
910 PyObject*
get_deepcopy(PyObject * obj,PyObject * memo)911 get_deepcopy(
912 PyObject* obj,
913 PyObject* memo) {
914
915 if (PyObject_HasAttrString(obj, "__deepcopy__")) {
916 return PyObject_CallMethod(obj, "__deepcopy__", "O", memo);
917 } else {
918 return PyObject_CallMethod(obj, "__copy__", "");
919 }
920 }
921
922 /***************************************************************************
923 * Miscellaneous helper functions *
924 ***************************************************************************/
925
926 int
parse_unsafe_unit_conversion_spec(const char * arg,int * ctrl)927 parse_unsafe_unit_conversion_spec(
928 const char* arg, int* ctrl) {
929
930 const char* p = NULL;
931
932 *ctrl = 0;
933
934 for (p = arg; *p != '\0'; ++p) {
935 switch (*p) {
936 case 's':
937 case 'S':
938 *ctrl |= 1;
939 break;
940 case 'h':
941 case 'H':
942 *ctrl |= 2;
943 break;
944 case 'd':
945 case 'D':
946 *ctrl |= 4;
947 break;
948 default:
949 PyErr_SetString(
950 PyExc_ValueError,
951 "translate_units may only contain the characters 's', 'h' or 'd'");
952 return 1;
953 }
954 }
955
956 return 0;
957 }
958