]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Application/Shell/ConsoleLogger.c
ShellPkg: Clean up header file usage.
[mirror_edk2.git] / ShellPkg / Application / Shell / ConsoleLogger.c
1 /** @file
2 Provides interface to shell console logger.
3
4 Copyright (c) 2009 - 2011, 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 #include "Shell.h"
15
16 STATIC CONST CHAR16 mCrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
17
18 /**
19 Install our intermediate ConOut into the system table to
20 keep a log of all the info that is displayed to the user.
21
22 @param[in] ScreensToSave Sets how many screen-worths of data to save.
23 @param[out] ConsoleInfo The object to pass into later functions.
24
25 @retval EFI_SUCCESS The operation was successful.
26 @return other The operation failed.
27
28 @sa ConsoleLoggerResetBuffers
29 @sa InstallProtocolInterface
30 **/
31 EFI_STATUS
32 EFIAPI
33 ConsoleLoggerInstall(
34 IN CONST UINTN ScreensToSave,
35 OUT CONSOLE_LOGGER_PRIVATE_DATA **ConsoleInfo
36 )
37 {
38 EFI_STATUS Status;
39 ASSERT(ConsoleInfo != NULL);
40
41 (*ConsoleInfo) = AllocateZeroPool(sizeof(CONSOLE_LOGGER_PRIVATE_DATA));
42 if ((*ConsoleInfo) == NULL) {
43 return (EFI_OUT_OF_RESOURCES);
44 }
45
46 (*ConsoleInfo)->Signature = CONSOLE_LOGGER_PRIVATE_DATA_SIGNATURE;
47 (*ConsoleInfo)->OldConOut = gST->ConOut;
48 (*ConsoleInfo)->OldConHandle = gST->ConsoleOutHandle;
49 (*ConsoleInfo)->Buffer = NULL;
50 (*ConsoleInfo)->BufferSize = 0;
51 (*ConsoleInfo)->OriginalStartRow = 0;
52 (*ConsoleInfo)->CurrentStartRow = 0;
53 (*ConsoleInfo)->RowsPerScreen = 0;
54 (*ConsoleInfo)->ColsPerScreen = 0;
55 (*ConsoleInfo)->Attributes = NULL;
56 (*ConsoleInfo)->AttribSize = 0;
57 (*ConsoleInfo)->ScreenCount = ScreensToSave;
58 (*ConsoleInfo)->HistoryMode.MaxMode = 1;
59 (*ConsoleInfo)->HistoryMode.Mode = 0;
60 (*ConsoleInfo)->HistoryMode.Attribute = 0;
61 (*ConsoleInfo)->HistoryMode.CursorColumn = 0;
62 (*ConsoleInfo)->HistoryMode.CursorRow = 0;
63 (*ConsoleInfo)->HistoryMode.CursorVisible = FALSE;
64 (*ConsoleInfo)->OurConOut.Reset = ConsoleLoggerReset;
65 (*ConsoleInfo)->OurConOut.OutputString = ConsoleLoggerOutputString;
66 (*ConsoleInfo)->OurConOut.TestString = ConsoleLoggerTestString;
67 (*ConsoleInfo)->OurConOut.QueryMode = ConsoleLoggerQueryMode;
68 (*ConsoleInfo)->OurConOut.SetMode = ConsoleLoggerSetMode;
69 (*ConsoleInfo)->OurConOut.SetAttribute = ConsoleLoggerSetAttribute;
70 (*ConsoleInfo)->OurConOut.ClearScreen = ConsoleLoggerClearScreen;
71 (*ConsoleInfo)->OurConOut.SetCursorPosition = ConsoleLoggerSetCursorPosition;
72 (*ConsoleInfo)->OurConOut.EnableCursor = ConsoleLoggerEnableCursor;
73 (*ConsoleInfo)->OurConOut.Mode = gST->ConOut->Mode;
74 (*ConsoleInfo)->Enabled = TRUE;
75
76 Status = ConsoleLoggerResetBuffers(*ConsoleInfo);
77 if (EFI_ERROR(Status)) {
78 SHELL_FREE_NON_NULL((*ConsoleInfo));
79 *ConsoleInfo = NULL;
80 return (Status);
81 }
82
83 Status = gBS->InstallProtocolInterface(&gImageHandle, &gEfiSimpleTextOutProtocolGuid, EFI_NATIVE_INTERFACE, (VOID*)&((*ConsoleInfo)->OurConOut));
84 if (EFI_ERROR(Status)) {
85 SHELL_FREE_NON_NULL((*ConsoleInfo)->Buffer);
86 SHELL_FREE_NON_NULL((*ConsoleInfo)->Attributes);
87 SHELL_FREE_NON_NULL((*ConsoleInfo));
88 *ConsoleInfo = NULL;
89 return (Status);
90 }
91
92 gST->ConsoleOutHandle = gImageHandle;
93 gST->ConOut = &(*ConsoleInfo)->OurConOut;
94
95 return (Status);
96 }
97
98 /**
99 Return the system to the state it was before InstallConsoleLogger
100 was installed.
101
102 @param[in] ConsoleInfo The object from the install function.
103
104 @retval EFI_SUCCESS The operation was successful
105 @return other The operation failed. This was from UninstallProtocolInterface.
106 **/
107 EFI_STATUS
108 EFIAPI
109 ConsoleLoggerUninstall(
110 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
111 )
112 {
113 ASSERT(ConsoleInfo != NULL);
114 ASSERT(ConsoleInfo->OldConOut != NULL);
115
116 if (ConsoleInfo->Buffer != NULL) {
117 FreePool(ConsoleInfo->Buffer);
118 DEBUG_CODE(ConsoleInfo->Buffer = NULL;);
119 DEBUG_CODE(ConsoleInfo->BufferSize = 0;);
120 }
121 if (ConsoleInfo->Attributes != NULL) {
122 FreePool(ConsoleInfo->Attributes);
123 DEBUG_CODE(ConsoleInfo->Attributes = NULL;);
124 DEBUG_CODE(ConsoleInfo->AttribSize = 0;);
125 }
126
127 gST->ConsoleOutHandle = ConsoleInfo->OldConHandle;
128 gST->ConOut = ConsoleInfo->OldConOut;
129
130 return (gBS->UninstallProtocolInterface(gImageHandle, &gEfiSimpleTextOutProtocolGuid, (VOID*)&ConsoleInfo->OurConOut));
131 }
132
133 /**
134 Displays previously logged output back to the screen.
135
136 This will scroll the screen forwards and backwards through the log of previous
137 output. If Rows is 0 then the size of 1/2 the screen will be scrolled. If Rows
138 is (UINTN)(-1) then the size of the screen will be scrolled.
139
140 @param[in] Forward If TRUE then the log will be displayed forwards (scroll to newer).
141 If FALSE then the log will be displayed backwards (scroll to older).
142 @param[in] Rows Determines how many rows the log should scroll.
143 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
144 **/
145 EFI_STATUS
146 EFIAPI
147 ConsoleLoggerDisplayHistory(
148 IN CONST BOOLEAN Forward,
149 IN CONST UINTN Rows,
150 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
151 )
152 {
153 UINTN RowChange;
154
155 ASSERT(ConsoleInfo != NULL);
156
157 //
158 // Calculate the row number change
159 //
160 switch (Rows) {
161 case ((UINTN)(-1)):
162 RowChange = ConsoleInfo->RowsPerScreen;
163 break;
164 case (0):
165 RowChange = ConsoleInfo->RowsPerScreen / 2;
166 break;
167 default:
168 RowChange = Rows;
169 break;
170 }
171
172 //
173 // Do the math for direction
174 //
175 if (Forward) {
176 if ((ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow) < RowChange) {
177 RowChange = ConsoleInfo->OriginalStartRow - ConsoleInfo->CurrentStartRow;
178 }
179 } else {
180 if (ConsoleInfo->CurrentStartRow < RowChange) {
181 RowChange = ConsoleInfo->CurrentStartRow;
182 }
183 }
184
185 //
186 // If we are already at one end or the other
187 //
188 if (RowChange == 0) {
189 return (EFI_SUCCESS);
190 }
191
192 //
193 // Clear the screen
194 //
195 ConsoleInfo->OldConOut->ClearScreen(ConsoleInfo->OldConOut);
196
197 //
198 // Set the new start row
199 //
200 if (Forward) {
201 ConsoleInfo->CurrentStartRow += RowChange;
202 } else {
203 ConsoleInfo->CurrentStartRow -= RowChange;
204 }
205
206 //
207 // Change the screen
208 //
209 return (UpdateDisplayFromHistory(ConsoleInfo));
210 }
211
212 /**
213 Function to return to normal output whent he scrolling is complete.
214 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
215
216 @retval EFI_SUCCESS The operation was successful.
217 @return other The operation failed. See UpdateDisplayFromHistory.
218
219 @sa UpdateDisplayFromHistory
220 **/
221 EFI_STATUS
222 EFIAPI
223 ConsoleLoggerStopHistory(
224 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
225 )
226 {
227 ASSERT(ConsoleInfo != NULL);
228 if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
229 return (EFI_SUCCESS);
230 }
231 ConsoleInfo->CurrentStartRow = ConsoleInfo->OriginalStartRow;
232 return (UpdateDisplayFromHistory(ConsoleInfo));
233 }
234
235 /**
236 Updates the hidden ConOut to be displaying the correct stuff.
237 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
238
239 @retval EFI_SUCCESS The operation was successful.
240 @return other The operation failed.
241 **/
242 EFI_STATUS
243 EFIAPI
244 UpdateDisplayFromHistory(
245 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
246 )
247 {
248 EFI_STATUS Status;
249 EFI_STATUS RetVal;
250 CHAR16 *Screen;
251 INT32 *Attributes;
252 UINTN CurrentRow;
253 CHAR16 TempCharHolder;
254 UINTN Column;
255 INT32 CurrentAttrib;
256 UINTN CurrentColumn;
257 CHAR16 *StringSegment;
258 CHAR16 *StringSegmentEnd;
259 CHAR16 StringSegmentEndChar;
260 INT32 OrigAttribute;
261
262 ASSERT(ConsoleInfo != NULL);
263 TempCharHolder = CHAR_NULL;
264 RetVal = EFI_SUCCESS;
265 OrigAttribute = ConsoleInfo->OldConOut->Mode->Attribute;
266
267 //
268 // Disable cursor visibility and move it to the top left corner
269 //
270 ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, FALSE);
271 ConsoleInfo->OldConOut->SetCursorPosition (ConsoleInfo->OldConOut, 0, 0);
272
273 Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
274 Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
275 for ( CurrentRow = 0
276 ; CurrentRow < ConsoleInfo->RowsPerScreen
277 ; CurrentRow++
278 , Screen += (ConsoleInfo->ColsPerScreen + 2)
279 , Attributes += ConsoleInfo->ColsPerScreen
280 ){
281 //
282 // dont use the last char - prevents screen scroll
283 //
284 if (CurrentRow == (ConsoleInfo->RowsPerScreen-1)){
285 TempCharHolder = Screen[ConsoleInfo->ColsPerScreen - 1];
286 Screen[ConsoleInfo->ColsPerScreen - 1] = CHAR_NULL;
287 }
288
289 for ( Column = 0
290 ; Column < ConsoleInfo->ColsPerScreen
291 ; Column++
292 ){
293 if (Screen[Column] != CHAR_NULL) {
294 CurrentAttrib = Attributes[Column];
295 CurrentColumn = Column;
296 StringSegment = &Screen[Column];
297
298 //
299 // Find the first char with a different arrribute and make that temporarily NULL
300 // so we can do fewer printout statements. (later) restore that one and we will
301 // start at that collumn on the next loop.
302 //
303 StringSegmentEndChar = CHAR_NULL;
304 for ( StringSegmentEnd = StringSegment
305 ; StringSegmentEnd != CHAR_NULL
306 ; StringSegmentEnd++
307 , Column++
308 ){
309 if (Attributes[Column] != CurrentAttrib) {
310 StringSegmentEndChar = *StringSegmentEnd;
311 *StringSegmentEnd = CHAR_NULL;
312 break;
313 }
314 } // StringSegmentEnd loop
315
316 //
317 // Now write out as much as had the same Attributes
318 //
319
320 ConsoleInfo->OldConOut->SetAttribute(ConsoleInfo->OldConOut, CurrentAttrib);
321 ConsoleInfo->OldConOut->SetCursorPosition(ConsoleInfo->OldConOut, CurrentColumn, CurrentRow);
322 Status = ConsoleInfo->OldConOut->OutputString(ConsoleInfo->OldConOut, StringSegment);
323
324 if (EFI_ERROR(Status)) {
325 ASSERT(FALSE);
326 RetVal = Status;
327 }
328
329 //
330 // If we found a change in attribute put the character back and decrement the column
331 // so when it increments it will point at that character and we will start printing
332 // a segment with that new attribute
333 //
334 if (StringSegmentEndChar != CHAR_NULL) {
335 *StringSegmentEnd = StringSegmentEndChar;
336 StringSegmentEndChar = CHAR_NULL;
337 Column--;
338 }
339 }
340 } // column for loop
341
342 //
343 // If we removed the last char and this was the last row put it back
344 //
345 if (TempCharHolder != CHAR_NULL) {
346 Screen[ConsoleInfo->ColsPerScreen - 1] = TempCharHolder;
347 TempCharHolder = CHAR_NULL;
348 }
349 } // row for loop
350
351 //
352 // If we are setting the screen back to original turn on the cursor and make it visible
353 // and set the attributes back to what they were
354 //
355 if (ConsoleInfo->CurrentStartRow == ConsoleInfo->OriginalStartRow) {
356 ConsoleInfo->OldConOut->SetAttribute (
357 ConsoleInfo->OldConOut,
358 ConsoleInfo->HistoryMode.Attribute
359 );
360 ConsoleInfo->OldConOut->SetCursorPosition (
361 ConsoleInfo->OldConOut,
362 ConsoleInfo->HistoryMode.CursorColumn,
363 ConsoleInfo->HistoryMode.CursorRow - ConsoleInfo->OriginalStartRow
364 );
365
366 Status = ConsoleInfo->OldConOut->EnableCursor (
367 ConsoleInfo->OldConOut,
368 ConsoleInfo->HistoryMode.CursorVisible
369 );
370 if (EFI_ERROR (Status)) {
371 RetVal = Status;
372 }
373 } else {
374 ConsoleInfo->OldConOut->SetAttribute (
375 ConsoleInfo->OldConOut,
376 OrigAttribute
377 );
378 }
379
380 return (RetVal);
381 }
382
383 /**
384 Reset the text output device hardware and optionaly run diagnostics
385
386 @param This pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
387 @param ExtendedVerification Indicates that a more extensive test may be performed
388
389 @retval EFI_SUCCESS The text output device was reset.
390 @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and
391 could not be reset.
392 **/
393 EFI_STATUS
394 EFIAPI
395 ConsoleLoggerReset (
396 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
397 IN BOOLEAN ExtendedVerification
398 )
399 {
400 EFI_STATUS Status;
401 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
402 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
403
404 //
405 // Forward the request to the original ConOut
406 //
407 Status = ConsoleInfo->OldConOut->Reset (ConsoleInfo->OldConOut, ExtendedVerification);
408
409 //
410 // Check that the buffers are still correct for logging
411 //
412 if (!EFI_ERROR (Status)) {
413 ConsoleLoggerResetBuffers(ConsoleInfo);
414 }
415
416 return Status;
417 }
418
419 /**
420 Appends a string to the history buffer. If the buffer is full then the oldest
421 information in the buffer will be dropped. Information is added in a line by
422 line manner such that an empty line takes up just as much space as a full line.
423
424 @param[in] String String pointer to add.
425 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
426 **/
427 EFI_STATUS
428 EFIAPI
429 AppendStringToHistory(
430 IN CONST CHAR16 *String,
431 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
432 )
433 {
434 CONST CHAR16 *Walker;
435 UINTN CopySize;
436 UINTN PrintIndex;
437 UINTN Index;
438
439 ASSERT(ConsoleInfo != NULL);
440
441 for ( Walker = String
442 ; Walker != NULL && *Walker != CHAR_NULL
443 ; Walker++
444 ){
445 switch (*Walker) {
446 case (CHAR_BACKSPACE):
447 if (ConsoleInfo->HistoryMode.CursorColumn > 0) {
448 ConsoleInfo->HistoryMode.CursorColumn--;
449 }
450 break;
451 case (CHAR_LINEFEED):
452 if (ConsoleInfo->HistoryMode.CursorRow >= (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1)) {
453 //
454 // Should never be bigger
455 //
456 ASSERT(ConsoleInfo->HistoryMode.CursorRow == (INT32)((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)-1));
457
458 //
459 // scroll history attributes 'up' 1 row and set the last row to default attribute
460 //
461 CopySize = ConsoleInfo->ColsPerScreen
462 * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
463 * sizeof(ConsoleInfo->Attributes[0]);
464 ASSERT(CopySize < ConsoleInfo->AttribSize);
465 CopyMem(
466 ConsoleInfo->Attributes,
467 ConsoleInfo->Attributes + ConsoleInfo->ColsPerScreen,
468 CopySize
469 );
470
471 for ( Index = 0
472 ; Index < ConsoleInfo->ColsPerScreen
473 ; Index++
474 ){
475 *(ConsoleInfo->Attributes + (CopySize/sizeof(ConsoleInfo->Attributes[0])) + Index) = ConsoleInfo->HistoryMode.Attribute;
476 }
477
478 //
479 // scroll history buffer 'up' 1 row and set the last row to spaces (L' ')
480 //
481 CopySize = (ConsoleInfo->ColsPerScreen + 2)
482 * ((ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount) - 1)
483 * sizeof(ConsoleInfo->Buffer[0]);
484 ASSERT(CopySize < ConsoleInfo->BufferSize);
485 CopyMem(
486 ConsoleInfo->Buffer,
487 ConsoleInfo->Buffer + (ConsoleInfo->ColsPerScreen + 2),
488 CopySize
489 );
490
491 //
492 // Set that last row of chars to spaces
493 //
494 SetMem16(((UINT8*)ConsoleInfo->Buffer)+CopySize, ConsoleInfo->ColsPerScreen*sizeof(CHAR16), L' ');
495 } else {
496 //
497 // we are not on the last row
498 //
499
500 //
501 // We should not be scrolling history
502 //
503 ASSERT (ConsoleInfo->OriginalStartRow == ConsoleInfo->CurrentStartRow);
504 //
505 // are we at the end of a row?
506 //
507 if (ConsoleInfo->HistoryMode.CursorRow == (INT32) (ConsoleInfo->OriginalStartRow + ConsoleInfo->RowsPerScreen - 1)) {
508 ConsoleInfo->OriginalStartRow++;
509 ConsoleInfo->CurrentStartRow++;
510 }
511 ConsoleInfo->HistoryMode.CursorRow++;
512 }
513 break;
514 case (CHAR_CARRIAGE_RETURN):
515 //
516 // Move the cursor to the beginning of the current row.
517 //
518 ConsoleInfo->HistoryMode.CursorColumn = 0;
519 break;
520 default:
521 //
522 // Acrtually print characters into the history buffer
523 //
524
525 PrintIndex = ConsoleInfo->HistoryMode.CursorRow * ConsoleInfo->ColsPerScreen + ConsoleInfo->HistoryMode.CursorColumn;
526
527 for ( // no initializer needed
528 ; ConsoleInfo->HistoryMode.CursorColumn < (INT32) ConsoleInfo->ColsPerScreen
529 ; ConsoleInfo->HistoryMode.CursorColumn++
530 , PrintIndex++
531 , Walker++
532 ){
533 if (*Walker == CHAR_NULL
534 ||*Walker == CHAR_BACKSPACE
535 ||*Walker == CHAR_LINEFEED
536 ||*Walker == CHAR_CARRIAGE_RETURN
537 ){
538 Walker--;
539 break;
540 }
541 //
542 // The buffer is 2*CursorRow more since it has that many \r\n characters at the end of each row.
543 //
544
545 ASSERT(PrintIndex + ConsoleInfo->HistoryMode.CursorRow < ConsoleInfo->BufferSize);
546 ConsoleInfo->Buffer[PrintIndex + (2*ConsoleInfo->HistoryMode.CursorRow)] = *Walker;
547 ASSERT(PrintIndex < ConsoleInfo->AttribSize);
548 ConsoleInfo->Attributes[PrintIndex] = ConsoleInfo->HistoryMode.Attribute;
549 } // for loop
550
551 //
552 // Add the carriage return and line feed at the end of the lines
553 //
554 if (ConsoleInfo->HistoryMode.CursorColumn >= (INT32)ConsoleInfo->ColsPerScreen) {
555 AppendStringToHistory(L"\r\n", ConsoleInfo);
556 Walker--;
557 }
558
559 break;
560 } // switch for character
561 } // for loop
562
563 return (EFI_SUCCESS);
564 }
565
566 /**
567 Worker function to handle printing the output to the screen
568 and the history buffer
569
570 @param[in] String The string to output
571 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
572
573 @retval EFI_SUCCESS The string was printed
574 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
575 the text.
576 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
577 defined text mode.
578 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
579 characters in the Unicode string could not be
580 rendered and were skipped.
581 **/
582 EFI_STATUS
583 EFIAPI
584 ConsoleLoggerOutputStringSplit(
585 IN CONST CHAR16 *String,
586 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
587 )
588 {
589 EFI_STATUS Status;
590
591 //
592 // Forward the request to the original ConOut
593 //
594 Status = ConsoleInfo->OldConOut->OutputString (ConsoleInfo->OldConOut, (CHAR16*)String);
595
596 if (EFI_ERROR(Status)) {
597 return (Status);
598 }
599
600 return (AppendStringToHistory(String, ConsoleInfo));
601 }
602
603 /**
604 Function to handle page break mode.
605
606 This function will prompt for continue or break.
607
608 @retval EFI_SUCCESS Continue was choosen
609 @return other Break was choosen
610 **/
611 EFI_STATUS
612 EFIAPI
613 ConsoleLoggerDoPageBreak(
614 VOID
615 )
616 {
617 SHELL_PROMPT_RESPONSE *Resp;
618 EFI_STATUS Status;
619
620 Resp = NULL;
621 ASSERT(ShellInfoObject.PageBreakEnabled);
622 ShellInfoObject.PageBreakEnabled = FALSE;
623 Status = ShellPromptForResponseHii(ShellPromptResponseTypeQuitContinue, STRING_TOKEN(STR_SHELL_QUIT_CONT), ShellInfoObject.HiiHandle, (VOID**)&Resp);
624 ShellInfoObject.PageBreakEnabled = TRUE;
625 ASSERT(Resp != NULL);
626 if (Resp == NULL) {
627 return (EFI_NOT_FOUND);
628 }
629 if (EFI_ERROR(Status)) {
630 if (Resp != NULL) {
631 FreePool(Resp);
632 }
633 return (Status);
634 }
635 if (*Resp == ShellPromptResponseContinue) {
636 FreePool(Resp);
637 ShellInfoObject.ConsoleInfo->RowCounter = 0;
638 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorRow = 0;
639 // ShellInfoObject.ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
640
641 return (EFI_SUCCESS);
642 } else if (*Resp == ShellPromptResponseQuit) {
643 FreePool(Resp);
644 ShellInfoObject.ConsoleInfo->Enabled = FALSE;
645 return (EFI_DEVICE_ERROR);
646 } else {
647 ASSERT(FALSE);
648 }
649 return (EFI_SUCCESS);
650 }
651 /**
652 Worker function to handle printing the output with page breaks.
653
654 @param[in] String The string to output
655 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
656
657 @retval EFI_SUCCESS The string was printed
658 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
659 the text.
660 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
661 defined text mode.
662 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
663 characters in the Unicode string could not be
664 rendered and were skipped.
665 **/
666 EFI_STATUS
667 EFIAPI
668 ConsoleLoggerPrintWithPageBreak(
669 IN CONST CHAR16 *String,
670 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
671 )
672 {
673 CONST CHAR16 *Walker;
674 CONST CHAR16 *LineStart;
675 CHAR16 *StringCopy;
676 CHAR16 TempChar;
677
678 StringCopy = NULL;
679 StringCopy = StrnCatGrow(&StringCopy, NULL, String, 0);
680 if (StringCopy == NULL) {
681 return (EFI_OUT_OF_RESOURCES);
682 }
683
684 for ( Walker = StringCopy
685 , LineStart = StringCopy
686 ; Walker != NULL && *Walker != CHAR_NULL
687 ; Walker++
688 ){
689 switch (*Walker) {
690 case (CHAR_BACKSPACE):
691 if (ConsoleInfo->OurConOut.Mode->CursorColumn > 0) {
692 ConsoleInfo->OurConOut.Mode->CursorColumn--;
693 }
694 break;
695 case (CHAR_LINEFEED):
696 //
697 // add a temp NULL terminator
698 //
699 TempChar = *(Walker + 1);
700 *((CHAR16*)(Walker+1)) = CHAR_NULL;
701
702 //
703 // output the string
704 //
705 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
706
707 //
708 // restore the temp NULL terminator to it's original character
709 //
710 *((CHAR16*)(Walker+1)) = TempChar;
711
712 //
713 // Update LineStart Variable
714 //
715 LineStart = Walker + 1;
716
717 //
718 // increment row count
719 //
720 ShellInfoObject.ConsoleInfo->RowCounter++;
721 ConsoleInfo->OurConOut.Mode->CursorRow++;
722
723 break;
724 case (CHAR_CARRIAGE_RETURN):
725 //
726 // Move the cursor to the beginning of the current row.
727 //
728 ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
729 break;
730 default:
731 //
732 // increment column count
733 //
734 ConsoleInfo->OurConOut.Mode->CursorColumn++;
735 //
736 // check if that is the last column
737 //
738 if ((INTN)ConsoleInfo->ColsPerScreen == ConsoleInfo->OurConOut.Mode->CursorColumn + 1) {
739 //
740 // output a line similar to the linefeed character.
741 //
742
743 //
744 // add a temp NULL terminator
745 //
746 TempChar = *(Walker + 1);
747 *((CHAR16*)(Walker+1)) = CHAR_NULL;
748
749 //
750 // output the string
751 //
752 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
753
754 //
755 // restore the temp NULL terminator to it's original character
756 //
757 *((CHAR16*)(Walker+1)) = TempChar;
758
759 //
760 // Update LineStart Variable
761 //
762 LineStart = Walker + 1;
763
764 //
765 // increment row count and zero the column
766 //
767 ShellInfoObject.ConsoleInfo->RowCounter++;
768 ConsoleInfo->OurConOut.Mode->CursorRow++;
769 ConsoleInfo->OurConOut.Mode->CursorColumn = 0;
770 } // last column on line
771 break;
772 } // switch for character
773
774 //
775 // check if that was the last printable row. If yes handle PageBreak mode
776 //
777 if ((ConsoleInfo->RowsPerScreen) -1 == ShellInfoObject.ConsoleInfo->RowCounter) {
778 if (EFI_ERROR(ConsoleLoggerDoPageBreak())) {
779 //
780 // We got an error which means 'break' and halt the printing
781 //
782 SHELL_FREE_NON_NULL(StringCopy);
783 return (EFI_DEVICE_ERROR);
784 }
785 }
786 } // for loop
787
788 if (LineStart != NULL && *LineStart != CHAR_NULL) {
789 ConsoleLoggerOutputStringSplit (LineStart, ConsoleInfo);
790 }
791
792 SHELL_FREE_NON_NULL(StringCopy);
793 return (EFI_SUCCESS);
794 }
795
796 /**
797 Write a Unicode string to the output device.
798
799 @param[in] This Protocol instance pointer.
800 @param[in] WString The NULL-terminated Unicode string to be displayed on the output
801 device(s). All output devices must also support the Unicode
802 drawing defined in this file.
803 @retval EFI_SUCCESS The string was output to the device.
804 @retval EFI_DEVICE_ERROR The device reported an error while attempting to output
805 the text.
806 @retval EFI_UNSUPPORTED The output device's mode is not currently in a
807 defined text mode.
808 @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the
809 characters in the Unicode string could not be
810 rendered and were skipped.
811 **/
812 EFI_STATUS
813 EFIAPI
814 ConsoleLoggerOutputString (
815 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
816 IN CHAR16 *WString
817 )
818 {
819 EFI_INPUT_KEY Key;
820 UINTN EventIndex;
821 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
822 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
823 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
824 return (EFI_UNSUPPORTED);
825 }
826 ASSERT(ShellInfoObject.ConsoleInfo == ConsoleInfo);
827 if (ShellInfoObject.HaltOutput) {
828 //
829 // just get some key
830 //
831 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
832 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
833 ShellInfoObject.HaltOutput = FALSE;
834 }
835 if (!ShellInfoObject.ConsoleInfo->Enabled) {
836 return (EFI_DEVICE_ERROR);
837 } else if (ShellInfoObject.PageBreakEnabled) {
838 return (ConsoleLoggerPrintWithPageBreak(WString, ConsoleInfo));
839 } else {
840 return (ConsoleLoggerOutputStringSplit(WString, ConsoleInfo));
841 }
842 }
843
844 /**
845 Verifies that all characters in a Unicode string can be output to the
846 target device.
847
848 @param[in] This Protocol instance pointer.
849 @param[in] WString The NULL-terminated Unicode string to be examined for the output
850 device(s).
851
852 @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
853 @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be
854 rendered by one or more of the output devices mapped
855 by the EFI handle.
856
857 **/
858 EFI_STATUS
859 EFIAPI
860 ConsoleLoggerTestString (
861 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
862 IN CHAR16 *WString
863 )
864 {
865 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
866 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
867 //
868 // Forward the request to the original ConOut
869 //
870 return (ConsoleInfo->OldConOut->TestString (ConsoleInfo->OldConOut, WString));
871 }
872
873 /**
874 Returns information for an available text mode that the output device(s)
875 supports.
876
877 @param[in] This Protocol instance pointer.
878 @param[in] ModeNumber The mode number to return information on.
879 @param[out] Columns Upon return, the number of columns in the selected geometry
880 @param[out] Rows Upon return, the number of rows in the selected geometry
881
882 @retval EFI_SUCCESS The requested mode information was returned.
883 @retval EFI_DEVICE_ERROR The device had an error and could not
884 complete the request.
885 @retval EFI_UNSUPPORTED The mode number was not valid.
886 **/
887 EFI_STATUS
888 EFIAPI
889 ConsoleLoggerQueryMode (
890 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
891 IN UINTN ModeNumber,
892 OUT UINTN *Columns,
893 OUT UINTN *Rows
894 )
895 {
896 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
897 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
898 //
899 // Forward the request to the original ConOut
900 //
901 return (ConsoleInfo->OldConOut->QueryMode (
902 ConsoleInfo->OldConOut,
903 ModeNumber,
904 Columns,
905 Rows
906 ));
907 }
908
909 /**
910 Sets the output device(s) to a specified mode.
911
912 @param[in] This Protocol instance pointer.
913 @param[in] ModeNumber The mode number to set.
914
915
916 @retval EFI_SUCCESS The requested text mode was set.
917 @retval EFI_DEVICE_ERROR The device had an error and
918 could not complete the request.
919 @retval EFI_UNSUPPORTED The mode number was not valid.
920 **/
921 EFI_STATUS
922 EFIAPI
923 ConsoleLoggerSetMode (
924 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
925 IN UINTN ModeNumber
926 )
927 {
928 EFI_STATUS Status;
929
930 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
931 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
932
933 //
934 // Forward the request to the original ConOut
935 //
936 Status = ConsoleInfo->OldConOut->SetMode (ConsoleInfo->OldConOut, ModeNumber);
937
938 //
939 // Check that the buffers are still correct for logging
940 //
941 if (!EFI_ERROR (Status)) {
942 ConsoleInfo->OurConOut.Mode = gST->ConOut->Mode;
943 ConsoleLoggerResetBuffers(ConsoleInfo);
944 }
945
946 return Status;
947 }
948
949 /**
950 Sets the background and foreground colors for the OutputString () and
951 ClearScreen () functions.
952
953 @param[in] This Protocol instance pointer.
954 @param[in] Attribute The attribute to set. Bits 0..3 are the foreground color, and
955 bits 4..6 are the background color. All other bits are undefined
956 and must be zero. The valid Attributes are defined in this file.
957
958 @retval EFI_SUCCESS The attribute was set.
959 @retval EFI_DEVICE_ERROR The device had an error and
960 could not complete the request.
961 @retval EFI_UNSUPPORTED The attribute requested is not defined.
962
963 **/
964 EFI_STATUS
965 EFIAPI
966 ConsoleLoggerSetAttribute (
967 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
968 IN UINTN Attribute
969 )
970 {
971 EFI_STATUS Status;
972
973 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
974 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
975
976 //
977 // Forward the request to the original ConOut
978 //
979 Status = ConsoleInfo->OldConOut->SetAttribute (ConsoleInfo->OldConOut, Attribute);
980
981 //
982 // Record console output history
983 //
984 if (!EFI_ERROR (Status)) {
985 ConsoleInfo->HistoryMode.Attribute = (INT32) Attribute;
986 }
987
988 return Status;
989 }
990
991 /**
992 Clears the output device(s) display to the currently selected background
993 color.
994
995 @param[in] This Protocol instance pointer.
996
997 @retval EFI_SUCCESS The operation completed successfully.
998 @retval EFI_DEVICE_ERROR The device had an error and
999 could not complete the request.
1000 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1001 **/
1002 EFI_STATUS
1003 EFIAPI
1004 ConsoleLoggerClearScreen (
1005 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
1006 )
1007 {
1008 EFI_STATUS Status;
1009 CHAR16 *Screen;
1010 INT32 *Attributes;
1011 UINTN Row;
1012 UINTN Column;
1013 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1014
1015 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
1016 return (EFI_UNSUPPORTED);
1017 }
1018
1019 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1020
1021 //
1022 // Forward the request to the original ConOut
1023 //
1024 Status = ConsoleInfo->OldConOut->ClearScreen (ConsoleInfo->OldConOut);
1025
1026 //
1027 // Record console output history
1028 //
1029 if (!EFI_ERROR (Status)) {
1030 Screen = &ConsoleInfo->Buffer[(ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->CurrentStartRow];
1031 Attributes = &ConsoleInfo->Attributes[ConsoleInfo->ColsPerScreen * ConsoleInfo->CurrentStartRow];
1032 for ( Row = ConsoleInfo->OriginalStartRow
1033 ; Row < (ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount)
1034 ; Row++
1035 ){
1036 for ( Column = 0
1037 ; Column < ConsoleInfo->ColsPerScreen
1038 ; Column++
1039 , Screen++
1040 , Attributes++
1041 ){
1042 *Screen = L' ';
1043 *Attributes = ConsoleInfo->OldConOut->Mode->Attribute;
1044 }
1045 //
1046 // Skip the NULL on each column end in text buffer only
1047 //
1048 Screen += 2;
1049 }
1050 ConsoleInfo->HistoryMode.CursorColumn = 0;
1051 ConsoleInfo->HistoryMode.CursorRow = 0;
1052 }
1053
1054 return Status;
1055 }
1056
1057 /**
1058 Sets the current coordinates of the cursor position
1059
1060 @param[in] This Protocol instance pointer.
1061 @param[in] Column Column to put the cursor in. Must be between zero and Column returned from QueryMode
1062 @param[in] Row Row to put the cursor in. Must be between zero and Row returned from QueryMode
1063
1064 @retval EFI_SUCCESS The operation completed successfully.
1065 @retval EFI_DEVICE_ERROR The device had an error and
1066 could not complete the request.
1067 @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the
1068 cursor position is invalid for the current mode.
1069 **/
1070 EFI_STATUS
1071 EFIAPI
1072 ConsoleLoggerSetCursorPosition (
1073 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1074 IN UINTN Column,
1075 IN UINTN Row
1076 )
1077 {
1078 EFI_STATUS Status;
1079 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1080
1081 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {
1082 return (EFI_UNSUPPORTED);
1083 }
1084
1085 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1086 //
1087 // Forward the request to the original ConOut
1088 //
1089 Status = ConsoleInfo->OldConOut->SetCursorPosition (
1090 ConsoleInfo->OldConOut,
1091 Column,
1092 Row
1093 );
1094
1095 //
1096 // Record console output history
1097 //
1098 if (!EFI_ERROR (Status)) {
1099 ConsoleInfo->HistoryMode.CursorColumn = (INT32)Column;
1100 ConsoleInfo->HistoryMode.CursorRow = (INT32)(ConsoleInfo->OriginalStartRow + Row);
1101 }
1102
1103 return Status;
1104 }
1105
1106 /**
1107 Makes the cursor visible or invisible
1108
1109 @param[in] This Protocol instance pointer.
1110 @param[in] Visible If TRUE, the cursor is set to be visible. If FALSE, the cursor is
1111 set to be invisible.
1112
1113 @retval EFI_SUCCESS The operation completed successfully.
1114 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1115 request, or the device does not support changing
1116 the cursor mode.
1117 @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
1118 **/
1119 EFI_STATUS
1120 EFIAPI
1121 ConsoleLoggerEnableCursor (
1122 IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
1123 IN BOOLEAN Visible
1124 )
1125 {
1126 EFI_STATUS Status;
1127
1128 CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo;
1129 ConsoleInfo = CONSOLE_LOGGER_PRIVATE_DATA_FROM_THIS(This);
1130 //
1131 // Forward the request to the original ConOut
1132 //
1133 Status = ConsoleInfo->OldConOut->EnableCursor (ConsoleInfo->OldConOut, Visible);
1134
1135 //
1136 // Record console output history
1137 //
1138 if (!EFI_ERROR (Status)) {
1139 ConsoleInfo->HistoryMode.CursorVisible = Visible;
1140 }
1141
1142 return Status;
1143 }
1144
1145 /**
1146 Function to update and verify that the current buffers are correct.
1147
1148 @param[in] ConsoleInfo The pointer to the instance of the console logger information.
1149
1150 This will be used when a mode has changed or a reset ocurred to verify all
1151 history buffers.
1152 **/
1153 EFI_STATUS
1154 EFIAPI
1155 ConsoleLoggerResetBuffers(
1156 IN CONSOLE_LOGGER_PRIVATE_DATA *ConsoleInfo
1157 )
1158 {
1159 EFI_STATUS Status;
1160
1161 if (ConsoleInfo->Buffer != NULL) {
1162 FreePool(ConsoleInfo->Buffer);
1163 ConsoleInfo->Buffer = NULL;
1164 ConsoleInfo->BufferSize = 0;
1165 }
1166 if (ConsoleInfo->Attributes != NULL) {
1167 FreePool(ConsoleInfo->Attributes);
1168 ConsoleInfo->Attributes = NULL;
1169 ConsoleInfo->AttribSize = 0;
1170 }
1171
1172 Status = gST->ConOut->QueryMode (gST->ConOut, gST->ConOut->Mode->Mode, &ConsoleInfo->ColsPerScreen, &ConsoleInfo->RowsPerScreen);
1173 if (EFI_ERROR(Status)){
1174 return (Status);
1175 }
1176
1177 ConsoleInfo->BufferSize = (ConsoleInfo->ColsPerScreen + 2) * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Buffer[0]);
1178 ConsoleInfo->AttribSize = ConsoleInfo->ColsPerScreen * ConsoleInfo->RowsPerScreen * ConsoleInfo->ScreenCount * sizeof(ConsoleInfo->Attributes[0]);
1179
1180 ConsoleInfo->Buffer = (CHAR16*)AllocateZeroPool(ConsoleInfo->BufferSize);
1181
1182 if (ConsoleInfo->Buffer == NULL) {
1183 return (EFI_OUT_OF_RESOURCES);
1184 }
1185
1186 ConsoleInfo->Attributes = (INT32*)AllocateZeroPool(ConsoleInfo->AttribSize);
1187 if (ConsoleInfo->Attributes == NULL) {
1188 FreePool(ConsoleInfo->Buffer);
1189 ConsoleInfo->Buffer = NULL;
1190 return (EFI_OUT_OF_RESOURCES);
1191 }
1192
1193 CopyMem (&ConsoleInfo->HistoryMode, ConsoleInfo->OldConOut->Mode, sizeof (EFI_SIMPLE_TEXT_OUTPUT_MODE));
1194
1195 return (EFI_SUCCESS);
1196 }