From 6c6c850ad62d6fdc73828057339be1dc7df37c8e Mon Sep 17 00:00:00 2001 From: darylm503 Date: Tue, 11 Dec 2012 21:19:14 +0000 Subject: StdLib: Add terminal type line editing (Interactive IO) for console devices. Adds a subset of the terminal I/O capabilities described in the Single Unix Specification, V4. Supports: Erase previous character. Default is Backspace or ^H Erase line. Default is ^U TAB characters are supported and, by default, are rendered as 8 spaces. They will still be read as a single TAB character. Both Canonical and Non-Canonical modes are supported. If a terminal device is opened with O_TTY_INIT in the mode, the device will be initialized to "sane" values for interactive use. It will be in Canonical mode, Enter will be translated to NewLine and on output, a NewLine is translated to CRLF. Echoing will be on, control characters are output as ^X, and TABs are expanded. See the new file for more information. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: daryl.mcdaniel@intel.com Reviewed-by: erik.c.bjorge@intel.com Reviewed-by: leroy.p.leahy@intel.com Reviewed-by: lee.g.rosenbaum@intel.com Reviewed-by: jaben.carsey@intel.com git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13989 6f19259b-4bc3-4df7-8a09-765794883524 --- StdLib/LibC/Uefi/InteractiveIO/CanonRead.c | 161 +++++++++ StdLib/LibC/Uefi/InteractiveIO/IIO.c | 373 +++++++++++++++++++++ StdLib/LibC/Uefi/InteractiveIO/IIO.inf | 51 +++ StdLib/LibC/Uefi/InteractiveIO/IIOecho.c | 141 ++++++++ StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h | 33 ++ StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c | 288 ++++++++++++++++ StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h | 129 +++++++ StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c | 210 ++++++++++++ StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c | 89 +++++ StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c | 285 ++++++++++++++++ 10 files changed, 1760 insertions(+) create mode 100644 StdLib/LibC/Uefi/InteractiveIO/CanonRead.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIO.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIO.inf create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIOecho.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h create mode 100644 StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c create mode 100644 StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c (limited to 'StdLib/LibC/Uefi/InteractiveIO') diff --git a/StdLib/LibC/Uefi/InteractiveIO/CanonRead.c b/StdLib/LibC/Uefi/InteractiveIO/CanonRead.c new file mode 100644 index 0000000000..db6af6e4bf --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/CanonRead.c @@ -0,0 +1,161 @@ +/** @file + Canonical Interactive Input Function. + + The functions assume that isatty() is TRUE at the time they are called. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 + +#include + +#include +#include +#include +#include +#include +#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); + 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; + } + 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; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIO.c b/StdLib/LibC/Uefi/InteractiveIO/IIO.c new file mode 100644 index 0000000000..65b61d9bcc --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIO.c @@ -0,0 +1,373 @@ +/** @file + Definitions for the Interactive IO library. + + The functions assume that isatty() is TRUE at the time they are called. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "IIOutilities.h" +#include "IIOechoCtrl.h" + +/** Read from an Interactive IO device. + + NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters. + They will need to be converted to MBCS when returned. + + Input is line buffered if ICANON is set, + otherwise MIN determines how many characters to input. + Currently MIN is always zero, meaning 0 or 1 character is input in + noncanonical mode. + + @param[in] filp Pointer to the descriptor of the device (file) to be read. + @param[in] BufferSize Maximum number of bytes to be returned to the caller. + @param[out] Buffer Pointer to the buffer where the input is to be stored. + + @retval -1 An error occurred. No data is available. + @retval 0 No data was available. Try again later. + @retval >0 The number of bytes consumed by the returned data. +**/ +static +ssize_t +EFIAPI +IIO_Read( + struct __filedes *filp, + size_t BufferSize, + VOID *Buffer + ) +{ + cIIO *This; + ssize_t NumRead; + tcflag_t Flags; + size_t XlateSz; + size_t Needed; + + NumRead = -1; + This = filp->devdata; + if(This != NULL) { + Flags = This->Termio.c_lflag; + if(Flags & ICANON) { + NumRead = IIO_CanonRead(filp); + } + else { + NumRead = IIO_NonCanonRead(filp); + } + // At this point, the input has been accumulated in the input buffer. + if(filp->f_iflags & _S_IWTTY) { + // Data in InBuf is wide characters. Convert to MBCS + // First, convert into a linear buffer + NumRead = This->InBuf->Copy(This->InBuf, gMD->UString2, (INT32)UNICODE_STRING_MAX-1); + gMD->UString2[NumRead] = 0; // Ensure that the buffer is terminated + // Determine the needed space + XlateSz = EstimateWtoM((const wchar_t *)gMD->UString2, BufferSize, &Needed); + + // Now translate this into MBCS in Buffer + NumRead = wcstombs((char *)Buffer, (const wchar_t *)gMD->UString2, XlateSz); + + // Consume the translated characters + (void)This->InBuf->Flush(This->InBuf, Needed); + } + else { + // Data in InBuf is narrow characters. Use verbatim. + NumRead = This->InBuf->Read(This->InBuf, Buffer, (INT32)BufferSize); + } + } + return NumRead; +} + +/** Process characters from buffer buf and write them to the output device + specified by filp. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] buf Pointer to the MBCS string to be output. + @param[in] N Number of bytes in buf. + + @retval >=0 Number of bytes sent to the output device. +**/ +static +ssize_t +EFIAPI +IIO_Write( + struct __filedes *filp, + const char *buf, + ssize_t N + ) +{ + cIIO *This; + cFIFO *OutBuf; + mbstate_t *OutState; + char *MbcsPtr; + ssize_t NumWritten; + ssize_t NumProc; + size_t CharLen; + UINTN MaxColumn; + UINTN MaxRow; + wchar_t OutChar[2]; // Just in case we run into 4-byte MBCS character + int OutMode; + + errno = 0; // indicate no error as default + NumWritten = -1; + + /* Determine what the current screen size is. Also validates the output device. */ + OutMode = IIO_GetOutputSize(filp->MyFD, &MaxColumn, &MaxRow); + + This = filp->devdata; + if((This != NULL) && (OutMode >= 0)) { + if(filp->MyFD == STDERR_FILENO) { + OutBuf = This->ErrBuf; + OutState = &This->ErrState; + } + else { + OutBuf = This->OutBuf; + OutState = &This->OutState; + } + + /* Set the maximum screen dimensions. */ + This->MaxColumn = MaxColumn; + This->MaxRow = MaxRow; + + /* Record where the cursor is at the beginning of the Output operation. */ + (void)IIO_GetCursorPosition(filp->MyFD, &This->InitialXY.Column, &This->InitialXY.Row); + This->CurrentXY.Column = This->InitialXY.Column; + This->CurrentXY.Row = This->InitialXY.Row; + + + NumWritten = 0; + OutChar[0] = (wchar_t)buf[0]; + while((OutChar[0] != 0) && (NumWritten < N)) { + CharLen = mbrtowc(OutChar, (const char *)&buf[NumWritten], MB_CUR_MAX, OutState); + NumProc = IIO_WriteOne(filp, OutBuf, OutChar[0]); + if(NumProc > 0) { + // Successfully processed and buffered one character + NumWritten += CharLen; // Index of start of next character + } + else if(NumProc == -1) { + // Encoding Error + (void)mbrtowc(NULL, NULL, 1, OutState); // Re-Initialize the conversion state + errno = EILSEQ; + break; + } + else { + // Last character was incomplete + break; + } + } + // At this point, the characters to write are in OutBuf + // First, linearize the buffer + NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1); + gMD->UString[NumWritten] = 0; // Ensure that the buffer is terminated + + if(filp->f_iflags & _S_IWTTY) { + // Output device expects wide characters, Output what we have + NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString); + } + else { + // Output device expects narrow characters, convert to MBCS + MbcsPtr = (char *)gMD->UString2; + // Determine the needed space + NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), &CharLen); + + // Now translate this into MBCS in Buffer + NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc); + MbcsPtr[NumWritten] = 0; // Ensure the buffer is terminated + + // Send the MBCS buffer to Output + NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr); + } + // Consume the translated characters + (void)OutBuf->Flush(OutBuf, NumWritten); + } + else { + if(This == NULL) { + errno = EINVAL; + } + // Otherwise, errno is already set. + } + return NumWritten; +} + +/** Echo a character to an output device. + Performs translation and edit processing depending upon termios flags. + + @param[in] filp A pointer to a file descriptor structure. + @param[in] EChar The character to echo. + @param[in] EchoIsOK TRUE if the caller has determined that characters + should be echoed. Otherwise, just buffer. + + @return Returns the number of characters actually output. +**/ +static +ssize_t +EFIAPI +IIO_Echo( + struct __filedes *filp, + wchar_t EChar, + BOOLEAN EchoIsOK + ) +{ + cIIO *This; + ssize_t NumWritten; + cFIFO *OutBuf; + char *MbcsPtr; + ssize_t NumProc; + tcflag_t LFlags; + + NumWritten = -1; + This = filp->devdata; + if(This != NULL) { + OutBuf = This->OutBuf; + LFlags = This->Termio.c_lflag & (ECHOK | ECHOE); + + if((EChar >= TtyFunKeyMin) && (EChar < TtyFunKeyMax)) { + // A special function key was pressed, buffer it, don't echo, and activate. + // Process and buffer the character. May produce multiple characters. + NumProc = IIO_EchoOne(filp, EChar, FALSE); // Don't echo this character + EChar = CHAR_LINEFEED; // Every line must end with '\n' (legacy) + } + // Process and buffer the character. May produce multiple characters. + NumProc = IIO_EchoOne(filp, EChar, EchoIsOK); + + // At this point, the character(s) to write are in OutBuf + // First, linearize the buffer + NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1); + gMD->UString[NumWritten] = 0; // Ensure that the buffer is terminated + + if((EChar == IIO_ECHO_KILL) && (LFlags & ECHOE) && EchoIsOK) { + // Position the cursor to the start of input. + (void)IIO_SetCursorPosition(filp, &This->InitialXY); + } + // Output the buffer + if(filp->f_iflags & _S_IWTTY) { + // Output device expects wide characters, Output what we have + NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString); + } + else { + // Output device expects narrow characters, convert to MBCS + MbcsPtr = (char *)gMD->UString2; + // Determine the needed space + NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), NULL); + + // Now translate this into MBCS in Buffer + NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc); + MbcsPtr[NumWritten] = 0; // Ensure the buffer is terminated + + // Send the MBCS buffer to Output + NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr); + } + // Consume the echoed characters + (void)OutBuf->Flush(OutBuf, NumWritten); + + if(EChar == IIO_ECHO_KILL) { + if(LFlags == ECHOK) { + NumWritten = IIO_WriteOne(filp, OutBuf, CHAR_LINEFEED); + } + else if((LFlags & ECHOE) && EchoIsOK) { + // Position the cursor to the start of input. + (void)IIO_SetCursorPosition(filp, &This->InitialXY); + } + NumWritten = 0; + } + } + else { + errno = EINVAL; + } + + return NumWritten; +} + +static +void +FifoDelete(cFIFO *Member) +{ + if(Member != NULL) { + Member->Delete(Member); + } +} + +/** Destructor for an IIO instance. + + Releases all resources used by a particular IIO instance. +**/ +static +void +EFIAPI +IIO_Delete( + cIIO *Self + ) +{ + if(Self != NULL) { + FifoDelete(Self->ErrBuf); + FifoDelete(Self->OutBuf); + FifoDelete(Self->InBuf); + if(Self->AttrBuf != NULL) { + FreePool(Self->AttrBuf); + } + FreePool(Self); + } +} + +/** Constructor for new IIO instances. + + @return Returns NULL or a pointer to a new IIO instance. +**/ +cIIO * +EFIAPI +New_cIIO(void) +{ + cIIO *IIO; + cc_t *TempBuf; + int i; + + IIO = (cIIO *)AllocateZeroPool(sizeof(cIIO)); + if(IIO != NULL) { + IIO->InBuf = New_cFIFO(MAX_INPUT, sizeof(wchar_t)); + IIO->OutBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t)); + IIO->ErrBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t)); + IIO->AttrBuf = (UINT8 *)AllocateZeroPool(MAX_OUTPUT); + + if((IIO->InBuf == NULL) || (IIO->OutBuf == NULL) || + (IIO->ErrBuf == NULL) || (IIO->AttrBuf == NULL)) + { + IIO_Delete(IIO); + IIO = NULL; + } + else { + IIO->Delete = IIO_Delete; + IIO->Read = IIO_Read; + IIO->Write = IIO_Write; + IIO->Echo = IIO_Echo; + } + // Initialize Termio member + TempBuf = &IIO->Termio.c_cc[0]; + TempBuf[0] = 8; // Default length for TABs + for(i=1; i < NCCS; ++i) { + TempBuf[i] = _POSIX_VDISABLE; + } + TempBuf[VMIN] = 0; + TempBuf[VTIME] = 0; + IIO->Termio.c_ispeed = B115200; + IIO->Termio.c_ospeed = B115200; + IIO->Termio.c_iflag = ICRNL; + IIO->Termio.c_oflag = OPOST | ONLCR | ONOCR | ONLRET; + IIO->Termio.c_cflag = 0; + IIO->Termio.c_lflag = ECHO | ECHONL; + } + return IIO; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIO.inf b/StdLib/LibC/Uefi/InteractiveIO/IIO.inf new file mode 100644 index 0000000000..dd21e85b13 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIO.inf @@ -0,0 +1,51 @@ +## @file +# Interactive I/O Library. +# +# Copyright (c) 2012, Intel Corporation. All rights reserved.
+# 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. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = LibIIO + FILE_GUID = c1e9fffb-5557-4cb5-a5f5-1fbd902a74ed + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = LibIIO + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + IIO.c + NonCanonRead.c + CanonRead.c + TerminalFunctions.c + IIOutilities.c + IIOwrite.c + IIOecho.c + +[Packages] + MdePkg/MdePkg.dec + StdLib/StdLib.dec + StdLibPrivateInternalFiles/DoNotUse.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + LibC + LibWchar + LibContainer + +[Protocols] + gEfiSimpleTextInProtocolGuid ## CONSUMES + gEfiSimpleTextOutProtocolGuid ## CONSUMES diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOecho.c b/StdLib/LibC/Uefi/InteractiveIO/IIOecho.c new file mode 100644 index 0000000000..14369de95b --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIOecho.c @@ -0,0 +1,141 @@ +/** @file + Echo characters to an Interactive I/O Output device. + + The functions assume that isatty() is TRUE at the time they are called. + Since the UEFI console is a WIDE character device, these functions do all + processing using wide characters. + + It is the responsibility of the caller, or higher level function, to perform + any necessary translation between wide and narrow characters. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 + +#include + +#include +#include +#include +#include +#include "IIOutilities.h" +#include "IIOechoCtrl.h" + +/** Echo one character to an IIO file. + + If character InCh is a special "echo control" character, process it and output + the resultant character(s), if any. Otherwise pass the character on to the + IIO_WriteOne() function which performs generic output processing, if needed. + + @param[in] filp Pointer to an open IIO file's file descriptor structure. + @param[in] InCh The wide character to be echoed. + @param[in] EchoIsOK A flag indicating whether echoing is appropriate for this + device or not. + + @retval -1 The filp argument does not refer to an IIO device. + Global value errno is set to EINVAL. + @retval >=0 The number of characters actually output. + + @sa IIO_WriteOne +**/ +ssize_t +IIO_EchoOne ( + struct __filedes *filp, + wchar_t InCh, + BOOLEAN EchoIsOK + ) +{ + cIIO *This; + cFIFO *OutBuf; + cFIFO *InBuf; + UINT8 *AttrBuf; + ssize_t NumEcho; + tcflag_t LFlags; + UINT32 AttrDex; + int i; + + NumEcho = -1; + This = filp->devdata; + + if(This != NULL) { + LFlags = This->Termio.c_lflag; + OutBuf = This->OutBuf; + InBuf = This->InBuf; + AttrBuf = This->AttrBuf; + AttrDex = InBuf->GetWDex(InBuf); + + switch(InCh) { + case IIO_ECHO_DISCARD: + // Do not buffer or otherwise process + NumEcho = 0; + break; + + case IIO_ECHO_ERASE: + // Delete last character from InBuf + if(!InBuf->IsEmpty(InBuf)) { + (void)InBuf->Truncate(InBuf); + + // Erase screen character(s) based on Attrib value + if(LFlags & ECHO) { + AttrDex = (UINT32)ModuloDecrement(AttrDex, InBuf->NumElements); + NumEcho = AttrBuf[AttrDex]; + for(i = 0; i < NumEcho; ++i) { + (void)IIO_WriteOne(filp, OutBuf, CHAR_BACKSPACE); + } + if(LFlags & ECHOE) { + for(i = 0; i < NumEcho; ++i) { + (void)IIO_WriteOne(filp, OutBuf, L' '); + } + for(i = 0; i < NumEcho; ++i) { + (void)IIO_WriteOne(filp, OutBuf, CHAR_BACKSPACE); + } + } + } + else { + NumEcho = 0; + } + } + break; + + case IIO_ECHO_KILL: + // Flush contents of InBuf and OutBuf + InBuf->Flush(InBuf, (size_t)-1); + OutBuf->Flush(OutBuf, (size_t)-1); + + // Erase characters from screen. + if(LFlags & ECHOE) { + NumEcho = IIO_CursorDelta(This, &This->InitialXY, &This->CurrentXY); + for(i = 0; i < NumEcho; ++i) { + (void)IIO_WriteOne(filp, OutBuf, L' '); + } + } + break; + + default: + // Add character to input buffer + (void)InBuf->Write(InBuf, &InCh, 1); + + NumEcho = 0; // In case echoing is not enabled or OK + // If echoing is OK and enabled, "echo" character using IIO_WriteOne + if( EchoIsOK && + ( (LFlags & ECHO) || + ((LFlags & ECHONL) && (InCh == CHAR_LINEFEED)))) + { + NumEcho = IIO_WriteOne(filp, OutBuf, InCh); + } + AttrBuf[AttrDex] = (UINT8)NumEcho; + break; + } + } + else { + errno = EINVAL; + } + return NumEcho; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h b/StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h new file mode 100644 index 0000000000..69d040af01 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIOechoCtrl.h @@ -0,0 +1,33 @@ +/** @file + Constants and declarations for the Echo function. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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. +**/ +#ifndef _IIO_ECHO_CTRL_H +#define _IIO_ECHO_CTRL_H +#include + +__BEGIN_DECLS + +/* These constants are assigned values within the Unicode Private Use range. + The value of IIO_ECHO_MIN must be adjusted to ensure that IIO_ECHO_MAX + never exceeds the value of 0xF900. +*/ +typedef enum { + IIO_ECHO_MIN = (TtyFunKeyMin - 3), + IIO_ECHO_DISCARD = IIO_ECHO_MIN, // Ignore this character completely + IIO_ECHO_ERASE, // Erase previous character + IIO_ECHO_KILL, // Kill the entire line + IIO_ECHO_MAX +} IioEchoCtrl; + +__END_DECLS + +#endif /* _IIO_ECHO_CTRL_H */ diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c new file mode 100644 index 0000000000..2da0628840 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.c @@ -0,0 +1,288 @@ +/** @file + Utilities for Interactive I/O Functions. + + The functions assume that isatty() is TRUE at the time they are called. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "IIOutilities.h" + +/** Get the low-level UEFI protocol associated with an open file. + + @param[in] fd File descriptor for an open file. + @param[out] filp NULL, or a pointer to where a pointer to the file's + file descriptor structure is to be stored. + + @return Returns NULL if fd is not a valid file descriptor, otherwise + a pointer to the file's associated UEFI protocol is returned. +**/ +void * +EFIAPI +IIO_GetDeviceProto ( + int fd, + struct __filedes **filp + ) +{ + void *Proto; + ConInstance *Stream; + struct __filedes *pfil; + + Proto = NULL; + if(ValidateFD( fd, VALID_OPEN)) { + pfil = &gMD->fdarray[fd]; + Stream = BASE_CR(pfil->f_ops, ConInstance, Abstraction); + Proto = (void *)Stream->Dev; + if(filp != NULL) { + *filp = pfil; + } + } + return Proto; +} + +/** Get a character either from the input buffer or from hardware. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] First Set to TRUE to identify the initial read. + + @return Returns a character read from either the input buffer + or from the open file (device) identified by filp. + A return value of WEOF indicates an error has occurred. +**/ +wint_t +EFIAPI +IIO_GetInChar ( + struct __filedes *filp, + BOOLEAN First +) +{ + cIIO *This; + cFIFO *InBuf; + EFI_STATUS Status; + ssize_t NumRead; + wint_t RetVal; + wchar_t InChar; + + static size_t BufCnt; + + This = filp->devdata; + InBuf = This->InBuf; + + NumRead = -1; + InChar = 0; + if(First) { + BufCnt = InBuf->Count(InBuf, AsElements); + } + if(BufCnt > 0) { + Status = InBuf->Read(InBuf, &InChar, 1); + --BufCnt; + NumRead = 1; + } + else { + NumRead = filp->f_ops->fo_read(filp, &filp->f_offset, sizeof(wchar_t), &InChar); + } + if(NumRead <= 0) { + RetVal = WEOF; + } + else { + RetVal = (wint_t)InChar; + } + return InChar; +} + +/** Get the current cursor position. + + @param[in] fd File descriptor for an open file. + @param[out] Column Pointer to where the current cursor column is to be stored. + @param[out] Row Pointer to where the current cursor row is to be stored. + + @retval -1 fd is not an IIO output device. + @retval 0 Cursor position retrieved, Cursor is Not Visible. + @retval 1 Cursor position retrieved, Cursor is Visible. +**/ +int +EFIAPI +IIO_GetCursorPosition ( + int fd, + UINT32 *Column, + UINT32 *Row + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + struct __filedes *pStdOut; + int RetVal; + + RetVal = -1; + + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut); + if(Proto != NULL) { + if(((pStdOut->f_iflags & _S_ITTY) != 0) && // file is a TTY + ((pStdOut->Oflags & O_ACCMODE) != 0)) // and it is open for output + { + // fd is for a TTY or "Interactive IO" device + *Column = Proto->Mode->CursorColumn; + *Row = Proto->Mode->CursorRow; + if(Proto->Mode->CursorVisible) { + RetVal = 1; + } + else { + RetVal = 0; + } + } + } + return RetVal; +} + +/** Set the cursor position. + + @param[in] filp Pointer to the output device's file descriptor structure. + @param[in] StartXY Pointer to a cursor coordinate (XY) structure indicating + the desired coordinate to move the cursor to. + + @retval -1 fd is not an IIO output device + @retval 0 Cursor position set successfully. +**/ +int +EFIAPI +IIO_SetCursorPosition ( + struct __filedes *filp, + CURSOR_XY *CursorXY + ) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + cIIO *This; + EFI_STATUS Status; + int RetVal; + + RetVal = -1; + + This = filp->devdata; + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(filp->MyFD, NULL); + if(Proto != NULL) { + if(((filp->f_iflags & _S_ITTY) != 0) && // file is a TTY + ((filp->Oflags & O_ACCMODE) != 0)) // and it is open for output + { + // fd is for a TTY or "Interactive IO" device + Status = Proto->SetCursorPosition(Proto, CursorXY->Column, CursorXY->Row); + if(Status == EFI_SUCCESS) { + This->CurrentXY.Column = CursorXY->Column; + This->CurrentXY.Row = CursorXY->Row; + RetVal = 0; + } + } + } + return RetVal; +} + +/** Get Output screen size and mode. + + @param[in] fd File descriptor of the output device. + @param[out] Col Pointer to where to store the MAX Column, or NULL. + @param[out] Row Pointer to where to store the MAX Row, or NULL. + + @retval <0 An error occurred. The reason is in errno and EFIerrno. + * EIO UEFI QueryMode failed + * ENOTTY fd does not refer to an interactive output device + @retval >=0 Current output mode +**/ +int +EFIAPI +IIO_GetOutputSize ( + int fd, + UINTN *Col, + UINTN *Row +) +{ + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + struct __filedes *pStdOut; + EFI_STATUS Status; + UINTN TempCol; + UINTN TempRow; + UINTN TempMode; + int RetVal; + + RetVal = -1; + + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)IIO_GetDeviceProto(fd, &pStdOut); + if(Proto != NULL) { + if(((pStdOut->f_iflags & _S_ITTY) != 0) && // file is a TTY + ((pStdOut->Oflags & O_ACCMODE) != 0)) // and it is open for output + { + // fd is for a TTY or "Interactive IO" device + TempMode = Proto->Mode->Mode; + Status = Proto->QueryMode(Proto, TempMode, &TempCol, &TempRow); + if(EFI_ERROR(Status)) { + EFIerrno = Status; + errno = EIO; + } + else { + *Col = TempCol; + *Row = TempRow; + RetVal = (int)TempMode; + } + } + else { + errno = ENOTTY; + } + } + return RetVal; +} + +/** Calculate the number of character positions between two X/Y coordinate pairs. + + Using the current output device characteristics, calculate the number of + characters between two coordinates. It is assumed that EndXY points to + an output location that occurs after StartXY. + + RowDelta is the computed difference between the ending and starting rows. + If RowDelta < 0, then EndXY is NOT after StartXY, so assert. + + ColumnDelta is the computed number of character positions (columns) between + the starting position and the ending position. If ColumnDelta is < 0, + then EndXY is NOT after StartXY, so assert. + + @param[in] This Pointer to the IIO instance to be examined. + @param[in] StartXY Pointer to the starting coordinate pair. + @param[in] EndXY Pointer to the ending coordinate pair. + + @return Returns the difference between the starting and ending coordinates. +**/ +UINT32 +EFIAPI +IIO_CursorDelta ( + cIIO *This, + CURSOR_XY *StartXY, + CURSOR_XY *EndXY +) +{ + INT32 ColumnDelta; + INT32 RowDelta; + + RowDelta = (int)EndXY->Row - (int)StartXY->Row; + + assert(RowDelta >= 0); // assert if EndXY is NOT after StartXY + + ColumnDelta = (INT32)((This->MaxColumn * RowDelta) + EndXY->Column); + ColumnDelta -= (INT32)StartXY->Column; + + assert(ColumnDelta >= 0); // assert if EndXY is NOT after StartXY + + return (UINT32)ColumnDelta; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h new file mode 100644 index 0000000000..778b612ea5 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIOutilities.h @@ -0,0 +1,129 @@ +/** @file + Utilities for Interactive I/O Functions. + + The functions assume that isatty() is TRUE at the time they are called. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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. +**/ +#ifndef _IIO_UTILITIES_H +#define _IIO_UTILITIES_H + +#include + +__BEGIN_DECLS + +/** Get the low-level UEFI protocol associated with an open file. + + @param[in] fd File descriptor for an open file. + @param[out] filp NULL, or a pointer to where a pointer to the file's + file descriptor structure is to be stored. + + @return Returns NULL if fd is not a valid file descriptor, otherwise + a pointer to the file's associated UEFI protocol is returned. +**/ +void * +EFIAPI +IIO_GetDeviceProto ( + int fd, + struct __filedes **filp // Optional - filp == NULL if unused + ); + +/** Get a character either from the input buffer or from hardware. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] First Set to TRUE to identify the initial read. + + @return Returns a character read from either the input buffer + or from the open file (device) identified by filp. + A return value of WEOF indicates an error has occurred. +**/ +wint_t +EFIAPI +IIO_GetInChar ( + struct __filedes *filp, + BOOLEAN First + ); + +/** Get the current cursor position. + + @param[in] fd File descriptor for an open file. + @param[out] Column Pointer to where the current cursor column is to be stored. + @param[out] Row Pointer to where the current cursor row is to be stored. + + @retval -1 fd is not an IIO output device. + @retval 0 Cursor position retrieved, Cursor is Not Visible. + @retval 1 Cursor position retrieved, Cursor is Visible. +**/ +int +EFIAPI +IIO_GetCursorPosition ( + int fd, + UINT32 *Column, + UINT32 *Row + ); + +/** Set the cursor position. + + @param[in] filp Pointer to the output device's file descriptor structure. + @param[in] StartXY Pointer to a cursor coordinate (XY) structure indicating + the desired coordinate to move the cursor to. + + @retval -1 fd is not an IIO output device + @retval 0 Cursor position set successfully. +**/ +int +EFIAPI +IIO_SetCursorPosition ( + struct __filedes *filp, + CURSOR_XY *StartXY + ); + +/** Get Output screen size and mode. + + @param[in] fd File descriptor of the output device. + @param[out] Col Pointer to where to store the MAX Column, or NULL. + @param[out] Row Pointer to where to store the MAX Row, or NULL. + + @retval <0 An error occurred. The reason is in errno and EFIerrno. + * EIO UEFI QueryMode failed + * ENOTTY fd does not refer to an interactive output device + @retval >=0 Current output mode +**/ +int +EFIAPI +IIO_GetOutputSize ( + int fd, + UINTN *Col, + UINTN *Row +); + +/** Calculate the number of character positions between two X/Y coordinate pairs. + + Using the current output device characteristics, calculate the number of + characters between two coordinates. + + @param[in] This Pointer to the IIO instance to be examined. + @param[in] StartXY Pointer to the starting coordinate pair. + @param[in] EndXY Pointer to the ending coordinate pair. + + @return Returns the difference between the starting and ending coordinates. + The return value is positive if the coordinates contained in EndXY + are larger than StartXY, otherwise the return value is negative. +**/ +int +EFIAPI +IIO_CursorDelta ( + cIIO *This, + CURSOR_XY *StartXY, + CURSOR_XY *EndXY + ); + +__END_DECLS +#endif /* _IIO_UTILITIES_H */ diff --git a/StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c b/StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c new file mode 100644 index 0000000000..927f4f4ff3 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c @@ -0,0 +1,210 @@ +/** @file + Write to an Interactive I/O Output device. + + The functions assume that isatty() is TRUE at the time they are called. + Since the UEFI console is a WIDE character device, these functions do all + processing using wide characters. + + It is the responsibility of the caller, or higher level function, to perform + any necessary translation between wide and narrow characters. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 + +#include + +#include +#include +#include +#include + +static wchar_t Spaces[] = L" "; // Spaces for expanding TABs + +#define MAX_TAB_WIDTH ((int)(sizeof(Spaces) / sizeof(wchar_t)) - 1) + +#define MAX_EXPANSION 3 + +/** Process and buffer one character for output. + + @param[in] filp Pointer to a file descriptor structure. + @param[out] OBuf Pointer to the Output Buffer FIFO. + @param[in] InCh The wide character to process. + + @retval <0 An error occurred. Reason is in errno. + * EINVAL The pointer to the IIO object is NULL. + * ENOSPC The OBuf FIFO is full. + + @retval 0 A character was input but not placed in the output buffer. + + @retval >0 The number of characters buffered. Normally 1, or 2. + If a character is discarded because of flag settings, a + 1 will be returned. +**/ +ssize_t +IIO_WriteOne(struct __filedes *filp, cFIFO *OBuf, wchar_t InCh) +{ + cIIO *This; + struct termios *Termio; + tcflag_t OFlag; + ssize_t RetVal; + wchar_t wc[MAX_EXPANSION]; // Sub-buffer for conversions + wchar_t *wcb; // Pointer to either wc or spaces + int numW = 0; // Wide characters placed in OBuf + INT32 TabWidth; // Each TAB expands into this number of spaces + UINT32 CurColumn; // Current cursor column on the screen + UINT32 CurRow; // Current cursor row on the screen + UINT32 PrevColumn; // Previous column. Used to detect wrapping. + UINT32 AdjColumn; // Current cursor column on the screen + UINT32 AdjRow; // Current cursor row on the screen + + RetVal = -1; + wcb = wc; + This = filp->devdata; + if((This != NULL) && (OBuf->FreeSpace(OBuf, AsElements) >= MAX_EXPANSION)) { + Termio = &This->Termio; + OFlag = Termio->c_oflag; + TabWidth = (INT32)This->Termio.c_cc[VTABLEN]; + if(TabWidth > MAX_TAB_WIDTH) { + TabWidth = MAX_TAB_WIDTH; + } + CurColumn = This->CurrentXY.Column; + CurRow = This->CurrentXY.Row; + + numW = 1; // The majority of characters buffer one character + AdjRow = 0; // Most characters just cause horizontal movement + AdjColumn = 0; + if(OFlag & OPOST) { + /* Perform output processing */ + switch(InCh) { + case CHAR_TAB: //{{ + if(OFlag & OXTABS) { + if(TabWidth > 0) { + int SpaceIndex; + + SpaceIndex = CurColumn % TabWidth; // Number of spaces after a Tab Stop + numW = TabWidth - SpaceIndex; // Number of spaces to the next Tab Stop + SpaceIndex = MAX_TAB_WIDTH - numW; // Index into the Spaces array + wcb = &Spaces[SpaceIndex]; // Point to the appropriate number of spaces + } + else { + wc[0] = L' '; + } + AdjColumn = numW; + } + else { + wc[0] = InCh; // Send the TAB itself - assumes that it does not move cursor. + } + break; //}} + + case CHAR_CARRIAGE_RETURN: //{{ + if((OFlag & OCRNL) == 0) { + if((OFlag & ONLRET) == 0) { + numW = 0; /* Discard the CR */ + // Cursor doesn't move + } + else { + wc[0] = CHAR_CARRIAGE_RETURN; + CurColumn = 0; + } + break; + } + else { + InCh = CHAR_LINEFEED; + } //}} + // Fall through to the NL case + case CHAR_LINEFEED: //{{ + if(OFlag & ONLCR) { + wc[0] = CHAR_CARRIAGE_RETURN; + wc[1] = CHAR_LINEFEED; + numW = 2; + CurColumn = 0; + } + AdjRow = 1; + break; //}} + + case CHAR_BACKSPACE: //{{ + if(CurColumn > 0) { + wc[0] = CHAR_BACKSPACE; + CurColumn = (UINT32)ModuloDecrement(CurColumn, (UINT32)This->MaxColumn); + } + else { + numW = 0; // Discard the backspace if in column 0 + } + break; //}} + + case CHAR_EOT: //{{ + if(OFlag & ONOEOT) { + numW = 0; // Discard the EOT character + // Cursor doesn't move + break; + } //}} + // Fall through to default in order to potentially output "^D" + default: //{{ + if((InCh >= 0) && (InCh < L' ')) { + // InCh contains a control character + if(OFlag & OCTRL) { + wc[1] = InCh + L'@'; + wc[0] = L'^'; + numW = 2; + AdjColumn = 2; + } + else { + numW = 0; // Discard. Not a UEFI supported control character. + } + } + else { + // Regular printing character + wc[0] = InCh; + AdjColumn = 1; + } + break; //}} + } + if(numW < MAX_EXPANSION) { + wc[numW] = 0; // Terminate the sub-buffer + } + if(AdjColumn != 0) { + // Adjust the cursor position + PrevColumn = CurColumn; + CurColumn = ModuloAdd(PrevColumn, AdjColumn, (UINT32)This->MaxColumn); + if(CurColumn < PrevColumn) { + // We must have wrapped, so we are on the next Row + ++CurRow; + if(CurRow >= This->MaxRow) { + // The screen has scrolled so need to adjust Initial location. + --This->InitialXY.Row; // Initial row has moved up one + CurRow = (UINT32)(This->MaxRow - 1); // We stay on the bottom row + } + } + } + This->CurrentXY.Column = CurColumn; + This->CurrentXY.Row = CurRow; + } + else { + // Output processing disabled -- RAW output mode + wc[0] = InCh; + wc[1] = 0; + } + // Put the character(s) into the output buffer + if(numW > 0) { + (void)OBuf->Write(OBuf, (const void *)wcb, (size_t)numW); + } + RetVal = numW; + } + else { + if(This == NULL) { + errno = EINVAL; + } + else { + errno = ENOSPC; + } + } + return RetVal; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c b/StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c new file mode 100644 index 0000000000..15bf43e260 --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/NonCanonRead.c @@ -0,0 +1,89 @@ +/** @file + NonCanonical Interactive Input Function. + + The functions assume that isatty() is TRUE at the time they are called. + If _S_IWTTY is set, the device returns WIDE characters. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ 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 + +#include +#include +#include +#include + +/** Perform a noncanonical read of input. + + @param[in] filp Pointer to a file descriptor structure. + @param[in] BufferSize Maximum number of bytes to return. + + @retval -1 An error has occurred. Reason in errno. + @retval -1 No data returned. None was ready. + @retval >0 The number of elements returned +**/ +ssize_t +IIO_NonCanonRead ( + struct __filedes *filp + ) +{ + cIIO *This; + cFIFO *InBuf; + struct termios *Termio; + EFI_STATUS Status; + ssize_t NumRead; + cc_t tioMin; + cc_t tioTime; + UINT32 InputType; + wchar_t InChar; // Intermediate character buffer + + NumRead = -1; + InChar = 0; // Initialize so compilers don't complain. + This = filp->devdata; + Termio = &This->Termio; + InBuf = This->InBuf; + tioMin = Termio->c_cc[VMIN]; + tioTime = Termio->c_cc[VTIME]; + + if(tioMin >= MAX_INPUT) { + tioMin = MAX_INPUT; + } + /* There are four types of processing that may be done, based on + the values of tioMin and tioTime. + Min Time Type + --- ---- ---- + 0 0 0 Return buffer contents or 1 new char + 0 >0 1 Return 0 or 1 character depending on timeout + >0 0 2 Buffer Min chars. Return BufferSize chars. + >0 >0 3 Return up to Min chars. Unless the inter-byte timer expires. + + Currently, only type 0 is implemented. + */ + InputType = 0; + if(tioMin != 0) InputType = 2; + if(tioTime != 0) ++InputType; + //switch(InputType) { + // case 0: + if(InBuf->IsEmpty(InBuf)) { + NumRead = filp->f_ops->fo_read(filp, &filp->f_offset, sizeof(wchar_t), &InChar); + if(NumRead > 0) { + Status = InBuf->Write(InBuf, &InChar, 1); // Buffer the character + } + } + // break; + // case 1: + // break; + // case 2: + // break; + // case 3: + // break; + //} + return NumRead; +} diff --git a/StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c b/StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c new file mode 100644 index 0000000000..807ab1fd4c --- /dev/null +++ b/StdLib/LibC/Uefi/InteractiveIO/TerminalFunctions.c @@ -0,0 +1,285 @@ +/** @file + "Terminal" Control functions for Interactive IO. + + Copyright (c) 2012, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License that accompanies this distribution. + The full text of the license may be found at + http://opensource.org/licenses/bsd-license. + + 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 +#include + +#include + +#include +#include +#include +#include + +/** Get input baud rate. + + Extracts the input baud rate from the termios structure pointed to by the + pTermios argument. + + @param[in] pTermios A pointer to the termios structure from which to extract + the input baud rate. + + @return The value of the input speed is returned exactly as it is contained + in the termios structure, without interpretation. +**/ +speed_t +cfgetispeed ( + const struct termios *pTermios + ) +{ + return pTermios->c_ispeed; +} + +/** Get output baud rate. + + Extracts the output baud rate from the termios structure pointed to by the + pTermios argument. + + @param[in] pTermios A pointer to the termios structure from which to extract + the output baud rate. + + @return The value of the output speed is returned exactly as it is contained + in the termios structure, without interpretation. +**/ +speed_t +cfgetospeed ( + const struct termios *pTermios + ) +{ + return pTermios->c_ospeed; +} + +/** Set input baud rate. + + Replaces the input baud rate, in the termios structure pointed to by the + pTermios argument, with the value of NewSpeed. + + @param[out] pTermios A pointer to the termios structure into which to set + the input baud rate. + @param[in] NewSpeed The new input baud rate. + + @retval 0 The operation completed successfully. + @retval -1 An error occured and errno is set to indicate the error. + * EINVAL - The value of NewSpeed is outside the range of + possible speed values as specified in . +**/ +int +cfsetispeed ( + struct termios *pTermios, + speed_t NewSpeed + ) +{ + int RetVal; + + if(NewSpeed < B921600) { + pTermios->c_ispeed = NewSpeed; + RetVal = 0; + } + else { + RetVal = -1; + errno = EINVAL; + } + return RetVal; +} + +/** Set output baud rate. + + Replaces the output baud rate, in the termios structure pointed to by the + pTermios argument, with the value of NewSpeed. + + @param[out] pTermios A pointer to the termios structure into which to set + the output baud rate. + @param[in] NewSpeed The new output baud rate. + + @retval 0 The operation completed successfully. + @retval -1 An error occured and errno is set to indicate the error. + * EINVAL - The value of NewSpeed is outside the range of + possible speed values as specified in . +**/ +int +cfsetospeed ( + struct termios *pTermios, + speed_t NewSpeed + ) +{ + int RetVal; + + if(NewSpeed < B921600) { + pTermios->c_ospeed = NewSpeed; + RetVal = 0; + } + else { + RetVal = -1; + errno = EINVAL; + } + return RetVal; +} + +/** Get the parameters associated with an interactive IO device. + + Get the parameters associated with the device referred to by + fd and store them into the termios structure referenced by pTermios. + + @param[in] fd The file descriptor for an open interactive IO device. + @param[out] pTermios A pointer to a termios structure into which to store + attributes of the interactive IO device. + + @retval 0 The operation completed successfully. + @retval -1 An error occured and errno is set to indicate the error. + * EBADF - The fd argument is not a valid file descriptor. + * ENOTTY - The file associated with fd is not an interactive IO device. +**/ +int +tcgetattr ( + int fd, + struct termios *pTermios + ) +{ + cIIO *IIO; + int RetVal; + struct __filedes *filp; + struct termios *Termio; + + RetVal = 0; + if(ValidateFD( fd, VALID_OPEN)) { + filp = &gMD->fdarray[fd]; + + if((filp->f_iflags & _S_ITTY) != 0) { + // fd is for a TTY or "Interactive IO" device + IIO = (cIIO *)filp->devdata; + Termio = &IIO->Termio; + (void)CopyMem((void *)pTermios, (const void *)Termio, sizeof(struct termios)); + } + else { + errno = ENOTTY; + RetVal = -1; + } + } + else { + errno = EBADF; + RetVal = -1; + } + return RetVal; +} + +/** Set the parameters associated with an interactive IO device. + + Set the parameters associated with the device referred to by + fd to the values in the termios structure referenced by pTermios. + + Behavior is modified by the value of the OptAct parameter: + * TCSANOW: The change shall occur immediately. + * TCSADRAIN: The change shall occur after all output written to fd is + transmitted. This action should be used when changing parameters which + affect output. + * TCSAFLUSH: The change shall occur after all output written to fd is + transmitted, and all input so far received but not read shall be + discarded before the change is made. + + @param[in] fd The file descriptor for an open interactive IO device. + @param[in] OptAct Currently has no effect. + @param[in] pTermios A pointer to a termios structure into which to retrieve + attributes to set in the interactive IO device. + + @retval 0 The operation completed successfully. + @retval -1 An error occured and errno is set to indicate the error. + * EBADF - The fd argument is not a valid file descriptor. + * ENOTTY - The file associated with fd is not an interactive IO device. +**/ +int +tcsetattr ( + int fd, + int OptAct, // Currently ignored + const struct termios *pTermios + ) +{ + cIIO *IIO; + int RetVal; + struct __filedes *filp; + struct termios *Termio; + + RetVal = 0; + if(ValidateFD( fd, VALID_OPEN)) { + filp = &gMD->fdarray[fd]; + + if((filp->f_iflags & _S_ITTY) != 0) { + // fd is for a TTY or "Interactive IO" device + IIO = (cIIO *)filp->devdata; + Termio = &IIO->Termio; + (void)CopyMem((void *)Termio, (const void *)pTermios, sizeof(struct termios)); + } + else { + errno = ENOTTY; + RetVal = -1; + } + } + else { + errno = EBADF; + RetVal = -1; + } + return RetVal; +} + +/** Transmit pending output. + + Function is not yet implemented for UEFI. + + @param[in] fd Ignored + + @retval -1 This function is not yet supported. errno is set to ENOTSUP. +**/ +int +tcdrain (int fd) +{ + errno = ENOTSUP; + return -1; +} + +/** Suspend or restart the transmission or reception of data. + + This function will suspend or resume transmission or reception of data on + the file referred to by fd, depending on the value of Action. + + Function is not yet implemented for UEFI. + + @param[in] fd Ignored + @param[in] Action Ignored + + @retval -1 This function is not yet supported. errno is set to ENOTSUP. +**/ +int +tcflow ( + int fd, + int Action) +{ + errno = ENOTSUP; + return -1; +} + +/** Discard non-transmitted output data, non-read input data, or both. + + Function is not yet implemented for UEFI. + + @param[in] fd Ignored + @param[in] QueueSelector Ignored + + @retval -1 This function is not yet supported. errno is set to ENOTSUP. +**/ +int +tcflush ( + int fd, + int QueueSelector) +{ + errno = ENOTSUP; + return -1; +} + -- cgit v1.2.3