]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/InteractiveIO/IIO.c
StdLib: Clarify and improve comments.
[mirror_edk2.git] / StdLib / LibC / Uefi / InteractiveIO / IIO.c
CommitLineData
6c6c850a 1/** @file\r
2 Definitions for the Interactive IO library.\r
3\r
4 The functions assume that isatty() is TRUE at the time they are called.\r
5\r
6 Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
7 This program and the accompanying materials are licensed and made available\r
8 under the terms and conditions of the BSD License which accompanies this\r
9 distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14**/\r
15#include <Uefi.h>\r
16#include <Library/MemoryAllocationLib.h>\r
17\r
18#include <LibConfig.h>\r
19\r
20#include <assert.h>\r
21#include <errno.h>\r
22#include <sys/syslimits.h>\r
23#include <sys/termios.h>\r
24#include <Device/IIO.h>\r
25#include <MainData.h>\r
26#include "IIOutilities.h"\r
27#include "IIOechoCtrl.h"\r
28\r
29/** Read from an Interactive IO device.\r
30\r
31 NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters.\r
32 They will need to be converted to MBCS when returned.\r
33\r
34 Input is line buffered if ICANON is set,\r
35 otherwise MIN determines how many characters to input.\r
36 Currently MIN is always zero, meaning 0 or 1 character is input in\r
37 noncanonical mode.\r
38\r
39 @param[in] filp Pointer to the descriptor of the device (file) to be read.\r
40 @param[in] BufferSize Maximum number of bytes to be returned to the caller.\r
41 @param[out] Buffer Pointer to the buffer where the input is to be stored.\r
42\r
43 @retval -1 An error occurred. No data is available.\r
44 @retval 0 No data was available. Try again later.\r
45 @retval >0 The number of bytes consumed by the returned data.\r
46**/\r
47static\r
48ssize_t\r
49EFIAPI\r
50IIO_Read(\r
51 struct __filedes *filp,\r
52 size_t BufferSize,\r
53 VOID *Buffer\r
54 )\r
55{\r
56 cIIO *This;\r
57 ssize_t NumRead;\r
58 tcflag_t Flags;\r
59 size_t XlateSz;\r
60 size_t Needed;\r
61\r
62 NumRead = -1;\r
63 This = filp->devdata;\r
64 if(This != NULL) {\r
65 Flags = This->Termio.c_lflag;\r
66 if(Flags & ICANON) {\r
67 NumRead = IIO_CanonRead(filp);\r
68 }\r
69 else {\r
70 NumRead = IIO_NonCanonRead(filp);\r
71 }\r
72 // At this point, the input has been accumulated in the input buffer.\r
73 if(filp->f_iflags & _S_IWTTY) {\r
74 // Data in InBuf is wide characters. Convert to MBCS\r
75 // First, convert into a linear buffer\r
76 NumRead = This->InBuf->Copy(This->InBuf, gMD->UString2, (INT32)UNICODE_STRING_MAX-1);\r
77 gMD->UString2[NumRead] = 0; // Ensure that the buffer is terminated\r
78 // Determine the needed space\r
79 XlateSz = EstimateWtoM((const wchar_t *)gMD->UString2, BufferSize, &Needed);\r
80\r
81 // Now translate this into MBCS in Buffer\r
82 NumRead = wcstombs((char *)Buffer, (const wchar_t *)gMD->UString2, XlateSz);\r
83\r
84 // Consume the translated characters\r
85 (void)This->InBuf->Flush(This->InBuf, Needed);\r
86 }\r
87 else {\r
88 // Data in InBuf is narrow characters. Use verbatim.\r
89 NumRead = This->InBuf->Read(This->InBuf, Buffer, (INT32)BufferSize);\r
90 }\r
91 }\r
92 return NumRead;\r
93}\r
94\r
95/** Process characters from buffer buf and write them to the output device\r
96 specified by filp.\r
97\r
98 @param[in] filp Pointer to a file descriptor structure.\r
99 @param[in] buf Pointer to the MBCS string to be output.\r
100 @param[in] N Number of bytes in buf.\r
101\r
102 @retval >=0 Number of bytes sent to the output device.\r
103**/\r
104static\r
105ssize_t\r
106EFIAPI\r
107IIO_Write(\r
108 struct __filedes *filp,\r
109 const char *buf,\r
110 ssize_t N\r
111 )\r
112{\r
113 cIIO *This;\r
114 cFIFO *OutBuf;\r
115 mbstate_t *OutState;\r
116 char *MbcsPtr;\r
117 ssize_t NumWritten;\r
118 ssize_t NumProc;\r
119 size_t CharLen;\r
120 UINTN MaxColumn;\r
121 UINTN MaxRow;\r
122 wchar_t OutChar[2]; // Just in case we run into 4-byte MBCS character\r
123 int OutMode;\r
124\r
125 errno = 0; // indicate no error as default\r
126 NumWritten = -1;\r
127\r
128 /* Determine what the current screen size is. Also validates the output device. */\r
129 OutMode = IIO_GetOutputSize(filp->MyFD, &MaxColumn, &MaxRow);\r
130\r
131 This = filp->devdata;\r
132 if((This != NULL) && (OutMode >= 0)) {\r
133 if(filp->MyFD == STDERR_FILENO) {\r
134 OutBuf = This->ErrBuf;\r
135 OutState = &This->ErrState;\r
136 }\r
137 else {\r
138 OutBuf = This->OutBuf;\r
139 OutState = &This->OutState;\r
140 }\r
141\r
142 /* Set the maximum screen dimensions. */\r
143 This->MaxColumn = MaxColumn;\r
144 This->MaxRow = MaxRow;\r
145\r
146 /* Record where the cursor is at the beginning of the Output operation. */\r
147 (void)IIO_GetCursorPosition(filp->MyFD, &This->InitialXY.Column, &This->InitialXY.Row);\r
148 This->CurrentXY.Column = This->InitialXY.Column;\r
149 This->CurrentXY.Row = This->InitialXY.Row;\r
150\r
151\r
152 NumWritten = 0;\r
153 OutChar[0] = (wchar_t)buf[0];\r
154 while((OutChar[0] != 0) && (NumWritten < N)) {\r
155 CharLen = mbrtowc(OutChar, (const char *)&buf[NumWritten], MB_CUR_MAX, OutState);\r
156 NumProc = IIO_WriteOne(filp, OutBuf, OutChar[0]);\r
157 if(NumProc > 0) {\r
158 // Successfully processed and buffered one character\r
159 NumWritten += CharLen; // Index of start of next character\r
160 }\r
161 else if(NumProc == -1) {\r
162 // Encoding Error\r
163 (void)mbrtowc(NULL, NULL, 1, OutState); // Re-Initialize the conversion state\r
164 errno = EILSEQ;\r
165 break;\r
166 }\r
167 else {\r
168 // Last character was incomplete\r
169 break;\r
170 }\r
171 }\r
172 // At this point, the characters to write are in OutBuf\r
173 // First, linearize the buffer\r
174 NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
175 gMD->UString[NumWritten] = 0; // Ensure that the buffer is terminated\r
176\r
177 if(filp->f_iflags & _S_IWTTY) {\r
178 // Output device expects wide characters, Output what we have\r
179 NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
180 }\r
181 else {\r
182 // Output device expects narrow characters, convert to MBCS\r
183 MbcsPtr = (char *)gMD->UString2;\r
184 // Determine the needed space\r
185 NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), &CharLen);\r
186\r
187 // Now translate this into MBCS in Buffer\r
188 NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
189 MbcsPtr[NumWritten] = 0; // Ensure the buffer is terminated\r
190\r
191 // Send the MBCS buffer to Output\r
192 NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
193 }\r
194 // Consume the translated characters\r
195 (void)OutBuf->Flush(OutBuf, NumWritten);\r
196 }\r
197 else {\r
198 if(This == NULL) {\r
199 errno = EINVAL;\r
200 }\r
201 // Otherwise, errno is already set.\r
202 }\r
203 return NumWritten;\r
204}\r
205\r
206/** Echo a character to an output device.\r
207 Performs translation and edit processing depending upon termios flags.\r
208\r
209 @param[in] filp A pointer to a file descriptor structure.\r
210 @param[in] EChar The character to echo.\r
211 @param[in] EchoIsOK TRUE if the caller has determined that characters\r
212 should be echoed. Otherwise, just buffer.\r
213\r
214 @return Returns the number of characters actually output.\r
215**/\r
216static\r
217ssize_t\r
218EFIAPI\r
219IIO_Echo(\r
220 struct __filedes *filp,\r
221 wchar_t EChar,\r
222 BOOLEAN EchoIsOK\r
223 )\r
224{\r
225 cIIO *This;\r
226 ssize_t NumWritten;\r
227 cFIFO *OutBuf;\r
228 char *MbcsPtr;\r
229 ssize_t NumProc;\r
230 tcflag_t LFlags;\r
231\r
232 NumWritten = -1;\r
233 This = filp->devdata;\r
234 if(This != NULL) {\r
235 OutBuf = This->OutBuf;\r
236 LFlags = This->Termio.c_lflag & (ECHOK | ECHOE);\r
237\r
238 if((EChar >= TtyFunKeyMin) && (EChar < TtyFunKeyMax)) {\r
239 // A special function key was pressed, buffer it, don't echo, and activate.\r
240 // Process and buffer the character. May produce multiple characters.\r
241 NumProc = IIO_EchoOne(filp, EChar, FALSE); // Don't echo this character\r
242 EChar = CHAR_LINEFEED; // Every line must end with '\n' (legacy)\r
243 }\r
244 // Process and buffer the character. May produce multiple characters.\r
245 NumProc = IIO_EchoOne(filp, EChar, EchoIsOK);\r
246\r
247 // At this point, the character(s) to write are in OutBuf\r
248 // First, linearize the buffer\r
249 NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
250 gMD->UString[NumWritten] = 0; // Ensure that the buffer is terminated\r
251\r
252 if((EChar == IIO_ECHO_KILL) && (LFlags & ECHOE) && EchoIsOK) {\r
253 // Position the cursor to the start of input.\r
254 (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
255 }\r
256 // Output the buffer\r
257 if(filp->f_iflags & _S_IWTTY) {\r
258 // Output device expects wide characters, Output what we have\r
259 NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
260 }\r
261 else {\r
262 // Output device expects narrow characters, convert to MBCS\r
263 MbcsPtr = (char *)gMD->UString2;\r
264 // Determine the needed space\r
265 NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), NULL);\r
266\r
267 // Now translate this into MBCS in Buffer\r
268 NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
269 MbcsPtr[NumWritten] = 0; // Ensure the buffer is terminated\r
270\r
271 // Send the MBCS buffer to Output\r
272 NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
273 }\r
274 // Consume the echoed characters\r
275 (void)OutBuf->Flush(OutBuf, NumWritten);\r
276\r
277 if(EChar == IIO_ECHO_KILL) {\r
278 if(LFlags == ECHOK) {\r
279 NumWritten = IIO_WriteOne(filp, OutBuf, CHAR_LINEFEED);\r
280 }\r
281 else if((LFlags & ECHOE) && EchoIsOK) {\r
282 // Position the cursor to the start of input.\r
283 (void)IIO_SetCursorPosition(filp, &This->InitialXY);\r
284 }\r
285 NumWritten = 0;\r
286 }\r
287 }\r
288 else {\r
289 errno = EINVAL;\r
290 }\r
291\r
292 return NumWritten;\r
293}\r
294\r
295static\r
296void\r
297FifoDelete(cFIFO *Member)\r
298{\r
299 if(Member != NULL) {\r
300 Member->Delete(Member);\r
301 }\r
302}\r
303\r
304/** Destructor for an IIO instance.\r
305\r
306 Releases all resources used by a particular IIO instance.\r
307**/\r
308static\r
309void\r
310EFIAPI\r
311IIO_Delete(\r
312 cIIO *Self\r
313 )\r
314{\r
315 if(Self != NULL) {\r
316 FifoDelete(Self->ErrBuf);\r
317 FifoDelete(Self->OutBuf);\r
318 FifoDelete(Self->InBuf);\r
319 if(Self->AttrBuf != NULL) {\r
320 FreePool(Self->AttrBuf);\r
321 }\r
322 FreePool(Self);\r
323 }\r
324}\r
325\r
326/** Constructor for new IIO instances.\r
327\r
328 @return Returns NULL or a pointer to a new IIO instance.\r
329**/\r
330cIIO *\r
331EFIAPI\r
332New_cIIO(void)\r
333{\r
334 cIIO *IIO;\r
335 cc_t *TempBuf;\r
336 int i;\r
337\r
338 IIO = (cIIO *)AllocateZeroPool(sizeof(cIIO));\r
339 if(IIO != NULL) {\r
340 IIO->InBuf = New_cFIFO(MAX_INPUT, sizeof(wchar_t));\r
341 IIO->OutBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
342 IIO->ErrBuf = New_cFIFO(MAX_OUTPUT, sizeof(wchar_t));\r
343 IIO->AttrBuf = (UINT8 *)AllocateZeroPool(MAX_OUTPUT);\r
344\r
345 if((IIO->InBuf == NULL) || (IIO->OutBuf == NULL) ||\r
346 (IIO->ErrBuf == NULL) || (IIO->AttrBuf == NULL))\r
347 {\r
348 IIO_Delete(IIO);\r
349 IIO = NULL;\r
350 }\r
351 else {\r
352 IIO->Delete = IIO_Delete;\r
353 IIO->Read = IIO_Read;\r
354 IIO->Write = IIO_Write;\r
355 IIO->Echo = IIO_Echo;\r
356 }\r
357 // Initialize Termio member\r
358 TempBuf = &IIO->Termio.c_cc[0];\r
359 TempBuf[0] = 8; // Default length for TABs\r
360 for(i=1; i < NCCS; ++i) {\r
361 TempBuf[i] = _POSIX_VDISABLE;\r
362 }\r
363 TempBuf[VMIN] = 0;\r
364 TempBuf[VTIME] = 0;\r
365 IIO->Termio.c_ispeed = B115200;\r
366 IIO->Termio.c_ospeed = B115200;\r
367 IIO->Termio.c_iflag = ICRNL;\r
368 IIO->Termio.c_oflag = OPOST | ONLCR | ONOCR | ONLRET;\r
369 IIO->Termio.c_cflag = 0;\r
370 IIO->Termio.c_lflag = ECHO | ECHONL;\r
371 }\r
372 return IIO;\r
373}\r