Home | History | Annotate | Download | only in InteractiveIO
      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
     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