[CMD]: Continue refactoring to lay out the way to using the CONUTILS library in CMD...
[reactos.git] / reactos / base / shell / cmd / console.c
index 00eb826..b83686f 100644 (file)
@@ -7,13 +7,13 @@
  *    20-Jan-1999 (Eric Kohl)
  *        started
  *
- *    03-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>
+ *    03-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
  *        Remove all hardcoded strings in En.rc
  *
- *    01-Jul-2005 (Brandon Turner) <turnerb7@msu.edu>
+ *    01-Jul-2005 (Brandon Turner <turnerb7@msu.edu>)
  *        Added ConPrintfPaging and ConOutPrintfPaging
  *
- *    02-Feb-2007 (Paolo Devoti) <devotip at gmail.com>
+ *    02-Feb-2007 (Paolo Devoti <devotip at gmail.com>)
  *        Fixed ConPrintfPaging
  */
 
 
 #define OUTPUT_BUFFER_SIZE  4096
 
-
+/* Cache codepage for text streams */
 UINT InputCodePage;
 UINT OutputCodePage;
 
 
-VOID ConInDisable (VOID)
+BOOL IsConsoleHandle(HANDLE hHandle)
 {
-    HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
     DWORD dwMode;
 
-    GetConsoleMode (hInput, &dwMode);
-    dwMode &= ~ENABLE_PROCESSED_INPUT;
-    SetConsoleMode (hInput, dwMode);
+    /* Check whether the handle may be that of a console... */
+    if ((GetFileType(hHandle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR)
+        return FALSE;
+
+    /*
+     * It may be. Perform another test... The idea comes from the
+     * MSDN description of the WriteConsole API:
+     *
+     * "WriteConsole fails if it is used with a standard handle
+     *  that is redirected to a file. If an application processes
+     *  multilingual output that can be redirected, determine whether
+     *  the output handle is a console handle (one method is to call
+     *  the GetConsoleMode function and check whether it succeeds).
+     *  If the handle is a console handle, call WriteConsole. If the
+     *  handle is not a console handle, the output is redirected and
+     *  you should call WriteFile to perform the I/O."
+     */
+    return GetConsoleMode(hHandle, &dwMode);
 }
 
 
-VOID ConInEnable (VOID)
+
+/********************* Console STREAM IN utility functions ********************/
+
+VOID ConInDisable(VOID)
 {
-    HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
+    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
     DWORD dwMode;
 
-    GetConsoleMode (hInput, &dwMode);
-    dwMode |= ENABLE_PROCESSED_INPUT;
-    SetConsoleMode (hInput, dwMode);
+    GetConsoleMode(hInput, &dwMode);
+    dwMode &= ~ENABLE_PROCESSED_INPUT;
+    SetConsoleMode(hInput, dwMode);
 }
 
-
-VOID ConInFlush (VOID)
+VOID ConInEnable(VOID)
 {
-    FlushConsoleInputBuffer (GetStdHandle (STD_INPUT_HANDLE));
+    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
+    DWORD dwMode;
+
+    GetConsoleMode(hInput, &dwMode);
+    dwMode |= ENABLE_PROCESSED_INPUT;
+    SetConsoleMode(hInput, dwMode);
 }
 
+VOID ConInFlush(VOID)
+{
+    FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
+}
 
-VOID ConInKey (PINPUT_RECORD lpBuffer)
+VOID ConInKey(PINPUT_RECORD lpBuffer)
 {
-    HANDLE hInput = GetStdHandle (STD_INPUT_HANDLE);
+    HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
     DWORD  dwRead;
 
     if (hInput == INVALID_HANDLE_VALUE)
@@ -64,7 +89,7 @@ VOID ConInKey (PINPUT_RECORD lpBuffer)
 
     do
     {
-        ReadConsoleInput (hInput, lpBuffer, 1, &dwRead);
+        ReadConsoleInput(hInput, lpBuffer, 1, &dwRead);
         if ((lpBuffer->EventType == KEY_EVENT) &&
             (lpBuffer->Event.KeyEvent.bKeyDown == TRUE))
             break;
@@ -72,8 +97,7 @@ VOID ConInKey (PINPUT_RECORD lpBuffer)
     while (TRUE);
 }
 
-
-VOID ConInString (LPTSTR lpInput, DWORD dwLength)
+VOID ConInString(LPTSTR lpInput, DWORD dwLength)
 {
     DWORD dwOldMode;
     DWORD dwRead = 0;
@@ -87,13 +111,13 @@ VOID ConInString (LPTSTR lpInput, DWORD dwLength)
 #else
     pBuf = lpInput;
 #endif
-    ZeroMemory (lpInput, dwLength * sizeof(TCHAR));
-    hFile = GetStdHandle (STD_INPUT_HANDLE);
-    GetConsoleMode (hFile, &dwOldMode);
+    ZeroMemory(lpInput, dwLength * sizeof(TCHAR));
+    hFile = GetStdHandle(STD_INPUT_HANDLE);
+    GetConsoleMode(hFile, &dwOldMode);
 
-    SetConsoleMode (hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
+    SetConsoleMode(hFile, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
 
-    ReadFile (hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
+    ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
 
 #ifdef _UNICODE
     MultiByteToWideChar(InputCodePage, 0, pBuf, dwRead, lpInput, dwLength - 1);
@@ -108,16 +132,29 @@ VOID ConInString (LPTSTR lpInput, DWORD dwLength)
         }
     }
 
-    SetConsoleMode (hFile, dwOldMode);
+    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;
 
-    if (WriteConsole(hOutput, str, len, &dwWritten, NULL))
+    /* Check whether we are writing to a console and if so, write to it */
+    if (IsConsoleHandle(hOutput))
+    {
+        WriteConsole(hOutput, str, len, &dwNumBytes, NULL);
         return;
+    }
 
     /* We're writing to a file or pipe instead of the console. Convert the
      * string from TCHARs to the desired output format, if the two differ */
@@ -130,10 +167,43 @@ static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
             error_out_of_memory();
             return;
         }
-        len = MultiByteToWideChar(OutputCodePage, 0, str, len, buffer, len);
+        len = (DWORD)MultiByteToWideChar(OutputCodePage, 0, str, (INT)len, buffer, (INT)len);
         str = (PVOID)buffer;
 #endif
-        WriteFile(hOutput, str, len * sizeof(WCHAR), &dwWritten, NULL);
+        /*
+         * Find any newline character in the buffer,
+         * 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 (len > 0)
+        {
+            /* 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')
+            {
+                /* Advance one character */
+                p = (PVOID)((PWCHAR)p + 1);
+                len--;
+            }
+
+            /* 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'))
+            {
+                /* ... 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--;
+            }
+        }
+
 #ifndef _UNICODE
         cmd_free(buffer);
 #endif
@@ -150,51 +220,129 @@ static VOID ConWrite(TCHAR *str, DWORD len, DWORD nStdHandle)
         len = WideCharToMultiByte(OutputCodePage, 0, str, len, buffer, len * MB_LEN_MAX, NULL, NULL);
         str = (PVOID)buffer;
 #endif
-        WriteFile(hOutput, str, len, &dwWritten, NULL);
+        /*
+         * Find any newline character in the buffer,
+         * 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 (len > 0)
+        {
+            /* 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')
+            {
+                /* Advance one character */
+                p = (PVOID)((PCHAR)p + 1);
+                len--;
+            }
+
+            /* 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'))
+            {
+                /* ... send a carriage-return + newline sequence and skip \r or \n */
+                WriteFile(hOutput, "\r\n", 2, &dwNumBytes, NULL);
+                str = (PVOID)((PCHAR)p + 1);
+                len--;
+            }
+        }
+
 #ifdef _UNICODE
         cmd_free(buffer);
 #endif
     }
 }
 
