3 * Pyke: the Python Kit for Extensions
5 * (c) 2019 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Pyke: the Python Kit for Extensions.
12 * Pyke is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
17 * Pyke is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License
23 * along with Pyke. If not, write to the Free Software Foundation, Inc.,
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
31 /*----- External variables ------------------------------------------------*/
34 PyObject
*home_module
;
36 /*----- Conversions -------------------------------------------------------*/
38 PyObject
*getulong(unsigned long w
)
40 if (w
<= LONG_MAX
) return (PyInt_FromLong(w
));
41 else return (PyLong_FromUnsignedLong(w
));
44 PyObject
*getbool(int b
)
45 { if (b
) RETURN_TRUE
; else RETURN_FALSE
; }
47 int convulong(PyObject
*o
, void *pp
)
49 unsigned long *p
= pp
;
52 if (!o
) VALERR("can't delete");
55 long i
= PyInt_AS_LONG(o
);
56 if (i
< 0) VALERR("must be nonnegative");
61 if ((t
= PyNumber_Long(o
)) == 0) goto end
;
62 *p
= PyLong_AsUnsignedLong(t
);
64 if (PyErr_Occurred()) goto end
;
71 int convuint(PyObject
*o
, void *pp
)
76 if (!convulong(o
, &u
)) goto end
;
77 if (u
> UINT_MAX
) VALERR("out of range");
84 int convszt(PyObject
*o
, void *pp
)
89 if (!convulong(o
, &u
)) goto end
;
90 if (u
> ~(size_t)0) VALERR("out of range");
97 int convbool(PyObject
*o
, void *pp
)
99 if (!o
) VALERR("can't delete");
100 *(int *)pp
= PyObject_IsTrue(o
);
106 int convbin(PyObject
*o
, void *pp
)
118 if (PyUnicode_Check(o
)) {
119 o
= _PyUnicode_AsDefaultEncodedString(o
, 0);
122 r
->p
= PyString_AS_STRING(o
);
123 r
->sz
= PyString_GET_SIZE(o
);
127 #if PY_VERSION_HEX < 0x02060000
129 return (PyObject_AsReadBuffer(o
, &r
->p
, &r
->sz
) ?
0 : 1);
131 rc
= PyObject_GetBuffer(o
, &r
->vw
, PyBUF_SIMPLE
); if (rc
) return (0);
132 o
->p
= o
->vw
.buf
; o
->sz
= o
->vw
.len
;
137 void freebin(struct bin
*r
)
138 { if (r
->vw
.obj
) PyBuffer_Release(&r
->vw
); }
140 /*----- Miscellaneous utilities -------------------------------------------*/
142 PyObject
*abstract_pynew(PyTypeObject
*ty
, PyObject
*arg
, PyObject
*kw
)
144 PyErr_SetString(PyExc_TypeError
, "can't instantiate this class");
148 PyObject
*enrich_compare(int op
, int cmp
)
153 case Py_LT
: r
= cmp
< 0; break;
154 case Py_LE
: r
= cmp
<= 0; break;
155 case Py_EQ
: r
= cmp
== 0; break;
156 case Py_NE
: r
= cmp
!= 0; break;
157 case Py_GE
: r
= cmp
>= 0; break;
158 case Py_GT
: r
= cmp
> 0; break;
164 /*----- Saving and restoring exceptions ----------------------------------*/
166 void report_lost_exception_v(struct excinfo
*exc
,
167 const char *why
, va_list ap
)
169 PyObject
*hookfn
= 0;
170 PyObject
*whyobj
= 0;
173 /* Make sure we start out without a pending exception, or this will get
176 assert(!PyErr_Occurred());
178 /* Format the explanation. */
179 if (why
) whyobj
= TEXT_VFORMAT(why
, ap
);
180 else { whyobj
= Py_None
; Py_INCREF(whyobj
); }
182 /* Find our home module's `lostexchook' function. This won't work if
183 * there's no module, or the function isn't defined, or it's `None'.
185 if (!home_module
) goto sys
;
186 hookfn
= PyObject_GetAttrString(home_module
, "lostexchook");
187 if (hookfn
== Py_None
) goto sys
;
189 else if (!PyErr_ExceptionMatches(PyExc_AttributeError
)) goto ouch
;
190 else { PyErr_Clear(); goto sys
; }
192 /* Call the hook function. */
193 obj
= PyObject_CallFunction(hookfn
, "(OOOO)",
194 whyobj
, exc
->ty
, exc
->val
, exc
->tb
);
198 /* Something went wrong reporting the problem. */
200 PySys_WriteStderr("\n!!! FAILURE REPORTING LOST EXCEPTION\n");
202 /* drop through... */
204 /* There was no hook, so try to do something sensible using
208 PySys_WriteStderr("\n!!! LOST EXCEPTION: %s\n", TEXT_PTR(whyobj
));
209 RESTORE_EXCINFO(exc
);
211 /* drop through... */
213 /* Clean up afterwards. */
220 void report_lost_exception(struct excinfo
*exc
, const char *why
, ...)
225 report_lost_exception_v(exc
, why
, ap
);
229 void stash_exception(struct excinfo
*exc
, const char *why
, ...)
232 struct excinfo stash
;
238 STASH_EXCINFO(&stash
);
239 report_lost_exception_v(&stash
, why
, ap
);
244 void restore_exception(struct excinfo
*exc
, const char *why
, ...)
247 struct excinfo stash
;
249 if (!PyErr_Occurred())
250 RESTORE_EXCINFO(exc
);
253 STASH_EXCINFO(&stash
);
254 report_lost_exception_v(exc
, why
, ap
);
255 RESTORE_EXCINFO(&stash
);
260 /*----- Type definitions --------------------------------------------------*/
262 static const PyTypeObject emptytype
= { 0 };
264 void *newtype(PyTypeObject
*metaty
,
265 const PyTypeObject
*skel
,
268 PyHeapTypeObject
*ty
=
269 (PyHeapTypeObject
*)_PyObject_GC_Malloc(_PyObject_VAR_SIZE(metaty
, 0));
270 if (!skel
) skel
= &emptytype
;
271 memcpy(ty
, skel
, sizeof(*skel
));
272 #define COPY(blah) do { \
273 if (ty->ht_type.tp_as_##blah) { \
274 memcpy(&ty->as_##blah, \
275 ty->ht_type.tp_as_##blah, \
276 sizeof(ty->as_##blah)); \
277 ty->ht_type.tp_as_##blah = &ty->as_##blah; \
286 ty
->ht_name
= TEXT_FROMSTR(name
);
287 else if (ty
->ht_type
.tp_name
)
288 ty
->ht_name
= TEXT_FROMSTR(ty
->ht_type
.tp_name
);
292 ty
->ht_type
.tp_name
= TEXT_STR(ty
->ht_name
);
297 (void)PyObject_INIT(&ty
->ht_type
, metaty
);
302 void typeready(PyTypeObject
*ty
)
305 PyHeapTypeObject
*hty
= (PyHeapTypeObject
*)ty
;
306 hty
->ht_qualname
= hty
->ht_name
;
309 PyDict_SetItemString(ty
->tp_dict
, "__module__", modname
);
312 PyTypeObject
*inittype(const PyTypeObject
*tyskel
,
313 PyTypeObject
*base
, PyTypeObject
*meta
)
315 PyTypeObject
*ty
= newtype(meta
, tyskel
, 0);
316 if (base
) { ty
->tp_base
= base
; Py_INCREF(base
); }
317 ty
->tp_flags
|= Py_TPFLAGS_HEAPTYPE
;
322 /*----- Populating modules ------------------------------------------------*/
324 PyObject
*mkexc(PyObject
*mod
, PyObject
*base
,
325 const char *name
, const PyMethodDef
*mm
)
327 PyObject
*nameobj
= 0;
333 if ((dict
= PyDict_New()) == 0) goto fail
;
336 while (mm
->ml_name
) {
337 if ((func
= PyCFunction_NewEx((/*unconst*/ PyMethodDef
*)mm
,
339 (meth
= PY23(PyMethod_New(func
, 0, exc
),
340 PyInstanceMethod_New(func
))) == 0 ||
341 PyDict_SetItemString(dict
, mm
->ml_name
, meth
))
343 Py_DECREF(func
); func
= 0;
344 Py_DECREF(meth
); meth
= 0;
349 if ((nameobj
= TEXT_FORMAT("%s.%s", PyModule_GetName(mod
), name
)) == 0 ||
350 (exc
= PyErr_NewException(TEXT_STR(nameobj
), base
, dict
)) == 0)
366 void setconstants(PyObject
*mod
, const struct nameval
*c
)
373 if (u
<= LONG_MAX
) x
= PyInt_FromLong(u
);
374 else if (c
->f
&CF_SIGNED
) x
= PyInt_FromLong(-1 - (long)(ULONG_MAX
- u
));
375 else x
= PyLong_FromUnsignedLong(u
);
376 PyModule_AddObject(mod
, (/*unconst*/ char *)c
->name
, x
);
381 /*----- Submodules --------------------------------------------------------*/
383 static PyMethodDef
*global_methods
;
384 static size_t nmethods
, methodsz
;
386 void addmethods(const PyMethodDef
*m
)
388 size_t n
, want
, newsz
;
390 for (n
= 0; m
[n
].ml_name
; n
++);
391 want
= nmethods
+ n
+ 1;
392 if (want
> methodsz
) {
393 newsz
= methodsz ?
2*methodsz
: 16;
394 while (want
> newsz
) newsz
*= 2;
396 global_methods
= PyObject_Malloc(newsz
*sizeof(PyMethodDef
));
398 global_methods
= PyObject_Realloc(global_methods
,
399 newsz
*sizeof(PyMethodDef
));
400 assert(global_methods
);
403 memcpy(global_methods
+ nmethods
, m
, n
*sizeof(PyMethodDef
));
405 global_methods
[nmethods
].ml_name
= 0;
408 PyMethodDef
*donemethods(void) { return (global_methods
); }
410 /*----- Low-level Python interface ----------------------------------------*/
412 static PyObject
*meth__set_home_module(PyObject
*me
, PyObject
*arg
)
416 if (!PyArg_ParseTuple(arg
, "O!:_set_home_module", &PyModule_Type
, &mod
))
418 Py_XDECREF(home_module
); home_module
= mod
; Py_INCREF(home_module
);
422 static const PyMethodDef methods
[] = {
423 #define METHNAME(func) meth_##func
424 METH (_set_home_module
, "_set_home_module(MOD)")
429 void pyke_core_pyinit(void) { addmethods(methods
); }
430 void pyke_core_pyinsert(PyObject
*mod
) { ; }
432 /*----- That's all, folks -------------------------------------------------*/