]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/LibC/Uefi/InteractiveIO/IIOwrite.c
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / StdLib / LibC / Uefi / InteractiveIO / IIOwrite.c
CommitLineData
6c6c850a 1/** @file\r
2 Write to an Interactive I/O Output device.\r
3\r
4 The functions assume that isatty() is TRUE at the time they are called.\r
5 Since the UEFI console is a WIDE character device, these functions do all\r
6 processing using wide characters.\r
7\r
8 It is the responsibility of the caller, or higher level function, to perform\r
9 any necessary translation between wide and narrow characters.\r
10\r
0e565888 11 Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>\r
6c6c850a 12 This program and the accompanying materials are licensed and made available\r
13 under the terms and conditions of the BSD License which accompanies this\r
14 distribution. The full text of the license may be found at\r
15 http://opensource.org/licenses/bsd-license.php.\r
16\r
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
19**/\r
20#include <Uefi.h>\r
21\r
22#include <LibConfig.h>\r
23\r
24#include <assert.h>\r
25#include <errno.h>\r
26#include <sys/termios.h>\r
27#include <Device/IIO.h>\r
28\r
29static wchar_t Spaces[] = L" "; // Spaces for expanding TABs\r
30\r
31#define MAX_TAB_WIDTH ((int)(sizeof(Spaces) / sizeof(wchar_t)) - 1)\r
32\r
33#define MAX_EXPANSION 3\r
34\r
35/** Process and buffer one character for output.\r
36\r
37 @param[in] filp Pointer to a file descriptor structure.\r
38 @param[out] OBuf Pointer to the Output Buffer FIFO.\r
39 @param[in] InCh The wide character to process.\r
40\r
41 @retval <0 An error occurred. Reason is in errno.\r
42 * EINVAL The pointer to the IIO object is NULL.\r
43 * ENOSPC The OBuf FIFO is full.\r
44\r
45 @retval 0 A character was input but not placed in the output buffer.\r
46\r
47 @retval >0 The number of characters buffered. Normally 1, or 2.\r
48 If a character is discarded because of flag settings, a\r
49 1 will be returned.\r
50**/\r
51ssize_t\r
52IIO_WriteOne(struct __filedes *filp, cFIFO *OBuf, wchar_t InCh)\r
53{\r
54 cIIO *This;\r
55 struct termios *Termio;\r
56 tcflag_t OFlag;\r
57 ssize_t RetVal;\r
58 wchar_t wc[MAX_EXPANSION]; // Sub-buffer for conversions\r
59 wchar_t *wcb; // Pointer to either wc or spaces\r
60 int numW = 0; // Wide characters placed in OBuf\r
61 INT32 TabWidth; // Each TAB expands into this number of spaces\r
62 UINT32 CurColumn; // Current cursor column on the screen\r
63 UINT32 CurRow; // Current cursor row on the screen\r
64 UINT32 PrevColumn; // Previous column. Used to detect wrapping.\r
65 UINT32 AdjColumn; // Current cursor column on the screen\r
6c6c850a 66\r
67 RetVal = -1;\r
68 wcb = wc;\r
69 This = filp->devdata;\r
70 if((This != NULL) && (OBuf->FreeSpace(OBuf, AsElements) >= MAX_EXPANSION)) {\r
71 Termio = &This->Termio;\r
72 OFlag = Termio->c_oflag;\r
73 TabWidth = (INT32)This->Termio.c_cc[VTABLEN];\r
74 if(TabWidth > MAX_TAB_WIDTH) {\r
75 TabWidth = MAX_TAB_WIDTH;\r
76 }\r
77 CurColumn = This->CurrentXY.Column;\r
78 CurRow = This->CurrentXY.Row;\r
79\r
80 numW = 1; // The majority of characters buffer one character\r
6c6c850a 81 AdjColumn = 0;\r
82 if(OFlag & OPOST) {\r
83 /* Perform output processing */\r
84 switch(InCh) {\r
85 case CHAR_TAB: //{{\r
86 if(OFlag & OXTABS) {\r
87 if(TabWidth > 0) {\r
88 int SpaceIndex;\r
89\r
90 SpaceIndex = CurColumn % TabWidth; // Number of spaces after a Tab Stop\r
91 numW = TabWidth - SpaceIndex; // Number of spaces to the next Tab Stop\r
92 SpaceIndex = MAX_TAB_WIDTH - numW; // Index into the Spaces array\r
93 wcb = &Spaces[SpaceIndex]; // Point to the appropriate number of spaces\r
94 }\r
95 else {\r
96 wc[0] = L' ';\r
97 }\r
98 AdjColumn = numW;\r
99 }\r
100 else {\r
101 wc[0] = InCh; // Send the TAB itself - assumes that it does not move cursor.\r
102 }\r
103 break; //}}\r
104\r
105 case CHAR_CARRIAGE_RETURN: //{{\r
106 if((OFlag & OCRNL) == 0) {\r
107 if((OFlag & ONLRET) == 0) {\r
108 numW = 0; /* Discard the CR */\r
109 // Cursor doesn't move\r
110 }\r
111 else {\r
112 wc[0] = CHAR_CARRIAGE_RETURN;\r
113 CurColumn = 0;\r
114 }\r
115 break;\r
116 }\r
117 else {\r
118 InCh = CHAR_LINEFEED;\r
119 } //}}\r
120 // Fall through to the NL case\r
121 case CHAR_LINEFEED: //{{\r
122 if(OFlag & ONLCR) {\r
123 wc[0] = CHAR_CARRIAGE_RETURN;\r
124 wc[1] = CHAR_LINEFEED;\r
125 numW = 2;\r
126 CurColumn = 0;\r
127 }\r
6c6c850a 128 break; //}}\r
129\r
130 case CHAR_BACKSPACE: //{{\r
131 if(CurColumn > 0) {\r
132 wc[0] = CHAR_BACKSPACE;\r
133 CurColumn = (UINT32)ModuloDecrement(CurColumn, (UINT32)This->MaxColumn);\r
134 }\r
135 else {\r
136 numW = 0; // Discard the backspace if in column 0\r
137 }\r
138 break; //}}\r
139\r
140 case CHAR_EOT: //{{\r
141 if(OFlag & ONOEOT) {\r
142 numW = 0; // Discard the EOT character\r
143 // Cursor doesn't move\r
144 break;\r
145 } //}}\r
146 // Fall through to default in order to potentially output "^D"\r
147 default: //{{\r
148 if((InCh >= 0) && (InCh < L' ')) {\r
149 // InCh contains a control character\r
150 if(OFlag & OCTRL) {\r
151 wc[1] = InCh + L'@';\r
152 wc[0] = L'^';\r
153 numW = 2;\r
154 AdjColumn = 2;\r
155 }\r
156 else {\r
157 numW = 0; // Discard. Not a UEFI supported control character.\r
158 }\r
159 }\r
160 else {\r
161 // Regular printing character\r
162 wc[0] = InCh;\r
163 AdjColumn = 1;\r
164 }\r
165 break; //}}\r
166 }\r
167 if(numW < MAX_EXPANSION) {\r
168 wc[numW] = 0; // Terminate the sub-buffer\r
169 }\r
170 if(AdjColumn != 0) {\r
171 // Adjust the cursor position\r
172 PrevColumn = CurColumn;\r
173 CurColumn = ModuloAdd(PrevColumn, AdjColumn, (UINT32)This->MaxColumn);\r
174 if(CurColumn < PrevColumn) {\r
175 // We must have wrapped, so we are on the next Row\r
176 ++CurRow;\r
177 if(CurRow >= This->MaxRow) {\r
178 // The screen has scrolled so need to adjust Initial location.\r
179 --This->InitialXY.Row; // Initial row has moved up one\r
180 CurRow = (UINT32)(This->MaxRow - 1); // We stay on the bottom row\r
181 }\r
182 }\r
183 }\r
184 This->CurrentXY.Column = CurColumn;\r
185 This->CurrentXY.Row = CurRow;\r
186 }\r
187 else {\r
188 // Output processing disabled -- RAW output mode\r
189 wc[0] = InCh;\r
190 wc[1] = 0;\r
191 }\r
192 // Put the character(s) into the output buffer\r
193 if(numW > 0) {\r
194 (void)OBuf->Write(OBuf, (const void *)wcb, (size_t)numW);\r
195 }\r
196 RetVal = numW;\r
197 }\r
198 else {\r
199 if(This == NULL) {\r
200 errno = EINVAL;\r
201 }\r
202 else {\r
203 errno = ENOSPC;\r
204 }\r
205 }\r
206 return RetVal;\r
207}\r