]>
Commit | Line | Data |
---|---|---|
1 | ## @file\r | |
2 | # This file is used to define comment parsing interface\r | |
3 | #\r | |
4 | # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r | |
5 | #\r | |
6 | # SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
7 | #\r | |
8 | \r | |
9 | '''\r | |
10 | CommentParsing\r | |
11 | '''\r | |
12 | \r | |
13 | ##\r | |
14 | # Import Modules\r | |
15 | #\r | |
16 | import re\r | |
17 | \r | |
18 | from Library.StringUtils import GetSplitValueList\r | |
19 | from Library.StringUtils import CleanString2\r | |
20 | from Library.DataType import HEADER_COMMENT_NOT_STARTED\r | |
21 | from Library.DataType import TAB_COMMENT_SPLIT\r | |
22 | from Library.DataType import HEADER_COMMENT_LICENSE\r | |
23 | from Library.DataType import HEADER_COMMENT_ABSTRACT\r | |
24 | from Library.DataType import HEADER_COMMENT_COPYRIGHT\r | |
25 | from Library.DataType import HEADER_COMMENT_DESCRIPTION\r | |
26 | from Library.DataType import TAB_SPACE_SPLIT\r | |
27 | from Library.DataType import TAB_COMMA_SPLIT\r | |
28 | from Library.DataType import SUP_MODULE_LIST\r | |
29 | from Library.DataType import TAB_VALUE_SPLIT\r | |
30 | from Library.DataType import TAB_PCD_VALIDRANGE\r | |
31 | from Library.DataType import TAB_PCD_VALIDLIST\r | |
32 | from Library.DataType import TAB_PCD_EXPRESSION\r | |
33 | from Library.DataType import TAB_PCD_PROMPT\r | |
34 | from Library.DataType import TAB_CAPHEX_START\r | |
35 | from Library.DataType import TAB_HEX_START\r | |
36 | from Library.DataType import PCD_ERR_CODE_MAX_SIZE\r | |
37 | from Library.ExpressionValidate import IsValidRangeExpr\r | |
38 | from Library.ExpressionValidate import IsValidListExpr\r | |
39 | from Library.ExpressionValidate import IsValidLogicalExpr\r | |
40 | from Object.POM.CommonObject import TextObject\r | |
41 | from Object.POM.CommonObject import PcdErrorObject\r | |
42 | import Logger.Log as Logger\r | |
43 | from Logger.ToolError import FORMAT_INVALID\r | |
44 | from Logger.ToolError import FORMAT_NOT_SUPPORTED\r | |
45 | from Logger import StringTable as ST\r | |
46 | \r | |
47 | ## ParseHeaderCommentSection\r | |
48 | #\r | |
49 | # Parse Header comment section lines, extract Abstract, Description, Copyright\r | |
50 | # , License lines\r | |
51 | #\r | |
52 | # @param CommentList: List of (Comment, LineNumber)\r | |
53 | # @param FileName: FileName of the comment\r | |
54 | #\r | |
55 | def ParseHeaderCommentSection(CommentList, FileName = None, IsBinaryHeader = False):\r | |
56 | Abstract = ''\r | |
57 | Description = ''\r | |
58 | Copyright = ''\r | |
59 | License = ''\r | |
60 | EndOfLine = "\n"\r | |
61 | if IsBinaryHeader:\r | |
62 | STR_HEADER_COMMENT_START = "@BinaryHeader"\r | |
63 | else:\r | |
64 | STR_HEADER_COMMENT_START = "@file"\r | |
65 | HeaderCommentStage = HEADER_COMMENT_NOT_STARTED\r | |
66 | \r | |
67 | #\r | |
68 | # first find the last copyright line\r | |
69 | #\r | |
70 | Last = 0\r | |
71 | for Index in range(len(CommentList)-1, 0, -1):\r | |
72 | Line = CommentList[Index][0]\r | |
73 | if _IsCopyrightLine(Line):\r | |
74 | Last = Index\r | |
75 | break\r | |
76 | \r | |
77 | for Item in CommentList:\r | |
78 | Line = Item[0]\r | |
79 | LineNo = Item[1]\r | |
80 | \r | |
81 | if not Line.startswith(TAB_COMMENT_SPLIT) and Line:\r | |
82 | Logger.Error("\nUPT", FORMAT_INVALID, ST.ERR_INVALID_COMMENT_FORMAT, FileName, Item[1])\r | |
83 | Comment = CleanString2(Line)[1]\r | |
84 | Comment = Comment.strip()\r | |
85 | #\r | |
86 | # if there are blank lines between License or Description, keep them as they would be\r | |
87 | # indication of different block; or in the position that Abstract should be, also keep it\r | |
88 | # as it indicates that no abstract\r | |
89 | #\r | |
90 | if not Comment and HeaderCommentStage not in [HEADER_COMMENT_LICENSE, \\r | |
91 | HEADER_COMMENT_DESCRIPTION, HEADER_COMMENT_ABSTRACT]:\r | |
92 | continue\r | |
93 | \r | |
94 | if HeaderCommentStage == HEADER_COMMENT_NOT_STARTED:\r | |
95 | if Comment.startswith(STR_HEADER_COMMENT_START):\r | |
96 | HeaderCommentStage = HEADER_COMMENT_ABSTRACT\r | |
97 | else:\r | |
98 | License += Comment + EndOfLine\r | |
99 | else:\r | |
100 | if HeaderCommentStage == HEADER_COMMENT_ABSTRACT:\r | |
101 | #\r | |
102 | # in case there is no abstract and description\r | |
103 | #\r | |
104 | if not Comment:\r | |
105 | HeaderCommentStage = HEADER_COMMENT_DESCRIPTION\r | |
106 | elif _IsCopyrightLine(Comment):\r | |
107 | Result, ErrMsg = _ValidateCopyright(Comment)\r | |
108 | ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)\r | |
109 | Copyright += Comment + EndOfLine\r | |
110 | HeaderCommentStage = HEADER_COMMENT_COPYRIGHT\r | |
111 | else:\r | |
112 | Abstract += Comment + EndOfLine\r | |
113 | HeaderCommentStage = HEADER_COMMENT_DESCRIPTION\r | |
114 | elif HeaderCommentStage == HEADER_COMMENT_DESCRIPTION:\r | |
115 | #\r | |
116 | # in case there is no description\r | |
117 | #\r | |
118 | if _IsCopyrightLine(Comment):\r | |
119 | Result, ErrMsg = _ValidateCopyright(Comment)\r | |
120 | ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)\r | |
121 | Copyright += Comment + EndOfLine\r | |
122 | HeaderCommentStage = HEADER_COMMENT_COPYRIGHT\r | |
123 | else:\r | |
124 | Description += Comment + EndOfLine\r | |
125 | elif HeaderCommentStage == HEADER_COMMENT_COPYRIGHT:\r | |
126 | if _IsCopyrightLine(Comment):\r | |
127 | Result, ErrMsg = _ValidateCopyright(Comment)\r | |
128 | ValidateCopyright(Result, ST.WRN_INVALID_COPYRIGHT, FileName, LineNo, ErrMsg)\r | |
129 | Copyright += Comment + EndOfLine\r | |
130 | else:\r | |
131 | #\r | |
132 | # Contents after copyright line are license, those non-copyright lines in between\r | |
133 | # copyright line will be discarded\r | |
134 | #\r | |
135 | if LineNo > Last:\r | |
136 | if License:\r | |
137 | License += EndOfLine\r | |
138 | License += Comment + EndOfLine\r | |
139 | HeaderCommentStage = HEADER_COMMENT_LICENSE\r | |
140 | else:\r | |
141 | if not Comment and not License:\r | |
142 | continue\r | |
143 | License += Comment + EndOfLine\r | |
144 | \r | |
145 | return Abstract.strip(), Description.strip(), Copyright.strip(), License.strip()\r | |
146 | \r | |
147 | ## _IsCopyrightLine\r | |
148 | # check whether current line is copyright line, the criteria is whether there is case insensitive keyword "Copyright"\r | |
149 | # followed by zero or more white space characters followed by a "(" character\r | |
150 | #\r | |
151 | # @param LineContent: the line need to be checked\r | |
152 | # @return: True if current line is copyright line, False else\r | |
153 | #\r | |
154 | def _IsCopyrightLine (LineContent):\r | |
155 | LineContent = LineContent.upper()\r | |
156 | Result = False\r | |
157 | \r | |
158 | ReIsCopyrightRe = re.compile(r"""(^|\s)COPYRIGHT *\(""", re.DOTALL)\r | |
159 | if ReIsCopyrightRe.search(LineContent):\r | |
160 | Result = True\r | |
161 | \r | |
162 | return Result\r | |
163 | \r | |
164 | ## ParseGenericComment\r | |
165 | #\r | |
166 | # @param GenericComment: Generic comment list, element of\r | |
167 | # (CommentLine, LineNum)\r | |
168 | # @param ContainerFile: Input value for filename of Dec file\r | |
169 | #\r | |
170 | def ParseGenericComment (GenericComment, ContainerFile=None, SkipTag=None):\r | |
171 | if ContainerFile:\r | |
172 | pass\r | |
173 | HelpTxt = None\r | |
174 | HelpStr = ''\r | |
175 | \r | |
176 | for Item in GenericComment:\r | |
177 | CommentLine = Item[0]\r | |
178 | Comment = CleanString2(CommentLine)[1]\r | |
179 | if SkipTag is not None and Comment.startswith(SkipTag):\r | |
180 | Comment = Comment.replace(SkipTag, '', 1)\r | |
181 | HelpStr += Comment + '\n'\r | |
182 | \r | |
183 | if HelpStr:\r | |
184 | HelpTxt = TextObject()\r | |
185 | if HelpStr.endswith('\n') and not HelpStr.endswith('\n\n') and HelpStr != '\n':\r | |
186 | HelpStr = HelpStr[:-1]\r | |
187 | HelpTxt.SetString(HelpStr)\r | |
188 | \r | |
189 | return HelpTxt\r | |
190 | \r | |
191 | ## ParsePcdErrorCode\r | |
192 | #\r | |
193 | # @param Value: original ErrorCode value\r | |
194 | # @param ContainerFile: Input value for filename of Dec file\r | |
195 | # @param LineNum: Line Num\r | |
196 | #\r | |
197 | def ParsePcdErrorCode (Value = None, ContainerFile = None, LineNum = None):\r | |
198 | try:\r | |
199 | if Value.strip().startswith((TAB_HEX_START, TAB_CAPHEX_START)):\r | |
200 | Base = 16\r | |
201 | else:\r | |
202 | Base = 10\r | |
203 | ErrorCode = int(Value, Base)\r | |
204 | if ErrorCode > PCD_ERR_CODE_MAX_SIZE or ErrorCode < 0:\r | |
205 | Logger.Error('Parser',\r | |
206 | FORMAT_NOT_SUPPORTED,\r | |
207 | "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value,\r | |
208 | File = ContainerFile,\r | |
209 | Line = LineNum)\r | |
210 | ErrorCode = '0x%x' % ErrorCode\r | |
211 | return ErrorCode\r | |
212 | except ValueError as XStr:\r | |
213 | if XStr:\r | |
214 | pass\r | |
215 | Logger.Error('Parser',\r | |
216 | FORMAT_NOT_SUPPORTED,\r | |
217 | "The format %s of ErrorCode is not valid, should be UNIT32 type or long type" % Value,\r | |
218 | File = ContainerFile,\r | |
219 | Line = LineNum)\r | |
220 | \r | |
221 | ## ParseDecPcdGenericComment\r | |
222 | #\r | |
223 | # @param GenericComment: Generic comment list, element of (CommentLine,\r | |
224 | # LineNum)\r | |
225 | # @param ContainerFile: Input value for filename of Dec file\r | |
226 | #\r | |
227 | def ParseDecPcdGenericComment (GenericComment, ContainerFile, TokenSpaceGuidCName, CName, MacroReplaceDict):\r | |
228 | HelpStr = ''\r | |
229 | PromptStr = ''\r | |
230 | PcdErr = None\r | |
231 | PcdErrList = []\r | |
232 | ValidValueNum = 0\r | |
233 | ValidRangeNum = 0\r | |
234 | ExpressionNum = 0\r | |
235 | \r | |
236 | for (CommentLine, LineNum) in GenericComment:\r | |
237 | Comment = CleanString2(CommentLine)[1]\r | |
238 | #\r | |
239 | # To replace Macro\r | |
240 | #\r | |
241 | MACRO_PATTERN = '[\t\s]*\$\([A-Z][_A-Z0-9]*\)'\r | |
242 | MatchedStrs = re.findall(MACRO_PATTERN, Comment)\r | |
243 | for MatchedStr in MatchedStrs:\r | |
244 | if MatchedStr:\r | |
245 | Macro = MatchedStr.strip().lstrip('$(').rstrip(')').strip()\r | |
246 | if Macro in MacroReplaceDict:\r | |
247 | Comment = Comment.replace(MatchedStr, MacroReplaceDict[Macro])\r | |
248 | if Comment.startswith(TAB_PCD_VALIDRANGE):\r | |
249 | if ValidValueNum > 0 or ExpressionNum > 0:\r | |
250 | Logger.Error('Parser',\r | |
251 | FORMAT_NOT_SUPPORTED,\r | |
252 | ST.WRN_MULTI_PCD_RANGES,\r | |
253 | File = ContainerFile,\r | |
254 | Line = LineNum)\r | |
255 | else:\r | |
256 | PcdErr = PcdErrorObject()\r | |
257 | PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)\r | |
258 | PcdErr.SetCName(CName)\r | |
259 | PcdErr.SetFileLine(Comment)\r | |
260 | PcdErr.SetLineNum(LineNum)\r | |
261 | ValidRangeNum += 1\r | |
262 | ValidRange = Comment.replace(TAB_PCD_VALIDRANGE, "", 1).strip()\r | |
263 | Valid, Cause = _CheckRangeExpression(ValidRange)\r | |
264 | if Valid:\r | |
265 | ValueList = ValidRange.split(TAB_VALUE_SPLIT)\r | |
266 | if len(ValueList) > 1:\r | |
267 | PcdErr.SetValidValueRange((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())\r | |
268 | PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))\r | |
269 | else:\r | |
270 | PcdErr.SetValidValueRange(ValidRange)\r | |
271 | PcdErrList.append(PcdErr)\r | |
272 | else:\r | |
273 | Logger.Error("Parser",\r | |
274 | FORMAT_NOT_SUPPORTED,\r | |
275 | Cause,\r | |
276 | ContainerFile,\r | |
277 | LineNum)\r | |
278 | elif Comment.startswith(TAB_PCD_VALIDLIST):\r | |
279 | if ValidRangeNum > 0 or ExpressionNum > 0:\r | |
280 | Logger.Error('Parser',\r | |
281 | FORMAT_NOT_SUPPORTED,\r | |
282 | ST.WRN_MULTI_PCD_RANGES,\r | |
283 | File = ContainerFile,\r | |
284 | Line = LineNum)\r | |
285 | elif ValidValueNum > 0:\r | |
286 | Logger.Error('Parser',\r | |
287 | FORMAT_NOT_SUPPORTED,\r | |
288 | ST.WRN_MULTI_PCD_VALIDVALUE,\r | |
289 | File = ContainerFile,\r | |
290 | Line = LineNum)\r | |
291 | else:\r | |
292 | PcdErr = PcdErrorObject()\r | |
293 | PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)\r | |
294 | PcdErr.SetCName(CName)\r | |
295 | PcdErr.SetFileLine(Comment)\r | |
296 | PcdErr.SetLineNum(LineNum)\r | |
297 | ValidValueNum += 1\r | |
298 | ValidValueExpr = Comment.replace(TAB_PCD_VALIDLIST, "", 1).strip()\r | |
299 | Valid, Cause = _CheckListExpression(ValidValueExpr)\r | |
300 | if Valid:\r | |
301 | ValidValue = Comment.replace(TAB_PCD_VALIDLIST, "", 1).replace(TAB_COMMA_SPLIT, TAB_SPACE_SPLIT)\r | |
302 | ValueList = ValidValue.split(TAB_VALUE_SPLIT)\r | |
303 | if len(ValueList) > 1:\r | |
304 | PcdErr.SetValidValue((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())\r | |
305 | PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))\r | |
306 | else:\r | |
307 | PcdErr.SetValidValue(ValidValue)\r | |
308 | PcdErrList.append(PcdErr)\r | |
309 | else:\r | |
310 | Logger.Error("Parser",\r | |
311 | FORMAT_NOT_SUPPORTED,\r | |
312 | Cause,\r | |
313 | ContainerFile,\r | |
314 | LineNum)\r | |
315 | elif Comment.startswith(TAB_PCD_EXPRESSION):\r | |
316 | if ValidRangeNum > 0 or ValidValueNum > 0:\r | |
317 | Logger.Error('Parser',\r | |
318 | FORMAT_NOT_SUPPORTED,\r | |
319 | ST.WRN_MULTI_PCD_RANGES,\r | |
320 | File = ContainerFile,\r | |
321 | Line = LineNum)\r | |
322 | else:\r | |
323 | PcdErr = PcdErrorObject()\r | |
324 | PcdErr.SetTokenSpaceGuidCName(TokenSpaceGuidCName)\r | |
325 | PcdErr.SetCName(CName)\r | |
326 | PcdErr.SetFileLine(Comment)\r | |
327 | PcdErr.SetLineNum(LineNum)\r | |
328 | ExpressionNum += 1\r | |
329 | Expression = Comment.replace(TAB_PCD_EXPRESSION, "", 1).strip()\r | |
330 | Valid, Cause = _CheckExpression(Expression)\r | |
331 | if Valid:\r | |
332 | ValueList = Expression.split(TAB_VALUE_SPLIT)\r | |
333 | if len(ValueList) > 1:\r | |
334 | PcdErr.SetExpression((TAB_VALUE_SPLIT.join(ValueList[1:])).strip())\r | |
335 | PcdErr.SetErrorNumber(ParsePcdErrorCode(ValueList[0], ContainerFile, LineNum))\r | |
336 | else:\r | |
337 | PcdErr.SetExpression(Expression)\r | |
338 | PcdErrList.append(PcdErr)\r | |
339 | else:\r | |
340 | Logger.Error("Parser",\r | |
341 | FORMAT_NOT_SUPPORTED,\r | |
342 | Cause,\r | |
343 | ContainerFile,\r | |
344 | LineNum)\r | |
345 | elif Comment.startswith(TAB_PCD_PROMPT):\r | |
346 | if PromptStr:\r | |
347 | Logger.Error('Parser',\r | |
348 | FORMAT_NOT_SUPPORTED,\r | |
349 | ST.WRN_MULTI_PCD_PROMPT,\r | |
350 | File = ContainerFile,\r | |
351 | Line = LineNum)\r | |
352 | PromptStr = Comment.replace(TAB_PCD_PROMPT, "", 1).strip()\r | |
353 | else:\r | |
354 | if Comment:\r | |
355 | HelpStr += Comment + '\n'\r | |
356 | \r | |
357 | #\r | |
358 | # remove the last EOL if the comment is of format 'FOO\n'\r | |
359 | #\r | |
360 | if HelpStr.endswith('\n'):\r | |
361 | if HelpStr != '\n' and not HelpStr.endswith('\n\n'):\r | |
362 | HelpStr = HelpStr[:-1]\r | |
363 | \r | |
364 | return HelpStr, PcdErrList, PromptStr\r | |
365 | \r | |
366 | ## ParseDecPcdTailComment\r | |
367 | #\r | |
368 | # @param TailCommentList: Tail comment list of Pcd, item of format (Comment, LineNum)\r | |
369 | # @param ContainerFile: Input value for filename of Dec file\r | |
370 | # @retVal SupModuleList: The supported module type list detected\r | |
371 | # @retVal HelpStr: The generic help text string detected\r | |
372 | #\r | |
373 | def ParseDecPcdTailComment (TailCommentList, ContainerFile):\r | |
374 | assert(len(TailCommentList) == 1)\r | |
375 | TailComment = TailCommentList[0][0]\r | |
376 | LineNum = TailCommentList[0][1]\r | |
377 | \r | |
378 | Comment = TailComment.lstrip(" #")\r | |
379 | \r | |
380 | ReFindFirstWordRe = re.compile(r"""^([^ #]*)""", re.DOTALL)\r | |
381 | \r | |
382 | #\r | |
383 | # get first word and compare with SUP_MODULE_LIST\r | |
384 | #\r | |
385 | MatchObject = ReFindFirstWordRe.match(Comment)\r | |
386 | if not (MatchObject and MatchObject.group(1) in SUP_MODULE_LIST):\r | |
387 | return None, Comment\r | |
388 | \r | |
389 | #\r | |
390 | # parse line, it must have supported module type specified\r | |
391 | #\r | |
392 | if Comment.find(TAB_COMMENT_SPLIT) == -1:\r | |
393 | Comment += TAB_COMMENT_SPLIT\r | |
394 | SupMode, HelpStr = GetSplitValueList(Comment, TAB_COMMENT_SPLIT, 1)\r | |
395 | SupModuleList = []\r | |
396 | for Mod in GetSplitValueList(SupMode, TAB_SPACE_SPLIT):\r | |
397 | if not Mod:\r | |
398 | continue\r | |
399 | elif Mod not in SUP_MODULE_LIST:\r | |
400 | Logger.Error("UPT",\r | |
401 | FORMAT_INVALID,\r | |
402 | ST.WRN_INVALID_MODULE_TYPE%Mod,\r | |
403 | ContainerFile,\r | |
404 | LineNum)\r | |
405 | else:\r | |
406 | SupModuleList.append(Mod)\r | |
407 | \r | |
408 | return SupModuleList, HelpStr\r | |
409 | \r | |
410 | ## _CheckListExpression\r | |
411 | #\r | |
412 | # @param Expression: Pcd value list expression\r | |
413 | #\r | |
414 | def _CheckListExpression(Expression):\r | |
415 | ListExpr = ''\r | |
416 | if TAB_VALUE_SPLIT in Expression:\r | |
417 | ListExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]\r | |
418 | else:\r | |
419 | ListExpr = Expression\r | |
420 | \r | |
421 | return IsValidListExpr(ListExpr)\r | |
422 | \r | |
423 | ## _CheckExpression\r | |
424 | #\r | |
425 | # @param Expression: Pcd value expression\r | |
426 | #\r | |
427 | def _CheckExpression(Expression):\r | |
428 | Expr = ''\r | |
429 | if TAB_VALUE_SPLIT in Expression:\r | |
430 | Expr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]\r | |
431 | else:\r | |
432 | Expr = Expression\r | |
433 | return IsValidLogicalExpr(Expr, True)\r | |
434 | \r | |
435 | ## _CheckRangeExpression\r | |
436 | #\r | |
437 | # @param Expression: Pcd range expression\r | |
438 | #\r | |
439 | def _CheckRangeExpression(Expression):\r | |
440 | RangeExpr = ''\r | |
441 | if TAB_VALUE_SPLIT in Expression:\r | |
442 | RangeExpr = Expression[Expression.find(TAB_VALUE_SPLIT)+1:]\r | |
443 | else:\r | |
444 | RangeExpr = Expression\r | |
445 | \r | |
446 | return IsValidRangeExpr(RangeExpr)\r | |
447 | \r | |
448 | ## ValidateCopyright\r | |
449 | #\r | |
450 | #\r | |
451 | #\r | |
452 | def ValidateCopyright(Result, ErrType, FileName, LineNo, ErrMsg):\r | |
453 | if not Result:\r | |
454 | Logger.Warn("\nUPT", ErrType, FileName, LineNo, ErrMsg)\r | |
455 | \r | |
456 | ## _ValidateCopyright\r | |
457 | #\r | |
458 | # @param Line: Line that contains copyright information, # stripped\r | |
459 | #\r | |
460 | # @retval Result: True if line is conformed to Spec format, False else\r | |
461 | # @retval ErrMsg: the detailed error description\r | |
462 | #\r | |
463 | def _ValidateCopyright(Line):\r | |
464 | if Line:\r | |
465 | pass\r | |
466 | Result = True\r | |
467 | ErrMsg = ''\r | |
468 | \r | |
469 | return Result, ErrMsg\r | |
470 | \r | |
471 | def GenerateTokenList (Comment):\r | |
472 | #\r | |
473 | # Tokenize Comment using '#' and ' ' as token separators\r | |
474 | #\r | |
475 | ReplacedComment = None\r | |
476 | while Comment != ReplacedComment:\r | |
477 | ReplacedComment = Comment\r | |
478 | Comment = Comment.replace('##', '#').replace(' ', ' ').replace(' ', '#').strip('# ')\r | |
479 | return Comment.split('#')\r | |
480 | \r | |
481 | \r | |
482 | #\r | |
483 | # Comment - Comment to parse\r | |
484 | # TypeTokens - A dictionary of type token synonyms\r | |
485 | # RemoveTokens - A list of tokens to remove from help text\r | |
486 | # ParseVariable - True for parsing [Guids]. Otherwise False\r | |
487 | #\r | |
488 | def ParseComment (Comment, UsageTokens, TypeTokens, RemoveTokens, ParseVariable):\r | |
489 | #\r | |
490 | # Initialize return values\r | |
491 | #\r | |
492 | Usage = None\r | |
493 | Type = None\r | |
494 | String = None\r | |
495 | \r | |
496 | Comment = Comment[0]\r | |
497 | \r | |
498 | NumTokens = 2\r | |
499 | if ParseVariable:\r | |
500 | #\r | |
501 | # Remove white space around first instance of ':' from Comment if 'Variable'\r | |
502 | # is in front of ':' and Variable is the 1st or 2nd token in Comment.\r | |
503 | #\r | |
504 | List = Comment.split(':', 1)\r | |
505 | if len(List) > 1:\r | |
506 | SubList = GenerateTokenList (List[0].strip())\r | |
507 | if len(SubList) in [1, 2] and SubList[-1] == 'Variable':\r | |
508 | if List[1].strip().find('L"') == 0:\r | |
509 | Comment = List[0].strip() + ':' + List[1].strip()\r | |
510 | \r | |
511 | #\r | |
512 | # Remove first instance of L"<VariableName> from Comment and put into String\r | |
513 | # if and only if L"<VariableName>" is the 1st token, the 2nd token. Or\r | |
514 | # L"<VariableName>" is the third token immediately following 'Variable:'.\r | |
515 | #\r | |
516 | End = -1\r | |
517 | Start = Comment.find('Variable:L"')\r | |
518 | if Start >= 0:\r | |
519 | String = Comment[Start + 9:]\r | |
520 | End = String[2:].find('"')\r | |
521 | else:\r | |
522 | Start = Comment.find('L"')\r | |
523 | if Start >= 0:\r | |
524 | String = Comment[Start:]\r | |
525 | End = String[2:].find('"')\r | |
526 | if End >= 0:\r | |
527 | SubList = GenerateTokenList (Comment[:Start])\r | |
528 | if len(SubList) < 2:\r | |
529 | Comment = Comment[:Start] + String[End + 3:]\r | |
530 | String = String[:End + 3]\r | |
531 | Type = 'Variable'\r | |
532 | NumTokens = 1\r | |
533 | \r | |
534 | #\r | |
535 | # Initialize HelpText to Comment.\r | |
536 | # Content will be remove from HelpText as matching tokens are found\r | |
537 | #\r | |
538 | HelpText = Comment\r | |
539 | \r | |
540 | #\r | |
541 | # Tokenize Comment using '#' and ' ' as token separators\r | |
542 | #\r | |
543 | List = GenerateTokenList (Comment)\r | |
544 | \r | |
545 | #\r | |
546 | # Search first two tokens for Usage and Type and remove any matching tokens\r | |
547 | # from HelpText\r | |
548 | #\r | |
549 | for Token in List[0:NumTokens]:\r | |
550 | if Usage is None and Token in UsageTokens:\r | |
551 | Usage = UsageTokens[Token]\r | |
552 | HelpText = HelpText.replace(Token, '')\r | |
553 | if Usage is not None or not ParseVariable:\r | |
554 | for Token in List[0:NumTokens]:\r | |
555 | if Type is None and Token in TypeTokens:\r | |
556 | Type = TypeTokens[Token]\r | |
557 | HelpText = HelpText.replace(Token, '')\r | |
558 | if Usage is not None:\r | |
559 | for Token in List[0:NumTokens]:\r | |
560 | if Token in RemoveTokens:\r | |
561 | HelpText = HelpText.replace(Token, '')\r | |
562 | \r | |
563 | #\r | |
564 | # If no Usage token is present and set Usage to UNDEFINED\r | |
565 | #\r | |
566 | if Usage is None:\r | |
567 | Usage = 'UNDEFINED'\r | |
568 | \r | |
569 | #\r | |
570 | # If no Type token is present and set Type to UNDEFINED\r | |
571 | #\r | |
572 | if Type is None:\r | |
573 | Type = 'UNDEFINED'\r | |
574 | \r | |
575 | #\r | |
576 | # If Type is not 'Variable:', then set String to None\r | |
577 | #\r | |
578 | if Type != 'Variable':\r | |
579 | String = None\r | |
580 | \r | |
581 | #\r | |
582 | # Strip ' ' and '#' from the beginning of HelpText\r | |
583 | # If HelpText is an empty string after all parsing is\r | |
584 | # complete then set HelpText to None\r | |
585 | #\r | |
586 | HelpText = HelpText.lstrip('# ')\r | |
587 | if HelpText == '':\r | |
588 | HelpText = None\r | |
589 | \r | |
590 | #\r | |
591 | # Return parsing results\r | |
592 | #\r | |
593 | return Usage, Type, String, HelpText\r |