X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FCommon%2FMisc.py;h=5e9a104305c2965b324c93a4e941f03443cbef4e;hb=7da06eeede10fc8b908327b375bcdf36707ff7b5;hp=a7e7797d0499df0a70026c2f6674e83ae0a0054c;hpb=ea927d2f3f2e34f4b26c10829f5887830cb0720e;p=mirror_edk2.git diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py index a7e7797d04..5e9a104305 100644 --- a/BaseTools/Source/Python/Common/Misc.py +++ b/BaseTools/Source/Python/Common/Misc.py @@ -76,7 +76,7 @@ def GetVariableOffset(mapfilepath, efifilepath, varnames): def _parseForXcode(lines, efifilepath, varnames): status = 0 ret = [] - for index, line in enumerate(lines): + for line in lines: line = line.strip() if status == 0 and line == "# Symbols:": status = 1 @@ -85,7 +85,7 @@ def _parseForXcode(lines, efifilepath, varnames): for varname in varnames: if varname in line: m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line) - if m != None: + if m is not None: ret.append((varname, m.group(1))) return ret @@ -110,27 +110,27 @@ def _parseForGCC(lines, efifilepath, varnames): # status handler if status == 3: m = re.match('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$', line) - if m != None: + if m is not None: sections.append(m.groups(0)) for varname in varnames: Str = '' m = re.match("^.data.(%s)" % varname, line) - if m != None: + if m is not None: m = re.match(".data.(%s)$" % varname, line) - if m != None: + if m is not None: Str = lines[index + 1] else: Str = line[len(".data.%s" % varname):] if Str: m = re.match('^([\da-fA-Fx]+) +([\da-fA-Fx]+)', Str.strip()) - if m != None: + if m is not None: varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0])) if not varoffset: return [] # get section information from efi file efisecs = PeImageClass(efifilepath).SectionHeaderList - if efisecs == None or len(efisecs) == 0: + if efisecs is None or len(efisecs) == 0: return [] #redirection redirection = 0 @@ -166,19 +166,19 @@ def _parseGeneral(lines, efifilepath, varnames): continue if status == 1 and len(line) != 0: m = secRe.match(line) - assert m != None, "Fail to parse the section in map file , line is %s" % line + assert m is not None, "Fail to parse the section in map file , line is %s" % line sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0) secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class]) if status == 2 and len(line) != 0: for varname in varnames: m = symRe.match(line) - assert m != None, "Fail to parse the symbol in map file, line is %s" % line + assert m is not None, "Fail to parse the symbol in map file, line is %s" % line sec_no, sym_offset, sym_name, vir_addr = m.groups(0) sec_no = int(sec_no, 16) sym_offset = int(sym_offset, 16) vir_addr = int(vir_addr, 16) m2 = re.match('^[_]*(%s)' % varname, sym_name) - if m2 != None: + if m2 is not None: # fond a binary pcd entry in map file for sec in secs: if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]): @@ -188,7 +188,7 @@ def _parseGeneral(lines, efifilepath, varnames): # get section information from efi file efisecs = PeImageClass(efifilepath).SectionHeaderList - if efisecs == None or len(efisecs) == 0: + if efisecs is None or len(efisecs) == 0: return [] ret = [] @@ -287,32 +287,6 @@ def ClearDuplicatedInf(): if os.path.exists(File): os.remove(File) -## callback routine for processing variable option -# -# This function can be used to process variable number of option values. The -# typical usage of it is specify architecure list on command line. -# (e.g. -a IA32 X64 IPF) -# -# @param Option Standard callback function parameter -# @param OptionString Standard callback function parameter -# @param Value Standard callback function parameter -# @param Parser Standard callback function parameter -# -# @retval -# -def ProcessVariableArgument(Option, OptionString, Value, Parser): - assert Value is None - Value = [] - RawArgs = Parser.rargs - while RawArgs: - Arg = RawArgs[0] - if (Arg[:2] == "--" and len(Arg) > 2) or \ - (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"): - break - Value.append(Arg) - del RawArgs[0] - setattr(Parser.values, Option.dest, Value) - ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style # # @param Guid The GUID string @@ -423,7 +397,7 @@ def GuidStructureStringToGuidValueName(GuidValue): # @param Directory The directory name # def CreateDirectory(Directory): - if Directory == None or Directory.strip() == "": + if Directory is None or Directory.strip() == "": return True try: if not os.access(Directory, os.F_OK): @@ -437,7 +411,7 @@ def CreateDirectory(Directory): # @param Directory The directory name # def RemoveDirectory(Directory, Recursively=False): - if Directory == None or Directory.strip() == "" or not os.path.exists(Directory): + if Directory is None or Directory.strip() == "" or not os.path.exists(Directory): return if Recursively: CurrentDirectory = os.getcwd() @@ -450,32 +424,6 @@ def RemoveDirectory(Directory, Recursively=False): os.chdir(CurrentDirectory) os.rmdir(Directory) -## Check if given file is changed or not -# -# This method is used to check if a file is changed or not between two build -# actions. It makes use a cache to store files timestamp. -# -# @param File The path of file -# -# @retval True If the given file is changed, doesn't exist, or can't be -# found in timestamp cache -# @retval False If the given file is changed -# -def IsChanged(File): - if not os.path.exists(File): - return True - - FileState = os.stat(File) - TimeStamp = FileState[-2] - - if File in gFileTimeStampCache and TimeStamp == gFileTimeStampCache[File]: - FileChanged = False - else: - FileChanged = True - gFileTimeStampCache[File] = TimeStamp - - return FileChanged - ## Store content in file # # This method is used to save file only when its content is changed. This is @@ -540,7 +488,7 @@ def DataDump(Data, File): except: EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False) finally: - if Fd != None: + if Fd is not None: Fd.close() ## Restore a Python object from a file @@ -560,7 +508,7 @@ def DataRestore(File): EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e))) Data = None finally: - if Fd != None: + if Fd is not None: Fd.close() return Data @@ -635,47 +583,6 @@ class DirCache: return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath]) return None -## Get all files of a directory -# -# @param Root: Root dir -# @param SkipList : The files need be skipped -# -# @retval A list of all files -# -def GetFiles(Root, SkipList=None, FullPath=True): - OriPath = Root - FileList = [] - for Root, Dirs, Files in os.walk(Root): - if SkipList: - for Item in SkipList: - if Item in Dirs: - Dirs.remove(Item) - - for File in Files: - File = os.path.normpath(os.path.join(Root, File)) - if not FullPath: - File = File[len(OriPath) + 1:] - FileList.append(File) - - return FileList - -## Check if gvien file exists or not -# -# @param File File name or path to be checked -# @param Dir The directory the file is relative to -# -# @retval True if file exists -# @retval False if file doesn't exists -# -def ValidFile(File, Ext=None): - if Ext != None: - Dummy, FileExt = os.path.splitext(File) - if FileExt.lower() != Ext.lower(): - return False - if not os.path.exists(File): - return False - return True - def RealPath(File, Dir='', OverrideDir=''): NewFile = os.path.normpath(os.path.join(Dir, File)) NewFile = GlobalData.gAllFiles[NewFile] @@ -710,115 +617,6 @@ def RealPath2(File, Dir='', OverrideDir=''): return None, None -## Check if gvien file exists or not -# -# -def ValidFile2(AllFiles, File, Ext=None, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): - NewFile = File - if Ext != None: - Dummy, FileExt = os.path.splitext(File) - if FileExt.lower() != Ext.lower(): - return False, File - - # Replace the Edk macros - if OverrideDir != '' and OverrideDir != None: - if OverrideDir.find('$(EFI_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) - if OverrideDir.find('$(EDK_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) - - # Replace the default dir to current dir - if Dir == '.': - Dir = os.getcwd() - Dir = Dir[len(Workspace) + 1:] - - # First check if File has Edk definition itself - if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1: - NewFile = File.replace('$(EFI_SOURCE)', EfiSource) - NewFile = NewFile.replace('$(EDK_SOURCE)', EdkSource) - NewFile = AllFiles[os.path.normpath(NewFile)] - if NewFile != None: - return True, NewFile - - # Second check the path with override value - if OverrideDir != '' and OverrideDir != None: - NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] - if NewFile != None: - return True, NewFile - - # Last check the path with normal definitions - File = os.path.join(Dir, File) - NewFile = AllFiles[os.path.normpath(File)] - if NewFile != None: - return True, NewFile - - return False, File - -## Check if gvien file exists or not -# -# -def ValidFile3(AllFiles, File, Workspace='', EfiSource='', EdkSource='', Dir='.', OverrideDir=''): - # Replace the Edk macros - if OverrideDir != '' and OverrideDir != None: - if OverrideDir.find('$(EFI_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EFI_SOURCE)', EfiSource) - if OverrideDir.find('$(EDK_SOURCE)') > -1: - OverrideDir = OverrideDir.replace('$(EDK_SOURCE)', EdkSource) - - # Replace the default dir to current dir - # Dir is current module dir related to workspace - if Dir == '.': - Dir = os.getcwd() - Dir = Dir[len(Workspace) + 1:] - - NewFile = File - RelaPath = AllFiles[os.path.normpath(Dir)] - NewRelaPath = RelaPath - - while(True): - # First check if File has Edk definition itself - if File.find('$(EFI_SOURCE)') > -1 or File.find('$(EDK_SOURCE)') > -1: - File = File.replace('$(EFI_SOURCE)', EfiSource) - File = File.replace('$(EDK_SOURCE)', EdkSource) - NewFile = AllFiles[os.path.normpath(File)] - if NewFile != None: - NewRelaPath = os.path.dirname(NewFile) - File = os.path.basename(NewFile) - #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] - break - - # Second check the path with override value - if OverrideDir != '' and OverrideDir != None: - NewFile = AllFiles[os.path.normpath(os.path.join(OverrideDir, File))] - if NewFile != None: - #NewRelaPath = os.path.dirname(NewFile) - NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1] - break - - # Last check the path with normal definitions - NewFile = AllFiles[os.path.normpath(os.path.join(Dir, File))] - if NewFile != None: - break - - # No file found - break - - return NewRelaPath, RelaPath, File - - -def GetRelPath(Path1, Path2): - FileName = os.path.basename(Path2) - L1 = os.path.normpath(Path1).split(os.path.normpath('/')) - L2 = os.path.normpath(Path2).split(os.path.normpath('/')) - for Index in range(0, len(L1)): - if L1[Index] != L2[Index]: - FileName = '../' * (len(L1) - Index) - for Index2 in range(Index, len(L2)): - FileName = os.path.join(FileName, L2[Index2]) - break - return os.path.normpath(FileName) - - ## Get GUID value from given packages # # @param CName The CName of the GUID @@ -1062,7 +860,7 @@ class Progressor: self.CodaMessage = CloseMessage self.ProgressChar = ProgressChar self.Interval = Interval - if Progressor._StopFlag == None: + if Progressor._StopFlag is None: Progressor._StopFlag = threading.Event() ## Start to print progress charater @@ -1070,10 +868,10 @@ class Progressor: # @param OpenMessage The string printed before progress charaters # def Start(self, OpenMessage=None): - if OpenMessage != None: + if OpenMessage is not None: self.PromptMessage = OpenMessage Progressor._StopFlag.clear() - if Progressor._ProgressThread == None: + if Progressor._ProgressThread is None: Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry) Progressor._ProgressThread.setDaemon(False) Progressor._ProgressThread.start() @@ -1084,7 +882,7 @@ class Progressor: # def Stop(self, CloseMessage=None): OriginalCodaMessage = self.CodaMessage - if CloseMessage != None: + if CloseMessage is not None: self.CodaMessage = CloseMessage self.Abort() self.CodaMessage = OriginalCodaMessage @@ -1107,9 +905,9 @@ class Progressor: ## Abort the progress display @staticmethod def Abort(): - if Progressor._StopFlag != None: + if Progressor._StopFlag is not None: Progressor._StopFlag.set() - if Progressor._ProgressThread != None: + if Progressor._ProgressThread is not None: Progressor._ProgressThread.join() Progressor._ProgressThread = None @@ -1228,7 +1026,7 @@ class sdict(IterableUserDict): return key, value def update(self, dict=None, **kwargs): - if dict != None: + if dict is not None: for k, v in dict.items(): self[k] = v if len(kwargs): @@ -1301,7 +1099,7 @@ class tdict: if self._Level_ > 1: RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)] - if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList: + if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList: FirstKey = self._Wildcard if self._Single_: @@ -1316,24 +1114,24 @@ class tdict: if FirstKey == self._Wildcard: if FirstKey in self.data: Value = self.data[FirstKey][RestKeys] - if Value == None: + if Value is None: for Key in self.data: Value = self.data[Key][RestKeys] - if Value != None: break + if Value is not None: break else: if FirstKey in self.data: Value = self.data[FirstKey][RestKeys] - if Value == None and self._Wildcard in self.data: + if Value is None and self._Wildcard in self.data: #print "Value=None" Value = self.data[self._Wildcard][RestKeys] else: if FirstKey == self._Wildcard: if FirstKey in self.data: Value = self.data[FirstKey] - if Value == None: + if Value is None: for Key in self.data: Value = self.data[Key] - if Value != None: break + if Value is not None: break else: if FirstKey in self.data: Value = self.data[FirstKey] @@ -1411,35 +1209,21 @@ class tdict: keys |= self.data[Key].GetKeys(KeyIndex - 1) return keys -## Boolean chain list -# -class Blist(UserList): - def __init__(self, initlist=None): - UserList.__init__(self, initlist) - def __setitem__(self, i, item): - if item not in [True, False]: - if item == 0: - item = False - else: - item = True - self.data[i] = item - def _GetResult(self): - Value = True - for item in self.data: - Value &= item - return Value - Result = property(_GetResult) - -def ParseConsoleLog(Filename): - Opr = open(os.path.normpath(Filename), 'r') - Opw = open(os.path.normpath(Filename + '.New'), 'w+') - for Line in Opr.readlines(): - if Line.find('.efi') > -1: - Line = Line[Line.rfind(' ') : Line.rfind('.efi')].strip() - Opw.write('%s\n' % Line) - - Opr.close() - Opw.close() +def IsFieldValueAnArray (Value): + Value = Value.strip() + if Value.startswith('GUID') and Value.endswith(')'): + return True + if Value.startswith('L"') and Value.endswith('"') and len(list(Value[2:-1])) > 1: + return True + if Value[0] == '"' and Value[-1] == '"' and len(list(Value[1:-1])) > 1: + return True + if Value[0] == '{' and Value[-1] == '}': + return True + if Value.startswith("L'") and Value.endswith("'") and len(list(Value[2:-1])) > 1: + return True + if Value[0] == "'" and Value[-1] == "'" and len(list(Value[1:-1])) > 1: + return True + return False def AnalyzePcdExpression(Setting): Setting = Setting.strip() @@ -1479,21 +1263,8 @@ def AnalyzePcdExpression(Setting): return FieldList def ParseDevPathValue (Value): - DevPathList = [ "Path","HardwarePath","Pci","PcCard","MemoryMapped","VenHw","Ctrl","BMC","AcpiPath","Acpi","PciRoot", - "PcieRoot","Floppy","Keyboard","Serial","ParallelPort","AcpiEx","AcpiExp","AcpiAdr","Msg","Ata","Scsi", - "Fibre","FibreEx","I1394","USB","I2O","Infiniband","VenMsg","VenPcAnsi","VenVt100","VenVt100Plus", - "VenUtf8","UartFlowCtrl","SAS","SasEx","NVMe","UFS","SD","eMMC","DebugPort","MAC","IPv4","IPv6","Uart", - "UsbClass","UsbAudio","UsbCDCControl","UsbHID","UsbImage","UsbPrinter","UsbMassStorage","UsbHub", - "UsbCDCData","UsbSmartCard","UsbVideo","UsbDiagnostic","UsbWireless","UsbDeviceFirmwareUpdate", - "UsbIrdaBridge","UsbTestAndMeasurement","UsbWwid","Unit","iSCSI","Vlan","Uri","Bluetooth","Wi-Fi", - "MediaPath","HD","CDROM","VenMedia","Media","Fv","FvFile","Offset","RamDisk","VirtualDisk","VirtualCD", - "PersistentVirtualDisk","PersistentVirtualCD","BbsPath","BBS","Sata" ] if '\\' in Value: Value.replace('\\', '/').replace(' ', '') - for Item in Value.split('/'): - Key = Item.strip().split('(')[0] - if Key not in DevPathList: - pass Cmd = 'DevicePath ' + '"' + Value + '"' try: @@ -1554,7 +1325,13 @@ def ParseFieldValue (Value): return Value, 16 if Value.startswith('L"') and Value.endswith('"'): # Unicode String - List = list(eval(Value[1:])) # translate escape character + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) List.reverse() Value = 0 for Char in List: @@ -1562,7 +1339,12 @@ def ParseFieldValue (Value): return Value, (len(List) + 1) * 2 if Value.startswith('"') and Value.endswith('"'): # ASCII String - List = list(eval(Value)) # translate escape character + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) List.reverse() Value = 0 for Char in List: @@ -1570,7 +1352,13 @@ def ParseFieldValue (Value): return Value, len(List) + 1 if Value.startswith("L'") and Value.endswith("'"): # Unicode Character Constant - List = list(eval(Value[1:])) # translate escape character + # translate escape character + Value = Value[1:] + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) if len(List) == 0: raise BadExpression('Length %s is %s' % (Value, len(List))) List.reverse() @@ -1580,7 +1368,12 @@ def ParseFieldValue (Value): return Value, len(List) * 2 if Value.startswith("'") and Value.endswith("'"): # Character constant - List = list(eval(Value)) # translate escape character + # translate escape character + try: + Value = eval(Value) + except: + Value = Value[1:-1] + List = list(Value) if len(List) == 0: raise BadExpression('Length %s is %s' % (Value, len(List))) List.reverse() @@ -1624,7 +1417,7 @@ def ParseFieldValue (Value): ## AnalyzeDscPcd # # Analyze DSC PCD value, since there is no data type info in DSC -# This fuction is used to match functions (AnalyzePcdData, AnalyzeHiiPcdData, AnalyzeVpdPcdData) used for retrieving PCD value from database +# This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database # 1. Feature flag: TokenSpace.PcdCName|PcdValue # 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize] # 3. Dynamic default: @@ -1682,14 +1475,6 @@ def AnalyzeDscPcd(Setting, PcdType, DataType=''): Type = DataType if len(FieldList) > 2: Size = FieldList[2] - else: - if Type == 'VOID*': - if Value.startswith("L"): - Size = str((len(Value)- 3 + 1) * 2) - elif Value.startswith("{"): - Size = str(len(Value.split(","))) - else: - Size = str(len(Value) -2 + 1 ) if DataType == "": IsValid = (len(FieldList) <= 1) else: @@ -1768,52 +1553,6 @@ def AnalyzePcdData(Setting): return ValueList -## AnalyzeHiiPcdData -# -# Analyze the pcd Value, variable name, variable Guid and variable offset. -# Used to avoid split issue while the value string contain "|" character -# -# @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information; -# -# @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue. -# -def AnalyzeHiiPcdData(Setting): - ValueList = ['', '', '', ''] - - TokenList = GetSplitValueList(Setting) - ValueList[0:len(TokenList)] = TokenList - - return ValueList - -## AnalyzeVpdPcdData -# -# Analyze the vpd pcd VpdOffset, MaxDatumSize and InitialValue. -# Used to avoid split issue while the value string contain "|" character -# -# @param[in] Setting: A String contain VpdOffset/MaxDatumSize/InitialValue information; -# -# @retval ValueList: A List contain VpdOffset, MaxDatumSize and InitialValue. -# -def AnalyzeVpdPcdData(Setting): - ValueList = ['', '', ''] - - ValueRe = re.compile(r'\s*L?\".*\|.*\"\s*$') - PtrValue = ValueRe.findall(Setting) - - ValueUpdateFlag = False - - if len(PtrValue) >= 1: - Setting = re.sub(ValueRe, '', Setting) - ValueUpdateFlag = True - - TokenList = Setting.split(TAB_VALUE_SPLIT) - ValueList[0:len(TokenList)] = TokenList - - if ValueUpdateFlag: - ValueList[2] = PtrValue[0] - - return ValueList - ## check format of PCD value against its the datum type # # For PCD value setting @@ -2036,7 +1775,7 @@ class PathClass(object): return hash(self.Path) def _GetFileKey(self): - if self._Key == None: + if self._Key is None: self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target return self._Key @@ -2355,31 +2094,6 @@ def PackRegistryFormatGuid(Guid): int(Guid[4][-2:], 16) ) -def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Value): - if PcdDatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64,'BOOLEAN']: - if Value.startswith('L') or Value.startswith('"'): - if not Value[1]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = Value - elif Value.startswith('H'): - if not Value[1]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = Value[1:] - else: - if not Value[0]: - EdkLogger.error("build", FORMAT_INVALID, 'For Void* type PCD, when specify the Value in the command line, please use the following format: "string", L"string", H"{...}"') - Value = '"' + Value + '"' - - IsValid, Cause = CheckPcdDatum(PcdDatumType, Value) - if not IsValid: - EdkLogger.error("build", FORMAT_INVALID, Cause, ExtraData="%s.%s" % (TokenSpaceGuidCName, TokenCName)) - if PcdDatumType == 'BOOLEAN': - Value = Value.upper() - if Value == 'TRUE' or Value == '1': - Value = '1' - elif Value == 'FALSE' or Value == '0': - Value = '0' - return Value ## Get the integer value from string like "14U" or integer like 2 # # @param Input The object that may be either a integer value or a string