cb_rules.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. #!/usr/bin/env python3
  2. """
  3. Build call-back mechanism for f2py2e.
  4. Copyright 2000 Pearu Peterson all rights reserved,
  5. Pearu Peterson <pearu@ioc.ee>
  6. Permission to use, modify, and distribute this software is given under the
  7. terms of the NumPy License.
  8. NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  9. $Date: 2005/07/20 11:27:58 $
  10. Pearu Peterson
  11. """
  12. from . import __version__
  13. from .auxfuncs import (
  14. applyrules, debugcapi, dictappend, errmess, getargs, hasnote, isarray,
  15. iscomplex, iscomplexarray, iscomplexfunction, isfunction, isintent_c,
  16. isintent_hide, isintent_in, isintent_inout, isintent_nothide,
  17. isintent_out, isoptional, isrequired, isscalar, isstring,
  18. isstringfunction, issubroutine, l_and, l_not, l_or, outmess, replace,
  19. stripcomma, throw_error
  20. )
  21. from . import cfuncs
  22. f2py_version = __version__.version
  23. ################## Rules for callback function ##############
  24. cb_routine_rules = {
  25. 'cbtypedefs': 'typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);',
  26. 'body': """
  27. #begintitle#
  28. typedef struct {
  29. PyObject *capi;
  30. PyTupleObject *args_capi;
  31. int nofargs;
  32. jmp_buf jmpbuf;
  33. } #name#_t;
  34. #if defined(F2PY_THREAD_LOCAL_DECL) && !defined(F2PY_USE_PYTHON_TLS)
  35. static F2PY_THREAD_LOCAL_DECL #name#_t *_active_#name# = NULL;
  36. static #name#_t *swap_active_#name#(#name#_t *ptr) {
  37. #name#_t *prev = _active_#name#;
  38. _active_#name# = ptr;
  39. return prev;
  40. }
  41. static #name#_t *get_active_#name#(void) {
  42. return _active_#name#;
  43. }
  44. #else
  45. static #name#_t *swap_active_#name#(#name#_t *ptr) {
  46. char *key = "__f2py_cb_#name#";
  47. return (#name#_t *)F2PySwapThreadLocalCallbackPtr(key, ptr);
  48. }
  49. static #name#_t *get_active_#name#(void) {
  50. char *key = "__f2py_cb_#name#";
  51. return (#name#_t *)F2PyGetThreadLocalCallbackPtr(key);
  52. }
  53. #endif
  54. /*typedef #rctype#(*#name#_typedef)(#optargs_td##args_td##strarglens_td##noargs#);*/
  55. #static# #rctype# #callbackname# (#optargs##args##strarglens##noargs#) {
  56. #name#_t cb_local = { NULL, NULL, 0 };
  57. #name#_t *cb = NULL;
  58. PyTupleObject *capi_arglist = NULL;
  59. PyObject *capi_return = NULL;
  60. PyObject *capi_tmp = NULL;
  61. PyObject *capi_arglist_list = NULL;
  62. int capi_j,capi_i = 0;
  63. int capi_longjmp_ok = 1;
  64. #decl#
  65. #ifdef F2PY_REPORT_ATEXIT
  66. f2py_cb_start_clock();
  67. #endif
  68. cb = get_active_#name#();
  69. if (cb == NULL) {
  70. capi_longjmp_ok = 0;
  71. cb = &cb_local;
  72. }
  73. capi_arglist = cb->args_capi;
  74. CFUNCSMESS(\"cb:Call-back function #name# (maxnofargs=#maxnofargs#(-#nofoptargs#))\\n\");
  75. CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
  76. if (cb->capi==NULL) {
  77. capi_longjmp_ok = 0;
  78. cb->capi = PyObject_GetAttrString(#modulename#_module,\"#argname#\");
  79. CFUNCSMESSPY(\"cb:#name#_capi=\",cb->capi);
  80. }
  81. if (cb->capi==NULL) {
  82. PyErr_SetString(#modulename#_error,\"cb: Callback #argname# not defined (as an argument or module #modulename# attribute).\\n\");
  83. goto capi_fail;
  84. }
  85. if (F2PyCapsule_Check(cb->capi)) {
  86. #name#_typedef #name#_cptr;
  87. #name#_cptr = F2PyCapsule_AsVoidPtr(cb->capi);
  88. #returncptr#(*#name#_cptr)(#optargs_nm##args_nm##strarglens_nm#);
  89. #return#
  90. }
  91. if (capi_arglist==NULL) {
  92. capi_longjmp_ok = 0;
  93. capi_tmp = PyObject_GetAttrString(#modulename#_module,\"#argname#_extra_args\");
  94. if (capi_tmp) {
  95. capi_arglist = (PyTupleObject *)PySequence_Tuple(capi_tmp);
  96. Py_DECREF(capi_tmp);
  97. if (capi_arglist==NULL) {
  98. PyErr_SetString(#modulename#_error,\"Failed to convert #modulename#.#argname#_extra_args to tuple.\\n\");
  99. goto capi_fail;
  100. }
  101. } else {
  102. PyErr_Clear();
  103. capi_arglist = (PyTupleObject *)Py_BuildValue(\"()\");
  104. }
  105. }
  106. if (capi_arglist == NULL) {
  107. PyErr_SetString(#modulename#_error,\"Callback #argname# argument list is not set.\\n\");
  108. goto capi_fail;
  109. }
  110. #setdims#
  111. #ifdef PYPY_VERSION
  112. #define CAPI_ARGLIST_SETITEM(idx, value) PyList_SetItem((PyObject *)capi_arglist_list, idx, value)
  113. capi_arglist_list = PySequence_List(capi_arglist);
  114. if (capi_arglist_list == NULL) goto capi_fail;
  115. #else
  116. #define CAPI_ARGLIST_SETITEM(idx, value) PyTuple_SetItem((PyObject *)capi_arglist, idx, value)
  117. #endif
  118. #pyobjfrom#
  119. #undef CAPI_ARGLIST_SETITEM
  120. #ifdef PYPY_VERSION
  121. CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist_list);
  122. #else
  123. CFUNCSMESSPY(\"cb:capi_arglist=\",capi_arglist);
  124. #endif
  125. CFUNCSMESS(\"cb:Call-back calling Python function #argname#.\\n\");
  126. #ifdef F2PY_REPORT_ATEXIT
  127. f2py_cb_start_call_clock();
  128. #endif
  129. #ifdef PYPY_VERSION
  130. capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist_list);
  131. Py_DECREF(capi_arglist_list);
  132. capi_arglist_list = NULL;
  133. #else
  134. capi_return = PyObject_CallObject(cb->capi,(PyObject *)capi_arglist);
  135. #endif
  136. #ifdef F2PY_REPORT_ATEXIT
  137. f2py_cb_stop_call_clock();
  138. #endif
  139. CFUNCSMESSPY(\"cb:capi_return=\",capi_return);
  140. if (capi_return == NULL) {
  141. fprintf(stderr,\"capi_return is NULL\\n\");
  142. goto capi_fail;
  143. }
  144. if (capi_return == Py_None) {
  145. Py_DECREF(capi_return);
  146. capi_return = Py_BuildValue(\"()\");
  147. }
  148. else if (!PyTuple_Check(capi_return)) {
  149. capi_return = Py_BuildValue(\"(N)\",capi_return);
  150. }
  151. capi_j = PyTuple_Size(capi_return);
  152. capi_i = 0;
  153. #frompyobj#
  154. CFUNCSMESS(\"cb:#name#:successful\\n\");
  155. Py_DECREF(capi_return);
  156. #ifdef F2PY_REPORT_ATEXIT
  157. f2py_cb_stop_clock();
  158. #endif
  159. goto capi_return_pt;
  160. capi_fail:
  161. fprintf(stderr,\"Call-back #name# failed.\\n\");
  162. Py_XDECREF(capi_return);
  163. Py_XDECREF(capi_arglist_list);
  164. if (capi_longjmp_ok) {
  165. longjmp(cb->jmpbuf,-1);
  166. }
  167. capi_return_pt:
  168. ;
  169. #return#
  170. }
  171. #endtitle#
  172. """,
  173. 'need': ['setjmp.h', 'CFUNCSMESS', 'F2PY_THREAD_LOCAL_DECL'],
  174. 'maxnofargs': '#maxnofargs#',
  175. 'nofoptargs': '#nofoptargs#',
  176. 'docstr': """\
  177. def #argname#(#docsignature#): return #docreturn#\\n\\
  178. #docstrsigns#""",
  179. 'latexdocstr': """
  180. {{}\\verb@def #argname#(#latexdocsignature#): return #docreturn#@{}}
  181. #routnote#
  182. #latexdocstrsigns#""",
  183. 'docstrshort': 'def #argname#(#docsignature#): return #docreturn#'
  184. }
  185. cb_rout_rules = [
  186. { # Init
  187. 'separatorsfor': {'decl': '\n',
  188. 'args': ',', 'optargs': '', 'pyobjfrom': '\n', 'freemem': '\n',
  189. 'args_td': ',', 'optargs_td': '',
  190. 'args_nm': ',', 'optargs_nm': '',
  191. 'frompyobj': '\n', 'setdims': '\n',
  192. 'docstrsigns': '\\n"\n"',
  193. 'latexdocstrsigns': '\n',
  194. 'latexdocstrreq': '\n', 'latexdocstropt': '\n',
  195. 'latexdocstrout': '\n', 'latexdocstrcbs': '\n',
  196. },
  197. 'decl': '/*decl*/', 'pyobjfrom': '/*pyobjfrom*/', 'frompyobj': '/*frompyobj*/',
  198. 'args': [], 'optargs': '', 'return': '', 'strarglens': '', 'freemem': '/*freemem*/',
  199. 'args_td': [], 'optargs_td': '', 'strarglens_td': '',
  200. 'args_nm': [], 'optargs_nm': '', 'strarglens_nm': '',
  201. 'noargs': '',
  202. 'setdims': '/*setdims*/',
  203. 'docstrsigns': '', 'latexdocstrsigns': '',
  204. 'docstrreq': ' Required arguments:',
  205. 'docstropt': ' Optional arguments:',
  206. 'docstrout': ' Return objects:',
  207. 'docstrcbs': ' Call-back functions:',
  208. 'docreturn': '', 'docsign': '', 'docsignopt': '',
  209. 'latexdocstrreq': '\\noindent Required arguments:',
  210. 'latexdocstropt': '\\noindent Optional arguments:',
  211. 'latexdocstrout': '\\noindent Return objects:',
  212. 'latexdocstrcbs': '\\noindent Call-back functions:',
  213. 'routnote': {hasnote: '--- #note#', l_not(hasnote): ''},
  214. }, { # Function
  215. 'decl': ' #ctype# return_value = 0;',
  216. 'frompyobj': [
  217. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
  218. '''\
  219. if (capi_j>capi_i) {
  220. GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
  221. "#ctype#_from_pyobj failed in converting return_value of"
  222. " call-back function #name# to C #ctype#\\n");
  223. } else {
  224. fprintf(stderr,"Warning: call-back function #name# did not provide"
  225. " return value (index=%d, type=#ctype#)\\n",capi_i);
  226. }''',
  227. {debugcapi:
  228. ' fprintf(stderr,"#showvalueformat#.\\n",return_value);'}
  229. ],
  230. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'}, 'GETSCALARFROMPYTUPLE'],
  231. 'return': ' return return_value;',
  232. '_check': l_and(isfunction, l_not(isstringfunction), l_not(iscomplexfunction))
  233. },
  234. { # String function
  235. 'pyobjfrom': {debugcapi: ' fprintf(stderr,"debug-capi:cb:#name#:%d:\\n",return_value_len);'},
  236. 'args': '#ctype# return_value,int return_value_len',
  237. 'args_nm': 'return_value,&return_value_len',
  238. 'args_td': '#ctype# ,int',
  239. 'frompyobj': [
  240. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->\\"");'},
  241. """\
  242. if (capi_j>capi_i) {
  243. GETSTRFROMPYTUPLE(capi_return,capi_i++,return_value,return_value_len);
  244. } else {
  245. fprintf(stderr,"Warning: call-back function #name# did not provide"
  246. " return value (index=%d, type=#ctype#)\\n",capi_i);
  247. }""",
  248. {debugcapi:
  249. ' fprintf(stderr,"#showvalueformat#\\".\\n",return_value);'}
  250. ],
  251. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
  252. 'string.h', 'GETSTRFROMPYTUPLE'],
  253. 'return': 'return;',
  254. '_check': isstringfunction
  255. },
  256. { # Complex function
  257. 'optargs': """
  258. #ifndef F2PY_CB_RETURNCOMPLEX
  259. #ctype# *return_value
  260. #endif
  261. """,
  262. 'optargs_nm': """
  263. #ifndef F2PY_CB_RETURNCOMPLEX
  264. return_value
  265. #endif
  266. """,
  267. 'optargs_td': """
  268. #ifndef F2PY_CB_RETURNCOMPLEX
  269. #ctype# *
  270. #endif
  271. """,
  272. 'decl': """
  273. #ifdef F2PY_CB_RETURNCOMPLEX
  274. #ctype# return_value = {0, 0};
  275. #endif
  276. """,
  277. 'frompyobj': [
  278. {debugcapi: ' CFUNCSMESS("cb:Getting return_value->");'},
  279. """\
  280. if (capi_j>capi_i) {
  281. #ifdef F2PY_CB_RETURNCOMPLEX
  282. GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,#ctype#,
  283. \"#ctype#_from_pyobj failed in converting return_value of call-back\"
  284. \" function #name# to C #ctype#\\n\");
  285. #else
  286. GETSCALARFROMPYTUPLE(capi_return,capi_i++,return_value,#ctype#,
  287. \"#ctype#_from_pyobj failed in converting return_value of call-back\"
  288. \" function #name# to C #ctype#\\n\");
  289. #endif
  290. } else {
  291. fprintf(stderr,
  292. \"Warning: call-back function #name# did not provide\"
  293. \" return value (index=%d, type=#ctype#)\\n\",capi_i);
  294. }""",
  295. {debugcapi: """\
  296. #ifdef F2PY_CB_RETURNCOMPLEX
  297. fprintf(stderr,\"#showvalueformat#.\\n\",(return_value).r,(return_value).i);
  298. #else
  299. fprintf(stderr,\"#showvalueformat#.\\n\",(*return_value).r,(*return_value).i);
  300. #endif
  301. """}
  302. ],
  303. 'return': """
  304. #ifdef F2PY_CB_RETURNCOMPLEX
  305. return return_value;
  306. #else
  307. return;
  308. #endif
  309. """,
  310. 'need': ['#ctype#_from_pyobj', {debugcapi: 'CFUNCSMESS'},
  311. 'string.h', 'GETSCALARFROMPYTUPLE', '#ctype#'],
  312. '_check': iscomplexfunction
  313. },
  314. {'docstrout': ' #pydocsignout#',
  315. 'latexdocstrout': ['\\item[]{{}\\verb@#pydocsignout#@{}}',
  316. {hasnote: '--- #note#'}],
  317. 'docreturn': '#rname#,',
  318. '_check': isfunction},
  319. {'_check': issubroutine, 'return': 'return;'}
  320. ]
  321. cb_arg_rules = [
  322. { # Doc
  323. 'docstropt': {l_and(isoptional, isintent_nothide): ' #pydocsign#'},
  324. 'docstrreq': {l_and(isrequired, isintent_nothide): ' #pydocsign#'},
  325. 'docstrout': {isintent_out: ' #pydocsignout#'},
  326. 'latexdocstropt': {l_and(isoptional, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
  327. {hasnote: '--- #note#'}]},
  328. 'latexdocstrreq': {l_and(isrequired, isintent_nothide): ['\\item[]{{}\\verb@#pydocsign#@{}}',
  329. {hasnote: '--- #note#'}]},
  330. 'latexdocstrout': {isintent_out: ['\\item[]{{}\\verb@#pydocsignout#@{}}',
  331. {l_and(hasnote, isintent_hide): '--- #note#',
  332. l_and(hasnote, isintent_nothide): '--- See above.'}]},
  333. 'docsign': {l_and(isrequired, isintent_nothide): '#varname#,'},
  334. 'docsignopt': {l_and(isoptional, isintent_nothide): '#varname#,'},
  335. 'depend': ''
  336. },
  337. {
  338. 'args': {
  339. l_and(isscalar, isintent_c): '#ctype# #varname_i#',
  340. l_and(isscalar, l_not(isintent_c)): '#ctype# *#varname_i#_cb_capi',
  341. isarray: '#ctype# *#varname_i#',
  342. isstring: '#ctype# #varname_i#'
  343. },
  344. 'args_nm': {
  345. l_and(isscalar, isintent_c): '#varname_i#',
  346. l_and(isscalar, l_not(isintent_c)): '#varname_i#_cb_capi',
  347. isarray: '#varname_i#',
  348. isstring: '#varname_i#'
  349. },
  350. 'args_td': {
  351. l_and(isscalar, isintent_c): '#ctype#',
  352. l_and(isscalar, l_not(isintent_c)): '#ctype# *',
  353. isarray: '#ctype# *',
  354. isstring: '#ctype#'
  355. },
  356. 'need': {l_or(isscalar, isarray, isstring): '#ctype#'},
  357. # untested with multiple args
  358. 'strarglens': {isstring: ',int #varname_i#_cb_len'},
  359. 'strarglens_td': {isstring: ',int'}, # untested with multiple args
  360. # untested with multiple args
  361. 'strarglens_nm': {isstring: ',#varname_i#_cb_len'},
  362. },
  363. { # Scalars
  364. 'decl': {l_not(isintent_c): ' #ctype# #varname_i#=(*#varname_i#_cb_capi);'},
  365. 'error': {l_and(isintent_c, isintent_out,
  366. throw_error('intent(c,out) is forbidden for callback scalar arguments')):
  367. ''},
  368. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
  369. {isintent_out:
  370. ' if (capi_j>capi_i)\n GETSCALARFROMPYTUPLE(capi_return,capi_i++,#varname_i#_cb_capi,#ctype#,"#ctype#_from_pyobj failed in converting argument #varname# of call-back function #name# to C #ctype#\\n");'},
  371. {l_and(debugcapi, l_and(l_not(iscomplex), isintent_c)):
  372. ' fprintf(stderr,"#showvalueformat#.\\n",#varname_i#);'},
  373. {l_and(debugcapi, l_and(l_not(iscomplex), l_not( isintent_c))):
  374. ' fprintf(stderr,"#showvalueformat#.\\n",*#varname_i#_cb_capi);'},
  375. {l_and(debugcapi, l_and(iscomplex, isintent_c)):
  376. ' fprintf(stderr,"#showvalueformat#.\\n",(#varname_i#).r,(#varname_i#).i);'},
  377. {l_and(debugcapi, l_and(iscomplex, l_not( isintent_c))):
  378. ' fprintf(stderr,"#showvalueformat#.\\n",(*#varname_i#_cb_capi).r,(*#varname_i#_cb_capi).i);'},
  379. ],
  380. 'need': [{isintent_out: ['#ctype#_from_pyobj', 'GETSCALARFROMPYTUPLE']},
  381. {debugcapi: 'CFUNCSMESS'}],
  382. '_check': isscalar
  383. }, {
  384. 'pyobjfrom': [{isintent_in: """\
  385. if (cb->nofargs>capi_i)
  386. if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1(#varname_i#)))
  387. goto capi_fail;"""},
  388. {isintent_inout: """\
  389. if (cb->nofargs>capi_i)
  390. if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#_cb_capi)))
  391. goto capi_fail;"""}],
  392. 'need': [{isintent_in: 'pyobj_from_#ctype#1'},
  393. {isintent_inout: 'pyarr_from_p_#ctype#1'},
  394. {iscomplex: '#ctype#'}],
  395. '_check': l_and(isscalar, isintent_nothide),
  396. '_optional': ''
  397. }, { # String
  398. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->\\"");'},
  399. """ if (capi_j>capi_i)
  400. GETSTRFROMPYTUPLE(capi_return,capi_i++,#varname_i#,#varname_i#_cb_len);""",
  401. {debugcapi:
  402. ' fprintf(stderr,"#showvalueformat#\\":%d:.\\n",#varname_i#,#varname_i#_cb_len);'},
  403. ],
  404. 'need': ['#ctype#', 'GETSTRFROMPYTUPLE',
  405. {debugcapi: 'CFUNCSMESS'}, 'string.h'],
  406. '_check': l_and(isstring, isintent_out)
  407. }, {
  408. 'pyobjfrom': [
  409. {debugcapi:
  410. (' fprintf(stderr,"debug-capi:cb:#varname#=#showvalueformat#:'
  411. '%d:\\n",#varname_i#,#varname_i#_cb_len);')},
  412. {isintent_in: """\
  413. if (cb->nofargs>capi_i)
  414. if (CAPI_ARGLIST_SETITEM(capi_i++,pyobj_from_#ctype#1size(#varname_i#,#varname_i#_cb_len)))
  415. goto capi_fail;"""},
  416. {isintent_inout: """\
  417. if (cb->nofargs>capi_i) {
  418. int #varname_i#_cb_dims[] = {#varname_i#_cb_len};
  419. if (CAPI_ARGLIST_SETITEM(capi_i++,pyarr_from_p_#ctype#1(#varname_i#,#varname_i#_cb_dims)))
  420. goto capi_fail;
  421. }"""}],
  422. 'need': [{isintent_in: 'pyobj_from_#ctype#1size'},
  423. {isintent_inout: 'pyarr_from_p_#ctype#1'}],
  424. '_check': l_and(isstring, isintent_nothide),
  425. '_optional': ''
  426. },
  427. # Array ...
  428. {
  429. 'decl': ' npy_intp #varname_i#_Dims[#rank#] = {#rank*[-1]#};',
  430. 'setdims': ' #cbsetdims#;',
  431. '_check': isarray,
  432. '_depend': ''
  433. },
  434. {
  435. 'pyobjfrom': [{debugcapi: ' fprintf(stderr,"debug-capi:cb:#varname#\\n");'},
  436. {isintent_c: """\
  437. if (cb->nofargs>capi_i) {
  438. /* tmp_arr will be inserted to capi_arglist_list that will be
  439. destroyed when leaving callback function wrapper together
  440. with tmp_arr. */
  441. PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
  442. #rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
  443. NPY_ARRAY_CARRAY,NULL);
  444. """,
  445. l_not(isintent_c): """\
  446. if (cb->nofargs>capi_i) {
  447. /* tmp_arr will be inserted to capi_arglist_list that will be
  448. destroyed when leaving callback function wrapper together
  449. with tmp_arr. */
  450. PyArrayObject *tmp_arr = (PyArrayObject *)PyArray_New(&PyArray_Type,
  451. #rank#,#varname_i#_Dims,#atype#,NULL,(char*)#varname_i#,#elsize#,
  452. NPY_ARRAY_FARRAY,NULL);
  453. """,
  454. },
  455. """
  456. if (tmp_arr==NULL)
  457. goto capi_fail;
  458. if (CAPI_ARGLIST_SETITEM(capi_i++,(PyObject *)tmp_arr))
  459. goto capi_fail;
  460. }"""],
  461. '_check': l_and(isarray, isintent_nothide, l_or(isintent_in, isintent_inout)),
  462. '_optional': '',
  463. }, {
  464. 'frompyobj': [{debugcapi: ' CFUNCSMESS("cb:Getting #varname#->");'},
  465. """ if (capi_j>capi_i) {
  466. PyArrayObject *rv_cb_arr = NULL;
  467. if ((capi_tmp = PyTuple_GetItem(capi_return,capi_i++))==NULL) goto capi_fail;
  468. rv_cb_arr = array_from_pyobj(#atype#,#varname_i#_Dims,#rank#,F2PY_INTENT_IN""",
  469. {isintent_c: '|F2PY_INTENT_C'},
  470. """,capi_tmp);
  471. if (rv_cb_arr == NULL) {
  472. fprintf(stderr,\"rv_cb_arr is NULL\\n\");
  473. goto capi_fail;
  474. }
  475. MEMCOPY(#varname_i#,PyArray_DATA(rv_cb_arr),PyArray_NBYTES(rv_cb_arr));
  476. if (capi_tmp != (PyObject *)rv_cb_arr) {
  477. Py_DECREF(rv_cb_arr);
  478. }
  479. }""",
  480. {debugcapi: ' fprintf(stderr,"<-.\\n");'},
  481. ],
  482. 'need': ['MEMCOPY', {iscomplexarray: '#ctype#'}],
  483. '_check': l_and(isarray, isintent_out)
  484. }, {
  485. 'docreturn': '#varname#,',
  486. '_check': isintent_out
  487. }
  488. ]
  489. ################## Build call-back module #############
  490. cb_map = {}
  491. def buildcallbacks(m):
  492. cb_map[m['name']] = []
  493. for bi in m['body']:
  494. if bi['block'] == 'interface':
  495. for b in bi['body']:
  496. if b:
  497. buildcallback(b, m['name'])
  498. else:
  499. errmess('warning: empty body for %s\n' % (m['name']))
  500. def buildcallback(rout, um):
  501. from . import capi_maps
  502. outmess(' Constructing call-back function "cb_%s_in_%s"\n' %
  503. (rout['name'], um))
  504. args, depargs = getargs(rout)
  505. capi_maps.depargs = depargs
  506. var = rout['vars']
  507. vrd = capi_maps.cb_routsign2map(rout, um)
  508. rd = dictappend({}, vrd)
  509. cb_map[um].append([rout['name'], rd['name']])
  510. for r in cb_rout_rules:
  511. if ('_check' in r and r['_check'](rout)) or ('_check' not in r):
  512. ar = applyrules(r, vrd, rout)
  513. rd = dictappend(rd, ar)
  514. savevrd = {}
  515. for i, a in enumerate(args):
  516. vrd = capi_maps.cb_sign2map(a, var[a], index=i)
  517. savevrd[a] = vrd
  518. for r in cb_arg_rules:
  519. if '_depend' in r:
  520. continue
  521. if '_optional' in r and isoptional(var[a]):
  522. continue
  523. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  524. ar = applyrules(r, vrd, var[a])
  525. rd = dictappend(rd, ar)
  526. if '_break' in r:
  527. break
  528. for a in args:
  529. vrd = savevrd[a]
  530. for r in cb_arg_rules:
  531. if '_depend' in r:
  532. continue
  533. if ('_optional' not in r) or ('_optional' in r and isrequired(var[a])):
  534. continue
  535. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  536. ar = applyrules(r, vrd, var[a])
  537. rd = dictappend(rd, ar)
  538. if '_break' in r:
  539. break
  540. for a in depargs:
  541. vrd = savevrd[a]
  542. for r in cb_arg_rules:
  543. if '_depend' not in r:
  544. continue
  545. if '_optional' in r:
  546. continue
  547. if ('_check' in r and r['_check'](var[a])) or ('_check' not in r):
  548. ar = applyrules(r, vrd, var[a])
  549. rd = dictappend(rd, ar)
  550. if '_break' in r:
  551. break
  552. if 'args' in rd and 'optargs' in rd:
  553. if isinstance(rd['optargs'], list):
  554. rd['optargs'] = rd['optargs'] + ["""
  555. #ifndef F2PY_CB_RETURNCOMPLEX
  556. ,
  557. #endif
  558. """]
  559. rd['optargs_nm'] = rd['optargs_nm'] + ["""
  560. #ifndef F2PY_CB_RETURNCOMPLEX
  561. ,
  562. #endif
  563. """]
  564. rd['optargs_td'] = rd['optargs_td'] + ["""
  565. #ifndef F2PY_CB_RETURNCOMPLEX
  566. ,
  567. #endif
  568. """]
  569. if isinstance(rd['docreturn'], list):
  570. rd['docreturn'] = stripcomma(
  571. replace('#docreturn#', {'docreturn': rd['docreturn']}))
  572. optargs = stripcomma(replace('#docsignopt#',
  573. {'docsignopt': rd['docsignopt']}
  574. ))
  575. if optargs == '':
  576. rd['docsignature'] = stripcomma(
  577. replace('#docsign#', {'docsign': rd['docsign']}))
  578. else:
  579. rd['docsignature'] = replace('#docsign#[#docsignopt#]',
  580. {'docsign': rd['docsign'],
  581. 'docsignopt': optargs,
  582. })
  583. rd['latexdocsignature'] = rd['docsignature'].replace('_', '\\_')
  584. rd['latexdocsignature'] = rd['latexdocsignature'].replace(',', ', ')
  585. rd['docstrsigns'] = []
  586. rd['latexdocstrsigns'] = []
  587. for k in ['docstrreq', 'docstropt', 'docstrout', 'docstrcbs']:
  588. if k in rd and isinstance(rd[k], list):
  589. rd['docstrsigns'] = rd['docstrsigns'] + rd[k]
  590. k = 'latex' + k
  591. if k in rd and isinstance(rd[k], list):
  592. rd['latexdocstrsigns'] = rd['latexdocstrsigns'] + rd[k][0:1] +\
  593. ['\\begin{description}'] + rd[k][1:] +\
  594. ['\\end{description}']
  595. if 'args' not in rd:
  596. rd['args'] = ''
  597. rd['args_td'] = ''
  598. rd['args_nm'] = ''
  599. if not (rd.get('args') or rd.get('optargs') or rd.get('strarglens')):
  600. rd['noargs'] = 'void'
  601. ar = applyrules(cb_routine_rules, rd)
  602. cfuncs.callbacks[rd['name']] = ar['body']
  603. if isinstance(ar['need'], str):
  604. ar['need'] = [ar['need']]
  605. if 'need' in rd:
  606. for t in cfuncs.typedefs.keys():
  607. if t in rd['need']:
  608. ar['need'].append(t)
  609. cfuncs.typedefs_generated[rd['name'] + '_typedef'] = ar['cbtypedefs']
  610. ar['need'].append(rd['name'] + '_typedef')
  611. cfuncs.needs[rd['name']] = ar['need']
  612. capi_maps.lcb2_map[rd['name']] = {'maxnofargs': ar['maxnofargs'],
  613. 'nofoptargs': ar['nofoptargs'],
  614. 'docstr': ar['docstr'],
  615. 'latexdocstr': ar['latexdocstr'],
  616. 'argname': rd['argname']
  617. }
  618. outmess(' %s\n' % (ar['docstrshort']))
  619. return
  620. ################## Build call-back function #############