blob: ba35abea478e1647da077a2699bbf7455cead2f9 [file] [log] [blame]
Michael Roth0f923be2011-07-19 14:50:39 -05001#
2# QAPI helper library
3#
4# Copyright IBM, Corp. 2011
Markus Armbruster47a6ea92018-02-26 13:19:40 -06005# Copyright (c) 2013-2018 Red Hat Inc.
Michael Roth0f923be2011-07-19 14:50:39 -05006#
7# Authors:
8# Anthony Liguori <aliguori@us.ibm.com>
Markus Armbrusterc7a3f252013-07-27 17:41:55 +02009# Markus Armbruster <armbru@redhat.com>
Michael Roth0f923be2011-07-19 14:50:39 -050010#
Markus Armbruster678e48a2014-03-01 08:40:34 +010011# This work is licensed under the terms of the GNU GPL, version 2.
12# See the COPYING file in the top-level directory.
Michael Roth0f923be2011-07-19 14:50:39 -050013
Markus Armbrusterc2613942017-03-15 13:57:35 +010014import re
Michael Roth0f923be2011-07-19 14:50:39 -050015
Eric Blake437db252015-09-29 16:21:02 -060016
Markus Armbruster849bc532015-05-14 06:50:53 -060017# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
18# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
19# ENUM24_Name -> ENUM24_NAME
20def 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 Armbrusterb736e252018-06-21 10:35:51 +020026 length = len(c_fun_str)
27 for i in range(length):
Markus Armbruster849bc532015-05-14 06:50:53 -060028 c = c_fun_str[i]
Markus Armbrusteref801a92017-03-15 13:57:08 +010029 # 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 Armbrusterb736e252018-06-21 10:35:51 +020031 if i < length - 1 and c_fun_str[i + 1].islower():
Eric Blake437db252015-09-29 16:21:02 -060032 new_name += '_'
33 elif c_fun_str[i - 1].isdigit():
Markus Armbruster849bc532015-05-14 06:50:53 -060034 new_name += '_'
35 new_name += c
36 return new_name.lstrip('_').upper()
37
Eric Blake437db252015-09-29 16:21:02 -060038
Daniel P. Berrange351d36e2015-08-26 14:21:20 +010039def c_enum_const(type_name, const_name, prefix=None):
40 if prefix is not None:
41 type_name = prefix
Eric Blaked20a5802015-11-18 01:53:01 -070042 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
Markus Armbruster849bc532015-05-14 06:50:53 -060043
Markus Armbrusterb736e252018-06-21 10:35:51 +020044
Markus Armbrustered39c032020-03-04 16:59:30 +010045c_name_trans = str.maketrans('.-', '__')
Markus Armbruster47299262015-05-14 06:50:47 -060046
Eric Blake437db252015-09-29 16:21:02 -060047
Eric Blakec6405b52015-05-14 06:50:55 -060048# Map @name to a valid C identifier.
49# If @protect, avoid returning certain ticklish identifiers (like
Markus Armbrusteref801a92017-03-15 13:57:08 +010050# C keywords) by prepending 'q_'.
Eric Blakec6405b52015-05-14 06:50:55 -060051#
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 Blake18df5152015-05-14 06:50:48 -060057def c_name(name, protect=True):
Blue Swirl427a1a22012-07-30 15:46:55 +000058 # ANSI X3J11/88-090, 3.1.1
59 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
Eric Blake437db252015-09-29 16:21:02 -060060 '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 Swirl427a1a22012-07-30 15:46:55 +000065 # 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 Blake437db252015-09-29 16:21:02 -060068 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
69 '_Noreturn', '_Static_assert', '_Thread_local'])
Blue Swirl427a1a22012-07-30 15:46:55 +000070 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
71 # excluding _.*
72 gcc_words = set(['asm', 'typeof'])
Tomoki Sekiyama6f880092013-08-07 11:39:43 -040073 # 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 Bonzini10577252012-09-19 16:31:07 +020083 # namespace pollution:
Laszlo Ersek9a801c72018-04-27 21:28:49 +020084 polluted_words = set(['unix', 'errno', 'mips', 'sparc', 'i386'])
Eric Blakec43567c2015-11-18 01:52:52 -070085 name = name.translate(c_name_trans)
Eric Blake437db252015-09-29 16:21:02 -060086 if protect and (name in c89_words | c99_words | c11_words | gcc_words
87 | cpp_words | polluted_words):
Markus Armbrusteref801a92017-03-15 13:57:08 +010088 return 'q_' + name
Eric Blakec43567c2015-11-18 01:52:52 -070089 return name
Michael Roth0f923be2011-07-19 14:50:39 -050090
Markus Armbrusterb736e252018-06-21 10:35:51 +020091
Amos Kong05dfb262014-06-10 19:25:53 +080092eatspace = '\033EATSPACE.'
Eric Blaked5573442015-05-14 06:50:54 -060093pointer_suffix = ' *' + eatspace
Amos Kong05dfb262014-06-10 19:25:53 +080094
Eric Blake437db252015-09-29 16:21:02 -060095
Michael Roth0f923be2011-07-19 14:50:39 -050096def genindent(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +010097 ret = ''
Eric Blake437db252015-09-29 16:21:02 -060098 for _ in range(count):
Markus Armbrusteref801a92017-03-15 13:57:08 +010099 ret += ' '
Michael Roth0f923be2011-07-19 14:50:39 -0500100 return ret
101
Markus Armbrusterb736e252018-06-21 10:35:51 +0200102
Michael Roth0f923be2011-07-19 14:50:39 -0500103indent_level = 0
104
Eric Blake437db252015-09-29 16:21:02 -0600105
Michael Roth0f923be2011-07-19 14:50:39 -0500106def push_indent(indent_amount=4):
107 global indent_level
108 indent_level += indent_amount
109
Eric Blake437db252015-09-29 16:21:02 -0600110
Michael Roth0f923be2011-07-19 14:50:39 -0500111def pop_indent(indent_amount=4):
112 global indent_level
113 indent_level -= indent_amount
114
Eric Blake437db252015-09-29 16:21:02 -0600115
Markus Armbruster77e703b2015-06-24 19:27:32 +0200116# Generate @code with @kwds interpolated.
117# Obey indent_level, and strip eatspace.
Michael Roth0f923be2011-07-19 14:50:39 -0500118def cgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +0200119 raw = code % kwds
120 if indent_level:
121 indent = genindent(indent_level)
Markus Armbruster2752e5b2015-09-07 17:45:55 +0200122 # re.subn() lacks flags support before Python 2.7, use re.compile()
Marc-André Lureau485d9482018-07-03 17:56:39 +0200123 raw = re.subn(re.compile(r'^(?!(#|$))', re.MULTILINE),
124 indent, raw)
Markus Armbruster77e703b2015-06-24 19:27:32 +0200125 raw = raw[0]
Markus Armbruster0fe675a2017-03-15 13:57:07 +0100126 return re.sub(re.escape(eatspace) + r' *', '', raw)
Michael Roth0f923be2011-07-19 14:50:39 -0500127
Eric Blake437db252015-09-29 16:21:02 -0600128
Michael Roth0f923be2011-07-19 14:50:39 -0500129def mcgen(code, **kwds):
Markus Armbruster77e703b2015-06-24 19:27:32 +0200130 if code[0] == '\n':
131 code = code[1:]
132 return cgen(code, **kwds)
Michael Roth0f923be2011-07-19 14:50:39 -0500133
Michael Roth0f923be2011-07-19 14:50:39 -0500134
Markus Armbruster709395f2019-03-01 16:40:48 +0100135def c_fname(filename):
136 return re.sub(r'[^A-Za-z0-9_]', '_', filename)
Michael Rothc0afa9c2013-05-10 17:46:00 -0500137
Eric Blake437db252015-09-29 16:21:02 -0600138
Michael Rothc0afa9c2013-05-10 17:46:00 -0500139def guardstart(name):
140 return mcgen('''
Michael Rothc0afa9c2013-05-10 17:46:00 -0500141#ifndef %(name)s
142#define %(name)s
143
144''',
Markus Armbruster709395f2019-03-01 16:40:48 +0100145 name=c_fname(name).upper())
Michael Rothc0afa9c2013-05-10 17:46:00 -0500146
Eric Blake437db252015-09-29 16:21:02 -0600147
Michael Rothc0afa9c2013-05-10 17:46:00 -0500148def guardend(name):
149 return mcgen('''
150
151#endif /* %(name)s */
Michael Rothc0afa9c2013-05-10 17:46:00 -0500152''',
Markus Armbruster709395f2019-03-01 16:40:48 +0100153 name=c_fname(name).upper())
Markus Armbruster2114f5a2015-04-02 13:12:21 +0200154
Eric Blake437db252015-09-29 16:21:02 -0600155
Marc-André Lureauded9fc22018-07-03 17:56:40 +0200156def 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
165def 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 Armbrusterbdd2d422018-08-15 21:37:36 +0800174def build_params(arg_type, boxed, extra=None):
Markus Armbruster03b43672015-09-16 13:06:20 +0200175 ret = ''
176 sep = ''
Eric Blake48825ca2016-07-13 21:50:19 -0600177 if boxed:
Markus Armbrusterbdd2d422018-08-15 21:37:36 +0800178 assert arg_type
Eric Blakec8184082016-07-13 21:50:20 -0600179 ret += '%s arg' % arg_type.c_param_type()
180 sep = ', '
Markus Armbrusterbdd2d422018-08-15 21:37:36 +0800181 elif arg_type:
Eric Blake48825ca2016-07-13 21:50:19 -0600182 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 Armbruster03b43672015-09-16 13:06:20 +0200190 if extra:
191 ret += sep + extra
Markus Armbrusterbdd2d422018-08-15 21:37:36 +0800192 return ret if ret else 'void'