[CMD]: Continue refactoring to lay out the way to using the CONUTILS library in CMD...
[reactos.git] / reactos / base / shell / cmd / console.c
index a01c0c8..b83686f 100644 (file)
@@ -21,7 +21,7 @@
 
 #define OUTPUT_BUFFER_SIZE  4096
 
-
+/* Cache codepage for text streams */
 UINT InputCodePage;
 UINT OutputCodePage;
 
@@ -50,6 +50,10 @@ BOOL IsConsoleHandle(HANDLE hHandle)
     return GetConsoleMode(hHandle, &dwMode);
 }
 
+
+
+/********************* Console STREAM IN utility functions ********************/
+
 VOID ConInDisable(VOID)
 {
     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
@@ -60,7 +64,6 @@ VOID ConInDisable(VOID)
     SetConsoleMode(hInput, dwMode);
 }
 
-
 VOID ConInEnable(VOID)
 {
     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
@@ -71,13 +74,11 @@ VOID ConInEnable(VOID)
     SetConsoleMode(hInput, dwMode);
 }
 
-
-VOID ConInFlush (VOID)
+VOID ConInFlush(VOID)
 {
     FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
 }
 
-
 VOID ConInKey(PINPUT_RECORD lpBuffer)
 {
     HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
@@ -96,7 +97,6 @@ VOID ConInKey(PINPUT_RECORD lpBuffer)
     while (TRUE);
 }
 
-
 VOID ConInString(LPTSTR lpInput, DWORD dwLength)
 {
     DWORD dwOldMode;
@@ -135,17 +135,25 @@ VOID ConInString(LPTSTR lpInput, DWORD dwLength)
     SetConsoleMode(hFile, dwOldMode);
 }
 
