2 Provides interface to shell MAN file parser.
4 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Verifies that the filename has .MAN on the end.
20 allocates a new buffer and copies the name (appending .MAN if necessary)
22 ASSERT if ManFileName is NULL
24 @param[in] ManFileName original filename
26 @return the new filename with .man as the extension.
31 IN CONST CHAR16
*ManFileName
35 if (ManFileName
== NULL
) {
41 if (StrnCmp(ManFileName
+StrLen(ManFileName
)-4, L
".man", 4)==0) {
42 Buffer
= AllocateCopyPool(StrSize(ManFileName
), ManFileName
);
44 Buffer
= AllocateZeroPool(StrSize(ManFileName
) + 4*sizeof(CHAR16
));
46 StrnCpy(Buffer
, ManFileName
, StrLen(ManFileName
));
47 StrnCat(Buffer
, L
".man", 4);
54 Search the path environment variable for possible locations and test for
55 which one contains a man file with the name specified. If a valid file is found
56 stop searching and return the (opened) SHELL_FILE_HANDLE for that file.
58 @param[in] FileName Name of the file to find and open.
59 @param[out] Handle Pointer to the handle of the found file. The
60 value of this is undefined for return values
63 @retval EFI_SUCCESS The file was found. Handle is a valid SHELL_FILE_HANDLE
64 @retval EFI_INVALID_PARAMETER A parameter had an invalid value.
65 @retval EFI_NOT_FOUND The file was not found.
70 IN CONST CHAR16
*FileName
,
71 OUT SHELL_FILE_HANDLE
*Handle
79 || StrLen(FileName
) == 0
81 return (EFI_INVALID_PARAMETER
);
84 FullFileName
= ShellFindFilePath(FileName
);
85 if (FullFileName
== NULL
) {
86 return (EFI_NOT_FOUND
);
92 Status
= EfiShellOpenFileByName(FullFileName
, Handle
, EFI_FILE_MODE_READ
);
93 FreePool(FullFileName
);
99 parses through Buffer (which is MAN file formatted) and returns the
100 detailed help for any sub section specified in the comma seperated list of
101 sections provided. If the end of the file or a .TH section is found then
104 Upon a sucessful return the caller is responsible to free the memory in *HelpText
106 @param[in] Buffer Buffer to read from
107 @param[in] Sections name of command's sub sections to find
108 @param[in] HelpText pointer to pointer to string where text goes.
109 @param[in] HelpSize pointer to size of allocated HelpText (may be updated)
111 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
112 @retval EFI_SUCCESS the section was found and its description sotred in
117 ManBufferFindSections(
118 IN CONST CHAR16
*Buffer
,
119 IN CONST CHAR16
*Sections
,
120 IN CHAR16
**HelpText
,
125 CONST CHAR16
*CurrentLocation
;
126 BOOLEAN CurrentlyReading
;
137 return (EFI_INVALID_PARAMETER
);
140 Status
= EFI_SUCCESS
;
141 CurrentlyReading
= FALSE
;
144 for (CurrentLocation
= Buffer
,TempString
= NULL
145 ; CurrentLocation
!= NULL
&& *CurrentLocation
!= CHAR_NULL
146 ; CurrentLocation
=StrStr(CurrentLocation
, L
"\r\n"),TempString
= NULL
148 while(CurrentLocation
[0] == L
'\r' || CurrentLocation
[0] == L
'\n') {
151 if (CurrentLocation
[0] == L
'#') {
153 // Skip comment lines
157 if (StrnCmp(CurrentLocation
, L
".TH", 3) == 0) {
159 // we hit the end of this commands section so stop.
163 if (StrnCmp(CurrentLocation
, L
".SH ", 4) == 0) {
164 if (Sections
== NULL
) {
165 CurrentlyReading
= TRUE
;
167 } else if (CurrentlyReading
) {
168 CurrentlyReading
= FALSE
;
170 CurrentLocation
+= 4;
172 // is this a section we want to read in?
174 if (StrLen(CurrentLocation
)!=0) {
175 TempString2
= StrStr(CurrentLocation
, L
" ");
176 TempString2
= MIN(TempString2
, StrStr(CurrentLocation
, L
"\r"));
177 TempString2
= MIN(TempString2
, StrStr(CurrentLocation
, L
"\n"));
178 ASSERT(TempString
== NULL
);
179 TempString
= StrnCatGrow(&TempString
, NULL
, CurrentLocation
, TempString2
==NULL
?0:TempString2
- CurrentLocation
);
180 if (TempString
== NULL
) {
181 Status
= EFI_OUT_OF_RESOURCES
;
184 SectionName
= TempString
;
185 SectionLen
= StrLen(SectionName
);
186 SectionName
= StrStr(Sections
, SectionName
);
187 if (SectionName
== NULL
) {
190 if (*(SectionName
+ SectionLen
) == CHAR_NULL
|| *(SectionName
+ SectionLen
) == L
',') {
191 CurrentlyReading
= TRUE
;
194 } else if (CurrentlyReading
) {
196 if (StrLen(CurrentLocation
)!=0) {
197 TempString2
= StrStr(CurrentLocation
, L
"\r");
198 TempString2
= MIN(TempString2
, StrStr(CurrentLocation
, L
"\n"));
199 ASSERT(TempString
== NULL
);
200 TempString
= StrnCatGrow(&TempString
, NULL
, CurrentLocation
, TempString2
==NULL
?0:TempString2
- CurrentLocation
);
201 if (TempString
== NULL
) {
202 Status
= EFI_OUT_OF_RESOURCES
;
206 // copy and save the current line.
208 ASSERT((*HelpText
== NULL
&& *HelpSize
== 0) || (*HelpText
!= NULL
));
209 StrnCatGrow (HelpText
, HelpSize
, TempString
, 0);
210 if (HelpText
== NULL
) {
211 Status
= EFI_OUT_OF_RESOURCES
;
214 StrnCatGrow (HelpText
, HelpSize
, L
"\r\n", 0);
215 if (HelpText
== NULL
) {
216 Status
= EFI_OUT_OF_RESOURCES
;
221 SHELL_FREE_NON_NULL(TempString
);
223 if (!Found
&& !EFI_ERROR(Status
)) {
224 return (EFI_NOT_FOUND
);
230 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the
231 detailed help for any sub section specified in the comma seperated list of
232 sections provided. If the end of the file or a .TH section is found then
235 Upon a sucessful return the caller is responsible to free the memory in *HelpText
237 @param[in] Handle FileHandle to read from
238 @param[in] Sections name of command's sub sections to find
239 @param[out] HelpText pointer to pointer to string where text goes.
240 @param[out] HelpSize pointer to size of allocated HelpText (may be updated)
241 @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise.
243 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
244 @retval EFI_SUCCESS the section was found and its description sotred in
250 IN SHELL_FILE_HANDLE Handle
,
251 IN CONST CHAR16
*Sections
,
252 OUT CHAR16
**HelpText
,
260 BOOLEAN CurrentlyReading
;
269 return (EFI_INVALID_PARAMETER
);
272 Status
= EFI_SUCCESS
;
273 CurrentlyReading
= FALSE
;
277 ReadLine
= AllocateZeroPool(Size
);
278 if (ReadLine
== NULL
) {
279 return (EFI_OUT_OF_RESOURCES
);
282 for (;!ShellFileHandleEof(Handle
);Size
= 1024) {
283 Status
= ShellFileHandleReadLine(Handle
, ReadLine
, &Size
, TRUE
, &Ascii
);
284 if (ReadLine
[0] == L
'#') {
286 // Skip comment lines
291 // ignore too small of buffer...
293 if (Status
== EFI_BUFFER_TOO_SMALL
) {
294 Status
= EFI_SUCCESS
;
296 if (EFI_ERROR(Status
)) {
298 } else if (StrnCmp(ReadLine
, L
".TH", 3) == 0) {
300 // we hit the end of this commands section so stop.
303 } else if (StrnCmp(ReadLine
, L
".SH", 3) == 0) {
304 if (Sections
== NULL
) {
305 CurrentlyReading
= TRUE
;
309 // we found a section
311 if (CurrentlyReading
) {
312 CurrentlyReading
= FALSE
;
315 // is this a section we want to read in?
317 for ( SectionName
= ReadLine
+ 3
318 ; *SectionName
== L
' '
320 SectionLen
= StrLen(SectionName
);
321 SectionName
= StrStr(Sections
, SectionName
);
322 if (SectionName
== NULL
) {
325 if (*(SectionName
+ SectionLen
) == CHAR_NULL
|| *(SectionName
+ SectionLen
) == L
',') {
326 CurrentlyReading
= TRUE
;
328 } else if (CurrentlyReading
) {
331 // copy and save the current line.
333 ASSERT((*HelpText
== NULL
&& *HelpSize
== 0) || (*HelpText
!= NULL
));
334 StrnCatGrow (HelpText
, HelpSize
, ReadLine
, 0);
335 StrnCatGrow (HelpText
, HelpSize
, L
"\r\n", 0);
339 if (!Found
&& !EFI_ERROR(Status
)) {
340 return (EFI_NOT_FOUND
);
346 parses through the MAN file formatted Buffer and returns the
347 "Brief Description" for the .TH section as specified by Command. If the
348 command section is not found return EFI_NOT_FOUND.
350 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc
352 @param[in] Handle Buffer to read from
353 @param[in] Command name of command's section to find
354 @param[in] BriefDesc pointer to pointer to string where description goes.
355 @param[in] BriefSize pointer to size of allocated BriefDesc
357 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
358 @retval EFI_SUCCESS the section was found and its description sotred in
363 ManBufferFindTitleSection(
365 IN CONST CHAR16
*Command
,
366 IN CHAR16
**BriefDesc
,
373 CHAR16
*CurrentLocation
;
375 CONST CHAR16 StartString
[] = L
".TH ";
376 CONST CHAR16 EndString
[] = L
" 0 ";
380 || (BriefDesc
!= NULL
&& BriefSize
== NULL
)
382 return (EFI_INVALID_PARAMETER
);
385 Status
= EFI_SUCCESS
;
388 // more characters for StartString and EndString
390 TitleLength
= StrSize(Command
) + (StrLen(StartString
) + StrLen(EndString
)) * sizeof(CHAR16
);
391 TitleString
= AllocateZeroPool(TitleLength
);
392 if (TitleString
== NULL
) {
393 return (EFI_OUT_OF_RESOURCES
);
395 StrnCpy(TitleString
, StartString
, TitleLength
/sizeof(CHAR16
) - 1);
396 StrnCat(TitleString
, Command
, TitleLength
/sizeof(CHAR16
) - 1 - StrLen(TitleString
));
397 StrnCat(TitleString
, EndString
, TitleLength
/sizeof(CHAR16
) - 1 - StrLen(TitleString
));
399 CurrentLocation
= StrStr(*Buffer
, TitleString
);
400 if (CurrentLocation
== NULL
){
401 Status
= EFI_NOT_FOUND
;
404 // we found it so copy out the rest of the line into BriefDesc
405 // After skipping any spaces or zeroes
407 for (CurrentLocation
+= StrLen(TitleString
)
408 ; *CurrentLocation
== L
' ' || *CurrentLocation
== L
'0' || *CurrentLocation
== L
'1' || *CurrentLocation
== L
'\"'
409 ; CurrentLocation
++);
411 TitleEnd
= StrStr(CurrentLocation
, L
"\"");
412 if (TitleEnd
== NULL
) {
413 Status
= EFI_DEVICE_ERROR
;
415 if (BriefDesc
!= NULL
) {
416 *BriefSize
= StrSize(TitleEnd
);
417 *BriefDesc
= AllocateZeroPool(*BriefSize
);
418 if (*BriefDesc
== NULL
) {
419 Status
= EFI_OUT_OF_RESOURCES
;
421 StrnCpy(*BriefDesc
, CurrentLocation
, TitleEnd
-CurrentLocation
);
425 for (CurrentLocation
= TitleEnd
426 ; *CurrentLocation
!= L
'\n'
427 ; CurrentLocation
++);
429 ; *CurrentLocation
== L
' ' || *CurrentLocation
== L
'\n' || *CurrentLocation
== L
'\r'
430 ; CurrentLocation
++);
431 *Buffer
= CurrentLocation
;
435 FreePool(TitleString
);
440 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the
441 "Brief Description" for the .TH section as specified by Command. if the
442 command section is not found return EFI_NOT_FOUND.
444 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc
446 @param[in] Handle FileHandle to read from
447 @param[in] Command name of command's section to find
448 @param[out] BriefDesc pointer to pointer to string where description goes.
449 @param[out] BriefSize pointer to size of allocated BriefDesc
450 @param[in, out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be
451 set if the file handle is at the 0 position.
453 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
454 @retval EFI_SUCCESS the section was found and its description sotred in
459 ManFileFindTitleSection(
460 IN SHELL_FILE_HANDLE Handle
,
461 IN CONST CHAR16
*Command
,
462 OUT CHAR16
**BriefDesc OPTIONAL
,
463 OUT UINTN
*BriefSize OPTIONAL
,
464 IN OUT BOOLEAN
*Ascii
478 || (BriefDesc
!= NULL
&& BriefSize
== NULL
)
480 return (EFI_INVALID_PARAMETER
);
483 Status
= EFI_SUCCESS
;
487 ReadLine
= AllocateZeroPool(Size
);
488 if (ReadLine
== NULL
) {
489 return (EFI_OUT_OF_RESOURCES
);
492 TitleSize
= (4*sizeof(CHAR16
)) + StrSize(Command
);
493 TitleString
= AllocateZeroPool(TitleSize
);
494 if (TitleString
== NULL
) {
496 return (EFI_OUT_OF_RESOURCES
);
498 StrnCpy(TitleString
, L
".TH ", TitleSize
/sizeof(CHAR16
) - 1);
499 StrnCat(TitleString
, Command
, TitleSize
/sizeof(CHAR16
) - 1 - StrLen(TitleString
));
501 TitleLen
= StrLen(TitleString
);
502 for (;!ShellFileHandleEof(Handle
);Size
= 1024) {
503 Status
= ShellFileHandleReadLine(Handle
, ReadLine
, &Size
, TRUE
, Ascii
);
504 if (ReadLine
[0] == L
'#') {
506 // Skip comment lines
511 // ignore too small of buffer...
513 if (Status
== EFI_BUFFER_TOO_SMALL
) {
514 Status
= EFI_SUCCESS
;
516 if (EFI_ERROR(Status
)) {
519 if (StrnCmp(ReadLine
, TitleString
, TitleLen
) == 0) {
522 // we found it so copy out the rest of the line into BriefDesc
523 // After skipping any spaces or zeroes
525 for ( TitleEnd
= ReadLine
+TitleLen
526 ; *TitleEnd
== L
' ' || *TitleEnd
== L
'0' || *TitleEnd
== L
'1'
528 if (BriefDesc
!= NULL
) {
529 *BriefSize
= StrSize(TitleEnd
);
530 *BriefDesc
= AllocateZeroPool(*BriefSize
);
531 if (*BriefDesc
== NULL
) {
532 Status
= EFI_OUT_OF_RESOURCES
;
535 StrnCpy(*BriefDesc
, TitleEnd
, (*BriefSize
)/sizeof(CHAR16
) - 1);
541 FreePool(TitleString
);
542 if (!Found
&& !EFI_ERROR(Status
)) {
543 return (EFI_NOT_FOUND
);
549 This function returns the help information for the specified command. The help text
550 will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B)
552 If Sections is specified, then each section name listed will be compared in a casesensitive
553 manner, to the section names described in Appendix B. If the section exists,
554 it will be appended to the returned help text. If the section does not exist, no
555 information will be returned. If Sections is NULL, then all help text information
556 available will be returned.
558 if BriefDesc is NULL, then the breif description will not be savedd seperatly,
559 but placed first in the main HelpText.
561 @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name.
562 @param[in] Command Points to the NULL-terminated UEFI Shell command name.
563 @param[in] Sections Points to the NULL-terminated comma-delimited
564 section names to return. If NULL, then all
565 sections will be returned.
566 @param[out] BriefDesc On return, points to a callee-allocated buffer
567 containing brief description text.
568 @param[out] HelpText On return, points to a callee-allocated buffer
569 containing all specified help text.
571 @retval EFI_SUCCESS The help text was returned.
572 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the
574 @retval EFI_INVALID_PARAMETER HelpText is NULL.
575 @retval EFI_INVALID_PARAMETER ManFileName is invalid.
576 @retval EFI_NOT_FOUND There is no help text available for Command.
581 IN CONST CHAR16
*ManFileName
,
582 IN CONST CHAR16
*Command
,
583 IN CONST CHAR16
*Sections OPTIONAL
,
584 OUT CHAR16
**BriefDesc OPTIONAL
,
585 OUT CHAR16
**HelpText
589 SHELL_FILE_HANDLE FileHandle
;
595 EFI_DEVICE_PATH_PROTOCOL
*FileDevPath
;
596 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
598 if ( ManFileName
== NULL
602 return (EFI_INVALID_PARAMETER
);
610 // See if it's in HII first
612 TempString
= ShellCommandGetCommandHelp(Command
);
613 if (TempString
!= NULL
) {
614 TempString2
= TempString
;
615 Status
= ManBufferFindTitleSection(&TempString2
, Command
, BriefDesc
, &BriefSize
);
616 if (!EFI_ERROR(Status
) && HelpText
!= NULL
){
617 Status
= ManBufferFindSections(TempString2
, Sections
, HelpText
, &HelpSize
);
621 TempString
= GetManFileName(ManFileName
);
622 if (TempString
== NULL
) {
623 return (EFI_INVALID_PARAMETER
);
626 Status
= SearchPathForFile(TempString
, &FileHandle
);
627 if (EFI_ERROR(Status
)) {
628 FileDevPath
= FileDevicePath(NULL
, TempString
);
629 DevPath
= AppendDevicePath (ShellInfoObject
.ImageDevPath
, FileDevPath
);
630 Status
= InternalOpenFileDevicePath(DevPath
, &FileHandle
, EFI_FILE_MODE_READ
, 0);
631 FreePool(FileDevPath
);
635 if (!EFI_ERROR(Status
)) {
638 Status
= ManFileFindTitleSection(FileHandle
, Command
, BriefDesc
, &BriefSize
, &Ascii
);
639 if (!EFI_ERROR(Status
) && HelpText
!= NULL
){
640 Status
= ManFileFindSections(FileHandle
, Sections
, HelpText
, &HelpSize
, Ascii
);
642 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(FileHandle
);
647 if (TempString
!= NULL
) {
648 FreePool(TempString
);