4
Build call-back mechanism for f2py2e.
6
Copyright 2000 Pearu Peterson all rights reserved,
7
Pearu Peterson <pearu@ioc.ee>
8
Permission to use, modify, and distribute this software is given under the
9
terms of the NumPy License.
11
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
12
$Date: 2005/07/20 11:27:58 $
16
__version__ = "$Revision: 1.53 $"[10:-1]
19
f2py_version = __version__.version
23
import sys,string,time,types,copy
24
errmess=sys.stderr.write
25
outmess=sys.stdout.write
28
from auxfuncs import *
30
#from capi_maps import *
33
################## Rules for callback function ##############
36
'cbtypedefs':'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);',
39
PyObject *#name#_capi = NULL;/*was Py_None*/
40
PyTupleObject *#name#_args_capi = NULL;
41
int #name#_nofargs = 0;
42
jmp_buf #name#_jmpbuf;
43
/*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
44
#static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
45
\tPyTupleObject *capi_arglist = #name#_args_capi;
46
\tPyObject *capi_return = NULL;
47
\tPyObject *capi_tmp = NULL;
48
\tint capi_j,capi_i = 0;
49
\tint capi_longjmp_ok = 1;
51
#ifdef F2PY_REPORT_ATEXIT
52
f2py_cb_start_clock();
54
\tCFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
55
\tCFUNCSMESSPY(\"cb:#name#_capi=\",#name#_capi);
56
\tif (#name#_capi==NULL) {
57
\t\tcapi_longjmp_ok = 0;
58
\t\t#name#_capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
60
\tif (#name#_capi==NULL) {
61
\t\tPyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
64
\tif (PyCObject_Check(#name#_capi)) {
65
\t#name#_typedef #name#_cptr;
66
\t#name#_cptr = PyCObject_AsVoidPtr(#name#_capi);
67
\t#returncptr#(*#name#_cptr)(#optargs_nm##args_nm#);
70
\tif (capi_arglist==NULL) {
71
\t\tcapi_longjmp_ok = 0;
72
\t\tcapi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
74
\t\t\tcapi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
75
\t\t\tif (capi_arglist==NULL) {
76
\t\t\t\tPyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
77
\t\t\t\tgoto capi_fail;
81
\t\t\tcapi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
84
\tif (capi_arglist == NULL) {
85
\t\tPyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
90
\tCFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
91
\tCFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
92
#ifdef F2PY_REPORT_ATEXIT
93
f2py_cb_start_call_clock();
95
\tcapi_return = PyObject_CallObject(#name#_capi,(PyObject *)capi_arglist);
96
#ifdef F2PY_REPORT_ATEXIT
97
f2py_cb_stop_call_clock();
99
\tCFUNCSMESSPY(\"cb:capi_return=\",capi_return);
100
\tif (capi_return == NULL) {
101
\t\tfprintf(stderr,\"capi_return is NULL\\n\");
104
\tif (capi_return == Py_None) {
105
\t\tPy_DECREF(capi_return);
106
\t\tcapi_return = Py_BuildValue(\"()\");
108
\telse if (!PyTuple_Check(capi_return)) {
109
\t\tcapi_return = Py_BuildValue(\"(N)\",capi_return);
111
\tcapi_j = PyTuple_Size(capi_return);
114
\tCFUNCSMESS(\"cb:#name#:successful\\n\");
115
\tPy_DECREF(capi_return);
116
#ifdef F2PY_REPORT_ATEXIT
117
f2py_cb_stop_clock();
119
\tgoto capi_return_pt;
121
\tfprintf(stderr,\"Call-back #name# failed.\\n\");
122
\tPy_XDECREF(capi_return);
123
\tif (capi_longjmp_ok)
124
\t\tlongjmp(#name#_jmpbuf,-1);
131
'need':['setjmp.h','CFUNCSMESS'],
132
'maxnofargs':'#maxnofargs#',
133
'nofoptargs':'#nofoptargs#',
135
\tdef #argname#(#docsignature#): return #docreturn#\\n\\
138
{{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}}
141
#latexdocstrsigns#""",
142
'docstrshort':'def #argname#(#docsignature#): return #docreturn#'
146
'separatorsfor':{'decl':'\n',
147
'args':',','optargs':'','pyobjfrom':'\n','freemem':'\n',
148
'args_td':',','optargs_td':'',
149
'args_nm':',','optargs_nm':'',
150
'frompyobj':'\n','setdims':'\n',
151
'docstrsigns':'\\n"\n"',
152
'latexdocstrsigns':'\n',
153
'latexdocstrreq':'\n','latexdocstropt':'\n',
154
'latexdocstrout':'\n','latexdocstrcbs':'\n',
156
'decl':'/*decl*/','pyobjfrom':'/*pyobjfrom*/','frompyobj':'/*frompyobj*/',
157
'args':[],'optargs':'','return':'','strarglens':'','freemem':'/*freemem*/',
158
'args_td':[],'optargs_td':'','strarglens_td':'',
159
'args_nm':[],'optargs_nm':'','strarglens_nm':'',
161
'setdims':'/*setdims*/',
162
'docstrsigns':'','latexdocstrsigns':'',
163
'docstrreq':'\tRequired arguments:',
164
'docstropt':'\tOptional arguments:',
165
'docstrout':'\tReturn objects:',
166
'docstrcbs':'\tCall-back functions:',
167
'docreturn':'','docsign':'','docsignopt':'',
168
'latexdocstrreq':'\\noindent Required arguments:',
169
'latexdocstropt':'\\noindent Optional arguments:',
170
'latexdocstrout':'\\noindent Return objects:',
171
'latexdocstrcbs':'\\noindent Call-back functions:',
172
'routnote':{hasnote:'--- #note#',l_not(hasnote):''},
174
'decl':'\t#ctype# return_value;',
175
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->");'},
176
'\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n");',
177
{debugcapi:'\tfprintf(stderr,"#showvalueformat#.\\n",return_value);'}
179
'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'},'GETSCALARFROMPYTUPLE'],
180
'return':'\treturn return_value;',
181
'_check':l_and(isfunction,l_not(isstringfunction),l_not(iscomplexfunction))
184
'pyobjfrom':{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
185
'args':'#ctype# return_value,int return_value_len',
186
'args_nm':'return_value,&return_value_len',
187
'args_td':'#ctype# ,int',
188
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->\\"");'},
189
"""\tif (capi_j>capi_i)
190
\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);""",
191
{debugcapi:'\tfprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
193
'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'},
194
'string.h','GETSTRFROMPYTUPLE'],
196
'_check':isstringfunction
200
#ifndef F2PY_CB_RETURNCOMPLEX
201
#ctype# *return_value
205
#ifndef F2PY_CB_RETURNCOMPLEX
210
#ifndef F2PY_CB_RETURNCOMPLEX
215
#ifdef F2PY_CB_RETURNCOMPLEX
216
\t#ctype# return_value;
219
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting return_value->");'},
222
#ifdef F2PY_CB_RETURNCOMPLEX
223
\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
225
\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,\"#ctype#_from_pyobj failed in converting return_value of call-back function #name# to C #ctype#\\n\");
229
#ifdef F2PY_CB_RETURNCOMPLEX
230
\tfprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
232
\tfprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
238
#ifdef F2PY_CB_RETURNCOMPLEX
239
\treturn return_value;
244
'need':['#ctype#_from_pyobj',{debugcapi:'CFUNCSMESS'},
245
'string.h','GETSCALARFROMPYTUPLE','#ctype#'],
246
'_check':iscomplexfunction
248
{'docstrout':'\t\t#pydocsignout#',
249
'latexdocstrout':['\\item[]{{}\\verb@#pydocsignout#@{}}',
250
{hasnote:'--- #note#'}],
251
'docreturn':'#rname#,',
252
'_check':isfunction},
253
{'_check':issubroutine,'return':'return;'}
258
'docstropt':{l_and(isoptional,isintent_nothide):'\t\t#pydocsign#'},
259
'docstrreq':{l_and(isrequired,isintent_nothide):'\t\t#pydocsign#'},
260
'docstrout':{isintent_out:'\t\t#pydocsignout#'},
261
'latexdocstropt':{l_and(isoptional,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}',
262
{hasnote:'--- #note#'}]},
263
'latexdocstrreq':{l_and(isrequired,isintent_nothide):['\\item[]{{}\\verb@#pydocsign#@{}}',
264
{hasnote:'--- #note#'}]},
265
'latexdocstrout':{isintent_out:['\\item[]{{}\\verb@#pydocsignout#@{}}',
266
{l_and(hasnote,isintent_hide):'--- #note#',
267
l_and(hasnote,isintent_nothide):'--- See above.'}]},
268
'docsign':{l_and(isrequired,isintent_nothide):'#varname#,'},
269
'docsignopt':{l_and(isoptional,isintent_nothide):'#varname#,'},
274
l_and (isscalar,isintent_c):'#ctype# #varname#',
275
l_and (isscalar,l_not(isintent_c)):'#ctype# *#varname#_cb_capi',
276
isarray:'#ctype# *#varname#',
277
isstring:'#ctype# #varname#'
280
l_and (isscalar,isintent_c):'#varname#',
281
l_and (isscalar,l_not(isintent_c)):'#varname#_cb_capi',
286
l_and (isscalar,isintent_c):'#ctype#',
287
l_and (isscalar,l_not(isintent_c)):'#ctype# *',
291
'strarglens':{isstring:',int #varname#_cb_len'}, # untested with multiple args
292
'strarglens_td':{isstring:',int'}, # untested with multiple args
296
'decl':{l_not(isintent_c):'\t#ctype# #varname#=(*#varname#_cb_capi);'},
297
'error': {l_and(isintent_c,isintent_out,
298
throw_error('intent(c,out) is forbidden for callback scalar arguments')):\
300
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->");'},
301
{isintent_out:'\tif (capi_j>capi_i)\n\t\tGETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
302
{l_and(debugcapi,l_and(l_not(iscomplex),isintent_c)):'\tfprintf(stderr,"#showvalueformat#.\\n",#varname#);'},
303
{l_and(debugcapi,l_and(l_not(iscomplex),l_not(isintent_c))):'\tfprintf(stderr,"#showvalueformat#.\\n",*#varname#_cb_capi);'},
304
{l_and(debugcapi,l_and(iscomplex,isintent_c)):'\tfprintf(stderr,"#showvalueformat#.\\n",(#varname#).r,(#varname#).i);'},
305
{l_and(debugcapi,l_and(iscomplex,l_not(isintent_c))):'\tfprintf(stderr,"#showvalueformat#.\\n",(*#varname#_cb_capi).r,(*#varname#_cb_capi).i);'},
307
'need':[{isintent_out:['#ctype#_from_pyobj','GETSCALARFROMPYTUPLE']},
308
{debugcapi:'CFUNCSMESS'}],
311
'pyobjfrom':[{isintent_in:"""\
312
\tif (#name#_nofargs>capi_i)
313
\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_#ctype#1(#varname#)))
314
\t\t\tgoto capi_fail;"""},
316
\tif (#name#_nofargs>capi_i)
317
\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyarr_from_p_#ctype#1(#varname#_cb_capi)))
318
\t\t\tgoto capi_fail;"""}],
319
'need':[{isintent_in:'pyobj_from_#ctype#1'},
320
{isintent_inout:'pyarr_from_p_#ctype#1'},
321
{iscomplex:'#ctype#'}],
322
'_check':l_and(isscalar,isintent_nothide),
325
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->\\"");'},
326
"""\tif (capi_j>capi_i)
327
\t\tGETSTRFROMPYTUPLE(capi_return,capi_i++,#varname#,#varname#_cb_len);""",
328
{debugcapi:'\tfprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname#,#varname#_cb_len);'},
330
'need':['#ctype#','GETSTRFROMPYTUPLE',
331
{debugcapi:'CFUNCSMESS'},'string.h'],
332
'_check':l_and(isstring,isintent_out)
334
'pyobjfrom':[{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#varname#=\\"#showvalueformat#\\":%d:\\n",#varname#,#varname#_cb_len);'},
336
\tif (#name#_nofargs>capi_i)
337
\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyobj_from_#ctype#1(#varname#)))
338
\t\t\tgoto capi_fail;"""},
340
\tif (#name#_nofargs>capi_i) {
341
\t\tint #varname#_cb_dims[] = {#varname#_cb_len};
342
\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,pyarr_from_p_#ctype#1(#varname#,#varname#_cb_dims)))
343
\t\t\tgoto capi_fail;
345
'need':[{isintent_in:'pyobj_from_#ctype#1'},
346
{isintent_inout:'pyarr_from_p_#ctype#1'}],
347
'_check':l_and(isstring,isintent_nothide),
352
'decl':'\tintp #varname#_Dims[#rank#] = {#rank*[-1]#};',
353
'setdims':'\t#cbsetdims#;',
358
'pyobjfrom':[{debugcapi:'\tfprintf(stderr,"debug-capi:cb:#varname#\\n");'},
360
\tif (#name#_nofargs>capi_i) {
361
\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname#_Dims,#atype#,NULL,(char*)#varname#,0,CARRAY_FLAGS,NULL); /*XXX: Hmm, what will destroy this array??? */
363
l_not(isintent_c):"""\
364
\tif (#name#_nofargs>capi_i) {
365
\t\tPyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,#rank#,#varname#_Dims,#atype#,NULL,(char*)#varname#,0,FARRAY_FLAGS,NULL); /*XXX: Hmm, what will destroy this array??? */
369
\t\tif (tmp_arr==NULL)
370
\t\t\tgoto capi_fail;
371
\t\tif (PyTuple_SetItem((PyObject *)capi_arglist,capi_i++,(PyObject *)tmp_arr))
372
\t\t\tgoto capi_fail;
374
'_check':l_and(isarray,isintent_nothide,l_or(isintent_in,isintent_inout)),
377
'frompyobj':[{debugcapi:'\tCFUNCSMESS("cb:Getting #varname#->");'},
378
"""\tif (capi_j>capi_i) {
379
\t\tPyArrayObject *rv_cb_arr = NULL;
380
\t\tif ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
381
\t\trv_cb_arr = array_from_pyobj(#atype#,#varname#_Dims,#rank#,F2PY_INTENT_IN""",
382
{isintent_c:'|F2PY_INTENT_C'},
384
\t\tif (rv_cb_arr == NULL) {
385
\t\t\tfprintf(stderr,\"rv_cb_arr is NULL\\n\");
386
\t\t\tgoto capi_fail;
388
\t\tMEMCOPY(#varname#,rv_cb_arr->data,PyArray_NBYTES(rv_cb_arr));
389
\t\tif (capi_tmp != (PyObject *)rv_cb_arr) {
390
\t\t\tPy_DECREF(rv_cb_arr);
393
{debugcapi:'\tfprintf(stderr,"<-.\\n");'},
395
'need':['MEMCOPY',{iscomplexarray:'#ctype#'}],
396
'_check':l_and(isarray,isintent_out)
398
'docreturn':'#varname#,',
399
'_check':isintent_out
403
################## Build call-back module #############
405
def buildcallbacks(m):
409
if bi['block']=='interface':
412
buildcallback(b,m['name'])
414
errmess('warning: empty body for %s\n' % (m['name']))
416
def buildcallback(rout,um):
418
outmess('\tConstructing call-back function "cb_%s_in_%s"\n'%(rout['name'],um))
419
args,depargs=getargs(rout)
420
capi_maps.depargs=depargs
422
vrd=capi_maps.cb_routsign2map(rout,um)
423
rd=dictappend({},vrd)
424
cb_map[um].append([rout['name'],rd['name']])
425
for r in cb_rout_rules:
426
if (r.has_key('_check') and r['_check'](rout)) or (not r.has_key('_check')):
427
ar=applyrules(r,vrd,rout)
431
vrd=capi_maps.cb_sign2map(a,var[a])
433
for r in cb_arg_rules:
434
if r.has_key('_depend'): continue
435
if r.has_key('_optional') and isoptional(var[a]): continue
436
if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')):
437
ar=applyrules(r,vrd,var[a])
439
if r.has_key('_break'): break
442
for r in cb_arg_rules:
443
if r.has_key('_depend'): continue
444
if (not r.has_key('_optional')) or (r.has_key('_optional') and isrequired(var[a])): continue
445
if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')):
446
ar=applyrules(r,vrd,var[a])
448
if r.has_key('_break'): break
451
for r in cb_arg_rules:
452
if not r.has_key('_depend'): continue
453
if r.has_key('_optional'): continue
454
if (r.has_key('_check') and r['_check'](var[a])) or (not r.has_key('_check')):
455
ar=applyrules(r,vrd,var[a])
457
if r.has_key('_break'): break
458
if rd.has_key('args') and rd.has_key('optargs'):
459
if type(rd['optargs'])==type([]):
460
rd['optargs']=rd['optargs']+["""
461
#ifndef F2PY_CB_RETURNCOMPLEX
465
rd['optargs_nm']=rd['optargs_nm']+["""
466
#ifndef F2PY_CB_RETURNCOMPLEX
470
rd['optargs_td']=rd['optargs_td']+["""
471
#ifndef F2PY_CB_RETURNCOMPLEX
475
if type(rd['docreturn'])==types.ListType:
476
rd['docreturn']=stripcomma(replace('#docreturn#',{'docreturn':rd['docreturn']}))
477
optargs=stripcomma(replace('#docsignopt#',
478
{'docsignopt':rd['docsignopt']}
481
rd['docsignature']=stripcomma(replace('#docsign#',{'docsign':rd['docsign']}))
483
rd['docsignature']=replace('#docsign#[#docsignopt#]',
484
{'docsign':rd['docsign'],
485
'docsignopt':optargs,
487
rd['latexdocsignature']=string.replace(rd['docsignature'],'_','\\_')
488
rd['latexdocsignature']=string.replace(rd['latexdocsignature'],',',', ')
490
rd['latexdocstrsigns']=[]
491
for k in ['docstrreq','docstropt','docstrout','docstrcbs']:
492
if rd.has_key(k) and type(rd[k])==types.ListType:
493
rd['docstrsigns']=rd['docstrsigns']+rd[k]
495
if rd.has_key(k) and type(rd[k])==types.ListType:
496
rd['latexdocstrsigns']=rd['latexdocstrsigns']+rd[k][0:1]+\
497
['\\begin{description}']+rd[k][1:]+\
498
['\\end{description}']
499
if not rd.has_key('args'):
503
if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')):
504
rd['noargs'] = 'void'
506
ar=applyrules(cb_routine_rules,rd)
507
cfuncs.callbacks[rd['name']]=ar['body']
508
if type(ar['need'])==types.StringType:
509
ar['need']=[ar['need']]
511
if rd.has_key('need'):
512
for t in cfuncs.typedefs.keys():
516
cfuncs.typedefs_generated[rd['name']+'_typedef'] = ar['cbtypedefs']
517
ar['need'].append(rd['name']+'_typedef')
518
cfuncs.needs[rd['name']]=ar['need']
520
capi_maps.lcb2_map[rd['name']]={'maxnofargs':ar['maxnofargs'],
521
'nofoptargs':ar['nofoptargs'],
522
'docstr':ar['docstr'],
523
'latexdocstr':ar['latexdocstr'],
524
'argname':rd['argname']
526
outmess('\t %s\n'%(ar['docstrshort']))
529
################## Build call-back function #############