-static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
+
+
+/******************** Console STREAM OUT utility functions ********************/
+
+static VOID ConWrite(DWORD nStdHandle, TCHAR *str, DWORD len)
 {
-    DWORD dwWritten;
+    DWORD dwNumBytes = 0;
     HANDLE hOutput = GetStdHandle(nStdHandle);
     PVOID p;
 
+    /* If we don't write anything, just return */
+    if (!str || len == 0)
+        return;
+
     /* Check whether we are writing to a console and if so, write to it */
     if (IsConsoleHandle(hOutput))
     {
-        if (WriteConsole(hOutput, str, len, &dwWritten, NULL))
-            return;
+        WriteConsole(hOutput, str, len, &dwNumBytes, NULL);
+        return;
     }
 
     /* We're writing to a file or pipe instead of the console. Convert the
@@ -164,30 +172,38 @@ static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
 #endif
         /*
          * Find any newline character in the buffer,
-         * send the part BEFORE the newline, then send
-         * a carriage-return + newline, and then send
+         * write the part BEFORE the newline, then write
+         * a carriage-return + newline, and then write
          * the remaining part of the buffer.
          *
          * This fixes output in files and serial console.
          */
-        while (str && *(PWCHAR)str && len > 0)
+        while (len > 0)
         {
-            p = wcspbrk((PWCHAR)str, L"\r\n");
-            if (p)
+            /* Loop until we find a \r or \n character */
+            // FIXME: What about the pair \r\n ?
+            p = str;
+            while (len > 0 && *(PWCHAR)p != L'\r' && *(PWCHAR)p != L'\n')
             {
-                len -= ((PWCHAR)p - (PWCHAR)str) + 1;
-                WriteFile(hOutput, str, ((PWCHAR)p - (PWCHAR)str) * sizeof(WCHAR), &dwWritten, NULL);
-                WriteFile(hOutput, L"\r\n", 2 * sizeof(WCHAR), &dwWritten, NULL);
-                str = (PVOID)((PWCHAR)p + 1);
+                /* Advance one character */
+                p = (PVOID)((PWCHAR)p + 1);
+                len--;
             }
-            else
+
+            /* Write everything up to \r or \n */
+            dwNumBytes = ((PWCHAR)p - (PWCHAR)str) * sizeof(WCHAR);
+            WriteFile(hOutput, str, dwNumBytes, &dwNumBytes, NULL);
+
+            /* If we hit \r or \n ... */
+            if (len > 0 && (*(PWCHAR)p == L'\r' || *(PWCHAR)p == L'\n'))
             {
-                WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
-                break;
+                /* ... send a carriage-return + newline sequence and skip \r or \n */
+                WriteFile(hOutput, L"\r\n", 2 * sizeof(WCHAR), &dwNumBytes, NULL);
+                str = (PVOID)((PWCHAR)p + 1);
+                len--;
             }
         }
 
-        // WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
 #ifndef _UNICODE
         cmd_free(buffer);
 #endif
@@ -206,76 +222,127 @@ static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
 #endif
         /*
          * Find any newline character in the buffer,
-         * send the part BEFORE the newline, then send
-         * a carriage-return + newline, and then send
+         * write the part BEFORE the newline, then write
+         * a carriage-return + newline, and then write
          * the remaining part of the buffer.
          *
          * This fixes output in files and serial console.
          */
-        while (str && *(PCHAR)str && len > 0)
+        while (len > 0)
         {
-            p = strpbrk((PCHAR)str, "\r\n");
-            if (p)
+            /* Loop until we find a \r or \n character */
+            // FIXME: What about the pair \r\n ?
+            p = str;
+            while (len > 0 && *(PCHAR)p != '\r' && *(PCHAR)p != '\n')
             {
-                len -= ((PCHAR)p - (PCHAR)str) + 1;
-                WriteFile(hOutput, str, ((PCHAR)p - (PCHAR)str), &dwWritten, NULL);
-                WriteFile(hOutput, "\r\n", 2, &dwWritten, NULL);
-                str = (PVOID)((PCHAR)p + 1);
+                /* Advance one character */
+                p = (PVOID)((PCHAR)p + 1);
+                len--;
             }
-            else
+
+            /* Write everything up to \r or \n */
+            dwNumBytes = ((PCHAR)p - (PCHAR)str) * sizeof(CHAR);
+            WriteFile(hOutput, str, dwNumBytes, &dwNumBytes, NULL);
+
+            /* If we hit \r or \n ... */
+            if (len > 0 && (*(PCHAR)p == '\r' || *(PCHAR)p == '\n'))
             {
-                WriteFile(hOutput, str, len, &dwWritten, NULL);
-                break;
+                /* ... send a carriage-return + newline sequence and skip \r or \n */
+                WriteFile(hOutput, "\r\n", 2, &dwNumBytes, NULL);
+                str = (PVOID)((PCHAR)p + 1);
+                len--;
             }
         }
 
-        // WriteFile(hOutput, str, len, &dwWritten, NULL);
 #ifdef _UNICODE
         cmd_free(buffer);
 #endif
     }
 }
 
-VOID ConOutChar(TCHAR c)
-{
-    ConWrite(&c, 1, STD_OUTPUT_HANDLE);
-}
-
-VOID ConPuts(LPTSTR szText, DWORD nStdHandle)
+VOID ConPuts(DWORD nStdHandle, LPTSTR szText)
 {
-    ConWrite(szText, (DWORD)_tcslen(szText), nStdHandle);
+    ConWrite(nStdHandle, szText, (DWORD)_tcslen(szText));
 }
 
-VOID ConOutResPaging(BOOL NewPage, UINT resID)
+VOID ConResPuts(DWORD nStdHandle, UINT resID)
 {
     TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConOutPrintfPaging(NewPage, szMsg);
+    LoadString(CMD_ModuleHandle, resID, szMsg, ARRAYSIZE(szMsg));
+    ConPuts(nStdHandle, szMsg);
 }
 
-VOID ConOutResPuts(UINT resID)
+VOID ConOutChar(TCHAR c)
 {
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConPuts(szMsg, STD_OUTPUT_HANDLE);
+    ConWrite(STD_OUTPUT_HANDLE, &c, 1);
 }
 
