]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/ini.py
3 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
8 from __future__
import absolute_import
13 section_re
= re
.compile(r
'^\[([\w., "]+)\]')
15 class BaseINIFile(object):
17 def __new__(cls
, *args
, **kwargs
):
18 """Maintain only a single instance of this object
19 @return: instance of this class
22 if len(args
) == 0: return object.__new
__(cls
)
28 key
= os
.path
.normpath(filename
)
29 if key
not in cls
._objs
.keys():
30 cls
._objs
[key
] = object.__new
__(cls
)
32 if parent
is not None:
33 cls
._objs
[key
].AddParent(parent
)
37 def __init__(self
, filename
=None, parent
=None):
40 self
._filename
= filename
44 def AddParent(self
, parent
):
45 if parent
is None: return
46 if not hasattr(self
, "_parents"):
49 if parent
in self
._parents
:
50 ErrorMsg("Duplicate parent is found for INI file %s" % self
._filename
)
52 self
._parents
.append(parent
)
54 def GetFilename(self
):
55 return os
.path
.normpath(self
._filename
)
60 def Modify(self
, modify
=True, obj
=None):
61 if modify
== self
._isModify
: return
62 self
._isModify
= modify
64 for parent
in self
._parents
:
65 parent
.Modify(True, self
)
67 def _ReadLines(self
, filename
):
71 if not os
.path
.exists(filename
):
75 handle
= open(filename
, 'r')
76 self
._lines
= handle
.readlines()
79 raise EdkException("Fail to open file %s" % filename
)
83 def GetSectionInstance(self
, parent
, name
, isCombined
=False):
84 return BaseINISection(parent
, name
, isCombined
)
86 def GetSectionByName(self
, name
):
88 for key
in self
._sections
.keys():
91 for item
in self
._sections
[key
]:
92 if item
.GetBaseName().lower().find(name
.lower()) != -1:
96 def GetSectionObjectsByName(self
, name
):
98 sects
= self
.GetSectionByName(name
)
100 for obj
in sect
.GetObjects():
105 if not self
._isModify
: return True
106 if not self
._ReadLines
(self
._filename
): return False
111 for index
in range(len(self
._lines
)):
112 templine
= self
._lines
[index
].strip()
114 if len(templine
) == 0: continue
115 if re
.match("^\[=*\]", templine
) or re
.match("^#", templine
) or \
116 re
.match("\*+/", templine
):
119 m
= section_re
.match(templine
)
120 if m
is not None: # found a section
122 # Finish the latest section first
125 sObj
._end
= index
- 1
127 ErrorMsg("Fail to parse section %s" % sObj
.GetBaseName(),
132 sname_arr
= m
.groups()[0].split(',')
134 for name
in sname_arr
:
135 sObj
= self
.GetSectionInstance(self
, name
, (len(sname_arr
) > 1))
138 if name
.lower() not in self
._sections
:
139 self
._sections
[name
.lower()] = [sObj
]
141 self
._sections
[name
.lower()].append(sObj
)
142 elif inGlobal
: # not start any section and find global object
143 gObj
= BaseINIGlobalObject(self
)
146 self
._globals
.append(gObj
)
148 # Finish the last section
153 ErrorMsg("Fail to parse section %s" % sObj
.GetBaseName(),
157 self
._isModify
= False
160 def Destroy(self
, parent
):
162 # check referenced parent
163 if parent
is not None:
164 assert parent
in self
._parents
, "when destory ini object, can not found parent reference!"
165 self
._parents
.remove(parent
)
167 if len(self
._parents
) != 0: return
169 for sects
in self
._sections
.values():
173 # dereference from _objs array
174 assert self
.GetFilename() in self
._objs
.keys(), "When destroy ini object, can not find obj reference!"
175 assert self
in self
._objs
.values(), "When destroy ini object, can not find obj reference!"
176 del self
._objs
[self
.GetFilename()]
181 def GetDefine(self
, name
):
182 sects
= self
.GetSectionByName('Defines')
184 for obj
in sect
.GetObjects():
185 line
= obj
.GetLineByOffset(obj
._start
).split('#')[0].strip()
186 arr
= line
.split('=')
187 if arr
[0].strip().lower() == name
.strip().lower():
188 return arr
[1].strip()
192 for sects
in self
._sections
.values():
195 self
._sections
.clear()
196 for gObj
in self
._globals
:
206 self
._isModify
= False
209 def AddNewSection(self
, sectName
):
210 if sectName
.lower() in self
._sections
.keys():
211 ErrorMsg('Section %s can not be created for conflict with existing section')
214 sectionObj
= self
.GetSectionInstance(self
, sectName
)
215 sectionObj
._start
= len(self
._lines
)
216 sectionObj
._end
= len(self
._lines
) + 1
217 self
._lines
.append('[%s]\n' % sectName
)
218 self
._lines
.append('\n\n')
219 self
._sections
[sectName
.lower()] = sectionObj
222 def CopySectionsByName(self
, oldDscObj
, nameStr
):
223 sects
= oldDscObj
.GetSectionByName(nameStr
)
225 sectObj
= self
.AddNewSection(sect
.GetName())
229 return ''.join(self
._lines
)
231 ## Get file header's comment from basic INI file.
232 # The file comments has two style:
236 def GetFileHeader(self
):
238 lineArr
= self
._lines
240 for num
in range(len(self
._lines
)):
241 line
= lineArr
[num
].strip()
242 if not inHeader
and (line
.startswith("#/**") or line
.startswith("##")) and \
243 line
.find("@file") != -1:
246 if inHeader
and (line
.startswith("#**/") or line
.startswith('##')):
250 prefixIndex
= line
.find('#')
251 if prefixIndex
== -1:
254 desc
.append(line
[prefixIndex
+ 1:])
255 return '<br>\n'.join(desc
)
257 class BaseINISection(object):
258 def __init__(self
, parent
, name
, isCombined
=False):
259 self
._parent
= parent
261 self
._isCombined
= isCombined
267 for obj
in self
._objs
:
274 def GetObjects(self
):
280 def GetStartLinenumber(self
):
283 def GetEndLinenumber(self
):
286 def GetLine(self
, linenumber
):
287 return self
._parent
._lines
[linenumber
]
289 def GetFilename(self
):
290 return self
._parent
.GetFilename()
292 def GetSectionINIObject(self
, parent
):
293 return BaseINISectionObject(parent
)
296 # skip first line in section, it is used by section name
297 visit
= self
._start
+ 1
299 while (visit
<= self
._end
):
300 line
= self
.GetLine(visit
).strip()
301 if re
.match("^\[=*\]", line
) or re
.match("^#", line
) or len(line
) == 0:
304 line
= line
.split('#')[0].strip()
305 if iniObj
is not None:
306 if line
.endswith('}'):
307 iniObj
._end
= visit
- self
._start
308 if not iniObj
.Parse():
309 ErrorMsg("Fail to parse ini object",
311 iniObj
.GetStartLinenumber())
313 self
._objs
.append(iniObj
)
316 iniObj
= self
.GetSectionINIObject(self
)
317 iniObj
._start
= visit
- self
._start
318 if not line
.endswith('{'):
319 iniObj
._end
= visit
- self
._start
320 if not iniObj
.Parse():
321 ErrorMsg("Fail to parse ini object",
323 iniObj
.GetStartLinenumber())
325 self
._objs
.append(iniObj
)
331 for obj
in self
._objs
:
334 def GetBaseName(self
):
337 def AddLine(self
, line
):
338 end
= self
.GetEndLinenumber()
339 self
._parent
._lines
.insert(end
, line
)
342 def Copy(self
, sectObj
):
343 index
= sectObj
.GetStartLinenumber() + 1
344 while index
< sectObj
.GetEndLinenumber():
345 line
= sectObj
.GetLine(index
)
346 if not line
.strip().startswith('#'):
350 def AddObject(self
, obj
):
351 lines
= obj
.GenerateLines()
355 def GetComment(self
):
357 start
= self
._start
- 1
361 line
= self
.GetLine(start
).strip()
365 if line
.startswith('##'):
367 index
= line
.rfind('#')
368 if (index
+ 1) < len(line
):
369 comments
.append(line
[index
+ 1:])
371 if line
.startswith('#'):
377 while (end
< self
._start
):
378 line
= self
.GetLine(end
).strip()
379 if len(line
) == 0: break
380 if not line
.startswith('#'): break
381 index
= line
.rfind('#')
382 if (index
+ 1) < len(line
):
383 comments
.append(line
[index
+ 1:])
387 class BaseINIGlobalObject(object):
388 def __init__(self
, parent
):
396 return parent
._lines
[self
._start
]
401 class BaseINISectionObject(object):
402 def __init__(self
, parent
):
405 self
._parent
= parent
413 def GetFilename(self
):
414 return self
.GetParent().GetFilename()
416 def GetPackageName(self
):
417 return self
.GetFilename()
419 def GetFileObj(self
):
420 return self
.GetParent().GetParent()
422 def GetStartLinenumber(self
):
423 return self
.GetParent()._start
+ self
._start
425 def GetLineByOffset(self
, offset
):
426 sect_start
= self
._parent
.GetStartLinenumber()
427 linenumber
= sect_start
+ offset
428 return self
._parent
.GetLine(linenumber
)
430 def GetLinenumberByOffset(self
, offset
):
431 return offset
+ self
._parent
.GetStartLinenumber()
440 return self
.GetLineByOffset(self
._start
).strip()
442 def GenerateLines(self
):
443 return ['default setion object string\n']
445 def GetComment(self
):
447 start
= self
.GetStartLinenumber() - 1
451 line
= self
.GetParent().GetLine(start
).strip()
455 if line
.startswith('##'):
457 index
= line
.rfind('#')
458 if (index
+ 1) < len(line
):
459 comments
.append(line
[index
+ 1:])
461 if line
.startswith('#'):
467 while (end
<= self
.GetStartLinenumber() - 1):
468 line
= self
.GetParent().GetLine(end
).strip()
469 if len(line
) == 0: break
470 if not line
.startswith('#'): break
471 index
= line
.rfind('#')
472 if (index
+ 1) < len(line
):
473 comments
.append(line
[index
+ 1:])