def check_two_call_command(self, name, info, params): """Check a two-call-idiom command.""" named_params = [(getElemName(p), p) for p in params] # Find the three important parameters capacity_input_param_name = None capacity_input_param_match = None count_output_param_name = None count_output_param_match = None array_param_name = None for param_name, param_elem in named_params: match = CAPACITY_INPUT_RE.match(param_name) if match: capacity_input_param_name = param_name capacity_input_param_match = match self.check_two_call_capacity_input(param_name, param_elem, match) continue match = COUNT_OUTPUT_RE.match(param_name) if match: count_output_param_name = param_name count_output_param_match = match self.check_two_call_count_output(param_name, param_elem, match) continue # Try detecting the output array using its length field if capacity_input_param_name: length = LengthEntry.parse_len_from_param(param_elem) if length and length[0].other_param_name == capacity_input_param_name: array_param_name = param_name if not capacity_input_param_name: self.record_error('Apparent two-call-idiom call missing a *CapacityInput parameter') if not count_output_param_name: self.record_error('Apparent two-call-idiom call missing a *CountOutput parameter') if not array_param_name: self.record_error('Apparent two-call-idiom call missing an array output parameter') if not capacity_input_param_name or \ not count_output_param_name or \ not array_param_name: # If we're missing at least one, stop checking two-call stuff here. return input_prefix = capacity_input_param_match.group('itemname') output_prefix = count_output_param_match.group('itemname') if input_prefix != output_prefix: self.record_error('Two-call-idiom call has "item name" prefixes for input and output names that mismatch:', input_prefix, output_prefix) # If not a "buffer", pluralize the item name for the array name. if input_prefix == TWO_CALL_STRING_NAME and output_prefix == TWO_CALL_STRING_NAME: expected_array_name = TWO_CALL_STRING_NAME else: expected_array_name = pluralize(input_prefix) if expected_array_name != array_param_name: self.record_error('Two-call-idiom call has array parameter with unexpected name: expected', expected_array_name, 'got', array_param_name)
def check_two_call_array(self, param_name, param_elem, match): """Check a two-call-idiom command's array output parameter.""" optional = param_elem.get('optional') if optional != 'true': self.record_error( 'Two-call-idiom call array parameter has incorrect "optional" attribute', optional, '- expected "true"') type_elem = param_elem.find('type') assert (type_elem is not None) tail = type_elem.tail.strip() if '*' not in tail: self.record_error('Two-call-idiom call has array parameter', param_name, 'that is not a pointer:', type_elem.text, type_elem.tail) length = LengthEntry.parse_len_from_param(param_elem) if not length[0].other_param_name: self.record_error('Two-call-idiom call has array parameter', param_name, 'whose first length is not another parameter:', length[0]) # Only valid reason to have more than 1 comma-separated entry in len is for strings, # which are named "buffer". if length is None: self.record_error('Two-call-idiom call has array parameter', param_name, 'with no length attribute specified') else: if len(length) > 2: self.record_error( 'Two-call-idiom call has array parameter', param_name, 'with too many lengths - should be 1 or 2 comma-separated lengths, not', len(length)) if len(length) == 2: if not length[1].null_terminated: self.record_error( 'Two-call-idiom call has two-length array parameter', param_name, 'whose second length is not "null-terminated":', length[1]) param_type = getElemType(param_elem) if param_type != 'char': self.record_error( 'Two-call-idiom call has two-length array parameter', param_name, 'that is not a string:', param_type) if param_name != TWO_CALL_STRING_NAME: self.record_error( 'Two-call-idiom call has two-length array parameter', param_name, 'that is not named "buffer"')