-VOID ConOutPuts(LPTSTR szText)
+VOID ConErrChar(TCHAR c)
 {
-    ConPuts(szText, STD_OUTPUT_HANDLE);
+    ConWrite(STD_ERROR_HANDLE, &c, 1);
 }
 
-
-VOID ConPrintf(LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
+VOID ConPrintfV(DWORD nStdHandle, LPTSTR szFormat, va_list arg_ptr)
 {
     TCHAR szOut[OUTPUT_BUFFER_SIZE];
     DWORD len;
 
     len = (DWORD)_vstprintf(szOut, szFormat, arg_ptr);
-    ConWrite(szOut, len, nStdHandle);
+    ConWrite(nStdHandle, szOut, len);
+}
+
+VOID ConPrintf(DWORD nStdHandle, LPTSTR szFormat, ...)
+{
+    va_list arg_ptr;
+
+    va_start(arg_ptr, szFormat);
+    ConPrintfV(nStdHandle, szFormat, arg_ptr);
+    va_end(arg_ptr);
 }
 
-INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
+VOID ConResPrintf(DWORD nStdHandle, UINT resID, ...)
+{
+    TCHAR szMsg[RC_STRING_MAX_SIZE];
+    va_list arg_ptr;
+
+    va_start(arg_ptr, resID);
+    LoadString(CMD_ModuleHandle, resID, szMsg, ARRAYSIZE(szMsg));
+    ConPrintfV(nStdHandle, szMsg, arg_ptr);
+    va_end(arg_ptr);
+}
+
+VOID ConFormatMessage(DWORD nStdHandle, DWORD MessageId, ...)
+{
+    DWORD ret;
+    LPTSTR text;
+    va_list arg_ptr;
+
+    va_start(arg_ptr, MessageId);
+    ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                        NULL,
+                        MessageId,
+                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                        (LPTSTR)&text,
+                        0,
+                        &arg_ptr);
+    va_end(arg_ptr);
+
+    if (ret > 0)
+    {
+        ConPuts(nStdHandle, text);
+        LocalFree(text);
+    }
+    else
+    {
+        ConResPrintf(nStdHandle, STRING_CONSOLE_ERROR, MessageId);
+    }
+}
+
+
+
+/************************** Console PAGER functions ***************************/
+
+BOOL ConPrintfVPaging(DWORD nStdHandle, BOOL NewPage, LPTSTR szFormat, va_list arg_ptr)
 {
     INT len;
     CONSOLE_SCREEN_BUFFER_INFO csbi;
@@ -283,13 +350,13 @@ INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHa
     DWORD dwWritten;
     HANDLE hOutput = GetStdHandle(nStdHandle);
 
-    /* used to count number of lines since last pause */
+    /* Used to count number of lines since last pause */
     static int LineCount = 0;
 
-    /* used to see how big the screen is */
+    /* Used to see how big the screen is */
     int ScreenLines = 0;
 
-    /* chars since start of line */
+    /* Chars since start of line */
     int CharSL;
 
     int from = 0, i = 0;
@@ -297,26 +364,30 @@ INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHa
     if (NewPage == TRUE)
         LineCount = 0;
 
-    /* rest LineCount and return if no string have been given */
+    /* Reset LineCount and return if no string has been given */
     if (szFormat == NULL)
-        return 0;
+        return TRUE;
 
-    /* Get the size of the visual screen that can be printed too */
+    /* Get the size of the visual screen that can be printed to */
     if (!IsConsoleHandle(hOutput) || !GetConsoleScreenBufferInfo(hOutput, &csbi))
     {
         /* We assume it's a file handle */
-        ConPrintf(szFormat, arg_ptr, nStdHandle);
-        return 0;
+        ConPrintfV(nStdHandle, szFormat, arg_ptr);
+        return TRUE;
     }
-    /* Subtract 2 to account for "press any key..." and for the blank line at the end of PagePrompt() */
-    ScreenLines = (csbi.srWindow.Bottom  - csbi.srWindow.Top) - 4;
+
+    /*
+     * Get the number of lines currently displayed on screen, minus 1
+     * to account for the "press any key..." prompt from PagePrompt().
+     */
+    ScreenLines = (csbi.srWindow.Bottom - csbi.srWindow.Top);
     CharSL = csbi.dwCursorPosition.X;
 
-    /* Make sure they didn't make the screen to small */
+    /* Make sure the user doesn't have the screen too small */
     if (ScreenLines < 4)
     {
-        ConPrintf(szFormat, arg_ptr, nStdHandle);
-        return 0;
+        ConPrintfV(nStdHandle, szFormat, arg_ptr);
+        return TRUE;
     }
 
     len = _vstprintf(szOut, szFormat, arg_ptr);
@@ -335,10 +406,13 @@ INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHa
             WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
             from = i;
 
+            /* Prompt the user */
             if (PagePrompt() != PROMPT_YES)
-            {
-                return 1;
-            }
+                return FALSE;
+
+            // TODO: Recalculate 'ScreenLines' in case the user redimensions
+            // the window during the prompt.
+
             /* Reset the number of lines being printed */
             LineCount = 0;
         }
