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