codekingpro/portable-devtools
115k
1"""
2Copyright 1999 -- 2011 Pearu Peterson all rights reserved.
3Copyright 2011 -- present NumPy Developers.
4Permission to use, modify, and distribute this software is given under the
5terms of the NumPy License.
6
7NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8"""
9from . import __version__
10
11f2py_version = __version__.version
12
13import copy
14import os
15import re
16
17from . import cb_rules
18from ._isocbind import iso_c2py_map, iso_c_binding_map, isoc_c2pycode_map
19
20# The environment provided by auxfuncs.py is needed for some calls to eval.
21# As the needed functions cannot be determined by static inspection of the
22# code, it is safest to use import * pending a major refactoring of f2py.
23from .auxfuncs import *
24from .crackfortran import markoutercomma
25
26__all__ = [
27 'getctype', 'getstrlength', 'getarrdims', 'getpydocsign',
28 'getarrdocsign', 'getinit', 'sign2map', 'routsign2map', 'modsign2map',
29 'cb_sign2map', 'cb_routsign2map', 'common_sign2map', 'process_f2cmap_dict'
30]
31
32
33depargs = []
34lcb_map = {}
35lcb2_map = {}
36# forced casting: mainly caused by the fact that Python or Numeric
37# C/APIs do not support the corresponding C types.
38c2py_map = {'double': 'float',
39 'float': 'float', # forced casting
40 'long_double': 'float', # forced casting
41 'char': 'int', # forced casting
42 'signed_char': 'int', # forced casting
43 'unsigned_char': 'int', # forced casting
44 'short': 'int', # forced casting
45 'unsigned_short': 'int', # forced casting
46 'int': 'int', # forced casting
47 'long': 'int',
48 'long_long': 'long',
49 'unsigned': 'int', # forced casting
50 'complex_float': 'complex', # forced casting
51 'complex_double': 'complex',
52 'complex_long_double': 'complex', # forced casting
53 'string': 'string',
54 'character': 'bytes',
55 }
56
57c2capi_map = {'double': 'NPY_DOUBLE',
58 'float': 'NPY_FLOAT',
59 'long_double': 'NPY_LONGDOUBLE',
60 'char': 'NPY_BYTE',
61 'unsigned_char': 'NPY_UBYTE',
62 'signed_char': 'NPY_BYTE',
63 'short': 'NPY_SHORT',
64 'unsigned_short': 'NPY_USHORT',
65 'int': 'NPY_INT',
66 'unsigned': 'NPY_UINT',
67 'long': 'NPY_LONG',
68 'unsigned_long': 'NPY_ULONG',
69 'long_long': 'NPY_LONGLONG',
70 'unsigned_long_long': 'NPY_ULONGLONG',
71 'complex_float': 'NPY_CFLOAT',
72 'complex_double': 'NPY_CDOUBLE',
73 'complex_long_double': 'NPY_CDOUBLE',
74 'string': 'NPY_STRING',
75 'character': 'NPY_STRING'}
76
77c2pycode_map = {'double': 'd',
78 'float': 'f',
79 'long_double': 'g',
80 'char': 'b',
81 'unsigned_char': 'B',
82 'signed_char': 'b',
83 'short': 'h',
84 'unsigned_short': 'H',
85 'int': 'i',
86 'unsigned': 'I',
87 'long': 'l',
88 'unsigned_long': 'L',
89 'long_long': 'q',
90 'unsigned_long_long': 'Q',
91 'complex_float': 'F',
92 'complex_double': 'D',
93 'complex_long_double': 'G',
94 'string': 'S',
95 'character': 'c'}
96
97# https://docs.python.org/3/c-api/arg.html#building-values
98c2buildvalue_map = {'double': 'd',
99 'float': 'f',
100 'char': 'b',
101 'signed_char': 'b',
102 'short': 'h',
103 'int': 'i',
104 'long': 'l',
105 'long_long': 'L',
106 'complex_float': 'N',
107 'complex_double': 'N',
108 'complex_long_double': 'N',
109 'string': 'y',
110 'character': 'c'}
111
112f2cmap_all = {'real': {'': 'float', '4': 'float', '8': 'double',
113 '12': 'long_double', '16': 'long_double'},
114 'integer': {'': 'int', '1': 'signed_char', '2': 'short',
115 '4': 'int', '8': 'long_long',
116 '-1': 'unsigned_char', '-2': 'unsigned_short',
117 '-4': 'unsigned', '-8': 'unsigned_long_long'},
118 'complex': {'': 'complex_float', '8': 'complex_float',
119 '16': 'complex_double', '24': 'complex_long_double',
120 '32': 'complex_long_double'},
121 'complexkind': {'': 'complex_float', '4': 'complex_float',
122 '8': 'complex_double', '12': 'complex_long_double',
123 '16': 'complex_long_double'},
124 'logical': {'': 'int', '1': 'char', '2': 'short', '4': 'int',
125 '8': 'long_long'},
126 'double complex': {'': 'complex_double'},
127 'double precision': {'': 'double'},
128 'byte': {'': 'char'},
129 }
130
131# Add ISO_C handling
132c2pycode_map.update(isoc_c2pycode_map)
133c2py_map.update(iso_c2py_map)
134f2cmap_all, _ = process_f2cmap_dict(f2cmap_all, iso_c_binding_map, c2py_map)
135# End ISO_C handling
136f2cmap_default = copy.deepcopy(f2cmap_all)
137
138f2cmap_mapped = []
139
140def load_f2cmap_file(f2cmap_file):
141 global f2cmap_all, f2cmap_mapped
142
143 f2cmap_all = copy.deepcopy(f2cmap_default)
144
145 if f2cmap_file is None:
146 # Default value
147 f2cmap_file = '.f2py_f2cmap'
148 if not os.path.isfile(f2cmap_file):
149 return
150
151 # User defined additions to f2cmap_all.
152 # f2cmap_file must contain a dictionary of dictionaries, only. For
153 # example, {'real':{'low':'float'}} means that Fortran 'real(low)' is
154 # interpreted as C 'float'. This feature is useful for F90/95 users if
155 # they use PARAMETERS in type specifications.
156 try:
157 outmess(f'Reading f2cmap from {f2cmap_file!r} ...\n')
158 with open(f2cmap_file) as f:
159 d = eval(f.read().lower(), {}, {})
160 f2cmap_all, f2cmap_mapped = process_f2cmap_dict(f2cmap_all, d, c2py_map, True)
161 outmess('Successfully applied user defined f2cmap changes\n')
162 except Exception as msg:
163 errmess(f'Failed to apply user defined f2cmap changes: {msg}. Skipping.\n')
164
165
166cformat_map = {'double': '%g',
167 'float': '%g',
168 'long_double': '%Lg',
169 'char': '%d',
170 'signed_char': '%d',
171 'unsigned_char': '%hhu',
172 'short': '%hd',
173 'unsigned_short': '%hu',
174 'int': '%d',
175 'unsigned': '%u',
176 'long': '%ld',
177 'unsigned_long': '%lu',
178 'long_long': '%ld',
179 'complex_float': '(%g,%g)',
180 'complex_double': '(%g,%g)',
181 'complex_long_double': '(%Lg,%Lg)',
182 'string': '\\"%s\\"',
183 'character': "'%c'",
184 }
185
186# Auxiliary functions
187
188
189def getctype(var):
190 """
191 Determines C type
192 """
193 ctype = 'void'
194 if isfunction(var):
195 if 'result' in var:
196 a = var['result']
197 else:
198 a = var['name']
199 if a in var['vars']:
200 return getctype(var['vars'][a])
201 else:
202 errmess(f'getctype: function {a} has no return value?!\n')
203 elif issubroutine(var):
204 return ctype
205 elif ischaracter_or_characterarray(var):
206 return 'character'
207 elif isstring_or_stringarray(var):
208 return 'string'
209 elif 'typespec' in var and var['typespec'].lower() in f2cmap_all:
210 typespec = var['typespec'].lower()
211 f2cmap = f2cmap_all[typespec]
212 ctype = f2cmap[''] # default type
213 if 'kindselector' in var:
214 if '*' in var['kindselector']:
215 try:
216 ctype = f2cmap[var['kindselector']['*']]
217 except KeyError:
218 errmess('getctype: "%s %s %s" not supported.\n' %
219 (var['typespec'], '*', var['kindselector']['*']))
220 elif 'kind' in var['kindselector']:
221 if typespec + 'kind' in f2cmap_all:
222 f2cmap = f2cmap_all[typespec + 'kind']
223 try:
224 ctype = f2cmap[var['kindselector']['kind']]
225 except KeyError:
226 if typespec in f2cmap_all:
227 f2cmap = f2cmap_all[typespec]
228 try:
229 ctype = f2cmap[str(var['kindselector']['kind'])]
230 except KeyError:
231 errmess('getctype: "%s(kind=%s)" is mapped to C "%s" (to override define dict(%s = dict(%s="<C typespec>")) in %s/.f2py_f2cmap file).\n'
232 % (typespec, var['kindselector']['kind'], ctype,
233 typespec, var['kindselector']['kind'], os.getcwd()))
234 elif not isexternal(var):
235 errmess(f'getctype: No C-type found in "{var}", assuming void.\n')
236 return ctype
237
238
239def f2cexpr(expr):
240 """Rewrite Fortran expression as f2py supported C expression.
241
242 Due to the lack of a proper expression parser in f2py, this
243 function uses a heuristic approach that assumes that Fortran
244 arithmetic expressions are valid C arithmetic expressions when
245 mapping Fortran function calls to the corresponding C function/CPP
246 macros calls.
247
248 """
249 # TODO: support Fortran `len` function with optional kind parameter
250 expr = re.sub(r'\blen\b', 'f2py_slen', expr)
251 return expr
252
253
254def getstrlength(var):
255 if isstringfunction(var):
256 if 'result' in var:
257 a = var['result']
258 else:
259 a = var['name']
260 if a in var['vars']:
261 return getstrlength(var['vars'][a])
262 else:
263 errmess(f'getstrlength: function {a} has no return value?!\n')
264 if not isstring(var):
265 errmess(
266 f'getstrlength: expected a signature of a string but got: {repr(var)}\n')
267 len = '1'
268 if 'charselector' in var:
269 a = var['charselector']
270 if '*' in a:
271 len = a['*']
272 elif 'len' in a:
273 len = f2cexpr(a['len'])
274 if re.match(r'\(\s*(\*|:)\s*\)', len) or re.match(r'(\*|:)', len):
275 if isintent_hide(var):
276 errmess('getstrlength:intent(hide): expected a string with defined length but got: %s\n' % (
277 repr(var)))
278 len = '-1'
279 return len
280
281
282def getarrdims(a, var, verbose=0):
283 ret = {}
284 if isstring(var) and not isarray(var):
285 ret['size'] = getstrlength(var)
286 ret['rank'] = '0'
287 ret['dims'] = ''
288 elif isscalar(var):
289 ret['size'] = '1'
290 ret['rank'] = '0'
291 ret['dims'] = ''
292 elif isarray(var):
293 dim = copy.copy(var['dimension'])
294 ret['size'] = '*'.join(dim)
295 try:
296 ret['size'] = repr(eval(ret['size']))
297 except Exception:
298 pass
299 ret['dims'] = ','.join(dim)
300 ret['rank'] = repr(len(dim))
301 ret['rank*[-1]'] = repr(len(dim) * [-1])[1:-1]
302 for i in range(len(dim)): # solve dim for dependencies
303 v = []
304 if dim[i] in depargs:
305 v = [dim[i]]
306 else:
307 for va in depargs:
308 if re.match(r'.*?\b%s\b.*' % va, dim[i]):
309 v.append(va)
310 for va in v:
311 if depargs.index(va) > depargs.index(a):
312 dim[i] = '*'
313 break
314 ret['setdims'], i = '', -1
315 for d in dim:
316 i = i + 1
317 if d not in ['*', ':', '(*)', '(:)']:
318 ret['setdims'] = '%s#varname#_Dims[%d]=%s,' % (
319 ret['setdims'], i, d)
320 if ret['setdims']:
321 ret['setdims'] = ret['setdims'][:-1]
322 ret['cbsetdims'], i = '', -1
323 for d in var['dimension']:
324 i = i + 1
325 if d not in ['*', ':', '(*)', '(:)']:
326 ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
327 ret['cbsetdims'], i, d)
328 elif isintent_in(var):
329 outmess('getarrdims:warning: assumed shape array, using 0 instead of %r\n'
330 % (d))
331 ret['cbsetdims'] = '%s#varname#_Dims[%d]=%s,' % (
332 ret['cbsetdims'], i, 0)
333 elif verbose:
334 errmess(
335 f'getarrdims: If in call-back function: array argument {repr(a)} must have bounded dimensions: got {repr(d)}\n')
336 if ret['cbsetdims']:
337 ret['cbsetdims'] = ret['cbsetdims'][:-1]
338# if not isintent_c(var):
339# var['dimension'].reverse()
340 return ret
341
342
343def getpydocsign(a, var):
344 global lcb_map
345 if isfunction(var):
346 if 'result' in var:
347 af = var['result']
348 else:
349 af = var['name']
350 if af in var['vars']:
351 return getpydocsign(af, var['vars'][af])
352 else:
353 errmess(f'getctype: function {af} has no return value?!\n')
354 return '', ''
355 sig, sigout = a, a
356 opt = ''
357 if isintent_in(var):
358 opt = 'input'
359 elif isintent_inout(var):
360 opt = 'in/output'
361 out_a = a
362 if isintent_out(var):
363 for k in var['intent']:
364 if k[:4] == 'out=':
365 out_a = k[4:]
366 break
367 init = ''
368 ctype = getctype(var)
369
370 if hasinitvalue(var):
371 init, showinit = getinit(a, var)
372 init = f', optional\\n Default: {showinit}'
373 if isscalar(var):
374 if isintent_inout(var):
375 sig = '%s : %s rank-0 array(%s,\'%s\')%s' % (a, opt, c2py_map[ctype],
376 c2pycode_map[ctype], init)
377 else:
378 sig = f'{a} : {opt} {c2py_map[ctype]}{init}'
379 sigout = f'{out_a} : {c2py_map[ctype]}'
380 elif isstring(var):
381 if isintent_inout(var):
382 sig = '%s : %s rank-0 array(string(len=%s),\'c\')%s' % (
383 a, opt, getstrlength(var), init)
384 else:
385 sig = f'{a} : {opt} string(len={getstrlength(var)}){init}'
386 sigout = f'{out_a} : string(len={getstrlength(var)})'
387 elif isarray(var):
388 dim = var['dimension']
389 rank = repr(len(dim))
390 sig = '%s : %s rank-%s array(\'%s\') with bounds (%s)%s' % (a, opt, rank,
391 c2pycode_map[
392 ctype],
393 ','.join(dim), init)
394 if a == out_a:
395 sigout = '%s : rank-%s array(\'%s\') with bounds (%s)'\
396 % (a, rank, c2pycode_map[ctype], ','.join(dim))
397 else:
398 sigout = '%s : rank-%s array(\'%s\') with bounds (%s) and %s storage'\
399 % (out_a, rank, c2pycode_map[ctype], ','.join(dim), a)
400 elif isexternal(var):
401 ua = ''
402 if a in lcb_map and lcb_map[a] in lcb2_map and 'argname' in lcb2_map[lcb_map[a]]:
403 ua = lcb2_map[lcb_map[a]]['argname']
404 if not ua == a:
405 ua = f' => {ua}'
406 else:
407 ua = ''
408 sig = f'{a} : call-back function{ua}'
409 sigout = sig
410 else:
411 errmess(
412 f'getpydocsign: Could not resolve docsignature for "{a}".\n')
413 return sig, sigout
414
415
416def getarrdocsign(a, var):
417 ctype = getctype(var)
418 if isstring(var) and (not isarray(var)):
419 sig = f'{a} : rank-0 array(string(len={getstrlength(var)}),\'c\')'
420 elif isscalar(var):
421 sig = f'{a} : rank-0 array({c2py_map[ctype]},\'{c2pycode_map[ctype]}\')'
422 elif isarray(var):
423 dim = var['dimension']
424 rank = repr(len(dim))
425 sig = '%s : rank-%s array(\'%s\') with bounds (%s)' % (a, rank,
426 c2pycode_map[
427 ctype],
428 ','.join(dim))
429 return sig
430
431
432def getinit(a, var):
433 if isstring(var):
434 init, showinit = '""', "''"
435 else:
436 init, showinit = '', ''
437 if hasinitvalue(var):
438 init = var['=']
439 showinit = init
440 if iscomplex(var) or iscomplexarray(var):
441 ret = {}
442
443 try:
444 v = var["="]
445 if ',' in v:
446 ret['init.r'], ret['init.i'] = markoutercomma(
447 v[1:-1]).split('@,@')
448 else:
449 v = eval(v, {}, {})
450 ret['init.r'], ret['init.i'] = str(v.real), str(v.imag)
451 except Exception:
452 raise ValueError(
453 f'getinit: expected complex number `(r,i)\' but got `{init}\' as initial value of {a!r}.')
454 if isarray(var):
455 init = f"(capi_c.r={ret['init.r']},capi_c.i={ret['init.i']},capi_c)"
456 elif isstring(var):
457 if not init:
458 init, showinit = '""', "''"
459 if init[0] == "'":
460 init = '"%s"' % (init[1:-1].replace('"', '\\"'))
461 if init[0] == '"':
462 showinit = f"'{init[1:-1]}'"
463 return init, showinit
464
465
466def get_elsize(var):
467 if isstring(var) or isstringarray(var):
468 elsize = getstrlength(var)
469 # override with user-specified length when available:
470 elsize = var['charselector'].get('f2py_len', elsize)
471 return elsize
472 if ischaracter(var) or ischaracterarray(var):
473 return '1'
474 # for numerical types, PyArray_New* functions ignore specified
475 # elsize, so we just return 1 and let elsize be determined at
476 # runtime, see fortranobject.c
477 return '1'
478
479
480def sign2map(a, var):
481 """
482 varname,ctype,atype
483 init,init.r,init.i,pytype
484 vardebuginfo,vardebugshowvalue,varshowvalue
485 varrformat
486
487 intent
488 """
489 out_a = a
490 if isintent_out(var):
491 for k in var['intent']:
492 if k[:4] == 'out=':
493 out_a = k[4:]
494 break
495 ret = {'varname': a, 'outvarname': out_a, 'ctype': getctype(var)}
496 intent_flags = []
497 for f, s in isintent_dict.items():
498 if f(var):
499 intent_flags.append(f'F2PY_{s}')
500 if intent_flags:
501 # TODO: Evaluate intent_flags here.
502 ret['intent'] = '|'.join(intent_flags)
503 else:
504 ret['intent'] = 'F2PY_INTENT_IN'
505 if isarray(var):
506 ret['varrformat'] = 'N'
507 elif ret['ctype'] in c2buildvalue_map:
508 ret['varrformat'] = c2buildvalue_map[ret['ctype']]
509 else:
510 ret['varrformat'] = 'O'
511 ret['init'], ret['showinit'] = getinit(a, var)
512 if hasinitvalue(var) and iscomplex(var) and not isarray(var):
513 ret['init.r'], ret['init.i'] = markoutercomma(
514 ret['init'][1:-1]).split('@,@')
515 if isexternal(var):
516 ret['cbnamekey'] = a
517 if a in lcb_map:
518 ret['cbname'] = lcb_map[a]
519 ret['maxnofargs'] = lcb2_map[lcb_map[a]]['maxnofargs']
520 ret['nofoptargs'] = lcb2_map[lcb_map[a]]['nofoptargs']
521 ret['cbdocstr'] = lcb2_map[lcb_map[a]]['docstr']
522 ret['cblatexdocstr'] = lcb2_map[lcb_map[a]]['latexdocstr']
523 else:
524 ret['cbname'] = a
525 errmess('sign2map: Confused: external %s is not in lcb_map%s.\n' % (
526 a, list(lcb_map.keys())))
527 if isstring(var):
528 ret['length'] = getstrlength(var)
529 if isarray(var):
530 ret = dictappend(ret, getarrdims(a, var))
531 dim = copy.copy(var['dimension'])
532 if ret['ctype'] in c2capi_map:
533 ret['atype'] = c2capi_map[ret['ctype']]
534 ret['elsize'] = get_elsize(var)
535 # Debug info
536 if debugcapi(var):
537 il = [isintent_in, 'input', isintent_out, 'output',
538 isintent_inout, 'inoutput', isrequired, 'required',
539 isoptional, 'optional', isintent_hide, 'hidden',
540 iscomplex, 'complex scalar',
541 l_and(isscalar, l_not(iscomplex)), 'scalar',
542 isstring, 'string', isarray, 'array',
543 iscomplexarray, 'complex array', isstringarray, 'string array',
544 iscomplexfunction, 'complex function',
545 l_and(isfunction, l_not(iscomplexfunction)), 'function',
546 isexternal, 'callback',
547 isintent_callback, 'callback',
548 isintent_aux, 'auxiliary',
549 ]
550 rl = []
551 for i in range(0, len(il), 2):
552 if il[i](var):
553 rl.append(il[i + 1])
554 if isstring(var):
555 rl.append(f"slen({a})={ret['length']}")
556 if isarray(var):
557 ddim = ','.join(
558 map(lambda x, y: f'{x}|{y}', var['dimension'], dim))
559 rl.append(f'dims({ddim})')
560 if isexternal(var):
561 ret['vardebuginfo'] = f"debug-capi:{a}=>{ret['cbname']}:{','.join(rl)}"
562 else:
563 ret['vardebuginfo'] = 'debug-capi:%s %s=%s:%s' % (
564 ret['ctype'], a, ret['showinit'], ','.join(rl))
565 if isscalar(var):
566 if ret['ctype'] in cformat_map:
567 ret['vardebugshowvalue'] = f"debug-capi:{a}={cformat_map[ret['ctype']]}"
568 if isstring(var):
569 ret['vardebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
570 a, a)
571 if isexternal(var):
572 ret['vardebugshowvalue'] = f'debug-capi:{a}=%p'
573 if ret['ctype'] in cformat_map:
574 ret['varshowvalue'] = f"#name#:{a}={cformat_map[ret['ctype']]}"
575 ret['showvalueformat'] = f"{cformat_map[ret['ctype']]}"
576 if isstring(var):
577 ret['varshowvalue'] = '#name#:slen(%s)=%%d %s=\\"%%s\\"' % (a, a)
578 ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
579 if hasnote(var):
580 ret['note'] = var['note']
581 return ret
582
583
584def routsign2map(rout):
585 """
586 name,NAME,begintitle,endtitle
587 rname,ctype,rformat
588 routdebugshowvalue
589 """
590 global lcb_map
591 name = rout['name']
592 fname = getfortranname(rout)
593 ret = {'name': name,
594 'texname': name.replace('_', '\\_'),
595 'name_lower': name.lower(),
596 'NAME': name.upper(),
597 'begintitle': gentitle(name),
598 'endtitle': gentitle(f'end of {name}'),
599 'fortranname': fname,
600 'FORTRANNAME': fname.upper(),
601 'callstatement': getcallstatement(rout) or '',
602 'usercode': getusercode(rout) or '',
603 'usercode1': getusercode1(rout) or '',
604 }
605 if '_' in fname:
606 ret['F_FUNC'] = 'F_FUNC_US'
607 else:
608 ret['F_FUNC'] = 'F_FUNC'
609 if '_' in name:
610 ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC_US'
611 else:
612 ret['F_WRAPPEDFUNC'] = 'F_WRAPPEDFUNC'
613 lcb_map = {}
614 if 'use' in rout:
615 for u in rout['use'].keys():
616 if u in cb_rules.cb_map:
617 for un in cb_rules.cb_map[u]:
618 ln = un[0]
619 if 'map' in rout['use'][u]:
620 for k in rout['use'][u]['map'].keys():
621 if rout['use'][u]['map'][k] == un[0]:
622 ln = k
623 break
624 lcb_map[ln] = un[1]
625 elif rout.get('externals'):
626 errmess('routsign2map: Confused: function %s has externals %s but no "use" statement.\n' % (
627 ret['name'], repr(rout['externals'])))
628 ret['callprotoargument'] = getcallprotoargument(rout, lcb_map) or ''
629 if isfunction(rout):
630 if 'result' in rout:
631 a = rout['result']
632 else:
633 a = rout['name']
634 ret['rname'] = a
635 ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
636 ret['ctype'] = getctype(rout['vars'][a])
637 if hasresultnote(rout):
638 ret['resultnote'] = rout['vars'][a]['note']
639 rout['vars'][a]['note'] = ['See elsewhere.']
640 if ret['ctype'] in c2buildvalue_map:
641 ret['rformat'] = c2buildvalue_map[ret['ctype']]
642 else:
643 ret['rformat'] = 'O'
644 errmess('routsign2map: no c2buildvalue key for type %s\n' %
645 (repr(ret['ctype'])))
646 if debugcapi(rout):
647 if ret['ctype'] in cformat_map:
648 ret['routdebugshowvalue'] = 'debug-capi:%s=%s' % (
649 a, cformat_map[ret['ctype']])
650 if isstringfunction(rout):
651 ret['routdebugshowvalue'] = 'debug-capi:slen(%s)=%%d %s=\\"%%s\\"' % (
652 a, a)
653 if isstringfunction(rout):
654 ret['rlength'] = getstrlength(rout['vars'][a])
655 if ret['rlength'] == '-1':
656 errmess('routsign2map: expected explicit specification of the length of the string returned by the fortran function %s; taking 10.\n' % (
657 repr(rout['name'])))
658 ret['rlength'] = '10'
659 if hasnote(rout):
660 ret['note'] = rout['note']
661 rout['note'] = ['See elsewhere.']
662 return ret
663
664
665def modsign2map(m):
666 """
667 modulename
668 """
669 if ismodule(m):
670 ret = {'f90modulename': m['name'],
671 'F90MODULENAME': m['name'].upper(),
672 'texf90modulename': m['name'].replace('_', '\\_')}
673 else:
674 ret = {'modulename': m['name'],
675 'MODULENAME': m['name'].upper(),
676 'texmodulename': m['name'].replace('_', '\\_')}
677 ret['restdoc'] = getrestdoc(m) or []
678 if hasnote(m):
679 ret['note'] = m['note']
680 ret['usercode'] = getusercode(m) or ''
681 ret['usercode1'] = getusercode1(m) or ''
682 if m['body']:
683 ret['interface_usercode'] = getusercode(m['body'][0]) or ''
684 else:
685 ret['interface_usercode'] = ''
686 ret['pymethoddef'] = getpymethoddef(m) or ''
687 if 'gil_used' in m:
688 ret['gil_used'] = m['gil_used']
689 if 'coutput' in m:
690 ret['coutput'] = m['coutput']
691 if 'f2py_wrapper_output' in m:
692 ret['f2py_wrapper_output'] = m['f2py_wrapper_output']
693 return ret
694
695
696def cb_sign2map(a, var, index=None):
697 ret = {'varname': a}
698 ret['varname_i'] = ret['varname']
699 ret['ctype'] = getctype(var)
700 if ret['ctype'] in c2capi_map:
701 ret['atype'] = c2capi_map[ret['ctype']]
702 ret['elsize'] = get_elsize(var)
703 if ret['ctype'] in cformat_map:
704 ret['showvalueformat'] = f"{cformat_map[ret['ctype']]}"
705 if isarray(var):
706 ret = dictappend(ret, getarrdims(a, var))
707 ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
708 if hasnote(var):
709 ret['note'] = var['note']
710 var['note'] = ['See elsewhere.']
711 return ret
712
713
714def cb_routsign2map(rout, um):
715 """
716 name,begintitle,endtitle,argname
717 ctype,rctype,maxnofargs,nofoptargs,returncptr
718 """
719 ret = {'name': f"cb_{rout['name']}_in_{um}",
720 'returncptr': ''}
721 if isintent_callback(rout):
722 if '_' in rout['name']:
723 F_FUNC = 'F_FUNC_US'
724 else:
725 F_FUNC = 'F_FUNC'
726 ret['callbackname'] = f"{F_FUNC}({rout['name'].lower()},{rout['name'].upper()})"
727 ret['static'] = 'extern'
728 else:
729 ret['callbackname'] = ret['name']
730 ret['static'] = 'static'
731 ret['argname'] = rout['name']
732 ret['begintitle'] = gentitle(ret['name'])
733 ret['endtitle'] = gentitle(f"end of {ret['name']}")
734 ret['ctype'] = getctype(rout)
735 ret['rctype'] = 'void'
736 if ret['ctype'] == 'string':
737 ret['rctype'] = 'void'
738 else:
739 ret['rctype'] = ret['ctype']
740 if ret['rctype'] != 'void':
741 if iscomplexfunction(rout):
742 ret['returncptr'] = """
743#ifdef F2PY_CB_RETURNCOMPLEX
744return_value=
745#endif
746"""
747 else:
748 ret['returncptr'] = 'return_value='
749 if ret['ctype'] in cformat_map:
750 ret['showvalueformat'] = f"{cformat_map[ret['ctype']]}"
751 if isstringfunction(rout):
752 ret['strlength'] = getstrlength(rout)
753 if isfunction(rout):
754 if 'result' in rout:
755 a = rout['result']
756 else:
757 a = rout['name']
758 if hasnote(rout['vars'][a]):
759 ret['note'] = rout['vars'][a]['note']
760 rout['vars'][a]['note'] = ['See elsewhere.']
761 ret['rname'] = a
762 ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, rout)
763 if iscomplexfunction(rout):
764 ret['rctype'] = """
765#ifdef F2PY_CB_RETURNCOMPLEX
766#ctype#
767#else
768void
769#endif
770"""
771 elif hasnote(rout):
772 ret['note'] = rout['note']
773 rout['note'] = ['See elsewhere.']
774 nofargs = 0
775 nofoptargs = 0
776 if 'args' in rout and 'vars' in rout:
777 for a in rout['args']:
778 var = rout['vars'][a]
779 if l_or(isintent_in, isintent_inout)(var):
780 nofargs = nofargs + 1
781 if isoptional(var):
782 nofoptargs = nofoptargs + 1
783 ret['maxnofargs'] = repr(nofargs)
784 ret['nofoptargs'] = repr(nofoptargs)
785 if hasnote(rout) and isfunction(rout) and 'result' in rout:
786 ret['routnote'] = rout['note']
787 rout['note'] = ['See elsewhere.']
788 return ret
789
790
791def common_sign2map(a, var): # obsolete
792 ret = {'varname': a, 'ctype': getctype(var)}
793 if isstringarray(var):
794 ret['ctype'] = 'char'
795 if ret['ctype'] in c2capi_map:
796 ret['atype'] = c2capi_map[ret['ctype']]
797 ret['elsize'] = get_elsize(var)
798 if ret['ctype'] in cformat_map:
799 ret['showvalueformat'] = f"{cformat_map[ret['ctype']]}"
800 if isarray(var):
801 ret = dictappend(ret, getarrdims(a, var))
802 elif isstring(var):
803 ret['size'] = getstrlength(var)
804 ret['rank'] = '1'
805 ret['pydocsign'], ret['pydocsignout'] = getpydocsign(a, var)
806 if hasnote(var):
807 ret['note'] = var['note']
808 var['note'] = ['See elsewhere.']
809 # for strings this returns 0-rank but actually is 1-rank
810 ret['arrdocstr'] = getarrdocsign(a, var)
811 return ret
812 