@@ -346,137 +420,30 @@ INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHa
 
     WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
 
-    return 0;
-}
-
-VOID ConErrFormatMessage(DWORD MessageId, ...)
-{
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    DWORD ret;
-    LPTSTR text;
-    va_list arg_ptr;
-
-    va_start(arg_ptr, MessageId);
-    ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-                        NULL,
-                        MessageId,
-                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                        (LPTSTR) &text,
-                        0,
-                        &arg_ptr);
-
-    va_end(arg_ptr);
-    if (ret > 0)
-    {
-        ConErrPuts(text);
-        LocalFree(text);
-    }
-    else
-    {
-        LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
-        ConErrPrintf(szMsg);
-    }
-}
-
-VOID ConOutFormatMessage(DWORD MessageId, ...)
-{
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    DWORD ret;
-    LPTSTR text;
-    va_list arg_ptr;
-
-    va_start(arg_ptr, MessageId);
-    ret = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-                        NULL,
-                        MessageId,
-                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                        (LPTSTR) &text,
-                        0,
-                        &arg_ptr);
-
-    va_end(arg_ptr);
-    if (ret > 0)
-    {
-        ConErrPuts(text);
-        LocalFree(text);
-    }
-    else
-    {
-        LoadString(CMD_ModuleHandle, STRING_CONSOLE_ERROR, szMsg, RC_STRING_MAX_SIZE);
-        ConErrPrintf(szMsg);
-    }
-}
-
-VOID ConOutResPrintf(UINT resID, ...)
-{
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    va_list arg_ptr;
-
-    va_start(arg_ptr, resID);
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConPrintf(szMsg, arg_ptr, STD_OUTPUT_HANDLE);
-    va_end(arg_ptr);
-}
-
-VOID ConOutPrintf(LPTSTR szFormat, ...)
-{
-    va_list arg_ptr;
-
-    va_start(arg_ptr, szFormat);
-    ConPrintf(szFormat, arg_ptr, STD_OUTPUT_HANDLE);
-    va_end(arg_ptr);
+    return TRUE;
 }
 
