]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ShellManParser.c
udk2010.up2.shell initial release.
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellManParser.c
1 /** @file
2 Provides interface to shell MAN file parser.
3
4 Copyright (c) 2009 - 2010, 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
9
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.
12
13 **/
14
15 #include "Shell.h"
16
17 /**
18 Verifies that the filename has .MAN on the end.
19
20 allocates a new buffer and copies the name (appending .MAN if necessary)
21
22 ASSERT if ManFileName is NULL
23
24 @param[in] ManFileName original filename
25
26 @return the new filename with .man as the extension.
27 **/
28 CHAR16 *
29 EFIAPI
30 GetManFileName(
31 IN CONST CHAR16 *ManFileName
32 )
33 {
34 CHAR16 *Buffer;
35 ASSERT(ManFileName != NULL);
36 //
37 // Fix the file name
38 //
39 if (StrnCmp(ManFileName+StrLen(ManFileName)-4, L".man", 4)==0) {
40 Buffer = AllocateZeroPool(StrSize(ManFileName));
41 StrCpy(Buffer, ManFileName);
42 } else {
43 Buffer = AllocateZeroPool(StrSize(ManFileName) + 4*sizeof(CHAR16));
44 StrCpy(Buffer, ManFileName);
45 StrCat(Buffer, L".man");
46 }
47 return (Buffer);
48 }
49
50 /**
51 Search the path environment variable for possible locations and test for
52 which one contains a man file with the name specified. If a valid file is found
53 stop searching and return the (opened) SHELL_FILE_HANDLE for that file.
54
55 @param[in] FileName Name of the file to find and open.
56 @param[out] Handle Pointer to the handle of the found file. The
57 value of this is undefined for return values
58 except EFI_SUCCESS.
59
60 @retval EFI_SUCCESS The file was found. Handle is a valid SHELL_FILE_HANDLE
61 @retval EFI_INVALID_PARAMETER A parameter had an invalid value.
62 @retval EFI_NOT_FOUND The file was not found.
63 **/
64 EFI_STATUS
65 EFIAPI
66 SearchPathForFile(
67 IN CONST CHAR16 *FileName,
68 OUT SHELL_FILE_HANDLE *Handle
69 )
70 {
71 CHAR16 *FullFileName;
72 EFI_STATUS Status;
73
74 if ( FileName == NULL
75 || Handle == NULL
76 || StrLen(FileName) == 0
77 ){
78 return (EFI_INVALID_PARAMETER);
79 }
80
81 FullFileName = ShellFindFilePath(FileName);
82 if (FullFileName == NULL) {
83 return (EFI_NOT_FOUND);
84 }
85
86 //
87 // now open that file
88 //
89 Status = EfiShellOpenFileByName(FullFileName, Handle, EFI_FILE_MODE_READ);
90 FreePool(FullFileName);
91
92 return (Status);
93 }
94
95 /**
96 parses through Buffer (which is MAN file formatted) and returns the
97 detailed help for any sub section specified in the comma seperated list of
98 sections provided. If the end of the file or a .TH section is found then
99 return.
100
101 Upon a sucessful return the caller is responsible to free the memory in *HelpText
102
103 @param[in] Buffer Buffer to read from
104 @param[in] Sections name of command's sub sections to find
105 @param[in] HelpText pointer to pointer to string where text goes.
106 @param[in] HelpSize pointer to size of allocated HelpText (may be updated)
107
108 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
109 @retval EFI_SUCCESS the section was found and its description sotred in
110 an alloceted buffer.
111 **/
112 EFI_STATUS
113 EFIAPI
114 ManBufferFindSections(
115 IN CONST CHAR16 *Buffer,
116 IN CONST CHAR16 *Sections,
117 IN CHAR16 **HelpText,
118 IN UINTN *HelpSize
119 )
120 {
121 EFI_STATUS Status;
122 CONST CHAR16 *CurrentLocation;
123 BOOLEAN CurrentlyReading;
124 CHAR16 *SectionName;
125 UINTN SectionLen;
126 BOOLEAN Found;
127 CHAR16 *TempString;
128 CHAR16 *TempString2;
129
130 if ( Buffer == NULL
131 || HelpText == NULL
132 || HelpSize == NULL
133 ){
134 return (EFI_INVALID_PARAMETER);
135 }
136
137 Status = EFI_SUCCESS;
138 CurrentlyReading = FALSE;
139 Found = FALSE;
140
141 for (CurrentLocation = Buffer,TempString = NULL
142 ; CurrentLocation != NULL && *CurrentLocation != CHAR_NULL
143 ; CurrentLocation=StrStr(CurrentLocation, L"\r\n"),TempString = NULL
144 ){
145 while(CurrentLocation[0] == L'\r' || CurrentLocation[0] == L'\n') {
146 CurrentLocation++;
147 }
148 if (CurrentLocation[0] == L'#') {
149 //
150 // Skip comment lines
151 //
152 continue;
153 }
154 if (StrnCmp(CurrentLocation, L".TH", 3) == 0) {
155 //
156 // we hit the end of this commands section so stop.
157 //
158 break;
159 }
160 if (StrnCmp(CurrentLocation, L".SH ", 4) == 0) {
161 if (Sections == NULL) {
162 CurrentlyReading = TRUE;
163 continue;
164 } else if (CurrentlyReading) {
165 CurrentlyReading = FALSE;
166 }
167 CurrentLocation += 4;
168 //
169 // is this a section we want to read in?
170 //
171 if (StrLen(CurrentLocation)!=0) {
172 TempString2 = StrStr(CurrentLocation, L" ");
173 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\r"));
174 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));
175 ASSERT(TempString == NULL);
176 TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);
177 SectionName = TempString;
178 SectionLen = StrLen(SectionName);
179 SectionName = StrStr(Sections, SectionName);
180 if (SectionName == NULL) {
181 continue;
182 }
183 if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') {
184 CurrentlyReading = TRUE;
185 }
186 }
187 } else if (CurrentlyReading) {
188 Found = TRUE;
189 if (StrLen(CurrentLocation)!=0) {
190 TempString2 = StrStr(CurrentLocation, L"\r");
191 TempString2 = MIN(TempString2, StrStr(CurrentLocation, L"\n"));
192 ASSERT(TempString == NULL);
193 TempString = StrnCatGrow(&TempString, NULL, CurrentLocation, TempString2==NULL?0:TempString2 - CurrentLocation);
194 //
195 // copy and save the current line.
196 //
197 ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL));
198 StrnCatGrow (HelpText, HelpSize, TempString, 0);
199 StrnCatGrow (HelpText, HelpSize, L"\r\n", 0);
200 }
201 }
202 SHELL_FREE_NON_NULL(TempString);
203 }
204 if (!Found && !EFI_ERROR(Status)) {
205 return (EFI_NOT_FOUND);
206 }
207 return (Status);
208 }
209
210 /**
211 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the
212 detailed help for any sub section specified in the comma seperated list of
213 sections provided. If the end of the file or a .TH section is found then
214 return.
215
216 Upon a sucessful return the caller is responsible to free the memory in *HelpText
217
218 @param[in] Handle FileHandle to read from
219 @param[in] Sections name of command's sub sections to find
220 @param[out] HelpText pointer to pointer to string where text goes.
221 @param[out] HelpSize pointer to size of allocated HelpText (may be updated)
222 @param[in] Ascii TRUE if the file is ASCII, FALSE otherwise.
223
224 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
225 @retval EFI_SUCCESS the section was found and its description sotred in
226 an alloceted buffer.
227 **/
228 EFI_STATUS
229 EFIAPI
230 ManFileFindSections(
231 IN SHELL_FILE_HANDLE Handle,
232 IN CONST CHAR16 *Sections,
233 OUT CHAR16 **HelpText,
234 OUT UINTN *HelpSize,
235 IN BOOLEAN Ascii
236 )
237 {
238 EFI_STATUS Status;
239 CHAR16 *ReadLine;
240 UINTN Size;
241 BOOLEAN CurrentlyReading;
242 CHAR16 *SectionName;
243 UINTN SectionLen;
244 BOOLEAN Found;
245
246 if ( Handle == NULL
247 || HelpText == NULL
248 || HelpSize == NULL
249 ){
250 return (EFI_INVALID_PARAMETER);
251 }
252
253 Status = EFI_SUCCESS;
254 CurrentlyReading = FALSE;
255 Size = 1024;
256 Found = FALSE;
257
258 ReadLine = AllocateZeroPool(Size);
259 if (ReadLine == NULL) {
260 return (EFI_OUT_OF_RESOURCES);
261 }
262
263 for (;!ShellFileHandleEof(Handle);Size = 1024) {
264 Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, &Ascii);
265 if (ReadLine[0] == L'#') {
266 //
267 // Skip comment lines
268 //
269 continue;
270 }
271 //
272 // ignore too small of buffer...
273 //
274 if (Status == EFI_BUFFER_TOO_SMALL) {
275 Status = EFI_SUCCESS;
276 }
277 if (EFI_ERROR(Status)) {
278 break;
279 } else if (StrnCmp(ReadLine, L".TH", 3) == 0) {
280 //
281 // we hit the end of this commands section so stop.
282 //
283 break;
284 } else if (StrnCmp(ReadLine, L".SH", 3) == 0) {
285 if (Sections == NULL) {
286 CurrentlyReading = TRUE;
287 continue;
288 }
289 //
290 // we found a section
291 //
292 if (CurrentlyReading) {
293 CurrentlyReading = FALSE;
294 }
295 //
296 // is this a section we want to read in?
297 //
298 for ( SectionName = ReadLine + 3
299 ; *SectionName == L' '
300 ; SectionName++);
301 SectionLen = StrLen(SectionName);
302 SectionName = StrStr(Sections, SectionName);
303 if (SectionName == NULL) {
304 continue;
305 }
306 if (*(SectionName + SectionLen) == CHAR_NULL || *(SectionName + SectionLen) == L',') {
307 CurrentlyReading = TRUE;
308 }
309 } else if (CurrentlyReading) {
310 Found = TRUE;
311 //
312 // copy and save the current line.
313 //
314 ASSERT((*HelpText == NULL && *HelpSize == 0) || (*HelpText != NULL));
315 StrnCatGrow (HelpText, HelpSize, ReadLine, 0);
316 StrnCatGrow (HelpText, HelpSize, L"\r\n", 0);
317 }
318 }
319 FreePool(ReadLine);
320 if (!Found && !EFI_ERROR(Status)) {
321 return (EFI_NOT_FOUND);
322 }
323 return (Status);
324 }
325
326 /**
327 parses through the MAN file formatted Buffer and returns the
328 "Brief Description" for the .TH section as specified by Command. If the
329 command section is not found return EFI_NOT_FOUND.
330
331 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc
332
333 @param[in] Handle Buffer to read from
334 @param[in] Command name of command's section to find
335 @param[in] BriefDesc pointer to pointer to string where description goes.
336 @param[in] BriefSize pointer to size of allocated BriefDesc
337
338 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
339 @retval EFI_SUCCESS the section was found and its description sotred in
340 an alloceted buffer.
341 **/
342 EFI_STATUS
343 EFIAPI
344 ManBufferFindTitleSection(
345 IN CHAR16 **Buffer,
346 IN CONST CHAR16 *Command,
347 IN CHAR16 **BriefDesc,
348 IN UINTN *BriefSize
349 )
350 {
351 EFI_STATUS Status;
352 CHAR16 *TitleString;
353 CHAR16 *TitleEnd;
354 CHAR16 *CurrentLocation;
355
356 if ( Buffer == NULL
357 || Command == NULL
358 || (BriefDesc != NULL && BriefSize == NULL)
359 ){
360 return (EFI_INVALID_PARAMETER);
361 }
362
363 Status = EFI_SUCCESS;
364
365 TitleString = AllocatePool((7*sizeof(CHAR16)) + StrSize(Command));
366 if (TitleString == NULL) {
367 return (EFI_OUT_OF_RESOURCES);
368 }
369 StrCpy(TitleString, L".TH ");
370 StrCat(TitleString, Command);
371 StrCat(TitleString, L" 0 ");
372
373 CurrentLocation = StrStr(*Buffer, TitleString);
374 if (CurrentLocation == NULL){
375 Status = EFI_NOT_FOUND;
376 } else {
377 //
378 // we found it so copy out the rest of the line into BriefDesc
379 // After skipping any spaces or zeroes
380 //
381 for (CurrentLocation += StrLen(TitleString)
382 ; *CurrentLocation == L' ' || *CurrentLocation == L'0' || *CurrentLocation == L'1' || *CurrentLocation == L'\"'
383 ; CurrentLocation++);
384
385 TitleEnd = StrStr(CurrentLocation, L"\"");
386 ASSERT(TitleEnd != NULL);
387 if (BriefDesc != NULL) {
388 *BriefSize = StrSize(TitleEnd);
389 *BriefDesc = AllocateZeroPool(*BriefSize);
390 if (*BriefDesc == NULL) {
391 Status = EFI_OUT_OF_RESOURCES;
392 } else {
393 StrnCpy(*BriefDesc, CurrentLocation, TitleEnd-CurrentLocation);
394 }
395 }
396
397 for (CurrentLocation = TitleEnd
398 ; *CurrentLocation != L'\n'
399 ; CurrentLocation++);
400 for (
401 ; *CurrentLocation == L' ' || *CurrentLocation == L'\n' || *CurrentLocation == L'\r'
402 ; CurrentLocation++);
403 *Buffer = CurrentLocation;
404 }
405
406 FreePool(TitleString);
407 return (Status);
408 }
409
410 /**
411 parses through the MAN file specified by SHELL_FILE_HANDLE and returns the
412 "Brief Description" for the .TH section as specified by Command. if the
413 command section is not found return EFI_NOT_FOUND.
414
415 Upon a sucessful return the caller is responsible to free the memory in *BriefDesc
416
417 @param[in] Handle FileHandle to read from
418 @param[in] Command name of command's section to find
419 @param[out] BriefDesc pointer to pointer to string where description goes.
420 @param[out] BriefSize pointer to size of allocated BriefDesc
421 @param[in,out] Ascii TRUE if the file is ASCII, FALSE otherwise, will be
422 set if the file handle is at the 0 position.
423
424 @retval EFI_OUT_OF_RESOURCES a memory allocation failed.
425 @retval EFI_SUCCESS the section was found and its description sotred in
426 an alloceted buffer.
427 **/
428 EFI_STATUS
429 EFIAPI
430 ManFileFindTitleSection(
431 IN SHELL_FILE_HANDLE Handle,
432 IN CONST CHAR16 *Command,
433 OUT CHAR16 **BriefDesc OPTIONAL,
434 OUT UINTN *BriefSize OPTIONAL,
435 IN OUT BOOLEAN *Ascii
436 )
437 {
438 EFI_STATUS Status;
439 CHAR16 *TitleString;
440 CHAR16 *ReadLine;
441 UINTN Size;
442 CHAR16 *TitleEnd;
443 UINTN TitleLen;
444 BOOLEAN Found;
445
446 if ( Handle == NULL
447 || Command == NULL
448 || (BriefDesc != NULL && BriefSize == NULL)
449 ){
450 return (EFI_INVALID_PARAMETER);
451 }
452
453 Status = EFI_SUCCESS;
454 Size = 1024;
455 Found = FALSE;
456
457 ReadLine = AllocateZeroPool(Size);
458 if (ReadLine == NULL) {
459 return (EFI_OUT_OF_RESOURCES);
460 }
461
462 TitleString = AllocatePool((4*sizeof(CHAR16)) + StrSize(Command));
463 if (TitleString == NULL) {
464 FreePool(ReadLine);
465 return (EFI_OUT_OF_RESOURCES);
466 }
467 StrCpy(TitleString, L".TH ");
468 StrCat(TitleString, Command);
469 TitleLen = StrLen(TitleString);
470 for (;!ShellFileHandleEof(Handle);Size = 1024) {
471 Status = ShellFileHandleReadLine(Handle, ReadLine, &Size, TRUE, Ascii);
472 if (ReadLine[0] == L'#') {
473 //
474 // Skip comment lines
475 //
476 continue;
477 }
478 //
479 // ignore too small of buffer...
480 //
481 if (Status == EFI_BUFFER_TOO_SMALL) {
482 Status = EFI_SUCCESS;
483 }
484 if (EFI_ERROR(Status)) {
485 break;
486 }
487 if (StrnCmp(ReadLine, TitleString, TitleLen) == 0) {
488 Found = TRUE;
489 //
490 // we found it so copy out the rest of the line into BriefDesc
491 // After skipping any spaces or zeroes
492 //
493 for ( TitleEnd = ReadLine+TitleLen
494 ; *TitleEnd == L' ' || *TitleEnd == L'0' || *TitleEnd == L'1'
495 ; TitleEnd++);
496 if (BriefDesc != NULL) {
497 *BriefSize = StrSize(TitleEnd);
498 *BriefDesc = AllocateZeroPool(*BriefSize);
499 if (*BriefDesc == NULL) {
500 Status = EFI_OUT_OF_RESOURCES;
501 break;
502 }
503 StrCpy(*BriefDesc, TitleEnd);
504 }
505 break;
506 }
507 }
508 FreePool(ReadLine);
509 FreePool(TitleString);
510 if (!Found && !EFI_ERROR(Status)) {
511 return (EFI_NOT_FOUND);
512 }
513 return (Status);
514 }
515
516 /**
517 This function returns the help information for the specified command. The help text
518 will be parsed from a UEFI Shell manual page. (see UEFI Shell 2.0 Appendix B)
519
520 If Sections is specified, then each section name listed will be compared in a casesensitive
521 manner, to the section names described in Appendix B. If the section exists,
522 it will be appended to the returned help text. If the section does not exist, no
523 information will be returned. If Sections is NULL, then all help text information
524 available will be returned.
525
526 if BriefDesc is NULL, then the breif description will not be savedd seperatly,
527 but placed first in the main HelpText.
528
529 @param[in] ManFileName Points to the NULL-terminated UEFI Shell MAN file name.
530 @param[in] Command Points to the NULL-terminated UEFI Shell command name.
531 @param[in] Sections Points to the NULL-terminated comma-delimited
532 section names to return. If NULL, then all
533 sections will be returned.
534 @param[out] BriefDesc On return, points to a callee-allocated buffer
535 containing brief description text.
536 @param[out] HelpText On return, points to a callee-allocated buffer
537 containing all specified help text.
538
539 @retval EFI_SUCCESS The help text was returned.
540 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the
541 returned help text.
542 @retval EFI_INVALID_PARAMETER HelpText is NULL
543 @retval EFI_NOT_FOUND There is no help text available for Command.
544 **/
545 EFI_STATUS
546 EFIAPI
547 ProcessManFile(
548 IN CONST CHAR16 *ManFileName,
549 IN CONST CHAR16 *Command,
550 IN CONST CHAR16 *Sections OPTIONAL,
551 OUT CHAR16 **BriefDesc OPTIONAL,
552 OUT CHAR16 **HelpText
553 )
554 {
555 CHAR16 *TempString;
556 SHELL_FILE_HANDLE FileHandle;
557 EFI_STATUS Status;
558 UINTN HelpSize;
559 UINTN BriefSize;
560 BOOLEAN Ascii;
561 CHAR16 *TempString2;
562 EFI_DEVICE_PATH_PROTOCOL *FileDevPath;
563 EFI_DEVICE_PATH_PROTOCOL *DevPath;
564
565 if ( ManFileName == NULL
566 || Command == NULL
567 || HelpText == NULL
568 ){
569 return (EFI_INVALID_PARAMETER);
570 }
571
572 HelpSize = 0;
573 BriefSize = 0;
574 TempString = NULL;
575 //
576 // See if it's in HII first
577 //
578 TempString = ShellCommandGetCommandHelp(Command);
579 if (TempString != NULL) {
580 TempString2 = TempString;
581 Status = ManBufferFindTitleSection(&TempString2, Command, BriefDesc, &BriefSize);
582 if (!EFI_ERROR(Status) && HelpText != NULL){
583 Status = ManBufferFindSections(TempString2, Sections, HelpText, &HelpSize);
584 }
585 } else {
586 FileHandle = NULL;
587 TempString = GetManFileName(ManFileName);
588
589 Status = SearchPathForFile(TempString, &FileHandle);
590 if (EFI_ERROR(Status)) {
591 FileDevPath = FileDevicePath(NULL, TempString);
592 DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, FileDevPath);
593 Status = InternalOpenFileDevicePath(DevPath, &FileHandle, EFI_FILE_MODE_READ, 0);
594 FreePool(FileDevPath);
595 FreePool(DevPath);
596 }
597
598 if (!EFI_ERROR(Status)) {
599 HelpSize = 0;
600 BriefSize = 0;
601 Status = ManFileFindTitleSection(FileHandle, Command, BriefDesc, &BriefSize, &Ascii);
602 if (!EFI_ERROR(Status) && HelpText != NULL){
603 Status = ManFileFindSections(FileHandle, Sections, HelpText, &HelpSize, Ascii);
604 }
605 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);
606 } else {
607 *HelpText = NULL;
608 }
609 }
610 if (TempString != NULL) {
611 FreePool(TempString);
612 }
613
614 return (Status);
615 }