]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StdLib/LibC/Uefi/InteractiveIO/IIO.c
StdLib: Fix IIO_Write() to return the number of bytes consumed, not characters output.
[mirror_edk2.git] / StdLib / LibC / Uefi / InteractiveIO / IIO.c
index 65b61d9bccde4f4c1e5c46a8cc7ea552dfcf37b4..547fdb3874f8a08b2f32ef49313ee285aaf104cc 100644 (file)
@@ -3,6 +3,7 @@
 \r
   The functions assume that isatty() is TRUE at the time they are called.\r
 \r
+  Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>\r
   Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials are licensed and made available\r
   under the terms and conditions of the BSD License which accompanies this\r
 #include  "IIOutilities.h"\r
 #include  "IIOechoCtrl.h"\r
 \r
+// Instrumentation used for debugging\r
+#define   IIO_C_DEBUG   0       ///< Set to 1 to enable instrumentation, 0 to disable\r
+\r
+#if IIO_C_DEBUG\r
+  static volatile size_t  IIO_C_WRemainder = 0;   ///< Characters in Out buffer after IIO_Write\r
+  static volatile size_t  IIO_C_RRemainder = 0;   ///< Characters in In buffer after IIO_Read\r
+\r
+  #define W_INSTRUMENT  IIO_C_WRemainder =\r
+  #define R_INSTRUMENT  IIO_C_RRemainder =\r
+#else // ! IIO_C_DEBUG -- don't instrument code\r
+  #define W_INSTRUMENT  (void)\r
+  #define R_INSTRUMENT  (void)\r
+#endif  // IIO_C_DEBUG\r
+\r
 /** Read from an Interactive IO device.\r
 \r
   NOTE: If _S_IWTTY is set, the internal buffer contains WIDE characters.\r
@@ -82,24 +97,44 @@ IIO_Read(
       NumRead = wcstombs((char *)Buffer, (const wchar_t *)gMD->UString2, XlateSz);\r
 \r
       // Consume the translated characters\r
-      (void)This->InBuf->Flush(This->InBuf, Needed);\r
+      (void) This->InBuf->Flush(This->InBuf, Needed);\r
     }\r
     else {\r
       // Data in InBuf is narrow characters.  Use verbatim.\r
       NumRead = This->InBuf->Read(This->InBuf, Buffer, (INT32)BufferSize);\r
     }\r
+#if IIO_C_DEBUG\r
+    IIO_C_RRemainder = This->InBuf->Count(This->InBuf, AsElements);\r
+#endif // IIO_C_DEBUG\r
   }\r
   return NumRead;\r
 }\r
 \r
-/** Process characters from buffer buf and write them to the output device\r
+/** Handle write to a Terminal (Interactive) device.\r
+\r
+    Processes characters from buffer buf and writes them to the Terminal device\r
     specified by filp.\r
 \r
+    The parameter buf points to a MBCS string to be output. This is processed\r
+    and buffered one character at a time by IIO_WriteOne() which handles TAB\r
+    expansion, NEWLINE to CARRIAGE_RETURN + NEWLINE expansion, as well as\r
+    basic line editing functions. The number of characters actually written to\r
+    the output device will seldom equal the number of characters consumed from\r
+    buf.\r
+\r
+    In this implementation, all of the special characters processed by\r
+    IIO_WriteOne() are single-byte characters with values less than 128.\r
+    (7-bit ASCII or the single-byte UTF-8 characters)\r
+\r
+    Every byte that is not one of the recognized special characters is passed,\r
+    unchanged, to the Terminal device.\r
+\r
     @param[in]      filp      Pointer to a file descriptor structure.\r
     @param[in]      buf       Pointer to the MBCS string to be output.\r
     @param[in]      N         Number of bytes in buf.\r
 \r
-    @retval   >=0    Number of bytes sent to the output device.\r
+    @retval   >=0     Number of bytes consumed from buf and sent to the\r
+                      Terminal device.\r
 **/\r
 static\r
 ssize_t\r
