1*b7893ccfSSadaf Ebrahimi#!/usr/bin/python3 -i 2*b7893ccfSSadaf Ebrahimi# 3*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 The Khronos Group Inc. 4*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Valve Corporation 5*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 LunarG, Inc. 6*b7893ccfSSadaf Ebrahimi# Copyright (c) 2015-2019 Google Inc. 7*b7893ccfSSadaf Ebrahimi# 8*b7893ccfSSadaf Ebrahimi# Licensed under the Apache License, Version 2.0 (the "License"); 9*b7893ccfSSadaf Ebrahimi# you may not use this file except in compliance with the License. 10*b7893ccfSSadaf Ebrahimi# You may obtain a copy of the License at 11*b7893ccfSSadaf Ebrahimi# 12*b7893ccfSSadaf Ebrahimi# http://www.apache.org/licenses/LICENSE-2.0 13*b7893ccfSSadaf Ebrahimi# 14*b7893ccfSSadaf Ebrahimi# Unless required by applicable law or agreed to in writing, software 15*b7893ccfSSadaf Ebrahimi# distributed under the License is distributed on an "AS IS" BASIS, 16*b7893ccfSSadaf Ebrahimi# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17*b7893ccfSSadaf Ebrahimi# See the License for the specific language governing permissions and 18*b7893ccfSSadaf Ebrahimi# limitations under the License. 19*b7893ccfSSadaf Ebrahimi# 20*b7893ccfSSadaf Ebrahimi# Author: Dustin Graves <dustin@lunarg.com> 21*b7893ccfSSadaf Ebrahimi# Author: Mark Lobodzinski <mark@lunarg.com> 22*b7893ccfSSadaf Ebrahimi# Author: Dave Houlton <daveh@lunarg.com> 23*b7893ccfSSadaf Ebrahimi 24*b7893ccfSSadaf Ebrahimiimport os,re,sys,string,json 25*b7893ccfSSadaf Ebrahimiimport xml.etree.ElementTree as etree 26*b7893ccfSSadaf Ebrahimifrom generator import * 27*b7893ccfSSadaf Ebrahimifrom collections import namedtuple 28*b7893ccfSSadaf Ebrahimifrom common_codegen import * 29*b7893ccfSSadaf Ebrahimi 30*b7893ccfSSadaf Ebrahimi# This is a workaround to use a Python 2.7 and 3.x compatible syntax. 31*b7893ccfSSadaf Ebrahimifrom io import open 32*b7893ccfSSadaf Ebrahimi 33*b7893ccfSSadaf Ebrahimi# ParameterValidationGeneratorOptions - subclass of GeneratorOptions. 34*b7893ccfSSadaf Ebrahimi# 35*b7893ccfSSadaf Ebrahimi# Adds options used by ParameterValidationOutputGenerator object during Parameter validation layer generation. 36*b7893ccfSSadaf Ebrahimi# 37*b7893ccfSSadaf Ebrahimi# Additional members 38*b7893ccfSSadaf Ebrahimi# prefixText - list of strings to prefix generated header with 39*b7893ccfSSadaf Ebrahimi# (usually a copyright statement + calling convention macros). 40*b7893ccfSSadaf Ebrahimi# protectFile - True if multiple inclusion protection should be 41*b7893ccfSSadaf Ebrahimi# generated (based on the filename) around the entire header. 42*b7893ccfSSadaf Ebrahimi# protectFeature - True if #ifndef..#endif protection should be 43*b7893ccfSSadaf Ebrahimi# generated around a feature interface in the header file. 44*b7893ccfSSadaf Ebrahimi# genFuncPointers - True if function pointer typedefs should be 45*b7893ccfSSadaf Ebrahimi# generated 46*b7893ccfSSadaf Ebrahimi# protectProto - If conditional protection should be generated 47*b7893ccfSSadaf Ebrahimi# around prototype declarations, set to either '#ifdef' 48*b7893ccfSSadaf Ebrahimi# to require opt-in (#ifdef protectProtoStr) or '#ifndef' 49*b7893ccfSSadaf Ebrahimi# to require opt-out (#ifndef protectProtoStr). Otherwise 50*b7893ccfSSadaf Ebrahimi# set to None. 51*b7893ccfSSadaf Ebrahimi# protectProtoStr - #ifdef/#ifndef symbol to use around prototype 52*b7893ccfSSadaf Ebrahimi# declarations, if protectProto is set 53*b7893ccfSSadaf Ebrahimi# apicall - string to use for the function declaration prefix, 54*b7893ccfSSadaf Ebrahimi# such as APICALL on Windows. 55*b7893ccfSSadaf Ebrahimi# apientry - string to use for the calling convention macro, 56*b7893ccfSSadaf Ebrahimi# in typedefs, such as APIENTRY. 57*b7893ccfSSadaf Ebrahimi# apientryp - string to use for the calling convention macro 58*b7893ccfSSadaf Ebrahimi# in function pointer typedefs, such as APIENTRYP. 59*b7893ccfSSadaf Ebrahimi# indentFuncProto - True if prototype declarations should put each 60*b7893ccfSSadaf Ebrahimi# parameter on a separate line 61*b7893ccfSSadaf Ebrahimi# indentFuncPointer - True if typedefed function pointers should put each 62*b7893ccfSSadaf Ebrahimi# parameter on a separate line 63*b7893ccfSSadaf Ebrahimi# alignFuncParam - if nonzero and parameters are being put on a 64*b7893ccfSSadaf Ebrahimi# separate line, align parameter names at the specified column 65*b7893ccfSSadaf Ebrahimiclass ParameterValidationGeneratorOptions(GeneratorOptions): 66*b7893ccfSSadaf Ebrahimi def __init__(self, 67*b7893ccfSSadaf Ebrahimi conventions = None, 68*b7893ccfSSadaf Ebrahimi filename = None, 69*b7893ccfSSadaf Ebrahimi directory = '.', 70*b7893ccfSSadaf Ebrahimi apiname = None, 71*b7893ccfSSadaf Ebrahimi profile = None, 72*b7893ccfSSadaf Ebrahimi versions = '.*', 73*b7893ccfSSadaf Ebrahimi emitversions = '.*', 74*b7893ccfSSadaf Ebrahimi defaultExtensions = None, 75*b7893ccfSSadaf Ebrahimi addExtensions = None, 76*b7893ccfSSadaf Ebrahimi removeExtensions = None, 77*b7893ccfSSadaf Ebrahimi emitExtensions = None, 78*b7893ccfSSadaf Ebrahimi sortProcedure = regSortFeatures, 79*b7893ccfSSadaf Ebrahimi prefixText = "", 80*b7893ccfSSadaf Ebrahimi apicall = '', 81*b7893ccfSSadaf Ebrahimi apientry = '', 82*b7893ccfSSadaf Ebrahimi apientryp = '', 83*b7893ccfSSadaf Ebrahimi indentFuncProto = True, 84*b7893ccfSSadaf Ebrahimi indentFuncPointer = False, 85*b7893ccfSSadaf Ebrahimi alignFuncParam = 0, 86*b7893ccfSSadaf Ebrahimi expandEnumerants = True, 87*b7893ccfSSadaf Ebrahimi valid_usage_path = ''): 88*b7893ccfSSadaf Ebrahimi GeneratorOptions.__init__(self, conventions, filename, directory, apiname, profile, 89*b7893ccfSSadaf Ebrahimi versions, emitversions, defaultExtensions, 90*b7893ccfSSadaf Ebrahimi addExtensions, removeExtensions, emitExtensions, sortProcedure) 91*b7893ccfSSadaf Ebrahimi self.prefixText = prefixText 92*b7893ccfSSadaf Ebrahimi self.apicall = apicall 93*b7893ccfSSadaf Ebrahimi self.apientry = apientry 94*b7893ccfSSadaf Ebrahimi self.apientryp = apientryp 95*b7893ccfSSadaf Ebrahimi self.indentFuncProto = indentFuncProto 96*b7893ccfSSadaf Ebrahimi self.indentFuncPointer = indentFuncPointer 97*b7893ccfSSadaf Ebrahimi self.alignFuncParam = alignFuncParam 98*b7893ccfSSadaf Ebrahimi self.expandEnumerants = expandEnumerants 99*b7893ccfSSadaf Ebrahimi self.valid_usage_path = valid_usage_path 100*b7893ccfSSadaf Ebrahimi 101*b7893ccfSSadaf Ebrahimi# ParameterValidationOutputGenerator - subclass of OutputGenerator. 102*b7893ccfSSadaf Ebrahimi# Generates param checker layer code. 103*b7893ccfSSadaf Ebrahimi# 104*b7893ccfSSadaf Ebrahimi# ---- methods ---- 105*b7893ccfSSadaf Ebrahimi# ParamCheckerOutputGenerator(errFile, warnFile, diagFile) - args as for 106*b7893ccfSSadaf Ebrahimi# OutputGenerator. Defines additional internal state. 107*b7893ccfSSadaf Ebrahimi# ---- methods overriding base class ---- 108*b7893ccfSSadaf Ebrahimi# beginFile(genOpts) 109*b7893ccfSSadaf Ebrahimi# endFile() 110*b7893ccfSSadaf Ebrahimi# beginFeature(interface, emit) 111*b7893ccfSSadaf Ebrahimi# endFeature() 112*b7893ccfSSadaf Ebrahimi# genType(typeinfo,name) 113*b7893ccfSSadaf Ebrahimi# genStruct(typeinfo,name) 114*b7893ccfSSadaf Ebrahimi# genGroup(groupinfo,name) 115*b7893ccfSSadaf Ebrahimi# genEnum(enuminfo, name) 116*b7893ccfSSadaf Ebrahimi# genCmd(cmdinfo) 117*b7893ccfSSadaf Ebrahimiclass ParameterValidationOutputGenerator(OutputGenerator): 118*b7893ccfSSadaf Ebrahimi """Generate Parameter Validation code based on XML element attributes""" 119*b7893ccfSSadaf Ebrahimi # This is an ordered list of sections in the header file. 120*b7893ccfSSadaf Ebrahimi ALL_SECTIONS = ['command'] 121*b7893ccfSSadaf Ebrahimi def __init__(self, 122*b7893ccfSSadaf Ebrahimi errFile = sys.stderr, 123*b7893ccfSSadaf Ebrahimi warnFile = sys.stderr, 124*b7893ccfSSadaf Ebrahimi diagFile = sys.stdout): 125*b7893ccfSSadaf Ebrahimi OutputGenerator.__init__(self, errFile, warnFile, diagFile) 126*b7893ccfSSadaf Ebrahimi self.INDENT_SPACES = 4 127*b7893ccfSSadaf Ebrahimi self.declarations = [] 128*b7893ccfSSadaf Ebrahimi 129*b7893ccfSSadaf Ebrahimi inline_custom_source_preamble = """ 130*b7893ccfSSadaf Ebrahimi""" 131*b7893ccfSSadaf Ebrahimi 132*b7893ccfSSadaf Ebrahimi # These functions have additional, custom-written checks in the utils cpp file. CodeGen will automatically add a call 133*b7893ccfSSadaf Ebrahimi # to those functions of the form 'bool manual_PreCallValidateAPIName', where the 'vk' is dropped. 134*b7893ccfSSadaf Ebrahimi # see 'manual_PreCallValidateCreateGraphicsPipelines' as an example. 135*b7893ccfSSadaf Ebrahimi self.functions_with_manual_checks = [ 136*b7893ccfSSadaf Ebrahimi 'vkCreateInstance', 137*b7893ccfSSadaf Ebrahimi 'vkCreateDevice', 138*b7893ccfSSadaf Ebrahimi 'vkCreateQueryPool' 139*b7893ccfSSadaf Ebrahimi 'vkCreateRenderPass', 140*b7893ccfSSadaf Ebrahimi 'vkCreateRenderPass2KHR', 141*b7893ccfSSadaf Ebrahimi 'vkCreateBuffer', 142*b7893ccfSSadaf Ebrahimi 'vkCreateImage', 143*b7893ccfSSadaf Ebrahimi 'vkCreateGraphicsPipelines', 144*b7893ccfSSadaf Ebrahimi 'vkCreateComputePipelines', 145*b7893ccfSSadaf Ebrahimi "vkCreateRayTracingPipelinesNV", 146*b7893ccfSSadaf Ebrahimi 'vkCreateSampler', 147*b7893ccfSSadaf Ebrahimi 'vkCreateDescriptorSetLayout', 148*b7893ccfSSadaf Ebrahimi 'vkFreeDescriptorSets', 149*b7893ccfSSadaf Ebrahimi 'vkUpdateDescriptorSets', 150*b7893ccfSSadaf Ebrahimi 'vkCreateRenderPass', 151*b7893ccfSSadaf Ebrahimi 'vkCreateRenderPass2KHR', 152*b7893ccfSSadaf Ebrahimi 'vkBeginCommandBuffer', 153*b7893ccfSSadaf Ebrahimi 'vkCmdSetViewport', 154*b7893ccfSSadaf Ebrahimi 'vkCmdSetScissor', 155*b7893ccfSSadaf Ebrahimi 'vkCmdSetLineWidth', 156*b7893ccfSSadaf Ebrahimi 'vkCmdDraw', 157*b7893ccfSSadaf Ebrahimi 'vkCmdDrawIndirect', 158*b7893ccfSSadaf Ebrahimi 'vkCmdDrawIndexedIndirect', 159*b7893ccfSSadaf Ebrahimi 'vkCmdClearAttachments', 160*b7893ccfSSadaf Ebrahimi 'vkCmdCopyImage', 161*b7893ccfSSadaf Ebrahimi 'vkCmdBindIndexBuffer', 162*b7893ccfSSadaf Ebrahimi 'vkCmdBlitImage', 163*b7893ccfSSadaf Ebrahimi 'vkCmdCopyBufferToImage', 164*b7893ccfSSadaf Ebrahimi 'vkCmdCopyImageToBuffer', 165*b7893ccfSSadaf Ebrahimi 'vkCmdUpdateBuffer', 166*b7893ccfSSadaf Ebrahimi 'vkCmdFillBuffer', 167*b7893ccfSSadaf Ebrahimi 'vkCreateSwapchainKHR', 168*b7893ccfSSadaf Ebrahimi 'vkQueuePresentKHR', 169*b7893ccfSSadaf Ebrahimi 'vkCreateDescriptorPool', 170*b7893ccfSSadaf Ebrahimi 'vkCmdDispatch', 171*b7893ccfSSadaf Ebrahimi 'vkCmdDispatchIndirect', 172*b7893ccfSSadaf Ebrahimi 'vkCmdDispatchBaseKHR', 173*b7893ccfSSadaf Ebrahimi 'vkCmdSetExclusiveScissorNV', 174*b7893ccfSSadaf Ebrahimi 'vkCmdSetViewportShadingRatePaletteNV', 175*b7893ccfSSadaf Ebrahimi 'vkCmdSetCoarseSampleOrderNV', 176*b7893ccfSSadaf Ebrahimi 'vkCmdDrawMeshTasksNV', 177*b7893ccfSSadaf Ebrahimi 'vkCmdDrawMeshTasksIndirectNV', 178*b7893ccfSSadaf Ebrahimi 'vkCmdDrawMeshTasksIndirectCountNV', 179*b7893ccfSSadaf Ebrahimi 'vkAllocateMemory', 180*b7893ccfSSadaf Ebrahimi 'vkCreateAccelerationStructureNV', 181*b7893ccfSSadaf Ebrahimi 'vkGetAccelerationStructureHandleNV', 182*b7893ccfSSadaf Ebrahimi 'vkCmdBuildAccelerationStructureNV', 183*b7893ccfSSadaf Ebrahimi 'vkCreateFramebuffer', 184*b7893ccfSSadaf Ebrahimi 'vkCmdSetLineStippleEXT', 185*b7893ccfSSadaf Ebrahimi ] 186*b7893ccfSSadaf Ebrahimi 187*b7893ccfSSadaf Ebrahimi # Commands to ignore 188*b7893ccfSSadaf Ebrahimi self.blacklist = [ 189*b7893ccfSSadaf Ebrahimi 'vkGetInstanceProcAddr', 190*b7893ccfSSadaf Ebrahimi 'vkGetDeviceProcAddr', 191*b7893ccfSSadaf Ebrahimi 'vkEnumerateInstanceVersion', 192*b7893ccfSSadaf Ebrahimi 'vkEnumerateInstanceLayerProperties', 193*b7893ccfSSadaf Ebrahimi 'vkEnumerateInstanceExtensionProperties', 194*b7893ccfSSadaf Ebrahimi 'vkEnumerateDeviceLayerProperties', 195*b7893ccfSSadaf Ebrahimi 'vkEnumerateDeviceExtensionProperties', 196*b7893ccfSSadaf Ebrahimi 'vkGetDeviceGroupSurfacePresentModes2EXT' 197*b7893ccfSSadaf Ebrahimi ] 198*b7893ccfSSadaf Ebrahimi 199*b7893ccfSSadaf Ebrahimi # Structure fields to ignore 200*b7893ccfSSadaf Ebrahimi self.structMemberBlacklist = { 'VkWriteDescriptorSet' : ['dstSet'] } 201*b7893ccfSSadaf Ebrahimi # Validation conditions for some special case struct members that are conditionally validated 202*b7893ccfSSadaf Ebrahimi self.structMemberValidationConditions = { 'VkPipelineColorBlendStateCreateInfo' : { 'logicOp' : '{}logicOpEnable == VK_TRUE' } } 203*b7893ccfSSadaf Ebrahimi # Header version 204*b7893ccfSSadaf Ebrahimi self.headerVersion = None 205*b7893ccfSSadaf Ebrahimi # Internal state - accumulators for different inner block text 206*b7893ccfSSadaf Ebrahimi self.validation = [] # Text comprising the main per-api parameter validation routines 207*b7893ccfSSadaf Ebrahimi self.stypes = [] # Values from the VkStructureType enumeration 208*b7893ccfSSadaf Ebrahimi self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType 209*b7893ccfSSadaf Ebrahimi self.handleTypes = set() # Set of handle type names 210*b7893ccfSSadaf Ebrahimi self.commands = [] # List of CommandData records for all Vulkan commands 211*b7893ccfSSadaf Ebrahimi self.structMembers = [] # List of StructMemberData records for all Vulkan structs 212*b7893ccfSSadaf Ebrahimi self.validatedStructs = dict() # Map of structs type names to generated validation code for that struct type 213*b7893ccfSSadaf Ebrahimi self.enumRanges = dict() # Map of enum name to BEGIN/END range values 214*b7893ccfSSadaf Ebrahimi self.enumValueLists = '' # String containing enumerated type map definitions 215*b7893ccfSSadaf Ebrahimi self.flags = set() # Map of flags typenames 216*b7893ccfSSadaf Ebrahimi self.flagBits = dict() # Map of flag bits typename to list of values 217*b7893ccfSSadaf Ebrahimi self.newFlags = set() # Map of flags typenames /defined in the current feature/ 218*b7893ccfSSadaf Ebrahimi self.required_extensions = dict() # Dictionary of required extensions for each item in the current extension 219*b7893ccfSSadaf Ebrahimi self.extension_type = '' # Type of active feature (extension), device or instance 220*b7893ccfSSadaf Ebrahimi self.extension_names = dict() # Dictionary of extension names to extension name defines 221*b7893ccfSSadaf Ebrahimi self.structextends_list = [] # List of extensions which extend another struct 222*b7893ccfSSadaf Ebrahimi self.struct_feature_protect = dict() # Dictionary of structnames and FeatureExtraProtect strings 223*b7893ccfSSadaf Ebrahimi self.valid_vuids = set() # Set of all valid VUIDs 224*b7893ccfSSadaf Ebrahimi self.vuid_dict = dict() # VUID dictionary (from JSON) 225*b7893ccfSSadaf Ebrahimi self.alias_dict = dict() # Dict of cmd|struct aliases 226*b7893ccfSSadaf Ebrahimi self.header_file = False # Header file generation flag 227*b7893ccfSSadaf Ebrahimi self.source_file = False # Source file generation flag 228*b7893ccfSSadaf Ebrahimi self.returnedonly_structs = [] 229*b7893ccfSSadaf Ebrahimi # Named tuples to store struct and command data 230*b7893ccfSSadaf Ebrahimi self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum', 231*b7893ccfSSadaf Ebrahimi 'isconst', 'isoptional', 'iscount', 'noautovalidity', 232*b7893ccfSSadaf Ebrahimi 'len', 'extstructs', 'condition', 'cdecl']) 233*b7893ccfSSadaf Ebrahimi self.CommandData = namedtuple('CommandData', ['name', 'params', 'cdecl', 'extension_type', 'result']) 234*b7893ccfSSadaf Ebrahimi self.StructMemberData = namedtuple('StructMemberData', ['name', 'members']) 235*b7893ccfSSadaf Ebrahimi 236*b7893ccfSSadaf Ebrahimi # 237*b7893ccfSSadaf Ebrahimi # Generate Copyright comment block for file 238*b7893ccfSSadaf Ebrahimi def GenerateCopyright(self): 239*b7893ccfSSadaf Ebrahimi copyright = '/* *** THIS FILE IS GENERATED - DO NOT EDIT! ***\n' 240*b7893ccfSSadaf Ebrahimi copyright += ' * See parameter_validation_generator.py for modifications\n' 241*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 242*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 The Khronos Group Inc.\n' 243*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2019 LunarG, Inc.\n' 244*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (C) 2015-2019 Google Inc.\n' 245*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 246*b7893ccfSSadaf Ebrahimi copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' 247*b7893ccfSSadaf Ebrahimi copyright += ' * you may not use this file except in compliance with the License.\n' 248*b7893ccfSSadaf Ebrahimi copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n' 249*b7893ccfSSadaf Ebrahimi copyright += ' * You may obtain a copy of the License at\n' 250*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 251*b7893ccfSSadaf Ebrahimi copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' 252*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 253*b7893ccfSSadaf Ebrahimi copyright += ' * Unless required by applicable law or agreed to in writing, software\n' 254*b7893ccfSSadaf Ebrahimi copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' 255*b7893ccfSSadaf Ebrahimi copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' 256*b7893ccfSSadaf Ebrahimi copyright += ' * See the License for the specific language governing permissions and\n' 257*b7893ccfSSadaf Ebrahimi copyright += ' * limitations under the License.\n' 258*b7893ccfSSadaf Ebrahimi copyright += ' *\n' 259*b7893ccfSSadaf Ebrahimi copyright += ' * Author: Mark Lobodzinski <mark@LunarG.com>\n' 260*b7893ccfSSadaf Ebrahimi copyright += ' * Author: Dave Houlton <daveh@LunarG.com>\n' 261*b7893ccfSSadaf Ebrahimi copyright += ' */\n\n' 262*b7893ccfSSadaf Ebrahimi return copyright 263*b7893ccfSSadaf Ebrahimi # 264*b7893ccfSSadaf Ebrahimi # Increases the global indent variable 265*b7893ccfSSadaf Ebrahimi def incIndent(self, indent): 266*b7893ccfSSadaf Ebrahimi inc = ' ' * self.INDENT_SPACES 267*b7893ccfSSadaf Ebrahimi if indent: 268*b7893ccfSSadaf Ebrahimi return indent + inc 269*b7893ccfSSadaf Ebrahimi return inc 270*b7893ccfSSadaf Ebrahimi # 271*b7893ccfSSadaf Ebrahimi # Decreases the global indent variable 272*b7893ccfSSadaf Ebrahimi def decIndent(self, indent): 273*b7893ccfSSadaf Ebrahimi if indent and (len(indent) > self.INDENT_SPACES): 274*b7893ccfSSadaf Ebrahimi return indent[:-self.INDENT_SPACES] 275*b7893ccfSSadaf Ebrahimi return '' 276*b7893ccfSSadaf Ebrahimi # 277*b7893ccfSSadaf Ebrahimi # Walk the JSON-derived dict and find all "vuid" key values 278*b7893ccfSSadaf Ebrahimi def ExtractVUIDs(self, d): 279*b7893ccfSSadaf Ebrahimi if hasattr(d, 'items'): 280*b7893ccfSSadaf Ebrahimi for k, v in d.items(): 281*b7893ccfSSadaf Ebrahimi if k == "vuid": 282*b7893ccfSSadaf Ebrahimi yield v 283*b7893ccfSSadaf Ebrahimi elif isinstance(v, dict): 284*b7893ccfSSadaf Ebrahimi for s in self.ExtractVUIDs(v): 285*b7893ccfSSadaf Ebrahimi yield s 286*b7893ccfSSadaf Ebrahimi elif isinstance (v, list): 287*b7893ccfSSadaf Ebrahimi for l in v: 288*b7893ccfSSadaf Ebrahimi for s in self.ExtractVUIDs(l): 289*b7893ccfSSadaf Ebrahimi yield s 290*b7893ccfSSadaf Ebrahimi # 291*b7893ccfSSadaf Ebrahimi # Called at file creation time 292*b7893ccfSSadaf Ebrahimi def beginFile(self, genOpts): 293*b7893ccfSSadaf Ebrahimi OutputGenerator.beginFile(self, genOpts) 294*b7893ccfSSadaf Ebrahimi self.header_file = (genOpts.filename == 'parameter_validation.h') 295*b7893ccfSSadaf Ebrahimi self.source_file = (genOpts.filename == 'parameter_validation.cpp') 296*b7893ccfSSadaf Ebrahimi 297*b7893ccfSSadaf Ebrahimi if not self.header_file and not self.source_file: 298*b7893ccfSSadaf Ebrahimi print("Error: Output Filenames have changed, update generator source.\n") 299*b7893ccfSSadaf Ebrahimi sys.exit(1) 300*b7893ccfSSadaf Ebrahimi 301*b7893ccfSSadaf Ebrahimi if self.source_file or self.header_file: 302*b7893ccfSSadaf Ebrahimi # Output Copyright text 303*b7893ccfSSadaf Ebrahimi s = self.GenerateCopyright() 304*b7893ccfSSadaf Ebrahimi write(s, file=self.outFile) 305*b7893ccfSSadaf Ebrahimi 306*b7893ccfSSadaf Ebrahimi if self.header_file: 307*b7893ccfSSadaf Ebrahimi return 308*b7893ccfSSadaf Ebrahimi 309*b7893ccfSSadaf Ebrahimi # Build map of structure type names to VkStructureType enum values 310*b7893ccfSSadaf Ebrahimi # Find all types of category "struct" 311*b7893ccfSSadaf Ebrahimi for struct in self.registry.tree.iterfind('types/type[@category="struct"]'): 312*b7893ccfSSadaf Ebrahimi # Check if struct has member named "sType" of type "VkStructureType" which has values defined 313*b7893ccfSSadaf Ebrahimi stype = struct.find('member[name="sType"][type="VkStructureType"][@values]') 314*b7893ccfSSadaf Ebrahimi if stype is not None: 315*b7893ccfSSadaf Ebrahimi # Store VkStructureType value for this type 316*b7893ccfSSadaf Ebrahimi self.structTypes[struct.get('name')] = stype.get('values') 317*b7893ccfSSadaf Ebrahimi 318*b7893ccfSSadaf Ebrahimi self.valid_usage_path = genOpts.valid_usage_path 319*b7893ccfSSadaf Ebrahimi vu_json_filename = os.path.join(self.valid_usage_path + os.sep, 'validusage.json') 320*b7893ccfSSadaf Ebrahimi if os.path.isfile(vu_json_filename): 321*b7893ccfSSadaf Ebrahimi json_file = open(vu_json_filename, 'r') 322*b7893ccfSSadaf Ebrahimi self.vuid_dict = json.load(json_file) 323*b7893ccfSSadaf Ebrahimi json_file.close() 324*b7893ccfSSadaf Ebrahimi if len(self.vuid_dict) == 0: 325*b7893ccfSSadaf Ebrahimi print("Error: Could not find, or error loading %s/validusage.json\n", vu_json_filename) 326*b7893ccfSSadaf Ebrahimi sys.exit(1) 327*b7893ccfSSadaf Ebrahimi # 328*b7893ccfSSadaf Ebrahimi # Build a set of all vuid text strings found in validusage.json 329*b7893ccfSSadaf Ebrahimi for json_vuid_string in self.ExtractVUIDs(self.vuid_dict): 330*b7893ccfSSadaf Ebrahimi self.valid_vuids.add(json_vuid_string) 331*b7893ccfSSadaf Ebrahimi # 332*b7893ccfSSadaf Ebrahimi # Headers 333*b7893ccfSSadaf Ebrahimi write('#include "chassis.h"', file=self.outFile) 334*b7893ccfSSadaf Ebrahimi self.newline() 335*b7893ccfSSadaf Ebrahimi write('#include "stateless_validation.h"', file=self.outFile) 336*b7893ccfSSadaf Ebrahimi self.newline() 337*b7893ccfSSadaf Ebrahimi # 338*b7893ccfSSadaf Ebrahimi # Called at end-time for final content output 339*b7893ccfSSadaf Ebrahimi def endFile(self): 340*b7893ccfSSadaf Ebrahimi if self.source_file: 341*b7893ccfSSadaf Ebrahimi # C-specific 342*b7893ccfSSadaf Ebrahimi self.newline() 343*b7893ccfSSadaf Ebrahimi write(self.enumValueLists, file=self.outFile) 344*b7893ccfSSadaf Ebrahimi self.newline() 345*b7893ccfSSadaf Ebrahimi 346*b7893ccfSSadaf Ebrahimi pnext_handler = 'bool StatelessValidation::ValidatePnextStructContents(const char *api_name, const ParameterName ¶meter_name, const VkBaseOutStructure* header) {\n' 347*b7893ccfSSadaf Ebrahimi pnext_handler += ' bool skip = false;\n' 348*b7893ccfSSadaf Ebrahimi pnext_handler += ' switch(header->sType) {\n' 349*b7893ccfSSadaf Ebrahimi 350*b7893ccfSSadaf Ebrahimi # Do some processing here to extract data from validatedstructs... 351*b7893ccfSSadaf Ebrahimi for item in self.structextends_list: 352*b7893ccfSSadaf Ebrahimi postProcSpec = {} 353*b7893ccfSSadaf Ebrahimi postProcSpec['ppp'] = '' if not item else '{postProcPrefix}' 354*b7893ccfSSadaf Ebrahimi postProcSpec['pps'] = '' if not item else '{postProcSuffix}' 355*b7893ccfSSadaf Ebrahimi postProcSpec['ppi'] = '' if not item else '{postProcInsert}' 356*b7893ccfSSadaf Ebrahimi 357*b7893ccfSSadaf Ebrahimi pnext_case = '\n' 358*b7893ccfSSadaf Ebrahimi protect = '' 359*b7893ccfSSadaf Ebrahimi # Guard struct cases with feature ifdefs, if necessary 360*b7893ccfSSadaf Ebrahimi if item in self.struct_feature_protect.keys(): 361*b7893ccfSSadaf Ebrahimi protect = self.struct_feature_protect[item] 362*b7893ccfSSadaf Ebrahimi pnext_case += '#ifdef %s\n' % protect 363*b7893ccfSSadaf Ebrahimi pnext_case += ' // Validation code for %s structure members\n' % item 364*b7893ccfSSadaf Ebrahimi pnext_case += ' case %s: {\n' % self.structTypes[item] 365*b7893ccfSSadaf Ebrahimi pnext_case += ' %s *structure = (%s *) header;\n' % (item, item) 366*b7893ccfSSadaf Ebrahimi expr = self.expandStructCode(item, item, 'structure->', '', ' ', [], postProcSpec) 367*b7893ccfSSadaf Ebrahimi struct_validation_source = self.ScrubStructCode(expr) 368*b7893ccfSSadaf Ebrahimi pnext_case += '%s' % struct_validation_source 369*b7893ccfSSadaf Ebrahimi pnext_case += ' } break;\n' 370*b7893ccfSSadaf Ebrahimi if protect: 371*b7893ccfSSadaf Ebrahimi pnext_case += '#endif // %s\n' % protect 372*b7893ccfSSadaf Ebrahimi # Skip functions containing no validation 373*b7893ccfSSadaf Ebrahimi if struct_validation_source: 374*b7893ccfSSadaf Ebrahimi pnext_handler += pnext_case; 375*b7893ccfSSadaf Ebrahimi pnext_handler += ' default:\n' 376*b7893ccfSSadaf Ebrahimi pnext_handler += ' skip = false;\n' 377*b7893ccfSSadaf Ebrahimi pnext_handler += ' }\n' 378*b7893ccfSSadaf Ebrahimi pnext_handler += ' return skip;\n' 379*b7893ccfSSadaf Ebrahimi pnext_handler += '}\n' 380*b7893ccfSSadaf Ebrahimi write(pnext_handler, file=self.outFile) 381*b7893ccfSSadaf Ebrahimi self.newline() 382*b7893ccfSSadaf Ebrahimi 383*b7893ccfSSadaf Ebrahimi ext_template = 'bool StatelessValidation::OutputExtensionError(const std::string &api_name, const std::string &extension_name) {\n' 384*b7893ccfSSadaf Ebrahimi ext_template += ' return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,\n' 385*b7893ccfSSadaf Ebrahimi ext_template += ' kVUID_PVError_ExtensionNotEnabled, "Attemped to call %s() but its required extension %s has not been enabled\\n",\n' 386*b7893ccfSSadaf Ebrahimi ext_template += ' api_name.c_str(), extension_name.c_str());\n' 387*b7893ccfSSadaf Ebrahimi ext_template += '}\n' 388*b7893ccfSSadaf Ebrahimi write(ext_template, file=self.outFile) 389*b7893ccfSSadaf Ebrahimi self.newline() 390*b7893ccfSSadaf Ebrahimi commands_text = '\n'.join(self.validation) 391*b7893ccfSSadaf Ebrahimi write(commands_text, file=self.outFile) 392*b7893ccfSSadaf Ebrahimi self.newline() 393*b7893ccfSSadaf Ebrahimi if self.header_file: 394*b7893ccfSSadaf Ebrahimi # Output declarations and record intercepted procedures 395*b7893ccfSSadaf Ebrahimi write('\n'.join(self.declarations), file=self.outFile) 396*b7893ccfSSadaf Ebrahimi # Finish processing in superclass 397*b7893ccfSSadaf Ebrahimi OutputGenerator.endFile(self) 398*b7893ccfSSadaf Ebrahimi # 399*b7893ccfSSadaf Ebrahimi # Processing at beginning of each feature or extension 400*b7893ccfSSadaf Ebrahimi def beginFeature(self, interface, emit): 401*b7893ccfSSadaf Ebrahimi # Start processing in superclass 402*b7893ccfSSadaf Ebrahimi OutputGenerator.beginFeature(self, interface, emit) 403*b7893ccfSSadaf Ebrahimi # C-specific 404*b7893ccfSSadaf Ebrahimi # Accumulate includes, defines, types, enums, function pointer typedefs, end function prototypes separately for this 405*b7893ccfSSadaf Ebrahimi # feature. They're only printed in endFeature(). 406*b7893ccfSSadaf Ebrahimi self.headerVersion = None 407*b7893ccfSSadaf Ebrahimi self.stypes = [] 408*b7893ccfSSadaf Ebrahimi self.commands = [] 409*b7893ccfSSadaf Ebrahimi self.structMembers = [] 410*b7893ccfSSadaf Ebrahimi self.newFlags = set() 411*b7893ccfSSadaf Ebrahimi self.featureExtraProtect = GetFeatureProtect(interface) 412*b7893ccfSSadaf Ebrahimi # Get base list of extension dependencies for all items in this extension 413*b7893ccfSSadaf Ebrahimi base_required_extensions = [] 414*b7893ccfSSadaf Ebrahimi if "VK_VERSION_1" not in self.featureName: 415*b7893ccfSSadaf Ebrahimi # Save Name Define to get correct enable name later 416*b7893ccfSSadaf Ebrahimi nameElem = interface[0][1] 417*b7893ccfSSadaf Ebrahimi name = nameElem.get('name') 418*b7893ccfSSadaf Ebrahimi self.extension_names[self.featureName] = name 419*b7893ccfSSadaf Ebrahimi # This extension is the first dependency for this command 420*b7893ccfSSadaf Ebrahimi base_required_extensions.append(self.featureName) 421*b7893ccfSSadaf Ebrahimi # Add any defined extension dependencies to the base dependency list for this extension 422*b7893ccfSSadaf Ebrahimi requires = interface.get('requires') 423*b7893ccfSSadaf Ebrahimi if requires is not None: 424*b7893ccfSSadaf Ebrahimi base_required_extensions.extend(requires.split(',')) 425*b7893ccfSSadaf Ebrahimi # Build dictionary of extension dependencies for each item in this extension 426*b7893ccfSSadaf Ebrahimi self.required_extensions = dict() 427*b7893ccfSSadaf Ebrahimi for require_element in interface.findall('require'): 428*b7893ccfSSadaf Ebrahimi # Copy base extension dependency list 429*b7893ccfSSadaf Ebrahimi required_extensions = list(base_required_extensions) 430*b7893ccfSSadaf Ebrahimi # Add any additional extension dependencies specified in this require block 431*b7893ccfSSadaf Ebrahimi additional_extensions = require_element.get('extension') 432*b7893ccfSSadaf Ebrahimi if additional_extensions: 433*b7893ccfSSadaf Ebrahimi required_extensions.extend(additional_extensions.split(',')) 434*b7893ccfSSadaf Ebrahimi # Save full extension list for all named items 435*b7893ccfSSadaf Ebrahimi for element in require_element.findall('*[@name]'): 436*b7893ccfSSadaf Ebrahimi self.required_extensions[element.get('name')] = required_extensions 437*b7893ccfSSadaf Ebrahimi 438*b7893ccfSSadaf Ebrahimi # And note if this is an Instance or Device extension 439*b7893ccfSSadaf Ebrahimi self.extension_type = interface.get('type') 440*b7893ccfSSadaf Ebrahimi # 441*b7893ccfSSadaf Ebrahimi # Called at the end of each extension (feature) 442*b7893ccfSSadaf Ebrahimi def endFeature(self): 443*b7893ccfSSadaf Ebrahimi if self.header_file: 444*b7893ccfSSadaf Ebrahimi return 445*b7893ccfSSadaf Ebrahimi # C-specific 446*b7893ccfSSadaf Ebrahimi # Actually write the interface to the output file. 447*b7893ccfSSadaf Ebrahimi if (self.emit): 448*b7893ccfSSadaf Ebrahimi # If type declarations are needed by other features based on this one, it may be necessary to suppress the ExtraProtect, 449*b7893ccfSSadaf Ebrahimi # or move it below the 'for section...' loop. 450*b7893ccfSSadaf Ebrahimi ifdef = '' 451*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 452*b7893ccfSSadaf Ebrahimi ifdef = '#ifdef %s\n' % self.featureExtraProtect 453*b7893ccfSSadaf Ebrahimi self.validation.append(ifdef) 454*b7893ccfSSadaf Ebrahimi # Generate the struct member checking code from the captured data 455*b7893ccfSSadaf Ebrahimi self.processStructMemberData() 456*b7893ccfSSadaf Ebrahimi # Generate the command parameter checking code from the captured data 457*b7893ccfSSadaf Ebrahimi self.processCmdData() 458*b7893ccfSSadaf Ebrahimi # Write the declaration for the HeaderVersion 459*b7893ccfSSadaf Ebrahimi if self.headerVersion: 460*b7893ccfSSadaf Ebrahimi write('const uint32_t GeneratedVulkanHeaderVersion = {};'.format(self.headerVersion), file=self.outFile) 461*b7893ccfSSadaf Ebrahimi self.newline() 462*b7893ccfSSadaf Ebrahimi # Write the declarations for the VkFlags values combining all flag bits 463*b7893ccfSSadaf Ebrahimi for flag in sorted(self.newFlags): 464*b7893ccfSSadaf Ebrahimi flagBits = flag.replace('Flags', 'FlagBits') 465*b7893ccfSSadaf Ebrahimi if flagBits in self.flagBits: 466*b7893ccfSSadaf Ebrahimi bits = self.flagBits[flagBits] 467*b7893ccfSSadaf Ebrahimi decl = 'const {} All{} = {}'.format(flag, flagBits, bits[0]) 468*b7893ccfSSadaf Ebrahimi for bit in bits[1:]: 469*b7893ccfSSadaf Ebrahimi decl += '|' + bit 470*b7893ccfSSadaf Ebrahimi decl += ';' 471*b7893ccfSSadaf Ebrahimi write(decl, file=self.outFile) 472*b7893ccfSSadaf Ebrahimi endif = '\n' 473*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 474*b7893ccfSSadaf Ebrahimi endif = '#endif // %s\n' % self.featureExtraProtect 475*b7893ccfSSadaf Ebrahimi self.validation.append(endif) 476*b7893ccfSSadaf Ebrahimi # Finish processing in superclass 477*b7893ccfSSadaf Ebrahimi OutputGenerator.endFeature(self) 478*b7893ccfSSadaf Ebrahimi # 479*b7893ccfSSadaf Ebrahimi # Type generation 480*b7893ccfSSadaf Ebrahimi def genType(self, typeinfo, name, alias): 481*b7893ccfSSadaf Ebrahimi # record the name/alias pair 482*b7893ccfSSadaf Ebrahimi if alias is not None: 483*b7893ccfSSadaf Ebrahimi self.alias_dict[name]=alias 484*b7893ccfSSadaf Ebrahimi OutputGenerator.genType(self, typeinfo, name, alias) 485*b7893ccfSSadaf Ebrahimi typeElem = typeinfo.elem 486*b7893ccfSSadaf Ebrahimi # If the type is a struct type, traverse the embedded <member> tags generating a structure. Otherwise, emit the tag text. 487*b7893ccfSSadaf Ebrahimi category = typeElem.get('category') 488*b7893ccfSSadaf Ebrahimi if (category == 'struct' or category == 'union'): 489*b7893ccfSSadaf Ebrahimi self.genStruct(typeinfo, name, alias) 490*b7893ccfSSadaf Ebrahimi elif (category == 'handle'): 491*b7893ccfSSadaf Ebrahimi self.handleTypes.add(name) 492*b7893ccfSSadaf Ebrahimi elif (category == 'bitmask'): 493*b7893ccfSSadaf Ebrahimi self.flags.add(name) 494*b7893ccfSSadaf Ebrahimi self.newFlags.add(name) 495*b7893ccfSSadaf Ebrahimi elif (category == 'define'): 496*b7893ccfSSadaf Ebrahimi if name == 'VK_HEADER_VERSION': 497*b7893ccfSSadaf Ebrahimi nameElem = typeElem.find('name') 498*b7893ccfSSadaf Ebrahimi self.headerVersion = noneStr(nameElem.tail).strip() 499*b7893ccfSSadaf Ebrahimi # 500*b7893ccfSSadaf Ebrahimi # Struct parameter check generation. 501*b7893ccfSSadaf Ebrahimi # This is a special case of the <type> tag where the contents are interpreted as a set of <member> tags instead of freeform C 502*b7893ccfSSadaf Ebrahimi # type declarations. The <member> tags are just like <param> tags - they are a declaration of a struct or union member. 503*b7893ccfSSadaf Ebrahimi # Only simple member declarations are supported (no nested structs etc.) 504*b7893ccfSSadaf Ebrahimi def genStruct(self, typeinfo, typeName, alias): 505*b7893ccfSSadaf Ebrahimi if not self.source_file: 506*b7893ccfSSadaf Ebrahimi return 507*b7893ccfSSadaf Ebrahimi # alias has already been recorded in genType, above 508*b7893ccfSSadaf Ebrahimi OutputGenerator.genStruct(self, typeinfo, typeName, alias) 509*b7893ccfSSadaf Ebrahimi conditions = self.structMemberValidationConditions[typeName] if typeName in self.structMemberValidationConditions else None 510*b7893ccfSSadaf Ebrahimi members = typeinfo.elem.findall('.//member') 511*b7893ccfSSadaf Ebrahimi if self.featureExtraProtect is not None: 512*b7893ccfSSadaf Ebrahimi self.struct_feature_protect[typeName] = self.featureExtraProtect 513*b7893ccfSSadaf Ebrahimi # 514*b7893ccfSSadaf Ebrahimi # Iterate over members once to get length parameters for arrays 515*b7893ccfSSadaf Ebrahimi lens = set() 516*b7893ccfSSadaf Ebrahimi for member in members: 517*b7893ccfSSadaf Ebrahimi len = self.getLen(member) 518*b7893ccfSSadaf Ebrahimi if len: 519*b7893ccfSSadaf Ebrahimi lens.add(len) 520*b7893ccfSSadaf Ebrahimi # 521*b7893ccfSSadaf Ebrahimi # Generate member info 522*b7893ccfSSadaf Ebrahimi membersInfo = [] 523*b7893ccfSSadaf Ebrahimi for member in members: 524*b7893ccfSSadaf Ebrahimi # Get the member's type and name 525*b7893ccfSSadaf Ebrahimi info = self.getTypeNameTuple(member) 526*b7893ccfSSadaf Ebrahimi type = info[0] 527*b7893ccfSSadaf Ebrahimi name = info[1] 528*b7893ccfSSadaf Ebrahimi stypeValue = '' 529*b7893ccfSSadaf Ebrahimi cdecl = self.makeCParamDecl(member, 0) 530*b7893ccfSSadaf Ebrahimi 531*b7893ccfSSadaf Ebrahimi # Store pointer/array/string info -- Check for parameter name in lens set 532*b7893ccfSSadaf Ebrahimi iscount = False 533*b7893ccfSSadaf Ebrahimi if name in lens: 534*b7893ccfSSadaf Ebrahimi iscount = True 535*b7893ccfSSadaf Ebrahimi # The pNext members are not tagged as optional, but are treated as optional for parameter NULL checks. Static array 536*b7893ccfSSadaf Ebrahimi # members are also treated as optional to skip NULL pointer validation, as they won't be NULL. 537*b7893ccfSSadaf Ebrahimi isstaticarray = self.paramIsStaticArray(member) 538*b7893ccfSSadaf Ebrahimi isoptional = False 539*b7893ccfSSadaf Ebrahimi if self.paramIsOptional(member) or (name == 'pNext') or (isstaticarray): 540*b7893ccfSSadaf Ebrahimi isoptional = True 541*b7893ccfSSadaf Ebrahimi # Determine if value should be ignored by code generation. 542*b7893ccfSSadaf Ebrahimi noautovalidity = False 543*b7893ccfSSadaf Ebrahimi if (member.attrib.get('noautovalidity') is not None) or ((typeName in self.structMemberBlacklist) and (name in self.structMemberBlacklist[typeName])): 544*b7893ccfSSadaf Ebrahimi noautovalidity = True 545*b7893ccfSSadaf Ebrahimi structextends = False 546*b7893ccfSSadaf Ebrahimi membersInfo.append(self.CommandParam(type=type, name=name, 547*b7893ccfSSadaf Ebrahimi ispointer=self.paramIsPointer(member), 548*b7893ccfSSadaf Ebrahimi isstaticarray=isstaticarray, 549*b7893ccfSSadaf Ebrahimi isbool=True if type == 'VkBool32' else False, 550*b7893ccfSSadaf Ebrahimi israngedenum=True if type in self.enumRanges else False, 551*b7893ccfSSadaf Ebrahimi isconst=True if 'const' in cdecl else False, 552*b7893ccfSSadaf Ebrahimi isoptional=isoptional, 553*b7893ccfSSadaf Ebrahimi iscount=iscount, 554*b7893ccfSSadaf Ebrahimi noautovalidity=noautovalidity, 555*b7893ccfSSadaf Ebrahimi len=self.getLen(member), 556*b7893ccfSSadaf Ebrahimi extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None, 557*b7893ccfSSadaf Ebrahimi condition=conditions[name] if conditions and name in conditions else None, 558*b7893ccfSSadaf Ebrahimi cdecl=cdecl)) 559*b7893ccfSSadaf Ebrahimi # If this struct extends another, keep its name in list for further processing 560*b7893ccfSSadaf Ebrahimi if typeinfo.elem.attrib.get('structextends') is not None: 561*b7893ccfSSadaf Ebrahimi self.structextends_list.append(typeName) 562*b7893ccfSSadaf Ebrahimi # Returnedonly structs should have most of their members ignored -- on entry, we only care about validating the sType and 563*b7893ccfSSadaf Ebrahimi # pNext members. Everything else will be overwritten by the callee. 564*b7893ccfSSadaf Ebrahimi if typeinfo.elem.attrib.get('returnedonly') is not None: 565*b7893ccfSSadaf Ebrahimi self.returnedonly_structs.append(typeName) 566*b7893ccfSSadaf Ebrahimi membersInfo = [m for m in membersInfo if m.name in ('sType', 'pNext')] 567*b7893ccfSSadaf Ebrahimi self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo)) 568*b7893ccfSSadaf Ebrahimi # 569*b7893ccfSSadaf Ebrahimi # Capture group (e.g. C "enum" type) info to be used for param check code generation. 570*b7893ccfSSadaf Ebrahimi # These are concatenated together with other types. 571*b7893ccfSSadaf Ebrahimi def genGroup(self, groupinfo, groupName, alias): 572*b7893ccfSSadaf Ebrahimi if not self.source_file: 573*b7893ccfSSadaf Ebrahimi return 574*b7893ccfSSadaf Ebrahimi # record the name/alias pair 575*b7893ccfSSadaf Ebrahimi if alias is not None: 576*b7893ccfSSadaf Ebrahimi self.alias_dict[groupName]=alias 577*b7893ccfSSadaf Ebrahimi OutputGenerator.genGroup(self, groupinfo, groupName, alias) 578*b7893ccfSSadaf Ebrahimi groupElem = groupinfo.elem 579*b7893ccfSSadaf Ebrahimi # Store the sType values 580*b7893ccfSSadaf Ebrahimi if groupName == 'VkStructureType': 581*b7893ccfSSadaf Ebrahimi for elem in groupElem.findall('enum'): 582*b7893ccfSSadaf Ebrahimi self.stypes.append(elem.get('name')) 583*b7893ccfSSadaf Ebrahimi elif 'FlagBits' in groupName: 584*b7893ccfSSadaf Ebrahimi bits = [] 585*b7893ccfSSadaf Ebrahimi for elem in groupElem.findall('enum'): 586*b7893ccfSSadaf Ebrahimi if elem.get('supported') != 'disabled': 587*b7893ccfSSadaf Ebrahimi bits.append(elem.get('name')) 588*b7893ccfSSadaf Ebrahimi if bits: 589*b7893ccfSSadaf Ebrahimi self.flagBits[groupName] = bits 590*b7893ccfSSadaf Ebrahimi else: 591*b7893ccfSSadaf Ebrahimi # Determine if begin/end ranges are needed (we don't do this for VkStructureType, which has a more finely grained check) 592*b7893ccfSSadaf Ebrahimi expandName = re.sub(r'([0-9a-z_])([A-Z0-9][^A-Z0-9]?)',r'\1_\2',groupName).upper() 593*b7893ccfSSadaf Ebrahimi expandPrefix = expandName 594*b7893ccfSSadaf Ebrahimi expandSuffix = '' 595*b7893ccfSSadaf Ebrahimi expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName) 596*b7893ccfSSadaf Ebrahimi if expandSuffixMatch: 597*b7893ccfSSadaf Ebrahimi expandSuffix = '_' + expandSuffixMatch.group() 598*b7893ccfSSadaf Ebrahimi # Strip off the suffix from the prefix 599*b7893ccfSSadaf Ebrahimi expandPrefix = expandName.rsplit(expandSuffix, 1)[0] 600*b7893ccfSSadaf Ebrahimi isEnum = ('FLAG_BITS' not in expandPrefix) 601*b7893ccfSSadaf Ebrahimi if isEnum: 602*b7893ccfSSadaf Ebrahimi self.enumRanges[groupName] = (expandPrefix + '_BEGIN_RANGE' + expandSuffix, expandPrefix + '_END_RANGE' + expandSuffix) 603*b7893ccfSSadaf Ebrahimi # Create definition for a list containing valid enum values for this enumerated type 604*b7893ccfSSadaf Ebrahimi if self.featureExtraProtect is not None: 605*b7893ccfSSadaf Ebrahimi enum_entry = '\n#ifdef %s\n' % self.featureExtraProtect 606*b7893ccfSSadaf Ebrahimi else: 607*b7893ccfSSadaf Ebrahimi enum_entry = '' 608*b7893ccfSSadaf Ebrahimi enum_entry += 'const std::vector<%s> All%sEnums = {' % (groupName, groupName) 609*b7893ccfSSadaf Ebrahimi for enum in groupElem: 610*b7893ccfSSadaf Ebrahimi name = enum.get('name') 611*b7893ccfSSadaf Ebrahimi if name is not None and enum.get('supported') != 'disabled': 612*b7893ccfSSadaf Ebrahimi enum_entry += '%s, ' % name 613*b7893ccfSSadaf Ebrahimi enum_entry += '};\n' 614*b7893ccfSSadaf Ebrahimi if self.featureExtraProtect is not None: 615*b7893ccfSSadaf Ebrahimi enum_entry += '#endif // %s\n' % self.featureExtraProtect 616*b7893ccfSSadaf Ebrahimi self.enumValueLists += enum_entry 617*b7893ccfSSadaf Ebrahimi # 618*b7893ccfSSadaf Ebrahimi # Capture command parameter info to be used for param check code generation. 619*b7893ccfSSadaf Ebrahimi def genCmd(self, cmdinfo, name, alias): 620*b7893ccfSSadaf Ebrahimi # record the name/alias pair 621*b7893ccfSSadaf Ebrahimi if alias is not None: 622*b7893ccfSSadaf Ebrahimi self.alias_dict[name]=alias 623*b7893ccfSSadaf Ebrahimi OutputGenerator.genCmd(self, cmdinfo, name, alias) 624*b7893ccfSSadaf Ebrahimi decls = self.makeCDecls(cmdinfo.elem) 625*b7893ccfSSadaf Ebrahimi typedef = decls[1] 626*b7893ccfSSadaf Ebrahimi typedef = typedef.split(')',1)[1] 627*b7893ccfSSadaf Ebrahimi if self.header_file: 628*b7893ccfSSadaf Ebrahimi if name not in self.blacklist: 629*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 630*b7893ccfSSadaf Ebrahimi self.declarations += [ '#ifdef %s' % self.featureExtraProtect ] 631*b7893ccfSSadaf Ebrahimi # Strip off 'vk' from API name 632*b7893ccfSSadaf Ebrahimi self.declarations += [ '%s%s' % ('bool PreCallValidate', decls[0].split("VKAPI_CALL vk")[1])] 633*b7893ccfSSadaf Ebrahimi if (self.featureExtraProtect is not None): 634*b7893ccfSSadaf Ebrahimi self.declarations += [ '#endif' ] 635*b7893ccfSSadaf Ebrahimi if self.source_file: 636*b7893ccfSSadaf Ebrahimi if name not in self.blacklist: 637*b7893ccfSSadaf Ebrahimi params = cmdinfo.elem.findall('param') 638*b7893ccfSSadaf Ebrahimi # Get list of array lengths 639*b7893ccfSSadaf Ebrahimi lens = set() 640*b7893ccfSSadaf Ebrahimi for param in params: 641*b7893ccfSSadaf Ebrahimi len = self.getLen(param) 642*b7893ccfSSadaf Ebrahimi if len: 643*b7893ccfSSadaf Ebrahimi lens.add(len) 644*b7893ccfSSadaf Ebrahimi # Get param info 645*b7893ccfSSadaf Ebrahimi paramsInfo = [] 646*b7893ccfSSadaf Ebrahimi for param in params: 647*b7893ccfSSadaf Ebrahimi paramInfo = self.getTypeNameTuple(param) 648*b7893ccfSSadaf Ebrahimi cdecl = self.makeCParamDecl(param, 0) 649*b7893ccfSSadaf Ebrahimi # Check for parameter name in lens set 650*b7893ccfSSadaf Ebrahimi iscount = False 651*b7893ccfSSadaf Ebrahimi if paramInfo[1] in lens: 652*b7893ccfSSadaf Ebrahimi iscount = True 653*b7893ccfSSadaf Ebrahimi paramsInfo.append(self.CommandParam(type=paramInfo[0], name=paramInfo[1], 654*b7893ccfSSadaf Ebrahimi ispointer=self.paramIsPointer(param), 655*b7893ccfSSadaf Ebrahimi isstaticarray=self.paramIsStaticArray(param), 656*b7893ccfSSadaf Ebrahimi isbool=True if paramInfo[0] == 'VkBool32' else False, 657*b7893ccfSSadaf Ebrahimi israngedenum=True if paramInfo[0] in self.enumRanges else False, 658*b7893ccfSSadaf Ebrahimi isconst=True if 'const' in cdecl else False, 659*b7893ccfSSadaf Ebrahimi isoptional=self.paramIsOptional(param), 660*b7893ccfSSadaf Ebrahimi iscount=iscount, 661*b7893ccfSSadaf Ebrahimi noautovalidity=True if param.attrib.get('noautovalidity') is not None else False, 662*b7893ccfSSadaf Ebrahimi len=self.getLen(param), 663*b7893ccfSSadaf Ebrahimi extstructs=None, 664*b7893ccfSSadaf Ebrahimi condition=None, 665*b7893ccfSSadaf Ebrahimi cdecl=cdecl)) 666*b7893ccfSSadaf Ebrahimi # Save return value information, if any 667*b7893ccfSSadaf Ebrahimi result_type = '' 668*b7893ccfSSadaf Ebrahimi resultinfo = cmdinfo.elem.find('proto/type') 669*b7893ccfSSadaf Ebrahimi if (resultinfo is not None and resultinfo.text != 'void'): 670*b7893ccfSSadaf Ebrahimi result_type = resultinfo.text 671*b7893ccfSSadaf Ebrahimi self.commands.append(self.CommandData(name=name, params=paramsInfo, cdecl=self.makeCDecls(cmdinfo.elem)[0], extension_type=self.extension_type, result=result_type)) 672*b7893ccfSSadaf Ebrahimi # 673*b7893ccfSSadaf Ebrahimi # Check if the parameter passed in is a pointer 674*b7893ccfSSadaf Ebrahimi def paramIsPointer(self, param): 675*b7893ccfSSadaf Ebrahimi ispointer = 0 676*b7893ccfSSadaf Ebrahimi paramtype = param.find('type') 677*b7893ccfSSadaf Ebrahimi if (paramtype.tail is not None) and ('*' in paramtype.tail): 678*b7893ccfSSadaf Ebrahimi ispointer = paramtype.tail.count('*') 679*b7893ccfSSadaf Ebrahimi elif paramtype.text[:4] == 'PFN_': 680*b7893ccfSSadaf Ebrahimi # Treat function pointer typedefs as a pointer to a single value 681*b7893ccfSSadaf Ebrahimi ispointer = 1 682*b7893ccfSSadaf Ebrahimi return ispointer 683*b7893ccfSSadaf Ebrahimi # 684*b7893ccfSSadaf Ebrahimi # Check if the parameter passed in is a static array 685*b7893ccfSSadaf Ebrahimi def paramIsStaticArray(self, param): 686*b7893ccfSSadaf Ebrahimi isstaticarray = 0 687*b7893ccfSSadaf Ebrahimi paramname = param.find('name') 688*b7893ccfSSadaf Ebrahimi if (paramname.tail is not None) and ('[' in paramname.tail): 689*b7893ccfSSadaf Ebrahimi isstaticarray = paramname.tail.count('[') 690*b7893ccfSSadaf Ebrahimi return isstaticarray 691*b7893ccfSSadaf Ebrahimi # 692*b7893ccfSSadaf Ebrahimi # Check if the parameter passed in is optional 693*b7893ccfSSadaf Ebrahimi # Returns a list of Boolean values for comma separated len attributes (len='false,true') 694*b7893ccfSSadaf Ebrahimi def paramIsOptional(self, param): 695*b7893ccfSSadaf Ebrahimi # See if the handle is optional 696*b7893ccfSSadaf Ebrahimi isoptional = False 697*b7893ccfSSadaf Ebrahimi # Simple, if it's optional, return true 698*b7893ccfSSadaf Ebrahimi optString = param.attrib.get('optional') 699*b7893ccfSSadaf Ebrahimi if optString: 700*b7893ccfSSadaf Ebrahimi if optString == 'true': 701*b7893ccfSSadaf Ebrahimi isoptional = True 702*b7893ccfSSadaf Ebrahimi elif ',' in optString: 703*b7893ccfSSadaf Ebrahimi opts = [] 704*b7893ccfSSadaf Ebrahimi for opt in optString.split(','): 705*b7893ccfSSadaf Ebrahimi val = opt.strip() 706*b7893ccfSSadaf Ebrahimi if val == 'true': 707*b7893ccfSSadaf Ebrahimi opts.append(True) 708*b7893ccfSSadaf Ebrahimi elif val == 'false': 709*b7893ccfSSadaf Ebrahimi opts.append(False) 710*b7893ccfSSadaf Ebrahimi else: 711*b7893ccfSSadaf Ebrahimi print('Unrecognized len attribute value',val) 712*b7893ccfSSadaf Ebrahimi isoptional = opts 713*b7893ccfSSadaf Ebrahimi return isoptional 714*b7893ccfSSadaf Ebrahimi # 715*b7893ccfSSadaf Ebrahimi # Check if the handle passed in is optional 716*b7893ccfSSadaf Ebrahimi # Uses the same logic as ValidityOutputGenerator.isHandleOptional 717*b7893ccfSSadaf Ebrahimi def isHandleOptional(self, param, lenParam): 718*b7893ccfSSadaf Ebrahimi # Simple, if it's optional, return true 719*b7893ccfSSadaf Ebrahimi if param.isoptional: 720*b7893ccfSSadaf Ebrahimi return True 721*b7893ccfSSadaf Ebrahimi # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes. 722*b7893ccfSSadaf Ebrahimi if param.noautovalidity: 723*b7893ccfSSadaf Ebrahimi return True 724*b7893ccfSSadaf Ebrahimi # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional 725*b7893ccfSSadaf Ebrahimi if lenParam and lenParam.isoptional: 726*b7893ccfSSadaf Ebrahimi return True 727*b7893ccfSSadaf Ebrahimi return False 728*b7893ccfSSadaf Ebrahimi # 729*b7893ccfSSadaf Ebrahimi # Retrieve the value of the len tag 730*b7893ccfSSadaf Ebrahimi def getLen(self, param): 731*b7893ccfSSadaf Ebrahimi result = None 732*b7893ccfSSadaf Ebrahimi len = param.attrib.get('len') 733*b7893ccfSSadaf Ebrahimi if len and len != 'null-terminated': 734*b7893ccfSSadaf Ebrahimi # For string arrays, 'len' can look like 'count,null-terminated', indicating that we have a null terminated array of 735*b7893ccfSSadaf Ebrahimi # strings. We strip the null-terminated from the 'len' field and only return the parameter specifying the string count 736*b7893ccfSSadaf Ebrahimi if 'null-terminated' in len: 737*b7893ccfSSadaf Ebrahimi result = len.split(',')[0] 738*b7893ccfSSadaf Ebrahimi else: 739*b7893ccfSSadaf Ebrahimi result = len 740*b7893ccfSSadaf Ebrahimi result = str(result).replace('::', '->') 741*b7893ccfSSadaf Ebrahimi return result 742*b7893ccfSSadaf Ebrahimi # 743*b7893ccfSSadaf Ebrahimi # Retrieve the type and name for a parameter 744*b7893ccfSSadaf Ebrahimi def getTypeNameTuple(self, param): 745*b7893ccfSSadaf Ebrahimi type = '' 746*b7893ccfSSadaf Ebrahimi name = '' 747*b7893ccfSSadaf Ebrahimi for elem in param: 748*b7893ccfSSadaf Ebrahimi if elem.tag == 'type': 749*b7893ccfSSadaf Ebrahimi type = noneStr(elem.text) 750*b7893ccfSSadaf Ebrahimi elif elem.tag == 'name': 751*b7893ccfSSadaf Ebrahimi name = noneStr(elem.text) 752*b7893ccfSSadaf Ebrahimi return (type, name) 753*b7893ccfSSadaf Ebrahimi # 754*b7893ccfSSadaf Ebrahimi # Find a named parameter in a parameter list 755*b7893ccfSSadaf Ebrahimi def getParamByName(self, params, name): 756*b7893ccfSSadaf Ebrahimi for param in params: 757*b7893ccfSSadaf Ebrahimi if param.name == name: 758*b7893ccfSSadaf Ebrahimi return param 759*b7893ccfSSadaf Ebrahimi return None 760*b7893ccfSSadaf Ebrahimi # 761*b7893ccfSSadaf Ebrahimi # Extract length values from latexmath. Currently an inflexible solution that looks for specific 762*b7893ccfSSadaf Ebrahimi # patterns that are found in vk.xml. Will need to be updated when new patterns are introduced. 763*b7893ccfSSadaf Ebrahimi def parseLateXMath(self, source): 764*b7893ccfSSadaf Ebrahimi name = 'ERROR' 765*b7893ccfSSadaf Ebrahimi decoratedName = 'ERROR' 766*b7893ccfSSadaf Ebrahimi if 'mathit' in source: 767*b7893ccfSSadaf Ebrahimi # Matches expressions similar to 'latexmath:[\lceil{\mathit{rasterizationSamples} \over 32}\rceil]' 768*b7893ccfSSadaf Ebrahimi match = re.match(r'latexmath\s*\:\s*\[\s*\\l(\w+)\s*\{\s*\\mathit\s*\{\s*(\w+)\s*\}\s*\\over\s*(\d+)\s*\}\s*\\r(\w+)\s*\]', source) 769*b7893ccfSSadaf Ebrahimi if not match or match.group(1) != match.group(4): 770*b7893ccfSSadaf Ebrahimi raise 'Unrecognized latexmath expression' 771*b7893ccfSSadaf Ebrahimi name = match.group(2) 772*b7893ccfSSadaf Ebrahimi decoratedName = '{}({}/{})'.format(*match.group(1, 2, 3)) 773*b7893ccfSSadaf Ebrahimi else: 774*b7893ccfSSadaf Ebrahimi # Matches expressions similar to 'latexmath : [dataSize \over 4]' 775*b7893ccfSSadaf Ebrahimi match = re.match(r'latexmath\s*\:\s*\[\s*(\\textrm\{)?(\w+)\}?\s*\\over\s*(\d+)\s*\]', source) 776*b7893ccfSSadaf Ebrahimi name = match.group(2) 777*b7893ccfSSadaf Ebrahimi decoratedName = '{}/{}'.format(*match.group(2, 3)) 778*b7893ccfSSadaf Ebrahimi return name, decoratedName 779*b7893ccfSSadaf Ebrahimi # 780*b7893ccfSSadaf Ebrahimi # Get the length paramater record for the specified parameter name 781*b7893ccfSSadaf Ebrahimi def getLenParam(self, params, name): 782*b7893ccfSSadaf Ebrahimi lenParam = None 783*b7893ccfSSadaf Ebrahimi if name: 784*b7893ccfSSadaf Ebrahimi if '->' in name: 785*b7893ccfSSadaf Ebrahimi # The count is obtained by dereferencing a member of a struct parameter 786*b7893ccfSSadaf Ebrahimi lenParam = self.CommandParam(name=name, iscount=True, ispointer=False, isbool=False, israngedenum=False, isconst=False, 787*b7893ccfSSadaf Ebrahimi isstaticarray=None, isoptional=False, type=None, noautovalidity=False, 788*b7893ccfSSadaf Ebrahimi len=None, extstructs=None, condition=None, cdecl=None) 789*b7893ccfSSadaf Ebrahimi elif 'latexmath' in name: 790*b7893ccfSSadaf Ebrahimi lenName, decoratedName = self.parseLateXMath(name) 791*b7893ccfSSadaf Ebrahimi lenParam = self.getParamByName(params, lenName) 792*b7893ccfSSadaf Ebrahimi else: 793*b7893ccfSSadaf Ebrahimi lenParam = self.getParamByName(params, name) 794*b7893ccfSSadaf Ebrahimi return lenParam 795*b7893ccfSSadaf Ebrahimi # 796*b7893ccfSSadaf Ebrahimi # Convert a vulkan.h command declaration into a parameter_validation.h definition 797*b7893ccfSSadaf Ebrahimi def getCmdDef(self, cmd): 798*b7893ccfSSadaf Ebrahimi # Strip the trailing ';' and split into individual lines 799*b7893ccfSSadaf Ebrahimi lines = cmd.cdecl[:-1].split('\n') 800*b7893ccfSSadaf Ebrahimi cmd_hdr = '\n'.join(lines) 801*b7893ccfSSadaf Ebrahimi return cmd_hdr 802*b7893ccfSSadaf Ebrahimi # 803*b7893ccfSSadaf Ebrahimi # Generate the code to check for a NULL dereference before calling the 804*b7893ccfSSadaf Ebrahimi # validation function 805*b7893ccfSSadaf Ebrahimi def genCheckedLengthCall(self, name, exprs): 806*b7893ccfSSadaf Ebrahimi count = name.count('->') 807*b7893ccfSSadaf Ebrahimi if count: 808*b7893ccfSSadaf Ebrahimi checkedExpr = [] 809*b7893ccfSSadaf Ebrahimi localIndent = '' 810*b7893ccfSSadaf Ebrahimi elements = name.split('->') 811*b7893ccfSSadaf Ebrahimi # Open the if expression blocks 812*b7893ccfSSadaf Ebrahimi for i in range(0, count): 813*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + 'if ({} != NULL) {{\n'.format('->'.join(elements[0:i+1]))) 814*b7893ccfSSadaf Ebrahimi localIndent = self.incIndent(localIndent) 815*b7893ccfSSadaf Ebrahimi # Add the validation expression 816*b7893ccfSSadaf Ebrahimi for expr in exprs: 817*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + expr) 818*b7893ccfSSadaf Ebrahimi # Close the if blocks 819*b7893ccfSSadaf Ebrahimi for i in range(0, count): 820*b7893ccfSSadaf Ebrahimi localIndent = self.decIndent(localIndent) 821*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + '}\n') 822*b7893ccfSSadaf Ebrahimi return [checkedExpr] 823*b7893ccfSSadaf Ebrahimi # No if statements were required 824*b7893ccfSSadaf Ebrahimi return exprs 825*b7893ccfSSadaf Ebrahimi # 826*b7893ccfSSadaf Ebrahimi # Generate code to check for a specific condition before executing validation code 827*b7893ccfSSadaf Ebrahimi def genConditionalCall(self, prefix, condition, exprs): 828*b7893ccfSSadaf Ebrahimi checkedExpr = [] 829*b7893ccfSSadaf Ebrahimi localIndent = '' 830*b7893ccfSSadaf Ebrahimi formattedCondition = condition.format(prefix) 831*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + 'if ({})\n'.format(formattedCondition)) 832*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + '{\n') 833*b7893ccfSSadaf Ebrahimi localIndent = self.incIndent(localIndent) 834*b7893ccfSSadaf Ebrahimi for expr in exprs: 835*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + expr) 836*b7893ccfSSadaf Ebrahimi localIndent = self.decIndent(localIndent) 837*b7893ccfSSadaf Ebrahimi checkedExpr.append(localIndent + '}\n') 838*b7893ccfSSadaf Ebrahimi return [checkedExpr] 839*b7893ccfSSadaf Ebrahimi # 840*b7893ccfSSadaf Ebrahimi # Get VUID identifier from implicit VUID tag 841*b7893ccfSSadaf Ebrahimi def GetVuid(self, name, suffix): 842*b7893ccfSSadaf Ebrahimi vuid_string = 'VUID-%s-%s' % (name, suffix) 843*b7893ccfSSadaf Ebrahimi vuid = "kVUIDUndefined" 844*b7893ccfSSadaf Ebrahimi if '->' in vuid_string: 845*b7893ccfSSadaf Ebrahimi return vuid 846*b7893ccfSSadaf Ebrahimi if vuid_string in self.valid_vuids: 847*b7893ccfSSadaf Ebrahimi vuid = "\"%s\"" % vuid_string 848*b7893ccfSSadaf Ebrahimi else: 849*b7893ccfSSadaf Ebrahimi if name in self.alias_dict: 850*b7893ccfSSadaf Ebrahimi alias_string = 'VUID-%s-%s' % (self.alias_dict[name], suffix) 851*b7893ccfSSadaf Ebrahimi if alias_string in self.valid_vuids: 852*b7893ccfSSadaf Ebrahimi vuid = "\"%s\"" % alias_string 853*b7893ccfSSadaf Ebrahimi return vuid 854*b7893ccfSSadaf Ebrahimi # 855*b7893ccfSSadaf Ebrahimi # Generate the sType check string 856*b7893ccfSSadaf Ebrahimi def makeStructTypeCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec, struct_type_name): 857*b7893ccfSSadaf Ebrahimi checkExpr = [] 858*b7893ccfSSadaf Ebrahimi stype = self.structTypes[value.type] 859*b7893ccfSSadaf Ebrahimi vuid_name = struct_type_name if struct_type_name is not None else funcPrintName 860*b7893ccfSSadaf Ebrahimi stype_vuid = self.GetVuid(value.type, "sType-sType") 861*b7893ccfSSadaf Ebrahimi param_vuid = self.GetVuid(vuid_name, "%s-parameter" % value.name) 862*b7893ccfSSadaf Ebrahimi 863*b7893ccfSSadaf Ebrahimi if lenValue: 864*b7893ccfSSadaf Ebrahimi count_required_vuid = self.GetVuid(vuid_name, "%s-arraylength" % lenValue.name) 865*b7893ccfSSadaf Ebrahimi 866*b7893ccfSSadaf Ebrahimi # This is an array with a pointer to a count value 867*b7893ccfSSadaf Ebrahimi if lenValue.ispointer: 868*b7893ccfSSadaf Ebrahimi # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required 869*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {}, {});\n'.format( 870*b7893ccfSSadaf Ebrahimi funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, stype_vuid, param_vuid, count_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec)) 871*b7893ccfSSadaf Ebrahimi # This is an array with an integer count value 872*b7893ccfSSadaf Ebrahimi else: 873*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_struct_type_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, "{sv}", {pf}{ln}, {pf}{vn}, {sv}, {}, {}, {}, {}, {});\n'.format( 874*b7893ccfSSadaf Ebrahimi funcPrintName, lenValueRequired, valueRequired, stype_vuid, param_vuid, count_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, sv=stype, pf=prefix, **postProcSpec)) 875*b7893ccfSSadaf Ebrahimi # This is an individual struct 876*b7893ccfSSadaf Ebrahimi else: 877*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", {}{vn}, {sv}, {}, {}, {});\n'.format( 878*b7893ccfSSadaf Ebrahimi funcPrintName, valuePrintName, prefix, valueRequired, param_vuid, stype_vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec)) 879*b7893ccfSSadaf Ebrahimi return checkExpr 880*b7893ccfSSadaf Ebrahimi # 881*b7893ccfSSadaf Ebrahimi # Generate the handle check string 882*b7893ccfSSadaf Ebrahimi def makeHandleCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec): 883*b7893ccfSSadaf Ebrahimi checkExpr = [] 884*b7893ccfSSadaf Ebrahimi if lenValue: 885*b7893ccfSSadaf Ebrahimi if lenValue.ispointer: 886*b7893ccfSSadaf Ebrahimi # This is assumed to be an output array with a pointer to a count value 887*b7893ccfSSadaf Ebrahimi raise('Unsupported parameter validation case: Output handle array elements are not NULL checked') 888*b7893ccfSSadaf Ebrahimi else: 889*b7893ccfSSadaf Ebrahimi # This is an array with an integer count value 890*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_handle_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {});\n'.format( 891*b7893ccfSSadaf Ebrahimi funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec)) 892*b7893ccfSSadaf Ebrahimi else: 893*b7893ccfSSadaf Ebrahimi # This is assumed to be an output handle pointer 894*b7893ccfSSadaf Ebrahimi raise('Unsupported parameter validation case: Output handles are not NULL checked') 895*b7893ccfSSadaf Ebrahimi return checkExpr 896*b7893ccfSSadaf Ebrahimi # 897*b7893ccfSSadaf Ebrahimi # Generate check string for an array of VkFlags values 898*b7893ccfSSadaf Ebrahimi def makeFlagsArrayCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec): 899*b7893ccfSSadaf Ebrahimi checkExpr = [] 900*b7893ccfSSadaf Ebrahimi flagBitsName = value.type.replace('Flags', 'FlagBits') 901*b7893ccfSSadaf Ebrahimi if not flagBitsName in self.flagBits: 902*b7893ccfSSadaf Ebrahimi raise('Unsupported parameter validation case: array of reserved VkFlags') 903*b7893ccfSSadaf Ebrahimi else: 904*b7893ccfSSadaf Ebrahimi allFlags = 'All' + flagBitsName 905*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_flags_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcPrintName, lenPrintName, valuePrintName, flagBitsName, allFlags, lenValue.name, value.name, lenValueRequired, valueRequired, pf=prefix, **postProcSpec)) 906*b7893ccfSSadaf Ebrahimi return checkExpr 907*b7893ccfSSadaf Ebrahimi # 908*b7893ccfSSadaf Ebrahimi # Generate pNext check string 909*b7893ccfSSadaf Ebrahimi def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName, postProcSpec, struct_type_name): 910*b7893ccfSSadaf Ebrahimi checkExpr = [] 911*b7893ccfSSadaf Ebrahimi # Generate an array of acceptable VkStructureType values for pNext 912*b7893ccfSSadaf Ebrahimi extStructCount = 0 913*b7893ccfSSadaf Ebrahimi extStructVar = 'NULL' 914*b7893ccfSSadaf Ebrahimi extStructNames = 'NULL' 915*b7893ccfSSadaf Ebrahimi vuid = self.GetVuid(struct_type_name, "pNext-pNext") 916*b7893ccfSSadaf Ebrahimi if value.extstructs: 917*b7893ccfSSadaf Ebrahimi extStructVar = 'allowed_structs_{}'.format(struct_type_name) 918*b7893ccfSSadaf Ebrahimi extStructCount = 'ARRAY_SIZE({})'.format(extStructVar) 919*b7893ccfSSadaf Ebrahimi extStructNames = '"' + ', '.join(value.extstructs) + '"' 920*b7893ccfSSadaf Ebrahimi checkExpr.append('const VkStructureType {}[] = {{ {} }};\n'.format(extStructVar, ', '.join([self.structTypes[s] for s in value.extstructs]))) 921*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_struct_pnext("{}", {ppp}"{}"{pps}, {}, {}{}, {}, {}, GeneratedVulkanHeaderVersion, {});\n'.format( 922*b7893ccfSSadaf Ebrahimi funcPrintName, valuePrintName, extStructNames, prefix, value.name, extStructCount, extStructVar, vuid, **postProcSpec)) 923*b7893ccfSSadaf Ebrahimi return checkExpr 924*b7893ccfSSadaf Ebrahimi # 925*b7893ccfSSadaf Ebrahimi # Generate the pointer check string 926*b7893ccfSSadaf Ebrahimi def makePointerCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, lenPtrRequired, funcPrintName, lenPrintName, valuePrintName, postProcSpec, struct_type_name): 927*b7893ccfSSadaf Ebrahimi checkExpr = [] 928*b7893ccfSSadaf Ebrahimi vuid_tag_name = struct_type_name if struct_type_name is not None else funcPrintName 929*b7893ccfSSadaf Ebrahimi if lenValue: 930*b7893ccfSSadaf Ebrahimi count_required_vuid = self.GetVuid(vuid_tag_name, "%s-arraylength" % (lenValue.name)) 931*b7893ccfSSadaf Ebrahimi array_required_vuid = self.GetVuid(vuid_tag_name, "%s-parameter" % (value.name)) 932*b7893ccfSSadaf Ebrahimi # TODO: Remove workaround for missing optional tag in vk.xml 933*b7893ccfSSadaf Ebrahimi if array_required_vuid == '"VUID-VkFramebufferCreateInfo-pAttachments-parameter"': 934*b7893ccfSSadaf Ebrahimi return [] 935*b7893ccfSSadaf Ebrahimi # This is an array with a pointer to a count value 936*b7893ccfSSadaf Ebrahimi if lenValue.ispointer: 937*b7893ccfSSadaf Ebrahimi # If count and array parameters are optional, there will be no validation 938*b7893ccfSSadaf Ebrahimi if valueRequired == 'true' or lenPtrRequired == 'true' or lenValueRequired == 'true': 939*b7893ccfSSadaf Ebrahimi # When the length parameter is a pointer, there is an extra Boolean parameter in the function call to indicate if it is required 940*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {}, {});\n'.format( 941*b7893ccfSSadaf Ebrahimi funcPrintName, lenPtrRequired, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec)) 942*b7893ccfSSadaf Ebrahimi # This is an array with an integer count value 943*b7893ccfSSadaf Ebrahimi else: 944*b7893ccfSSadaf Ebrahimi # If count and array parameters are optional, there will be no validation 945*b7893ccfSSadaf Ebrahimi if valueRequired == 'true' or lenValueRequired == 'true': 946*b7893ccfSSadaf Ebrahimi if value.type != 'char': 947*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, &{pf}{vn}, {}, {}, {}, {});\n'.format( 948*b7893ccfSSadaf Ebrahimi funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec)) 949*b7893ccfSSadaf Ebrahimi else: 950*b7893ccfSSadaf Ebrahimi # Arrays of strings receive special processing 951*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_string_array("{}", {ppp}"{ldn}"{pps}, {ppp}"{dn}"{pps}, {pf}{ln}, {pf}{vn}, {}, {}, {}, {});\n'.format( 952*b7893ccfSSadaf Ebrahimi funcPrintName, lenValueRequired, valueRequired, count_required_vuid, array_required_vuid, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix, **postProcSpec)) 953*b7893ccfSSadaf Ebrahimi if checkExpr: 954*b7893ccfSSadaf Ebrahimi if lenValue and ('->' in lenValue.name): 955*b7893ccfSSadaf Ebrahimi # Add checks to ensure the validation call does not dereference a NULL pointer to obtain the count 956*b7893ccfSSadaf Ebrahimi checkExpr = self.genCheckedLengthCall(lenValue.name, checkExpr) 957*b7893ccfSSadaf Ebrahimi # This is an individual struct that is not allowed to be NULL 958*b7893ccfSSadaf Ebrahimi elif not value.isoptional: 959*b7893ccfSSadaf Ebrahimi # Function pointers need a reinterpret_cast to void* 960*b7893ccfSSadaf Ebrahimi ptr_required_vuid = self.GetVuid(vuid_tag_name, "%s-parameter" % (value.name)) 961*b7893ccfSSadaf Ebrahimi if value.type[:4] == 'PFN_': 962*b7893ccfSSadaf Ebrahimi allocator_dict = {'pfnAllocation': '"VUID-VkAllocationCallbacks-pfnAllocation-00632"', 963*b7893ccfSSadaf Ebrahimi 'pfnReallocation': '"VUID-VkAllocationCallbacks-pfnReallocation-00633"', 964*b7893ccfSSadaf Ebrahimi 'pfnFree': '"VUID-VkAllocationCallbacks-pfnFree-00634"', 965*b7893ccfSSadaf Ebrahimi } 966*b7893ccfSSadaf Ebrahimi vuid = allocator_dict.get(value.name) 967*b7893ccfSSadaf Ebrahimi if vuid is not None: 968*b7893ccfSSadaf Ebrahimi ptr_required_vuid = vuid 969*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec)) 970*b7893ccfSSadaf Ebrahimi else: 971*b7893ccfSSadaf Ebrahimi checkExpr.append('skip |= validate_required_pointer("{}", {ppp}"{}"{pps}, {}{}, {});\n'.format(funcPrintName, valuePrintName, prefix, value.name, ptr_required_vuid, **postProcSpec)) 972*b7893ccfSSadaf Ebrahimi else: 973*b7893ccfSSadaf Ebrahimi # Special case for optional internal allocation function pointers. 974*b7893ccfSSadaf Ebrahimi if (value.type, value.name) == ('PFN_vkInternalAllocationNotification', 'pfnInternalAllocation'): 975*b7893ccfSSadaf Ebrahimi checkExpr.extend(self.internalAllocationCheck(funcPrintName, prefix, value.name, 'pfnInternalFree', postProcSpec)) 976*b7893ccfSSadaf Ebrahimi elif (value.type, value.name) == ('PFN_vkInternalFreeNotification', 'pfnInternalFree'): 977*b7893ccfSSadaf Ebrahimi checkExpr.extend(self.internalAllocationCheck(funcPrintName, prefix, value.name, 'pfnInternalAllocation', postProcSpec)) 978*b7893ccfSSadaf Ebrahimi return checkExpr 979*b7893ccfSSadaf Ebrahimi 980*b7893ccfSSadaf Ebrahimi # 981*b7893ccfSSadaf Ebrahimi # Generate internal allocation function pointer check. 982*b7893ccfSSadaf Ebrahimi def internalAllocationCheck(self, funcPrintName, prefix, name, complementaryName, postProcSpec): 983*b7893ccfSSadaf Ebrahimi checkExpr = [] 984*b7893ccfSSadaf Ebrahimi vuid = '"VUID-VkAllocationCallbacks-pfnInternalAllocation-00635"' 985*b7893ccfSSadaf Ebrahimi checkExpr.append('if ({}{} != NULL)'.format(prefix, name)) 986*b7893ccfSSadaf Ebrahimi checkExpr.append('{') 987*b7893ccfSSadaf Ebrahimi local_indent = self.incIndent('') 988*b7893ccfSSadaf Ebrahimi # Function pointers need a reinterpret_cast to void* 989*b7893ccfSSadaf Ebrahimi checkExpr.append(local_indent + 'skip |= validate_required_pointer("{}", {ppp}"{}{}"{pps}, reinterpret_cast<const void*>({}{}), {});\n'.format(funcPrintName, prefix, complementaryName, prefix, complementaryName, vuid, **postProcSpec)) 990*b7893ccfSSadaf Ebrahimi checkExpr.append('}\n') 991*b7893ccfSSadaf Ebrahimi return checkExpr 992*b7893ccfSSadaf Ebrahimi 993*b7893ccfSSadaf Ebrahimi # 994*b7893ccfSSadaf Ebrahimi # Process struct member validation code, performing name substitution if required 995*b7893ccfSSadaf Ebrahimi def processStructMemberCode(self, line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec): 996*b7893ccfSSadaf Ebrahimi # Build format specifier list 997*b7893ccfSSadaf Ebrahimi kwargs = {} 998*b7893ccfSSadaf Ebrahimi if '{postProcPrefix}' in line: 999*b7893ccfSSadaf Ebrahimi # If we have a tuple that includes a format string and format parameters, need to use ParameterName class 1000*b7893ccfSSadaf Ebrahimi if type(memberDisplayNamePrefix) is tuple: 1001*b7893ccfSSadaf Ebrahimi kwargs['postProcPrefix'] = 'ParameterName(' 1002*b7893ccfSSadaf Ebrahimi else: 1003*b7893ccfSSadaf Ebrahimi kwargs['postProcPrefix'] = postProcSpec['ppp'] 1004*b7893ccfSSadaf Ebrahimi if '{postProcSuffix}' in line: 1005*b7893ccfSSadaf Ebrahimi # If we have a tuple that includes a format string and format parameters, need to use ParameterName class 1006*b7893ccfSSadaf Ebrahimi if type(memberDisplayNamePrefix) is tuple: 1007*b7893ccfSSadaf Ebrahimi kwargs['postProcSuffix'] = ', ParameterName::IndexVector{{ {}{} }})'.format(postProcSpec['ppi'], memberDisplayNamePrefix[1]) 1008*b7893ccfSSadaf Ebrahimi else: 1009*b7893ccfSSadaf Ebrahimi kwargs['postProcSuffix'] = postProcSpec['pps'] 1010*b7893ccfSSadaf Ebrahimi if '{postProcInsert}' in line: 1011*b7893ccfSSadaf Ebrahimi # If we have a tuple that includes a format string and format parameters, need to use ParameterName class 1012*b7893ccfSSadaf Ebrahimi if type(memberDisplayNamePrefix) is tuple: 1013*b7893ccfSSadaf Ebrahimi kwargs['postProcInsert'] = '{}{}, '.format(postProcSpec['ppi'], memberDisplayNamePrefix[1]) 1014*b7893ccfSSadaf Ebrahimi else: 1015*b7893ccfSSadaf Ebrahimi kwargs['postProcInsert'] = postProcSpec['ppi'] 1016*b7893ccfSSadaf Ebrahimi if '{funcName}' in line: 1017*b7893ccfSSadaf Ebrahimi kwargs['funcName'] = funcName 1018*b7893ccfSSadaf Ebrahimi if '{valuePrefix}' in line: 1019*b7893ccfSSadaf Ebrahimi kwargs['valuePrefix'] = memberNamePrefix 1020*b7893ccfSSadaf Ebrahimi if '{displayNamePrefix}' in line: 1021*b7893ccfSSadaf Ebrahimi # Check for a tuple that includes a format string and format parameters to be used with the ParameterName class 1022*b7893ccfSSadaf Ebrahimi if type(memberDisplayNamePrefix) is tuple: 1023*b7893ccfSSadaf Ebrahimi kwargs['displayNamePrefix'] = memberDisplayNamePrefix[0] 1024*b7893ccfSSadaf Ebrahimi else: 1025*b7893ccfSSadaf Ebrahimi kwargs['displayNamePrefix'] = memberDisplayNamePrefix 1026*b7893ccfSSadaf Ebrahimi 1027*b7893ccfSSadaf Ebrahimi if kwargs: 1028*b7893ccfSSadaf Ebrahimi # Need to escape the C++ curly braces 1029*b7893ccfSSadaf Ebrahimi if 'IndexVector' in line: 1030*b7893ccfSSadaf Ebrahimi line = line.replace('IndexVector{ ', 'IndexVector{{ ') 1031*b7893ccfSSadaf Ebrahimi line = line.replace(' }),', ' }}),') 1032*b7893ccfSSadaf Ebrahimi return line.format(**kwargs) 1033*b7893ccfSSadaf Ebrahimi return line 1034*b7893ccfSSadaf Ebrahimi # 1035*b7893ccfSSadaf Ebrahimi # Process struct member validation code, stripping metadata 1036*b7893ccfSSadaf Ebrahimi def ScrubStructCode(self, code): 1037*b7893ccfSSadaf Ebrahimi scrubbed_lines = '' 1038*b7893ccfSSadaf Ebrahimi for line in code: 1039*b7893ccfSSadaf Ebrahimi if 'validate_struct_pnext' in line: 1040*b7893ccfSSadaf Ebrahimi continue 1041*b7893ccfSSadaf Ebrahimi if 'allowed_structs' in line: 1042*b7893ccfSSadaf Ebrahimi continue 1043*b7893ccfSSadaf Ebrahimi if 'xml-driven validation' in line: 1044*b7893ccfSSadaf Ebrahimi continue 1045*b7893ccfSSadaf Ebrahimi line = line.replace('{postProcPrefix}', '') 1046*b7893ccfSSadaf Ebrahimi line = line.replace('{postProcSuffix}', '') 1047*b7893ccfSSadaf Ebrahimi line = line.replace('{postProcInsert}', '') 1048*b7893ccfSSadaf Ebrahimi line = line.replace('{funcName}', '') 1049*b7893ccfSSadaf Ebrahimi line = line.replace('{valuePrefix}', '') 1050*b7893ccfSSadaf Ebrahimi line = line.replace('{displayNamePrefix}', '') 1051*b7893ccfSSadaf Ebrahimi line = line.replace('{IndexVector}', '') 1052*b7893ccfSSadaf Ebrahimi line = line.replace('local_data->', '') 1053*b7893ccfSSadaf Ebrahimi scrubbed_lines += line 1054*b7893ccfSSadaf Ebrahimi return scrubbed_lines 1055*b7893ccfSSadaf Ebrahimi # 1056*b7893ccfSSadaf Ebrahimi # Process struct validation code for inclusion in function or parent struct validation code 1057*b7893ccfSSadaf Ebrahimi def expandStructCode(self, item_type, funcName, memberNamePrefix, memberDisplayNamePrefix, indent, output, postProcSpec): 1058*b7893ccfSSadaf Ebrahimi lines = self.validatedStructs[item_type] 1059*b7893ccfSSadaf Ebrahimi for line in lines: 1060*b7893ccfSSadaf Ebrahimi if output: 1061*b7893ccfSSadaf Ebrahimi output[-1] += '\n' 1062*b7893ccfSSadaf Ebrahimi if type(line) is list: 1063*b7893ccfSSadaf Ebrahimi for sub in line: 1064*b7893ccfSSadaf Ebrahimi output.append(self.processStructMemberCode(indent + sub, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec)) 1065*b7893ccfSSadaf Ebrahimi else: 1066*b7893ccfSSadaf Ebrahimi output.append(self.processStructMemberCode(indent + line, funcName, memberNamePrefix, memberDisplayNamePrefix, postProcSpec)) 1067*b7893ccfSSadaf Ebrahimi return output 1068*b7893ccfSSadaf Ebrahimi # 1069*b7893ccfSSadaf Ebrahimi # Process struct pointer/array validation code, performing name substitution if required 1070*b7893ccfSSadaf Ebrahimi def expandStructPointerCode(self, prefix, value, lenValue, funcName, valueDisplayName, postProcSpec): 1071*b7893ccfSSadaf Ebrahimi expr = [] 1072*b7893ccfSSadaf Ebrahimi expr.append('if ({}{} != NULL)\n'.format(prefix, value.name)) 1073*b7893ccfSSadaf Ebrahimi expr.append('{') 1074*b7893ccfSSadaf Ebrahimi indent = self.incIndent(None) 1075*b7893ccfSSadaf Ebrahimi if lenValue: 1076*b7893ccfSSadaf Ebrahimi # Need to process all elements in the array 1077*b7893ccfSSadaf Ebrahimi indexName = lenValue.name.replace('Count', 'Index') 1078*b7893ccfSSadaf Ebrahimi expr[-1] += '\n' 1079*b7893ccfSSadaf Ebrahimi if lenValue.ispointer: 1080*b7893ccfSSadaf Ebrahimi # If the length value is a pointer, de-reference it for the count. 1081*b7893ccfSSadaf Ebrahimi expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < *{}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName)) 1082*b7893ccfSSadaf Ebrahimi else: 1083*b7893ccfSSadaf Ebrahimi expr.append(indent + 'for (uint32_t {iname} = 0; {iname} < {}{}; ++{iname})\n'.format(prefix, lenValue.name, iname=indexName)) 1084*b7893ccfSSadaf Ebrahimi expr.append(indent + '{') 1085*b7893ccfSSadaf Ebrahimi indent = self.incIndent(indent) 1086*b7893ccfSSadaf Ebrahimi # Prefix for value name to display in error message 1087*b7893ccfSSadaf Ebrahimi if value.ispointer == 2: 1088*b7893ccfSSadaf Ebrahimi memberNamePrefix = '{}{}[{}]->'.format(prefix, value.name, indexName) 1089*b7893ccfSSadaf Ebrahimi memberDisplayNamePrefix = ('{}[%i]->'.format(valueDisplayName), indexName) 1090*b7893ccfSSadaf Ebrahimi else: 1091*b7893ccfSSadaf Ebrahimi memberNamePrefix = '{}{}[{}].'.format(prefix, value.name, indexName) 1092*b7893ccfSSadaf Ebrahimi memberDisplayNamePrefix = ('{}[%i].'.format(valueDisplayName), indexName) 1093*b7893ccfSSadaf Ebrahimi else: 1094*b7893ccfSSadaf Ebrahimi memberNamePrefix = '{}{}->'.format(prefix, value.name) 1095*b7893ccfSSadaf Ebrahimi memberDisplayNamePrefix = '{}->'.format(valueDisplayName) 1096*b7893ccfSSadaf Ebrahimi # Expand the struct validation lines 1097*b7893ccfSSadaf Ebrahimi expr = self.expandStructCode(value.type, funcName, memberNamePrefix, memberDisplayNamePrefix, indent, expr, postProcSpec) 1098*b7893ccfSSadaf Ebrahimi if lenValue: 1099*b7893ccfSSadaf Ebrahimi # Close if and for scopes 1100*b7893ccfSSadaf Ebrahimi indent = self.decIndent(indent) 1101*b7893ccfSSadaf Ebrahimi expr.append(indent + '}\n') 1102*b7893ccfSSadaf Ebrahimi expr.append('}\n') 1103*b7893ccfSSadaf Ebrahimi return expr 1104*b7893ccfSSadaf Ebrahimi # 1105*b7893ccfSSadaf Ebrahimi # Generate the parameter checking code 1106*b7893ccfSSadaf Ebrahimi def genFuncBody(self, funcName, values, valuePrefix, displayNamePrefix, structTypeName): 1107*b7893ccfSSadaf Ebrahimi lines = [] # Generated lines of code 1108*b7893ccfSSadaf Ebrahimi unused = [] # Unused variable names 1109*b7893ccfSSadaf Ebrahimi for value in values: 1110*b7893ccfSSadaf Ebrahimi usedLines = [] 1111*b7893ccfSSadaf Ebrahimi lenParam = None 1112*b7893ccfSSadaf Ebrahimi # 1113*b7893ccfSSadaf Ebrahimi # Prefix and suffix for post processing of parameter names for struct members. Arrays of structures need special processing to include the array index in the full parameter name. 1114*b7893ccfSSadaf Ebrahimi postProcSpec = {} 1115*b7893ccfSSadaf Ebrahimi postProcSpec['ppp'] = '' if not structTypeName else '{postProcPrefix}' 1116*b7893ccfSSadaf Ebrahimi postProcSpec['pps'] = '' if not structTypeName else '{postProcSuffix}' 1117*b7893ccfSSadaf Ebrahimi postProcSpec['ppi'] = '' if not structTypeName else '{postProcInsert}' 1118*b7893ccfSSadaf Ebrahimi # 1119*b7893ccfSSadaf Ebrahimi # Generate the full name of the value, which will be printed in the error message, by adding the variable prefix to the value name 1120*b7893ccfSSadaf Ebrahimi valueDisplayName = '{}{}'.format(displayNamePrefix, value.name) 1121*b7893ccfSSadaf Ebrahimi # 1122*b7893ccfSSadaf Ebrahimi # Check for NULL pointers, ignore the in-out count parameters that 1123*b7893ccfSSadaf Ebrahimi # will be validated with their associated array 1124*b7893ccfSSadaf Ebrahimi if (value.ispointer or value.isstaticarray) and not value.iscount: 1125*b7893ccfSSadaf Ebrahimi # Parameters for function argument generation 1126*b7893ccfSSadaf Ebrahimi req = 'true' # Parameter cannot be NULL 1127*b7893ccfSSadaf Ebrahimi cpReq = 'true' # Count pointer cannot be NULL 1128*b7893ccfSSadaf Ebrahimi cvReq = 'true' # Count value cannot be 0 1129*b7893ccfSSadaf Ebrahimi lenDisplayName = None # Name of length parameter to print with validation messages; parameter name with prefix applied 1130*b7893ccfSSadaf Ebrahimi # Generate required/optional parameter strings for the pointer and count values 1131*b7893ccfSSadaf Ebrahimi if value.isoptional: 1132*b7893ccfSSadaf Ebrahimi req = 'false' 1133*b7893ccfSSadaf Ebrahimi if value.len: 1134*b7893ccfSSadaf Ebrahimi # The parameter is an array with an explicit count parameter 1135*b7893ccfSSadaf Ebrahimi lenParam = self.getLenParam(values, value.len) 1136*b7893ccfSSadaf Ebrahimi lenDisplayName = '{}{}'.format(displayNamePrefix, lenParam.name) 1137*b7893ccfSSadaf Ebrahimi if lenParam.ispointer: 1138*b7893ccfSSadaf Ebrahimi # Count parameters that are pointers are inout 1139*b7893ccfSSadaf Ebrahimi if type(lenParam.isoptional) is list: 1140*b7893ccfSSadaf Ebrahimi if lenParam.isoptional[0]: 1141*b7893ccfSSadaf Ebrahimi cpReq = 'false' 1142*b7893ccfSSadaf Ebrahimi if lenParam.isoptional[1]: 1143*b7893ccfSSadaf Ebrahimi cvReq = 'false' 1144*b7893ccfSSadaf Ebrahimi else: 1145*b7893ccfSSadaf Ebrahimi if lenParam.isoptional: 1146*b7893ccfSSadaf Ebrahimi cpReq = 'false' 1147*b7893ccfSSadaf Ebrahimi else: 1148*b7893ccfSSadaf Ebrahimi if lenParam.isoptional: 1149*b7893ccfSSadaf Ebrahimi cvReq = 'false' 1150*b7893ccfSSadaf Ebrahimi # 1151*b7893ccfSSadaf Ebrahimi # The parameter will not be processed when tagged as 'noautovalidity' 1152*b7893ccfSSadaf Ebrahimi # For the pointer to struct case, the struct pointer will not be validated, but any 1153*b7893ccfSSadaf Ebrahimi # members not tagged as 'noautovalidity' will be validated 1154*b7893ccfSSadaf Ebrahimi # We special-case the custom allocator checks, as they are explicit but can be auto-generated. 1155*b7893ccfSSadaf Ebrahimi AllocatorFunctions = ['PFN_vkAllocationFunction', 'PFN_vkReallocationFunction', 'PFN_vkFreeFunction', 'PFN_vkInternalAllocationNotification', 'PFN_vkInternalFreeNotification'] 1156*b7893ccfSSadaf Ebrahimi if value.noautovalidity and value.type not in AllocatorFunctions: 1157*b7893ccfSSadaf Ebrahimi # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually 1158*b7893ccfSSadaf Ebrahimi self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name)) 1159*b7893ccfSSadaf Ebrahimi else: 1160*b7893ccfSSadaf Ebrahimi if value.type in self.structTypes: 1161*b7893ccfSSadaf Ebrahimi # If this is a pointer to a struct with an sType field, verify the type 1162*b7893ccfSSadaf Ebrahimi usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec, structTypeName) 1163*b7893ccfSSadaf Ebrahimi # If this is an input handle array that is not allowed to contain NULL handles, verify that none of the handles are VK_NULL_HANDLE 1164*b7893ccfSSadaf Ebrahimi elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam): 1165*b7893ccfSSadaf Ebrahimi usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec) 1166*b7893ccfSSadaf Ebrahimi elif value.type in self.flags and value.isconst: 1167*b7893ccfSSadaf Ebrahimi usedLines += self.makeFlagsArrayCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName, postProcSpec) 1168*b7893ccfSSadaf Ebrahimi elif value.isbool and value.isconst: 1169*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_bool32_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec)) 1170*b7893ccfSSadaf Ebrahimi elif value.israngedenum and value.isconst: 1171*b7893ccfSSadaf Ebrahimi enum_value_list = 'All%sEnums' % value.type 1172*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_ranged_enum_array("{}", {ppp}"{}"{pps}, {ppp}"{}"{pps}, "{}", {}, {pf}{}, {pf}{}, {}, {});\n'.format(funcName, lenDisplayName, valueDisplayName, value.type, enum_value_list, lenParam.name, value.name, cvReq, req, pf=valuePrefix, **postProcSpec)) 1173*b7893ccfSSadaf Ebrahimi elif value.name == 'pNext' and value.isconst: 1174*b7893ccfSSadaf Ebrahimi usedLines += self.makeStructNextCheck(valuePrefix, value, funcName, valueDisplayName, postProcSpec, structTypeName) 1175*b7893ccfSSadaf Ebrahimi else: 1176*b7893ccfSSadaf Ebrahimi usedLines += self.makePointerCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName, postProcSpec, structTypeName) 1177*b7893ccfSSadaf Ebrahimi # If this is a pointer to a struct (input), see if it contains members that need to be checked 1178*b7893ccfSSadaf Ebrahimi if value.type in self.validatedStructs: 1179*b7893ccfSSadaf Ebrahimi if value.isconst: # or value.type in self.returnedonly_structs: 1180*b7893ccfSSadaf Ebrahimi usedLines.append(self.expandStructPointerCode(valuePrefix, value, lenParam, funcName, valueDisplayName, postProcSpec)) 1181*b7893ccfSSadaf Ebrahimi elif value.type in self.returnedonly_structs: 1182*b7893ccfSSadaf Ebrahimi usedLines.append(self.expandStructPointerCode(valuePrefix, value, lenParam, funcName, valueDisplayName, postProcSpec)) 1183*b7893ccfSSadaf Ebrahimi # Non-pointer types 1184*b7893ccfSSadaf Ebrahimi else: 1185*b7893ccfSSadaf Ebrahimi # The parameter will not be processes when tagged as 'noautovalidity' 1186*b7893ccfSSadaf Ebrahimi # For the struct case, the struct type will not be validated, but any 1187*b7893ccfSSadaf Ebrahimi # members not tagged as 'noautovalidity' will be validated 1188*b7893ccfSSadaf Ebrahimi if value.noautovalidity: 1189*b7893ccfSSadaf Ebrahimi # Log a diagnostic message when validation cannot be automatically generated and must be implemented manually 1190*b7893ccfSSadaf Ebrahimi self.logMsg('diag', 'ParameterValidation: No validation for {} {}'.format(structTypeName if structTypeName else funcName, value.name)) 1191*b7893ccfSSadaf Ebrahimi else: 1192*b7893ccfSSadaf Ebrahimi vuid_name_tag = structTypeName if structTypeName is not None else funcName 1193*b7893ccfSSadaf Ebrahimi if value.type in self.structTypes: 1194*b7893ccfSSadaf Ebrahimi stype = self.structTypes[value.type] 1195*b7893ccfSSadaf Ebrahimi vuid = self.GetVuid(value.type, "sType-sType") 1196*b7893ccfSSadaf Ebrahimi undefined_vuid = '"kVUIDUndefined"' 1197*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_struct_type("{}", {ppp}"{}"{pps}, "{sv}", &({}{vn}), {sv}, false, kVUIDUndefined, {});\n'.format( 1198*b7893ccfSSadaf Ebrahimi funcName, valueDisplayName, valuePrefix, vuid, vn=value.name, sv=stype, vt=value.type, **postProcSpec)) 1199*b7893ccfSSadaf Ebrahimi elif value.type in self.handleTypes: 1200*b7893ccfSSadaf Ebrahimi if not self.isHandleOptional(value, None): 1201*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_required_handle("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec)) 1202*b7893ccfSSadaf Ebrahimi elif value.type in self.flags and value.type.replace('Flags', 'FlagBits') not in self.flagBits: 1203*b7893ccfSSadaf Ebrahimi vuid = self.GetVuid(vuid_name_tag, "%s-zerobitmask" % (value.name)) 1204*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_reserved_flags("{}", {ppp}"{}"{pps}, {pf}{}, {});\n'.format(funcName, valueDisplayName, value.name, vuid, pf=valuePrefix, **postProcSpec)) 1205*b7893ccfSSadaf Ebrahimi elif value.type in self.flags or value.type in self.flagBits: 1206*b7893ccfSSadaf Ebrahimi if value.type in self.flags: 1207*b7893ccfSSadaf Ebrahimi flagBitsName = value.type.replace('Flags', 'FlagBits') 1208*b7893ccfSSadaf Ebrahimi flagsType = 'kOptionalFlags' if value.isoptional else 'kRequiredFlags' 1209*b7893ccfSSadaf Ebrahimi invalidVuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name)) 1210*b7893ccfSSadaf Ebrahimi zeroVuid = self.GetVuid(vuid_name_tag, "%s-requiredbitmask" % (value.name)) 1211*b7893ccfSSadaf Ebrahimi elif value.type in self.flagBits: 1212*b7893ccfSSadaf Ebrahimi flagBitsName = value.type 1213*b7893ccfSSadaf Ebrahimi flagsType = 'kOptionalSingleBit' if value.isoptional else 'kRequiredSingleBit' 1214*b7893ccfSSadaf Ebrahimi invalidVuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name)) 1215*b7893ccfSSadaf Ebrahimi zeroVuid = invalidVuid 1216*b7893ccfSSadaf Ebrahimi allFlagsName = 'All' + flagBitsName 1217*b7893ccfSSadaf Ebrahimi 1218*b7893ccfSSadaf Ebrahimi invalid_vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name)) 1219*b7893ccfSSadaf Ebrahimi allFlagsName = 'All' + flagBitsName 1220*b7893ccfSSadaf Ebrahimi zeroVuidArg = '' if value.isoptional else ', ' + zeroVuid 1221*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_flags("{}", {ppp}"{}"{pps}, "{}", {}, {pf}{}, {}, {}{});\n'.format(funcName, valueDisplayName, flagBitsName, allFlagsName, value.name, flagsType, invalidVuid, zeroVuidArg, pf=valuePrefix, **postProcSpec)) 1222*b7893ccfSSadaf Ebrahimi elif value.isbool: 1223*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_bool32("{}", {ppp}"{}"{pps}, {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name, **postProcSpec)) 1224*b7893ccfSSadaf Ebrahimi elif value.israngedenum: 1225*b7893ccfSSadaf Ebrahimi vuid = self.GetVuid(vuid_name_tag, "%s-parameter" % (value.name)) 1226*b7893ccfSSadaf Ebrahimi enum_value_list = 'All%sEnums' % value.type 1227*b7893ccfSSadaf Ebrahimi usedLines.append('skip |= validate_ranged_enum("{}", {ppp}"{}"{pps}, "{}", {}, {}{}, {});\n'.format(funcName, valueDisplayName, value.type, enum_value_list, valuePrefix, value.name, vuid, **postProcSpec)) 1228*b7893ccfSSadaf Ebrahimi # If this is a struct, see if it contains members that need to be checked 1229*b7893ccfSSadaf Ebrahimi if value.type in self.validatedStructs: 1230*b7893ccfSSadaf Ebrahimi memberNamePrefix = '{}{}.'.format(valuePrefix, value.name) 1231*b7893ccfSSadaf Ebrahimi memberDisplayNamePrefix = '{}.'.format(valueDisplayName) 1232*b7893ccfSSadaf Ebrahimi usedLines.append(self.expandStructCode(value.type, funcName, memberNamePrefix, memberDisplayNamePrefix, '', [], postProcSpec)) 1233*b7893ccfSSadaf Ebrahimi # Append the parameter check to the function body for the current command 1234*b7893ccfSSadaf Ebrahimi if usedLines: 1235*b7893ccfSSadaf Ebrahimi # Apply special conditional checks 1236*b7893ccfSSadaf Ebrahimi if value.condition: 1237*b7893ccfSSadaf Ebrahimi usedLines = self.genConditionalCall(valuePrefix, value.condition, usedLines) 1238*b7893ccfSSadaf Ebrahimi lines += usedLines 1239*b7893ccfSSadaf Ebrahimi elif not value.iscount: 1240*b7893ccfSSadaf Ebrahimi # If no expression was generated for this value, it is unreferenced by the validation function, unless 1241*b7893ccfSSadaf Ebrahimi # it is an array count, which is indirectly referenced for array valiadation. 1242*b7893ccfSSadaf Ebrahimi unused.append(value.name) 1243*b7893ccfSSadaf Ebrahimi if not lines: 1244*b7893ccfSSadaf Ebrahimi lines.append('// No xml-driven validation\n') 1245*b7893ccfSSadaf Ebrahimi return lines, unused 1246*b7893ccfSSadaf Ebrahimi # 1247*b7893ccfSSadaf Ebrahimi # Generate the struct member check code from the captured data 1248*b7893ccfSSadaf Ebrahimi def processStructMemberData(self): 1249*b7893ccfSSadaf Ebrahimi indent = self.incIndent(None) 1250*b7893ccfSSadaf Ebrahimi for struct in self.structMembers: 1251*b7893ccfSSadaf Ebrahimi # 1252*b7893ccfSSadaf Ebrahimi # The string returned by genFuncBody will be nested in an if check for a NULL pointer, so needs its indent incremented 1253*b7893ccfSSadaf Ebrahimi lines, unused = self.genFuncBody('{funcName}', struct.members, '{valuePrefix}', '{displayNamePrefix}', struct.name) 1254*b7893ccfSSadaf Ebrahimi if lines: 1255*b7893ccfSSadaf Ebrahimi self.validatedStructs[struct.name] = lines 1256*b7893ccfSSadaf Ebrahimi # 1257*b7893ccfSSadaf Ebrahimi # Generate the command param check code from the captured data 1258*b7893ccfSSadaf Ebrahimi def processCmdData(self): 1259*b7893ccfSSadaf Ebrahimi indent = self.incIndent(None) 1260*b7893ccfSSadaf Ebrahimi for command in self.commands: 1261*b7893ccfSSadaf Ebrahimi # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance) 1262*b7893ccfSSadaf Ebrahimi startIndex = 0 if command.name == 'vkCreateInstance' else 1 1263*b7893ccfSSadaf Ebrahimi lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None) 1264*b7893ccfSSadaf Ebrahimi # Cannot validate extension dependencies for device extension APIs having a physical device as their dispatchable object 1265*b7893ccfSSadaf Ebrahimi if (command.name in self.required_extensions) and (self.extension_type != 'device' or command.params[0].type != 'VkPhysicalDevice'): 1266*b7893ccfSSadaf Ebrahimi ext_test = '' 1267*b7893ccfSSadaf Ebrahimi if command.params[0].type in ["VkInstance", "VkPhysicalDevice"] or command.name == 'vkCreateInstance': 1268*b7893ccfSSadaf Ebrahimi ext_table_type = 'instance' 1269*b7893ccfSSadaf Ebrahimi else: 1270*b7893ccfSSadaf Ebrahimi ext_table_type = 'device' 1271*b7893ccfSSadaf Ebrahimi for ext in self.required_extensions[command.name]: 1272*b7893ccfSSadaf Ebrahimi ext_name_define = '' 1273*b7893ccfSSadaf Ebrahimi ext_enable_name = '' 1274*b7893ccfSSadaf Ebrahimi for extension in self.registry.extensions: 1275*b7893ccfSSadaf Ebrahimi if extension.attrib['name'] == ext: 1276*b7893ccfSSadaf Ebrahimi ext_name_define = extension[0][1].get('name') 1277*b7893ccfSSadaf Ebrahimi ext_enable_name = ext_name_define.lower() 1278*b7893ccfSSadaf Ebrahimi ext_enable_name = re.sub('_extension_name', '', ext_enable_name) 1279*b7893ccfSSadaf Ebrahimi break 1280*b7893ccfSSadaf Ebrahimi ext_test = 'if (!%s_extensions.%s) skip |= OutputExtensionError("%s", %s);\n' % (ext_table_type, ext_enable_name, command.name, ext_name_define) 1281*b7893ccfSSadaf Ebrahimi lines.insert(0, ext_test) 1282*b7893ccfSSadaf Ebrahimi if lines: 1283*b7893ccfSSadaf Ebrahimi func_sig = self.getCmdDef(command) + ' {\n' 1284*b7893ccfSSadaf Ebrahimi func_sig = func_sig.split('VKAPI_CALL vk')[1] 1285*b7893ccfSSadaf Ebrahimi cmdDef = 'bool StatelessValidation::PreCallValidate' + func_sig 1286*b7893ccfSSadaf Ebrahimi cmdDef += '%sbool skip = false;\n' % indent 1287*b7893ccfSSadaf Ebrahimi for line in lines: 1288*b7893ccfSSadaf Ebrahimi if type(line) is list: 1289*b7893ccfSSadaf Ebrahimi for sub in line: 1290*b7893ccfSSadaf Ebrahimi cmdDef += indent + sub 1291*b7893ccfSSadaf Ebrahimi else: 1292*b7893ccfSSadaf Ebrahimi cmdDef += indent + line 1293*b7893ccfSSadaf Ebrahimi # Insert call to custom-written function if present 1294*b7893ccfSSadaf Ebrahimi if command.name in self.functions_with_manual_checks: 1295*b7893ccfSSadaf Ebrahimi # Generate parameter list for manual fcn and down-chain calls 1296*b7893ccfSSadaf Ebrahimi params_text = '' 1297*b7893ccfSSadaf Ebrahimi for param in command.params: 1298*b7893ccfSSadaf Ebrahimi params_text += '%s, ' % param.name 1299*b7893ccfSSadaf Ebrahimi params_text = params_text[:-2] + ');\n' 1300*b7893ccfSSadaf Ebrahimi cmdDef += ' if (!skip) skip |= manual_PreCallValidate'+ command.name[2:] + '(' + params_text 1301*b7893ccfSSadaf Ebrahimi cmdDef += '%sreturn skip;\n' % indent 1302*b7893ccfSSadaf Ebrahimi cmdDef += '}\n' 1303*b7893ccfSSadaf Ebrahimi self.validation.append(cmdDef) 1304