]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/LibC/Uefi/InteractiveIO/IIO.c
2 Definitions for the Interactive IO library.
4 The functions assume that isatty() is TRUE at the time they are called.
6 Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>
7 Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
8 This program and the accompanying materials are licensed and made available
9 under the terms and conditions of the BSD License which accompanies this
10 distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php.
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Library/MemoryAllocationLib.h>
19 #include <LibConfig.h>
23 #include <sys/syslimits.h>
24 #include <sys/termios.h>
25 #include <Device/IIO.h>
27 #include "IIOutilities.h"
28 #include "IIOechoCtrl.h"
30 // Instrumentation used for debugging
31 #define IIO_C_DEBUG 0 ///< Set to 1 to enable instrumentation, 0 to disable
34 static volatile size_t IIO_C_WRemainder
= 0; ///< Characters in Out buffer after IIO_Write
35 static volatile size_t IIO_C_RRemainder
= 0; ///< Characters in In buffer after IIO_Read
37 #define W_INSTRUMENT IIO_C_WRemainder =
38 #define R_INSTRUMENT IIO_C_RRemainder =
39 #else // ! IIO_C_DEBUG -- don't instrument code
40 #define W_INSTRUMENT (void)
41 #define R_INSTRUMENT (void)
44 /** Read from an Interactive IO device.
46 NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters.
47 They will need to be converted to MBCS when returned.
49 Input is line buffered if ICANON is set,
50 otherwise MIN determines how many characters to input.
51 Currently MIN is always zero, meaning 0 or 1 character is input in
54 @param[in] filp Pointer to the descriptor of the device (file) to be read.
55 @param[in] BufferSize Maximum number of bytes to be returned to the caller.
56 @param[out] Buffer Pointer to the buffer where the input is to be stored.
58 @retval -1 An error occurred. No data is available.
59 @retval 0 No data was available. Try again later.
60 @retval >0 The number of bytes consumed by the returned data.
66 struct __filedes
*filp
,
80 Flags
= This
->Termio
.c_lflag
;
82 NumRead
= IIO_CanonRead(filp
);
85 NumRead
= IIO_NonCanonRead(filp
);
87 // At this point, the input has been accumulated in the input buffer.
88 if(filp
->f_iflags
& _S_IWTTY
) {
89 // Data in InBuf is wide characters. Convert to MBCS
90 // First, convert into a linear buffer
91 NumRead
= This
->InBuf
->Copy(This
->InBuf
, gMD
->UString2
, (INT32
)UNICODE_STRING_MAX
-1);
92 gMD
->UString2
[NumRead
] = 0; // Ensure that the buffer is terminated
93 // Determine the needed space
94 XlateSz
= EstimateWtoM((const wchar_t *)gMD
->UString2
, BufferSize
, &Needed
);
96 // Now translate this into MBCS in Buffer
97 NumRead
= wcstombs((char *)Buffer
, (const wchar_t *)gMD
->UString2
, XlateSz
);
99 // Consume the translated characters
100 (void) This
->InBuf
->Flush(This
->InBuf
, Needed
);
103 // Data in InBuf is narrow characters. Use verbatim.
104 NumRead
= This
->InBuf
->Read(This
->InBuf
, Buffer
, (INT32
)BufferSize
);
107 IIO_C_RRemainder
= This
->InBuf
->Count(This
->InBuf
, AsElements
);
108 #endif // IIO_C_DEBUG
113 /** Handle write to a Terminal (Interactive) device.
115 Processes characters from buffer buf and writes them to the Terminal device
118 The parameter buf points to a MBCS string to be output. This is processed
119 and buffered one character at a time by IIO_WriteOne() which handles TAB
120 expansion, NEWLINE to CARRIAGE_RETURN + NEWLINE expansion, as well as
121 basic line editing functions. The number of characters actually written to
122 the output device will seldom equal the number of characters consumed from
125 In this implementation, all of the special characters processed by
126 IIO_WriteOne() are single-byte characters with values less than 128.
127 (7-bit ASCII or the single-byte UTF-8 characters)
129 Every byte that is not one of the recognized special characters is passed,
130 unchanged, to the Terminal device.
132 @param[in] filp Pointer to a file descriptor structure.
133 @param[in] buf Pointer to the MBCS string to be output.
134 @param[in] N Number of bytes in buf.
136 @retval >=0 Number of bytes consumed from buf and sent to the
143 struct __filedes
*filp
,
157 wchar_t OutChar
[2]; // Just in case we run into a 4-byte MBCS character
162 /* Determine what the current screen size is. Also validates the output device. */
163 OutMode
= IIO_GetOutputSize(filp
->MyFD
, &MaxColumn
, &MaxRow
);
165 This
= filp
->devdata
;
166 if((This
!= NULL
) && (OutMode
>= 0)) {
167 if(filp
->MyFD
== STDERR_FILENO
) {
168 OutBuf
= This
->ErrBuf
;
169 OutState
= &This
->ErrState
;
172 OutBuf
= This
->OutBuf
;
173 OutState
= &This
->OutState
;
176 /* Set the maximum screen dimensions. */
177 This
->MaxColumn
= MaxColumn
;
178 This
->MaxRow
= MaxRow
;
180 /* Record where the cursor is at the beginning of the Output operation. */
181 (void)IIO_GetCursorPosition(filp
->MyFD
, &This
->InitialXY
.Column
, &This
->InitialXY
.Row
);
182 This
->CurrentXY
.Column
= This
->InitialXY
.Column
;
183 This
->CurrentXY
.Row
= This
->InitialXY
.Row
;
186 OutChar
[0] = (wchar_t)buf
[0];
187 while((OutChar
[0] != 0) && (NumConsumed
< N
)) {
188 CharLen
= mbrtowc(OutChar
, (const char *)&buf
[NumConsumed
], MB_CUR_MAX
, OutState
);
189 if (CharLen
< 0) { // Encoding Error
190 OutChar
[0] = BLOCKELEMENT_LIGHT_SHADE
;
191 CharLen
= 1; // Consume a byte
192 (void)mbrtowc(NULL
, NULL
, 1, OutState
); // Re-Initialize the conversion state
194 NumProc
= IIO_WriteOne(filp
, OutBuf
, OutChar
[0]);
196 // Successfully processed and buffered one character
197 NumConsumed
+= CharLen
; // Index of start of next character
200 if (errno
== ENOSPC
) {
201 // Not enough room in OutBuf to hold a potentially expanded character
204 return -1; // Something corrupted and filp->devdata is now NULL
207 // At this point, the characters to write are in OutBuf
208 // First, linearize the buffer
209 NumProc
= OutBuf
->Copy(OutBuf
, gMD
->UString
, UNICODE_STRING_MAX
-1);
210 gMD
->UString
[NumProc
] = 0; // Ensure that the buffer is terminated
212 if(filp
->f_iflags
& _S_IWTTY
) {
213 // Output device expects wide characters, Output what we have
214 NumProc
= filp
->f_ops
->fo_write(filp
, NULL
, NumProc
, gMD
->UString
);
216 // Consume the output characters
217 W_INSTRUMENT OutBuf
->Flush(OutBuf
, NumProc
);
220 // Output device expects narrow characters, convert to MBCS
221 MbcsPtr
= (char *)gMD
->UString2
;
222 // Determine the needed space. NumProc is the number of bytes needed.
223 NumProc
= (ssize_t
)EstimateWtoM((const wchar_t *)gMD
->UString
, UNICODE_STRING_MAX
* sizeof(wchar_t), &CharLen
);
225 // Now translate this into MBCS in the buffer pointed to by MbcsPtr.
226 // The returned value, NumProc, is the resulting number of bytes.
227 NumProc
= wcstombs(MbcsPtr
, (const wchar_t *)gMD
->UString
, NumProc
);
228 MbcsPtr
[NumProc
] = 0; // Ensure the buffer is terminated
230 // Send the MBCS buffer to Output
231 NumProc
= filp
->f_ops
->fo_write(filp
, NULL
, NumProc
, MbcsPtr
);
232 // Mark the Mbcs buffer after the last byte actually written
233 MbcsPtr
[NumProc
] = 0;
234 // Count the CHARACTERS actually sent
235 CharLen
= CountMbcsChars(MbcsPtr
);
237 // Consume the number of output characters actually sent
238 W_INSTRUMENT OutBuf
->Flush(OutBuf
, CharLen
);
245 // Otherwise, errno is already set.
250 /** Echo a character to an output device.
251 Performs translation and edit processing depending upon termios flags.
253 @param[in] filp A pointer to a file descriptor structure.
254 @param[in] EChar The character to echo.
255 @param[in] EchoIsOK TRUE if the caller has determined that characters
256 should be echoed. Otherwise, just buffer.
258 @return Returns the number of characters actually output.
264 struct __filedes
*filp
,
277 This
= filp
->devdata
;
279 OutBuf
= This
->OutBuf
;
280 LFlags
= This
->Termio
.c_lflag
& (ECHOK
| ECHOE
);
282 if((EChar
>= TtyFunKeyMin
) && (EChar
< TtyFunKeyMax
)) {
283 // A special function key was pressed, buffer it, don't echo, and activate.
284 // Process and buffer the character. May produce multiple characters.
285 NumProc
= IIO_EchoOne(filp
, EChar
, FALSE
); // Don't echo this character
286 EChar
= CHAR_LINEFEED
; // Every line must end with '\n' (legacy)
288 // Process and buffer the character. May produce multiple characters.
289 NumProc
= IIO_EchoOne(filp
, EChar
, EchoIsOK
);
291 // At this point, the character(s) to write are in OutBuf
292 // First, linearize the buffer
293 NumWritten
= OutBuf
->Copy(OutBuf
, gMD
->UString
, UNICODE_STRING_MAX
-1);
294 gMD
->UString
[NumWritten
] = 0; // Ensure that the buffer is terminated
296 if((EChar
== IIO_ECHO_KILL
) && (LFlags
& ECHOE
) && EchoIsOK
) {
297 // Position the cursor to the start of input.
298 (void)IIO_SetCursorPosition(filp
, &This
->InitialXY
);
301 if(filp
->f_iflags
& _S_IWTTY
) {
302 // Output device expects wide characters, Output what we have
303 NumWritten
= filp
->f_ops
->fo_write(filp
, NULL
, NumWritten
, gMD
->UString
);
306 // Output device expects narrow characters, convert to MBCS
307 MbcsPtr
= (char *)gMD
->UString2
;
308 // Determine the needed space
309 NumProc
= (ssize_t
)EstimateWtoM((const wchar_t *)gMD
->UString
, UNICODE_STRING_MAX
* sizeof(wchar_t), NULL
);
311 // Now translate this into MBCS in Buffer
312 NumWritten
= wcstombs(MbcsPtr
, (const wchar_t *)gMD
->UString
, NumProc
);
313 MbcsPtr
[NumWritten
] = 0; // Ensure the buffer is terminated
315 // Send the MBCS buffer to Output
316 NumWritten
= filp
->f_ops
->fo_write(filp
, NULL
, NumWritten
, MbcsPtr
);
318 // Consume the echoed characters
319 (void)OutBuf
->Flush(OutBuf
, NumWritten
);
321 if(EChar
== IIO_ECHO_KILL
) {
322 if(LFlags
== ECHOK
) {
323 NumWritten
= IIO_WriteOne(filp
, OutBuf
, CHAR_LINEFEED
);
325 else if((LFlags
& ECHOE
) && EchoIsOK
) {
326 // Position the cursor to the start of input.
327 (void)IIO_SetCursorPosition(filp
, &This
->InitialXY
);
341 FifoDelete(cFIFO
*Member
)
344 Member
->Delete(Member
);
348 /** Destructor for an IIO instance.
350 Releases all resources used by a particular IIO instance.
360 FifoDelete(Self
->ErrBuf
);
361 FifoDelete(Self
->OutBuf
);
362 FifoDelete(Self
->InBuf
);
363 if(Self
->AttrBuf
!= NULL
) {
364 FreePool(Self
->AttrBuf
);
370 /** Constructor for new IIO instances.
372 @return Returns NULL or a pointer to a new IIO instance.
382 IIO
= (cIIO
*)AllocateZeroPool(sizeof(cIIO
));
384 IIO
->InBuf
= New_cFIFO(MAX_INPUT
, sizeof(wchar_t));
385 IIO
->OutBuf
= New_cFIFO(MAX_OUTPUT
, sizeof(wchar_t));
386 IIO
->ErrBuf
= New_cFIFO(MAX_OUTPUT
, sizeof(wchar_t));
387 IIO
->AttrBuf
= (UINT8
*)AllocateZeroPool(MAX_OUTPUT
);
389 if((IIO
->InBuf
== NULL
) || (IIO
->OutBuf
== NULL
) ||
390 (IIO
->ErrBuf
== NULL
) || (IIO
->AttrBuf
== NULL
))
396 IIO
->Delete
= IIO_Delete
;
397 IIO
->Read
= IIO_Read
;
398 IIO
->Write
= IIO_Write
;
399 IIO
->Echo
= IIO_Echo
;
401 // Initialize Termio member
402 TempBuf
= &IIO
->Termio
.c_cc
[0];
403 TempBuf
[0] = 8; // Default length for TABs
404 for(i
=1; i
< NCCS
; ++i
) {
405 TempBuf
[i
] = _POSIX_VDISABLE
;
409 IIO
->Termio
.c_ispeed
= B115200
;
410 IIO
->Termio
.c_ospeed
= B115200
;
411 IIO
->Termio
.c_iflag
= ICRNL
;
412 IIO
->Termio
.c_oflag
= OPOST
| ONLCR
| ONOCR
| ONLRET
;
413 IIO
->Termio
.c_cflag
= 0;
414 IIO
->Termio
.c_lflag
= ECHO
| ECHONL
;