From nobody Mon May 6 19:18:49 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) client-ip=66.175.222.12; envelope-from=bounce+27952+41572+1787277+3901457@groups.io; helo=web01.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+41572+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1559110147; cv=none; d=zoho.com; s=zohoarc; b=G4jmyj/rnNiFP1tvyouvpOp4S7akuJm+QD5sy6VXTpGUZkrNhujqL33NrpxXug5Be0bFHDmLqYZJ6/LtyWi5/TZ/JwMJlZcOF9unwRrIiE8BddbfIpdCBeJMIGpbQ9X03Gw74S0XB9DdFXUGoH2Gh9YYHl5iz3+GQkEwI8TZY+c= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1559110147; h=Content-Type:Cc:Date:From:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Sender:Subject:To:ARC-Authentication-Results; bh=FcjQdAFHgWiEqUjoSupxJ+Uz1YqvLFBF9STCs52PxPU=; b=ZmqEV6vUHkmjPapOlwjSpeHrqYFcAI+Uz8jKbOfayvBhDxGP6X/TjsoTp2XH/jVCo9y7jlbVuBTk+BwTekomqdaXP8klCrqSysbVh2WUFOrSq11nQ2cFzMHe6y+IGPdH6mI9EtkK7x5eh2Cvo2T8Phk3qEZCZhQtWq4iaAcLZNI= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of groups.io designates 66.175.222.12 as permitted sender) smtp.mailfrom=bounce+27952+41572+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) header.from= Received: from web01.groups.io (web01.groups.io [66.175.222.12]) by mx.zohomail.com with SMTPS id 1559110147519101.26028004917032; Tue, 28 May 2019 23:09:07 -0700 (PDT) Return-Path: X-Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by groups.io with SMTP; Tue, 28 May 2019 23:09:06 -0700 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 28 May 2019 23:09:05 -0700 X-ExtLoop1: 1 X-Received: from fmsmsx103.amr.corp.intel.com ([10.18.124.201]) by orsmga003.jf.intel.com with ESMTP; 28 May 2019 23:09:05 -0700 X-Received: from fmsmsx156.amr.corp.intel.com (10.18.116.74) by FMSMSX103.amr.corp.intel.com (10.18.124.201) with Microsoft SMTP Server (TLS) id 14.3.408.0; Tue, 28 May 2019 23:09:05 -0700 X-Received: from shsmsx152.ccr.corp.intel.com (10.239.6.52) by fmsmsx156.amr.corp.intel.com (10.18.116.74) with Microsoft SMTP Server (TLS) id 14.3.408.0; Tue, 28 May 2019 23:09:04 -0700 X-Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.129]) by SHSMSX152.ccr.corp.intel.com ([169.254.6.18]) with mapi id 14.03.0415.000; Wed, 29 May 2019 14:09:02 +0800 From: "Fan, ZhijuX" To: "devel@edk2.groups.io" CC: "Gao, Liming" , "Feng, Bob C" Subject: [edk2-devel] [PATCH] BaseTools:add UniTool.py to Edk2\BaseTools\Scripts Thread-Topic: [PATCH] BaseTools:add UniTool.py to Edk2\BaseTools\Scripts Thread-Index: AdUV5NFgiPHjimoeT/KdgIAvm6jaWQ== Date: Wed, 29 May 2019 06:09:02 +0000 Message-ID: Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-product: dlpe-windows dlp-version: 11.0.600.7 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,zhijux.fan@intel.com Content-Type: multipart/mixed; boundary="_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF631CCSHSMSX101ccrcor_" Content-Language: en-US DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1559110147; bh=WWK90U/jBvBWT6EepK2CJpTNrVv8VEKrOUiRAtivCog=; h=CC:Content-Type:Date:From:Reply-To:Subject:To; b=LTHCTIAEqE8Z76ctfY2vNlRvn7LZtOqWEeL+lrQNf/fzSEqtTst/m3hFycuD4nPmgZp JeBlXV/YWZXqVgLkAYQo3jJ+Qp2Yd/ptr+cX6GOk8e5uK245kPHTk5M/oWYwk7ALx2OfA 1anrmc1TEhAGwGp6BmQIB8BFdLg0l+p3kTc= X-Zoho-Virus-Status: 1 X-ZohoMail-DKIM: pass (identity @groups.io) --_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF631CCSHSMSX101ccrcor_ Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=3D1855 UniTool is one python script to generate UQI (Universal Question Identifier) unicode string for HII question PROMPT string. UQI string can be used to identify each HII question. This script can be run in both Py2 and Py3. Cc: Bob Feng Cc: Liming Gao Signed-off-by: Zhiju.Fan --- BaseTools/Scripts/UniTool.py | 490 +++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 490 insertions(+) create mode 100644 BaseTools/Scripts/UniTool.py diff --git a/BaseTools/Scripts/UniTool.py b/BaseTools/Scripts/UniTool.py new file mode 100644 index 0000000000..6faecb9e7e --- /dev/null +++ b/BaseTools/Scripts/UniTool.py @@ -0,0 +1,490 @@ +## @file +# +# Function will sync up UQI definitions with uni files based on vfi/vfr/hf= r/sd/sdi in the tree. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +import re, sys, os, getopt, codecs, fnmatch + +# global variable declarations +questionError =3D False +uqiList =3D re.compile('^#string[ \t]+([A-Z_0-9]+)[ \t]+#language[ \t]+uqi= [ \t\r\n]+"(?:[x\S]{1,2})([0-9a-fA-F]{4,5})"',re.M).findall +allUqis =3D {} +stringDict =3D {} +GlobalVarId =3D {} +options =3D {} + +#********************************************************************** +# description: Prints help information +# +# arguments: none +# +# returns: none +# + +def usage () : + sys.exit("Syntax: %s [-b] [-u] [-l] [-x] [-h] [-d 'rootDirectory1'] [-d= 'rootDirectory2'] [-d 'rootDirectory3']... [-q e|w] \ +'rootDirectory0' 'uqiFile'|'uqiFileDirectory' ['excludedDirectory1'] ['exc= ludedDirectory2'] ['excludedDirectory3']...\n%s" % + (os.path.basename(sys.argv[0]), + """\nFunction will sync up UQI definitions with uni files based on v= fi/vfr/hfr/sd/sdi in the tree.\n +Required Arguments: + 'rootdirectory0' path to root directory + 'uqiFileDirectory' path to UQI file(UqiList.uni) + 'uqiFile' UQI file + +Options: + -h Show this help + -b Build option returns error if any new UQI needs as= signing + based on vfi/vfr/hfr/sd/sdi when no -u option is s= pecified + -u Create new UQIs that does not already exist in uqi= File for + any string requiring a UQI based on vfi/vfr/hfr/sd= /sdi + NOTE: 'uqiFile' cannot be readonly! + -l Language deletion option (keeps only English and u= qi) + moves all UQIs to 'uqiFile' + NOTE: Uni files cannot be readonly! + -x Exclude 'rootDirectory'/'excludedDirectory1' & + 'rootDirectory'/'excludedDirectory2'... from UQI l= ist build + NOTE: Cannot be the same as rootDirectory + -d Add multiple root directories to process + -q Print warning(w) or return error(e) if different H= II questions + are referring same string token + +Return error if any duplicated UQI string or value in UQI list or if no de= finition +for any string referred by HII question when -b or -u is specified + +NOTE: Options must be specified before parameters +""")) + +#********************************************************************** +# description: Get uni file encoding +# +# arguments: filename - name of uni file +# +# returns: utf-8 or utf-16 +# +def GetUniFileEncoding(filename): + # + # Detect Byte Order Mark at beginning of file. Default to UTF-8 + # + Encoding =3D 'utf-8' + + # + # Read file + # + try: + UniFile =3D open(filename, mode=3D'rb') + FileIn =3D UniFile.read() + UniFile.close() + except: + return Encoding + + if (FileIn.startswith(codecs.BOM_UTF16_BE) or FileIn.startswith(codecs.B= OM_UTF16_LE)): + Encoding =3D 'utf-16' + + return Encoding + +# rewrite function os.path.walk +def Walk(top, func, arg): + try: + names =3D os.listdir(top) + except os.error: + return + func(arg, top, names) + for name in names: + name =3D os.path.join(top, name) + if os.path.isdir(name): + Walk(name, func, arg) + +#********************************************************************** +# description: Parses commandline arguments and options +# Calls function processUni to build dictionary of strings +# Calls other functions according to user specified options +# +# arguments: argv - contains all input from command line +# - must contain path to root directory +# - may contain options -h, -u, -l, -b or -x before path +# +# returns: none +# +def main(argv) : +##### Read input arguments and options + global allUqis, uqiList, questionError + try: + opts, args =3D getopt.getopt(argv[1:], "hulbxd:q:") # each letter is a= n optional argument + except getopt.GetoptError: + usage() + try: + dirNameList =3D [args[0]] + QuestionOption =3D None + for eachOpt in opts: + if eachOpt[0] =3D=3D '-d': + dirNameList.append(eachOpt[1]) + if eachOpt[0] =3D=3D '-q': + QuestionOption =3D eachOpt[1] + if (QuestionOption !=3D "e") and (QuestionOption !=3D "w"): + print("\nERROR: invalid option value for -q option\n") + raise Exception + destname =3D args[1] + if len(args) > 2: + exDirList =3D args[2:] + except: + usage() + + UpdateUQIs =3D False + LangOption =3D False + BuildOption =3D False + ExcludeOption =3D False + exPathList =3D [] + + for o,a in opts: + if o =3D=3D "-h": + usage() + if o =3D=3D "-b": + BuildOption =3D True + if o =3D=3D "-u": + BuildOption =3D True + UpdateUQIs =3D True + if o =3D=3D "-l": + LangOption =3D True + if o =3D=3D "-x": + ExcludeOption =3D True + try: + for eachExDir in exDirList: + for eachRootDir in dirNameList: + if eachExDir =3D=3D eachRootDir: + print("\nERROR: excludedDirectory is same as rootDirectory\n= ") + raise Exception + exPathList.append(eachRootDir + os.sep + eachExDir) + except: + usage() + + global options + options =3D {'destname':destname, 'dirNameList':dirNameList, 'exPathList= ':exPathList, 'BuildOption':BuildOption, 'UpdateUQIs':UpdateUQIs, + 'LangOption':LangOption, 'ExcludeOption':ExcludeOption, 'Ques= tionOption':QuestionOption} + print("UQI file: %s" %destname) + for eachDirName in dirNameList: + Walk(eachDirName, processUni, None) + if questionError: + raise RuntimeError + return + if os.path.isdir(options['destname']): + destFileName =3D options['destname']+os.sep+'UqiList.uni' + else: + destFileName =3D options['destname'] + if os.path.exists(destFileName) and (destFileName not in list(allUqis.ke= ys())): + try: + Encoding =3D GetUniFileEncoding (destFileName) + destFile =3D codecs.open(destFileName, 'r+', Encoding) + destFileBuffer =3D destFile.read() + destFile.close() + except IOError as e: + print("ERROR: " + e.args[1]) + raise RuntimeError + return + allUqis[destFileName]=3D uqiList(destFileBuffer) + returnVal =3D 0 + if BuildOption: + returnVal =3D newUqi() + if (returnVal =3D=3D 1): + raise(RuntimeError, 'Please fix UQI ERROR(s) above before proceeding= .') + else: + print("No UQI issues detected\n") + return + +#********************************************************************** +# description: newUqi collects a list of all currently used uqi values in = the tree +# Halt build if any duplicated string or value in UQI list. +# If -u option was specified, creates new UQIs that does not +# already exist in uqiFile for any string requiring a UQI. +# +# arguments: none +# +# returns: 0 on success +# 1 on error - this should cause the build to halt +# + +syntax =3D "S" +syntaxRE =3D re.compile('#string[ \t]+[A-Z_0-9]+[ \t]+#language[ \t]+uqi[ = \t\r\n]+"([x\S]{1,2}).*',re.DOTALL).findall + +def newUqi(): + global options, GlobalVarId, allUqis, syntax, syntaxRE + uqiRange=3D[] + uqiStringList=3D[] + createUQI=3D[] + returnVal =3D 0 + BaseNumSpaces =3D 47 # Used to line up the UQI values in the resulting u= qiFile + + # Look for duplication in the current UQIs and collect current range of = UQIs + for path in allUqis.keys(): + for uqiString in allUqis[path]: # path contains the path and filename = of each uni file + #Checks for duplicated strings in UQI list + for tempString in uqiStringList: + if tempString =3D=3D uqiString[0]: + print("ERROR: UQI string %s was assigned more than once and will= cause corruption!" %uqiString[0]) + print("Delete one occurrence of the string and rerun tool.") + returnVal =3D 1 #halt build + + uqiStringList.append(uqiString[0]) + + #Checks for duplicated UQI values in UQI list + if int(uqiString[1],16) in uqiRange: + print("ERROR: UQI value %04x was assigned more than once and will = cause corruption!" %int(uqiString[1],16)) + print("Delete one occurrance of the UQI and rerun tool to create a= lternate value.") + returnVal =3D 1 #halt build + uqiRange.append(int(uqiString[1],16)) + + for stringValue in GlobalVarId.keys(): + stringFound =3D False + for path in stringDict.keys(): + for uniString in stringDict[path]: # path contains the path and file= name of each uni file + if (stringValue =3D=3D uniString): + stringFound =3D True + break + if not stringFound: + print("ERROR: No definition for %s referred by HII question" %(strin= gValue)) + returnVal =3D 1 #halt build + + # Require a UQI for any string in vfr/vfi files + for stringValue in GlobalVarId.keys(): + # Ignore strings defined as STRING_TOKEN(0) + if (stringValue !=3D "0"): + # Check if this string already exists in the UQI list + if (stringValue not in uqiStringList) and (stringValue not in create= UQI): + createUQI.append(stringValue) + if not options['UpdateUQIs']: + print("ERROR: No UQI for %s referred by HII question" %(stringVa= lue)) + returnVal =3D 1 # halt build after printing all error messages + + if (returnVal =3D=3D 1): + return returnVal + + # Update uqiFile with necessary UQIs + if options['UpdateUQIs'] and createUQI: + if os.path.isdir(options['destname']): + destFileName =3D options['destname']+os.sep+'UqiList.uni' + else: + destFileName =3D options['destname'] + try: + Encoding =3D GetUniFileEncoding (destFileName) + outputFile =3D codecs.open(destFileName, 'r+', Encoding) + platformUQI=3DoutputFile.read() + except IOError as e: + print("ERROR: " + e.args[1]) + if (e.args[0]=3D=3D2): + try: + outputFile =3D codecs.open(destFileName, 'w', Encoding) + print(destFileName + " did not exist. Creating new file.") + platformUQI=3D'' + except: + print("Error creating " + destFileName + ".") + return 1 + if (e.args[1]=3D=3D"Permission denied"): + print("\n%s is Readonly. You must uncheck the ReadOnly attibute t= o run the -u option.\n" %destFileName) + return 1 + + #Determines and sets the UQI number format + #TODO: there is probably a more elegant way to do this... + syntaxL =3D syntaxRE(platformUQI) + if len(syntaxL) !=3D 0: + syntax =3D syntaxL[0] + + # script is reading the file in and writing it back instead of appendi= ng because the codecs module + # automatically adds a BOM wherever you start writing. This caused bui= ld failure. + uqiRange.sort() + if (uqiRange =3D=3D []): + nextUqi =3D 0 + else: + nextUqi =3D uqiRange[len(uqiRange) - 1] + 1 + + for stringValue in createUQI: + print("%s will be assigned a new UQI value" %stringValue) + uqiRange.append(nextUqi) + # + # Lines up the UQI values in the resulting uqiFile + # + spaces =3D " "*(BaseNumSpaces - len(stringValue)) + platformUQI +=3D '#string %s%s #language uqi \"%s%04x\"\r\n' %(strin= gValue,spaces,syntax,nextUqi) + print("#string %s%s #language uqi \"%s%04X\"" %(stringValue, spaces= , syntax, nextUqi)) + nextUqi +=3D 1 + + outputFile.seek(0) + outputFile.write(platformUQI) + outputFile.close() + + return 0 + + +#********************************************************************** +# description: Parses each uni file to collect dictionary of strings +# Removes additional languages and overwrites current uni fil= es +# if -l option was specified +# +# arguments: path - directory location of file including file name +# filename - name of file to be modified +# +# returns: error string if failure occurred; +# none if completed sucessfully +# +# the following are global so that parsefile is quicker + +findUniString =3D re.compile('^#string[ \t]+([A-Z_0-9]+)(?:[ \t\r\n]+#lang= uage[ \t]+[a-zA-Z-]{2,5}[ \t\r\n]+".*"[ \t]*[\r]?[\n]?)*',re.M).findall + +otherLang =3D re.compile('^#string[ \t]+[A-Z_0-9]+(?:[ \t\r\n]+#language[ = \t]+[a-zA-Z-]{2,5}[ \t\r\n]+".*"[ \t]*[\r]?[\n]?)*',re.M).findall +eachLang =3D re.compile('[ \t\r\n]+#language[ \t]+([a-zA-Z-]{2,5})[ \t\r\n= ]+".*"[ \t]*[\r]?[\n]?').findall + +uqiStrings =3D re.compile('^#string[ \t]+[A-Z_0-9]+[ \t]+#language[ \t]+uq= i[ \t\r\n]+".*"[ \t]*[\r]?[\n]?',re.M) + +def parsefile(path,filename): + global options, stringDict, allUqis, uqiList, findUniString, otherLang, = eachLang, uqiStrings + + FullPath =3D path+os.sep+filename + + try: + UniEncoding =3D GetUniFileEncoding (FullPath) + UniFile =3D codecs.open(FullPath, 'r', UniEncoding) + databuffer =3D UniFile.read() + UniFile.close() + except: + return ("Error opening " + FullPath + " for reading.") + writeFile =3D False + + if os.path.isdir(options['destname']): + destFileName =3D options['destname']+os.sep+'UqiList.uni' + else: + destFileName =3D options['destname'] + + if options['LangOption']: + try: + UqiEncoding =3D GetUniFileEncoding (destFileName) + outputFile =3D codecs.open(destFileName, 'r+', UqiEncoding) + platformUQI=3DoutputFile.read() + except IOError as e: + print("ERROR: " + e.args[1]) + if (e.args[0]=3D=3D2): + try: + outputFile =3D codecs.open(destFileName, 'w', UqiEncoding) + print(destFileName + " did not exist. Creating new file.") + platformUQI=3D'' + except: + return ("Error creating " + destFileName + ".") + else: + return ("Error opening " + destFileName + " for appending.") + + if (filename!=3DdestFileName.split(os.sep)[-1]): + Uqis =3D re.findall(uqiStrings,databuffer) + if Uqis: + for uqi in Uqis: + platformUQI +=3D uqi + outputFile.seek(0) + outputFile.write(platformUQI) + outputFile.close() + databuffer =3D re.sub(uqiStrings, '', databuffer) + if Uqis: + writeFile =3D True + print("Deleted uqis from %s" %FullPath) + stringlist =3D otherLang(databuffer) + for stringfound in stringlist: + thisString =3D eachLang(stringfound) + for languageFound in thisString: + if ((languageFound !=3D 'en') and (languageFound !=3D 'en-US') a= nd (languageFound !=3D 'eng') and (languageFound !=3D 'uqi')): + databuffer =3D re.sub(re.escape(stringfound), '', databuffer) + writeFile =3D True + print("Deleted %s from %s" %(languageFound, FullPath)) + if (filename!=3DdestFileName.split(os.sep)[-1]): + #adding strings to dictionary + stringDict[r'%s' %FullPath]=3D findUniString(databuffer) + #adding UQIs to dictionary + allUqis[r'%s' %FullPath]=3D uqiList(databuffer) + + if writeFile: + try: + UniFile =3D codecs.open(FullPath, 'w', UniEncoding) + UniFile.write(databuffer) + UniFile.close() + except: + return ("Error opening " + FullPath + " for writing.") + return + +#********************************************************************** +# description: Searches tree for uni files +# Calls parsefile to collect dictionary of strings in each un= i file +# Calls searchVfiFile for each vfi or vfr file found +# +# arguments: argument list is built by os.path.walk function call +# arg - None +# dirname - directory location of files +# names - specific files to search in directory +# +# returns: none +# +def processUni(args,dirname,names) : + global options + #Remove excludedDirectory + if options['ExcludeOption']: + for eachExDir in options['exPathList']: + for dir in names: + if os.path.join(dirname,dir) =3D=3D eachExDir: + names.remove(dir) + + for entry in names: + FullPath =3D dirname+os.sep+entry + if fnmatch.fnmatch(FullPath,'*.uni'): + parsefile(dirname,entry) + if fnmatch.fnmatch(FullPath,'*.vf*'): + searchVfiFile(FullPath) + if fnmatch.fnmatch(FullPath,'*.sd'): + searchVfiFile(FullPath) + if fnmatch.fnmatch(FullPath,'*.sdi'): + searchVfiFile(FullPath) + if fnmatch.fnmatch(FullPath,'*.hfr'): + searchVfiFile(FullPath) + return + +#********************************************************************** +# description: Compose a dictionary of all strings that may need UQIs assi= gned +# to them and key is the string +# +# arguments: filename - name of file to search for strings +# +# returns: none +# + +#separate regexes for readability +stringGroups =3D re.compile('^[ \t]*(?:oneof|numeric|checkbox|orderedlist)= [ \t]+varid.+?(?:endoneof|endnumeric|endcheckbox|endorderedlist);', re.DOTA= LL|re.M).findall +stringVarIds =3D re.compile('[ \t]*(?:oneof|numeric|checkbox|orderedlist)[= \t]+varid[ \t]*=3D[ \t]*([a-zA-Z_0-9]+\.[a-zA-Z_0-9]+)').findall +stringTokens =3D re.compile('prompt[ \t]*=3D[ \t]*STRING_TOKEN[ \t]*\(([a-= zA-Z_0-9]+)\)').findall + +def searchVfiFile(filename) : + global options, GlobalVarId, stringGroups, stringVarIds, stringTokens, q= uestionError + try: + vfiFile =3D open(filename, 'r') + databuffer=3DvfiFile.read() + vfiFile.close() + + # Finds specified lines in file + vfiStringGroup =3D stringGroups(databuffer) + + # Searches for prompts within specified lines + for eachGroup in vfiStringGroup: + for eachString in stringTokens(eachGroup): + # Ignore strings defined as STRING_TOKEN(0), STRING_TOKEN(STR_EMPT= Y) or STRING_TOKEN(STR_NULL) + if (eachString !=3D "0") and (eachString !=3D "STR_EMPTY") and (ea= chString !=3D "STR_NULL"): + if eachString not in GlobalVarId: + GlobalVarId[eachString]=3DstringVarIds(eachGroup) + else: + if (GlobalVarId[eachString][0] !=3D stringVarIds(eachGroup)[0]= ): + if options['QuestionOption']: + if options['QuestionOption'] =3D=3D "e": + questionError =3D True + print("ERROR:"), + if options['QuestionOption'] =3D=3D "w": + print("WARNING:"), + print("%s referred by different HII questions(%s and %s)" = %(eachString, GlobalVarId[eachString][0], stringVarIds(eachGroup)[0])) + except: + print("Error opening file at %s for reading." %filename) + +if __name__ =3D=3D '__main__' : + sys.exit(main(sys.argv)) --=20 2.14.1.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#41572): https://edk2.groups.io/g/devel/message/41572 Mute This Topic: https://groups.io/mt/31831056/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- --_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF631CCSHSMSX101ccrcor_ Content-Disposition: attachment; filename="winmail.dat" Content-Transfer-Encoding: base64 Content-Type: application/ms-tnef; name="winmail.dat" eJ8+Iq4NAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEJgAEAIQAAAEFDRUMwRDFC MEZFNjNFNDc4MkU5MkVERjJBNUMwOUNBAIgHAQ2ABAACAAAAAgACAAEFgAMADgAAAOMHBQAdAAYA CQACAAMAIAEBIIADAA4AAADjBwUAHQAGAAkAAgADACABAQiABwAYAAAASVBNLk1pY3Jvc29mdCBN YWlsLk5vdGUAMQgBBIABADsAAABbUEFUQ0hdIEJhc2VUb29sczphZGQgVW5pVG9vbC5weSB0byBF ZGsyXEJhc2VUb29sc1xTY3JpcHRzAM0UAQuAAQAhAAAAQUNFQzBEMUIwRkU2M0U0NzgyRTkyRURG MkE1QzA5Q0EAiAcBA5AGAAQqAAA0AAAAAgF/AAEAAABIAAAAPEZBRDBEN0UwQUUwRkE1NEQ5ODdG NkU3MjQzNUNBRkQ1MEFGNjMxQ0NAU0hTTVNYMTAxLmNjci5jb3JwLmludGVsLmNvbT4ACwAfDgEA AAACAQkQAQAAAEMgAAA/IAAAIFkAAExaRnUPQy17YQAKZmJpZAQAAGNjwHBnMTI1MgD+A0PwdGV4 dAH3AqQD4wIABGNoCsBzZXQwIO8HbQKDAFARTTIKgAa0AoCWfQqACMg7CWIxOQ7AvwnDFnIKMhZx AoAVYioJsHMJ8ASQYXQFsg5QA2Bzom8BgCBFeBHBbhgwXQZSdgSQF7YCEHIAwHR9CFBuGjEQIAXA BaAbZGSaIANSIBAiF7JcdgiQ5HdrC4BkNR1TBPAHQA0XcDAKcRfyYmttawZzAZAAICBCTV9C4EVH SU59CvwB8QvxER+wWjpoAkBwczrALy9idWd6AxALYCQudAcwbm8FoWUuAQWwZy9zaG93X0EiUS5j Z2k/DdA9qDE4NR3gbAuAZQqBpSUUVQMAVG8G8CAEAMYgAiAZ4HB5dCPQA6AbBPUYkCAYNRngVVFJ LCAoJeEaMXMHQCBR6wpQH2BpJxFJAQACMAaQ9QiRKSUFdQMABaABACcwnnQFEBnAHHAFsUhJKJAC cSl2UFJPTVBUvSuFLihjK5UeUAOgYhngfnUSABxgGJAlBQ3QKhN5VCBlANBoLDsuJQxU7mgmYQT1 LrVyKxAmUC7Rxm8m8C0AeTIgAHAcYEU0gDMxrUNjOh+wb1hiIEYJ8CvgPAbgYmkkQC5mNrFAC4AQ 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 VZ8zi1agAQIR4pr9f+g9Q2XkAR3QpVxGpqUN/437qSBRIbuhy/RokeKiuNP/ubpDJXFEH0OFYR7q ou9Jj++yx24iNKQdUHdcgHEQbzH/SwzZ33HhTbR1QU0s3P+8xHdxRW8nM1QoVMd+j0phSf8QMG4w EzYdUNGBc0FooA/wc7KwNgkoMIJxXMs18V/gRU1QVFl8oG4xXd98TlUoMIOPixJXqXhxIv4wqsB8 tGItXqdjL2Q4YJL/qsBZ///jV6kagMFBdVA9ifdnP3aiPYlbV6iS4Cm6WUl/an+5ELYQnCx2ymu/ bMRb/DBdeGJtP1mUcwFnL9+J/dhWUUEF2U+6jHZ/d4vhsvgiZSJ4X3C4QPuFb3jugYcVRVJST1I6 qsDeLH8PeX96j3uUd3wPf//gIldBUk42IYFvhl/+IpIQp3GjYS2xweL8oKNS8cDSSElJQOdO4IoR EmL1khApqPAlYhk9a3JNPxz/dD1umaY/gIioK73jDuGKET8ddqqDmFA7N0++aGFfX/fHspgg4bIn mCAA0FVgmCByJzvKc3ngMNwworAorZkSKJpCxTF2kYctxbDhiCUyLjE0nOCigDixNG934DAxiCWI JX19A2EwnvAAHwBCAAEAAAAYAAAARgBhAG4ALAAgAFoAaABpAGoAdQBYAAAAHwBlAAEAAAAqAAAA egBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAuAGMAbwBtAAAAAAAfAGQAAQAAAAoAAABT AE0AVABQAAAAAAACAUEAAQAAAGQAAAAAAAAAgSsfpL6jEBmdbgDdAQ9UAgAAAIBGAGEAbgAsACAA WgBoAGkAagB1AFgAAABTAE0AVABQAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAu AGMAbwBtAAAAHwACXQEAAAAqAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAuAGMA bwBtAAAAAAAfAOVfAQAAADIAAABzAGkAcAA6AHoAaABpAGoAdQB4AC4AZgBhAG4AQABpAG4AdABl AGwALgBjAG8AbQAAAAAAHwAaDAEAAAAYAAAARgBhAG4ALAAgAFoAaABpAGoAdQBYAAAAHwAfDAEA AAAqAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAuAGMAbwBtAAAAAAAfAB4MAQAA AAoAAABTAE0AVABQAAAAAAACARkMAQAAAGQAAAAAAAAAgSsfpL6jEBmdbgDdAQ9UAgAAAIBGAGEA bgAsACAAWgBoAGkAagB1AFgAAABTAE0AVABQAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0 AGUAbAAuAGMAbwBtAAAAHwABXQEAAAAqAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUA bAAuAGMAbwBtAAAAAAAfAPg/AQAAABgAAABGAGEAbgAsACAAWgBoAGkAagB1AFgAAAAfACNAAQAA ACoAAAB6AGgAaQBqAHUAeAAuAGYAYQBuAEAAaQBuAHQAZQBsAC4AYwBvAG0AAAAAAB8AIkABAAAA CgAAAFMATQBUAFAAAAAAAAIB+T8BAAAAZAAAAAAAAACBKx+kvqMQGZ1uAN0BD1QCAAAAgEYAYQBu ACwAIABaAGgAaQBqAHUAWAAAAFMATQBUAFAAAAB6AGgAaQBqAHUAeAAuAGYAYQBuAEAAaQBuAHQA ZQBsAC4AYwBvAG0AAAAfAAldAQAAACoAAAB6AGgAaQBqAHUAeAAuAGYAYQBuAEAAaQBuAHQAZQBs AC4AYwBvAG0AAAAAAAsAQDoBAAAAHwAaAAEAAAASAAAASQBQAE0ALgBOAG8AdABlAAAAAAADAPE/ CQQAAAsAQDoBAAAAAwD9P+QEAAACAQswAQAAABAAAACs7A0bD+Y+R4LpLt8qXAnKAwAXAAEAAABA ADkAAFMKA+UV1QFAAAgwgKFLA+UV1QEfAACAhgMCAAAAAADAAAAAAAAARgEAAAAeAAAAYQBjAGMA ZQBwAHQAbABhAG4AZwB1AGEAZwBlAAAAAAABAAAADAAAAGUAbgAtAFUAUwAAAB8ANwABAAAAdgAA AFsAUABBAFQAQwBIAF0AIABCAGEAcwBlAFQAbwBvAGwAcwA6AGEAZABkACAAVQBuAGkAVABvAG8A bAAuAHAAeQAgAHQAbwAgAEUAZABrADIAXABCAGEAcwBlAFQAbwBvAGwAcwBcAFMAYwByAGkAcAB0 AHMAAAAAAB8APQABAAAAAgAAAAAAAAADADYAAAAAAAIBcQABAAAAFgAAAAHVFeTRYIjx44pqHk/y nYCAL5uo2lkAAB8AcAABAAAAdgAAAFsAUABBAFQAQwBIAF0AIABCAGEAcwBlAFQAbwBvAGwAcwA6 AGEAZABkACAAVQBuAGkAVABvAG8AbAAuAHAAeQAgAHQAbwAgAEUAZABrADIAXABCAGEAcwBlAFQA bwBvAGwAcwBcAFMAYwByAGkAcAB0AHMAAAAAAB8ANRABAAAAkAAAADwARgBBAEQAMABEADcARQAw AEEARQAwAEYAQQA1ADQARAA5ADgANwBGADYARQA3ADIANAAzADUAQwBBAEYARAA1ADAAQQBGADYA MwAxAEMAQwBAAFMASABTAE0AUwBYADEAMAAxAC4AYwBjAHIALgBjAG8AcgBwAC4AaQBuAHQAZQBs AC4AYwBvAG0APgAAAAMA3j+fTgAAQAAHMJG6PwPlFdUBAgELAAEAAAAQAAAArOwNGw/mPkeC6S7f KlwJygMAJgAAAAAAAgFHAAEAAAAzAAAAYz1VUzthPU1DSTtwPUludGVsO2w9U0hTTVNYMTAxLTE5 MDUyOTA2MDkwMlotMjcwMDQAAAIBEDABAAAARgAAAAAAAAAmd705O+w4SaSmFT3LpXtCBwD60Nfg rg+lTZh/bnJDXK/VAAAARBFeAACmk2g2iHZsS6dK0+tHmkxkAAAJVI+PAAAAAB8A+j8BAAAAGAAA AEYAYQBuACwAIABaAGgAaQBqAHUAWAAAAAMACVkBAAAAQAAAgAggBgAAAAAAwAAAAAAAAEYAAAAA v4UAAJA0JgLlFdUBCwAAgAggBgAAAAAAwAAAAAAAAEYAAAAAgoUAAAAAAAADAACACCAGAAAAAADA AAAAAAAARgAAAADrhQAACQQAAB8AAICGAwIAAAAAAMAAAAAAAABGAQAAABgAAABkAGwAcAAtAHAA cgBvAGQAdQBjAHQAAAABAAAAGgAAAGQAbABwAGUALQB3AGkAbgBkAG8AdwBzAAAAAAAfAACAhgMC AAAAAADAAAAAAAAARgEAAAAYAAAAZABsAHAALQB2AGUAcgBzAGkAbwBuAAAAAQAAABYAAAAxADEA LgAwAC4ANgAwADAALgA3AAAAAAAfAACAhgMCAAAAAADAAAAAAAAARgEAAAAaAAAAZABsAHAALQBy AGUAYQBjAHQAaQBvAG4AAAAAAAEAAAAUAAAAbgBvAC0AYQBjAHQAaQBvAG4AAAADAA00/T8AAB8A AICGAwIAAAAAAMAAAAAAAABGAQAAACAAAAB4AC0AbQBzAC0AaABhAHMALQBhAHQAdABhAGMAaAAA AAEAAAACAAAAAAAAAB8AAICGAwIAAAAAAMAAAAAAAABGAQAAACIAAAB4AC0AbwByAGkAZwBpAG4A YQB0AGkAbgBnAC0AaQBwAAAAAAABAAAAIAAAAFsAMQAwAC4AMgAzADkALgAxADIANwAuADQAMABd AAAAR1w= --_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF631CCSHSMSX101ccrcor_--