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