Eric Pouech : kernel32: In readline, now print control characters with ^ escape.

Alexandre Julliard julliard at winehq.org
Mon Dec 13 10:43:20 CST 2010


Module: wine
Branch: master
Commit: 8aa3ec414d8ff4a5ebd7ca32fa171c267af2640e
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=8aa3ec414d8ff4a5ebd7ca32fa171c267af2640e

Author: Eric Pouech <eric.pouech at orange.fr>
Date:   Sun Dec 12 22:31:49 2010 +0100

kernel32: In readline, now print control characters with ^ escape.

---

 dlls/kernel32/editline.c |  136 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 101 insertions(+), 35 deletions(-)

diff --git a/dlls/kernel32/editline.c b/dlls/kernel32/editline.c
index 4dff110..b33798b 100644
--- a/dlls/kernel32/editline.c
+++ b/dlls/kernel32/editline.c
@@ -57,7 +57,7 @@ typedef struct WCEL_Context {
                                                    (for consoles that can't change cursor pos) */
     unsigned                    last_max;       /* max number of chars written
                                                    (for consoles that can't change cursor pos) */
-    unsigned			ofs;		/* offset for cursor in current line */
+    unsigned			ofs;    	/* offset for cursor in current line */
     WCHAR*			yanked;		/* yanked line */
     unsigned			mark;		/* marked point (emacs mode only) */
     CONSOLE_SCREEN_BUFFER_INFO	csbi;		/* current state (initial cursor, window size, attribute) */
@@ -111,10 +111,27 @@ static inline BOOL WCEL_IsSingleLine(WCEL_Context* ctx, size_t len)
     return ctx->csbi.dwCursorPosition.X + ctx->len + len <= ctx->csbi.dwSize.X;
 }
 
-static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int ofs)
+static inline int WCEL_CharWidth(WCHAR wch)
+{
+    return wch < ' ' ? 2 : 1;
+}
+
+static inline int WCEL_StringWidth(const WCHAR* str, int beg, int len)
+{
+    int         i, ofs;
+
+    for (i = 0, ofs = 0; i < len; i++)
+        ofs += WCEL_CharWidth(str[beg + i]);
+    return ofs;
+}
+
+static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int strofs)
 {
     COORD       c;
     int         len = ctx->csbi.dwSize.X - ctx->csbi.dwCursorPosition.X;
+    int         ofs;
+
+    ofs = WCEL_StringWidth(ctx->line, 0, strofs);
 
     c.Y = ctx->csbi.dwCursorPosition.Y;
     if (ofs >= len)
@@ -127,35 +144,79 @@ static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int ofs)
     return c;
 }
 
+static DWORD WCEL_WriteConsole(WCEL_Context* ctx, DWORD beg, DWORD len)
+{
+    DWORD i, last, dw, ret = 0;
+    WCHAR tmp[2];
+
+    for (i = last = 0; i < len; i++)
+    {
+        if (ctx->line[beg + i] < ' ')
+        {
+            if (last != i)
+            {
+                WriteConsoleW(ctx->hConOut, &ctx->line[beg + last], i - last, &dw, NULL);
+                ret += dw;
+            }
+            tmp[0] = '^';
+            tmp[1] = '@' + ctx->line[beg + i];
+            WriteConsoleW(ctx->hConOut, tmp, 2, &dw, NULL);
+            last = i + 1;
+            ret += dw;
+        }
+    }
+    if (last != len)
+    {
+        WriteConsoleW(ctx->hConOut, &ctx->line[beg + last], len - last, &dw, NULL);
+        ret += dw;
+    }
+    return ret;
+}
+
+static inline void WCEL_WriteNChars(WCEL_Context* ctx, char ch, int count)
+{
+    DWORD       dw;
+
+    if (count > 0)
+    {
+        while (count--) WriteFile(ctx->hConOut, &ch, 1, &dw, NULL);
+    }
+}
+
 static inline void WCEL_Update(WCEL_Context* ctx, int beg, int len)
 {
-    if (!ctx->shall_echo) return;
-    if (ctx->can_pos_cursor)
+    int         i, last;
+    WCHAR       tmp[2];
+
+    /* bare console case is handled in CONSOLE_ReadLine (we always reprint the whole string) */
+    if (!ctx->shall_echo || !ctx->can_pos_cursor) return;
+
+    for (i = last = beg; i < beg + len; i++)
     {
-        WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[beg], len,
-                                     WCEL_GetCoord(ctx, beg), NULL);
-        FillConsoleOutputAttribute(ctx->hConOut, ctx->csbi.wAttributes, len,
-                                   WCEL_GetCoord(ctx, beg), NULL);
+        if (ctx->line[i] < ' ')
+        {
+            if (last != i)
+            {
+                WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[last], i - last,
+                                             WCEL_GetCoord(ctx, last), NULL);
+                FillConsoleOutputAttribute(ctx->hConOut, ctx->csbi.wAttributes, i - last,
+                                           WCEL_GetCoord(ctx, last), NULL);
+            }
+            tmp[0] = '^';
+            tmp[1] = '@' + ctx->line[i];
+            WriteConsoleOutputCharacterW(ctx->hConOut, tmp, 2,
+                                         WCEL_GetCoord(ctx, i), NULL);
+            FillConsoleOutputAttribute(ctx->hConOut, ctx->csbi.wAttributes, 2,
+                                       WCEL_GetCoord(ctx, i), NULL);
+            last = i + 1;
+        }
     }
