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