@pairling/runtime-darwin-x64 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +1 -1
  2. package/bin/pairling-connectd +0 -0
  3. package/manifest.json +4 -4
  4. package/package.json +3 -3
  5. package/python/bin/python3 +0 -0
  6. package/python/bin/python3.12 +0 -0
  7. package/python/lib/libpython3.12.dylib +0 -0
  8. package/python/lib/python3.12/lib-dynload/_crypt.cpython-312-darwin.so +0 -0
  9. package/python/lib/python3.12/lib-dynload/_dbm.cpython-312-darwin.so +0 -0
  10. package/python/lib/python3.12/site-packages/_cffi_backend.cpython-312-darwin.so +0 -0
  11. package/python/lib/python3.12/site-packages/cffi/__init__.py +14 -0
  12. package/python/lib/python3.12/site-packages/cffi/_cffi_errors.h +149 -0
  13. package/python/lib/python3.12/site-packages/cffi/_cffi_include.h +389 -0
  14. package/python/lib/python3.12/site-packages/cffi/_embedding.h +550 -0
  15. package/python/lib/python3.12/site-packages/cffi/_imp_emulation.py +83 -0
  16. package/python/lib/python3.12/site-packages/cffi/_shimmed_dist_utils.py +45 -0
  17. package/python/lib/python3.12/site-packages/cffi/api.py +967 -0
  18. package/python/lib/python3.12/site-packages/cffi/backend_ctypes.py +1121 -0
  19. package/python/lib/python3.12/site-packages/cffi/cffi_opcode.py +187 -0
  20. package/python/lib/python3.12/site-packages/cffi/commontypes.py +82 -0
  21. package/python/lib/python3.12/site-packages/cffi/cparser.py +1015 -0
  22. package/python/lib/python3.12/site-packages/cffi/error.py +31 -0
  23. package/python/lib/python3.12/site-packages/cffi/ffiplatform.py +113 -0
  24. package/python/lib/python3.12/site-packages/cffi/lock.py +30 -0
  25. package/python/lib/python3.12/site-packages/cffi/model.py +618 -0
  26. package/python/lib/python3.12/site-packages/cffi/parse_c_type.h +181 -0
  27. package/python/lib/python3.12/site-packages/cffi/pkgconfig.py +121 -0
  28. package/python/lib/python3.12/site-packages/cffi/recompiler.py +1598 -0
  29. package/python/lib/python3.12/site-packages/cffi/setuptools_ext.py +216 -0
  30. package/python/lib/python3.12/site-packages/cffi/vengine_cpy.py +1084 -0
  31. package/python/lib/python3.12/site-packages/cffi/vengine_gen.py +679 -0
  32. package/python/lib/python3.12/site-packages/cffi/verifier.py +306 -0
  33. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/INSTALLER +1 -0
  34. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/LICENSE +26 -0
  35. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/METADATA +40 -0
  36. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/RECORD +30 -0
  37. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/WHEEL +5 -0
  38. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/entry_points.txt +2 -0
  39. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/top_level.txt +2 -0
  40. package/python/lib/python3.12/site-packages/cryptography/__about__.py +17 -0
  41. package/python/lib/python3.12/site-packages/cryptography/__init__.py +26 -0
  42. package/python/lib/python3.12/site-packages/cryptography/exceptions.py +52 -0
  43. package/python/lib/python3.12/site-packages/cryptography/fernet.py +224 -0
  44. package/python/lib/python3.12/site-packages/cryptography/hazmat/__init__.py +13 -0
  45. package/python/lib/python3.12/site-packages/cryptography/hazmat/_oid.py +348 -0
  46. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/__init__.py +13 -0
  47. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/openssl/__init__.py +9 -0
  48. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/openssl/backend.py +308 -0
  49. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/__init__.py +3 -0
  50. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi +37 -0
  51. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi +8 -0
  52. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi +7 -0
  53. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi +17 -0
  54. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi +117 -0
  55. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +75 -0
  56. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi +107 -0
  57. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi +38 -0
  58. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi +18 -0
  59. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi +51 -0
  60. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi +41 -0
  61. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi +52 -0
  62. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +13 -0
  63. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +13 -0
  64. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi +28 -0
  65. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi +22 -0
  66. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +49 -0
  67. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi +34 -0
  68. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi +15 -0
  69. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi +55 -0
  70. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +13 -0
  71. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +13 -0
  72. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi +52 -0
  73. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi +50 -0
  74. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi +23 -0
  75. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +313 -0
  76. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust.abi3.so +0 -0
  77. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/__init__.py +3 -0
  78. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +191 -0
  79. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/binding.py +122 -0
  80. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/__init__.py +5 -0
  81. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py +5 -0
  82. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py +112 -0
  83. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/__init__.py +3 -0
  84. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_asymmetric.py +19 -0
  85. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py +60 -0
  86. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_serialization.py +168 -0
  87. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py +3 -0
  88. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py +147 -0
  89. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py +167 -0
  90. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py +447 -0
  91. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py +129 -0
  92. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py +131 -0
  93. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +113 -0
  94. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +277 -0
  95. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/types.py +111 -0
  96. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py +24 -0
  97. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py +122 -0
  98. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py +125 -0
  99. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py +27 -0
  100. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/aead.py +23 -0
  101. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +183 -0
  102. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/base.py +146 -0
  103. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/modes.py +268 -0
  104. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/cmac.py +10 -0
  105. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/constant_time.py +14 -0
  106. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/hashes.py +246 -0
  107. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/hmac.py +13 -0
  108. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/__init__.py +23 -0
  109. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/argon2.py +13 -0
  110. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +125 -0
  111. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +101 -0
  112. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +305 -0
  113. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +62 -0
  114. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py +19 -0
  115. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +61 -0
  116. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/keywrap.py +177 -0
  117. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/padding.py +69 -0
  118. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/poly1305.py +11 -0
  119. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +65 -0
  120. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/base.py +14 -0
  121. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +176 -0
  122. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +411 -0
  123. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +1619 -0
  124. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py +9 -0
  125. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +101 -0
  126. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +56 -0
  127. package/python/lib/python3.12/site-packages/cryptography/py.typed +0 -0
  128. package/python/lib/python3.12/site-packages/cryptography/utils.py +139 -0
  129. package/python/lib/python3.12/site-packages/cryptography/x509/__init__.py +270 -0
  130. package/python/lib/python3.12/site-packages/cryptography/x509/base.py +848 -0
  131. package/python/lib/python3.12/site-packages/cryptography/x509/certificate_transparency.py +35 -0
  132. package/python/lib/python3.12/site-packages/cryptography/x509/extensions.py +2528 -0
  133. package/python/lib/python3.12/site-packages/cryptography/x509/general_name.py +281 -0
  134. package/python/lib/python3.12/site-packages/cryptography/x509/name.py +477 -0
  135. package/python/lib/python3.12/site-packages/cryptography/x509/ocsp.py +379 -0
  136. package/python/lib/python3.12/site-packages/cryptography/x509/oid.py +37 -0
  137. package/python/lib/python3.12/site-packages/cryptography/x509/verification.py +34 -0
  138. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/INSTALLER +1 -0
  139. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/METADATA +139 -0
  140. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/RECORD +106 -0
  141. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/REQUESTED +0 -0
  142. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/WHEEL +4 -0
  143. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE +3 -0
  144. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE.APACHE +202 -0
  145. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE.BSD +27 -0
  146. package/python/lib/python3.12/site-packages/pycparser/__init__.py +99 -0
  147. package/python/lib/python3.12/site-packages/pycparser/_ast_gen.py +355 -0
  148. package/python/lib/python3.12/site-packages/pycparser/_c_ast.cfg +195 -0
  149. package/python/lib/python3.12/site-packages/pycparser/ast_transforms.py +174 -0
  150. package/python/lib/python3.12/site-packages/pycparser/c_ast.py +1341 -0
  151. package/python/lib/python3.12/site-packages/pycparser/c_generator.py +573 -0
  152. package/python/lib/python3.12/site-packages/pycparser/c_lexer.py +706 -0
  153. package/python/lib/python3.12/site-packages/pycparser/c_parser.py +2376 -0
  154. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/INSTALLER +1 -0
  155. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/METADATA +244 -0
  156. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/RECORD +14 -0
  157. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/WHEEL +5 -0
  158. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/licenses/LICENSE +27 -0
  159. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1015 @@