-    else
+    if (last != beg + len)
     {
-        char ch;
-        unsigned i;
-        DWORD dw;
-
-        /* erase previous chars */
-        ch = '\b';
-        for (i = beg; i < ctx->last_rub; i++)
-            WriteFile(ctx->hConOut, &ch, 1, &dw, NULL);
-        beg = min(beg, ctx->last_rub);
-
-        /* write new chars */
-        WriteConsoleW(ctx->hConOut, &ctx->line[beg], ctx->len - beg, &dw, NULL);
-        /* clean rest of line (if any) */
-        ch = ' ';
-        for (i = ctx->len; i < ctx->last_max; i++)
-            WriteFile(ctx->hConOut, &ch, 1, &dw, NULL);
-        ctx->last_rub = max(ctx->last_max, ctx->len);
+        WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[last], i - last,
+                                     WCEL_GetCoord(ctx, last), NULL);
+        FillConsoleOutputAttribute(ctx->hConOut, ctx->csbi.wAttributes, i - last,
+                                   WCEL_GetCoord(ctx, last), NULL);
     }
 }
 
@@ -887,18 +948,23 @@ WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, BOOL can_pos_cursor)
         }
         else if (!ctx.done && !ctx.error)
         {
-            char        ch;
-            unsigned    i;
-            DWORD       dw;
-
+            DWORD last;
             /* erase previous chars */
-            ch = '\b';
-            for (i = 0; i < ctx.last_rub; i++)
-                WriteFile(ctx.hConOut, &ch, 1, &dw, NULL);
+            WCEL_WriteNChars(&ctx, '\b', ctx.last_rub);
 
             /* write chars up to cursor */
-            WriteConsoleW(ctx.hConOut, ctx.line, ctx.ofs, &dw, NULL);
-            if ((ctx.last_rub = ctx.ofs) > ctx.last_max) ctx.last_max = ctx.ofs;
+            ctx.last_rub = WCEL_WriteConsole(&ctx, 0, ctx.ofs);
+            /* write chars past cursor */
+            last = ctx.last_rub + WCEL_WriteConsole(&ctx, ctx.ofs, ctx.len - ctx.ofs);
+            if (last < ctx.last_max) /* ctx.line has been shortened, erase */
+            {
+                WCEL_WriteNChars(&ctx, ' ', ctx.last_max - last);
+                WCEL_WriteNChars(&ctx, '\b', ctx.last_max - last);
+                ctx.last_max = last;
+            }
+            else ctx.last_max = last;
+            /* reposition at cursor */
+            WCEL_WriteNChars(&ctx, '\b', last - ctx.last_rub);
         }
     }
     if (ctx.error)




More information about the wine-cvs mailing list