@@ -114,16 +149,15 @@ IIO_Write(
   cFIFO      *OutBuf;\r
   mbstate_t  *OutState;\r
   char       *MbcsPtr;\r
-  ssize_t     NumWritten;\r
+  ssize_t     NumConsumed;\r
   ssize_t     NumProc;\r
   size_t      CharLen;\r
   UINTN       MaxColumn;\r
   UINTN       MaxRow;\r
-  wchar_t     OutChar[2];     // Just in case we run into 4-byte MBCS character\r
+  wchar_t     OutChar[2];     // Just in case we run into 4-byte MBCS character\r
   int         OutMode;\r
 \r
-  errno = 0;          // indicate no error as default\r
-  NumWritten = -1;\r
+  NumConsumed = -1;\r
 \r
   /* Determine what the current screen size is. Also validates the output device. */\r
   OutMode = IIO_GetOutputSize(filp->MyFD, &MaxColumn, &MaxRow);\r
@@ -148,51 +182,61 @@ IIO_Write(
     This->CurrentXY.Column  = This->InitialXY.Column;\r
     This->CurrentXY.Row     = This->InitialXY.Row;\r
 \r
-\r
-    NumWritten = 0;\r
-    OutChar[0] = (wchar_t)buf[0];\r
-    while((OutChar[0] != 0) && (NumWritten < N)) {\r
-      CharLen = mbrtowc(OutChar, (const char *)&buf[NumWritten], MB_CUR_MAX, OutState);\r
+    NumConsumed = 0;\r
+    OutChar[0]  = (wchar_t)buf[0];\r
+    while((OutChar[0] != 0) && (NumConsumed < N)) {\r
+      CharLen = mbrtowc(OutChar, (const char *)&buf[NumConsumed], MB_CUR_MAX, OutState);\r
+      if (CharLen < 0) {  // Encoding Error\r
+        OutChar[0] = BLOCKELEMENT_LIGHT_SHADE;\r
+        CharLen = 1;  // Consume a byte\r
+        (void)mbrtowc(NULL, NULL, 1, OutState);  // Re-Initialize the conversion state\r
+      }\r
       NumProc = IIO_WriteOne(filp, OutBuf, OutChar[0]);\r
-      if(NumProc > 0) {\r
+      if(NumProc >= 0) {\r
         // Successfully processed and buffered one character\r
-        NumWritten += CharLen;   // Index of start of next character\r
-      }\r
-      else if(NumProc == -1) {\r
-        // Encoding Error\r
-        (void)mbrtowc(NULL, NULL, 1, OutState);  // Re-Initialize the conversion state\r
-        errno = EILSEQ;\r
-        break;\r
+        NumConsumed += CharLen;   // Index of start of next character\r
       }\r
       else {\r
-        // Last character was incomplete\r
-        break;\r
+        if (errno == ENOSPC) {\r
+          // Not enough room in OutBuf to hold a potentially expanded character\r
+          break;\r
+        }\r
+        return -1;    // Something corrupted and filp->devdata is now NULL\r
       }\r
     }\r
     // At this point, the characters to write are in OutBuf\r
     // First, linearize the buffer\r
-    NumWritten = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
-    gMD->UString[NumWritten] = 0;   // Ensure that the buffer is terminated\r
+    NumProc = OutBuf->Copy(OutBuf, gMD->UString, UNICODE_STRING_MAX-1);\r
+    gMD->UString[NumProc] = 0;   // Ensure that the buffer is terminated\r
 \r
     if(filp->f_iflags & _S_IWTTY) {\r
       // Output device expects wide characters, Output what we have\r
-      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, gMD->UString);\r
+      NumProc = filp->f_ops->fo_write(filp, NULL, NumProc, gMD->UString);\r
+\r
+      // Consume the output characters\r
+      W_INSTRUMENT OutBuf->Flush(OutBuf, NumProc);\r
     }\r
     else {\r
       // Output device expects narrow characters, convert to MBCS\r
       MbcsPtr = (char *)gMD->UString2;\r
-      // Determine the needed space\r
+      // Determine the needed space. NumProc is the number of bytes needed.\r
       NumProc = (ssize_t)EstimateWtoM((const wchar_t *)gMD->UString, UNICODE_STRING_MAX * sizeof(wchar_t), &CharLen);\r
 \r
-      // Now translate this into MBCS in Buffer\r
-      NumWritten = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
-      MbcsPtr[NumWritten] = 0;   // Ensure the buffer is terminated\r
+      // Now translate this into MBCS in the buffer pointed to by MbcsPtr.\r
+      // The returned value, NumProc, is the resulting number of bytes.\r
+      NumProc = wcstombs(MbcsPtr, (const wchar_t *)gMD->UString, NumProc);\r
+      MbcsPtr[NumProc] = 0;   // Ensure the buffer is terminated\r
 \r
       // Send the MBCS buffer to Output\r
-      NumWritten = filp->f_ops->fo_write(filp, NULL, NumWritten, MbcsPtr);\r
+      NumProc = filp->f_ops->fo_write(filp, NULL, NumProc, MbcsPtr);\r
+      // Mark the Mbcs buffer after the last byte actually written\r
+      MbcsPtr[NumProc] = 0;\r
+      // Count the CHARACTERS actually sent\r
+      CharLen = CountMbcsChars(MbcsPtr);\r
+\r
+      // Consume the number of output characters actually sent\r
+      W_INSTRUMENT OutBuf->Flush(OutBuf, CharLen);\r
     }\r
-    // Consume the translated characters\r
-    (void)OutBuf->Flush(OutBuf, NumWritten);\r
   }\r
   else {\r
     if(This == NULL) {\r
@@ -200,7 +244,7 @@ IIO_Write(
     }\r
     // Otherwise, errno is already set.\r
   }\r
-  return NumWritten;\r
+  return NumConsumed;\r
 }\r
 \r
 /** Echo a character to an output device.\r