# parse FDF file\r
#\r
# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2015, Hewlett Packard Enterprise Development, L.P.<BR>\r
#\r
# This program and the accompanying materials\r
# are licensed and made available under the terms and conditions of the BSD License\r
RegionOffsetPcdPattern = re.compile("\s*(?P<base>\w+\.\w+)\s*$")\r
ShortcutPcdPattern = re.compile("\s*\w+\s*=\s*(?P<value>(?:0x|0X)?[a-fA-F0-9]+)\s*\|\s*(?P<name>\w+\.\w+)\s*")\r
\r
-IncludeFileList = []\r
+AllIncludeFileList = []\r
+\r
+# Get the closest parent\r
+def GetParentAtLine (Line):\r
+ for Profile in AllIncludeFileList:\r
+ if Profile.IsLineInFile(Line):\r
+ return Profile\r
+ return None\r
+\r
+# Check include loop\r
+def IsValidInclude (File, Line):\r
+ for Profile in AllIncludeFileList:\r
+ if Profile.IsLineInFile(Line) and Profile.FileName == File:\r
+ return False\r
+\r
+ return True\r
\r
def GetRealFileLine (File, Line):\r
\r
InsertedLines = 0\r
- for Profile in IncludeFileList:\r
- if Line >= Profile.InsertStartLineNumber and Line < Profile.InsertStartLineNumber + Profile.InsertAdjust + len(Profile.FileLinesList):\r
- return (Profile.FileName, Line - Profile.InsertStartLineNumber + 1)\r
- if Line >= Profile.InsertStartLineNumber + Profile.InsertAdjust + len(Profile.FileLinesList):\r
- InsertedLines += Profile.InsertAdjust + len(Profile.FileLinesList)\r
+ for Profile in AllIncludeFileList:\r
+ if Profile.IsLineInFile(Line):\r
+ return Profile.GetLineInFile(Line)\r
+ elif Line >= Profile.InsertStartLineNumber and Profile.Level == 1:\r
+ InsertedLines += Profile.GetTotalLines()\r
\r
return (File, Line - InsertedLines)\r
\r
FileLineTuple = GetRealFileLine(File, Line)\r
self.FileName = FileLineTuple[0]\r
self.LineNumber = FileLineTuple[1]\r
+ self.OriginalLineNumber = Line\r
self.Message = Str\r
self.ToolName = 'FdfParser'\r
\r
\r
self.InsertStartLineNumber = None\r
self.InsertAdjust = 0\r
+ self.IncludeFileList = []\r
+ self.Level = 1 # first level include file\r
+ \r
+ def GetTotalLines(self):\r
+ TotalLines = self.InsertAdjust + len(self.FileLinesList)\r
+\r
+ for Profile in self.IncludeFileList:\r
+ TotalLines += Profile.GetTotalLines()\r
+\r
+ return TotalLines\r
+\r
+ def IsLineInFile(self, Line):\r
+ if Line >= self.InsertStartLineNumber and Line < self.InsertStartLineNumber + self.GetTotalLines():\r
+ return True\r
+\r
+ return False\r
+\r
+ def GetLineInFile(self, Line):\r
+ if not self.IsLineInFile (Line):\r
+ return (self.FileName, -1)\r
+ \r
+ InsertedLines = self.InsertStartLineNumber\r
+\r
+ for Profile in self.IncludeFileList:\r
+ if Profile.IsLineInFile(Line):\r
+ return Profile.GetLineInFile(Line)\r
+ elif Line >= Profile.InsertStartLineNumber:\r
+ InsertedLines += Profile.GetTotalLines()\r
+\r
+ return (self.FileName, Line - InsertedLines + 1)\r
+\r
+\r
\r
## The FDF content class that used to record file data when parsing FDF\r
#\r
# Reset file data buffer to the initial state\r
#\r
# @param self The object pointer\r
+ # @param DestLine Optional new destination line number.\r
+ # @param DestOffset Optional new destination offset. \r
#\r
- def Rewind(self):\r
- self.CurrentLineNumber = 1\r
- self.CurrentOffsetWithinLine = 0\r
+ def Rewind(self, DestLine = 1, DestOffset = 0): \r
+ self.CurrentLineNumber = DestLine \r
+ self.CurrentOffsetWithinLine = DestOffset \r
\r
## __UndoOneChar() method\r
#\r
# @param self The object pointer\r
#\r
def PreprocessIncludeFile(self):\r
-\r
+ # nested include support\r
+ Processed = False\r
while self.__GetNextToken():\r
\r
if self.__Token == '!include':\r
+ Processed = True\r
IncludeLine = self.CurrentLineNumber\r
IncludeOffset = self.CurrentOffsetWithinLine - len('!include')\r
if not self.__GetNextToken():\r
raise Warning("The include file does not exist under below directories: \n%s\n%s\n%s\n"%(os.path.dirname(self.FileName), PlatformDir, GlobalData.gWorkspace), \r
self.FileName, self.CurrentLineNumber)\r
\r
+ if not IsValidInclude (IncludedFile1.Path, self.CurrentLineNumber):\r
+ raise Warning("The include file {0} is causing a include loop.\n".format (IncludedFile1.Path), self.FileName, self.CurrentLineNumber)\r
+\r
IncFileProfile = IncludeFileProfile(IncludedFile1.Path)\r
\r
CurrentLine = self.CurrentLineNumber\r
CurrentOffset = self.CurrentOffsetWithinLine\r
# list index of the insertion, note that line number is 'CurrentLine + 1'\r
InsertAtLine = CurrentLine\r
+ ParentProfile = GetParentAtLine (CurrentLine)\r
+ if ParentProfile != None:\r
+ ParentProfile.IncludeFileList.insert(0, IncFileProfile)\r
+ IncFileProfile.Level = ParentProfile.Level + 1\r
IncFileProfile.InsertStartLineNumber = InsertAtLine + 1\r
# deal with remaining portions after "!include filename", if exists.\r
if self.__GetNextToken():\r
self.CurrentLineNumber += 1\r
InsertAtLine += 1\r
\r
- IncludeFileList.append(IncFileProfile)\r
+ # reversely sorted to better determine error in file\r
+ AllIncludeFileList.insert(0, IncFileProfile)\r
\r
# comment out the processed include file statement\r
TempList = list(self.Profile.FileLinesList[IncludeLine - 1])\r
TempList.insert(IncludeOffset, '#')\r
self.Profile.FileLinesList[IncludeLine - 1] = ''.join(TempList)\r
-\r
+ if Processed: # Nested and back-to-back support\r
+ self.Rewind(DestLine = IncFileProfile.InsertStartLineNumber - 1)\r
+ Processed = False\r
+ # Preprocess done.\r
self.Rewind()\r
\r
def __GetIfListCurrentItemStat(self, IfList):\r
\r
except Warning, X:\r
self.__UndoToken()\r
- FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber)\r
#'\n\tGot Token: \"%s\" from File %s\n' % (self.__Token, FileLineTuple[0]) + \\r
- X.Message += ' near line %d, column %d: %s' \\r
+ # At this point, the closest parent would be the included file itself\r
+ Profile = GetParentAtLine(X.OriginalLineNumber)\r
+ if Profile != None:\r
+ X.Message += ' near line %d, column %d: %s' \\r
+ % (X.LineNumber, 0, Profile.FileLinesList[X.LineNumber-1])\r
+ else:\r
+ FileLineTuple = GetRealFileLine(self.FileName, self.CurrentLineNumber)\r
+ X.Message += ' near line %d, column %d: %s' \\r
% (FileLineTuple[1], self.CurrentOffsetWithinLine + 1, self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine :].rstrip('\n').rstrip('\r'))\r
raise\r
\r
# This file is used to parse meta files\r
#\r
# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2015, Hewlett Packard Enterprise Development, L.P.<BR>\r
# This program and the accompanying materials\r
# are licensed and made available under the terms and conditions of the BSD License\r
# which accompanies this distribution. The full text of the license may be found at\r
File=self.MetaFile, Line=self._LineIndex + 1,\r
ExtraData=self._CurrentLine)\r
self._DirectiveStack.append((ItemType, self._LineIndex + 1, self._CurrentLine))\r
- elif self._From > 0:\r
- EdkLogger.error('Parser', FORMAT_INVALID,\r
- "No '!include' allowed in included file",\r
- ExtraData=self._CurrentLine, File=self.MetaFile,\r
- Line=self._LineIndex + 1)\r
\r
#\r
# Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,\r
Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,\r
Owner=Owner, From=Owner)\r
\r
+ # Does not allow lower level included file to include upper level included file\r
+ if Parser._From != Owner and int(Owner) > int (Parser._From):\r
+ EdkLogger.error('parser', FILE_ALREADY_EXIST, File=self._FileWithError,\r
+ Line=self._LineIndex + 1, ExtraData="{0} is already included at a higher level.".format(IncludedFile1))\r
+\r
+\r
# set the parser status with current status\r
Parser._SectionName = self._SectionName\r
Parser._SectionType = self._SectionType\r