1
+ from . import model
2
+ from .commontypes import COMMON_TYPES, resolve_common_type
3
+ from .error import FFIError, CDefError
4
+ try:
5
+ from . import _pycparser as pycparser
6
+ except ImportError:
7
+ import pycparser
8
+ import weakref, re, sys
9
+
10
+ try:
11
+ if sys.version_info < (3,):
12
+ import thread as _thread
13
+ else:
14
+ import _thread
15
+ lock = _thread.allocate_lock()
16
+ except ImportError:
17
+ lock = None
18
+
19
+ def _workaround_for_static_import_finders():
20
+ # Issue #392: packaging tools like cx_Freeze can not find these
21
+ # because pycparser uses exec dynamic import. This is an obscure
22
+ # workaround. This function is never called.
23
+ import pycparser.yacctab
24
+ import pycparser.lextab
25
+
26
+ CDEF_SOURCE_STRING = "<cdef source string>"
27
+ _r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$",
28
+ re.DOTALL | re.MULTILINE)
29
+ _r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)"
30
+ r"\b((?:[^\n\\]|\\.)*?)$",
31
+ re.DOTALL | re.MULTILINE)
32
+ _r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE)
33
+ _r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}")
34
+ _r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$")
35
+ _r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]")
36
+ _r_words = re.compile(r"\w+|\S")
37
+ _parser_cache = None
38
+ _r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE)
39
+ _r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b")
40
+ _r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b")
41
+ _r_cdecl = re.compile(r"\b__cdecl\b")
42
+ _r_extern_python = re.compile(r'\bextern\s*"'
43
+ r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.')
44
+ _r_star_const_space = re.compile( # matches "* const "
45
+ r"[*]\s*((const|volatile|restrict)\b\s*)+")
46
+ _r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+"
47
+ r"\.\.\.")
48
+ _r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.")
49
+
50
+ def _get_parser():
51
+ global _parser_cache
52
+ if _parser_cache is None:
53
+ _parser_cache = pycparser.CParser()
54
+ return _parser_cache
55
+
56
+ def _workaround_for_old_pycparser(csource):
57
+ # Workaround for a pycparser issue (fixed between pycparser 2.10 and
58
+ # 2.14): "char*const***" gives us a wrong syntax tree, the same as
59
+ # for "char***(*const)". This means we can't tell the difference
60
+ # afterwards. But "char(*const(***))" gives us the right syntax
61
+ # tree. The issue only occurs if there are several stars in
62
+ # sequence with no parenthesis inbetween, just possibly qualifiers.
63
+ # Attempt to fix it by adding some parentheses in the source: each
64
+ # time we see "* const" or "* const *", we add an opening
65
+ # parenthesis before each star---the hard part is figuring out where
66
+ # to close them.
67
+ parts = []
68
+ while True:
69
+ match = _r_star_const_space.search(csource)
70
+ if not match:
71
+ break
72
+ #print repr(''.join(parts)+csource), '=>',
73
+ parts.append(csource[:match.start()])
74
+ parts.append('('); closing = ')'
75
+ parts.append(match.group()) # e.g. "* const "
76
+ endpos = match.end()
77
+ if csource.startswith('*', endpos):
78
+ parts.append('('); closing += ')'
79
+ level = 0
80
+ i = endpos
81
+ while i < len(csource):
82
+ c = csource[i]
83
+ if c == '(':
84
+ level += 1
85
+ elif c == ')':
86
+ if level == 0:
87
+ break
88
+ level -= 1
89
+ elif c in ',;=':
90
+ if level == 0:
91
+ break
92
+ i += 1
93
+ csource = csource[endpos:i] + closing + csource[i:]
94
+ #print repr(''.join(parts)+csource)
95
+ parts.append(csource)
96
+ return ''.join(parts)
97
+
98
+ def _preprocess_extern_python(csource):
99
+ # input: `extern "Python" int foo(int);` or
100
+ # `extern "Python" { int foo(int); }`
101
+ # output:
102
+ # void __cffi_extern_python_start;
103
+ # int foo(int);
104
+ # void __cffi_extern_python_stop;
105
+ #
106
+ # input: `extern "Python+C" int foo(int);`
107
+ # output:
108
+ # void __cffi_extern_python_plus_c_start;
109
+ # int foo(int);
110
+ # void __cffi_extern_python_stop;
111
+ parts = []
112
+ while True:
113
+ match = _r_extern_python.search(csource)
114
+ if not match:
115
+ break
116
+ endpos = match.end() - 1
117
+ #print
118
+ #print ''.join(parts)+csource
119
+ #print '=>'
120
+ parts.append(csource[:match.start()])
121
+ if 'C' in match.group(1):
122
+ parts.append('void __cffi_extern_python_plus_c_start; ')
123
+ else:
124
+ parts.append('void __cffi_extern_python_start; ')
125
+ if csource[endpos] == '{':
126
+ # grouping variant
127
+ closing = csource.find('}', endpos)
128
+ if closing < 0:
129
+ raise CDefError("'extern \"Python\" {': no '}' found")
130
+ if csource.find('{', endpos + 1, closing) >= 0:
131
+ raise NotImplementedError("cannot use { } inside a block "
132
+ "'extern \"Python\" { ... }'")
133
+ parts.append(csource[endpos+1:closing])
134
+ csource = csource[closing+1:]
135
+ else:
136
+ # non-grouping variant
137
+ semicolon = csource.find(';', endpos)
138
+ if semicolon < 0:
139
+ raise CDefError("'extern \"Python\": no ';' found")
140
+ parts.append(csource[endpos:semicolon+1])
141
+ csource = csource[semicolon+1:]
142
+ parts.append(' void __cffi_extern_python_stop;')
143
+ #print ''.join(parts)+csource
144
+ #print
145
+ parts.append(csource)
146
+ return ''.join(parts)
147
+
148
+ def _warn_for_string_literal(csource):
149
+ if '"' not in csource:
150
+ return
151
+ for line in csource.splitlines():
152
+ if '"' in line and not line.lstrip().startswith('#'):
153
+ import warnings
154
+ warnings.warn("String literal found in cdef() or type source. "
155
+ "String literals are ignored here, but you should "
156
+ "remove them anyway because some character sequences "
157
+ "confuse pre-parsing.")
158
+ break
159
+
160
+ def _warn_for_non_extern_non_static_global_variable(decl):
161
+ if not decl.storage:
162
+ import warnings
163
+ warnings.warn("Global variable '%s' in cdef(): for consistency "
164
+ "with C it should have a storage class specifier "
165
+ "(usually 'extern')" % (decl.name,))
166
+
167
+ def _remove_line_directives(csource):
168
+ # _r_line_directive matches whole lines, without the final \n, if they
169
+ # start with '#line' with some spacing allowed, or '#NUMBER'. This
170
+ # function stores them away and replaces them with exactly the string
171
+ # '#line@N', where N is the index in the list 'line_directives'.
172
+ line_directives = []
173
+ def replace(m):
174
+ i = len(line_directives)
175
+ line_directives.append(m.group())
176
+ return '#line@%d' % i
177
+ csource = _r_line_directive.sub(replace, csource)
178
+ return csource, line_directives
179
+
180
+ def _put_back_line_directives(csource, line_directives):
181
+ def replace(m):
182
+ s = m.group()
183
+ if not s.startswith('#line@'):
184
+ raise AssertionError("unexpected #line directive "
185
+ "(should have been processed and removed")
186
+ return line_directives[int(s[6:])]
187
+ return _r_line_directive.sub(replace, csource)
188
+
189
+ def _preprocess(csource):
190
+ # First, remove the lines of the form '#line N "filename"' because
191
+ # the "filename" part could confuse the rest
192
+ csource, line_directives = _remove_line_directives(csource)
193
+ # Remove comments. NOTE: this only work because the cdef() section
194
+ # should not contain any string literals (except in line directives)!
195
+ def replace_keeping_newlines(m):
196
+ return ' ' + m.group().count('\n') * '\n'
197
+ csource = _r_comment.sub(replace_keeping_newlines, csource)
198
+ # Remove the "#define FOO x" lines
199
+ macros = {}
200
+ for match in _r_define.finditer(csource):
201
+ macroname, macrovalue = match.groups()
202
+ macrovalue = macrovalue.replace('\\\n', '').strip()
203
+ macros[macroname] = macrovalue
204
+ csource = _r_define.sub('', csource)
205
+ #
206
+ if pycparser.__version__ < '2.14':
207
+ csource = _workaround_for_old_pycparser(csource)
208
+ #
209
+ # BIG HACK: replace WINAPI or __stdcall with "volatile const".
210
+ # It doesn't make sense for the return type of a function to be
211
+ # "volatile volatile const", so we abuse it to detect __stdcall...
212
+ # Hack number 2 is that "int(volatile *fptr)();" is not valid C
213
+ # syntax, so we place the "volatile" before the opening parenthesis.
214
+ csource = _r_stdcall2.sub(' volatile volatile const(', csource)
215
+ csource = _r_stdcall1.sub(' volatile volatile const ', csource)
216
+ csource = _r_cdecl.sub(' ', csource)
217
+ #
218
+ # Replace `extern "Python"` with start/end markers
219
+ csource = _preprocess_extern_python(csource)
220
+ #
221
+ # Now there should not be any string literal left; warn if we get one
222
+ _warn_for_string_literal(csource)
223
+ #
224
+ # Replace "[...]" with "[__dotdotdotarray__]"
225
+ csource = _r_partial_array.sub('[__dotdotdotarray__]', csource)
226
+ #
227
+ # Replace "...}" with "__dotdotdotNUM__}". This construction should
228
+ # occur only at the end of enums; at the end of structs we have "...;}"
229
+ # and at the end of vararg functions "...);". Also replace "=...[,}]"
230
+ # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when
231
+ # giving an unknown value.
232
+ matches = list(_r_partial_enum.finditer(csource))
233
+ for number, match in enumerate(reversed(matches)):
234
+ p = match.start()
235
+ if csource[p] == '=':
236
+ p2 = csource.find('...', p, match.end())
237
+ assert p2 > p
238
+ csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number,
239
+ csource[p2+3:])
240
+ else:
241
+ assert csource[p:p+3] == '...'
242
+ csource = '%s __dotdotdot%d__ %s' % (csource[:p], number,
243
+ csource[p+3:])
244
+ # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__"
245
+ csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource)
246
+ # Replace "float ..." or "double..." with "__dotdotdotfloat__"
247
+ csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource)
248
+ # Replace all remaining "..." with the same name, "__dotdotdot__",
249
+ # which is declared with a typedef for the purpose of C parsing.
250
+ csource = csource.replace('...', ' __dotdotdot__ ')
251
+ # Finally, put back the line directives
252
+ csource = _put_back_line_directives(csource, line_directives)
253
+ return csource, macros
254
+
255
+ def _common_type_names(csource):
256
+ # Look in the source for what looks like usages of types from the
257
+ # list of common types. A "usage" is approximated here as the
258
+ # appearance of the word, minus a "definition" of the type, which
259
+ # is the last word in a "typedef" statement. Approximative only
260
+ # but should be fine for all the common types.
261
+ look_for_words = set(COMMON_TYPES)
262
+ look_for_words.add(';')
263
+ look_for_words.add(',')
264
+ look_for_words.add('(')
265
+ look_for_words.add(')')
266
+ look_for_words.add('typedef')
267
+ words_used = set()
268
+ is_typedef = False
269
+ paren = 0
270
+ previous_word = ''
271
+ for word in _r_words.findall(csource):
272
+ if word in look_for_words:
273
+ if word == ';':
274
+ if is_typedef:
275
+ words_used.discard(previous_word)
276
+ look_for_words.discard(previous_word)
277
+ is_typedef = False
278
+ elif word == 'typedef':
279
+ is_typedef = True
280
+ paren = 0
281
+ elif word == '(':
282
+ paren += 1
283
+ elif word == ')':
284
+ paren -= 1
285
+ elif word == ',':
286
+ if is_typedef and paren == 0:
287
+ words_used.discard(previous_word)
288
+ look_for_words.discard(previous_word)
289
+ else: # word in COMMON_TYPES
290
+ words_used.add(word)
291
+ previous_word = word
292
+ return words_used
293
+
294
+
295
+ class Parser(object):
296
+
297
+ def __init__(self):
298
+ self._declarations = {}
299
+ self._included_declarations = set()
300
+ self._anonymous_counter = 0
301
+ self._structnode2type = weakref.WeakKeyDictionary()
302
+ self._options = {}
303
+ self._int_constants = {}
304
+ self._recomplete = []
305
+ self._uses_new_feature = None
306
+
307
+ def _parse(self, csource):
308
+ csource, macros = _preprocess(csource)
309
+ # XXX: for more efficiency we would need to poke into the
310
+ # internals of CParser... the following registers the
311
+ # typedefs, because their presence or absence influences the
312
+ # parsing itself (but what they are typedef'ed to plays no role)
313
+ ctn = _common_type_names(csource)
314
+ typenames = []
315
+ for name in sorted(self._declarations):
316
+ if name.startswith('typedef '):
317
+ name = name[8:]
318
+ typenames.append(name)
319
+ ctn.discard(name)
320
+ typenames += sorted(ctn)
321
+ #
322
+ csourcelines = []
323
+ csourcelines.append('# 1 "<cdef automatic initialization code>"')
324
+ for typename in typenames:
325
+ csourcelines.append('typedef int %s;' % typename)
326
+ csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,'
327
+ ' __dotdotdot__;')
328
+ # this forces pycparser to consider the following in the file
329
+ # called <cdef source string> from line 1
330
+ csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,))
331
+ csourcelines.append(csource)
332
+ csourcelines.append('') # see test_missing_newline_bug
333
+ fullcsource = '\n'.join(csourcelines)
334
+ if lock is not None:
335
+ lock.acquire() # pycparser is not thread-safe...
336
+ try:
337
+ ast = _get_parser().parse(fullcsource)
338
+ except pycparser.c_parser.ParseError as e:
339
+ self.convert_pycparser_error(e, csource)
340
+ finally:
341
+ if lock is not None:
342
+ lock.release()
343
+ # csource will be used to find buggy source text
344
+ return ast, macros, csource
345
+
346
+ def _convert_pycparser_error(self, e, csource):
347
+ # xxx look for "<cdef source string>:NUM:" at the start of str(e)
348
+ # and interpret that as a line number. This will not work if
349
+ # the user gives explicit ``# NUM "FILE"`` directives.
350
+ line = None
351
+ msg = str(e)
352
+ match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg)
353
+ if match:
354
+ linenum = int(match.group(1), 10)
355
+ csourcelines = csource.splitlines()
356
+ if 1 <= linenum <= len(csourcelines):
357
+ line = csourcelines[linenum-1]
358
+ return line
359
+
360
+ def convert_pycparser_error(self, e, csource):
361
+ line = self._convert_pycparser_error(e, csource)
362
+
363
+ msg = str(e)
364
+ if line:
365
+ msg = 'cannot parse "%s"\n%s' % (line.strip(), msg)
366
+ else:
367
+ msg = 'parse error\n%s' % (msg,)
368
+ raise CDefError(msg)
369
+
370
+ def parse(self, csource, override=False, packed=False, pack=None,
371
+ dllexport=False):
372
+ if packed:
373
+ if packed != True:
374
+ raise ValueError("'packed' should be False or True; use "
375
+ "'pack' to give another value")
376
+ if pack:
377
+ raise ValueError("cannot give both 'pack' and 'packed'")
378
+ pack = 1
379
+ elif pack:
380
+ if pack & (pack - 1):
381
+ raise ValueError("'pack' must be a power of two, not %r" %
382
+ (pack,))
383
+ else:
384
+ pack = 0
385
+ prev_options = self._options
386
+ try:
387
+ self._options = {'override': override,
388
+ 'packed': pack,
389
+ 'dllexport': dllexport}
390
+ self._internal_parse(csource)
391
+ finally:
392
+ self._options = prev_options
393
+
394
+ def _internal_parse(self, csource):
395
+ ast, macros, csource = self._parse(csource)
396
+ # add the macros
397
+ self._process_macros(macros)
398
+ # find the first "__dotdotdot__" and use that as a separator
399
+ # between the repeated typedefs and the real csource
400
+ iterator = iter(ast.ext)
401
+ for decl in iterator:
402
+ if decl.name == '__dotdotdot__':
403
+ break
404
+ else:
405
+ assert 0
406
+ current_decl = None
407
+ #
408
+ try:
409
+ self._inside_extern_python = '__cffi_extern_python_stop'
410
+ for decl in iterator:
411
+ current_decl = decl
412
+ if isinstance(decl, pycparser.c_ast.Decl):
413
+ self._parse_decl(decl)
414
+ elif isinstance(decl, pycparser.c_ast.Typedef):
415
+ if not decl.name:
416
+ raise CDefError("typedef does not declare any name",
417
+ decl)
418
+ quals = 0
419
+ if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and
420
+ decl.type.type.names[-1].startswith('__dotdotdot')):
421
+ realtype = self._get_unknown_type(decl)
422
+ elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
423
+ isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
424
+ isinstance(decl.type.type.type,
425
+ pycparser.c_ast.IdentifierType) and
426
+ decl.type.type.type.names[-1].startswith('__dotdotdot')):
427
+ realtype = self._get_unknown_ptr_type(decl)
428
+ else:
429
+ realtype, quals = self._get_type_and_quals(
430
+ decl.type, name=decl.name, partial_length_ok=True,
431
+ typedef_example="*(%s *)0" % (decl.name,))
432
+ self._declare('typedef ' + decl.name, realtype, quals=quals)
433
+ elif decl.__class__.__name__ == 'Pragma':
434
+ # skip pragma, only in pycparser 2.15
435
+ import warnings
436
+ warnings.warn(
437
+ "#pragma in cdef() are entirely ignored. "
438
+ "They should be removed for now, otherwise your "
439
+ "code might behave differently in a future version "
440
+ "of CFFI if #pragma support gets added. Note that "
441
+ "'#pragma pack' needs to be replaced with the "
442
+ "'packed' keyword argument to cdef().")
443
+ else:
444
+ raise CDefError("unexpected <%s>: this construct is valid "
445
+ "C but not valid in cdef()" %
446
+ decl.__class__.__name__, decl)
447
+ except CDefError as e:
448
+ if len(e.args) == 1:
449
+ e.args = e.args + (current_decl,)
450
+ raise
451
+ except FFIError as e:
452
+ msg = self._convert_pycparser_error(e, csource)
453
+ if msg:
454
+ e.args = (e.args[0] + "\n *** Err: %s" % msg,)
455
+ raise
456
+
457
+ def _add_constants(self, key, val):
458
+ if key in self._int_constants:
459
+ if self._int_constants[key] == val:
460
+ return # ignore identical double declarations
461
+ raise FFIError(
462
+ "multiple declarations of constant: %s" % (key,))
463
+ self._int_constants[key] = val
464
+
465
+ def _add_integer_constant(self, name, int_str):
466
+ int_str = int_str.lower().rstrip("ul")
467
+ neg = int_str.startswith('-')
468
+ if neg:
469
+ int_str = int_str[1:]
470
+ # "010" is not valid oct in py3
471
+ if (int_str.startswith("0") and int_str != '0'
472
+ and not int_str.startswith("0x")):
473
+ int_str = "0o" + int_str[1:]
474
+ pyvalue = int(int_str, 0)
475
+ if neg:
476
+ pyvalue = -pyvalue
477
+ self._add_constants(name, pyvalue)
478
+ self._declare('macro ' + name, pyvalue)
479
+
480
+ def _process_macros(self, macros):
481
+ for key, value in macros.items():
482
+ value = value.strip()
483
+ if _r_int_literal.match(value):
484
+ self._add_integer_constant(key, value)
485
+ elif value == '...':
486
+ self._declare('macro ' + key, value)
487
+ else:
488
+ raise CDefError(
489
+ 'only supports one of the following syntax:\n'
490
+ ' #define %s ... (literally dot-dot-dot)\n'
491
+ ' #define %s NUMBER (with NUMBER an integer'
492
+ ' constant, decimal/hex/octal)\n'
493
+ 'got:\n'
494
+ ' #define %s %s'
495
+ % (key, key, key, value))
496
+
497
+ def _declare_function(self, tp, quals, decl):
498
+ tp = self._get_type_pointer(tp, quals)
499
+ if self._options.get('dllexport'):
500
+ tag = 'dllexport_python '
501
+ elif self._inside_extern_python == '__cffi_extern_python_start':
502
+ tag = 'extern_python '
503
+ elif self._inside_extern_python == '__cffi_extern_python_plus_c_start':
504
+ tag = 'extern_python_plus_c '
505
+ else:
506
+ tag = 'function '
507
+ self._declare(tag + decl.name, tp)
508
+
509
+ def _parse_decl(self, decl):
510
+ node = decl.type
511
+ if isinstance(node, pycparser.c_ast.FuncDecl):
512
+ tp, quals = self._get_type_and_quals(node, name=decl.name)
513
+ assert isinstance(tp, model.RawFunctionType)
514
+ self._declare_function(tp, quals, decl)
515
+ else:
516
+ if isinstance(node, pycparser.c_ast.Struct):
517
+ self._get_struct_union_enum_type('struct', node)
518
+ elif isinstance(node, pycparser.c_ast.Union):
519
+ self._get_struct_union_enum_type('union', node)
520
+ elif isinstance(node, pycparser.c_ast.Enum):
521
+ self._get_struct_union_enum_type('enum', node)
522
+ elif not decl.name:
523
+ raise CDefError("construct does not declare any variable",
524
+ decl)
525
+ #
526
+ if decl.name:
527
+ tp, quals = self._get_type_and_quals(node,
528
+ partial_length_ok=True)
529
+ if tp.is_raw_function:
530
+ self._declare_function(tp, quals, decl)
531
+ elif (tp.is_integer_type() and
532
+ hasattr(decl, 'init') and
533
+ hasattr(decl.init, 'value') and
534
+ _r_int_literal.match(decl.init.value)):
535
+ self._add_integer_constant(decl.name, decl.init.value)
536
+ elif (tp.is_integer_type() and
537
+ isinstance(decl.init, pycparser.c_ast.UnaryOp) and
538
+ decl.init.op == '-' and
539
+ hasattr(decl.init.expr, 'value') and
540
+ _r_int_literal.match(decl.init.expr.value)):
541
+ self._add_integer_constant(decl.name,
542
+ '-' + decl.init.expr.value)
543
+ elif (tp is model.void_type and
544
+ decl.name.startswith('__cffi_extern_python_')):
545
+ # hack: `extern "Python"` in the C source is replaced
546
+ # with "void __cffi_extern_python_start;" and
547
+ # "void __cffi_extern_python_stop;"
548
+ self._inside_extern_python = decl.name
549
+ else:
550
+ if self._inside_extern_python !='__cffi_extern_python_stop':
551
+ raise CDefError(
552
+ "cannot declare constants or "
553
+ "variables with 'extern \"Python\"'")
554
+ if (quals & model.Q_CONST) and not tp.is_array_type:
555
+ self._declare('constant ' + decl.name, tp, quals=quals)
556
+ else:
557
+ _warn_for_non_extern_non_static_global_variable(decl)
558
+ self._declare('variable ' + decl.name, tp, quals=quals)
559
+
560
+ def parse_type(self, cdecl):
561
+ return self.parse_type_and_quals(cdecl)[0]
562
+
563
+ def parse_type_and_quals(self, cdecl):
564
+ ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2]
565
+ assert not macros
566
+ exprnode = ast.ext[-1].type.args.params[0]
567
+ if isinstance(exprnode, pycparser.c_ast.ID):
568
+ raise CDefError("unknown identifier '%s'" % (exprnode.name,))
569
+ return self._get_type_and_quals(exprnode.type)
570
+
571
+ def _declare(self, name, obj, included=False, quals=0):
572
+ if name in self._declarations:
573
+ prevobj, prevquals = self._declarations[name]
574
+ if prevobj is obj and prevquals == quals:
575
+ return
576
+ if not self._options.get('override'):
577
+ raise FFIError(
578
+ "multiple declarations of %s (for interactive usage, "
579
+ "try cdef(xx, override=True))" % (name,))
580
+ assert '__dotdotdot__' not in name.split()
581
+ self._declarations[name] = (obj, quals)
582
+ if included:
583
+ self._included_declarations.add(obj)
584
+
585
+ def _extract_quals(self, type):
586
+ quals = 0
587
+ if isinstance(type, (pycparser.c_ast.TypeDecl,
588
+ pycparser.c_ast.PtrDecl)):
589
+ if 'const' in type.quals:
590
+ quals |= model.Q_CONST
591
+ if 'volatile' in type.quals:
592
+ quals |= model.Q_VOLATILE
593
+ if 'restrict' in type.quals:
594
+ quals |= model.Q_RESTRICT
595
+ return quals
596
+
597
+ def _get_type_pointer(self, type, quals, declname=None):
598
+ if isinstance(type, model.RawFunctionType):
599
+ return type.as_function_pointer()
600
+ if (isinstance(type, model.StructOrUnionOrEnum) and
601
+ type.name.startswith('$') and type.name[1:].isdigit() and
602
+ type.forcename is None and declname is not None):
603
+ return model.NamedPointerType(type, declname, quals)
604
+ return model.PointerType(type, quals)
605
+
606
+ def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False,
607
+ typedef_example=None):
608
+ # first, dereference typedefs, if we have it already parsed, we're good
609
+ if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
610
+ isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
611
+ len(typenode.type.names) == 1 and
612
+ ('typedef ' + typenode.type.names[0]) in self._declarations):
613
+ tp, quals = self._declarations['typedef ' + typenode.type.names[0]]
614
+ quals |= self._extract_quals(typenode)
615
+ return tp, quals
616
+ #
617
+ if isinstance(typenode, pycparser.c_ast.ArrayDecl):
618
+ # array type
619
+ if typenode.dim is None:
620
+ length = None
621
+ else:
622
+ length = self._parse_constant(
623
+ typenode.dim, partial_length_ok=partial_length_ok)
624
+ # a hack: in 'typedef int foo_t[...][...];', don't use '...' as
625
+ # the length but use directly the C expression that would be
626
+ # generated by recompiler.py. This lets the typedef be used in
627
+ # many more places within recompiler.py
628
+ if typedef_example is not None:
629
+ if length == '...':
630
+ length = '_cffi_array_len(%s)' % (typedef_example,)
631
+ typedef_example = "*" + typedef_example
632
+ #
633
+ tp, quals = self._get_type_and_quals(typenode.type,
634
+ partial_length_ok=partial_length_ok,
635
+ typedef_example=typedef_example)
636
+ return model.ArrayType(tp, length), quals
637
+ #
638
+ if isinstance(typenode, pycparser.c_ast.PtrDecl):
639
+ # pointer type
640
+ itemtype, itemquals = self._get_type_and_quals(typenode.type)
641
+ tp = self._get_type_pointer(itemtype, itemquals, declname=name)
642
+ quals = self._extract_quals(typenode)
643
+ return tp, quals
644
+ #
645
+ if isinstance(typenode, pycparser.c_ast.TypeDecl):
646
+ quals = self._extract_quals(typenode)
647
+ type = typenode.type
648
+ if isinstance(type, pycparser.c_ast.IdentifierType):
649
+ # assume a primitive type. get it from .names, but reduce
650
+ # synonyms to a single chosen combination
651
+ names = list(type.names)
652
+ if names != ['signed', 'char']: # keep this unmodified
653
+ prefixes = {}
654
+ while names:
655
+ name = names[0]
656
+ if name in ('short', 'long', 'signed', 'unsigned'):
657
+ prefixes[name] = prefixes.get(name, 0) + 1
658
+ del names[0]
659
+ else:
660
+ break
661
+ # ignore the 'signed' prefix below, and reorder the others
662
+ newnames = []
663
+ for prefix in ('unsigned', 'short', 'long'):
664
+ for i in range(prefixes.get(prefix, 0)):
665
+ newnames.append(prefix)
666
+ if not names:
667
+ names = ['int'] # implicitly
668
+ if names == ['int']: # but kill it if 'short' or 'long'
669
+ if 'short' in prefixes or 'long' in prefixes:
670
+ names = []
671
+ names = newnames + names
672
+ ident = ' '.join(names)
673
+ if ident == 'void':
674
+ return model.void_type, quals
675
+ if ident == '__dotdotdot__':
676
+ raise FFIError(':%d: bad usage of "..."' %
677
+ typenode.coord.line)
678
+ tp0, quals0 = resolve_common_type(self, ident)
679
+ return tp0, (quals | quals0)
680
+ #
681
+ if isinstance(type, pycparser.c_ast.Struct):
682
+ # 'struct foobar'
683
+ tp = self._get_struct_union_enum_type('struct', type, name)
684
+ return tp, quals
685
+ #
686
+ if isinstance(type, pycparser.c_ast.Union):
687
+ # 'union foobar'
688
+ tp = self._get_struct_union_enum_type('union', type, name)
689
+ return tp, quals
690
+ #
691
+ if isinstance(type, pycparser.c_ast.Enum):
692
+ # 'enum foobar'
693
+ tp = self._get_struct_union_enum_type('enum', type, name)
694
+ return tp, quals
695
+ #
696
+ if isinstance(typenode, pycparser.c_ast.FuncDecl):
697
+ # a function type
698
+ return self._parse_function_type(typenode, name), 0
699
+ #
700
+ # nested anonymous structs or unions end up here
701
+ if isinstance(typenode, pycparser.c_ast.Struct):
702
+ return self._get_struct_union_enum_type('struct', typenode, name,
703
+ nested=True), 0
704
+ if isinstance(typenode, pycparser.c_ast.Union):
705
+ return self._get_struct_union_enum_type('union', typenode, name,
706
+ nested=True), 0
707
+ #
708
+ raise FFIError(":%d: bad or unsupported type declaration" %
709
+ typenode.coord.line)
710
+
711
+ def _parse_function_type(self, typenode, funcname=None):
712
+ params = list(getattr(typenode.args, 'params', []))
713
+ for i, arg in enumerate(params):
714
+ if not hasattr(arg, 'type'):
715
+ raise CDefError("%s arg %d: unknown type '%s'"
716
+ " (if you meant to use the old C syntax of giving"
717
+ " untyped arguments, it is not supported)"
718
+ % (funcname or 'in expression', i + 1,
719
+ getattr(arg, 'name', '?')))
720
+ ellipsis = (
721
+ len(params) > 0 and
722
+ isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and
723
+ isinstance(params[-1].type.type,
724
+ pycparser.c_ast.IdentifierType) and
725
+ params[-1].type.type.names == ['__dotdotdot__'])
726
+ if ellipsis:
727
+ params.pop()
728
+ if not params:
729
+ raise CDefError(
730
+ "%s: a function with only '(...)' as argument"
731
+ " is not correct C" % (funcname or 'in expression'))
732
+ args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type))
733
+ for argdeclnode in params]
734
+ if not ellipsis and args == [model.void_type]:
735
+ args = []
736
+ result, quals = self._get_type_and_quals(typenode.type)
737
+ # the 'quals' on the result type are ignored. HACK: we absure them
738
+ # to detect __stdcall functions: we textually replace "__stdcall"
739
+ # with "volatile volatile const" above.
740
+ abi = None
741
+ if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway
742
+ if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']:
743
+ abi = '__stdcall'
744
+ return model.RawFunctionType(tuple(args), result, ellipsis, abi)
745
+
746
+ def _as_func_arg(self, type, quals):
747
+ if isinstance(type, model.ArrayType):
748
+ return model.PointerType(type.item, quals)
749
+ elif isinstance(type, model.RawFunctionType):
750
+ return type.as_function_pointer()
751
+ else:
752
+ return type
753
+
754
+ def _get_struct_union_enum_type(self, kind, type, name=None, nested=False):
755
+ # First, a level of caching on the exact 'type' node of the AST.
756
+ # This is obscure, but needed because pycparser "unrolls" declarations
757
+ # such as "typedef struct { } foo_t, *foo_p" and we end up with
758
+ # an AST that is not a tree, but a DAG, with the "type" node of the
759
+ # two branches foo_t and foo_p of the trees being the same node.
760
+ # It's a bit silly but detecting "DAG-ness" in the AST tree seems
761
+ # to be the only way to distinguish this case from two independent
762
+ # structs. See test_struct_with_two_usages.
763
+ try:
764
+ return self._structnode2type[type]
765
+ except KeyError:
766
+ pass
767
+ #
768
+ # Note that this must handle parsing "struct foo" any number of
769
+ # times and always return the same StructType object. Additionally,
770
+ # one of these times (not necessarily the first), the fields of
771
+ # the struct can be specified with "struct foo { ...fields... }".
772
+ # If no name is given, then we have to create a new anonymous struct
773
+ # with no caching; in this case, the fields are either specified
774
+ # right now or never.
775
+ #
776
+ force_name = name
777
+ name = type.name
778
+ #
779
+ # get the type or create it if needed
780
+ if name is None:
781
+ # 'force_name' is used to guess a more readable name for
782
+ # anonymous structs, for the common case "typedef struct { } foo".
783
+ if force_name is not None:
784
+ explicit_name = '$%s' % force_name
785
+ else:
786
+ self._anonymous_counter += 1
787
+ explicit_name = '$%d' % self._anonymous_counter
788
+ tp = None
789
+ else:
790
+ explicit_name = name
791
+ key = '%s %s' % (kind, name)
792
+ tp, _ = self._declarations.get(key, (None, None))
793
+ #
794
+ if tp is None:
795
+ if kind == 'struct':
796
+ tp = model.StructType(explicit_name, None, None, None)
797
+ elif kind == 'union':
798
+ tp = model.UnionType(explicit_name, None, None, None)
799
+ elif kind == 'enum':
800
+ if explicit_name == '__dotdotdot__':
801
+ raise CDefError("Enums cannot be declared with ...")
802
+ tp = self._build_enum_type(explicit_name, type.values)
803
+ else:
804
+ raise AssertionError("kind = %r" % (kind,))
805
+ if name is not None:
806
+ self._declare(key, tp)
807
+ else:
808
+ if kind == 'enum' and type.values is not None:
809
+ raise NotImplementedError(
810
+ "enum %s: the '{}' declaration should appear on the first "
811
+ "time the enum is mentioned, not later" % explicit_name)
812
+ if not tp.forcename:
813
+ tp.force_the_name(force_name)
814
+ if tp.forcename and '$' in tp.name:
815
+ self._declare('anonymous %s' % tp.forcename, tp)
816
+ #
817
+ self._structnode2type[type] = tp
818
+ #
819
+ # enums: done here
820
+ if kind == 'enum':
821
+ return tp
822
+ #
823
+ # is there a 'type.decls'? If yes, then this is the place in the
824
+ # C sources that declare the fields. If no, then just return the
825
+ # existing type, possibly still incomplete.
826
+ if type.decls is None:
827
+ return tp
828
+ #
829
+ if tp.fldnames is not None:
830
+ raise CDefError("duplicate declaration of struct %s" % name)
831
+ fldnames = []
832
+ fldtypes = []
833
+ fldbitsize = []
834
+ fldquals = []
835
+ for decl in type.decls:
836
+ if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and
837
+ ''.join(decl.type.names) == '__dotdotdot__'):
838
+ # XXX pycparser is inconsistent: 'names' should be a list
839
+ # of strings, but is sometimes just one string. Use
840
+ # str.join() as a way to cope with both.
841
+ self._make_partial(tp, nested)
842
+ continue
843
+ if decl.bitsize is None:
844
+ bitsize = -1
845
+ else:
846
+ bitsize = self._parse_constant(decl.bitsize)
847
+ self._partial_length = False
848
+ type, fqual = self._get_type_and_quals(decl.type,
849
+ partial_length_ok=True)
850
+ if self._partial_length:
851
+ self._make_partial(tp, nested)
852
+ if isinstance(type, model.StructType) and type.partial:
853
+ self._make_partial(tp, nested)
854
+ fldnames.append(decl.name or '')
855
+ fldtypes.append(type)
856
+ fldbitsize.append(bitsize)
857
+ fldquals.append(fqual)
858
+ tp.fldnames = tuple(fldnames)
859
+ tp.fldtypes = tuple(fldtypes)
860
+ tp.fldbitsize = tuple(fldbitsize)
861
+ tp.fldquals = tuple(fldquals)
862
+ if fldbitsize != [-1] * len(fldbitsize):
863
+ if isinstance(tp, model.StructType) and tp.partial:
864
+ raise NotImplementedError("%s: using both bitfields and '...;'"
865
+ % (tp,))
866
+ tp.packed = self._options.get('packed')
867
+ if tp.completed: # must be re-completed: it is not opaque any more
868
+ tp.completed = 0
869
+ self._recomplete.append(tp)
870
+ return tp
871
+
872
+ def _make_partial(self, tp, nested):
873
+ if not isinstance(tp, model.StructOrUnion):
874
+ raise CDefError("%s cannot be partial" % (tp,))
875
+ if not tp.has_c_name() and not nested:
876
+ raise NotImplementedError("%s is partial but has no C name" %(tp,))
877
+ tp.partial = True
878
+
879
+ def _parse_constant(self, exprnode, partial_length_ok=False):
880
+ # for now, limited to expressions that are an immediate number
881
+ # or positive/negative number
882
+ if isinstance(exprnode, pycparser.c_ast.Constant):
883
+ s = exprnode.value
884
+ if '0' <= s[0] <= '9':
885
+ s = s.rstrip('uUlL')
886
+ try:
887
+ if s.startswith('0'):
888
+ return int(s, 8)
889
+ else:
890
+ return int(s, 10)
891
+ except ValueError:
892
+ if len(s) > 1:
893
+ if s.lower()[0:2] == '0x':
894
+ return int(s, 16)
895
+ elif s.lower()[0:2] == '0b':
896
+ return int(s, 2)
897
+ raise CDefError("invalid constant %r" % (s,))
898
+ elif s[0] == "'" and s[-1] == "'" and (
899
+ len(s) == 3 or (len(s) == 4 and s[1] == "\\")):
900
+ return ord(s[-2])
901
+ else:
902
+ raise CDefError("invalid constant %r" % (s,))
903
+ #
904
+ if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
905
+ exprnode.op == '+'):
906
+ return self._parse_constant(exprnode.expr)
907
+ #
908
+ if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and
909
+ exprnode.op == '-'):
910
+ return -self._parse_constant(exprnode.expr)
911
+ # load previously defined int constant
912
+ if (isinstance(exprnode, pycparser.c_ast.ID) and
913
+ exprnode.name in self._int_constants):
914
+ return self._int_constants[exprnode.name]
915
+ #
916
+ if (isinstance(exprnode, pycparser.c_ast.ID) and
917
+ exprnode.name == '__dotdotdotarray__'):
918
+ if partial_length_ok:
919
+ self._partial_length = True
920
+ return '...'
921
+ raise FFIError(":%d: unsupported '[...]' here, cannot derive "
922
+ "the actual array length in this context"
923
+ % exprnode.coord.line)
924
+ #
925
+ if isinstance(exprnode, pycparser.c_ast.BinaryOp):
926
+ left = self._parse_constant(exprnode.left)
927
+ right = self._parse_constant(exprnode.right)
928
+ if exprnode.op == '+':
929
+ return left + right
930
+ elif exprnode.op == '-':
931
+ return left - right
932
+ elif exprnode.op == '*':
933
+ return left * right
934
+ elif exprnode.op == '/':
935
+ return self._c_div(left, right)
936
+ elif exprnode.op == '%':
937
+ return left - self._c_div(left, right) * right
938
+ elif exprnode.op == '<<':
939
+ return left << right
940
+ elif exprnode.op == '>>':
941
+ return left >> right
942
+ elif exprnode.op == '&':
943
+ return left & right
944
+ elif exprnode.op == '|':
945
+ return left | right
946
+ elif exprnode.op == '^':
947
+ return left ^ right
948
+ #
949
+ raise FFIError(":%d: unsupported expression: expected a "
950
+ "simple numeric constant" % exprnode.coord.line)
951
+
952
+ def _c_div(self, a, b):
953
+ result = a // b
954
+ if ((a < 0) ^ (b < 0)) and (a % b) != 0:
955
+ result += 1
956
+ return result
957
+
958
+ def _build_enum_type(self, explicit_name, decls):
959
+ if decls is not None:
960
+ partial = False
961
+ enumerators = []
962
+ enumvalues = []
963
+ nextenumvalue = 0
964
+ for enum in decls.enumerators:
965
+ if _r_enum_dotdotdot.match(enum.name):
966
+ partial = True
967
+ continue
968
+ if enum.value is not None:
969
+ nextenumvalue = self._parse_constant(enum.value)
970
+ enumerators.append(enum.name)
971
+ enumvalues.append(nextenumvalue)
972
+ self._add_constants(enum.name, nextenumvalue)
973
+ nextenumvalue += 1
974
+ enumerators = tuple(enumerators)
975
+ enumvalues = tuple(enumvalues)
976
+ tp = model.EnumType(explicit_name, enumerators, enumvalues)
977
+ tp.partial = partial
978
+ else: # opaque enum
979
+ tp = model.EnumType(explicit_name, (), ())
980
+ return tp
981
+
982
+ def include(self, other):
983
+ for name, (tp, quals) in other._declarations.items():
984
+ if name.startswith('anonymous $enum_$'):
985
+ continue # fix for test_anonymous_enum_include
986
+ kind = name.split(' ', 1)[0]
987
+ if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'):
988
+ self._declare(name, tp, included=True, quals=quals)
989
+ for k, v in other._int_constants.items():
990
+ self._add_constants(k, v)
991
+
992
+ def _get_unknown_type(self, decl):
993
+ typenames = decl.type.type.names
994
+ if typenames == ['__dotdotdot__']:
995
+ return model.unknown_type(decl.name)
996
+
997
+ if typenames == ['__dotdotdotint__']:
998
+ if self._uses_new_feature is None:
999
+ self._uses_new_feature = "'typedef int... %s'" % decl.name
1000
+ return model.UnknownIntegerType(decl.name)
1001
+
1002
+ if typenames == ['__dotdotdotfloat__']:
1003
+ # note: not for 'long double' so far
1004
+ if self._uses_new_feature is None:
1005
+ self._uses_new_feature = "'typedef float... %s'" % decl.name
1006
+ return model.UnknownFloatType(decl.name)
1007
+
1008
+ raise FFIError(':%d: unsupported usage of "..." in typedef'
1009
+ % decl.coord.line)
1010
+
1011
+ def _get_unknown_ptr_type(self, decl):
1012
+ if decl.type.type.type.names == ['__dotdotdot__']:
1013
+ return model.unknown_ptr_type(decl.name)
1014
+ raise FFIError(':%d: unsupported usage of "..." in typedef'
1015
+ % decl.coord.line)