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