From nobody Fri May 3 05:50:04 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+41584+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+41584+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1559116505; cv=none; d=zoho.com; s=zohoarc; b=Ox6Ey7szqZLpXpsWw3dn8hsot83LdkMLmlN5paFnhk4vhq+y/3f+dIvyWXg6Wn6q3/rna4BeXnMB3iKTTnpQooG2o8KmxUr84zDASIYJpgnK5vIXUSxpSlK6BdmdZRZ6D55T0/x1gxvMQIw7W8SFnw8IkQXU1tdF+54NgD1DBAE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1559116505; h=Content-Type:Cc:Date:From:List-Id:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Sender:Subject:To:ARC-Authentication-Results; bh=x7pkjOoOllYAZwruLJ0iDzZk1tpd+LxPsAxUn8wZwRc=; b=gTA7JzFCOk4JSiPx91lsrYwUaOVzxl4WZ351/ZfUqED/bKCwOVkaiYPjHjQyVJJcuF8LQ9iSb46nAUFPGnzRcKrpVoJBbQfgGfJYa5bT8vsYpBl0L2r0VkkvFBZCwLvucnmmb+ziT3bNfB4VC8ae/udw9A5u3XO+xtS4x8etPBM= 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+41584+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 1559116505984805.8651728133744; Wed, 29 May 2019 00:55:05 -0700 (PDT) Return-Path: X-Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by groups.io with SMTP; Wed, 29 May 2019 00:55:04 -0700 X-Amp-Result: UNSCANNABLE X-Amp-File-Uploaded: False X-Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 29 May 2019 00:55:03 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,526,1549958400"; d="dat'59?scan'59,208,59";a="179496513" X-Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by fmsmga002.fm.intel.com with ESMTP; 29 May 2019 00:55:03 -0700 X-Received: from fmsmsx153.amr.corp.intel.com (10.18.125.6) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.408.0; Wed, 29 May 2019 00:55:03 -0700 X-Received: from shsmsx108.ccr.corp.intel.com (10.239.4.97) by FMSMSX153.amr.corp.intel.com (10.18.125.6) with Microsoft SMTP Server (TLS) id 14.3.408.0; Wed, 29 May 2019 00:55:02 -0700 X-Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.129]) by SHSMSX108.ccr.corp.intel.com ([169.254.8.126]) with mapi id 14.03.0415.000; Wed, 29 May 2019 15:55:01 +0800 From: "Fan, ZhijuX" To: "devel@edk2.groups.io" CC: "Gao, Liming" , "Feng, Bob C" Subject: [edk2-devel] [PATCH V2] BaseTools:add UniTool.py to Edk2\BaseTools\Scripts Thread-Topic: [PATCH V2] BaseTools:add UniTool.py to Edk2\BaseTools\Scripts Thread-Index: AdUV872e9SFT1+KSSZeCoQej1V1piQ== Date: Wed, 29 May 2019 07:54:59 +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_FAD0D7E0AE0FA54D987F6E72435CAFD50AF63276SHSMSX101ccrcor_" Content-Language: en-US DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1559116505; bh=Yaeo0Fk/xeUkPLKjtzDOGgLwE2peeW+n5TgmsPwMuug=; h=CC:Content-Type:Date:From:Reply-To:Subject:To; b=dDMmfFrNDxt/PqoQMEsOpj3xYYhVLOZhbHySAryCUCBwiF2JfO+a4eOS5J9yZMdc3O8 BBTkN9GOA/Vf7JRk+J8FVrllJsuAPT55G7DzOPoZSyW2fwFXDRBqoYb2v6J4qHoKVyrPZ OwDiKFAoSN1Nev97BeRmobK3eRrU8LI/PJg= X-Zoho-Virus-Status: 1 X-ZohoMail-DKIM: pass (identity @groups.io) --_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF63276SHSMSX101ccrcor_ 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. The scripts function will sync up UQI definitions with uni files based on vfi/vfr/hfr/sd/sdi in the tree. 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 | 485 +++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 485 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..2f76d305cd --- /dev/null +++ b/BaseTools/Scripts/UniTool.py @@ -0,0 +1,485 @@ +## @file +# generate UQI (Universal Question Identifier) unicode string for HII ques= tion PROMPT string. UQI string can be used to +# identify each HII question. +# +# 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: + with open(filename, mode=3D'rb') as UniFile: + FileIn =3D UniFile.read() + 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) + with codecs.open(destFileName, 'r+', Encoding) as destFile: + destFileBuffer =3D destFile.read() + 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) + with codecs.open(FullPath, 'r', UniEncoding) as UniFile: + databuffer =3D UniFile.read() + 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: + with codecs.open(FullPath, 'w', UniEncoding) as UniFile: + UniFile.write(databuffer) + 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: + with open(filename, 'r') as vfiFile: + databuffer=3DvfiFile.read() + + # 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 (#41584): https://edk2.groups.io/g/devel/message/41584 Mute This Topic: https://groups.io/mt/31831563/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_FAD0D7E0AE0FA54D987F6E72435CAFD50AF63276SHSMSX101ccrcor_ Content-Disposition: attachment; filename="winmail.dat" Content-Transfer-Encoding: base64 Content-Type: application/ms-tnef; name="winmail.dat" eJ8+IjQIAQaQCAAEAAAAAAABAAEAAQeQBgAIAAAA5AQAAAAAAADoAAEJgAEAIQAAADk4NzZDMTZC QTBBMkUzNEM5OTE4QkM1M0RDQkQ2NThBAFYHAQ2ABAACAAAAAgACAAEFgAMADgAAAOMHBQAdAAcA NgA7AAMAhwEBIIADAA4AAADjBwUAHQAHADYAOwADAIcBAQiABwAYAAAASVBNLk1pY3Jvc29mdCBN YWlsLk5vdGUAMQgBBIABAD4AAABbUEFUQ0ggVjJdIEJhc2VUb29sczphZGQgVW5pVG9vbC5weSB0 byBFZGsyXEJhc2VUb29sc1xTY3JpcHRzAHUVAQuAAQAhAAAAOTg3NkMxNkJBMEEyRTM0Qzk5MThC QzUzRENCRDY1OEEAVgcBA5AGABwqAAA0AAAAAgF/AAEAAABIAAAAPEZBRDBEN0UwQUUwRkE1NEQ5 ODdGNkU3MjQzNUNBRkQ1MEFGNjMyNzZAU0hTTVNYMTAxLmNjci5jb3JwLmludGVsLmNvbT4ACwAf DgEAAAACAQkQAQAAAFEgAABNIAAAa1kAAExaRnX1V+lgYQAKZmJpZAQAAGNjwHBnMTI1MgD+A0Pw dGV4dAH3AqQD4wIABGNoCsBzZXQwIO8HbQKDAFARTTIKgAa0AoCWfQqACMg7CWIxOQ7AvwnDFnIK MhZxAoAVYioJsHMJ8ASQYXQFsg5QA2Bzom8BgCBFeBHBbhgwXQZSdgSQF7YCEHIAwHR9CFBuGjEQ IAXABaAbZGSaIANSIBAiF7JcdgiQ5HdrC4BkNR1TBPAHQA0XcDAKcRfyYmttawZzAZAAICBCTV9C 4EVHSU59CvwB8QvxER+wWjpoAkBwczrALy9idWd6AxALYCQudAcwbm8FoWUuAQWwZy9zaG93X0Ei US5jZ2k/DdA9qDE4NR3gbAuAZQqBpSUUVQMAVG8G8CAEAMYgAiAZ4HB5dCPQA6AbBPUYkCAYNRng VVFJLCAoJeEaMXMHQCBR2wpQH2BpAiAlBUkBAAIw4waQCJEpIHUDAAWgAQA9JzB0BRAZwBxwBbFI SQUokHEpdSBQUk9N9FBUK4UuKGIlBSuVHlD1A6BiGeB1EgAcYCexDdBRKnN5IGUA0GgsOy65JQVU aCtxBQMEIGYrEN5jLMMD8CKgJzB5MwArAO5wKGMBAQuAaSmiBCAD8D8m8CsCHHADEAeQJQViYSsv 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 LgBjAG8AbQAAAAAAHwAeDAEAAAAKAAAAUwBNAFQAUAAAAAAAAgEZDAEAAABkAAAAAAAAAIErH6S+ oxAZnW4A3QEPVAIAAACARgBhAG4ALAAgAFoAaABpAGoAdQBYAAAAUwBNAFQAUAAAAHoAaABpAGoA dQB4AC4AZgBhAG4AQABpAG4AdABlAGwALgBjAG8AbQAAAB8AAV0BAAAAKgAAAHoAaABpAGoAdQB4 AC4AZgBhAG4AQABpAG4AdABlAGwALgBjAG8AbQAAAAAAHwD4PwEAAAAYAAAARgBhAG4ALAAgAFoA aABpAGoAdQBYAAAAHwAjQAEAAAAqAAAAegBoAGkAagB1AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAu AGMAbwBtAAAAAAAfACJAAQAAAAoAAABTAE0AVABQAAAAAAACAfk/AQAAAGQAAAAAAAAAgSsfpL6j EBmdbgDdAQ9UAgAAAIBGAGEAbgAsACAAWgBoAGkAagB1AFgAAABTAE0AVABQAAAAegBoAGkAagB1 AHgALgBmAGEAbgBAAGkAbgB0AGUAbAAuAGMAbwBtAAAAHwAJXQEAAAAqAAAAegBoAGkAagB1AHgA LgBmAGEAbgBAAGkAbgB0AGUAbAAuAGMAbwBtAAAAAAALAEA6AQAAAB8AGgABAAAAEgAAAEkAUABN AC4ATgBvAHQAZQAAAAAAAwDxPwkEAAALAEA6AQAAAAMA/T/kBAAAAgELMAEAAAAQAAAAmHbBa6Ci 40yZGLxT3L1ligMAFwABAAAAQAA5AICLG9DzFdUBQAAIMJgItNDzFdUBHwAAgIYDAgAAAAAAwAAA AAAAAEYBAAAAHgAAAGEAYwBjAGUAcAB0AGwAYQBuAGcAdQBhAGcAZQAAAAAAAQAAAAwAAABlAG4A LQBVAFMAAAAfADcAAQAAAHwAAABbAFAAQQBUAEMASAAgAFYAMgBdACAAQgBhAHMAZQBUAG8AbwBs AHMAOgBhAGQAZAAgAFUAbgBpAFQAbwBvAGwALgBwAHkAIAB0AG8AIABFAGQAawAyAFwAQgBhAHMA ZQBUAG8AbwBsAHMAXABTAGMAcgBpAHAAdABzAAAAHwA9AAEAAAACAAAAAAAAAAMANgAAAAAAAgFx AAEAAAAWAAAAAdUV872e9SFT1+KSSZeCoQej1V1piQAAHwBwAAEAAAB8AAAAWwBQAEEAVABDAEgA IABWADIAXQAgAEIAYQBzAGUAVABvAG8AbABzADoAYQBkAGQAIABVAG4AaQBUAG8AbwBsAC4AcAB5 ACAAdABvACAARQBkAGsAMgBcAEIAYQBzAGUAVABvAG8AbABzAFwAUwBjAHIAaQBwAHQAcwAAAB8A NRABAAAAkAAAADwARgBBAEQAMABEADcARQAwAEEARQAwAEYAQQA1ADQARAA5ADgANwBGADYARQA3 ADIANAAzADUAQwBBAEYARAA1ADAAQQBGADYAMwAyADcANgBAAFMASABTAE0AUwBYADEAMAAxAC4A YwBjAHIALgBjAG8AcgBwAC4AaQBuAHQAZQBsAC4AYwBvAG0APgAAAAMA3j+fTgAAQAAHMDWnsdDz FdUBAgELAAEAAAAQAAAAmHbBa6Ci40yZGLxT3L1ligMAJgAAAAAAAgFHAAEAAAAzAAAAYz1VUzth PU1DSTtwPUludGVsO2w9U0hTTVNYMTAxLTE5MDUyOTA3NTQ1OVotMjcyMzUAAAIBEDABAAAARgAA AAAAAAAmd705O+w4SaSmFT3LpXtCBwD60Nfgrg+lTZh/bnJDXK/VAAAARBFeAACmk2g2iHZsS6dK 0+tHmkxkAAAJVI+QAAAAAB8A+j8BAAAAGAAAAEYAYQBuACwAIABaAGgAaQBqAHUAWAAAAAMACVkB AAAAQAAAgAggBgAAAAAAwAAAAAAAAEYAAAAAv4UAAFAEoc/zFdUBCwAAgAggBgAAAAAAwAAAAAAA AEYAAAAAgoUAAAAAAAADAACACCAGAAAAAADAAAAAAAAARgAAAADrhQAACQQAAB8AAICGAwIAAAAA AMAAAAAAAABGAQAAABgAAABkAGwAcAAtAHAAcgBvAGQAdQBjAHQAAAABAAAAGgAAAGQAbABwAGUA LQB3AGkAbgBkAG8AdwBzAAAAAAAfAACAhgMCAAAAAADAAAAAAAAARgEAAAAYAAAAZABsAHAALQB2 AGUAcgBzAGkAbwBuAAAAAQAAABYAAAAxADEALgAwAC4ANgAwADAALgA3AAAAAAAfAACAhgMCAAAA AADAAAAAAAAARgEAAAAaAAAAZABsAHAALQByAGUAYQBjAHQAaQBvAG4AAAAAAAEAAAAUAAAAbgBv AC0AYQBjAHQAaQBvAG4AAAADAA00/T8AAB8AAICGAwIAAAAAAMAAAAAAAABGAQAAACAAAAB4AC0A bQBzAC0AaABhAHMALQBhAHQAdABhAGMAaAAAAAEAAAACAAAAAAAAAB8AAICGAwIAAAAAAMAAAAAA AABGAQAAACIAAAB4AC0AbwByAGkAZwBpAG4AYQB0AGkAbgBnAC0AaQBwAAAAAAABAAAAIAAAAFsA MQAwAC4AMgAzADkALgAxADIANwAuADQAMABdAAAAoIo= --_000_FAD0D7E0AE0FA54D987F6E72435CAFD50AF63276SHSMSX101ccrcor_--