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