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