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