123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- ## @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
|