-VOID ConOutChar (TCHAR c)
+VOID ConPuts(DWORD nStdHandle, LPTSTR szText)
 {
-    ConWrite(&c, 1, STD_OUTPUT_HANDLE);
+    ConWrite(nStdHandle, szText, (DWORD)_tcslen(szText));
 }
 
-VOID ConPuts(LPTSTR szText, DWORD nStdHandle)
+VOID ConResPuts(DWORD nStdHandle, UINT resID)
 {
-    ConWrite(szText, _tcslen(szText), nStdHandle);
+    TCHAR szMsg[RC_STRING_MAX_SIZE];
+    LoadString(CMD_ModuleHandle, resID, szMsg, ARRAYSIZE(szMsg));
+    ConPuts(nStdHandle, szMsg);
 }
 
-VOID ConOutResPaging(BOOL NewPage, UINT resID)
+VOID ConOutChar(TCHAR c)
 {
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConOutPrintfPaging(NewPage, szMsg);
+    ConWrite(STD_OUTPUT_HANDLE, &c, 1);
 }
 
-VOID ConOutResPuts (UINT resID)
+VOID ConErrChar(TCHAR c)
 {
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
+    ConWrite(STD_ERROR_HANDLE, &c, 1);
+}
+
+VOID ConPrintfV(DWORD nStdHandle, LPTSTR szFormat, va_list arg_ptr)
+{
+    TCHAR szOut[OUTPUT_BUFFER_SIZE];
+    DWORD len;
 
-    ConPuts(szMsg, STD_OUTPUT_HANDLE);
+    len = (DWORD)_vstprintf(szOut, szFormat, arg_ptr);
+    ConWrite(nStdHandle, szOut, len);
 }
 
