]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/ShellManParser.c
ShellPkg: Fix memory leak in 'ShellOpenFileByName'.
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellManParser.c
CommitLineData
a405b86d 1/** @file\r
2 Provides interface to shell MAN file parser.\r
3\r
e75390f0 4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
52d1f930 5 Copyright 2015 Dell Inc.\r
a405b86d 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Shell.h"\r
17\r
aa6f7931
QS
18/**\r
19 Convert a Unicode character to upper case only if\r
20 it maps to a valid small-case ASCII character.\r
21\r
22 This internal function only deal with Unicode character\r
23 which maps to a valid small-case ASCII character, i.e.\r
24 L'a' to L'z'. For other Unicode character, the input character\r
25 is returned directly.\r
26\r
27 @param Char The character to convert.\r
28\r
29 @retval LowerCharacter If the Char is with range L'a' to L'z'.\r
30 @retval Unchanged Otherwise.\r
31\r
32**/\r
33CHAR16\r
34EFIAPI \r
35InternalShellCharToUpper (\r
36 IN CHAR16 Char\r
37 );\r
52d1f930 38\r
a405b86d 39/**\r
40 Verifies that the filename has .MAN on the end.\r
41\r
42 allocates a new buffer and copies the name (appending .MAN if necessary)\r
43\r
44 ASSERT if ManFileName is NULL\r
45\r
46 @param[in] ManFileName original filename\r
47\r
48 @return the new filename with .man as the extension.\r
49**/\r
50CHAR16 *\r
51EFIAPI\r
52GetManFileName(\r
53 IN CONST CHAR16 *ManFileName\r
54 )\r
55{\r
56 CHAR16 *Buffer;\r
3c865f20 57 if (ManFileName == NULL) {\r
58 return (NULL);\r
59 }\r
a405b86d 60 //\r
61 // Fix the file name\r
62 //\r
63 if (StrnCmp(ManFileName+StrLen(ManFileName)-4, L".man", 4)==0) {\r
7f79b01e 64 Buffer = AllocateCopyPool(StrSize(ManFileName), ManFileName);\r
a405b86d 65 } else {\r
66 Buffer = AllocateZeroPool(StrSize(ManFileName) + 4*sizeof(CHAR16));\r
3c865f20 67 if (Buffer != NULL) {\r
e75390f0
QS
68 StrnCpyS( Buffer, \r
69 (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16), \r
70 ManFileName, \r
71 StrLen(ManFileName)\r
72 );\r
73 StrnCatS( Buffer, \r
74 (StrSize(ManFileName) + 4*sizeof(CHAR16))/sizeof(CHAR16),\r
75 L".man", \r
76 4\r
77 );\r
3c865f20 78 }\r
a405b86d 79 }\r
80 return (Buffer);\r
81}\r
82\r
83/**\r
84 Search the path environment variable for possible locations and test for\r
85 which one contains a man file with the name specified. If a valid file is found\r
86 stop searching and return the (opened) SHELL_FILE_HANDLE for that file.\r
87\r
88 @param[in] FileName Name of the file to find and open.\r
89 @param[out] Handle Pointer to the handle of the found file. The\r
90 value of this is undefined for return values\r
91 except EFI_SUCCESS.\r
92\r
93 @retval EFI_SUCCESS The file was found. Handle is a valid SHELL_FILE_HANDLE\r
94 @retval EFI_INVALID_PARAMETER A parameter had an invalid value.\r
95 @retval EFI_NOT_FOUND The file was not found.\r
96**/\r
97EFI_STATUS\r
98EFIAPI\r
99SearchPathForFile(\r
100 IN CONST CHAR16 *FileName,\r
101 OUT SHELL_FILE_HANDLE *Handle\r
102 )\r
103{\r
104 CHAR16 *FullFileName;\r
105 EFI_STATUS Status;\r
106\r
107 if ( FileName == NULL\r
108 || Handle == NULL\r
109 || StrLen(FileName) == 0\r
110 ){\r
111 return (EFI_INVALID_PARAMETER);\r
112 }\r
113\r
114 FullFileName = ShellFindFilePath(FileName);\r
115 if (FullFileName == NULL) {\r
116 return (EFI_NOT_FOUND);\r
117 }\r
118\r
119 //\r
120 // now open that file\r
121 //\r
122 Status = EfiShellOpenFileByName(FullFileName, Handle, EFI_FILE_MODE_READ);\r
123 FreePool(FullFileName);\r
124\r
125 return (Status);\r
126}\r
127\r
128/**\r
129 parses through Buffer (which is MAN file formatted) and returns the\r
130 detailed help for any sub section specified in the comma seperated list of\r
131 sections provided. If the end of the file or a .TH section is found then\r
132 return.\r
133\r
134 Upon a sucessful return the caller is responsible to free the memory in *HelpText\r
135\r
136 @param[in] Buffer Buffer to read from\r
137 @param[in] Sections name of command's sub sections to find\r
138 @param[in] HelpText pointer to pointer to string where text goes.\r
139 @param[in] HelpSize pointer to size of allocated HelpText (may be updated)\r
140\r
141 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.\r
142 @retval EFI_SUCCESS the section was found and its description sotred in\r
143 an alloceted buffer.\r
144**/\r
145EFI_STATUS\r
146EFIAPI\r
147ManBufferFindSections(\r
148 IN CONST CHAR16 *Buffer,\r
149 IN CONST CHAR16 *Sections,\r
150 IN CHAR16 **HelpText,\r
151 IN UINTN *HelpSize\r
152 )\r
153{\r
154 EFI_STATUS Status;\r
155 CONST CHAR16 *CurrentLocation;\r
156 BOOLEAN CurrentlyReading;\r
157 CHAR16 *SectionName;\r
158 UINTN SectionLen;\r
159 BOOLEAN Found;\r
160 CHAR16 *TempString;\r
161 CHAR16 *TempString2;\r
162\r
163 if ( Buffer == NULL\r
164 || HelpText == NULL\r
165 || HelpSize == NULL\r
166 ){\r
167 return (EFI_INVALID_PARAMETER);\r
168 }\r
169\r
170 Status = EFI_SUCCESS;\r
171 CurrentlyReading = FALSE;\r
172 Found = FALSE;\r
173\r
174 for (CurrentLocation = Buffer,TempString = NULL\r
175 ; CurrentLocation != NULL && *CurrentLocation != CHAR_NULL\r
176 ; CurrentLocation=StrStr(CurrentLocation, L"\r\n"),TempString = NULL\r
177 ){\r
178 while(CurrentLocation[0] == L'\r' || CurrentLocation[0] == L'\n') {\r
179 CurrentLocation++;\r
180 }\r
181 if (CurrentLocation[0] == L'#') {\r
182 //\r
183 // Skip comment lines\r
184 //\r
185 continue;\r
186 }\r
187 if (StrnCmp(CurrentLocation, L".TH", 3) == 0) {\r
188 //\r
189 // we hit the end of this commands section so stop.\r
190 //\r
191 break;\r
192 }\r
193 if (StrnCmp(CurrentLocation, L".SH ", 4) == 0) {\r
194 if (Sections == NULL) {\r
195 CurrentlyReading = TRUE;\r
196 continue;\r
197 } else if (CurrentlyReading) {\r
198 CurrentlyReading = FALSE;\r
199 }\r
200 CurrentLocation += 4;\r
201 //\r
202 // is this a section we want to read in?\r
203 //\r
204 if (StrLen(CurrentLocation)!=0) {\r
205 TempString2 = StrStr(CurrentLocation, L" ");\r
206 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\r"));\r
207 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));\r
208 ASSERT(TempString == NULL);\r
209 TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);\r
532691c8 210 if (TempString == NULL) {\r
211 Status = EFI_OUT_OF_RESOURCES;\r
212 break;\r
213 }\r
a405b86d 214 SectionName = TempString;\r
215 SectionLen = StrLen(SectionName);\r
216 SectionName = StrStr(Sections, SectionName);\r
217 if (SectionName == NULL) {\r
218 continue;\r
219 }\r
220 if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') {\r
221 CurrentlyReading = TRUE;\r
222 }\r
223 }\r
224 } else if (CurrentlyReading) {\r
225 Found = TRUE;\r
226 if (StrLen(CurrentLocation)!=0) {\r
227 TempString2 = StrStr(CurrentLocation, L"\r");\r
228 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));\r
229 ASSERT(TempString == NULL);\r
230 TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);\r
532691c8 231 if (TempString == NULL) {\r
232 Status = EFI_OUT_OF_RESOURCES;\r
233 break;\r
234 }\r
a405b86d 235 //\r
236 // copy and save the current line.\r
237 //\r
238 ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL));\r
239 StrnCatGrow (HelpText, HelpSize, TempString, 0);\r
532691c8 240 if (HelpText == NULL) {\r
241 Status = EFI_OUT_OF_RESOURCES;\r
242 break;\r
243 }\r
a405b86d 244 StrnCatGrow (HelpText, HelpSize, L"\r\n", 0);\r
532691c8 245 if (HelpText == NULL) {\r
246 Status = EFI_OUT_OF_RESOURCES;\r
247 break;\r
248 }\r
a405b86d 249 }\r
250 }\r
251 SHELL_FREE_NON_NULL(TempString);\r
252 }\r
253 if (!Found && !EFI_ERROR(Status)) {\r
254 return (EFI_NOT_FOUND);\r
255 }\r
256 return (Status);\r
257}\r
258\r
259/**\r
260 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
261 detailed help for any sub section specified in the comma seperated list of\r
262 sections provided. If the end of the file or a .TH section is found then\r
263 return.\r
264\r
265 Upon a sucessful return the caller is responsible to free the memory in *HelpText\r
266\r
267 @param[in] Handle FileHandle to read from\r
268 @param[in] Sections name of command's sub sections to find\r
269 @param[out] HelpText pointer to pointer to string where text goes.\r
270 @param[out] HelpSize pointer to size of allocated HelpText (may be updated)\r
271 @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise.\r
272\r
273 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.\r
274 @retval EFI_SUCCESS the section was found and its description sotred in\r
275 an alloceted buffer.\r
276**/\r
277EFI_STATUS\r
278EFIAPI\r
279ManFileFindSections(\r
280 IN SHELL_FILE_HANDLE Handle,\r
281 IN CONST CHAR16 *Sections,\r
282 OUT CHAR16 **HelpText,\r
283 OUT UINTN *HelpSize,\r
284 IN BOOLEAN Ascii\r
285 )\r
286{\r
287 EFI_STATUS Status;\r
288 CHAR16 *ReadLine;\r
289 UINTN Size;\r
290 BOOLEAN CurrentlyReading;\r
291 CHAR16 *SectionName;\r
292 UINTN SectionLen;\r
293 BOOLEAN Found;\r
294\r
295 if ( Handle == NULL\r
296 || HelpText == NULL\r
297 || HelpSize == NULL\r
298 ){\r
299 return (EFI_INVALID_PARAMETER);\r
300 }\r
301\r
302 Status = EFI_SUCCESS;\r
303 CurrentlyReading = FALSE;\r
304 Size = 1024;\r
305 Found = FALSE;\r
306\r
307 ReadLine = AllocateZeroPool(Size);\r
308 if (ReadLine == NULL) {\r
309 return (EFI_OUT_OF_RESOURCES);\r
310 }\r
311\r
312 for (;!ShellFileHandleEof(Handle);Size = 1024) {\r
313 Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, &Ascii);\r
314 if (ReadLine[0] == L'#') {\r
315 //\r
316 // Skip comment lines\r
317 //\r
318 continue;\r
319 }\r
320 //\r
321 // ignore too small of buffer...\r
322 //\r
323 if (Status == EFI_BUFFER_TOO_SMALL) {\r
324 Status = EFI_SUCCESS;\r
325 }\r
326 if (EFI_ERROR(Status)) {\r
327 break;\r
328 } else if (StrnCmp(ReadLine, L".TH", 3) == 0) {\r
329 //\r
330 // we hit the end of this commands section so stop.\r
331 //\r
332 break;\r
333 } else if (StrnCmp(ReadLine, L".SH", 3) == 0) {\r
334 if (Sections == NULL) {\r
335 CurrentlyReading = TRUE;\r
336 continue;\r
337 }\r
338 //\r
339 // we found a section\r
340 //\r
341 if (CurrentlyReading) {\r
342 CurrentlyReading = FALSE;\r
343 }\r
344 //\r
345 // is this a section we want to read in?\r
346 //\r
347 for ( SectionName = ReadLine + 3\r
348 ; *SectionName == L' '\r
349 ; SectionName++);\r
350 SectionLen = StrLen(SectionName);\r
351 SectionName = StrStr(Sections, SectionName);\r
352 if (SectionName == NULL) {\r
353 continue;\r
354 }\r
355 if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') {\r
356 CurrentlyReading = TRUE;\r
357 }\r
358 } else if (CurrentlyReading) {\r
359 Found = TRUE;\r
360 //\r
361 // copy and save the current line.\r
362 //\r
363 ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL));\r
364 StrnCatGrow (HelpText, HelpSize, ReadLine, 0);\r
365 StrnCatGrow (HelpText, HelpSize, L"\r\n", 0);\r
366 }\r
367 }\r
368 FreePool(ReadLine);\r
369 if (!Found && !EFI_ERROR(Status)) {\r
370 return (EFI_NOT_FOUND);\r
371 }\r
372 return (Status);\r
373}\r
374\r
375/**\r
376 parses through the MAN file formatted Buffer and returns the\r
377 "Brief Description" for the .TH section as specified by Command. If the\r
378 command section is not found return EFI_NOT_FOUND.\r
379\r
380 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc\r
381\r
382 @param[in] Handle Buffer to read from\r
383 @param[in] Command name of command's section to find\r
384 @param[in] BriefDesc pointer to pointer to string where description goes.\r
385 @param[in] BriefSize pointer to size of allocated BriefDesc\r
386\r
387 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.\r
388 @retval EFI_SUCCESS the section was found and its description sotred in\r
389 an alloceted buffer.\r
390**/\r
391EFI_STATUS\r
392EFIAPI\r
393ManBufferFindTitleSection(\r
394 IN CHAR16 **Buffer,\r
395 IN CONST CHAR16 *Command,\r
396 IN CHAR16 **BriefDesc,\r
397 IN UINTN *BriefSize\r
398 )\r
399{\r
400 EFI_STATUS Status;\r
401 CHAR16 *TitleString;\r
402 CHAR16 *TitleEnd;\r
403 CHAR16 *CurrentLocation;\r
7f79b01e
JC
404 UINTN TitleLength;\r
405 CONST CHAR16 StartString[] = L".TH ";\r
406 CONST CHAR16 EndString[] = L" 0 ";\r
a405b86d 407\r
408 if ( Buffer == NULL\r
409 || Command == NULL\r
410 || (BriefDesc != NULL && BriefSize == NULL)\r
411 ){\r
412 return (EFI_INVALID_PARAMETER);\r
413 }\r
414\r
415 Status = EFI_SUCCESS;\r
416\r
7f79b01e
JC
417 //\r
418 // more characters for StartString and EndString\r
419 //\r
420 TitleLength = StrSize(Command) + (StrLen(StartString) + StrLen(EndString)) * sizeof(CHAR16);\r
421 TitleString = AllocateZeroPool(TitleLength);\r
a405b86d 422 if (TitleString == NULL) {\r
423 return (EFI_OUT_OF_RESOURCES);\r
424 }\r
e75390f0
QS
425 StrCpyS(TitleString, TitleLength/sizeof(CHAR16), StartString);\r
426 StrCatS(TitleString, TitleLength/sizeof(CHAR16), Command);\r
427 StrCatS(TitleString, TitleLength/sizeof(CHAR16), EndString);\r
a405b86d 428\r
429 CurrentLocation = StrStr(*Buffer, TitleString);\r
430 if (CurrentLocation == NULL){\r
431 Status = EFI_NOT_FOUND;\r
432 } else {\r
433 //\r
434 // we found it so copy out the rest of the line into BriefDesc\r
435 // After skipping any spaces or zeroes\r
436 //\r
437 for (CurrentLocation += StrLen(TitleString)\r
438 ; *CurrentLocation == L' ' || *CurrentLocation == L'0' || *CurrentLocation == L'1' || *CurrentLocation == L'\"'\r
439 ; CurrentLocation++);\r
440\r
441 TitleEnd = StrStr(CurrentLocation, L"\"");\r
733f138d 442 if (TitleEnd == NULL) {\r
443 Status = EFI_DEVICE_ERROR;\r
444 } else {\r
445 if (BriefDesc != NULL) {\r
446 *BriefSize = StrSize(TitleEnd);\r
447 *BriefDesc = AllocateZeroPool(*BriefSize);\r
448 if (*BriefDesc == NULL) {\r
449 Status = EFI_OUT_OF_RESOURCES;\r
450 } else {\r
e75390f0 451 StrnCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), CurrentLocation, TitleEnd-CurrentLocation);\r
733f138d 452 }\r
a405b86d 453 }\r
a405b86d 454\r
733f138d 455 for (CurrentLocation = TitleEnd\r
456 ; *CurrentLocation != L'\n'\r
457 ; CurrentLocation++);\r
458 for (\r
459 ; *CurrentLocation == L' ' || *CurrentLocation == L'\n' || *CurrentLocation == L'\r'\r
460 ; CurrentLocation++);\r
461 *Buffer = CurrentLocation;\r
462 }\r
a405b86d 463 }\r
464\r
465 FreePool(TitleString);\r
466 return (Status);\r
467}\r
468\r
52d1f930
JD
469/**\r
470 Parses a line from a MAN file to see if it is the Title Header. If it is, then\r
471 if the "Brief Description" is desired, allocate a buffer for it and return a\r
472 copy. Upon a sucessful return the caller is responsible to free the memory in\r
473 *BriefDesc\r
474\r
475 Uses a simple state machine that allows "unlimited" whitespace before and after the\r
476 ".TH", compares Command and the MAN file commnd name without respect to case, and\r
477 allows "unlimited" whitespace and '0' and '1' characters before the Short Description.\r
478 The PCRE regex describing this functionality is: ^\s*\.TH\s+(\S)\s[\s01]*(.*)$\r
479 where group 1 is the Command Name and group 2 is the Short Description.\r
480\r
481 @param[in] Command name of command whose MAN file we think Line came from\r
482 @param[in] Line Pointer to a line from the MAN file\r
483 @param[out] BriefDesc pointer to pointer to string where description goes.\r
484 @param[out] BriefSize pointer to size of allocated BriefDesc\r
485 @param[out] Found TRUE if the Title Header was found and it belongs to Command\r
486\r
487 @retval TRUE Line contained the Title Header\r
488 @retval FALSE Line did not contain the Title Header\r
489**/\r
490BOOLEAN\r
491IsTitleHeader(\r
492 IN CONST CHAR16 *Command,\r
493 IN CHAR16 *Line,\r
494 OUT CHAR16 **BriefDesc OPTIONAL,\r
495 OUT UINTN *BriefSize OPTIONAL,\r
496 OUT BOOLEAN *Found\r
497 )\r
498{\r
499 // The states of a simple state machine used to recognize a title header line\r
500 // and to extract the Short Description, if desired.\r
501 typedef enum {\r
502 LookForThMacro, LookForCommandName, CompareCommands, GetBriefDescription, Final\r
503 } STATEVALUES;\r
504\r
505 STATEVALUES State;\r
506 UINTN CommandIndex; // Indexes Command as we compare its chars to the MAN file.\r
507 BOOLEAN ReturnValue; // TRUE if this the Title Header line of *some* MAN file.\r
508 BOOLEAN ReturnFound; // TRUE if this the Title Header line of *the desired* MAN file.\r
509\r
510 ReturnValue = FALSE;\r
511 ReturnFound = FALSE;\r
512 CommandIndex = 0;\r
513 State = LookForThMacro;\r
514\r
515 do {\r
516\r
517 if (*Line == L'\0') {\r
518 break;\r
519 }\r
520\r
521 switch (State) {\r
522\r
523 // Handle "^\s*.TH\s"\r
524 // Go to state LookForCommandName if the title header macro is present; otherwise,\r
525 // eat white space. If we see something other than white space, this is not a\r
526 // title header line.\r
527 case LookForThMacro:\r
528 if (StrnCmp (L".TH ", Line, 4) == 0 || StrnCmp (L".TH\t", Line, 4) == 0) {\r
529 Line += 4;\r
530 State = LookForCommandName;\r
531 }\r
532 else if (*Line == L' ' || *Line == L'\t') {\r
533 Line++;\r
534 }\r
535 else {\r
536 State = Final;\r
537 }\r
538 break;\r
539\r
540 // Handle "\s*"\r
541 // Eat any "extra" whitespace after the title header macro (we have already seen\r
542 // at least one white space character). Go to state CompareCommands when a\r
543 // non-white space is seen.\r
544 case LookForCommandName:\r
545 if (*Line == L' ' || *Line == L'\t') {\r
546 Line++;\r
547 }\r
548 else {\r
549 ReturnValue = TRUE; // This is *some* command's title header line.\r
550 State = CompareCommands;\r
551 // Do not increment Line; it points to the first character of the command\r
552 // name on the title header line.\r
553 }\r
554 break;\r
555\r
556 // Handle "(\S)\s"\r
557 // Compare Command to the title header command name, ignoring case. When we\r
558 // reach the end of the command (i.e. we see white space), the next state\r
559 // depends on whether the caller wants a copy of the Brief Description.\r
560 case CompareCommands:\r
561 if (*Line == L' ' || *Line == L'\t') {\r
562 ReturnFound = TRUE; // This is the desired command's title header line.\r
563 State = (BriefDesc == NULL) ? Final : GetBriefDescription;\r
564 }\r
565 else if (InternalShellCharToUpper (*Line) != InternalShellCharToUpper (*(Command + CommandIndex++))) {\r
566 State = Final;\r
567 }\r
568 Line++;\r
569 break;\r
570\r
571 // Handle "[\s01]*(.*)$"\r
572 // Skip whitespace, '0', and '1' characters, if any, prior to the brief description.\r
573 // Return the description to the caller.\r
574 case GetBriefDescription:\r
575 if (*Line != L' ' && *Line != L'\t' && *Line != L'0' && *Line != L'1') {\r
576 *BriefSize = StrSize(Line);\r
577 *BriefDesc = AllocateZeroPool(*BriefSize);\r
578 if (*BriefDesc != NULL) {\r
579 StrCpyS(*BriefDesc, (*BriefSize)/sizeof(CHAR16), Line);\r
580 }\r
581 State = Final;\r
582 }\r
583 Line++;\r
584 break;\r
585\r
d8ed4dec
PA
586 default:\r
587 break;\r
52d1f930
JD
588 }\r
589\r
590 } while (State < Final);\r
591\r
592 *Found = ReturnFound;\r
593 return ReturnValue;\r
594}\r
595\r
a405b86d 596/**\r
597 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the\r
52d1f930 598 "Brief Description" for the .TH section as specified by Command. If the\r
a405b86d 599 command section is not found return EFI_NOT_FOUND.\r
600\r
601 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc\r
602\r
4ff7e37b 603 @param[in] Handle FileHandle to read from\r
52d1f930
JD
604 @param[in] Command name of command's section to find as entered on the\r
605 command line (may be a relative or absolute path or\r
606 be in any case: upper, lower, or mixed in numerous ways!).\r
4ff7e37b
ED
607 @param[out] BriefDesc pointer to pointer to string where description goes.\r
608 @param[out] BriefSize pointer to size of allocated BriefDesc\r
609 @param[in, out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be\r
610 set if the file handle is at the 0 position.\r
a405b86d 611\r
612 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.\r
52d1f930
JD
613 @retval EFI_SUCCESS the section was found and its description stored in\r
614 an allocated buffer if requested.\r
a405b86d 615**/\r
616EFI_STATUS\r
617EFIAPI\r
618ManFileFindTitleSection(\r
619 IN SHELL_FILE_HANDLE Handle,\r
620 IN CONST CHAR16 *Command,\r
621 OUT CHAR16 **BriefDesc OPTIONAL,\r
622 OUT UINTN *BriefSize OPTIONAL,\r
623 IN OUT BOOLEAN *Ascii\r
624 )\r
625{\r
626 EFI_STATUS Status;\r
a405b86d 627 CHAR16 *ReadLine;\r
628 UINTN Size;\r
a405b86d 629 BOOLEAN Found;\r
52d1f930 630 UINTN Start;\r
a405b86d 631\r
632 if ( Handle == NULL\r
633 || Command == NULL\r
634 || (BriefDesc != NULL && BriefSize == NULL)\r
635 ){\r
636 return (EFI_INVALID_PARAMETER);\r
637 }\r
638\r
639 Status = EFI_SUCCESS;\r
640 Size = 1024;\r
641 Found = FALSE;\r
642\r
643 ReadLine = AllocateZeroPool(Size);\r
644 if (ReadLine == NULL) {\r
645 return (EFI_OUT_OF_RESOURCES);\r
646 }\r
647\r
52d1f930
JD
648 //\r
649 // Do not pass any leading path information that may be present to IsTitleHeader().\r
650 //\r
651 Start = StrLen(Command);\r
aa6f7931 652 while ((Start != 0)\r
52d1f930
JD
653 && (*(Command + Start - 1) != L'\\')\r
654 && (*(Command + Start - 1) != L'/')\r
655 && (*(Command + Start - 1) != L':')) {\r
656 --Start;\r
a405b86d 657 }\r
d233c122 658\r
a405b86d 659 for (;!ShellFileHandleEof(Handle);Size = 1024) {\r
660 Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, Ascii);\r
a405b86d 661 //\r
662 // ignore too small of buffer...\r
663 //\r
52d1f930 664 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
a405b86d 665 break;\r
666 }\r
52d1f930
JD
667\r
668 Status = EFI_NOT_FOUND;\r
669 if (IsTitleHeader (Command+Start, ReadLine, BriefDesc, BriefSize, &Found)) {\r
670 Status = Found ? EFI_SUCCESS : EFI_NOT_FOUND;\r
a405b86d 671 break;\r
672 }\r
673 }\r
52d1f930 674\r
a405b86d 675 FreePool(ReadLine);\r
a405b86d 676 return (Status);\r
677}\r
678\r
679/**\r
680 This function returns the help information for the specified command. The help text\r
681 will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B)\r
682\r
683 If Sections is specified, then each section name listed will be compared in a casesensitive\r
684 manner, to the section names described in Appendix B. If the section exists,\r
685 it will be appended to the returned help text. If the section does not exist, no\r
686 information will be returned. If Sections is NULL, then all help text information\r
687 available will be returned.\r
688\r
689 if BriefDesc is NULL, then the breif description will not be savedd seperatly,\r
690 but placed first in the main HelpText.\r
691\r
692 @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name.\r
693 @param[in] Command Points to the NULL-terminated UEFI Shell command name.\r
694 @param[in] Sections Points to the NULL-terminated comma-delimited\r
695 section names to return. If NULL, then all\r
696 sections will be returned.\r
697 @param[out] BriefDesc On return, points to a callee-allocated buffer\r
698 containing brief description text.\r
699 @param[out] HelpText On return, points to a callee-allocated buffer\r
700 containing all specified help text.\r
701\r
702 @retval EFI_SUCCESS The help text was returned.\r
703 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the\r
704 returned help text.\r
ecae5117 705 @retval EFI_INVALID_PARAMETER HelpText is NULL.\r
706 @retval EFI_INVALID_PARAMETER ManFileName is invalid.\r
a405b86d 707 @retval EFI_NOT_FOUND There is no help text available for Command.\r
708**/\r
709EFI_STATUS\r
710EFIAPI\r
711ProcessManFile(\r
712 IN CONST CHAR16 *ManFileName,\r
713 IN CONST CHAR16 *Command,\r
714 IN CONST CHAR16 *Sections OPTIONAL,\r
715 OUT CHAR16 **BriefDesc OPTIONAL,\r
716 OUT CHAR16 **HelpText\r
717 )\r
718{\r
719 CHAR16 *TempString;\r
720 SHELL_FILE_HANDLE FileHandle;\r
721 EFI_STATUS Status;\r
722 UINTN HelpSize;\r
723 UINTN BriefSize;\r
724 BOOLEAN Ascii;\r
725 CHAR16 *TempString2;\r
726 EFI_DEVICE_PATH_PROTOCOL *FileDevPath;\r
727 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
728\r
729 if ( ManFileName == NULL\r
730 || Command == NULL\r
731 || HelpText == NULL\r
732 ){\r
733 return (EFI_INVALID_PARAMETER);\r
734 }\r
735\r
736 HelpSize = 0;\r
737 BriefSize = 0;\r
738 TempString = NULL;\r
33fe8308 739 Ascii = FALSE;\r
a405b86d 740 //\r
741 // See if it's in HII first\r
742 //\r
743 TempString = ShellCommandGetCommandHelp(Command);\r
744 if (TempString != NULL) {\r
745 TempString2 = TempString;\r
746 Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, &BriefSize);\r
747 if (!EFI_ERROR(Status) && HelpText != NULL){\r
748 Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize);\r
749 }\r
750 } else {\r
751 FileHandle = NULL;\r
752 TempString = GetManFileName(ManFileName);\r
ecae5117 753 if (TempString == NULL) {\r
754 return (EFI_INVALID_PARAMETER);\r
755 }\r
a405b86d 756\r
757 Status = SearchPathForFile(TempString, &FileHandle);\r
758 if (EFI_ERROR(Status)) {\r
759 FileDevPath = FileDevicePath(NULL, TempString);\r
760 DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath);\r
761 Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
762 FreePool(FileDevPath);\r
763 FreePool(DevPath);\r
764 }\r
765\r
766 if (!EFI_ERROR(Status)) {\r
767 HelpSize = 0;\r
768 BriefSize = 0;\r
769 Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii);\r
770 if (!EFI_ERROR(Status) && HelpText != NULL){\r
771 Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii);\r
772 }\r
773 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
774 } else {\r
775 *HelpText = NULL;\r
776 }\r
777 }\r
778 if (TempString != NULL) {\r
779 FreePool(TempString);\r
780 }\r
781\r
782 return (Status);\r
783}\r