summaryrefslogtreecommitdiffstats
path: root/scripts/qapi.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/qapi.py')
-rw-r--r--scripts/qapi.py244
1 files changed, 173 insertions, 71 deletions
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 166b74f..f96a777 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -13,8 +13,11 @@
import re
from ordereddict import OrderedDict
+import errno
+import getopt
import os
import sys
+import string
builtin_types = {
'str': 'QTYPE_QSTRING',
@@ -537,7 +540,7 @@ def check_union(expr, expr_info):
# Otherwise, check for conflicts in the generated enum
else:
- c_key = _generate_enum_string(key)
+ c_key = camel_to_upper(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Union '%s' member '%s' clashes with '%s'"
@@ -555,7 +558,7 @@ def check_alternate(expr, expr_info):
check_name(expr_info, "Member of alternate '%s'" % name, key)
# Check for conflicts in the generated enum
- c_key = _generate_enum_string(key)
+ c_key = camel_to_upper(key)
if c_key in values:
raise QAPIExprError(expr_info,
"Alternate '%s' member '%s' clashes with '%s'"
@@ -586,7 +589,7 @@ def check_enum(expr, expr_info):
for member in members:
check_name(expr_info, "Member of enum '%s'" %name, member,
enum_member=True)
- key = _generate_enum_string(member)
+ key = camel_to_upper(member)
if key in values:
raise QAPIExprError(expr_info,
"Enum '%s' member '%s' clashes with '%s'"
@@ -728,17 +731,6 @@ def parse_args(typeinfo):
# value of an optional argument.
yield (argname, argentry, optional)
-def de_camel_case(name):
- new_name = ''
- for ch in name:
- if ch.isupper() and new_name:
- new_name += '_'
- if ch == '-':
- new_name += '_'
- else:
- new_name += ch.lower()
- return new_name
-
def camel_case(name):
new_name = ''
first = True
@@ -752,7 +744,43 @@ def camel_case(name):
new_name += ch.lower()
return new_name
-def c_var(name, protect=True):
+# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
+# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
+# ENUM24_Name -> ENUM24_NAME
+def camel_to_upper(value):
+ c_fun_str = c_name(value, False)
+ if value.isupper():
+ return c_fun_str
+
+ new_name = ''
+ l = len(c_fun_str)
+ for i in range(l):
+ c = c_fun_str[i]
+ # When c is upper and no "_" appears before, do more checks
+ if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
+ # Case 1: next string is lower
+ # Case 2: previous string is digit
+ if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
+ c_fun_str[i - 1].isdigit():
+ new_name += '_'
+ new_name += c
+ return new_name.lstrip('_').upper()
+
+def c_enum_const(type_name, const_name):
+ return camel_to_upper(type_name + '_' + const_name)
+
+c_name_trans = string.maketrans('.-', '__')
+
+# Map @name to a valid C identifier.
+# If @protect, avoid returning certain ticklish identifiers (like
+# C keywords) by prepending "q_".
+#
+# Used for converting 'name' from a 'name':'type' qapi definition
+# into a generated struct member, as well as converting type names
+# into substrings of a generated C function name.
+# '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
+# protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
+def c_name(name, protect=True):
# ANSI X3J11/88-090, 3.1.1
c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
@@ -781,18 +809,27 @@ def c_var(name, protect=True):
polluted_words = set(['unix', 'errno'])
if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words):
return "q_" + name
- return name.replace('-', '_').lstrip("*")
-
-def c_fun(name, protect=True):
- return c_var(name, protect).replace('.', '_')
+ return name.translate(c_name_trans)
+# Map type @name to the C typedef name for the list form.
+#
+# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
def c_list_type(name):
- return '%sList' % name
+ return type_name(name) + 'List'
-def type_name(name):
- if type(name) == list:
- return c_list_type(name[0])
- return name
+# Map type @value to the C typedef form.
+#
+# Used for converting 'type' from a 'member':'type' qapi definition
+# into the alphanumeric portion of the type for a generated C parameter,
+# as well as generated C function names. See c_type() for the rest of
+# the conversion such as adding '*' on pointer types.
+# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
+def type_name(value):
+ if type(value) == list:
+ return c_list_type(value[0])
+ if value in builtin_types.keys():
+ return value
+ return c_name(value)
def add_name(name, info, meta, implicit = False):
global all_names
@@ -849,42 +886,48 @@ def is_enum(name):
return find_enum(name) != None
eatspace = '\033EATSPACE.'
+pointer_suffix = ' *' + eatspace
+# Map type @name to its C type expression.
+# If @is_param, const-qualify the string type.
+#
+# This function is used for computing the full C type of 'member':'name'.
# A special suffix is added in c_type() for pointer types, and it's
# stripped in mcgen(). So please notice this when you check the return
# value of c_type() outside mcgen().
-def c_type(name, is_param=False):
- if name == 'str':
+def c_type(value, is_param=False):
+ if value == 'str':
if is_param:
- return 'const char *' + eatspace
- return 'char *' + eatspace
+ return 'const char' + pointer_suffix
+ return 'char' + pointer_suffix
- elif name == 'int':
+ elif value == 'int':
return 'int64_t'
- elif (name == 'int8' or name == 'int16' or name == 'int32' or
- name == 'int64' or name == 'uint8' or name == 'uint16' or
- name == 'uint32' or name == 'uint64'):
- return name + '_t'
- elif name == 'size':
+ elif (value == 'int8' or value == 'int16' or value == 'int32' or
+ value == 'int64' or value == 'uint8' or value == 'uint16' or
+ value == 'uint32' or value == 'uint64'):
+ return value + '_t'
+ elif value == 'size':
return 'uint64_t'
- elif name == 'bool':
+ elif value == 'bool':
return 'bool'
- elif name == 'number':
+ elif value == 'number':
return 'double'
- elif type(name) == list:
- return '%s *%s' % (c_list_type(name[0]), eatspace)
- elif is_enum(name):
- return name
- elif name == None or len(name) == 0:
+ elif type(value) == list:
+ return c_list_type(value[0]) + pointer_suffix
+ elif is_enum(value):
+ return c_name(value)
+ elif value == None:
return 'void'
- elif name in events:
- return '%sEvent *%s' % (camel_case(name), eatspace)
+ elif value in events:
+ return camel_case(value) + 'Event' + pointer_suffix
else:
- return '%s *%s' % (name, eatspace)
+ # complex type name
+ assert isinstance(value, str) and value != ""
+ return c_name(value) + pointer_suffix
-def is_c_ptr(name):
- suffix = "*" + eatspace
- return c_type(name).endswith(suffix)
+def is_c_ptr(value):
+ return c_type(value).endswith(pointer_suffix)
def genindent(count):
ret = ""
@@ -938,29 +981,88 @@ def guardend(name):
''',
name=guardname(name))
-# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
-# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
-# ENUM24_Name -> ENUM24_NAME
-def _generate_enum_string(value):
- c_fun_str = c_fun(value, False)
- if value.isupper():
- return c_fun_str
+def parse_command_line(extra_options = "", extra_long_options = []):
- new_name = ''
- l = len(c_fun_str)
- for i in range(l):
- c = c_fun_str[i]
- # When c is upper and no "_" appears before, do more checks
- if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
- # Case 1: next string is lower
- # Case 2: previous string is digit
- if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
- c_fun_str[i - 1].isdigit():
- new_name += '_'
- new_name += c
- return new_name.lstrip('_').upper()
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:],
+ "chp:o:" + extra_options,
+ ["source", "header", "prefix=",
+ "output-dir="] + extra_long_options)
+ except getopt.GetoptError, err:
+ print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
+ sys.exit(1)
+
+ output_dir = ""
+ prefix = ""
+ do_c = False
+ do_h = False
+ extra_opts = []
+
+ for oa in opts:
+ o, a = oa
+ if o in ("-p", "--prefix"):
+ prefix = a
+ elif o in ("-o", "--output-dir"):
+ output_dir = a + "/"
+ elif o in ("-c", "--source"):
+ do_c = True
+ elif o in ("-h", "--header"):
+ do_h = True
+ else:
+ extra_opts.append(oa)
+
+ if not do_c and not do_h:
+ do_c = True
+ do_h = True
+
+ if len(args) != 1:
+ print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
+ sys.exit(1)
+ input_file = args[0]
+
+ return (input_file, output_dir, do_c, do_h, prefix, extra_opts)
+
+def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
+ c_comment, h_comment):
+ c_file = output_dir + prefix + c_file
+ h_file = output_dir + prefix + h_file
+
+ try:
+ os.makedirs(output_dir)
+ except os.error, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ def maybe_open(really, name, opt):
+ if really:
+ return open(name, opt)
+ else:
+ import StringIO
+ return StringIO.StringIO()
+
+ fdef = maybe_open(do_c, c_file, 'w')
+ fdecl = maybe_open(do_h, h_file, 'w')
+
+ fdef.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+%(comment)s
+''',
+ comment = c_comment))
+
+ fdecl.write(mcgen('''
+/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
+%(comment)s
+#ifndef %(guard)s
+#define %(guard)s
+
+''',
+ comment = h_comment, guard = guardname(h_file)))
+
+ return (fdef, fdecl)
-def generate_enum_full_value(enum_name, enum_value):
- abbrev_string = _generate_enum_string(enum_name)
- value_string = _generate_enum_string(enum_value)
- return "%s_%s" % (abbrev_string, value_string)
+def close_output(fdef, fdecl):
+ fdecl.write('''
+#endif
+''')
+ fdecl.close()
+ fdef.close()
OpenPOWER on IntegriCloud