-VOID ConOutPuts (LPTSTR szText)
+VOID ConPrintf(DWORD nStdHandle, LPTSTR szFormat, ...)
 {
-    ConPuts(szText, STD_OUTPUT_HANDLE);
+    va_list arg_ptr;
+
+    va_start(arg_ptr, szFormat);
+    ConPrintfV(nStdHandle, szFormat, arg_ptr);
+    va_end(arg_ptr);
 }
 
+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 ConPrintf(LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
+VOID ConFormatMessage(DWORD nStdHandle, DWORD MessageId, ...)
 {
-    TCHAR szOut[OUTPUT_BUFFER_SIZE];
-    ConWrite(szOut, _vstprintf(szOut, szFormat, arg_ptr), nStdHandle);
+    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);
+    }
 }
 
-INT ConPrintfPaging(BOOL NewPage, LPTSTR szFormat, va_list arg_ptr, DWORD nStdHandle)
+
+
+/************************** Console PAGER functions ***************************/
+
+BOOL ConPrintfVPaging(DWORD nStdHandle, BOOL NewPage, LPTSTR szFormat, va_list arg_ptr)
 {
     INT len;
     CONSOLE_SCREEN_BUFFER_INFO csbi;
@@ -202,267 +350,239 @@ 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;
 
-    if(NewPage == TRUE)
+    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
-    if (!GetConsoleScreenBufferInfo(hOutput, &csbi))
+    /* Get the size of the visual screen that can be printed to */
+    if (!IsConsoleHandle(hOutput) || !GetConsoleScreenBufferInfo(hOutput, &csbi))
     {
-        // we assuming its a file handle
-        ConPrintf(szFormat, arg_ptr, nStdHandle);
-        return 0;
+        /* We assume it's a file handle */
+        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 didnt make the screen to small
-    if(ScreenLines<4)
+    /* 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);
+    len = _vstprintf(szOut, szFormat, arg_ptr);
 
     while (i < len)
     {
-        // Search until the end of a line is reached
+        /* Search until the end of a line is reached */
         if (szOut[i++] != _T('\n') && ++CharSL < csbi.dwSize.X)
             continue;
 
         LineCount++;
         CharSL=0;
 
-        if(LineCount >= ScreenLines)
+        if (LineCount >= ScreenLines)
         {
             WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
             from = i;
 
-            if(PagePrompt() != PROMPT_YES)
-            {
-                return 1;
-            }
-            //reset the number of lines being printed
+            /* Prompt the user */
+            if (PagePrompt() != PROMPT_YES)
+                return FALSE;
+
+            // TODO: Recalculate 'ScreenLines' in case the user redimensions
+            // the window during the prompt.
+
+            /* Reset the number of lines being printed */
             LineCount = 0;
         }
     }
 
     WriteConsole(hOutput, &szOut[from], i-from, &dwWritten, NULL);
 
-    return 0;
+    return TRUE;
 }
 
-VOID ConErrFormatMessage (DWORD MessageId, ...)
+BOOL ConOutPrintfPaging(BOOL NewPage, LPTSTR szFormat, ...)
 {
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    DWORD ret;
-    LPTSTR text;
+    BOOL bRet;
     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);
-    }
+    va_start(arg_ptr, szFormat);
+    bRet = ConPrintfVPaging(STD_OUTPUT_HANDLE, NewPage, szFormat, arg_ptr);
+    va_end(arg_ptr);
+    return bRet;
 }
 
-VOID ConOutFormatMessage (DWORD MessageId, ...)
+VOID ConOutResPaging(BOOL NewPage, UINT resID)
 {
     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);
-    }
+    LoadString(CMD_ModuleHandle, resID, szMsg, ARRAYSIZE(szMsg));
+    ConOutPrintfPaging(NewPage, 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);
-}
+/************************** Console SCREEN functions **************************/
 
-INT ConOutPrintfPaging (BOOL NewPage, LPTSTR szFormat, ...)
+VOID SetCursorXY(SHORT x, SHORT y)
 {
-    INT iReturn;
-    va_list arg_ptr;
+    COORD coPos;
 
-    va_start (arg_ptr, szFormat);
-    iReturn = ConPrintfPaging(NewPage, szFormat, arg_ptr, STD_OUTPUT_HANDLE);
-    va_end (arg_ptr);
-    return iReturn;
+    coPos.X = x;
+    coPos.Y = y;
+    SetConsoleCursorPosition(GetStdHandle (STD_OUTPUT_HANDLE), coPos);
 }
 
