| /** @file | |
| Canonical Interactive Input Function. | |
| The functions assume that isatty() is TRUE at the time they are called. | |
| Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials are licensed and made available | |
| under the terms and conditions of the BSD License which accompanies this | |
| distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <Uefi.h> | |
| #include <LibConfig.h> | |
| #include <errno.h> | |
| #include <sys/syslimits.h> | |
| #include <sys/termios.h> | |
| #include <Device/IIO.h> | |
| #include <MainData.h> | |
| #include "IIOutilities.h" | |
| #include "IIOechoCtrl.h" | |
| /** Read a line from the input file in canonical mode. | |
| Perform echoing and input processing as directed by the termios flags. | |
| @param[in] filp A pointer to a file descriptor structure. | |
| @return The number of characters in the input buffer, or -1 if there | |
| was an error. | |
| **/ | |
| ssize_t | |
| IIO_CanonRead ( | |
| struct __filedes *filp | |
| ) | |
| { | |
| cIIO *This; | |
| cFIFO *InBuf; | |
| struct termios *Termio; | |
| struct __filedes *fpOut; | |
| size_t NumRead; | |
| wint_t InChar; | |
| tcflag_t IFlag; | |
| tcflag_t LFlag; | |
| BOOLEAN EchoIsOK; | |
| BOOLEAN Activate; | |
| BOOLEAN FirstRead; | |
| int OutMode; | |
| UINTN MaxColumn; | |
| UINTN MaxRow; | |
| NumRead = MAX_INPUT; // Workaround "potentially uninitialized" warning | |
| EchoIsOK = FALSE; | |
| FirstRead = TRUE; | |
| This = filp->devdata; | |
| Termio = &This->Termio; | |
| InBuf = This->InBuf; | |
| // Get a copy of the flags we are going to use | |
| IFlag = Termio->c_iflag; | |
| LFlag = Termio->c_lflag; | |
| /* Determine what the current screen size is. Also validates the output device. */ | |
| OutMode = IIO_GetOutputSize(STDOUT_FILENO, &MaxColumn, &MaxRow); | |
| if(OutMode >= 0) { | |
| /* Set the maximum screen dimensions. */ | |
| This->MaxColumn = MaxColumn; | |
| This->MaxRow = MaxRow; | |
| /* Record where the cursor is at the beginning of this Input operation. | |
| The currently set stdout device is used to determine this. If there is | |
| no stdout, or stdout is not an interactive device, nothing is recorded. | |
| */ | |
| if (IIO_GetCursorPosition(STDOUT_FILENO, &This->InitialXY.Column, &This->InitialXY.Row) >= 0) { | |
| This->CurrentXY.Column = This->InitialXY.Column; | |
| This->CurrentXY.Row = This->InitialXY.Row; | |
| EchoIsOK = TRUE; // Can only echo to stdout | |
| } | |
| } | |
| // For now, we only echo to stdout. | |
| fpOut = &gMD->fdarray[STDOUT_FILENO]; | |
| // Input and process characters until BufferSize is exhausted. | |
| do { | |
| InChar = IIO_GetInChar(filp, FirstRead); | |
| if (InChar == WEOF) { | |
| NumRead = 0; | |
| break; | |
| } | |
| FirstRead = FALSE; | |
| Activate = TRUE; | |
| if(InChar == CHAR_CARRIAGE_RETURN) { | |
| if((IFlag & IGNCR) != 0) { | |
| continue; // Restart the do loop, discarding the CR | |
| } | |
| else if((IFlag & ICRNL) != 0) { | |
| InChar = L'\n'; | |
| } | |
| } | |
| else if(InChar == CHAR_LINEFEED) { | |
| if((IFlag & INLCR) != 0) { | |
| InChar = L'\r'; | |
| } | |
| } | |
| else if(CCEQ(Termio->c_cc[VINTR], InChar)) { | |
| if((LFlag & ISIG) != 0) { | |
| // Raise Signal | |
| // Flush Input Buffer | |
| // Return to caller | |
| InChar = IIO_ECHO_DISCARD; | |
| errno = EINTR; | |
| } | |
| else { | |
| Activate = FALSE; | |
| } | |
| } | |
| else if(CCEQ(Termio->c_cc[VQUIT], InChar)) { | |
| if((LFlag & ISIG) != 0) { | |
| // Raise Signal | |
| // Flush Input Buffer | |
| // Return to caller | |
| InChar = IIO_ECHO_DISCARD; | |
| errno = EINTR; | |
| } | |
| else { | |
| Activate = FALSE; | |
| } | |
| } | |
| else if(CCEQ(Termio->c_cc[VEOF], InChar)) { | |
| InChar = WEOF; | |
| NumRead = 0; | |
| EchoIsOK = FALSE; // Buffer, but don't echo this character | |
| } | |
| else if(CCEQ(Termio->c_cc[VEOL], InChar)) { | |
| EchoIsOK = FALSE; // Buffer, but don't echo this character | |
| } | |
| else if(CCEQ(Termio->c_cc[VERASE], InChar)) { | |
| InChar = IIO_ECHO_ERASE; | |
| Activate = FALSE; | |
| } | |
| else if(CCEQ(Termio->c_cc[VKILL], InChar)) { | |
| InChar = IIO_ECHO_KILL; | |
| Activate = FALSE; | |
| } | |
| else { | |
| if((InChar < TtySpecKeyMin) || (InChar >= TtyFunKeyMax)) { | |
| Activate = FALSE; | |
| } | |
| } | |
| /** The Echo function is responsible for: | |
| * Adding the character to the input buffer, if appropriate. | |
| * Removing characters from the input buffer for ERASE and KILL processing. | |
| * Visually removing characters from the screen if ECHOE is set. | |
| * Ensuring one can not backspace beyond the beginning of the input text. | |
| * Sending final echo strings to output. | |
| **/ | |
| (void)This->Echo(fpOut, (wchar_t)InChar, EchoIsOK); | |
| NumRead = InBuf->Count(InBuf, AsElements); | |
| } while((NumRead < MAX_INPUT) && | |
| (Activate == FALSE)); | |
| return (ssize_t)NumRead; | |
| } |