summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py475
1 files changed, 475 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
new file mode 100755
index 00000000..6d61b7a2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
@@ -0,0 +1,475 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+from __future__ import absolute_import
+from .message import *
+import re
+import os
+
+section_re = re.compile(r'^\[([\w., "]+)\]')
+
+class BaseINIFile(object):
+ _objs = {}
+ def __new__(cls, *args, **kwargs):
+ """Maintain only a single instance of this object
+ @return: instance of this class
+
+ """
+ if len(args) == 0: return object.__new__(cls)
+ filename = args[0]
+ parent = None
+ if len(args) > 1:
+ parent = args[1]
+
+ key = os.path.normpath(filename)
+ if key not in cls._objs.keys():
+ cls._objs[key] = object.__new__(cls)
+
+ if parent is not None:
+ cls._objs[key].AddParent(parent)
+
+ return cls._objs[key]
+
+ def __init__(self, filename=None, parent=None):
+ self._lines = []
+ self._sections = {}
+ self._filename = filename
+ self._globals = []
+ self._isModify = True
+
+ def AddParent(self, parent):
+ if parent is None: return
+ if not hasattr(self, "_parents"):
+ self._parents = []
+
+ if parent in self._parents:
+ ErrorMsg("Duplicate parent is found for INI file %s" % self._filename)
+ return
+ self._parents.append(parent)
+
+ def GetFilename(self):
+ return os.path.normpath(self._filename)
+
+ def IsModified(self):
+ return self._isModify
+
+ def Modify(self, modify=True, obj=None):
+ if modify == self._isModify: return
+ self._isModify = modify
+ if modify:
+ for parent in self._parents:
+ parent.Modify(True, self)
+
+ def _ReadLines(self, filename):
+ #
+ # try to open file
+ #
+ if not os.path.exists(filename):
+ return False
+
+ try:
+ handle = open(filename, 'r')
+ self._lines = handle.readlines()
+ handle.close()
+ except:
+ raise EdkException("Fail to open file %s" % filename)
+
+ return True
+
+ def GetSectionInstance(self, parent, name, isCombined=False):
+ return BaseINISection(parent, name, isCombined)
+
+ def GetSectionByName(self, name):
+ arr = []
+ for key in self._sections.keys():
+ if '.private' in key:
+ continue
+ for item in self._sections[key]:
+ if item.GetBaseName().lower().find(name.lower()) != -1:
+ arr.append(item)
+ return arr
+
+ def GetSectionObjectsByName(self, name):
+ arr = []
+ sects = self.GetSectionByName(name)
+ for sect in sects:
+ for obj in sect.GetObjects():
+ arr.append(obj)
+ return arr
+
+ def Parse(self):
+ if not self._isModify: return True
+ if not self._ReadLines(self._filename): return False
+
+ sObjs = []
+ inGlobal = True
+ # process line
+ for index in range(len(self._lines)):
+ templine = self._lines[index].strip()
+ # skip comments
+ if len(templine) == 0: continue
+ if re.match("^\[=*\]", templine) or re.match("^#", templine) or \
+ re.match("\*+/", templine):
+ continue
+
+ m = section_re.match(templine)
+ if m is not None: # found a section
+ inGlobal = False
+ # Finish the latest section first
+ if len(sObjs) != 0:
+ for sObj in sObjs:
+ sObj._end = index - 1
+ if not sObj.Parse():
+ ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
+ self._filename,
+ sObj._start)
+
+ # start new section
+ sname_arr = m.groups()[0].split(',')
+ sObjs = []
+ for name in sname_arr:
+ sObj = self.GetSectionInstance(self, name, (len(sname_arr) > 1))
+ sObj._start = index
+ sObjs.append(sObj)
+ if name.lower() not in self._sections:
+ self._sections[name.lower()] = [sObj]
+ else:
+ self._sections[name.lower()].append(sObj)
+ elif inGlobal: # not start any section and find global object
+ gObj = BaseINIGlobalObject(self)
+ gObj._start = index
+ gObj.Parse()
+ self._globals.append(gObj)
+
+ # Finish the last section
+ if len(sObjs) != 0:
+ for sObj in sObjs:
+ sObj._end = index
+ if not sObj.Parse():
+ ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),
+ self._filename,
+ sObj._start)
+
+ self._isModify = False
+ return True
+
+ def Destroy(self, parent):
+
+ # check referenced parent
+ if parent is not None:
+ assert parent in self._parents, "when destory ini object, can not found parent reference!"
+ self._parents.remove(parent)
+
+ if len(self._parents) != 0: return
+
+ for sects in self._sections.values():
+ for sect in sects:
+ sect.Destroy()
+
+ # dereference from _objs array
+ assert self.GetFilename() in self._objs.keys(), "When destroy ini object, can not find obj reference!"
+ assert self in self._objs.values(), "When destroy ini object, can not find obj reference!"
+ del self._objs[self.GetFilename()]
+
+ # dereference self
+ self.Clear()
+
+ def GetDefine(self, name):
+ sects = self.GetSectionByName('Defines')
+ for sect in sects:
+ for obj in sect.GetObjects():
+ line = obj.GetLineByOffset(obj._start).split('#')[0].strip()
+ arr = line.split('=')
+ if arr[0].strip().lower() == name.strip().lower():
+ return arr[1].strip()
+ return None
+
+ def Clear(self):
+ for sects in self._sections.values():
+ for sect in sects:
+ del sect
+ self._sections.clear()
+ for gObj in self._globals:
+ del gObj
+
+ del self._globals[:]
+ del self._lines[:]
+
+ def Reload(self):
+ self.Clear()
+ ret = self.Parse()
+ if ret:
+ self._isModify = False
+ return ret
+
+ def AddNewSection(self, sectName):
+ if sectName.lower() in self._sections.keys():
+ ErrorMsg('Section %s can not be created for conflict with existing section')
+ return None
+
+ sectionObj = self.GetSectionInstance(self, sectName)
+ sectionObj._start = len(self._lines)
+ sectionObj._end = len(self._lines) + 1
+ self._lines.append('[%s]\n' % sectName)
+ self._lines.append('\n\n')
+ self._sections[sectName.lower()] = sectionObj
+ return sectionObj
+
+ def CopySectionsByName(self, oldDscObj, nameStr):
+ sects = oldDscObj.GetSectionByName(nameStr)
+ for sect in sects:
+ sectObj = self.AddNewSection(sect.GetName())
+ sectObj.Copy(sect)
+
+ def __str__(self):
+ return ''.join(self._lines)
+
+ ## Get file header's comment from basic INI file.
+ # The file comments has two style:
+ # 1) #/** @file
+ # 2) ## @file
+ #
+ def GetFileHeader(self):
+ desc = []
+ lineArr = self._lines
+ inHeader = False
+ for num in range(len(self._lines)):
+ line = lineArr[num].strip()
+ if not inHeader and (line.startswith("#/**") or line.startswith("##")) and \
+ line.find("@file") != -1:
+ inHeader = True
+ continue
+ if inHeader and (line.startswith("#**/") or line.startswith('##')):
+ inHeader = False
+ break
+ if inHeader:
+ prefixIndex = line.find('#')
+ if prefixIndex == -1:
+ desc.append(line)
+ else:
+ desc.append(line[prefixIndex + 1:])
+ return '<br>\n'.join(desc)
+
+class BaseINISection(object):
+ def __init__(self, parent, name, isCombined=False):
+ self._parent = parent
+ self._name = name
+ self._isCombined = isCombined
+ self._start = 0
+ self._end = 0
+ self._objs = []
+
+ def __del__(self):
+ for obj in self._objs:
+ del obj
+ del self._objs[:]
+
+ def GetName(self):
+ return self._name
+
+ def GetObjects(self):
+ return self._objs
+
+ def GetParent(self):
+ return self._parent
+
+ def GetStartLinenumber(self):
+ return self._start
+
+ def GetEndLinenumber(self):
+ return self._end
+
+ def GetLine(self, linenumber):
+ return self._parent._lines[linenumber]
+
+ def GetFilename(self):
+ return self._parent.GetFilename()
+
+ def GetSectionINIObject(self, parent):
+ return BaseINISectionObject(parent)
+
+ def Parse(self):
+ # skip first line in section, it is used by section name
+ visit = self._start + 1
+ iniObj = None
+ while (visit <= self._end):
+ line = self.GetLine(visit).strip()
+ if re.match("^\[=*\]", line) or re.match("^#", line) or len(line) == 0:
+ visit += 1
+ continue
+ line = line.split('#')[0].strip()
+ if iniObj is not None:
+ if line.endswith('}'):
+ iniObj._end = visit - self._start
+ if not iniObj.Parse():
+ ErrorMsg("Fail to parse ini object",
+ self.GetFilename(),
+ iniObj.GetStartLinenumber())
+ else:
+ self._objs.append(iniObj)
+ iniObj = None
+ else:
+ iniObj = self.GetSectionINIObject(self)
+ iniObj._start = visit - self._start
+ if not line.endswith('{'):
+ iniObj._end = visit - self._start
+ if not iniObj.Parse():
+ ErrorMsg("Fail to parse ini object",
+ self.GetFilename(),
+ iniObj.GetStartLinenumber())
+ else:
+ self._objs.append(iniObj)
+ iniObj = None
+ visit += 1
+ return True
+
+ def Destroy(self):
+ for obj in self._objs:
+ obj.Destroy()
+
+ def GetBaseName(self):
+ return self._name
+
+ def AddLine(self, line):
+ end = self.GetEndLinenumber()
+ self._parent._lines.insert(end, line)
+ self._end += 1
+
+ def Copy(self, sectObj):
+ index = sectObj.GetStartLinenumber() + 1
+ while index < sectObj.GetEndLinenumber():
+ line = sectObj.GetLine(index)
+ if not line.strip().startswith('#'):
+ self.AddLine(line)
+ index += 1
+
+ def AddObject(self, obj):
+ lines = obj.GenerateLines()
+ for line in lines:
+ self.AddLine(line)
+
+ def GetComment(self):
+ comments = []
+ start = self._start - 1
+ bFound = False
+
+ while (start > 0):
+ line = self.GetLine(start).strip()
+ if len(line) == 0:
+ start -= 1
+ continue
+ if line.startswith('##'):
+ bFound = True
+ index = line.rfind('#')
+ if (index + 1) < len(line):
+ comments.append(line[index + 1:])
+ break
+ if line.startswith('#'):
+ start -= 1
+ continue
+ break
+ if bFound:
+ end = start + 1
+ while (end < self._start):
+ line = self.GetLine(end).strip()
+ if len(line) == 0: break
+ if not line.startswith('#'): break
+ index = line.rfind('#')
+ if (index + 1) < len(line):
+ comments.append(line[index + 1:])
+ end += 1
+ return comments
+
+class BaseINIGlobalObject(object):
+ def __init__(self, parent):
+ self._start = 0
+ self._end = 0
+
+ def Parse(self):
+ return True
+
+ def __str__(self):
+ return parent._lines[self._start]
+
+ def __del__(self):
+ pass
+
+class BaseINISectionObject(object):
+ def __init__(self, parent):
+ self._start = 0
+ self._end = 0
+ self._parent = parent
+
+ def __del__(self):
+ self._parent = None
+
+ def GetParent(self):
+ return self._parent
+
+ def GetFilename(self):
+ return self.GetParent().GetFilename()
+
+ def GetPackageName(self):
+ return self.GetFilename()
+
+ def GetFileObj(self):
+ return self.GetParent().GetParent()
+
+ def GetStartLinenumber(self):
+ return self.GetParent()._start + self._start
+
+ def GetLineByOffset(self, offset):
+ sect_start = self._parent.GetStartLinenumber()
+ linenumber = sect_start + offset
+ return self._parent.GetLine(linenumber)
+
+ def GetLinenumberByOffset(self, offset):
+ return offset + self._parent.GetStartLinenumber()
+
+ def Parse(self):
+ return True
+
+ def Destroy(self):
+ pass
+
+ def __str__(self):
+ return self.GetLineByOffset(self._start).strip()
+
+ def GenerateLines(self):
+ return ['default setion object string\n']
+
+ def GetComment(self):
+ comments = []
+ start = self.GetStartLinenumber() - 1
+ bFound = False
+
+ while (start > 0):
+ line = self.GetParent().GetLine(start).strip()
+ if len(line) == 0:
+ start -= 1
+ continue
+ if line.startswith('##'):
+ bFound = True
+ index = line.rfind('#')
+ if (index + 1) < len(line):
+ comments.append(line[index + 1:])
+ break
+ if line.startswith('#'):
+ start -= 1
+ continue
+ break
+ if bFound:
+ end = start + 1
+ while (end <= self.GetStartLinenumber() - 1):
+ line = self.GetParent().GetLine(end).strip()
+ if len(line) == 0: break
+ if not line.startswith('#'): break
+ index = line.rfind('#')
+ if (index + 1) < len(line):
+ comments.append(line[index + 1:])
+ end += 1
+ return comments