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 <sys/termios.h> 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
This commit is contained in:
210
StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c
Normal file
210
StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c
Normal file
@@ -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.<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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/termios.h>
|
||||
#include <Device/IIO.h>
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user