-INT ConOutPrintfPaging(BOOL NewPage, LPTSTR szFormat, ...)
+BOOL ConOutPrintfPaging(BOOL NewPage, LPTSTR szFormat, ...)
 {
-    INT iReturn;
+    BOOL bRet;
     va_list arg_ptr;
 
     va_start(arg_ptr, szFormat);
-    iReturn = ConPrintfPaging(NewPage, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
+    bRet = ConPrintfVPaging(STD_OUTPUT_HANDLE, NewPage, szFormat, arg_ptr);
     va_end(arg_ptr);
-    return iReturn;
-}
-
-VOID ConErrChar(TCHAR c)
-{
-    ConWrite(&c, 1, STD_ERROR_HANDLE);
-}
-
-
-VOID ConErrResPuts(UINT resID)
-{
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConPuts(szMsg, STD_ERROR_HANDLE);
-}
-
-VOID ConErrPuts(LPTSTR szText)
-{
-    ConPuts(szText, STD_ERROR_HANDLE);
+    return bRet;
 }
 
-
-VOID ConErrResPrintf(UINT resID, ...)
+VOID ConOutResPaging(BOOL NewPage, UINT resID)
 {
     TCHAR szMsg[RC_STRING_MAX_SIZE];
-    va_list arg_ptr;
-
-    va_start(arg_ptr, resID);
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConPrintf(szMsg, arg_ptr, STD_ERROR_HANDLE);
-    va_end(arg_ptr);
+    LoadString(CMD_ModuleHandle, resID, szMsg, ARRAYSIZE(szMsg));
+    ConOutPrintfPaging(NewPage, szMsg);
 }
 
-VOID ConErrPrintf(LPTSTR szFormat, ...)
-{
-    va_list arg_ptr;
 
-    va_start(arg_ptr, szFormat);
-    ConPrintf(szFormat, arg_ptr, STD_ERROR_HANDLE);
-    va_end(arg_ptr);
-}
 
+/************************** Console SCREEN functions **************************/
 
 VOID SetCursorXY(SHORT x, SHORT y)
 {
@@ -537,4 +504,85 @@ VOID GetScreenSize(PSHORT maxx, PSHORT maxy)
     if (maxy) *maxy = csbi.dwSize.Y;
 }
 
+
+
+
+BOOL ConSetTitle(IN LPCTSTR lpConsoleTitle)
+{
+    /* Now really set the console title */
+    return SetConsoleTitle(lpConsoleTitle);
+}
+
+#ifdef INCLUDE_CMD_BEEP
+VOID ConRingBell(HANDLE hOutput)
+{
+#if 0
+    /* Emit an error beep sound */
+    if (IsConsoleHandle(hOutput))
+        Beep(800, 200);
+    else if (IsTTYHandle(hOutput))
+        ConOutPuts(_T("\a")); // BEL character 0x07
+    else
+#endif
+        MessageBeep(-1);
+}
+#endif
+
+#ifdef INCLUDE_CMD_CLS
+VOID ConClearScreen(HANDLE hOutput)
+{
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    COORD coPos;
+    DWORD dwWritten;
+
+    if (GetConsoleScreenBufferInfo(hOutput, &csbi))
+    {
+        coPos.X = 0;
+        coPos.Y = 0;
+        FillConsoleOutputAttribute(hOutput, csbi.wAttributes,
+                                   csbi.dwSize.X * csbi.dwSize.Y,
+                                   coPos, &dwWritten);
+        FillConsoleOutputCharacter(hOutput, _T(' '),
+                                   csbi.dwSize.X * csbi.dwSize.Y,
+                                   coPos, &dwWritten);
+        SetConsoleCursorPosition(hOutput, coPos);
+    }
+    else
+    {
+        ConOutChar(_T('\f'));
+    }
+}
+#endif
+
+#ifdef INCLUDE_CMD_COLOR
+BOOL ConSetScreenColor(HANDLE hOutput, WORD wColor, BOOL bFill)
+{
+    DWORD dwWritten;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    COORD coPos;
+
+    /* Foreground and Background colors can't be the same */
+    if ((wColor & 0x0F) == (wColor & 0xF0) >> 4)
+        return FALSE;
+
+    /* Fill the whole background if needed */
+    if (bFill)
+    {
+        GetConsoleScreenBufferInfo(hOutput, &csbi);
+
+        coPos.X = 0;
+        coPos.Y = 0;
+        FillConsoleOutputAttribute(hOutput,
+                                   wColor & 0x00FF,
+                                   csbi.dwSize.X * csbi.dwSize.Y,
+                                   coPos,
+                                   &dwWritten);
+    }
+
+    /* Set the text attribute */
+    SetConsoleTextAttribute(hOutput, wColor & 0x00FF);
+    return TRUE;
+}
+#endif
+
 /* EOF */