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