Before this patch, if a channel is defined conditionally in spice.proto
(because it depends on external headers like the smartcard channel),
spice_codegen would write an entry to the channels array in
spice_get_*_channel_parser which would only take up a place in the array
if the ifdef condition is true, thus moving up all other intializers
one place when it is not true. This was causing issues (crashes) when building
spice-gtk with the combination of usbredir support enabled and smartcard
support disabled.
This patch fixes this by adding #else { NULL, 0 }, to the generated code.
Thanks to coolper chen <lixin.chen@saicocch.com> for reporting this!
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
375 lines
10 KiB
Python
375 lines
10 KiB
Python
from __future__ import with_statement
|
|
from cStringIO import StringIO
|
|
|
|
def camel_to_underscores(s, upper = False):
|
|
res = ""
|
|
for i in range(len(s)):
|
|
c = s[i]
|
|
if i > 0 and c.isupper():
|
|
res = res + "_"
|
|
if upper:
|
|
res = res + c.upper()
|
|
else:
|
|
res = res + c.lower()
|
|
return res
|
|
|
|
def underscores_to_camel(s):
|
|
res = ""
|
|
do_upper = True
|
|
for i in range(len(s)):
|
|
c = s[i]
|
|
if c == "_":
|
|
do_upper = True
|
|
else:
|
|
if do_upper:
|
|
res = res + c.upper()
|
|
else:
|
|
res = res + c
|
|
do_upper = False
|
|
return res
|
|
|
|
proto_prefix = "Temp"
|
|
|
|
def set_prefix(prefix):
|
|
global proto_prefix
|
|
global proto_prefix_upper
|
|
global proto_prefix_lower
|
|
proto_prefix = prefix
|
|
proto_prefix_upper = prefix.upper()
|
|
proto_prefix_lower = prefix.lower()
|
|
|
|
def prefix_underscore_upper(*args):
|
|
s = proto_prefix_upper
|
|
for arg in args:
|
|
s = s + "_" + arg
|
|
return s
|
|
|
|
def prefix_underscore_lower(*args):
|
|
s = proto_prefix_lower
|
|
for arg in args:
|
|
s = s + "_" + arg
|
|
return s
|
|
|
|
def prefix_camel(*args):
|
|
s = proto_prefix
|
|
for arg in args:
|
|
s = s + underscores_to_camel(arg)
|
|
return s
|
|
|
|
def increment_identifier(idf):
|
|
v = idf[-1:]
|
|
if v.isdigit():
|
|
return idf[:-1] + str(int(v) + 1)
|
|
return idf + "2"
|
|
|
|
def sum_array(array):
|
|
if len(array) == 0:
|
|
return 0
|
|
return " + ".join(array)
|
|
|
|
class CodeWriter:
|
|
def __init__(self):
|
|
self.out = StringIO()
|
|
self.contents = [self.out]
|
|
self.indentation = 0
|
|
self.at_line_start = True
|
|
self.indexes = ["i", "j", "k", "ii", "jj", "kk"]
|
|
self.current_index = 0
|
|
self.generated = {}
|
|
self.vars = []
|
|
self.has_error_check = False
|
|
self.options = {}
|
|
self.function_helper_writer = None
|
|
|
|
def set_option(self, opt, value = True):
|
|
self.options[opt] = value
|
|
|
|
def has_option(self, opt):
|
|
return self.options.has_key(opt)
|
|
|
|
def set_is_generated(self, kind, name):
|
|
if not self.generated.has_key(kind):
|
|
v = {}
|
|
self.generated[kind] = v
|
|
else:
|
|
v = self.generated[kind]
|
|
v[name] = 1
|
|
|
|
def is_generated(self, kind, name):
|
|
if not self.generated.has_key(kind):
|
|
return False
|
|
v = self.generated[kind]
|
|
return v.has_key(name)
|
|
|
|
def getvalue(self):
|
|
strs = map(lambda writer: writer.getvalue(), self.contents)
|
|
return "".join(strs)
|
|
|
|
def get_subwriter(self):
|
|
writer = CodeWriter()
|
|
self.contents.append(writer)
|
|
self.out = StringIO()
|
|
self.contents.append(self.out)
|
|
writer.indentation = self.indentation
|
|
writer.at_line_start = self.at_line_start
|
|
writer.generated = self.generated
|
|
writer.options = self.options
|
|
writer.public_prefix = self.public_prefix
|
|
|
|
return writer
|
|
|
|
def write(self, s):
|
|
# Ensure its a string
|
|
s = str(s)
|
|
|
|
if len(s) == 0:
|
|
return
|
|
|
|
if self.at_line_start:
|
|
for i in range(self.indentation):
|
|
self.out.write(" ")
|
|
self.at_line_start = False
|
|
self.out.write(s)
|
|
return self
|
|
|
|
def newline(self):
|
|
self.out.write("\n")
|
|
self.at_line_start = True
|
|
return self
|
|
|
|
def writeln(self, s):
|
|
self.write(s)
|
|
self.newline()
|
|
return self
|
|
|
|
def label(self, s):
|
|
self.indentation = self.indentation - 1
|
|
self.write(s + ":")
|
|
self.indentation = self.indentation + 1
|
|
self.newline()
|
|
|
|
def statement(self, s):
|
|
self.write(s)
|
|
self.write(";")
|
|
self.newline()
|
|
return self
|
|
|
|
def assign(self, var, val):
|
|
self.write("%s = %s" % (var, val))
|
|
self.write(";")
|
|
self.newline()
|
|
return self
|
|
|
|
def increment(self, var, val):
|
|
self.write("%s += %s" % (var, val))
|
|
self.write(";")
|
|
self.newline()
|
|
return self
|
|
|
|
def comment(self, str):
|
|
self.write("/* " + str + " */")
|
|
return self
|
|
|
|
def todo(self, str):
|
|
self.comment("TODO: *** %s ***" % str).newline()
|
|
return self
|
|
|
|
def error_check(self, check, label = "error"):
|
|
self.has_error_check = True
|
|
with self.block("if (SPICE_UNLIKELY(%s))" % check):
|
|
if self.has_option("print_error"):
|
|
self.statement('printf("%%s: Caught error - %s", __PRETTY_FUNCTION__)' % check)
|
|
if self.has_option("assert_on_error"):
|
|
self.statement("assert(0)")
|
|
self.statement("goto %s" % label)
|
|
|
|
def indent(self):
|
|
self.indentation += 4
|
|
|
|
def unindent(self):
|
|
self.indentation -= 4
|
|
if self.indentation < 0:
|
|
self.indenttation = 0
|
|
|
|
def begin_block(self, prefix= "", comment = ""):
|
|
if len(prefix) > 0:
|
|
self.write(prefix)
|
|
if self.at_line_start:
|
|
self.write("{")
|
|
else:
|
|
self.write(" {")
|
|
if len(comment) > 0:
|
|
self.write(" ")
|
|
self.comment(comment)
|
|
self.newline()
|
|
self.indent()
|
|
|
|
def end_block(self, semicolon=False, newline=True):
|
|
self.unindent()
|
|
if self.at_line_start:
|
|
self.write("}")
|
|
else:
|
|
self.write(" }")
|
|
if semicolon:
|
|
self.write(";")
|
|
if newline:
|
|
self.newline()
|
|
|
|
class Block:
|
|
def __init__(self, writer, semicolon, newline):
|
|
self.writer = writer
|
|
self.semicolon = semicolon
|
|
self.newline = newline
|
|
|
|
def __enter__(self):
|
|
return self.writer.get_subwriter()
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.writer.end_block(self.semicolon, self.newline)
|
|
|
|
class PartialBlock:
|
|
def __init__(self, writer, scope, semicolon, newline):
|
|
self.writer = writer
|
|
self.scope = scope
|
|
self.semicolon = semicolon
|
|
self.newline = newline
|
|
|
|
def __enter__(self):
|
|
return self.scope
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.writer.end_block(self.semicolon, self.newline)
|
|
|
|
class NoBlock:
|
|
def __init__(self, scope):
|
|
self.scope = scope
|
|
|
|
def __enter__(self):
|
|
return self.scope
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
def block(self, prefix= "", comment = "", semicolon=False, newline=True):
|
|
self.begin_block(prefix, comment)
|
|
return self.Block(self, semicolon, newline)
|
|
|
|
def partial_block(self, scope, semicolon=False, newline=True):
|
|
return self.PartialBlock(self, scope, semicolon, newline)
|
|
|
|
def no_block(self, scope):
|
|
return self.NoBlock(scope)
|
|
|
|
def optional_block(self, scope):
|
|
if scope != None:
|
|
return self.NoBlock(scope)
|
|
return self.block()
|
|
|
|
def for_loop(self, index, limit):
|
|
return self.block("for (%s = 0; %s < %s; %s++)" % (index, index, limit, index))
|
|
|
|
def while_loop(self, expr):
|
|
return self.block("while (%s)" % (expr))
|
|
|
|
def if_block(self, check, elseif=False, newline=True):
|
|
s = "if (%s)" % (check)
|
|
if elseif:
|
|
s = " else " + s
|
|
self.begin_block(s, "")
|
|
return self.Block(self, False, newline)
|
|
|
|
def variable_defined(self, name):
|
|
for n in self.vars:
|
|
if n == name:
|
|
return True
|
|
return False
|
|
|
|
def variable_def(self, ctype, *names):
|
|
for n in names:
|
|
# Strip away initialization
|
|
i = n.find("=")
|
|
if i != -1:
|
|
n = n[0:i]
|
|
self.vars.append(n.strip())
|
|
# only add space for non-pointer types
|
|
if ctype[-1] == "*":
|
|
ctype = ctype[:-1].rstrip()
|
|
self.writeln("%s *%s;"%(ctype, ", *".join(names)))
|
|
else:
|
|
self.writeln("%s %s;"%(ctype, ", ".join(names)))
|
|
return self
|
|
|
|
def function_helper(self):
|
|
if self.function_helper_writer != None:
|
|
writer = self.function_helper_writer.get_subwriter()
|
|
self.function_helper_writer.newline()
|
|
else:
|
|
writer = self.get_subwriter()
|
|
return writer
|
|
|
|
def function(self, name, return_type, args, static = False):
|
|
self.has_error_check = False
|
|
self.function_helper_writer = self.get_subwriter()
|
|
if static:
|
|
self.write("static ")
|
|
self.write(return_type)
|
|
self.write(" %s(%s)"% (name, args)).newline()
|
|
self.begin_block()
|
|
self.function_variables_writer = self.get_subwriter()
|
|
self.function_variables = {}
|
|
return self.function_variables_writer
|
|
|
|
def macro(self, name, args, define):
|
|
self.write("#define %s(%s) %s" % (name, args, define)).newline()
|
|
|
|
def ifdef(self, name):
|
|
indentation = self.indentation
|
|
self.indentation = 0;
|
|
self.write("#ifdef %s" % (name)).newline()
|
|
self.indentation = indentation
|
|
|
|
def ifdef_else(self, name):
|
|
indentation = self.indentation
|
|
self.indentation = 0;
|
|
self.write("#else /* %s */" % (name)).newline()
|
|
self.indentation = indentation
|
|
|
|
def endif(self, name):
|
|
indentation = self.indentation
|
|
self.indentation = 0;
|
|
self.write("#endif /* %s */" % (name)).newline()
|
|
self.indentation = indentation
|
|
|
|
def add_function_variable(self, ctype, name):
|
|
if self.function_variables.has_key(name):
|
|
assert(self.function_variables[name] == ctype)
|
|
else:
|
|
self.function_variables[name] = ctype
|
|
self.function_variables_writer.variable_def(ctype, name)
|
|
|
|
def pop_index(self):
|
|
index = self.indexes[self.current_index]
|
|
self.current_index = self.current_index + 1
|
|
self.add_function_variable("uint32_t", index)
|
|
return index
|
|
|
|
def push_index(self):
|
|
self.current_index = self.current_index - 1
|
|
|
|
class Index:
|
|
def __init__(self, writer, val):
|
|
self.writer = writer
|
|
self.val = val
|
|
|
|
def __enter__(self):
|
|
return self.val
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.writer.push_index()
|
|
|
|
def index(self, no_block = False):
|
|
if no_block:
|
|
return self.no_block(None)
|
|
val = self.pop_index()
|
|
return self.Index(self, val)
|