scsi: esp: check buffer length before reading scsi command
[qemu.git] / scripts / qapi.py
1 #
2 # QAPI helper library
3 #
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
6 #
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
10 #
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
13
14 import re
15 from ordereddict import OrderedDict
16 import errno
17 import getopt
18 import os
19 import sys
20 import string
21
22 builtin_types = {
23 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
35 'size': 'QTYPE_QINT',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
38 }
39
40 # Whitelist of commands allowed to return a non-dictionary
41 returns_whitelist = [
42 # From QMP:
43 'human-monitor-command',
44 'qom-get',
45 'query-migrate-cache-size',
46 'query-tpm-models',
47 'query-tpm-types',
48 'ringbuf-read',
49
50 # From QGA:
51 'guest-file-open',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
56 'guest-get-time',
57 'guest-set-vcpus',
58 'guest-sync',
59 'guest-sync-delimited',
60 ]
61
62 # Whitelist of entities allowed to violate case conventions
63 case_whitelist = [
64 # From QMP:
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
72 ]
73
74 enum_types = []
75 struct_types = []
76 union_types = []
77 events = []
78 all_names = {}
79
80 #
81 # Parsing the schema into expressions
82 #
83
84
85 def error_path(parent):
86 res = ""
87 while parent:
88 res = ("In file included from %s:%d:\n" % (parent['file'],
89 parent['line'])) + res
90 parent = parent['parent']
91 return res
92
93
94 class QAPISchemaError(Exception):
95 def __init__(self, schema, msg):
96 Exception.__init__(self)
97 self.fname = schema.fname
98 self.msg = msg
99 self.col = 1
100 self.line = schema.line
101 for ch in schema.src[schema.line_pos:schema.pos]:
102 if ch == '\t':
103 self.col = (self.col + 7) % 8 + 1
104 else:
105 self.col += 1
106 self.info = schema.incl_info
107
108 def __str__(self):
109 return error_path(self.info) + \
110 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
111
112
113 class QAPIExprError(Exception):
114 def __init__(self, expr_info, msg):
115 Exception.__init__(self)
116 assert expr_info
117 self.info = expr_info
118 self.msg = msg
119
120 def __str__(self):
121 return error_path(self.info['parent']) + \
122 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
123
124
125 class QAPISchemaParser(object):
126
127 def __init__(self, fp, previously_included=[], incl_info=None):
128 abs_fname = os.path.abspath(fp.name)
129 fname = fp.name
130 self.fname = fname
131 previously_included.append(abs_fname)
132 self.incl_info = incl_info
133 self.src = fp.read()
134 if self.src == '' or self.src[-1] != '\n':
135 self.src += '\n'
136 self.cursor = 0
137 self.line = 1
138 self.line_pos = 0
139 self.exprs = []
140 self.accept()
141
142 while self.tok is not None:
143 expr_info = {'file': fname, 'line': self.line,
144 'parent': self.incl_info}
145 expr = self.get_expr(False)
146 if isinstance(expr, dict) and "include" in expr:
147 if len(expr) != 1:
148 raise QAPIExprError(expr_info,
149 "Invalid 'include' directive")
150 include = expr["include"]
151 if not isinstance(include, str):
152 raise QAPIExprError(expr_info,
153 "Value of 'include' must be a string")
154 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
155 include)
156 # catch inclusion cycle
157 inf = expr_info
158 while inf:
159 if incl_abs_fname == os.path.abspath(inf['file']):
160 raise QAPIExprError(expr_info, "Inclusion loop for %s"
161 % include)
162 inf = inf['parent']
163 # skip multiple include of the same file
164 if incl_abs_fname in previously_included:
165 continue
166 try:
167 fobj = open(incl_abs_fname, 'r')
168 except IOError as e:
169 raise QAPIExprError(expr_info,
170 '%s: %s' % (e.strerror, include))
171 exprs_include = QAPISchemaParser(fobj, previously_included,
172 expr_info)
173 self.exprs.extend(exprs_include.exprs)
174 else:
175 expr_elem = {'expr': expr,
176 'info': expr_info}
177 self.exprs.append(expr_elem)
178
179 def accept(self):
180 while True:
181 self.tok = self.src[self.cursor]
182 self.pos = self.cursor
183 self.cursor += 1
184 self.val = None
185
186 if self.tok == '#':
187 self.cursor = self.src.find('\n', self.cursor)
188 elif self.tok in "{}:,[]":
189 return
190 elif self.tok == "'":
191 string = ''
192 esc = False
193 while True:
194 ch = self.src[self.cursor]
195 self.cursor += 1
196 if ch == '\n':
197 raise QAPISchemaError(self,
198 'Missing terminating "\'"')
199 if esc:
200 if ch == 'b':
201 string += '\b'
202 elif ch == 'f':
203 string += '\f'
204 elif ch == 'n':
205 string += '\n'
206 elif ch == 'r':
207 string += '\r'
208 elif ch == 't':
209 string += '\t'
210 elif ch == 'u':
211 value = 0
212 for _ in range(0, 4):
213 ch = self.src[self.cursor]
214 self.cursor += 1
215 if ch not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self,
217 '\\u escape needs 4 '
218 'hex digits')
219 value = (value << 4) + int(ch, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value or value > 0x7f:
225 raise QAPISchemaError(self,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
229 string += chr(value)
230 elif ch in "\\/'\"":
231 string += ch
232 else:
233 raise QAPISchemaError(self,
234 "Unknown escape \\%s" % ch)
235 esc = False
236 elif ch == "\\":
237 esc = True
238 elif ch == "'":
239 self.val = string
240 return
241 else:
242 string += ch
243 elif self.src.startswith("true", self.pos):
244 self.val = True
245 self.cursor += 3
246 return
247 elif self.src.startswith("false", self.pos):
248 self.val = False
249 self.cursor += 4
250 return
251 elif self.src.startswith("null", self.pos):
252 self.val = None
253 self.cursor += 3
254 return
255 elif self.tok == '\n':
256 if self.cursor == len(self.src):
257 self.tok = None
258 return
259 self.line += 1
260 self.line_pos = self.cursor
261 elif not self.tok.isspace():
262 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
263
264 def get_members(self):
265 expr = OrderedDict()
266 if self.tok == '}':
267 self.accept()
268 return expr
269 if self.tok != "'":
270 raise QAPISchemaError(self, 'Expected string or "}"')
271 while True:
272 key = self.val
273 self.accept()
274 if self.tok != ':':
275 raise QAPISchemaError(self, 'Expected ":"')
276 self.accept()
277 if key in expr:
278 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
279 expr[key] = self.get_expr(True)
280 if self.tok == '}':
281 self.accept()
282 return expr
283 if self.tok != ',':
284 raise QAPISchemaError(self, 'Expected "," or "}"')
285 self.accept()
286 if self.tok != "'":
287 raise QAPISchemaError(self, 'Expected string')
288
289 def get_values(self):
290 expr = []
291 if self.tok == ']':
292 self.accept()
293 return expr
294 if self.tok not in "{['tfn":
295 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
296 'boolean or "null"')
297 while True:
298 expr.append(self.get_expr(True))
299 if self.tok == ']':
300 self.accept()
301 return expr
302 if self.tok != ',':
303 raise QAPISchemaError(self, 'Expected "," or "]"')
304 self.accept()
305
306 def get_expr(self, nested):
307 if self.tok != '{' and not nested:
308 raise QAPISchemaError(self, 'Expected "{"')
309 if self.tok == '{':
310 self.accept()
311 expr = self.get_members()
312 elif self.tok == '[':
313 self.accept()
314 expr = self.get_values()
315 elif self.tok in "'tfn":
316 expr = self.val
317 self.accept()
318 else:
319 raise QAPISchemaError(self, 'Expected "{", "[" or string')
320 return expr
321
322 #
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
326 #
327
328
329 def find_base_members(base):
330 if isinstance(base, dict):
331 return base
332 base_struct_define = find_struct(base)
333 if not base_struct_define:
334 return None
335 return base_struct_define['data']
336
337
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type):
340 if qapi_type in builtin_types:
341 return builtin_types[qapi_type]
342 elif find_struct(qapi_type):
343 return "QTYPE_QDICT"
344 elif find_enum(qapi_type):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type):
347 return "QTYPE_QDICT"
348 return None
349
350
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr):
354 base = expr.get('base')
355 discriminator = expr.get('discriminator')
356
357 if not (discriminator and base):
358 return None
359
360 base_members = find_base_members(base)
361 if not base_members:
362 return None
363
364 discriminator_type = base_members.get(discriminator)
365 if not discriminator_type:
366 return None
367
368 return find_enum(discriminator_type)
369
370
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name = re.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
376
377
378 def check_name(expr_info, source, name, allow_optional=False,
379 enum_member=False):
380 global valid_name
381 membername = name
382
383 if not isinstance(name, str):
384 raise QAPIExprError(expr_info,
385 "%s requires a string name" % source)
386 if name.startswith('*'):
387 membername = name[1:]
388 if not allow_optional:
389 raise QAPIExprError(expr_info,
390 "%s does not allow optional name '%s'"
391 % (source, name))
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
394 if enum_member and membername[0].isdigit():
395 membername = 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
398 if not valid_name.match(membername) or \
399 c_name(membername, False).startswith('q_'):
400 raise QAPIExprError(expr_info,
401 "%s uses invalid name '%s'" % (source, name))
402
403
404 def add_name(name, info, meta, implicit=False):
405 global all_names
406 check_name(info, "'%s'" % meta, name)
407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
409 if name in all_names:
410 raise QAPIExprError(info,
411 "%s '%s' is already defined"
412 % (all_names[name], name))
413 if not implicit and (name.endswith('Kind') or name.endswith('List')):
414 raise QAPIExprError(info,
415 "%s '%s' should not end in '%s'"
416 % (meta, name, name[-4:]))
417 all_names[name] = meta
418
419
420 def add_struct(definition, info):
421 global struct_types
422 name = definition['struct']
423 add_name(name, info, 'struct')
424 struct_types.append(definition)
425
426
427 def find_struct(name):
428 global struct_types
429 for struct in struct_types:
430 if struct['struct'] == name:
431 return struct
432 return None
433
434
435 def add_union(definition, info):
436 global union_types
437 name = definition['union']
438 add_name(name, info, 'union')
439 union_types.append(definition)
440
441
442 def find_union(name):
443 global union_types
444 for union in union_types:
445 if union['union'] == name:
446 return union
447 return None
448
449
450 def add_enum(name, info, enum_values=None, implicit=False):
451 global enum_types
452 add_name(name, info, 'enum', implicit)
453 enum_types.append({"enum_name": name, "enum_values": enum_values})
454
455
456 def find_enum(name):
457 global enum_types
458 for enum in enum_types:
459 if enum['enum_name'] == name:
460 return enum
461 return None
462
463
464 def is_enum(name):
465 return find_enum(name) is not None
466
467
468 def check_type(expr_info, source, value, allow_array=False,
469 allow_dict=False, allow_optional=False,
470 allow_metas=[]):
471 global all_names
472
473 if value is None:
474 return
475
476 # Check if array type for value is okay
477 if isinstance(value, list):
478 if not allow_array:
479 raise QAPIExprError(expr_info,
480 "%s cannot be an array" % source)
481 if len(value) != 1 or not isinstance(value[0], str):
482 raise QAPIExprError(expr_info,
483 "%s: array type must contain single type name"
484 % source)
485 value = value[0]
486
487 # Check if type name for value is okay
488 if isinstance(value, str):
489 if value not in all_names:
490 raise QAPIExprError(expr_info,
491 "%s uses unknown type '%s'"
492 % (source, value))
493 if not all_names[value] in allow_metas:
494 raise QAPIExprError(expr_info,
495 "%s cannot use %s type '%s'"
496 % (source, all_names[value], value))
497 return
498
499 if not allow_dict:
500 raise QAPIExprError(expr_info,
501 "%s should be a type name" % source)
502
503 if not isinstance(value, OrderedDict):
504 raise QAPIExprError(expr_info,
505 "%s should be a dictionary or type name" % source)
506
507 # value is a dictionary, check that each member is okay
508 for (key, arg) in value.items():
509 check_name(expr_info, "Member of %s" % source, key,
510 allow_optional=allow_optional)
511 if c_name(key, False) == 'u' or c_name(key, False).startswith('has_'):
512 raise QAPIExprError(expr_info,
513 "Member of %s uses reserved name '%s'"
514 % (source, key))
515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
517 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
518 allow_array=True,
519 allow_metas=['built-in', 'union', 'alternate', 'struct',
520 'enum'])
521
522
523 def check_command(expr, expr_info):
524 name = expr['command']
525
526 check_type(expr_info, "'data' for command '%s'" % name,
527 expr.get('data'), allow_dict=True, allow_optional=True,
528 allow_metas=['struct'])
529 returns_meta = ['union', 'struct']
530 if name in returns_whitelist:
531 returns_meta += ['built-in', 'alternate', 'enum']
532 check_type(expr_info, "'returns' for command '%s'" % name,
533 expr.get('returns'), allow_array=True,
534 allow_optional=True, allow_metas=returns_meta)
535
536
537 def check_event(expr, expr_info):
538 global events
539 name = expr['event']
540
541 events.append(name)
542 check_type(expr_info, "'data' for event '%s'" % name,
543 expr.get('data'), allow_dict=True, allow_optional=True,
544 allow_metas=['struct'])
545
546
547 def check_union(expr, expr_info):
548 name = expr['union']
549 base = expr.get('base')
550 discriminator = expr.get('discriminator')
551 members = expr['data']
552
553 # Two types of unions, determined by discriminator.
554
555 # With no discriminator it is a simple union.
556 if discriminator is None:
557 enum_define = None
558 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
559 if base is not None:
560 raise QAPIExprError(expr_info,
561 "Simple union '%s' must not have a base"
562 % name)
563
564 # Else, it's a flat union.
565 else:
566 # The object must have a string or dictionary 'base'.
567 check_type(expr_info, "'base' for union '%s'" % name,
568 base, allow_dict=True, allow_optional=True,
569 allow_metas=['struct'])
570 if not base:
571 raise QAPIExprError(expr_info,
572 "Flat union '%s' must have a base"
573 % name)
574 base_members = find_base_members(base)
575 assert base_members
576
577 # The value of member 'discriminator' must name a non-optional
578 # member of the base struct.
579 check_name(expr_info, "Discriminator of flat union '%s'" % name,
580 discriminator)
581 discriminator_type = base_members.get(discriminator)
582 if not discriminator_type:
583 raise QAPIExprError(expr_info,
584 "Discriminator '%s' is not a member of base "
585 "struct '%s'"
586 % (discriminator, base))
587 enum_define = find_enum(discriminator_type)
588 allow_metas = ['struct']
589 # Do not allow string discriminator
590 if not enum_define:
591 raise QAPIExprError(expr_info,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator)
594
595 # Check every branch; don't allow an empty union
596 if len(members) == 0:
597 raise QAPIExprError(expr_info,
598 "Union '%s' cannot have empty 'data'" % name)
599 for (key, value) in members.items():
600 check_name(expr_info, "Member of union '%s'" % name, key)
601
602 # Each value must name a known type
603 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
604 value, allow_array=not base, allow_metas=allow_metas)
605
606 # If the discriminator names an enum type, then all members
607 # of 'data' must also be members of the enum type.
608 if enum_define:
609 if key not in enum_define['enum_values']:
610 raise QAPIExprError(expr_info,
611 "Discriminator value '%s' is not found in "
612 "enum '%s'" %
613 (key, enum_define["enum_name"]))
614
615
616 def check_alternate(expr, expr_info):
617 name = expr['alternate']
618 members = expr['data']
619 types_seen = {}
620
621 # Check every branch; require at least two branches
622 if len(members) < 2:
623 raise QAPIExprError(expr_info,
624 "Alternate '%s' should have at least two branches "
625 "in 'data'" % name)
626 for (key, value) in members.items():
627 check_name(expr_info, "Member of alternate '%s'" % name, key)
628
629 # Ensure alternates have no type conflicts.
630 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
631 value,
632 allow_metas=['built-in', 'union', 'struct', 'enum'])
633 qtype = find_alternate_member_qtype(value)
634 if not qtype:
635 raise QAPIExprError(expr_info,
636 "Alternate '%s' member '%s' cannot use "
637 "type '%s'" % (name, key, value))
638 if qtype in types_seen:
639 raise QAPIExprError(expr_info,
640 "Alternate '%s' member '%s' can't "
641 "be distinguished from member '%s'"
642 % (name, key, types_seen[qtype]))
643 types_seen[qtype] = key
644
645
646 def check_enum(expr, expr_info):
647 name = expr['enum']
648 members = expr.get('data')
649 prefix = expr.get('prefix')
650
651 if not isinstance(members, list):
652 raise QAPIExprError(expr_info,
653 "Enum '%s' requires an array for 'data'" % name)
654 if prefix is not None and not isinstance(prefix, str):
655 raise QAPIExprError(expr_info,
656 "Enum '%s' requires a string for 'prefix'" % name)
657 for member in members:
658 check_name(expr_info, "Member of enum '%s'" % name, member,
659 enum_member=True)
660
661
662 def check_struct(expr, expr_info):
663 name = expr['struct']
664 members = expr['data']
665
666 check_type(expr_info, "'data' for struct '%s'" % name, members,
667 allow_dict=True, allow_optional=True)
668 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
669 allow_metas=['struct'])
670
671
672 def check_keys(expr_elem, meta, required, optional=[]):
673 expr = expr_elem['expr']
674 info = expr_elem['info']
675 name = expr[meta]
676 if not isinstance(name, str):
677 raise QAPIExprError(info,
678 "'%s' key must have a string value" % meta)
679 required = required + [meta]
680 for (key, value) in expr.items():
681 if key not in required and key not in optional:
682 raise QAPIExprError(info,
683 "Unknown key '%s' in %s '%s'"
684 % (key, meta, name))
685 if (key == 'gen' or key == 'success-response') and value is not False:
686 raise QAPIExprError(info,
687 "'%s' of %s '%s' should only use false value"
688 % (key, meta, name))
689 for key in required:
690 if key not in expr:
691 raise QAPIExprError(info,
692 "Key '%s' is missing from %s '%s'"
693 % (key, meta, name))
694
695
696 def check_exprs(exprs):
697 global all_names
698
699 # Learn the types and check for valid expression keys
700 for builtin in builtin_types.keys():
701 all_names[builtin] = 'built-in'
702 for expr_elem in exprs:
703 expr = expr_elem['expr']
704 info = expr_elem['info']
705 if 'enum' in expr:
706 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
707 add_enum(expr['enum'], info, expr['data'])
708 elif 'union' in expr:
709 check_keys(expr_elem, 'union', ['data'],
710 ['base', 'discriminator'])
711 add_union(expr, info)
712 elif 'alternate' in expr:
713 check_keys(expr_elem, 'alternate', ['data'])
714 add_name(expr['alternate'], info, 'alternate')
715 elif 'struct' in expr:
716 check_keys(expr_elem, 'struct', ['data'], ['base'])
717 add_struct(expr, info)
718 elif 'command' in expr:
719 check_keys(expr_elem, 'command', [],
720 ['data', 'returns', 'gen', 'success-response'])
721 add_name(expr['command'], info, 'command')
722 elif 'event' in expr:
723 check_keys(expr_elem, 'event', [], ['data'])
724 add_name(expr['event'], info, 'event')
725 else:
726 raise QAPIExprError(expr_elem['info'],
727 "Expression is missing metatype")
728
729 # Try again for hidden UnionKind enum
730 for expr_elem in exprs:
731 expr = expr_elem['expr']
732 if 'union' in expr:
733 if not discriminator_find_enum_define(expr):
734 add_enum('%sKind' % expr['union'], expr_elem['info'],
735 implicit=True)
736 elif 'alternate' in expr:
737 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
738 implicit=True)
739
740 # Validate that exprs make sense
741 for expr_elem in exprs:
742 expr = expr_elem['expr']
743 info = expr_elem['info']
744
745 if 'enum' in expr:
746 check_enum(expr, info)
747 elif 'union' in expr:
748 check_union(expr, info)
749 elif 'alternate' in expr:
750 check_alternate(expr, info)
751 elif 'struct' in expr:
752 check_struct(expr, info)
753 elif 'command' in expr:
754 check_command(expr, info)
755 elif 'event' in expr:
756 check_event(expr, info)
757 else:
758 assert False, 'unexpected meta type'
759
760 return exprs
761
762
763 #
764 # Schema compiler frontend
765 #
766
767 class QAPISchemaEntity(object):
768 def __init__(self, name, info):
769 assert isinstance(name, str)
770 self.name = name
771 # For explicitly defined entities, info points to the (explicit)
772 # definition. For builtins (and their arrays), info is None.
773 # For implicitly defined entities, info points to a place that
774 # triggered the implicit definition (there may be more than one
775 # such place).
776 self.info = info
777
778 def c_name(self):
779 return c_name(self.name)
780
781 def check(self, schema):
782 pass
783
784 def is_implicit(self):
785 return not self.info
786
787 def visit(self, visitor):
788 pass
789
790
791 class QAPISchemaVisitor(object):
792 def visit_begin(self, schema):
793 pass
794
795 def visit_end(self):
796 pass
797
798 def visit_needed(self, entity):
799 # Default to visiting everything
800 return True
801
802 def visit_builtin_type(self, name, info, json_type):
803 pass
804
805 def visit_enum_type(self, name, info, values, prefix):
806 pass
807
808 def visit_array_type(self, name, info, element_type):
809 pass
810
811 def visit_object_type(self, name, info, base, members, variants):
812 pass
813
814 def visit_object_type_flat(self, name, info, members, variants):
815 pass
816
817 def visit_alternate_type(self, name, info, variants):
818 pass
819
820 def visit_command(self, name, info, arg_type, ret_type,
821 gen, success_response):
822 pass
823
824 def visit_event(self, name, info, arg_type):
825 pass
826
827
828 class QAPISchemaType(QAPISchemaEntity):
829 # Return the C type for common use.
830 # For the types we commonly box, this is a pointer type.
831 def c_type(self):
832 pass
833
834 # Return the C type to be used in a parameter list.
835 def c_param_type(self):
836 return self.c_type()
837
838 # Return the C type to be used where we suppress boxing.
839 def c_unboxed_type(self):
840 return self.c_type()
841
842 def json_type(self):
843 pass
844
845 def alternate_qtype(self):
846 json2qtype = {
847 'string': 'QTYPE_QSTRING',
848 'number': 'QTYPE_QFLOAT',
849 'int': 'QTYPE_QINT',
850 'boolean': 'QTYPE_QBOOL',
851 'object': 'QTYPE_QDICT'
852 }
853 return json2qtype.get(self.json_type())
854
855
856 class QAPISchemaBuiltinType(QAPISchemaType):
857 def __init__(self, name, json_type, c_type):
858 QAPISchemaType.__init__(self, name, None)
859 assert not c_type or isinstance(c_type, str)
860 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
861 'value')
862 self._json_type_name = json_type
863 self._c_type_name = c_type
864
865 def c_name(self):
866 return self.name
867
868 def c_type(self):
869 return self._c_type_name
870
871 def c_param_type(self):
872 if self.name == 'str':
873 return 'const ' + self._c_type_name
874 return self._c_type_name
875
876 def json_type(self):
877 return self._json_type_name
878
879 def visit(self, visitor):
880 visitor.visit_builtin_type(self.name, self.info, self.json_type())
881
882
883 class QAPISchemaEnumType(QAPISchemaType):
884 def __init__(self, name, info, values, prefix):
885 QAPISchemaType.__init__(self, name, info)
886 for v in values:
887 assert isinstance(v, QAPISchemaMember)
888 v.set_owner(name)
889 assert prefix is None or isinstance(prefix, str)
890 self.values = values
891 self.prefix = prefix
892
893 def check(self, schema):
894 seen = {}
895 for v in self.values:
896 v.check_clash(self.info, seen)
897
898 def is_implicit(self):
899 # See QAPISchema._make_implicit_enum_type()
900 return self.name.endswith('Kind')
901
902 def c_type(self):
903 return c_name(self.name)
904
905 def member_names(self):
906 return [v.name for v in self.values]
907
908 def json_type(self):
909 return 'string'
910
911 def visit(self, visitor):
912 visitor.visit_enum_type(self.name, self.info,
913 self.member_names(), self.prefix)
914
915
916 class QAPISchemaArrayType(QAPISchemaType):
917 def __init__(self, name, info, element_type):
918 QAPISchemaType.__init__(self, name, info)
919 assert isinstance(element_type, str)
920 self._element_type_name = element_type
921 self.element_type = None
922
923 def check(self, schema):
924 self.element_type = schema.lookup_type(self._element_type_name)
925 assert self.element_type
926
927 def is_implicit(self):
928 return True
929
930 def c_type(self):
931 return c_name(self.name) + pointer_suffix
932
933 def json_type(self):
934 return 'array'
935
936 def visit(self, visitor):
937 visitor.visit_array_type(self.name, self.info, self.element_type)
938
939
940 class QAPISchemaObjectType(QAPISchemaType):
941 def __init__(self, name, info, base, local_members, variants):
942 # struct has local_members, optional base, and no variants
943 # flat union has base, variants, and no local_members
944 # simple union has local_members, variants, and no base
945 QAPISchemaType.__init__(self, name, info)
946 assert base is None or isinstance(base, str)
947 for m in local_members:
948 assert isinstance(m, QAPISchemaObjectTypeMember)
949 m.set_owner(name)
950 if variants is not None:
951 assert isinstance(variants, QAPISchemaObjectTypeVariants)
952 variants.set_owner(name)
953 self._base_name = base
954 self.base = None
955 self.local_members = local_members
956 self.variants = variants
957 self.members = None
958
959 def check(self, schema):
960 if self.members is False: # check for cycles
961 raise QAPIExprError(self.info,
962 "Object %s contains itself" % self.name)
963 if self.members:
964 return
965 self.members = False # mark as being checked
966 seen = OrderedDict()
967 if self._base_name:
968 self.base = schema.lookup_type(self._base_name)
969 assert isinstance(self.base, QAPISchemaObjectType)
970 self.base.check(schema)
971 self.base.check_clash(schema, self.info, seen)
972 for m in self.local_members:
973 m.check(schema)
974 m.check_clash(self.info, seen)
975 self.members = seen.values()
976 if self.variants:
977 self.variants.check(schema, seen)
978 assert self.variants.tag_member in self.members
979 self.variants.check_clash(schema, self.info, seen)
980
981 # Check that the members of this type do not cause duplicate JSON members,
982 # and update seen to track the members seen so far. Report any errors
983 # on behalf of info, which is not necessarily self.info
984 def check_clash(self, schema, info, seen):
985 assert not self.variants # not implemented
986 for m in self.members:
987 m.check_clash(info, seen)
988
989 def is_implicit(self):
990 # See QAPISchema._make_implicit_object_type(), as well as
991 # _def_predefineds()
992 return self.name.startswith('q_')
993
994 def c_name(self):
995 return QAPISchemaType.c_name(self)
996
997 def c_type(self):
998 assert not self.is_implicit()
999 return c_name(self.name) + pointer_suffix
1000
1001 def c_unboxed_type(self):
1002 return c_name(self.name)
1003
1004 def json_type(self):
1005 return 'object'
1006
1007 def visit(self, visitor):
1008 visitor.visit_object_type(self.name, self.info,
1009 self.base, self.local_members, self.variants)
1010 visitor.visit_object_type_flat(self.name, self.info,
1011 self.members, self.variants)
1012
1013
1014 class QAPISchemaMember(object):
1015 role = 'member'
1016
1017 def __init__(self, name):
1018 assert isinstance(name, str)
1019 self.name = name
1020 self.owner = None
1021
1022 def set_owner(self, name):
1023 assert not self.owner
1024 self.owner = name
1025
1026 def check_clash(self, info, seen):
1027 cname = c_name(self.name)
1028 if cname.lower() != cname and self.owner not in case_whitelist:
1029 raise QAPIExprError(info,
1030 "%s should not use uppercase" % self.describe())
1031 if cname in seen:
1032 raise QAPIExprError(info,
1033 "%s collides with %s"
1034 % (self.describe(), seen[cname].describe()))
1035 seen[cname] = self
1036
1037 def _pretty_owner(self):
1038 owner = self.owner
1039 if owner.startswith('q_obj_'):
1040 # See QAPISchema._make_implicit_object_type() - reverse the
1041 # mapping there to create a nice human-readable description
1042 owner = owner[6:]
1043 if owner.endswith('-arg'):
1044 return '(parameter of %s)' % owner[:-4]
1045 elif owner.endswith('-base'):
1046 return '(base of %s)' % owner[:-5]
1047 else:
1048 assert owner.endswith('-wrapper')
1049 # Unreachable and not implemented
1050 assert False
1051 if owner.endswith('Kind'):
1052 # See QAPISchema._make_implicit_enum_type()
1053 return '(branch of %s)' % owner[:-4]
1054 return '(%s of %s)' % (self.role, owner)
1055
1056 def describe(self):
1057 return "'%s' %s" % (self.name, self._pretty_owner())
1058
1059
1060 class QAPISchemaObjectTypeMember(QAPISchemaMember):
1061 def __init__(self, name, typ, optional):
1062 QAPISchemaMember.__init__(self, name)
1063 assert isinstance(typ, str)
1064 assert isinstance(optional, bool)
1065 self._type_name = typ
1066 self.type = None
1067 self.optional = optional
1068
1069 def check(self, schema):
1070 assert self.owner
1071 self.type = schema.lookup_type(self._type_name)
1072 assert self.type
1073
1074
1075 class QAPISchemaObjectTypeVariants(object):
1076 def __init__(self, tag_name, tag_member, variants):
1077 # Flat unions pass tag_name but not tag_member.
1078 # Simple unions and alternates pass tag_member but not tag_name.
1079 # After check(), tag_member is always set, and tag_name remains
1080 # a reliable witness of being used by a flat union.
1081 assert bool(tag_member) != bool(tag_name)
1082 assert (isinstance(tag_name, str) or
1083 isinstance(tag_member, QAPISchemaObjectTypeMember))
1084 assert len(variants) > 0
1085 for v in variants:
1086 assert isinstance(v, QAPISchemaObjectTypeVariant)
1087 self.tag_name = tag_name
1088 self.tag_member = tag_member
1089 self.variants = variants
1090
1091 def set_owner(self, name):
1092 for v in self.variants:
1093 v.set_owner(name)
1094
1095 def check(self, schema, seen):
1096 if not self.tag_member: # flat union
1097 self.tag_member = seen[c_name(self.tag_name)]
1098 assert self.tag_name == self.tag_member.name
1099 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1100 for v in self.variants:
1101 v.check(schema)
1102 # Union names must match enum values; alternate names are
1103 # checked separately. Use 'seen' to tell the two apart.
1104 if seen:
1105 assert v.name in self.tag_member.type.member_names()
1106 assert isinstance(v.type, QAPISchemaObjectType)
1107 v.type.check(schema)
1108
1109 def check_clash(self, schema, info, seen):
1110 for v in self.variants:
1111 # Reset seen map for each variant, since qapi names from one
1112 # branch do not affect another branch
1113 assert isinstance(v.type, QAPISchemaObjectType)
1114 v.type.check_clash(schema, info, dict(seen))
1115
1116
1117 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1118 role = 'branch'
1119
1120 def __init__(self, name, typ):
1121 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1122
1123
1124 class QAPISchemaAlternateType(QAPISchemaType):
1125 def __init__(self, name, info, variants):
1126 QAPISchemaType.__init__(self, name, info)
1127 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1128 assert not variants.tag_name
1129 variants.set_owner(name)
1130 variants.tag_member.set_owner(self.name)
1131 self.variants = variants
1132
1133 def check(self, schema):
1134 self.variants.tag_member.check(schema)
1135 # Not calling self.variants.check_clash(), because there's nothing
1136 # to clash with
1137 self.variants.check(schema, {})
1138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1140 seen = {}
1141 for v in self.variants.variants:
1142 v.check_clash(self.info, seen)
1143
1144 def c_type(self):
1145 return c_name(self.name) + pointer_suffix
1146
1147 def json_type(self):
1148 return 'value'
1149
1150 def visit(self, visitor):
1151 visitor.visit_alternate_type(self.name, self.info, self.variants)
1152
1153
1154 class QAPISchemaCommand(QAPISchemaEntity):
1155 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1156 QAPISchemaEntity.__init__(self, name, info)
1157 assert not arg_type or isinstance(arg_type, str)
1158 assert not ret_type or isinstance(ret_type, str)
1159 self._arg_type_name = arg_type
1160 self.arg_type = None
1161 self._ret_type_name = ret_type
1162 self.ret_type = None
1163 self.gen = gen
1164 self.success_response = success_response
1165
1166 def check(self, schema):
1167 if self._arg_type_name:
1168 self.arg_type = schema.lookup_type(self._arg_type_name)
1169 assert isinstance(self.arg_type, QAPISchemaObjectType)
1170 assert not self.arg_type.variants # not implemented
1171 if self._ret_type_name:
1172 self.ret_type = schema.lookup_type(self._ret_type_name)
1173 assert isinstance(self.ret_type, QAPISchemaType)
1174
1175 def visit(self, visitor):
1176 visitor.visit_command(self.name, self.info,
1177 self.arg_type, self.ret_type,
1178 self.gen, self.success_response)
1179
1180
1181 class QAPISchemaEvent(QAPISchemaEntity):
1182 def __init__(self, name, info, arg_type):
1183 QAPISchemaEntity.__init__(self, name, info)
1184 assert not arg_type or isinstance(arg_type, str)
1185 self._arg_type_name = arg_type
1186 self.arg_type = None
1187
1188 def check(self, schema):
1189 if self._arg_type_name:
1190 self.arg_type = schema.lookup_type(self._arg_type_name)
1191 assert isinstance(self.arg_type, QAPISchemaObjectType)
1192 assert not self.arg_type.variants # not implemented
1193
1194 def visit(self, visitor):
1195 visitor.visit_event(self.name, self.info, self.arg_type)
1196
1197
1198 class QAPISchema(object):
1199 def __init__(self, fname):
1200 try:
1201 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1202 self._entity_dict = {}
1203 self._predefining = True
1204 self._def_predefineds()
1205 self._predefining = False
1206 self._def_exprs()
1207 self.check()
1208 except (QAPISchemaError, QAPIExprError) as err:
1209 print >>sys.stderr, err
1210 exit(1)
1211
1212 def _def_entity(self, ent):
1213 # Only the predefined types are allowed to not have info
1214 assert ent.info or self._predefining
1215 assert ent.name not in self._entity_dict
1216 self._entity_dict[ent.name] = ent
1217
1218 def lookup_entity(self, name, typ=None):
1219 ent = self._entity_dict.get(name)
1220 if typ and not isinstance(ent, typ):
1221 return None
1222 return ent
1223
1224 def lookup_type(self, name):
1225 return self.lookup_entity(name, QAPISchemaType)
1226
1227 def _def_builtin_type(self, name, json_type, c_type):
1228 self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type))
1229 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1230 # qapi-types.h from a single .c, all arrays of builtins must be
1231 # declared in the first file whether or not they are used. Nicer
1232 # would be to use lazy instantiation, while figuring out how to
1233 # avoid compilation issues with multiple qapi-types.h.
1234 self._make_array_type(name, None)
1235
1236 def _def_predefineds(self):
1237 for t in [('str', 'string', 'char' + pointer_suffix),
1238 ('number', 'number', 'double'),
1239 ('int', 'int', 'int64_t'),
1240 ('int8', 'int', 'int8_t'),
1241 ('int16', 'int', 'int16_t'),
1242 ('int32', 'int', 'int32_t'),
1243 ('int64', 'int', 'int64_t'),
1244 ('uint8', 'int', 'uint8_t'),
1245 ('uint16', 'int', 'uint16_t'),
1246 ('uint32', 'int', 'uint32_t'),
1247 ('uint64', 'int', 'uint64_t'),
1248 ('size', 'int', 'uint64_t'),
1249 ('bool', 'boolean', 'bool'),
1250 ('any', 'value', 'QObject' + pointer_suffix)]:
1251 self._def_builtin_type(*t)
1252 self.the_empty_object_type = QAPISchemaObjectType('q_empty', None,
1253 None, [], None)
1254 self._def_entity(self.the_empty_object_type)
1255 qtype_values = self._make_enum_members(['none', 'qnull', 'qint',
1256 'qstring', 'qdict', 'qlist',
1257 'qfloat', 'qbool'])
1258 self._def_entity(QAPISchemaEnumType('QType', None, qtype_values,
1259 'QTYPE'))
1260
1261 def _make_enum_members(self, values):
1262 return [QAPISchemaMember(v) for v in values]
1263
1264 def _make_implicit_enum_type(self, name, info, values):
1265 # See also QAPISchemaObjectTypeMember._pretty_owner()
1266 name = name + 'Kind' # Use namespace reserved by add_name()
1267 self._def_entity(QAPISchemaEnumType(
1268 name, info, self._make_enum_members(values), None))
1269 return name
1270
1271 def _make_array_type(self, element_type, info):
1272 name = element_type + 'List' # Use namespace reserved by add_name()
1273 if not self.lookup_type(name):
1274 self._def_entity(QAPISchemaArrayType(name, info, element_type))
1275 return name
1276
1277 def _make_implicit_object_type(self, name, info, role, members):
1278 if not members:
1279 return None
1280 # See also QAPISchemaObjectTypeMember._pretty_owner()
1281 name = 'q_obj_%s-%s' % (name, role)
1282 if not self.lookup_entity(name, QAPISchemaObjectType):
1283 self._def_entity(QAPISchemaObjectType(name, info, None,
1284 members, None))
1285 return name
1286
1287 def _def_enum_type(self, expr, info):
1288 name = expr['enum']
1289 data = expr['data']
1290 prefix = expr.get('prefix')
1291 self._def_entity(QAPISchemaEnumType(
1292 name, info, self._make_enum_members(data), prefix))
1293
1294 def _make_member(self, name, typ, info):
1295 optional = False
1296 if name.startswith('*'):
1297 name = name[1:]
1298 optional = True
1299 if isinstance(typ, list):
1300 assert len(typ) == 1
1301 typ = self._make_array_type(typ[0], info)
1302 return QAPISchemaObjectTypeMember(name, typ, optional)
1303
1304 def _make_members(self, data, info):
1305 return [self._make_member(key, value, info)
1306 for (key, value) in data.iteritems()]
1307
1308 def _def_struct_type(self, expr, info):
1309 name = expr['struct']
1310 base = expr.get('base')
1311 data = expr['data']
1312 self._def_entity(QAPISchemaObjectType(name, info, base,
1313 self._make_members(data, info),
1314 None))
1315
1316 def _make_variant(self, case, typ):
1317 return QAPISchemaObjectTypeVariant(case, typ)
1318
1319 def _make_simple_variant(self, case, typ, info):
1320 if isinstance(typ, list):
1321 assert len(typ) == 1
1322 typ = self._make_array_type(typ[0], info)
1323 typ = self._make_implicit_object_type(
1324 typ, info, 'wrapper', [self._make_member('data', typ, info)])
1325 return QAPISchemaObjectTypeVariant(case, typ)
1326
1327 def _def_union_type(self, expr, info):
1328 name = expr['union']
1329 data = expr['data']
1330 base = expr.get('base')
1331 tag_name = expr.get('discriminator')
1332 tag_member = None
1333 if isinstance(base, dict):
1334 base = (self._make_implicit_object_type(
1335 name, info, 'base', self._make_members(base, info)))
1336 if tag_name:
1337 variants = [self._make_variant(key, value)
1338 for (key, value) in data.iteritems()]
1339 members = []
1340 else:
1341 variants = [self._make_simple_variant(key, value, info)
1342 for (key, value) in data.iteritems()]
1343 typ = self._make_implicit_enum_type(name, info,
1344 [v.name for v in variants])
1345 tag_member = QAPISchemaObjectTypeMember('type', typ, False)
1346 members = [tag_member]
1347 self._def_entity(
1348 QAPISchemaObjectType(name, info, base, members,
1349 QAPISchemaObjectTypeVariants(tag_name,
1350 tag_member,
1351 variants)))
1352
1353 def _def_alternate_type(self, expr, info):
1354 name = expr['alternate']
1355 data = expr['data']
1356 variants = [self._make_variant(key, value)
1357 for (key, value) in data.iteritems()]
1358 tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
1359 self._def_entity(
1360 QAPISchemaAlternateType(name, info,
1361 QAPISchemaObjectTypeVariants(None,
1362 tag_member,
1363 variants)))
1364
1365 def _def_command(self, expr, info):
1366 name = expr['command']
1367 data = expr.get('data')
1368 rets = expr.get('returns')
1369 gen = expr.get('gen', True)
1370 success_response = expr.get('success-response', True)
1371 if isinstance(data, OrderedDict):
1372 data = self._make_implicit_object_type(
1373 name, info, 'arg', self._make_members(data, info))
1374 if isinstance(rets, list):
1375 assert len(rets) == 1
1376 rets = self._make_array_type(rets[0], info)
1377 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1378 success_response))
1379
1380 def _def_event(self, expr, info):
1381 name = expr['event']
1382 data = expr.get('data')
1383 if isinstance(data, OrderedDict):
1384 data = self._make_implicit_object_type(
1385 name, info, 'arg', self._make_members(data, info))
1386 self._def_entity(QAPISchemaEvent(name, info, data))
1387
1388 def _def_exprs(self):
1389 for expr_elem in self.exprs:
1390 expr = expr_elem['expr']
1391 info = expr_elem['info']
1392 if 'enum' in expr:
1393 self._def_enum_type(expr, info)
1394 elif 'struct' in expr:
1395 self._def_struct_type(expr, info)
1396 elif 'union' in expr:
1397 self._def_union_type(expr, info)
1398 elif 'alternate' in expr:
1399 self._def_alternate_type(expr, info)
1400 elif 'command' in expr:
1401 self._def_command(expr, info)
1402 elif 'event' in expr:
1403 self._def_event(expr, info)
1404 else:
1405 assert False
1406
1407 def check(self):
1408 for ent in self._entity_dict.values():
1409 ent.check(self)
1410
1411 def visit(self, visitor):
1412 visitor.visit_begin(self)
1413 for (name, entity) in sorted(self._entity_dict.items()):
1414 if visitor.visit_needed(entity):
1415 entity.visit(visitor)
1416 visitor.visit_end()
1417
1418
1419 #
1420 # Code generation helpers
1421 #
1422
1423 def camel_case(name):
1424 new_name = ''
1425 first = True
1426 for ch in name:
1427 if ch in ['_', '-']:
1428 first = True
1429 elif first:
1430 new_name += ch.upper()
1431 first = False
1432 else:
1433 new_name += ch.lower()
1434 return new_name
1435
1436
1437 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1438 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1439 # ENUM24_Name -> ENUM24_NAME
1440 def camel_to_upper(value):
1441 c_fun_str = c_name(value, False)
1442 if value.isupper():
1443 return c_fun_str
1444
1445 new_name = ''
1446 l = len(c_fun_str)
1447 for i in range(l):
1448 c = c_fun_str[i]
1449 # When c is upper and no "_" appears before, do more checks
1450 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1451 if i < l - 1 and c_fun_str[i + 1].islower():
1452 new_name += '_'
1453 elif c_fun_str[i - 1].isdigit():
1454 new_name += '_'
1455 new_name += c
1456 return new_name.lstrip('_').upper()
1457
1458
1459 def c_enum_const(type_name, const_name, prefix=None):
1460 if prefix is not None:
1461 type_name = prefix
1462 return camel_to_upper(type_name) + '_' + c_name(const_name, False).upper()
1463
1464 c_name_trans = string.maketrans('.-', '__')
1465
1466
1467 # Map @name to a valid C identifier.
1468 # If @protect, avoid returning certain ticklish identifiers (like
1469 # C keywords) by prepending "q_".
1470 #
1471 # Used for converting 'name' from a 'name':'type' qapi definition
1472 # into a generated struct member, as well as converting type names
1473 # into substrings of a generated C function name.
1474 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1475 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1476 def c_name(name, protect=True):
1477 # ANSI X3J11/88-090, 3.1.1
1478 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1479 'default', 'do', 'double', 'else', 'enum', 'extern',
1480 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1481 'return', 'short', 'signed', 'sizeof', 'static',
1482 'struct', 'switch', 'typedef', 'union', 'unsigned',
1483 'void', 'volatile', 'while'])
1484 # ISO/IEC 9899:1999, 6.4.1
1485 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1486 # ISO/IEC 9899:2011, 6.4.1
1487 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1488 '_Noreturn', '_Static_assert', '_Thread_local'])
1489 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1490 # excluding _.*
1491 gcc_words = set(['asm', 'typeof'])
1492 # C++ ISO/IEC 14882:2003 2.11
1493 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1494 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1495 'namespace', 'new', 'operator', 'private', 'protected',
1496 'public', 'reinterpret_cast', 'static_cast', 'template',
1497 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1498 'using', 'virtual', 'wchar_t',
1499 # alternative representations
1500 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1501 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1502 # namespace pollution:
1503 polluted_words = set(['unix', 'errno', 'mips', 'sparc'])
1504 name = name.translate(c_name_trans)
1505 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1506 | cpp_words | polluted_words):
1507 return "q_" + name
1508 return name
1509
1510 eatspace = '\033EATSPACE.'
1511 pointer_suffix = ' *' + eatspace
1512
1513
1514 def genindent(count):
1515 ret = ""
1516 for _ in range(count):
1517 ret += " "
1518 return ret
1519
1520 indent_level = 0
1521
1522
1523 def push_indent(indent_amount=4):
1524 global indent_level
1525 indent_level += indent_amount
1526
1527
1528 def pop_indent(indent_amount=4):
1529 global indent_level
1530 indent_level -= indent_amount
1531
1532
1533 # Generate @code with @kwds interpolated.
1534 # Obey indent_level, and strip eatspace.
1535 def cgen(code, **kwds):
1536 raw = code % kwds
1537 if indent_level:
1538 indent = genindent(indent_level)
1539 # re.subn() lacks flags support before Python 2.7, use re.compile()
1540 raw = re.subn(re.compile("^.", re.MULTILINE),
1541 indent + r'\g<0>', raw)
1542 raw = raw[0]
1543 return re.sub(re.escape(eatspace) + ' *', '', raw)
1544
1545
1546 def mcgen(code, **kwds):
1547 if code[0] == '\n':
1548 code = code[1:]
1549 return cgen(code, **kwds)
1550
1551
1552 def guardname(filename):
1553 return c_name(filename, protect=False).upper()
1554
1555
1556 def guardstart(name):
1557 return mcgen('''
1558
1559 #ifndef %(name)s
1560 #define %(name)s
1561
1562 ''',
1563 name=guardname(name))
1564
1565
1566 def guardend(name):
1567 return mcgen('''
1568
1569 #endif /* %(name)s */
1570
1571 ''',
1572 name=guardname(name))
1573
1574
1575 def gen_enum_lookup(name, values, prefix=None):
1576 ret = mcgen('''
1577
1578 const char *const %(c_name)s_lookup[] = {
1579 ''',
1580 c_name=c_name(name))
1581 for value in values:
1582 index = c_enum_const(name, value, prefix)
1583 ret += mcgen('''
1584 [%(index)s] = "%(value)s",
1585 ''',
1586 index=index, value=value)
1587
1588 max_index = c_enum_const(name, '_MAX', prefix)
1589 ret += mcgen('''
1590 [%(max_index)s] = NULL,
1591 };
1592 ''',
1593 max_index=max_index)
1594 return ret
1595
1596
1597 def gen_enum(name, values, prefix=None):
1598 # append automatically generated _MAX value
1599 enum_values = values + ['_MAX']
1600
1601 ret = mcgen('''
1602
1603 typedef enum %(c_name)s {
1604 ''',
1605 c_name=c_name(name))
1606
1607 i = 0
1608 for value in enum_values:
1609 ret += mcgen('''
1610 %(c_enum)s = %(i)d,
1611 ''',
1612 c_enum=c_enum_const(name, value, prefix),
1613 i=i)
1614 i += 1
1615
1616 ret += mcgen('''
1617 } %(c_name)s;
1618 ''',
1619 c_name=c_name(name))
1620
1621 ret += mcgen('''
1622
1623 extern const char *const %(c_name)s_lookup[];
1624 ''',
1625 c_name=c_name(name))
1626 return ret
1627
1628
1629 def gen_params(arg_type, extra):
1630 if not arg_type:
1631 return extra
1632 assert not arg_type.variants
1633 ret = ''
1634 sep = ''
1635 for memb in arg_type.members:
1636 ret += sep
1637 sep = ', '
1638 if memb.optional:
1639 ret += 'bool has_%s, ' % c_name(memb.name)
1640 ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name))
1641 if extra:
1642 ret += sep + extra
1643 return ret
1644
1645
1646 def gen_err_check():
1647 return mcgen('''
1648 if (err) {
1649 goto out;
1650 }
1651 ''')
1652
1653
1654 #
1655 # Common command line parsing
1656 #
1657
1658
1659 def parse_command_line(extra_options="", extra_long_options=[]):
1660
1661 try:
1662 opts, args = getopt.gnu_getopt(sys.argv[1:],
1663 "chp:o:" + extra_options,
1664 ["source", "header", "prefix=",
1665 "output-dir="] + extra_long_options)
1666 except getopt.GetoptError as err:
1667 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1668 sys.exit(1)
1669
1670 output_dir = ""
1671 prefix = ""
1672 do_c = False
1673 do_h = False
1674 extra_opts = []
1675
1676 for oa in opts:
1677 o, a = oa
1678 if o in ("-p", "--prefix"):
1679 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1680 if match.end() != len(a):
1681 print >>sys.stderr, \
1682 "%s: 'funny character '%s' in argument of --prefix" \
1683 % (sys.argv[0], a[match.end()])
1684 sys.exit(1)
1685 prefix = a
1686 elif o in ("-o", "--output-dir"):
1687 output_dir = a + "/"
1688 elif o in ("-c", "--source"):
1689 do_c = True
1690 elif o in ("-h", "--header"):
1691 do_h = True
1692 else:
1693 extra_opts.append(oa)
1694
1695 if not do_c and not do_h:
1696 do_c = True
1697 do_h = True
1698
1699 if len(args) != 1:
1700 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1701 sys.exit(1)
1702 fname = args[0]
1703
1704 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1705
1706 #
1707 # Generate output files with boilerplate
1708 #
1709
1710
1711 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1712 c_comment, h_comment):
1713 guard = guardname(prefix + h_file)
1714 c_file = output_dir + prefix + c_file
1715 h_file = output_dir + prefix + h_file
1716
1717 if output_dir:
1718 try:
1719 os.makedirs(output_dir)
1720 except os.error as e:
1721 if e.errno != errno.EEXIST:
1722 raise
1723
1724 def maybe_open(really, name, opt):
1725 if really:
1726 return open(name, opt)
1727 else:
1728 import StringIO
1729 return StringIO.StringIO()
1730
1731 fdef = maybe_open(do_c, c_file, 'w')
1732 fdecl = maybe_open(do_h, h_file, 'w')
1733
1734 fdef.write(mcgen('''
1735 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1736 %(comment)s
1737 ''',
1738 comment=c_comment))
1739
1740 fdecl.write(mcgen('''
1741 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1742 %(comment)s
1743 #ifndef %(guard)s
1744 #define %(guard)s
1745
1746 ''',
1747 comment=h_comment, guard=guard))
1748
1749 return (fdef, fdecl)
1750
1751
1752 def close_output(fdef, fdecl):
1753 fdecl.write('''
1754 #endif
1755 ''')
1756 fdecl.close()
1757 fdef.close()