1## @file
2#
3# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
4#
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8from plugins.EdkPlugins.basemodel import ini
9import re, os
10from plugins.EdkPlugins.basemodel.message import *
11
12class INFFile(ini.BaseINIFile):
13    _libobjs = {}
14
15    def GetSectionInstance(self, parent, name, isCombined=False):
16        return INFSection(parent, name, isCombined)
17
18    def GetProduceLibraryClass(self):
19        obj = self.GetDefine("LIBRARY_CLASS")
20        if obj is None: return None
21
22        return obj.split('|')[0].strip()
23
24    def GetSectionObjectsByName(self, name, arch=None):
25        arr = []
26        sects = self.GetSectionByName(name)
27        for sect in sects:
28            # skip unmatched archtecture content
29            if not sect.IsArchMatch(arch):
30                continue
31
32            for obj in sect.GetObjects():
33                arr.append(obj)
34
35        return arr
36
37    def GetSourceObjects(self, arch=None, tool=None):
38        arr = []
39        sects = self.GetSectionByName('sources')
40        for sect in sects:
41            # skip unmatched archtecture content
42            if not sect.IsArchMatch(arch):
43                continue
44
45            for obj in sect.GetObjects():
46                if not obj.IsMatchFamily(tool):
47                    continue
48                arr.append(obj)
49
50        return arr
51
52    def Parse(self):
53        if not ini.BaseINIFile.Parse(self):
54            return False
55        classname = self.GetProduceLibraryClass()
56        if classname is not None:
57            libobjdict = INFFile._libobjs
58            if classname in libobjdict:
59                if self not in libobjdict[classname]:
60                    libobjdict[classname].append(self)
61            else:
62                libobjdict[classname] = [self]
63
64        return True
65
66    def GetBaseName(self):
67        return self.GetDefine("BASE_NAME").strip()
68
69    def GetModuleRootPath(self):
70        return os.path.dirname(self.GetFilename())
71
72    def Clear(self):
73        classname = self.GetProduceLibraryClass()
74        if classname is not None:
75            libobjdict = INFFile._libobjs
76            libobjdict[classname].remove(self)
77            if len(libobjdict[classname]) == 0:
78                del libobjdict[classname]
79        ini.BaseINIFile.Clear(self)
80
81
82class INFSection(ini.BaseINISection):
83    def GetSectionINIObject(self, parent):
84        type = self.GetType()
85
86        if type.lower() == 'libraryclasses':
87            return INFLibraryClassObject(self)
88        if type.lower() == 'sources':
89            return INFSourceObject(self)
90        if type.lower().find('pcd') != -1:
91            return INFPcdObject(self)
92        if type.lower() == 'packages':
93            return INFDependentPackageObject(self)
94        if type.lower() in ['guids', 'protocols', 'ppis']:
95            return INFGuidObject(self)
96        if type.lower() == 'defines':
97            return INFDefineSectionObject(self)
98        return INFSectionObject(self)
99
100    def GetType(self):
101        arr = self._name.split('.')
102        return arr[0].strip()
103
104    def GetArch(self):
105        arr = self._name.split('.')
106        if len(arr) == 1:
107            return 'common'
108        return arr[1]
109
110    def IsArchMatch(self, arch):
111        if arch is None or self.GetArch() == 'common':
112            return True
113
114        if self.GetArch().lower() != arch.lower():
115            return False
116
117        return True
118
119class INFSectionObject(ini.BaseINISectionObject):
120    def GetArch(self):
121        return self.GetParent().GetArch()
122
123class INFDefineSectionObject(INFSectionObject):
124    def __init__(self, parent):
125        INFSectionObject.__init__(self, parent)
126        self._key = None
127        self._value = None
128
129    def Parse(self):
130        assert (self._start == self._end), 'The object in define section must be in single line'
131
132        line = self.GetLineByOffset(self._start).strip()
133
134        line = line.split('#')[0]
135        arr  = line.split('=')
136        if len(arr) != 2:
137            ErrorMsg('Invalid define section object',
138                   self.GetFilename(),
139                   self._start
140                   )
141            return False
142
143        self._key   = arr[0].strip()
144        self._value = arr[1].strip()
145
146        return True
147
148    def GetKey(self):
149        return self._key
150
151    def GetValue(self):
152        return self._value
153
154class INFLibraryClassObject(INFSectionObject):
155    _objs = {}
156    def __init__(self, parent):
157        INFSectionObject.__init__(self, parent)
158        self._classname = None
159
160    def GetClass(self):
161        return self._classname
162
163    def Parse(self):
164        self._classname = self.GetLineByOffset(self._start).split('#')[0].strip()
165        objdict = INFLibraryClassObject._objs
166        if self._classname in objdict:
167            objdict[self._classname].append(self)
168        else:
169            objdict[self._classname] = [self]
170        return True
171
172    def Destroy(self):
173        objdict = INFLibraryClassObject._objs
174        objdict[self._classname].remove(self)
175        if len(objdict[self._classname]) == 0:
176            del objdict[self._classname]
177
178    def GetName(self):
179        return self._classname
180
181    @staticmethod
182    def GetObjectDict():
183        return INFLibraryClassObject._objs
184
185class INFDependentPackageObject(INFSectionObject):
186    def GetPath(self):
187        return self.GetLineByOffset(self._start).split('#')[0].strip()
188
189class INFSourceObject(INFSectionObject):
190    _objs = {}
191    def __init__(self, parent):
192        INFSectionObject.__init__(self, parent)
193
194        self.mSourcename  = None
195        self.mToolCode    = None
196        self.mFamily      = None
197        self.mTagName     = None
198        self.mFeaturePcd  = None
199        self.mFilename    = None
200
201    def GetSourcePath(self):
202        return self.mSourcename
203
204    def GetSourceFullPath(self):
205        path = os.path.dirname(self.GetFilename())
206        path = os.path.join(path, self.GetSourcePath())
207        return os.path.normpath(path)
208
209    def GetToolCode(self):
210        return self.mToolCode
211
212    def GetFamily(self):
213        return self.mFamily
214
215    def GetTagName(self):
216        return self.mTagName
217
218    def GetFeaturePcd(self):
219        return self.mFeaturePcd
220
221    def Parse(self):
222        line = self.GetLineByOffset(self._start).strip().split('#')[0]
223
224        arr = line.split('|')
225
226        self.mSourcename = arr[0].strip()
227        if len(arr) >= 2:
228            self.mFamily = arr[1].strip()
229        if len(arr) >= 3:
230            self.mTagName = arr[2].strip()
231        if len(arr) >= 4:
232            self.mToolCode = arr[3].strip()
233        if len(arr) >= 5:
234            self.mFeaturePcd = arr[4].strip()
235
236        self.mFilename = os.path.basename(self.GetSourceFullPath())
237        objdict = INFSourceObject._objs
238        if self.mFilename not in objdict:
239            objdict[self.mFilename] = [self]
240        else:
241            objdict[self.mFilename].append(self)
242
243        return True
244
245    def GetName(self):
246        return self.mFilename
247
248    def Destroy(self):
249        objdict = INFSourceObject._objs
250        objdict[self.mFilename].remove(self)
251        if len(objdict[self.mFilename]) == 0:
252            del objdict[self.mFilename]
253
254    def IsMatchFamily(self, family):
255        if family is None:
256            return True
257        if self.mFamily is not None:
258            if family.strip().lower() == self.mFamily.lower():
259                return True
260            else:
261                return False
262        else:
263            fname = self.GetSourcePath()
264            if fname.endswith('.S') and family.lower() != 'gcc':
265                return False
266            if fname.endswith('.s') and (self.GetArch().lower() != 'ipf' and self.GetArch().lower() != 'common'):
267                return False
268            if fname.lower().endswith('.asm') and (family.lower() != 'msft' and family.lower() != 'intel'):
269                return False
270        return True
271
272    @staticmethod
273    def GetObjectDict():
274        return INFSourceObject._objs
275
276class INFPcdObject(INFSectionObject):
277    _objs = {}
278
279    def __init__(self, parent):
280        INFSectionObject.__init__(self, parent)
281
282        self.mPcdType      = None
283        self.mDefaultValue = None
284        self.mPcdName      = None
285
286    @staticmethod
287    def GetObjectDict():
288        return INFPcdObject._objs
289
290    def Parse(self):
291        line = self.GetLineByOffset(self._start).strip().split('#')[0]
292
293        arr = line.split('|')
294        self.mPcdName       = arr[0].strip()
295
296        if len(arr) >= 2:
297            self.mDefaultValue = arr[1].strip()
298
299        objdict = INFPcdObject._objs
300        if self.GetName() in objdict:
301            if self not in objdict[self.GetName()]:
302                objdict[self.GetName()].append(self)
303        else:
304            objdict[self.GetName()] = [self]
305        return True
306
307    def GetPcdName(self):
308        return self.mPcdName
309
310    def GetPcdType(self):
311        return self.GetParent().GetType()
312
313    def GetName(self):
314        return self.mPcdName.split('.')[1]
315
316    def Destroy(self):
317        objdict = INFPcdObject._objs
318        objdict[self.GetName()].remove(self)
319        if len(objdict[self.GetName()]) == 0:
320            del objdict[self.GetName()]
321
322class INFGuidObject(INFSectionObject):
323    def __init__(self, parent):
324        INFSectionObject.__init__(self, parent)
325        self._name = None
326
327    def Parse(self):
328        line = self.GetLineByOffset(self._start).strip().split('#')[0].split("|")[0]
329        self._name =  line.strip()
330        return True
331
332    def GetName(self):
333        return self._name
334
335
336