+++ /dev/null
-/** @file\r
- Definitions for the Interactive IO library.\r
-\r
- The functions assume that isatty() is TRUE at the time they are called.\r
-\r
- Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>\r
- Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials are licensed and made available\r
- under the terms and conditions of the BSD License which accompanies this\r
- distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-**/\r
-#include <Uefi.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-\r
-#include <LibConfig.h>\r
-\r
-#include <assert.h>\r
-#include <errno.h>\r
-#include <sys/syslimits.h>\r
-#include <sys/termios.h>\r
-#include <Device/IIO.h>\r
-#include <MainData.h>\r
-#include "IIOutilities.h"\r
-#include "IIOechoCtrl.h"\r
-\r
-// Instrumentation used for debugging\r
-#define IIO_C_DEBUG 0 ///< Set to 1 to enable instrumentation, 0 to disable\r
-\r
-#if IIO_C_DEBUG\r
- static volatile size_t IIO_C_WRemainder = 0; ///< Characters in Out buffer after IIO_Write\r
- static volatile size_t IIO_C_RRemainder = 0; ///< Characters in In buffer after IIO_Read\r
-\r
- #define W_INSTRUMENT IIO_C_WRemainder =\r
- #define R_INSTRUMENT IIO_C_RRemainder =\r
-#else // ! IIO_C_DEBUG -- don't instrument code\r
- #define W_INSTRUMENT (void)\r
- #define R_INSTRUMENT (void)\r
-#endif // IIO_C_DEBUG\r
-\r
-/** Read from an Interactive IO device.\r
-\r
- NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters.\r
- They will need to be converted to MBCS when returned.\r
-\r
- Input is line buffered if ICANON is set,\r
- otherwise MIN determines how many characters to input.\r
- Currently MIN is always zero, meaning 0 or 1 character is input in\r
- noncanonical mode.\r
-\r
- @param[in] filp Pointer to the descriptor of the device (file) to be read.\r
- @param[in] BufferSize Maximum number of bytes to be returned to the caller.\r
- @param[out] Buffer Pointer to the buffer where the input is to be stored.\r
-\r
- @retval -1 An error occurred. No data is available.\r
- @retval 0 No data was available. Try again later.\r
- @retval >0 The number of bytes consumed by the returned data.\r
-**/\r
-static\r
-ssize_t\r
-EFIAPI\r
-IIO_Read(\r
- struct __filedes *filp,\r
- size_t BufferSize,\r
- VOID *Buffer\r
- )\r
-{\r
- cIIO *This;\r
- ssize_t NumRead;\r
- tcflag_t Flags;\r
- size_t XlateSz;\r
- size_t Needed;\r
-\r
- NumRead = -1;\r
- This = filp->devdata;\r
- if(This != NULL) {\r
- Flags = This->Termio.c_lflag;\r
- if(Flags & ICANON) {\r
- NumRead = IIO_CanonRead(filp);\r
- }\r
- else {\r
- NumRead = IIO_NonCanonRead(filp);\r
- }\r
- // At this point, the input has been accumulated in the input buffer.\r
- if(filp->f_iflags & _S_IWTTY) {\r
- // Data in InBuf is wide characters. Convert to MBCS\r
- // First, convert into a linear buffer\r
- NumRead = This->InBuf->Copy(This->InBuf, gMD->UString2, (INT32)UNICODE_STRING_MAX-1);\r
- gMD->UString2[NumRead] = 0; // Ensure that the buffer is terminated\r
- // Determine the needed space\r
- XlateSz = EstimateWtoM((const wchar_t *)gMD->UString2, BufferSize, &Needed);\r
-\r
- // Now translate this into MBCS in Buffer\r
- NumRead = wcstombs((char *)Buffer, (const wchar_t *)gMD->UString2, XlateSz);\r
-\r
- // Consume the translated characters\r
- (void) This->InBuf->Flush(This->InBuf, Needed);\r
- }\r
- else {\r
- // Data in InBuf is narrow characters. Use verbatim.\r
- NumRead = This->InBuf->Read(This->InBuf, Buffer, (INT32)BufferSize);\r
- }\r
-#if IIO_C_DEBUG\r
- IIO_C_RRemainder = This->InBuf->Count(This->InBuf, AsElements);\r
-#endif // IIO_C_DEBUG\r
- }\r
- return NumRead;\r
-}\r
-\r
-/** Handle write to a Terminal (Interactive) device.\r
-\r
- Processes characters from buffer buf and writes them to the Terminal device\r
- specified by filp.\r
-\r
- The parameter buf points to a MBCS string to be output. This is processed\r
- and buffered one character at a time by IIO_WriteOne() which handles TAB\r
- expansion, NEWLINE to CARRIAGE_RETURN + NEWLINE expansion, as well as\r
- basic line editing functions. The number of characters actually written to\r
- the output device will seldom equal the number of characters consumed from\r
- buf.\r
-\r
- In this implementation, all of the special characters processed by\r
- IIO_WriteOne() are single-byte characters with values less than 128.\r
- (7-bit ASCII or the single-byte UTF-8 characters)\r
-\r
- Every byte that is not one of the recognized special characters is passed,\r
- unchanged, to the Terminal device.\r
-\r
- @param[in] filp Pointer to a file descriptor structure.\r
- @param[in] buf Pointer to the MBCS string to be output.\r
- @param[in] N Number of bytes in buf.\r
-\r
- @retval >=0 Number of bytes consumed from buf and sent to the\r
- Terminal device.\r
-**/\r
-static\r
-ssize_t\r
-EFIAPI\r
-IIO_Write(\r
- struct __filedes *filp,\r
- const char *buf,\r
- ssize_t N\r
- )\r
-{\r
- cIIO *This;\r
- cFIFO *OutBuf;\r
- mbstate_t *OutState;\r
- char *MbcsPtr;\r
- ssize_t NumConsumed;\r
- ssize_t NumProc;\r
- size_t CharLen;\r
- UINTN MaxColumn;\r
- UINTN MaxRow;\r
- wchar_t OutChar[2]; // Just in case we run into a 4-byte MBCS character\r
- int OutMode;\r
-\r
- NumConsumed = -1;\r
-\r
- /* Determine what the current screen size is. Also validates the output device. */\r
- OutMode = IIO_GetOutputSize(filp->MyFD, &MaxColumn, &MaxRow);\r
-\r
- This = filp->devdata;\r
- if((This != NULL) && (OutMode >= 0)) {\r
- if(filp->MyFD == STDERR_FILENO) {\r
- OutBuf = This->ErrBuf;\r
- OutState = &This->ErrState;\r
- }\r
- else {\r
- OutBuf = This->OutBuf;\r
- OutState = &This->OutState;\r
- }\r
-\r
- /* Set the maximum screen dimensions. */\r
- This->MaxColumn = MaxColumn;\r
- This->MaxRow = MaxRow;\r
-\r
- /* Record where the cursor is at the beginning of the Output operation. */\r
- (void)IIO_GetCursorPosition(filp->MyFD, &This->InitialXY.Column, &This->InitialXY.Row);\r
- This->CurrentXY.Column = This->InitialXY.Column;\r
- This->CurrentXY.Row = This->InitialXY.Row;\r
-\r
- NumConsumed = 0;\r
- OutChar[0] = (wchar_t)buf[0];\r
- while((OutChar[0] != 0) && (NumConsumed < N)) {\r
- CharLen = mbrtowc(OutChar, (const char *)&buf[NumConsumed], MB_CUR_MAX, OutState);\r
- if (CharLen < 0) { // Encoding Error\r
- OutChar[0] = BLOCKELEMENT_LIGHT_SHADE;\r
- CharLen = 1; // Consume a byte\r
- (void)mbrtowc(NULL, NULL, 1, OutState); // Re-Initialize the conversion state\r
- }\r
- NumProc = IIO_WriteOne(filp, OutBuf, OutChar[0]);\r
- if(NumProc >= 0) {\r
- // Successfully processed and buffered one character\r
- NumConsumed += CharLen; // Index of start of next character\r
- }\r
- else {\r
- if (errno == ENOSPC) {\r
- // Not enough room in OutBuf to hold a potentially expanded character\r
- break;\r
- }\r
- return -1; // Something corrupted and filp->devdata is now NULL\r
- }\r
- }\r
- // At this point, the characters to write are in OutBuf\r
- // First, linearize the buffer\r
- NumProc = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
- gMD->UString[NumProc] = 0; // Ensure that the buffer is terminated\r
-\r
- if(filp->f_iflags & _S_IWTTY) {\r
- // Output device expects wide characters, Output what we have\r
- NumProc = filp->f_ops->fo_write(filp, NULL, NumProc, gMD->UString);\r
-\r
- // Consume the output characters\r
- W_INSTRUMENT OutBuf->Flush(OutBuf, NumProc);\r
- }\r
- else {\r
- // Output device expects narrow characters, convert to MBCS\r
- MbcsPtr = (char *)gMD->UString2;\r
- // Determine the needed space. NumProc is the number of bytes needed.\r
- NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), &CharLen);\r
-\r
- // Now translate this into MBCS in the buffer pointed to by MbcsPtr.\r
- // The returned value, NumProc, is the resulting number of bytes.\r
- NumProc = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
- MbcsPtr[NumProc] = 0; // Ensure the buffer is terminated\r
-\r
- // Send the MBCS buffer to Output\r
- NumProc = filp->f_ops->fo_write(filp, NULL, NumProc, MbcsPtr);\r
- // Mark the Mbcs buffer after the last byte actually written\r
- MbcsPtr[NumProc] = 0;\r
- // Count the CHARACTERS actually sent\r
- CharLen = CountMbcsChars(MbcsPtr);\r
-\r
- // Consume the number of output characters actually sent\r
- W_INSTRUMENT OutBuf->Flush(OutBuf, CharLen);\r
- }\r
- }\r
- else {\r
- if(This == NULL) {\r
- errno = EINVAL;\r
- }\r
- // Otherwise, errno is already set.\r
- }\r
- return NumConsumed;\r
-}\r
-\r
-/** Echo a character to an output device.\r
- Performs translation and edit processing depending upon termios flags.\r
-\r
- @param[in] filp A pointer to a file descriptor structure.\r
- @param[in] EChar The character to echo.\r
- @param[in] EchoIsOK TRUE if the caller has determined that characters\r
- should be echoed. Otherwise, just buffer.\r
-\r
- @return Returns the number of characters actually output.\r
-**/\r
-static\r
-ssize_t\r
-EFIAPI\r
-IIO_Echo(\r
- struct __filedes *filp,\r
- wchar_t EChar,\r
- BOOLEAN EchoIsOK\r
- )\r
-{\r
- cIIO *This;\r
- ssize_t NumWritten;\r
- cFIFO *OutBuf;\r
- char *MbcsPtr;\r
- ssize_t NumProc;\r
- tcflag_t LFlags;\r
-\r
- NumWritten = -1;\r
- This = filp->devdata;\r
- if(This != NULL) {\r
- OutBuf = This->OutBuf;\r
- LFlags = This->Termio.c_lflag & (ECHOK | ECHOE);\r
-\r
- if((EChar >= TtyFunKeyMin) && (EChar < TtyFunKeyMax)) {\r
- // A special function key was pressed, buffer it, don't echo, and activate.\r
- // Process and buffer the character. May produce multiple characters.\r
- NumProc = IIO_EchoOne(filp, EChar, FALSE); // Don't echo this character\r
- EChar = CHAR_LINEFEED; // Every line must end with '\n' (legacy)\r
- }\r
- // Process and buffer the character. May produce multiple characters.\r
- NumProc = IIO_EchoOne(filp, EChar, EchoIsOK);\r
-\r
- // At this point, the character(s) to write are in OutBuf\r
- // First, linearize the buffer\r
- NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
- gMD->UString[NumWritten] = 0; // Ensure that the buffer is terminated\r
-\r
- if((EChar == IIO_ECHO_KILL) && (LFlags & ECHOE) && EchoIsOK) {\r
- // Position the cursor to the start of input.\r
- (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
- }\r
- // Output the buffer\r
- if(filp->f_iflags & _S_IWTTY) {\r
- // Output device expects wide characters, Output what we have\r
- NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
- }\r
- else {\r
- // Output device expects narrow characters, convert to MBCS\r
- MbcsPtr = (char *)gMD->UString2;\r
- // Determine the needed space\r
- NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), NULL);\r
-\r
- // Now translate this into MBCS in Buffer\r
- NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
- MbcsPtr[NumWritten] = 0; // Ensure the buffer is terminated\r
-\r
- // Send the MBCS buffer to Output\r
- NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
- }\r
- // Consume the echoed characters\r
- (void)OutBuf->Flush(OutBuf, NumWritten);\r
-\r
- if(EChar == IIO_ECHO_KILL) {\r
- if(LFlags == ECHOK) {\r
- NumWritten = IIO_WriteOne(filp, OutBuf, CHAR_LINEFEED);\r
- }\r
- else if((LFlags & ECHOE) && EchoIsOK) {\r
- // Position the cursor to the start of input.\r
- (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
- }\r
- NumWritten = 0;\r
- }\r
- }\r
- else {\r
- errno = EINVAL;\r
- }\r
-\r
- return NumWritten;\r
-}\r
-\r
-static\r
-void\r
-FifoDelete(cFIFO *Member)\r
-{\r
- if(Member != NULL) {\r
- Member->Delete(Member);\r
- }\r
-}\r
-\r
-/** Destructor for an IIO instance.\r
-\r
- Releases all resources used by a particular IIO instance.\r
-**/\r
-static\r
-void\r
-EFIAPI\r
-IIO_Delete(\r
- cIIO *Self\r
- )\r
-{\r
- if(Self != NULL) {\r
- FifoDelete(Self->ErrBuf);\r
- FifoDelete(Self->OutBuf);\r
- FifoDelete(Self->InBuf);\r
- if(Self->AttrBuf != NULL) {\r
- FreePool(Self->AttrBuf);\r
- }\r
- FreePool(Self);\r
- }\r
-}\r
-\r
-/** Constructor for new IIO instances.\r
-\r
- @return Returns NULL or a pointer to a new IIO instance.\r
-**/\r
-cIIO *\r
-EFIAPI\r
-New_cIIO(void)\r
-{\r
- cIIO *IIO;\r
- cc_t *TempBuf;\r
- int i;\r
-\r
- IIO = (cIIO *)AllocateZeroPool(sizeof(cIIO));\r
- if(IIO != NULL) {\r
- IIO->InBuf = New_cFIFO(MAX_INPUT, sizeof(wchar_t));\r
- IIO->OutBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
- IIO->ErrBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
- IIO->AttrBuf = (UINT8 *)AllocateZeroPool(MAX_OUTPUT);\r
-\r
- if((IIO->InBuf == NULL) || (IIO->OutBuf == NULL) ||\r
- (IIO->ErrBuf == NULL) || (IIO->AttrBuf == NULL))\r
- {\r
- IIO_Delete(IIO);\r
- IIO = NULL;\r
- }\r
- else {\r
- IIO->Delete = IIO_Delete;\r
- IIO->Read = IIO_Read;\r
- IIO->Write = IIO_Write;\r
- IIO->Echo = IIO_Echo;\r
- }\r
- // Initialize Termio member\r
- TempBuf = &IIO->Termio.c_cc[0];\r
- TempBuf[0] = 8; // Default length for TABs\r
- for(i=1; i < NCCS; ++i) {\r
- TempBuf[i] = _POSIX_VDISABLE;\r
- }\r
- TempBuf[VMIN] = 0;\r
- TempBuf[VTIME] = 0;\r
- IIO->Termio.c_ispeed = B115200;\r
- IIO->Termio.c_ospeed = B115200;\r
- IIO->Termio.c_iflag = ICRNL;\r
- IIO->Termio.c_oflag = OPOST | ONLCR | ONOCR | ONLRET;\r
- IIO->Termio.c_cflag = 0;\r
- IIO->Termio.c_lflag = ECHO | ECHONL;\r
- }\r
- return IIO;\r
-}\r