--- /dev/null
+## @file\r
+#\r
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+\r
+from message import *\r
+import re\r
+import os\r
+\r
+section_re = re.compile(r'^\[([\w., "]+)\]')\r
+\r
+class BaseINIFile(object):\r
+ _objs = {}\r
+ def __new__(cls, *args, **kwargs):\r
+ """Maintain only a single instance of this object\r
+ @return: instance of this class\r
+\r
+ """\r
+ if len(args) == 0: return object.__new__(cls, *args, **kwargs)\r
+ filename = args[0]\r
+ parent = None\r
+ if len(args) > 1:\r
+ parent = args[1]\r
+\r
+ key = os.path.normpath(filename)\r
+ if key not in cls._objs.keys():\r
+ cls._objs[key] = object.__new__(cls, *args, **kwargs)\r
+\r
+ if parent != None:\r
+ cls._objs[key].AddParent(parent)\r
+\r
+ return cls._objs[key]\r
+\r
+ def __init__(self, filename=None, parent=None):\r
+ self._lines = []\r
+ self._sections = {}\r
+ self._filename = filename\r
+ self._globals = []\r
+ self._isModify = True\r
+\r
+ def AddParent(self, parent):\r
+ if parent == None: return\r
+ if not hasattr(self, "_parents"):\r
+ self._parents = []\r
+\r
+ if parent in self._parents:\r
+ ErrorMsg("Duplicate parent is found for INI file %s" % self._filename)\r
+ return\r
+ self._parents.append(parent)\r
+\r
+ def GetFilename(self):\r
+ return os.path.normpath(self._filename)\r
+\r
+ def IsModified(self):\r
+ return self._isModify\r
+\r
+ def Modify(self, modify=True, obj=None):\r
+ if modify == self._isModify: return\r
+ self._isModify = modify\r
+ if modify:\r
+ for parent in self._parents:\r
+ parent.Modify(True, self)\r
+\r
+ def _ReadLines(self, filename):\r
+ #\r
+ # try to open file\r
+ #\r
+ if not os.path.exists(filename):\r
+ return False\r
+\r
+ try:\r
+ handle = open(filename, 'r')\r
+ self._lines = handle.readlines()\r
+ handle.close()\r
+ except:\r
+ raise EdkException("Fail to open file %s" % filename)\r
+\r
+ return True\r
+\r
+ def GetSectionInstance(self, parent, name, isCombined=False):\r
+ return BaseINISection(parent, name, isCombined)\r
+\r
+ def GetSectionByName(self, name):\r
+ arr = []\r
+ for key in self._sections.keys():\r
+ if '.private' in key:\r
+ continue\r
+ for item in self._sections[key]:\r
+ if item.GetBaseName().lower().find(name.lower()) != -1:\r
+ arr.append(item)\r
+ return arr\r
+\r
+ def GetSectionObjectsByName(self, name):\r
+ arr = []\r
+ sects = self.GetSectionByName(name)\r
+ for sect in sects:\r
+ for obj in sect.GetObjects():\r
+ arr.append(obj)\r
+ return arr\r
+\r
+ def Parse(self):\r
+ if not self._isModify: return True\r
+ if not self._ReadLines(self._filename): return False\r
+\r
+ sObjs = []\r
+ inGlobal = True\r
+ # process line\r
+ for index in range(len(self._lines)):\r
+ templine = self._lines[index].strip()\r
+ # skip comments\r
+ if len(templine) == 0: continue\r
+ if re.match("^\[=*\]", templine) or re.match("^#", templine) or \\r
+ re.match("\*+/", templine):\r
+ continue\r
+\r
+ m = section_re.match(templine)\r
+ if m!= None: # found a section\r
+ inGlobal = False\r
+ # Finish the latest section first\r
+ if len(sObjs) != 0:\r
+ for sObj in sObjs:\r
+ sObj._end = index - 1\r
+ if not sObj.Parse():\r
+ ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),\r
+ self._filename,\r
+ sObj._start)\r
+\r
+ # start new section\r
+ sname_arr = m.groups()[0].split(',')\r
+ sObjs = []\r
+ for name in sname_arr:\r
+ sObj = self.GetSectionInstance(self, name, (len(sname_arr) > 1))\r
+ sObj._start = index\r
+ sObjs.append(sObj)\r
+ if not self._sections.has_key(name.lower()):\r
+ self._sections[name.lower()] = [sObj]\r
+ else:\r
+ self._sections[name.lower()].append(sObj)\r
+ elif inGlobal: # not start any section and find global object\r
+ gObj = BaseINIGlobalObject(self)\r
+ gObj._start = index\r
+ gObj.Parse()\r
+ self._globals.append(gObj)\r
+\r
+ # Finish the last section\r
+ if len(sObjs) != 0:\r
+ for sObj in sObjs:\r
+ sObj._end = index\r
+ if not sObj.Parse():\r
+ ErrorMsg("Fail to parse section %s" % sObj.GetBaseName(),\r
+ self._filename,\r
+ sObj._start)\r
+\r
+ self._isModify = False\r
+ return True\r
+\r
+ def Destroy(self, parent):\r
+\r
+ # check referenced parent\r
+ if parent != None:\r
+ assert parent in self._parents, "when destory ini object, can not found parent reference!"\r
+ self._parents.remove(parent)\r
+\r
+ if len(self._parents) != 0: return\r
+\r
+ for sects in self._sections.values():\r
+ for sect in sects:\r
+ sect.Destroy()\r
+\r
+ # dereference from _objs array\r
+ assert self.GetFilename() in self._objs.keys(), "When destroy ini object, can not find obj reference!"\r
+ assert self in self._objs.values(), "When destroy ini object, can not find obj reference!"\r
+ del self._objs[self.GetFilename()]\r
+\r
+ # dereference self\r
+ self.Clear()\r
+\r
+ def GetDefine(self, name):\r
+ sects = self.GetSectionByName('Defines')\r
+ for sect in sects:\r
+ for obj in sect.GetObjects():\r
+ line = obj.GetLineByOffset(obj._start).split('#')[0].strip()\r
+ arr = line.split('=')\r
+ if arr[0].strip().lower() == name.strip().lower():\r
+ return arr[1].strip()\r
+ return None\r
+\r
+ def Clear(self):\r
+ for sects in self._sections.values():\r
+ for sect in sects:\r
+ del sect\r
+ self._sections.clear()\r
+ for gObj in self._globals:\r
+ del gObj\r
+\r
+ del self._globals[:]\r
+ del self._lines[:]\r
+\r
+ def Reload(self):\r
+ self.Clear()\r
+ ret = self.Parse()\r
+ if ret:\r
+ self._isModify = False\r
+ return ret\r
+\r
+ def AddNewSection(self, sectName):\r
+ if sectName.lower() in self._sections.keys():\r
+ ErrorMsg('Section %s can not be created for conflict with existing section')\r
+ return None\r
+\r
+ sectionObj = self.GetSectionInstance(self, sectName)\r
+ sectionObj._start = len(self._lines)\r
+ sectionObj._end = len(self._lines) + 1\r
+ self._lines.append('[%s]\n' % sectName)\r
+ self._lines.append('\n\n')\r
+ self._sections[sectName.lower()] = sectionObj\r
+ return sectionObj\r
+\r
+ def CopySectionsByName(self, oldDscObj, nameStr):\r
+ sects = oldDscObj.GetSectionByName(nameStr)\r
+ for sect in sects:\r
+ sectObj = self.AddNewSection(sect.GetName())\r
+ sectObj.Copy(sect)\r
+\r
+ def __str__(self):\r
+ return ''.join(self._lines)\r
+\r
+ ## Get file header's comment from basic INI file.\r
+ # The file comments has two style:\r
+ # 1) #/** @file\r
+ # 2) ## @file\r
+ #\r
+ def GetFileHeader(self):\r
+ desc = []\r
+ lineArr = self._lines\r
+ inHeader = False\r
+ for num in range(len(self._lines)):\r
+ line = lineArr[num].strip()\r
+ if not inHeader and (line.startswith("#/**") or line.startswith("##")) and \\r
+ line.find("@file") != -1:\r
+ inHeader = True\r
+ continue\r
+ if inHeader and (line.startswith("#**/") or line.startswith('##')):\r
+ inHeader = False\r
+ break\r
+ if inHeader:\r
+ prefixIndex = line.find('#')\r
+ if prefixIndex == -1:\r
+ desc.append(line)\r
+ else:\r
+ desc.append(line[prefixIndex + 1:])\r
+ return '<br>\n'.join(desc)\r
+\r
+class BaseINISection(object):\r
+ def __init__(self, parent, name, isCombined=False):\r
+ self._parent = parent\r
+ self._name = name\r
+ self._isCombined = isCombined\r
+ self._start = 0\r
+ self._end = 0\r
+ self._objs = []\r
+\r
+ def __del__(self):\r
+ for obj in self._objs:\r
+ del obj\r
+ del self._objs[:]\r
+\r
+ def GetName(self):\r
+ return self._name\r
+\r
+ def GetObjects(self):\r
+ return self._objs\r
+\r
+ def GetParent(self):\r
+ return self._parent\r
+\r
+ def GetStartLinenumber(self):\r
+ return self._start\r
+\r
+ def GetEndLinenumber(self):\r
+ return self._end\r
+\r
+ def GetLine(self, linenumber):\r
+ return self._parent._lines[linenumber]\r
+\r
+ def GetFilename(self):\r
+ return self._parent.GetFilename()\r
+\r
+ def GetSectionINIObject(self, parent):\r
+ return BaseINISectionObject(parent)\r
+\r
+ def Parse(self):\r
+ # skip first line in section, it is used by section name\r
+ visit = self._start + 1\r
+ iniObj = None\r
+ while (visit <= self._end):\r
+ line = self.GetLine(visit).strip()\r
+ if re.match("^\[=*\]", line) or re.match("^#", line) or len(line) == 0:\r
+ visit += 1\r
+ continue\r
+ line = line.split('#')[0].strip()\r
+ if iniObj != None:\r
+ if line.endswith('}'):\r
+ iniObj._end = visit - self._start\r
+ if not iniObj.Parse():\r
+ ErrorMsg("Fail to parse ini object",\r
+ self.GetFilename(),\r
+ iniObj.GetStartLinenumber())\r
+ else:\r
+ self._objs.append(iniObj)\r
+ iniObj = None\r
+ else:\r
+ iniObj = self.GetSectionINIObject(self)\r
+ iniObj._start = visit - self._start\r
+ if not line.endswith('{'):\r
+ iniObj._end = visit - self._start\r
+ if not iniObj.Parse():\r
+ ErrorMsg("Fail to parse ini object",\r
+ self.GetFilename(),\r
+ iniObj.GetStartLinenumber())\r
+ else:\r
+ self._objs.append(iniObj)\r
+ iniObj = None\r
+ visit += 1\r
+ return True\r
+\r
+ def Destroy(self):\r
+ for obj in self._objs:\r
+ obj.Destroy()\r
+\r
+ def GetBaseName(self):\r
+ return self._name\r
+\r
+ def AddLine(self, line):\r
+ end = self.GetEndLinenumber()\r
+ self._parent._lines.insert(end, line)\r
+ self._end += 1\r
+\r
+ def Copy(self, sectObj):\r
+ index = sectObj.GetStartLinenumber() + 1\r
+ while index < sectObj.GetEndLinenumber():\r
+ line = sectObj.GetLine(index)\r
+ if not line.strip().startswith('#'):\r
+ self.AddLine(line)\r
+ index += 1\r
+\r
+ def AddObject(self, obj):\r
+ lines = obj.GenerateLines()\r
+ for line in lines:\r
+ self.AddLine(line)\r
+\r
+ def GetComment(self):\r
+ comments = []\r
+ start = self._start - 1\r
+ bFound = False\r
+\r
+ while (start > 0):\r
+ line = self.GetLine(start).strip()\r
+ if len(line) == 0:\r
+ start -= 1\r
+ continue\r
+ if line.startswith('##'):\r
+ bFound = True\r
+ index = line.rfind('#')\r
+ if (index + 1) < len(line):\r
+ comments.append(line[index + 1:])\r
+ break\r
+ if line.startswith('#'):\r
+ start -= 1\r
+ continue\r
+ break\r
+ if bFound:\r
+ end = start + 1\r
+ while (end < self._start):\r
+ line = self.GetLine(end).strip()\r
+ if len(line) == 0: break\r
+ if not line.startswith('#'): break\r
+ index = line.rfind('#')\r
+ if (index + 1) < len(line):\r
+ comments.append(line[index + 1:])\r
+ end += 1\r
+ return comments\r
+\r
+class BaseINIGlobalObject(object):\r
+ def __init__(self, parent):\r
+ self._start = 0\r
+ self._end = 0\r
+\r
+ def Parse(self):\r
+ return True\r
+\r
+ def __str__(self):\r
+ return parent._lines[self._start]\r
+\r
+ def __del__(self):\r
+ pass\r
+\r
+class BaseINISectionObject(object):\r
+ def __init__(self, parent):\r
+ self._start = 0\r
+ self._end = 0\r
+ self._parent = parent\r
+\r
+ def __del__(self):\r
+ self._parent = None\r
+\r
+ def GetParent(self):\r
+ return self._parent\r
+\r
+ def GetFilename(self):\r
+ return self.GetParent().GetFilename()\r
+\r
+ def GetPackageName(self):\r
+ return self.GetFilename()\r
+\r
+ def GetFileObj(self):\r
+ return self.GetParent().GetParent()\r
+\r
+ def GetStartLinenumber(self):\r
+ return self.GetParent()._start + self._start\r
+\r
+ def GetLineByOffset(self, offset):\r
+ sect_start = self._parent.GetStartLinenumber()\r
+ linenumber = sect_start + offset\r
+ return self._parent.GetLine(linenumber)\r
+\r
+ def GetLinenumberByOffset(self, offset):\r
+ return offset + self._parent.GetStartLinenumber()\r
+\r
+ def Parse(self):\r
+ return True\r
+\r
+ def Destroy(self):\r
+ pass\r
+\r
+ def __str__(self):\r
+ return self.GetLineByOffset(self._start).strip()\r
+\r
+ def GenerateLines(self):\r
+ return ['default setion object string\n']\r
+\r
+ def GetComment(self):\r
+ comments = []\r
+ start = self.GetStartLinenumber() - 1\r
+ bFound = False\r
+\r
+ while (start > 0):\r
+ line = self.GetParent().GetLine(start).strip()\r
+ if len(line) == 0:\r
+ start -= 1\r
+ continue\r
+ if line.startswith('##'):\r
+ bFound = True\r
+ index = line.rfind('#')\r
+ if (index + 1) < len(line):\r
+ comments.append(line[index + 1:])\r
+ break\r
+ if line.startswith('#'):\r
+ start -= 1\r
+ continue\r
+ break\r
+ if bFound:\r
+ end = start + 1\r
+ while (end <= self.GetStartLinenumber() - 1):\r
+ line = self.GetParent().GetLine(end).strip()\r
+ if len(line) == 0: break\r
+ if not line.startswith('#'): break\r
+ index = line.rfind('#')\r
+ if (index + 1) < len(line):\r
+ comments.append(line[index + 1:])\r
+ end += 1\r
+ return comments\r