]>
Commit | Line | Data |
---|---|---|
0f923be2 MR |
1 | # |
2 | # QAPI helper library | |
3 | # | |
4 | # Copyright IBM, Corp. 2011 | |
47a6ea9a | 5 | # Copyright (c) 2013-2018 Red Hat Inc. |
0f923be2 MR |
6 | # |
7 | # Authors: | |
8 | # Anthony Liguori <[email protected]> | |
c7a3f252 | 9 | # Markus Armbruster <[email protected]> |
0f923be2 | 10 | # |
678e48a2 MA |
11 | # This work is licensed under the terms of the GNU GPL, version 2. |
12 | # See the COPYING file in the top-level directory. | |
0f923be2 | 13 | |
c2613949 | 14 | import re |
47299262 | 15 | import string |
0f923be2 | 16 | |
437db254 | 17 | |
849bc538 MA |
18 | # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1 |
19 | # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2 | |
20 | # ENUM24_Name -> ENUM24_NAME | |
21 | def camel_to_upper(value): | |
22 | c_fun_str = c_name(value, False) | |
23 | if value.isupper(): | |
24 | return c_fun_str | |
25 | ||
26 | new_name = '' | |
b736e25a MA |
27 | length = len(c_fun_str) |
28 | for i in range(length): | |
849bc538 | 29 | c = c_fun_str[i] |
ef801a9b MA |
30 | # When c is upper and no '_' appears before, do more checks |
31 | if c.isupper() and (i > 0) and c_fun_str[i - 1] != '_': | |
b736e25a | 32 | if i < length - 1 and c_fun_str[i + 1].islower(): |
437db254 EB |
33 | new_name += '_' |
34 | elif c_fun_str[i - 1].isdigit(): | |
849bc538 MA |
35 | new_name += '_' |
36 | new_name += c | |
37 | return new_name.lstrip('_').upper() | |
38 | ||
437db254 | 39 | |
351d36e4 DB |
40 | def c_enum_const(type_name, const_name, prefix=None): |
41 | if prefix is not None: | |
42 | type_name = prefix | |
d20a580b | 43 | return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper() |
849bc538 | 44 | |
b736e25a | 45 | |
52c4272c | 46 | if hasattr(str, 'maketrans'): |
eb815e24 | 47 | c_name_trans = str.maketrans('.-', '__') |
52c4272c | 48 | else: |
eb815e24 | 49 | c_name_trans = string.maketrans('.-', '__') |
47299262 | 50 | |
437db254 | 51 | |
c6405b54 EB |
52 | # Map @name to a valid C identifier. |
53 | # If @protect, avoid returning certain ticklish identifiers (like | |
ef801a9b | 54 | # C keywords) by prepending 'q_'. |
c6405b54 EB |
55 | # |
56 | # Used for converting 'name' from a 'name':'type' qapi definition | |
57 | # into a generated struct member, as well as converting type names | |
58 | # into substrings of a generated C function name. | |
59 | # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo' | |
60 | # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int' | |
18df515e | 61 | def c_name(name, protect=True): |
427a1a2c BS |
62 | # ANSI X3J11/88-090, 3.1.1 |
63 | c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue', | |
437db254 EB |
64 | 'default', 'do', 'double', 'else', 'enum', 'extern', |
65 | 'float', 'for', 'goto', 'if', 'int', 'long', 'register', | |
66 | 'return', 'short', 'signed', 'sizeof', 'static', | |
67 | 'struct', 'switch', 'typedef', 'union', 'unsigned', | |
68 | 'void', 'volatile', 'while']) | |
427a1a2c BS |
69 | # ISO/IEC 9899:1999, 6.4.1 |
70 | c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary']) | |
71 | # ISO/IEC 9899:2011, 6.4.1 | |
437db254 EB |
72 | c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', |
73 | '_Noreturn', '_Static_assert', '_Thread_local']) | |
427a1a2c BS |
74 | # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html |
75 | # excluding _.* | |
76 | gcc_words = set(['asm', 'typeof']) | |
6f88009e TS |
77 | # C++ ISO/IEC 14882:2003 2.11 |
78 | cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete', | |
79 | 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable', | |
80 | 'namespace', 'new', 'operator', 'private', 'protected', | |
81 | 'public', 'reinterpret_cast', 'static_cast', 'template', | |
82 | 'this', 'throw', 'true', 'try', 'typeid', 'typename', | |
83 | 'using', 'virtual', 'wchar_t', | |
84 | # alternative representations | |
85 | 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', | |
86 | 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) | |
1057725f | 87 | # namespace pollution: |
9a801c7d | 88 | polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386']) |
c43567c1 | 89 | name = name.translate(c_name_trans) |
437db254 EB |
90 | if protect and (name in c89_words | c99_words | c11_words | gcc_words |
91 | | cpp_words | polluted_words): | |
ef801a9b | 92 | return 'q_' + name |
c43567c1 | 93 | return name |
0f923be2 | 94 | |
b736e25a | 95 | |
05dfb26c | 96 | eatspace = '\033EATSPACE.' |
d5573446 | 97 | pointer_suffix = ' *' + eatspace |
05dfb26c | 98 | |
437db254 | 99 | |
0f923be2 | 100 | def genindent(count): |
ef801a9b | 101 | ret = '' |
437db254 | 102 | for _ in range(count): |
ef801a9b | 103 | ret += ' ' |
0f923be2 MR |
104 | return ret |
105 | ||
b736e25a | 106 | |
0f923be2 MR |
107 | indent_level = 0 |
108 | ||
437db254 | 109 | |
0f923be2 MR |
110 | def push_indent(indent_amount=4): |
111 | global indent_level | |
112 | indent_level += indent_amount | |
113 | ||
437db254 | 114 | |
0f923be2 MR |
115 | def pop_indent(indent_amount=4): |
116 | global indent_level | |
117 | indent_level -= indent_amount | |
118 | ||
437db254 | 119 | |
77e703b8 MA |
120 | # Generate @code with @kwds interpolated. |
121 | # Obey indent_level, and strip eatspace. | |
0f923be2 | 122 | def cgen(code, **kwds): |
77e703b8 MA |
123 | raw = code % kwds |
124 | if indent_level: | |
125 | indent = genindent(indent_level) | |
2752e5be | 126 | # re.subn() lacks flags support before Python 2.7, use re.compile() |
485d948c MAL |
127 | raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE), |
128 | indent, raw) | |
77e703b8 | 129 | raw = raw[0] |
0fe675af | 130 | return re.sub(re.escape(eatspace) + r' *', '', raw) |
0f923be2 | 131 | |
437db254 | 132 | |
0f923be2 | 133 | def mcgen(code, **kwds): |
77e703b8 MA |
134 | if code[0] == '\n': |
135 | code = code[1:] | |
136 | return cgen(code, **kwds) | |
0f923be2 | 137 | |
0f923be2 | 138 | |
709395f8 MA |
139 | def c_fname(filename): |
140 | return re.sub(r'[^A-Za-z0-9_]', '_', filename) | |
c0afa9c5 | 141 | |
437db254 | 142 | |
c0afa9c5 MR |
143 | def guardstart(name): |
144 | return mcgen(''' | |
c0afa9c5 MR |
145 | #ifndef %(name)s |
146 | #define %(name)s | |
147 | ||
148 | ''', | |
709395f8 | 149 | name=c_fname(name).upper()) |
c0afa9c5 | 150 | |
437db254 | 151 | |
c0afa9c5 MR |
152 | def guardend(name): |
153 | return mcgen(''' | |
154 | ||
155 | #endif /* %(name)s */ | |
c0afa9c5 | 156 | ''', |
709395f8 | 157 | name=c_fname(name).upper()) |
2114f5a9 | 158 | |
437db254 | 159 | |
ded9fc28 MAL |
160 | def gen_if(ifcond): |
161 | ret = '' | |
162 | for ifc in ifcond: | |
163 | ret += mcgen(''' | |
164 | #if %(cond)s | |
165 | ''', cond=ifc) | |
166 | return ret | |
167 | ||
168 | ||
169 | def gen_endif(ifcond): | |
170 | ret = '' | |
171 | for ifc in reversed(ifcond): | |
172 | ret += mcgen(''' | |
173 | #endif /* %(cond)s */ | |
174 | ''', cond=ifc) | |
175 | return ret | |
176 | ||
177 | ||
bdd2d42b | 178 | def build_params(arg_type, boxed, extra=None): |
03b4367a MA |
179 | ret = '' |
180 | sep = '' | |
48825ca4 | 181 | if boxed: |
bdd2d42b | 182 | assert arg_type |
c818408e EB |
183 | ret += '%s arg' % arg_type.c_param_type() |
184 | sep = ', ' | |
bdd2d42b | 185 | elif arg_type: |
48825ca4 EB |
186 | assert not arg_type.variants |
187 | for memb in arg_type.members: | |
188 | ret += sep | |
189 | sep = ', ' | |
190 | if memb.optional: | |
191 | ret += 'bool has_%s, ' % c_name(memb.name) | |
192 | ret += '%s %s' % (memb.type.c_param_type(), | |
193 | c_name(memb.name)) | |
03b4367a MA |
194 | if extra: |
195 | ret += sep + extra | |
bdd2d42b | 196 | return ret if ret else 'void' |