-VOID ConErrChar (TCHAR c)
+VOID GetCursorXY(PSHORT x, PSHORT y)
 {
-    ConWrite(&c, 1, STD_ERROR_HANDLE);
-}
-
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
-VOID ConErrResPuts (UINT resID)
-{
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    LoadString(CMD_ModuleHandle, resID, szMsg, RC_STRING_MAX_SIZE);
-    ConPuts(szMsg, STD_ERROR_HANDLE);
-}
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
 
-VOID ConErrPuts (LPTSTR szText)
-{
-    ConPuts(szText, STD_ERROR_HANDLE);
+    *x = csbi.dwCursorPosition.X;
+    *y = csbi.dwCursorPosition.Y;
 }
 
-
-VOID ConErrResPrintf (UINT resID, ...)
+SHORT GetCursorX(VOID)
 {
-    TCHAR szMsg[RC_STRING_MAX_SIZE];
-    va_list arg_ptr;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
-    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);
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+    return csbi.dwCursorPosition.X;
 }
 
-VOID ConErrPrintf (LPTSTR szFormat, ...)
+SHORT GetCursorY(VOID)
 {
-    va_list arg_ptr;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
-    va_start (arg_ptr, szFormat);
-    ConPrintf(szFormat, arg_ptr, STD_ERROR_HANDLE);
-    va_end (arg_ptr);
+    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+    return csbi.dwCursorPosition.Y;
 }
 
-VOID SetCursorXY (SHORT x, SHORT y)
+VOID SetCursorType(BOOL bInsert, BOOL bVisible)
 {
-    COORD coPos;
+    CONSOLE_CURSOR_INFO cci;
 
-    coPos.X = x;
-    coPos.Y = y;
-    SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coPos);
-}
+    cci.dwSize = bInsert ? 10 : 99;
+    cci.bVisible = bVisible;
 
+    SetConsoleCursorInfo(GetStdHandle (STD_OUTPUT_HANDLE), &cci);
+}
 
-VOID GetCursorXY (PSHORT x, PSHORT y)
+VOID GetScreenSize(PSHORT maxx, PSHORT maxy)
 {
     CONSOLE_SCREEN_BUFFER_INFO csbi;
 
-    GetConsoleScreenBufferInfo (GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+    if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
+    {
+        csbi.dwSize.X = 80;
+        csbi.dwSize.Y = 25;
+    }
 
-    *x = csbi.dwCursorPosition.X;
-    *y = csbi.dwCursorPosition.Y;
+    if (maxx) *maxx = csbi.dwSize.X;
+    if (maxy) *maxy = csbi.dwSize.Y;
 }
 
 
-SHORT GetCursorX (VOID)
-{
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
-    GetConsoleScreenBufferInfo (GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
 
-    return csbi.dwCursorPosition.X;
+BOOL ConSetTitle(IN LPCTSTR lpConsoleTitle)
+{
+    /* Now really set the console title */
+    return SetConsoleTitle(lpConsoleTitle);
 }
 
-
-SHORT GetCursorY (VOID)
+#ifdef INCLUDE_CMD_BEEP
+VOID ConRingBell(HANDLE hOutput)
 {
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-
-    GetConsoleScreenBufferInfo (GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
-
-    return csbi.dwCursorPosition.Y;
+#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
 
-
-VOID GetScreenSize (PSHORT maxx, PSHORT maxy)
+#ifdef INCLUDE_CMD_CLS
+VOID ConClearScreen(HANDLE hOutput)
 {
     CONSOLE_SCREEN_BUFFER_INFO csbi;
+    COORD coPos;
+    DWORD dwWritten;
 
-    if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
+    if (GetConsoleScreenBufferInfo(hOutput, &csbi))
     {
-        csbi.dwSize.X = 80;
-        csbi.dwSize.Y = 25;
+        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'));
     }
-
-    if (maxx)
-        *maxx = csbi.dwSize.X;
-    if (maxy)
-        *maxy = csbi.dwSize.Y;
 }
+#endif
 
-
-VOID SetCursorType (BOOL bInsert, BOOL bVisible)
+#ifdef INCLUDE_CMD_COLOR
+BOOL ConSetScreenColor(HANDLE hOutput, WORD wColor, BOOL bFill)
 {
-    CONSOLE_CURSOR_INFO cci;
+    DWORD dwWritten;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    COORD coPos;
 
-    cci.dwSize = bInsert ? 10 : 99;
-    cci.bVisible = bVisible;
+    /* Foreground and Background colors can't be the same */
+    if ((wColor & 0x0F) == (wColor & 0xF0) >> 4)
+        return FALSE;
 
-    SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE), &cci);
+    /* 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 */