source: trunk/src/kernel32/conbuffervio.cpp @ 22052

Last change on this file since 22052 was 22052, checked in by dmik, 8 years ago

kernel32: Properly handle backspace and tab characters in console input/output mode.

File size: 13.4 KB
Line 
1/* $Id: conbuffervio.cpp,v 1.7 2003-04-11 12:08:35 sandervl Exp $ */
2
3/*
4 * Win32 Console API Translation for OS/2
5 *
6 * 1998/02/10 Patrick Haller (haller@zebra.fh-weingarten.de)
7 *
8 * @(#) console.cpp         1.0.0   1998/02/10 PH Start from scratch
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 */
13
14
15#ifdef DEBUG
16#define DEBUG_LOCAL
17#define DEBUG_LOCAL2
18#endif
19
20//#undef DEBUG_LOCAL
21//#undef DEBUG_LOCAL2
22
23
24/*****************************************************************************
25 * Remark                                                                    *
26 *****************************************************************************
27
28 - DWORD HandlerRoutine (DWORD dwCtrlType)
29   basically an exception handler routine. handles a few signals / excpts.
30   should be somewhere near the exception handling code ... :)
31
32   Hmm, however as PM applications don't really get a ctrl-c signal,
33   I'll have to do this on my own ...
34
35 - supply unicode<->ascii conversions for all the _A and _W function pairs.
36
37 - problem: we can't prevent thread1 from blocking the message queue ?
38            what will happen if a WinTerminate() is issued there ?
39            will the message queue be closed and provide smooth tasking ?
40            how will open32 react on this ?
41
42 - ECHO_LINE_INPUT / ReadFile blocks till CR
43
44 - scrollbars
45 * do some flowchart to exactly determine WHEN to use WHICH setting
46   and perform WHAT action
47
48 - clipboard support
49*/
50
51
52/*****************************************************************************
53 * Includes                                                                  *
54 *****************************************************************************/
55
56// Vio/Kbd/Mou declarations conflict in GCC and in real OS2TK headers;
57// force GCC declarations since we link against GCC libs
58#if defined (__EMX__) && defined (USE_OS2_TOOLKIT_HEADERS)
59#undef USE_OS2_TOOLKIT_HEADERS
60#endif
61
62#define  INCL_WIN
63#define  INCL_DOSMEMMGR
64#define  INCL_DOSSEMAPHORES
65#define  INCL_DOSERRORS
66#define  INCL_DOSPROCESS
67#define  INCL_DOSMODULEMGR
68#define  INCL_VIO
69#define  INCL_AVIO
70#include <os2wrap.h>    //Odin32 OS/2 api wrappers
71
72#include <win32api.h>
73#include <misc.h>
74#include <string.h>
75#include <stdlib.h>
76#include <stdio.h>
77#include <malloc.h>
78
79#include "conwin.h"          // Windows Header for console only
80#include "HandleManager.h"
81#include "HMDevice.h"
82#include "ConBuffervio.H"
83#include "Console2.h"
84#include <heapstring.h>
85
86#define DBG_LOCALLOG    DBG_conbuffer
87#include "dbglocal.h"
88
89/*****************************************************************************
90 * Name      :
91 * Purpose   :
92 * Parameters:
93 * Variables :
94 * Result    :
95 * Remark    :
96 * Status    :
97 *
98 * Author    : Patrick Haller [Wed, 1998/02/11 20:44]
99 *****************************************************************************/
100
101BOOL HMDeviceConsoleVioBufferClass::WriteFile(PHMHANDLEDATA pHMHandleData,
102                                              LPCVOID       lpBuffer,
103                                              DWORD         nNumberOfBytesToWrite,
104                                              LPDWORD       lpNumberOfBytesWritten,
105                                              LPOVERLAPPED lpOverlapped,
106                                              LPOVERLAPPED_COMPLETION_ROUTINE  lpCompletionRoutine)
107{
108  PCONSOLEBUFFER pConsoleBuffer = (PCONSOLEBUFFER)pHMHandleData->lpHandlerData;
109           ULONG ulCounter;                 /* counter for the byte transfer */
110           PSZ   pszBuffer;
111           char  filler[4] = {' ', 0x07, ' ', 0x07};
112  register UCHAR ucChar;
113          APIRET rc;
114          USHORT Row;
115          USHORT Column;
116          int    numchar;
117
118#ifdef DEBUG_LOCAL2
119  WriteLog("KERNEL32/CONSOLE:HMDeviceConsoleVioBufferClass:WriteFile %s(%08x,%08x,%08x,%08x,%08x)\n",
120           lpHMDeviceName,
121           pHMHandleData->hHMHandle,
122           lpBuffer,
123           nNumberOfBytesToWrite,
124           lpNumberOfBytesWritten,
125           lpOverlapped);
126#endif
127
128  if(lpCompletionRoutine) {
129      dprintf(("!WARNING!: lpCompletionRoutine not supported -> fall back to sync IO"));
130  }
131
132  /* check if we're called with non-existing line buffer */
133  if (pConsoleBuffer->ppszLine == NULL) {
134    SetLastError(ERROR_OUTOFMEMORY_W);
135    return FALSE;
136  }
137
138  dprintf(("Current cursor position (%d,%d)", pConsoleBuffer->coordCursorPosition.X, pConsoleBuffer->coordCursorPosition.Y));
139
140  if(nNumberOfBytesToWrite > 1024)
141  {
142    int  tmp = 0;
143    BOOL retcode;
144
145    while(nNumberOfBytesToWrite) {
146        *lpNumberOfBytesWritten = 0;
147        retcode = WriteFile(pHMHandleData, lpBuffer,
148                            min(nNumberOfBytesToWrite, 512), lpNumberOfBytesWritten,
149                            lpOverlapped, lpCompletionRoutine);
150        if(retcode != TRUE)     break;
151
152        tmp                   += *lpNumberOfBytesWritten;
153        nNumberOfBytesToWrite -= *lpNumberOfBytesWritten;
154        lpBuffer               = (LPCVOID)((char *)lpBuffer + *lpNumberOfBytesWritten);
155    }
156    *lpNumberOfBytesWritten = tmp;
157    return retcode;
158  }
159  pszBuffer = (PSZ)alloca(nNumberOfBytesToWrite);
160  if(pszBuffer == NULL) {
161    DebugInt3();
162    return FALSE;
163  }
164  memcpy(pszBuffer, lpBuffer, nNumberOfBytesToWrite);
165
166  ulCounter = 0;
167  while(ulCounter < nNumberOfBytesToWrite)
168  {
169    ucChar = pszBuffer[ulCounter];                        /* map to register */
170
171    if ( (pConsoleBuffer->dwConsoleMode & ENABLE_PROCESSED_OUTPUT) &&
172         (ucChar < 32) )     /* this is faster than a large switch statement */
173    {
174      switch (ucChar)
175      {
176        case 7: /* BEL */
177          if (pConsoleGlobals->Options.fSpeakerEnabled == TRUE)
178            DosBeep(pConsoleGlobals->Options.ulSpeakerFrequency,
179                    pConsoleGlobals->Options.ulSpeakerDuration);
180          break;
181
182        case 8: /* Backspace */
183        {
184          BOOL go = FALSE;
185          if (pConsoleBuffer->coordCursorPosition.X > 0)
186          {
187            pConsoleBuffer->coordCursorPosition.X--;
188            go = TRUE;
189          }
190          else if (pConsoleBuffer->coordCursorPosition.Y > 0)
191          {
192            pConsoleBuffer->coordCursorPosition.Y--;
193            pConsoleBuffer->coordCursorPosition.X = pConsoleBuffer->coordBufferSize.X - 1;
194            go = TRUE;
195          }
196          if (go)
197          {
198            *(pConsoleBuffer->ppszLine[pConsoleBuffer->coordCursorPosition.Y] +
199              pConsoleBuffer->coordCursorPosition.X * 2) = 0x20;
200            VioWrtCharStr((PCH)" ", 1, pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
201            VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
202          }
203          break;
204        }
205
206        case 9: /* Tab */
207          pConsoleBuffer->coordCursorPosition.X =
208            (pConsoleBuffer->coordCursorPosition.X
209             / pConsoleGlobals->Options.ulTabSize
210             + 1)
211            * pConsoleGlobals->Options.ulTabSize;
212
213          if (pConsoleBuffer->coordCursorPosition.X >=
214              pConsoleBuffer->coordBufferSize.X)
215          {
216            pConsoleBuffer->coordCursorPosition.X %= pConsoleBuffer->coordBufferSize.X;
217            pConsoleBuffer->coordCursorPosition.Y++;
218
219            if (pConsoleBuffer->coordCursorPosition.Y >=
220                pConsoleBuffer->coordBufferSize.Y)
221            {
222              if (pConsoleBuffer->dwConsoleMode & ENABLE_WRAP_AT_EOL_OUTPUT)
223              {
224                VioScrollUp(0, 0, pConsoleBuffer->coordWindowSize.Y-1, pConsoleBuffer->coordWindowSize.X-1,
225                            1, &filler[0], 0);
226                pConsoleBuffer->coordCursorPosition.Y = pConsoleBuffer->coordWindowSize.Y-1;
227              }
228            }
229          }
230          VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
231          break;
232
233        case 13: /* CARRIAGE RETURN */
234            dprintf(("CR"));
235            pConsoleBuffer->coordCursorPosition.X = 0;
236            VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
237            break;
238
239        case 10: /* LINEFEED */
240        {
241            dprintf(("LF"));
242            pConsoleBuffer->coordCursorPosition.Y++;
243            pConsoleBuffer->coordCursorPosition.X = 0;
244            if(pConsoleBuffer->coordCursorPosition.Y >= pConsoleBuffer->coordWindowSize.Y) {
245                dprintf(("scrollup"));
246                VioScrollUp(0, 0, pConsoleBuffer->coordWindowSize.Y-1, pConsoleBuffer->coordWindowSize.X-1,
247                            1, &filler[0], 0);
248                pConsoleBuffer->coordCursorPosition.Y = pConsoleBuffer->coordWindowSize.Y-1;
249            }
250            VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
251            break;
252        }
253        default:
254          break;
255      }
256      ulCounter++;
257    }
258    else
259    {
260////        dprintf(("Current cursor position (%d,%d)", pConsoleBuffer->coordCursorPosition.X, pConsoleBuffer->coordCursorPosition.Y));
261        numchar = ulCounter;
262        while(pszBuffer[numchar] >= 32 && numchar < nNumberOfBytesToWrite) {
263            numchar++;
264        }
265        numchar = numchar - ulCounter;
266
267        if(pConsoleBuffer->coordCursorPosition.X + numchar > pConsoleBuffer->coordWindowSize.X)
268        {
269            int tmp = pConsoleBuffer->coordWindowSize.X - pConsoleBuffer->coordCursorPosition.X;
270
271            VioWrtCharStr(&pszBuffer[ulCounter], tmp, pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
272            ulCounter += tmp;
273            numchar   -= tmp;
274
275            pConsoleBuffer->coordCursorPosition.X = 0;
276            pConsoleBuffer->coordCursorPosition.Y++;
277            if(pConsoleBuffer->coordCursorPosition.Y >= pConsoleBuffer->coordWindowSize.Y) {
278                dprintf(("scrollup"));
279                VioScrollUp(0, 0, pConsoleBuffer->coordWindowSize.Y-1, pConsoleBuffer->coordWindowSize.X-1,
280                            1, &filler[0], 0);
281                pConsoleBuffer->coordCursorPosition.Y = pConsoleBuffer->coordWindowSize.Y-1;
282            }
283            VioWrtCharStr(&pszBuffer[ulCounter], numchar, pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
284            pConsoleBuffer->coordCursorPosition.X += numchar;
285            VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
286        }
287        else {
288            VioWrtCharStr(&pszBuffer[ulCounter], numchar, pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
289            pConsoleBuffer->coordCursorPosition.X += numchar;
290            VioSetCurPos(pConsoleBuffer->coordCursorPosition.Y, pConsoleBuffer->coordCursorPosition.X, 0);
291        }
292        ulCounter += numchar;
293    }
294  }
295
296  *lpNumberOfBytesWritten = ulCounter;
297
298  return TRUE;
299}
300
301DWORD HMDeviceConsoleVioBufferClass::FillConsoleOutputAttribute(PHMHANDLEDATA pHMHandleData,
302                                                             WORD    wAttribute,
303                                                             DWORD   nLength,
304                                                             COORD   dwWriteCoord,
305                                                             LPDWORD lpNumberOfAttrsWritten)
306{
307  APIRET  rc;
308
309#ifdef DEBUG_LOCAL2
310  WriteLog("KERNEL32/CONSOLE: HMDeviceConsoleVioBufferClass::FillConsoleOutputAttribute(%08x,attr=%04x,%u,x=%u y=%u,res=%08x).\n",
311           pHMHandleData,
312           wAttribute,
313           nLength,
314           dwWriteCoord.X,
315           dwWriteCoord.Y,
316           lpNumberOfAttrsWritten);
317#endif
318
319  if (HMDeviceConsoleBufferClass::FillConsoleOutputAttribute(pHMHandleData,
320                                                             wAttribute,
321                                                             nLength,
322                                                             dwWriteCoord,
323                                                             lpNumberOfAttrsWritten))
324  {
325    rc = VioWrtNAttr((PBYTE)&wAttribute, *lpNumberOfAttrsWritten, dwWriteCoord.Y, dwWriteCoord.X,
326                     0);
327    if (rc == NO_ERROR)
328    {
329      return TRUE;
330    } else
331    {
332      return FALSE;
333    }
334  } else
335    return FALSE;
336}
337
338DWORD HMDeviceConsoleVioBufferClass::FillConsoleOutputCharacterA(PHMHANDLEDATA pHMHandleData,
339                                                              UCHAR   ucCharacter,
340                                                              DWORD   nLength,
341                                                              COORD   dwWriteCoord,
342                                                              LPDWORD lpNumberOfCharsWritten)
343{
344  APIRET  rc;
345
346#ifdef DEBUG_LOCAL2
347  WriteLog("KERNEL32/CONSOLE: HMDeviceConsoleVioBufferClass::FillConsoleOutputCharacterA(%08x,char=%02x,%u,x=%u y=%u,res=%08x).\n",
348           pHMHandleData,
349           ucCharacter,
350           nLength,
351           dwWriteCoord.X,
352           dwWriteCoord.Y,
353           lpNumberOfCharsWritten);
354#endif
355  if (HMDeviceConsoleBufferClass::FillConsoleOutputCharacterA(pHMHandleData,
356                                                                 ucCharacter,
357                                                                 nLength,
358                                                                 dwWriteCoord,
359                                                                 lpNumberOfCharsWritten))
360  {
361    rc = VioWrtNChar((PCH)&ucCharacter, *lpNumberOfCharsWritten, dwWriteCoord.Y, dwWriteCoord.X,
362         0);
363    if (rc == NO_ERROR)
364    {
365      return TRUE;
366    } else
367    {
368      return FALSE;
369    }
370  } else
371    return FALSE;
372}
373
Note: See TracBrowser for help on using the repository browser.