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