Implemented the GetBinaryType API function.
[wine] / win32 / console.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis and Cameron Heide
5  * Copyright 1997 Karl Garrison
6  * Copyright 1998 John Richardson
7  * Copyright 1998 Marcus Meissner
8  */
9
10 /* FIXME:
11  * - Completely lacks SCREENBUFFER interface.
12  * - No abstraction for something other than xterm.
13  * - Key input translation shouldn't use VkKeyScan and MapVirtualKey, since
14  *   they are window (USER) driver dependend.
15  * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
16  */
17 /* Reference applications:
18  * -  IDA (interactive disassembler) full version 3.75. Works.
19  * -  LYNX/W32. Works mostly, some keys crash it.
20  */
21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <termios.h>
25 #include <strings.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/errno.h>
33 #include <signal.h>
34 #include <assert.h>
35
36 #include "windows.h"
37 #include "k32obj.h"
38 #include "thread.h"
39 #include "async.h"
40 #include "file.h"
41 #include "process.h"
42 #include "winerror.h"
43 #include "wincon.h"
44 #include "heap.h"
45 #include "debug.h"
46
47 /* The CONSOLE kernel32 Object */
48 typedef struct _CONSOLE {
49         K32OBJ                  header;
50         DWORD                   mode;
51         CONSOLE_CURSOR_INFO     cinfo;
52
53         int                     master; /* xterm side of pty */
54         int                     infd,outfd;
55         int                     pid;    /* xterm's pid, -1 if no xterm */
56         LPSTR                   title;  /* title of console */
57         INPUT_RECORD            *irs;   /* buffered input records */
58         int                     nrofirs;/* nr of buffered input records */
59         THREAD_QUEUE            wait_queue;
60 } CONSOLE;
61
62 static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id);
63 static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id);
64 static BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id);
65 static BOOL32 CONSOLE_Signaled(K32OBJ *ptr, DWORD thread_id);
66 static void CONSOLE_Destroy( K32OBJ *obj );
67 static BOOL32 CONSOLE_Write(K32OBJ *ptr, LPCVOID lpBuffer, 
68                             DWORD nNumberOfChars,  LPDWORD lpNumberOfChars, 
69                             LPOVERLAPPED lpOverlapped);
70 static BOOL32 CONSOLE_Read(K32OBJ *ptr, LPVOID lpBuffer, 
71                            DWORD nNumberOfChars, LPDWORD lpNumberOfChars, 
72                            LPOVERLAPPED lpOverlapped);
73
74 const K32OBJ_OPS CONSOLE_Ops =
75 {
76         CONSOLE_Signaled,       /* signaled */
77         CONSOLE_Satisfied,      /* satisfied */
78         CONSOLE_AddWait,        /* add_wait */
79         CONSOLE_RemoveWait,     /* remove_wait */
80         CONSOLE_Read,           /* read */
81         CONSOLE_Write,          /* write */
82         CONSOLE_Destroy         /* destroy */
83 };
84
85 /***********************************************************************
86  * CONSOLE_Destroy
87  */
88 static void CONSOLE_Destroy(K32OBJ *obj)
89 {
90         CONSOLE *console = (CONSOLE *)obj;
91         assert(obj->type == K32OBJ_CONSOLE);
92
93         obj->type = K32OBJ_UNKNOWN;
94
95         if (console->title)
96                   HeapFree( SystemHeap, 0, console->title );
97         console->title = NULL;
98         /* if there is a xterm, kill it. */
99         if (console->pid != -1)
100                 kill(console->pid, SIGTERM);
101         HeapFree(SystemHeap, 0, console);
102 }
103
104
105 /***********************************************************************
106  * CONSOLE_Read
107  *
108  * NOTES
109  *    lpOverlapped is ignored
110  */
111 static BOOL32 CONSOLE_Read(K32OBJ *ptr, LPVOID lpBuffer, DWORD nNumberOfChars,
112                         LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped)
113 {
114         CONSOLE *console = (CONSOLE *)ptr;
115         int result;
116
117         TRACE(console, "%p %p %ld\n", ptr, lpBuffer, nNumberOfChars);
118         *lpNumberOfChars = 0; 
119         if ((result = read(console->infd, lpBuffer, nNumberOfChars)) == -1) {
120                 FILE_SetDosError();
121                 return FALSE;
122         }
123         *lpNumberOfChars = result;
124         return TRUE;
125 }
126
127
128 /***********************************************************************
129  * CONSOLE_Write
130  *
131  * NOTES
132  *    lpOverlapped is ignored
133  */
134 static BOOL32 CONSOLE_Write(K32OBJ *ptr, LPCVOID lpBuffer, 
135                             DWORD nNumberOfChars,
136                             LPDWORD lpNumberOfChars, LPOVERLAPPED lpOverlapped)
137 {
138         CONSOLE *console = (CONSOLE *)ptr;
139         int result;
140
141         TRACE(console, "%p %p %ld\n", ptr, lpBuffer, nNumberOfChars);
142         *lpNumberOfChars = 0; 
143         /* 
144          * I assume this loop around EAGAIN is here because
145          * win32 doesn't have interrupted system calls 
146          */
147
148         for (;;)
149         {
150                 result = write(console->outfd, lpBuffer, nNumberOfChars);
151                 if (result != -1) {
152                         *lpNumberOfChars = result;
153                         return TRUE;
154                 }
155                 if (errno != EINTR) {
156                         FILE_SetDosError();
157                         return FALSE;
158                 }
159         }
160 }
161
162 /****************************************************************************
163  *              CONSOLE_add_input_record                        [internal]
164  *
165  * Adds an INPUT_RECORD to the CONSOLEs input queue.
166  */
167 static void
168 CONSOLE_add_input_record(CONSOLE *console,INPUT_RECORD *inp) {
169         console->irs = HeapReAlloc(GetProcessHeap(),0,console->irs,sizeof(INPUT_RECORD)*(console->nrofirs+1));
170         console->irs[console->nrofirs++]=*inp;
171 }
172
173 /****************************************************************************
174  *              XTERM_string_to_IR                      [internal]
175  *
176  * Transfers a string read from XTERM to INPUT_RECORDs and adds them to the
177  * queue. Does translation of vt100 style function keys and xterm-mouse clicks.
178  */
179 static void
180 CONSOLE_string_to_IR(CONSOLE *console,unsigned char *buf,int len) {
181     int                 j,k;
182     INPUT_RECORD        ir;
183
184     for (j=0;j<len;j++) {
185         unsigned char inchar = buf[j];
186
187         if (inchar!=27) { /* no escape -> 'normal' keyboard event */
188             ir.EventType = 1; /* Key_event */
189
190             ir.Event.KeyEvent.bKeyDown          = 1;
191             ir.Event.KeyEvent.wRepeatCount      = 0;
192
193             ir.Event.KeyEvent.dwControlKeyState = 0;
194             if (inchar & 0x80) {
195                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
196                 inchar &= ~0x80;
197             }
198             ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan16(inchar);
199             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0100)
200                 ir.Event.KeyEvent.dwControlKeyState|=SHIFT_PRESSED;
201             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0200)
202                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_CTRL_PRESSED;
203             if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0400)
204                 ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
205             ir.Event.KeyEvent.wVirtualScanCode = MapVirtualKey16(
206                 ir.Event.KeyEvent.wVirtualKeyCode & 0x00ff,
207                 0 /* VirtualKeyCodes to ScanCode */
208             );
209             if (inchar=='\n') {
210                 ir.Event.KeyEvent.uChar.AsciiChar       = '\r';
211                 ir.Event.KeyEvent.wVirtualKeyCode       = 0x0d;
212                 ir.Event.KeyEvent.wVirtualScanCode      = 0x1c;
213             } else {
214                 ir.Event.KeyEvent.uChar.AsciiChar = inchar;
215                 if (inchar<' ') {
216                     /* FIXME: find good values for ^X */
217                     ir.Event.KeyEvent.wVirtualKeyCode = 0xdead;
218                     ir.Event.KeyEvent.wVirtualScanCode = 0xbeef;
219                 } 
220             }
221
222             CONSOLE_add_input_record(console,&ir);
223             ir.Event.KeyEvent.bKeyDown = 0;
224             CONSOLE_add_input_record(console,&ir);
225             continue;
226         }
227         /* inchar is ESC */
228         if ((j==len-1) || (buf[j+1]!='[')) {/* add ESCape on its own */
229             ir.EventType = 1; /* Key_event */
230             ir.Event.KeyEvent.bKeyDown          = 1;
231             ir.Event.KeyEvent.wRepeatCount      = 0;
232
233             ir.Event.KeyEvent.wVirtualKeyCode   = VkKeyScan16(27);
234             ir.Event.KeyEvent.wVirtualScanCode  = MapVirtualKey16(
235                 ir.Event.KeyEvent.wVirtualKeyCode,0
236             );
237             ir.Event.KeyEvent.dwControlKeyState = 0;
238             ir.Event.KeyEvent.uChar.AsciiChar   = 27;
239             CONSOLE_add_input_record(console,&ir);
240             ir.Event.KeyEvent.bKeyDown = 0;
241             CONSOLE_add_input_record(console,&ir);
242             continue;
243         }
244         for (k=j;k<len;k++) {
245             if (((buf[k]>='A') && (buf[k]<='Z')) ||
246                 ((buf[k]>='a') && (buf[k]<='z')) ||
247                  (buf[k]=='~')
248             )
249                 break;
250         }
251         if (k<len) {
252             int subid,scancode=0;
253
254             ir.EventType                        = 1; /* Key_event */
255             ir.Event.KeyEvent.bKeyDown          = 1;
256             ir.Event.KeyEvent.wRepeatCount      = 0;
257             ir.Event.KeyEvent.dwControlKeyState = 0;
258
259             ir.Event.KeyEvent.wVirtualKeyCode   = 0xad; /* FIXME */
260             ir.Event.KeyEvent.wVirtualScanCode  = 0xad; /* FIXME */
261             ir.Event.KeyEvent.uChar.AsciiChar   = 0;
262
263             switch (buf[k]) {
264             case '~':
265                 sscanf(&buf[j+2],"%d",&subid);
266                 switch (subid) {
267                 case  2:/*INS */scancode = 0xe052;break;
268                 case  3:/*DEL */scancode = 0xe053;break;
269                 case  6:/*PGDW*/scancode = 0xe051;break;
270                 case  5:/*PGUP*/scancode = 0xe049;break;
271                 case 11:/*F1  */scancode = 0x003b;break;
272                 case 12:/*F2  */scancode = 0x003c;break;
273                 case 13:/*F3  */scancode = 0x003d;break;
274                 case 14:/*F4  */scancode = 0x003e;break;
275                 case 15:/*F5  */scancode = 0x003f;break;
276                 case 17:/*F6  */scancode = 0x0040;break;
277                 case 18:/*F7  */scancode = 0x0041;break;
278                 case 19:/*F8  */scancode = 0x0042;break;
279                 case 20:/*F9  */scancode = 0x0043;break;
280                 case 21:/*F10 */scancode = 0x0044;break;
281                 case 23:/*F11 */scancode = 0x00d9;break;
282                 case 24:/*F12 */scancode = 0x00da;break;
283                 /* FIXME: Shift-Fx */
284                 default:
285                         FIXME(console,"parse ESC[%d~\n",subid);
286                         break;
287                 }
288                 break;
289             case 'A': /* Cursor Up    */scancode = 0xe048;break;
290             case 'B': /* Cursor Down  */scancode = 0xe050;break;
291             case 'D': /* Cursor Left  */scancode = 0xe04b;break;
292             case 'C': /* Cursor Right */scancode = 0xe04d;break;
293             case 'F': /* End          */scancode = 0xe04f;break;
294             case 'H': /* Home         */scancode = 0xe047;break;
295             case 'M':
296                 /* Mouse Button Press  (ESCM<button+'!'><x+'!'><y+'!'>) or
297                  *              Release (ESCM#<x+'!'><y+'!'>
298                  */
299                 if (k<len-3) {
300                     ir.EventType                        = MOUSE_EVENT;
301                     ir.Event.MouseEvent.dwMousePosition.x = buf[k+2]-'!';
302                     ir.Event.MouseEvent.dwMousePosition.y = buf[k+3]-'!';
303                     if (buf[k+1]=='#')
304                         ir.Event.MouseEvent.dwButtonState = 0;
305                     else
306                         ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
307                     ir.Event.MouseEvent.dwEventFlags      = 0; /* FIXME */
308                     CONSOLE_add_input_record(console,&ir);
309                     j=k+3;
310                 }
311                 break;
312                 
313             }
314             if (scancode) {
315                 ir.Event.KeyEvent.wVirtualScanCode = scancode;
316                 ir.Event.KeyEvent.wVirtualKeyCode = MapVirtualKey16(scancode,1);
317                 CONSOLE_add_input_record(console,&ir);
318                 ir.Event.KeyEvent.bKeyDown              = 0;
319                 CONSOLE_add_input_record(console,&ir);
320                 j=k;
321                 continue;
322             }
323         }
324     }
325 }
326 /****************************************************************************
327  *              CONSOLE_get_input               (internal)
328  *
329  * Reads (nonblocking) as much input events as possible and stores them
330  * in an internal queue.
331  * (not necessarily XTERM dependend, but UNIX filedescriptor...)
332  */
333 static void
334 CONSOLE_get_input(CONSOLE *console) {
335     char        *buf = HeapAlloc(GetProcessHeap(),0,1);
336     int         len = 0;
337
338     while (1) {
339         fd_set  infds;
340         DWORD   res;
341         struct timeval tv;
342         char            inchar;
343
344         FD_ZERO(&infds);
345         FD_SET(console->infd,&infds);
346         memset(&tv,0,sizeof(tv));
347         if (select(console->infd+1,&infds,NULL,NULL,&tv)<1)
348             break; /* no input there */
349
350         if (!FD_ISSET(console->infd,&infds))
351             break;
352         if (!CONSOLE_Read((K32OBJ*)console,&inchar,1,&res,NULL))
353             break;
354         buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
355         buf[len++]=inchar;
356     }
357     CONSOLE_string_to_IR(console,buf,len);
358     HeapFree(GetProcessHeap(),0,buf);
359 }
360
361 /****************************************************************************
362  *              CONSOLE_drain_input             (internal)
363  *
364  * Drains 'n' console input events from the queue.
365  */
366 static void
367 CONSOLE_drain_input(CONSOLE *console,int n) {
368     assert(n<=console->nrofirs);
369     if (n) {
370         console->nrofirs-=n;
371         memcpy( &console->irs[0],
372                 &console->irs[n],
373                 console->nrofirs*sizeof(INPUT_RECORD)
374         );
375         console->irs = HeapReAlloc(
376                 GetProcessHeap(),
377                 0,
378                 console->irs,
379                 console->nrofirs*sizeof(INPUT_RECORD)
380         );
381     }
382 }
383
384 /***********************************************************************
385  *              CONSOLE_async_handler                   [internal]
386  */
387 static void
388 CONSOLE_async_handler(int unixfd,void *private) {
389         CONSOLE *console = (CONSOLE*)private;
390
391         SYNC_WakeUp(&console->wait_queue,INFINITE32);
392 }
393
394 /***********************************************************************
395  *              CONSOLE_Signaled                        [internal]
396  *
397  * Checks if we can read something. (Hmm, what about writing ?)
398  */
399 static BOOL32
400 CONSOLE_Signaled(K32OBJ *ptr,DWORD tid) {
401         CONSOLE *console =(CONSOLE*)ptr;
402
403         if (ptr->type!= K32OBJ_CONSOLE)
404                 return FALSE;
405         CONSOLE_get_input(console);
406         if (console->nrofirs!=0)
407                 return TRUE;
408         /* addref console */
409         return FALSE;
410 }
411
412 /***********************************************************************
413  *              CONSOLE_AddWait                 [internal]
414  *
415  * Add thread to our waitqueue (so we can signal it if we have input).
416  */
417 static void CONSOLE_AddWait(K32OBJ *ptr, DWORD thread_id)
418 {
419     CONSOLE *console = (CONSOLE *)ptr;
420
421     /* register our unix filedescriptors for async IO */
422     if (!console->wait_queue)
423         ASYNC_RegisterFD(console->infd,CONSOLE_async_handler,console);
424     THREAD_AddQueue( &console->wait_queue, THREAD_ID_TO_THDB(thread_id) );
425 }
426
427 /***********************************************************************
428  *              CONSOLE_RemoveWait                      [internal]
429  *
430  * Remove thread from our waitqueue.
431  */
432 static void CONSOLE_RemoveWait(K32OBJ *ptr, DWORD thread_id)
433 {
434     CONSOLE *console = (CONSOLE *)ptr;
435
436     THREAD_RemoveQueue( &console->wait_queue, THREAD_ID_TO_THDB(thread_id) );
437     if (!console->wait_queue)
438         ASYNC_UnregisterFD(console->infd,CONSOLE_async_handler);
439 }
440
441 /***********************************************************************
442  *              CONSOLE_Satisfied                       [internal]
443  *
444  * Condition from last Signaled is satisfied and will be used now.
445  */
446 static BOOL32 CONSOLE_Satisfied(K32OBJ *ptr, DWORD thread_id)
447 {
448     return FALSE;
449 }
450
451
452 /******************************************************************************
453  * SetConsoleCtrlHandler [KERNEL32.459]  Adds function to calling process list
454  *
455  * PARAMS
456  *    func [I] Address of handler function
457  *    add  [I] Handler to add or remove
458  *
459  * RETURNS
460  *    Success: TRUE
461  *    Failure: FALSE
462  *
463  * CHANGED
464  * James Sutherland (JamesSutherland@gmx.de)
465  * Added global variables console_ignore_ctrl_c and handlers[]
466  * Does not yet do any error checking, or set LastError if failed.
467  * This doesn't yet matter, since these handlers are not yet called...!
468  */
469 static unsigned int console_ignore_ctrl_c = 0;
470 static HANDLER_ROUTINE *handlers[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
471 BOOL32 WINAPI SetConsoleCtrlHandler( HANDLER_ROUTINE *func, BOOL32 add )
472 {
473   unsigned int alloc_loop = sizeof(handlers)/sizeof(HANDLER_ROUTINE *);
474   unsigned int done = 0;
475   FIXME(console, "(%p,%i) - no error checking or testing yet\n", func, add);
476   if (!func)
477     {
478       console_ignore_ctrl_c = add;
479       return TRUE;
480     }
481   if (add)
482       {
483         for (;alloc_loop--;)
484           if (!handlers[alloc_loop] && !done)
485             {
486               handlers[alloc_loop] = func;
487               done++;
488             }
489         if (!done)
490            FIXME(console, "Out of space on CtrlHandler table\n");
491         return(done);
492       }
493     else
494       {
495         for (;alloc_loop--;)
496           if (handlers[alloc_loop] == func && !done)
497             {
498               handlers[alloc_loop] = 0;
499               done++;
500             }
501         if (!done)
502            WARN(console, "Attempt to remove non-installed CtrlHandler %p\n",
503                 func);
504         return (done);
505       }
506     return (done);
507 }
508
509
510 /******************************************************************************
511  * GenerateConsoleCtrlEvent [KERNEL32.275] Simulate a CTRL-C or CTRL-BREAK
512  *
513  * PARAMS
514  *    dwCtrlEvent        [I] Type of event
515  *    dwProcessGroupID   [I] Process group ID to send event to
516  *
517  * NOTES
518  *    Doesn't yet work...!
519  *
520  * RETURNS
521  *    Success: True
522  *    Failure: False (and *should* [but doesn't] set LastError)
523  */
524 BOOL32 WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
525                                         DWORD dwProcessGroupID )
526 {
527   if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
528     {
529       ERR( console, "invalid event %d for PGID %ld\n", 
530            (unsigned short)dwCtrlEvent, dwProcessGroupID );
531       return FALSE;
532     }
533   if (dwProcessGroupID == GetCurrentProcessId() )
534     {
535       FIXME( console, "Attempt to send event %d to self - stub\n",
536              (unsigned short)dwCtrlEvent );
537       return FALSE;
538     }
539   FIXME( console,"event %d to external PGID %ld - not implemented yet\n",
540          (unsigned short)dwCtrlEvent, dwProcessGroupID );
541   return FALSE;
542 }
543
544
545 /******************************************************************************
546  * CreateConsoleScreenBuffer [KERNEL32.151]  Creates a console screen buffer
547  *
548  * PARAMS
549  *    dwDesiredAccess    [I] Access flag
550  *    dwShareMode        [I] Buffer share mode
551  *    sa                 [I] Security attributes
552  *    dwFlags            [I] Type of buffer to create
553  *    lpScreenBufferData [I] Reserved
554  *
555  * NOTES
556  *    Should call SetLastError
557  *
558  * RETURNS
559  *    Success: Handle to new console screen buffer
560  *    Failure: INVALID_HANDLE_VALUE
561  */
562 HANDLE32 WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess,
563                 DWORD dwShareMode, LPSECURITY_ATTRIBUTES sa,
564                 DWORD dwFlags, LPVOID lpScreenBufferData )
565 {
566     FIXME(console, "(%ld,%ld,%p,%ld,%p): stub\n",dwDesiredAccess,
567           dwShareMode, sa, dwFlags, lpScreenBufferData);
568     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
569     return INVALID_HANDLE_VALUE32;
570 }
571
572
573 /***********************************************************************
574  *           GetConsoleScreenBufferInfo   (KERNEL32.190)
575  */
576 BOOL32 WINAPI GetConsoleScreenBufferInfo( HANDLE32 hConsoleOutput,
577                                           LPCONSOLE_SCREEN_BUFFER_INFO csbi )
578 {
579     csbi->dwSize.x = 80;
580     csbi->dwSize.y = 24;
581     csbi->dwCursorPosition.x = 0;
582     csbi->dwCursorPosition.y = 0;
583     csbi->wAttributes = 0;
584     csbi->srWindow.Left = 0;
585     csbi->srWindow.Right        = 79;
586     csbi->srWindow.Top  = 0;
587     csbi->srWindow.Bottom       = 23;
588     csbi->dwMaximumWindowSize.x = 80;
589     csbi->dwMaximumWindowSize.y = 24;
590     return TRUE;
591 }
592
593
594 /******************************************************************************
595  * SetConsoleActiveScreenBuffer [KERNEL32.623]  Sets buffer to current console
596  *
597  * RETURNS
598  *    Success: TRUE
599  *    Failure: FALSE
600  */
601 BOOL32 WINAPI SetConsoleActiveScreenBuffer(
602     HANDLE32 hConsoleOutput) /* [in] Handle to console screen buffer */
603 {
604     FIXME(console, "(%x): stub\n", hConsoleOutput);
605     return FALSE;
606 }
607
608
609 /***********************************************************************
610  *            GetLargestConsoleWindowSize   (KERNEL32.226)
611  */
612 DWORD WINAPI GetLargestConsoleWindowSize( HANDLE32 hConsoleOutput )
613 {
614     return (DWORD)MAKELONG(80,24);
615 }
616
617 /***********************************************************************
618  *            FreeConsole (KERNEL32.267)
619  */
620 BOOL32 WINAPI FreeConsole(VOID)
621 {
622
623         PDB32 *pdb = PROCESS_Current();
624         CONSOLE *console;
625
626         SYSTEM_LOCK();
627
628         console = (CONSOLE *)pdb->console;
629
630         if (console == NULL) {
631                 SetLastError(ERROR_INVALID_PARAMETER);
632                 return FALSE;
633         }
634
635         HANDLE_CloseAll( pdb, &console->header );
636
637         K32OBJ_DecCount( &console->header );
638         pdb->console = NULL;
639         SYSTEM_UNLOCK();
640         return TRUE;
641 }
642
643
644 /** 
645  *  It looks like the openpty that comes with glibc in RedHat 5.0
646  *  is buggy (second call returns what looks like a dup of 0 and 1
647  *  instead of a new pty), this is a generic replacement.
648  */
649 static int CONSOLE_openpty(CONSOLE *console, char *name, 
650                         struct termios *term, struct winsize *winsize)
651 {
652         int fdm, fds;
653         char *ptr1, *ptr2;
654         char pts_name[512];
655
656         strcpy (pts_name, "/dev/ptyXY");
657
658         for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
659                 pts_name[8] = *ptr1;
660                 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
661                         pts_name[9] = *ptr2;
662
663                         if ((fdm = open(pts_name, O_RDWR)) < 0) {
664                                 if (errno == ENOENT)
665                                         return -1;
666                                 else
667                                         continue;
668                         }
669                         pts_name[5] = 't';
670                         if ((fds = open(pts_name, O_RDWR)) < 0) {
671                                 pts_name[5] = 'p';
672                                 continue;
673                         }
674                         console->master = fdm;
675                         console->infd = console->outfd = fds;
676                         
677                         if (term != NULL)
678                                 tcsetattr(console->infd, TCSANOW, term);
679                         if (winsize != NULL)
680                                 ioctl(console->outfd, TIOCSWINSZ, winsize);
681                         if (name != NULL)
682                                 strcpy(name, pts_name);
683                         return fds;
684                 }
685         }
686         return -1;
687 }
688
689 /*************************************************************************
690  *              CONSOLE_make_complex                    [internal]
691  *
692  * Turns a CONSOLE kernel object into a complex one.
693  * (switches from output/input using the terminal where WINE was started to 
694  * its own xterm).
695  * 
696  * This makes simple commandline tools pipeable, while complex commandline 
697  * tools work without getting messed up by debugoutput.
698  * 
699  * All other functions should work indedependend from this call.
700  *
701  * To test for complex console: pid == -1 -> simple, otherwise complex.
702  */
703 static BOOL32 CONSOLE_make_complex(CONSOLE *console)
704 {
705         struct termios term;
706         char buf[30];
707         char c = '\0';
708         int status = 0;
709         int i,xpid;
710         DWORD   xlen;
711
712         if (console->pid != -1)
713                 return TRUE; /* already complex */
714
715         MSG("Console: Making console complex (creating an xterm)...\n");
716
717         if (tcgetattr(0, &term) < 0) return FALSE;
718         term.c_lflag = ~(ECHO|ICANON);
719         if (CONSOLE_openpty(console, NULL, &term, NULL) < 0) return FALSE;
720
721         if ((xpid=fork()) == 0) {
722                 tcsetattr(console->infd, TCSADRAIN, &term);
723                 sprintf(buf, "-Sxx%d", console->master);
724                 /* "-fn vga" for VGA font. Harmless if vga is not present:
725                  *  xterm: unable to open font "vga", trying "fixed".... 
726                  */
727                 execlp("xterm", "xterm", buf, "-fn","vga",NULL);
728                 ERR(console, "error creating AllocConsole xterm\n");
729                 exit(1);
730         }
731         console->pid = xpid;
732
733         /* most xterms like to print their window ID when used with -S;
734          * read it and continue before the user has a chance...
735          */
736         for (i=0; c!='\n'; (status=read(console->infd, &c, 1)), i++) {
737                 if (status == -1 && c == '\0') {
738                                 /* wait for xterm to be created */
739                         usleep(100);
740                 }
741                 if (i > 10000) {
742                         ERR(console, "can't read xterm WID\n");
743                         kill(console->pid, SIGKILL);
744                         return FALSE;
745                 }
746         }
747         /* enable mouseclicks */
748         sprintf(buf,"%c[?1001s%c[?1000h",27,27);
749         CONSOLE_Write(&console->header,buf,strlen(buf),&xlen,NULL);
750         return TRUE;
751
752 }
753
754 /***********************************************************************
755  *              CONSOLE_GetConsoleHandle
756  *       returns a 16-bit style console handle
757  * note: only called from _lopen
758  */
759 HFILE32 CONSOLE_GetConsoleHandle(VOID)
760 {
761         PDB32 *pdb = PROCESS_Current();
762         HFILE32 handle = HFILE_ERROR32;
763
764         SYSTEM_LOCK();
765         if (pdb->console != NULL) {
766                 CONSOLE *console = (CONSOLE *)pdb->console;
767                 handle = (HFILE32)HANDLE_Alloc(pdb, &console->header, 0, TRUE, -1);
768         }
769         SYSTEM_UNLOCK();
770         return handle;
771 }
772
773 /***********************************************************************
774  *            AllocConsole (KERNEL32.103)
775  *
776  * creates an xterm with a pty to our program
777  */
778 BOOL32 WINAPI AllocConsole(VOID)
779 {
780
781         PDB32 *pdb = PROCESS_Current();
782         CONSOLE *console;
783         HANDLE32 hIn, hOut, hErr;
784
785         SYSTEM_LOCK();          /* FIXME: really only need to lock the process */
786
787         SetLastError(ERROR_CANNOT_MAKE);  /* this might not be the right 
788                                              error, but it's a good guess :) */
789
790         console = (CONSOLE *)pdb->console;
791
792         /* don't create a console if we already have one */
793         if (console != NULL) {
794                 SetLastError(ERROR_ACCESS_DENIED);
795                 SYSTEM_UNLOCK();
796                 return FALSE;
797         }
798
799         if (!(console = (CONSOLE*)HeapAlloc( SystemHeap, 0, sizeof(*console))))
800         {
801             SYSTEM_UNLOCK();
802             return FALSE;
803         }
804
805         console->header.type     = K32OBJ_CONSOLE;
806         console->header.refcount = 1;
807         console->pid             = -1;
808         console->title           = NULL;
809         console->nrofirs         = 0;
810         console->wait_queue      = NULL;
811         console->irs             = HeapAlloc(GetProcessHeap(),0,1);;
812         console->mode            =   ENABLE_PROCESSED_INPUT
813                                    | ENABLE_LINE_INPUT
814                                    | ENABLE_ECHO_INPUT;
815         /* FIXME: we shouldn't probably use hardcoded UNIX values here. */
816         console->infd            = 0;
817         console->outfd           = 1;
818
819         if ((hIn = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
820         {
821             K32OBJ_DecCount(&console->header);
822             SYSTEM_UNLOCK();
823             return FALSE;
824         }
825
826         if ((hOut = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
827         {
828             CloseHandle(hIn);
829             K32OBJ_DecCount(&console->header);
830             SYSTEM_UNLOCK();
831             return FALSE;
832         }
833
834
835         if ((hErr = HANDLE_Alloc(pdb,&console->header, 0, TRUE,-1)) == INVALID_HANDLE_VALUE32)
836         {
837             CloseHandle(hIn);
838             CloseHandle(hOut);
839             K32OBJ_DecCount(&console->header);
840             SYSTEM_UNLOCK();
841             return FALSE;
842         }
843
844         if (pdb->console) K32OBJ_DecCount( pdb->console );
845         pdb->console = (K32OBJ *)console;
846         K32OBJ_IncCount( pdb->console );
847
848         /* NT resets the STD_*_HANDLEs on console alloc */
849         SetStdHandle(STD_INPUT_HANDLE, hIn);
850         SetStdHandle(STD_OUTPUT_HANDLE, hOut);
851         SetStdHandle(STD_ERROR_HANDLE, hErr);
852
853         SetLastError(ERROR_SUCCESS);
854         SYSTEM_UNLOCK();
855         SetConsoleTitle32A("Wine Console");
856         return TRUE;
857 }
858
859
860 /******************************************************************************
861  * GetConsoleCP [KERNEL32.295]  Returns the OEM code page for the console
862  *
863  * RETURNS
864  *    Code page code
865  */
866 UINT32 WINAPI GetConsoleCP(VOID)
867 {
868     return GetACP();
869 }
870
871
872 /***********************************************************************
873  *            GetConsoleOutputCP   (KERNEL32.189)
874  */
875 UINT32 WINAPI GetConsoleOutputCP(VOID)
876 {
877     return GetConsoleCP();
878 }
879
880 /***********************************************************************
881  *            GetConsoleMode   (KERNEL32.188)
882  */
883 BOOL32 WINAPI GetConsoleMode(HANDLE32 hcon,LPDWORD mode)
884 {
885     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
886
887     if (!console) {
888         FIXME(console,"(%d,%p), no console handle passed!\n",hcon,mode);
889         return FALSE;
890     }
891     *mode = console->mode;
892     K32OBJ_DecCount(&console->header);
893     return TRUE;
894 }
895
896
897 /******************************************************************************
898  * SetConsoleMode [KERNEL32.628]  Sets input mode of console's input buffer
899  *
900  * PARAMS
901  *    hcon [I] Handle to console input or screen buffer
902  *    mode [I] Input or output mode to set
903  *
904  * RETURNS
905  *    Success: TRUE
906  *    Failure: FALSE
907  */
908 BOOL32 WINAPI SetConsoleMode( HANDLE32 hcon, DWORD mode )
909 {
910     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
911
912     if (!console) {
913         FIXME(console,"(%d,%ld), no console handle passed!\n",hcon,mode);
914         return FALSE;
915     }
916     FIXME(console,"(0x%08x,0x%08lx): stub\n",hcon,mode);
917     console->mode = mode;
918     K32OBJ_DecCount(&console->header);
919     return TRUE;
920 }
921
922
923 /***********************************************************************
924  *            GetConsoleTitleA   (KERNEL32.191)
925  */
926 DWORD WINAPI GetConsoleTitle32A(LPSTR title,DWORD size)
927 {
928     PDB32 *pdb = PROCESS_Current();
929     CONSOLE *console= (CONSOLE *)pdb->console;
930
931     if(console && console->title) {
932         lstrcpyn32A(title,console->title,size);
933         return strlen(title);
934     }
935     return 0;
936 }
937
938
939 /******************************************************************************
940  * GetConsoleTitle32W [KERNEL32.192]  Retrieves title string for console
941  *
942  * PARAMS
943  *    title [O] Address of buffer for title
944  *    size  [I] Size of buffer
945  *
946  * RETURNS
947  *    Success: Length of string copied
948  *    Failure: 0
949  */
950 DWORD WINAPI GetConsoleTitle32W( LPWSTR title, DWORD size )
951 {
952     PDB32 *pdb = PROCESS_Current();
953     CONSOLE *console= (CONSOLE *)pdb->console;
954     if(console && console->title) 
955     {
956         lstrcpynAtoW(title,console->title,size);
957         return (lstrlen32W(title));
958     }
959     return 0;
960 }
961
962
963 /***********************************************************************
964  *            WriteConsoleA   (KERNEL32.729)
965  */
966 BOOL32 WINAPI WriteConsole32A( HANDLE32 hConsoleOutput,
967                                LPCVOID lpBuffer,
968                                DWORD nNumberOfCharsToWrite,
969                                LPDWORD lpNumberOfCharsWritten,
970                                LPVOID lpReserved )
971 {
972         /* FIXME: should I check if this is a console handle? */
973         return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
974                          lpNumberOfCharsWritten, NULL);
975 }
976
977
978 #define CADD(c)                                                         \
979         if (bufused==curbufsize-1)                                      \
980             buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
981         buffer[bufused++]=c;
982 #define SADD(s) { char *x=s;while (*x) {CADD(*x);x++;}}
983
984 /***********************************************************************
985  *            WriteConsoleOutputA   (KERNEL32.732)
986  */
987 BOOL32 WINAPI WriteConsoleOutput32A( HANDLE32 hConsoleOutput,
988                                      LPCHAR_INFO lpBuffer,
989                                      COORD dwBufferSize,
990                                      COORD dwBufferCoord,
991                                      LPSMALL_RECT lpWriteRegion)
992 {
993     int i,j,off=0,lastattr=-1;
994     char        sbuf[20],*buffer=NULL;
995     int         bufused=0,curbufsize = 100;
996     DWORD       res;
997     const int colormap[8] = {
998         0,4,2,6,
999         1,5,3,7,
1000     };
1001     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hConsoleOutput, K32OBJ_CONSOLE, 0, NULL);
1002
1003     if (!console) {
1004         FIXME(console,"(%d,...): no console handle!\n",hConsoleOutput);
1005         return FALSE;
1006     }
1007     CONSOLE_make_complex(console);
1008     buffer = HeapAlloc(GetProcessHeap(),0,100);;
1009     curbufsize = 100;
1010
1011     TRACE(console,"wr: top = %d, bottom=%d, left=%d,right=%d\n",
1012         lpWriteRegion->Top,
1013         lpWriteRegion->Bottom,
1014         lpWriteRegion->Left,
1015         lpWriteRegion->Right
1016     );
1017
1018     for (i=lpWriteRegion->Top;i<=lpWriteRegion->Bottom;i++) {
1019         sprintf(sbuf,"%c[%d;%dH",27,i+1,lpWriteRegion->Left+1);
1020         SADD(sbuf);
1021         for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
1022             if (lastattr!=lpBuffer[off].Attributes) {
1023                 lastattr = lpBuffer[off].Attributes;
1024                 sprintf(sbuf,"%c[0;%s3%d;4%dm",
1025                         27,
1026                         (lastattr & FOREGROUND_INTENSITY)?"1;":"",
1027                         colormap[lastattr&7],
1028                         colormap[(lastattr&0x70)>>4]
1029                 );
1030                 /* FIXME: BACKGROUND_INTENSITY */
1031                 SADD(sbuf);
1032             }
1033             CADD(lpBuffer[off].Char.AsciiChar);
1034             off++;
1035         }
1036     }
1037     sprintf(sbuf,"%c[0m",27);SADD(sbuf);
1038     WriteFile(hConsoleOutput,buffer,bufused,&res,NULL);
1039     HeapFree(GetProcessHeap(),0,buffer);
1040     K32OBJ_DecCount(&console->header);
1041     return TRUE;
1042 }
1043
1044 /***********************************************************************
1045  *            WriteConsoleW   (KERNEL32.577)
1046  */
1047 BOOL32 WINAPI WriteConsole32W( HANDLE32 hConsoleOutput,
1048                                LPCVOID lpBuffer,
1049                                DWORD nNumberOfCharsToWrite,
1050                                LPDWORD lpNumberOfCharsWritten,
1051                                LPVOID lpReserved )
1052 {
1053         BOOL32 ret;
1054         LPSTR xstring=HeapAlloc( GetProcessHeap(), 0, nNumberOfCharsToWrite );
1055
1056         lstrcpynWtoA( xstring,  lpBuffer,nNumberOfCharsToWrite);
1057
1058         /* FIXME: should I check if this is a console handle? */
1059         ret= WriteFile(hConsoleOutput, xstring, nNumberOfCharsToWrite,
1060                          lpNumberOfCharsWritten, NULL);
1061         HeapFree( GetProcessHeap(), 0, xstring );
1062         return ret;
1063 }
1064
1065
1066 /***********************************************************************
1067  *            ReadConsoleA   (KERNEL32.419)
1068  */
1069 BOOL32 WINAPI ReadConsole32A( HANDLE32 hConsoleInput,
1070                               LPVOID lpBuffer,
1071                               DWORD nNumberOfCharsToRead,
1072                               LPDWORD lpNumberOfCharsRead,
1073                               LPVOID lpReserved )
1074 {
1075     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hConsoleInput, K32OBJ_CONSOLE, 0, NULL);
1076     int         i,charsread = 0;
1077     LPSTR       xbuf = (LPSTR)lpBuffer;
1078
1079     if (!console) {
1080         SetLastError(ERROR_INVALID_HANDLE);
1081         FIXME(console,"(%d,...), no console handle!\n",hConsoleInput);
1082         return FALSE;
1083     }
1084     TRACE(console,"(%d,%p,%ld,%p,%p)\n",
1085             hConsoleInput,lpBuffer,nNumberOfCharsToRead,
1086             lpNumberOfCharsRead,lpReserved
1087     );
1088     CONSOLE_get_input(console);
1089
1090     /* FIXME:   should this drain everything from the input queue and just 
1091      *          put the keypresses in the buffer? Needs further thought.
1092      */
1093     for (i=0;(i<console->nrofirs)&&(charsread<nNumberOfCharsToRead);i++) {
1094         if (console->irs[i].EventType != KEY_EVENT)
1095                 continue;
1096         if (!console->irs[i].Event.KeyEvent.bKeyDown)
1097                 continue;
1098         *xbuf++ = console->irs[i].Event.KeyEvent.uChar.AsciiChar; 
1099         charsread++;
1100     }
1101     CONSOLE_drain_input(console,i);
1102     if (lpNumberOfCharsRead)
1103         *lpNumberOfCharsRead = charsread;
1104     K32OBJ_DecCount(&console->header);
1105     return TRUE;
1106 }
1107
1108 /***********************************************************************
1109  *            ReadConsoleW   (KERNEL32.427)
1110  */
1111 BOOL32 WINAPI ReadConsole32W( HANDLE32 hConsoleInput,
1112                               LPVOID lpBuffer,
1113                               DWORD nNumberOfCharsToRead,
1114                               LPDWORD lpNumberOfCharsRead,
1115                               LPVOID lpReserved )
1116 {
1117     BOOL32 ret;
1118     LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
1119
1120     ret = ReadConsole32A(
1121         hConsoleInput,
1122         buf,
1123         nNumberOfCharsToRead,
1124         lpNumberOfCharsRead,
1125         lpReserved
1126     );
1127     if (ret)
1128         lstrcpynAtoW(lpBuffer,buf,nNumberOfCharsToRead);
1129     HeapFree( GetProcessHeap(), 0, buf );
1130     return ret;
1131 }
1132
1133
1134 /******************************************************************************
1135  * ReadConsoleInput32A [KERNEL32.569]  Reads data from a console
1136  *
1137  * PARAMS
1138  *    hConsoleInput        [I] Handle to console input buffer
1139  *    lpBuffer             [O] Address of buffer for read data
1140  *    nLength              [I] Number of records to read
1141  *    lpNumberOfEventsRead [O] Address of number of records read
1142  *
1143  * RETURNS
1144  *    Success: TRUE
1145  *    Failure: FALSE
1146  */
1147 BOOL32 WINAPI ReadConsoleInput32A(HANDLE32 hConsoleInput,
1148                                   LPINPUT_RECORD lpBuffer,
1149                                   DWORD nLength, LPDWORD lpNumberOfEventsRead)
1150 {
1151     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hConsoleInput, K32OBJ_CONSOLE, 0, NULL);
1152
1153     TRACE(console, "(%d,%p,%ld,%p)\n",hConsoleInput, lpBuffer, nLength,
1154           lpNumberOfEventsRead);
1155     if (!console) {
1156         FIXME(console, "(%d,%p,%ld,%p), No console handle!\n",hConsoleInput,
1157                 lpBuffer, nLength, lpNumberOfEventsRead);
1158         return FALSE;
1159     }
1160     CONSOLE_get_input(console);
1161     if (nLength>console->nrofirs)
1162         nLength = console->nrofirs;
1163     memcpy(lpBuffer,console->irs,sizeof(INPUT_RECORD)*nLength);
1164     if (lpNumberOfEventsRead)
1165         *lpNumberOfEventsRead = nLength;
1166     CONSOLE_drain_input(console,nLength);
1167     K32OBJ_DecCount(&console->header);
1168     return TRUE;
1169 }
1170
1171 /***********************************************************************
1172  *            SetConsoleTitle32A   (KERNEL32.476)
1173  *
1174  * Sets the console title.
1175  *
1176  * We do not necessarily need to create a complex console for that,
1177  * but should remember the title and set it on creation of the latter.
1178  * (not fixed at this time).
1179  */
1180 BOOL32 WINAPI SetConsoleTitle32A(LPCSTR title)
1181 {
1182     PDB32 *pdb = PROCESS_Current();
1183     CONSOLE *console;
1184     DWORD written;
1185     char titleformat[]="\033]2;%s\a"; /*this should work for xterms*/
1186     LPSTR titlestring; 
1187     BOOL32 ret=FALSE;
1188
1189     TRACE(console,"(%s)\n",title);
1190
1191     console = (CONSOLE *)pdb->console;
1192     if (!console)
1193         return FALSE;
1194     if(console->title) /* Free old title, if there is one */
1195         HeapFree( SystemHeap, 0, console->title );
1196     console->title = (LPSTR)HeapAlloc(SystemHeap, 0,strlen(title)+1);
1197     if(console->title) strcpy(console->title,title);
1198     titlestring = HeapAlloc(GetProcessHeap(), 0,strlen(title)+strlen(titleformat)+1);
1199     if (!titlestring) {
1200         K32OBJ_DecCount(&console->header);
1201         return FALSE;
1202     }
1203
1204     sprintf(titlestring,titleformat,title);
1205     /* FIXME: hmm, should use WriteFile probably... */
1206     CONSOLE_Write(&console->header,titlestring,strlen(titlestring),&written,NULL);
1207     if (written == strlen(titlestring))
1208         ret =TRUE;
1209     HeapFree( GetProcessHeap(), 0, titlestring );
1210     K32OBJ_DecCount(&console->header);
1211     return ret;
1212 }
1213
1214
1215 /******************************************************************************
1216  * SetConsoleTitle32W [KERNEL32.477]  Sets title bar string for console
1217  *
1218  * PARAMS
1219  *    title [I] Address of new title
1220  *
1221  * NOTES
1222  *    This should not be calling the A version
1223  *
1224  * RETURNS
1225  *    Success: TRUE
1226  *    Failure: FALSE
1227  */
1228 BOOL32 WINAPI SetConsoleTitle32W( LPCWSTR title )
1229 {
1230     BOOL32 ret;
1231
1232     LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
1233     ret = SetConsoleTitle32A(titleA);
1234     HeapFree( GetProcessHeap(), 0, titleA );
1235     return ret;
1236 }
1237
1238 /***********************************************************************
1239  *            ReadConsoleInput32W   (KERNEL32.570)
1240  */
1241 BOOL32 WINAPI ReadConsoleInput32W(HANDLE32 hConsoleInput,
1242                                 LPINPUT_RECORD lpBuffer,
1243                                 DWORD nLength, LPDWORD lpNumberOfEventsRead)
1244 {
1245     FIXME(console, "(%d,%p,%ld,%p): stub\n",hConsoleInput, lpBuffer, nLength,
1246           lpNumberOfEventsRead);
1247     return 0;
1248 }
1249
1250 /***********************************************************************
1251  *            FlushConsoleInputBuffer   (KERNEL32.132)
1252  */
1253 BOOL32 WINAPI FlushConsoleInputBuffer(HANDLE32 hConsoleInput)
1254 {
1255     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hConsoleInput, K32OBJ_CONSOLE, 0, NULL);
1256
1257     if (!console)
1258         return FALSE;
1259     CONSOLE_drain_input(console,console->nrofirs);
1260     K32OBJ_DecCount(&console->header);
1261     return TRUE;
1262 }
1263
1264
1265 /******************************************************************************
1266  * SetConsoleCursorPosition [KERNEL32.627]
1267  * Sets the cursor position in console
1268  *
1269  * PARAMS
1270  *    hConsoleOutput   [I] Handle of console screen buffer
1271  *    dwCursorPosition [I] New cursor position coordinates
1272  *
1273  * RETURNS STD
1274  */
1275 BOOL32 WINAPI SetConsoleCursorPosition( HANDLE32 hcon, COORD pos )
1276 {
1277     char        xbuf[20];
1278     DWORD       xlen;
1279     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
1280
1281     if (!console) {
1282         FIXME(console,"(%d,...), no console handle!\n",hcon);
1283         return FALSE;
1284     }
1285     CONSOLE_make_complex(console);
1286     TRACE(console, "%d (%dx%d)\n", hcon, pos.x , pos.y );
1287     /* x are columns, y rows */
1288     sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.y+1, pos.x+1);
1289     /* FIXME: store internal if we start using own console buffers */
1290     WriteFile(hcon,xbuf,strlen(xbuf),&xlen,NULL);
1291     K32OBJ_DecCount(&console->header);
1292     return TRUE;
1293 }
1294
1295 /***********************************************************************
1296  *            GetNumberOfConsoleInputEvents   (KERNEL32.246)
1297  */
1298 BOOL32 WINAPI GetNumberOfConsoleInputEvents(HANDLE32 hcon,LPDWORD nrofevents)
1299 {
1300     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
1301
1302     if (!console) {
1303         FIXME(console,"(%d,%p), no console handle!\n",hcon,nrofevents);
1304         return FALSE;
1305     }
1306     CONSOLE_get_input(console);
1307     *nrofevents = console->nrofirs;
1308     K32OBJ_DecCount(&console->header);
1309     return TRUE;
1310 }
1311
1312 /***********************************************************************
1313  *            GetNumberOfConsoleMouseButtons   (KERNEL32.358)
1314  */
1315 BOOL32 WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
1316 {
1317     FIXME(console,"(%p): stub\n", nrofbuttons);
1318     *nrofbuttons = 2;
1319     return TRUE;
1320 }
1321
1322 /***********************************************************************
1323  *            PeekConsoleInputA   (KERNEL32.550)
1324  *
1325  * Gets 'cInRecords' first events (or less) from input queue.
1326  *
1327  * Does not need a complex console.
1328  */
1329 BOOL32 WINAPI PeekConsoleInput32A(HANDLE32 hConsoleInput,
1330                                   LPINPUT_RECORD pirBuffer,
1331                                   DWORD cInRecords,
1332                                   LPDWORD lpcRead)
1333 {
1334     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hConsoleInput, K32OBJ_CONSOLE, 0, NULL);
1335
1336     if (!console) {
1337         FIXME(console,"(%d,%p,%ld,%p), No console handle passed!\n",hConsoleInput, pirBuffer, cInRecords, lpcRead);
1338         return FALSE;
1339     }
1340     TRACE(console,"(%d,%p,%ld,%p)\n",hConsoleInput, pirBuffer, cInRecords, lpcRead);
1341     CONSOLE_get_input(console);
1342     if (cInRecords>console->nrofirs)
1343         cInRecords = console->nrofirs;
1344     if (pirBuffer)
1345         memcpy(pirBuffer,console->irs,cInRecords*sizeof(INPUT_RECORD));
1346     if (lpcRead)
1347         *lpcRead = cInRecords;
1348     K32OBJ_DecCount(&console->header);
1349     return TRUE;
1350 }
1351
1352 /***********************************************************************
1353  *            PeekConsoleInputW   (KERNEL32.551)
1354  */
1355 BOOL32 WINAPI PeekConsoleInput32W(HANDLE32 hConsoleInput,
1356                                   LPINPUT_RECORD pirBuffer,
1357                                   DWORD cInRecords,
1358                                   LPDWORD lpcRead)
1359 {
1360     /* FIXME: Hmm. Fix this if we get UNICODE input. */
1361     return PeekConsoleInput32A(hConsoleInput,pirBuffer,cInRecords,lpcRead);
1362 }
1363
1364
1365 /******************************************************************************
1366  * GetConsoleCursorInfo32 [KERNEL32.296]  Gets size and visibility of console
1367  *
1368  * PARAMS
1369  *    hcon  [I] Handle to console screen buffer
1370  *    cinfo [O] Address of cursor information
1371  *
1372  * RETURNS
1373  *    Success: TRUE
1374  *    Failure: FALSE
1375  */
1376 BOOL32 WINAPI GetConsoleCursorInfo32( HANDLE32 hcon,
1377                                       LPCONSOLE_CURSOR_INFO cinfo )
1378 {
1379     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
1380
1381     if (!console) {
1382         FIXME(console, "(%x,%p), no console handle!\n", hcon, cinfo);
1383         return FALSE;
1384     }
1385     TRACE(console, "(%x,%p)\n", hcon, cinfo);
1386     if (!cinfo)
1387         return FALSE;
1388     *cinfo = console->cinfo;
1389     K32OBJ_DecCount(&console->header);
1390     return TRUE;
1391 }
1392
1393
1394 /******************************************************************************
1395  * SetConsoleCursorInfo32 [KERNEL32.626]  Sets size and visibility of cursor
1396  *
1397  * RETURNS
1398  *    Success: TRUE
1399  *    Failure: FALSE
1400  */
1401 BOOL32 WINAPI SetConsoleCursorInfo32( 
1402     HANDLE32 hcon,                /* [in] Handle to console screen buffer */
1403     LPCONSOLE_CURSOR_INFO cinfo)  /* [in] Address of cursor information */
1404 {
1405     char        buf[8];
1406     DWORD       xlen;
1407     CONSOLE     *console = (CONSOLE*)HANDLE_GetObjPtr( PROCESS_Current(), hcon, K32OBJ_CONSOLE, 0, NULL);
1408
1409     TRACE(console, "(%x,%ld,%i): stub\n", hcon,cinfo->dwSize,cinfo->bVisible);
1410     if (!console)
1411         return FALSE;
1412     CONSOLE_make_complex(console);
1413     sprintf(buf,"%c[?25%c",27,cinfo->bVisible?'h':'l');
1414     WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
1415     console->cinfo = *cinfo;
1416     K32OBJ_DecCount(&console->header);
1417     return TRUE;
1418 }
1419
1420
1421 /******************************************************************************
1422  * SetConsoleWindowInfo [KERNEL32.634]  Sets size and position of console
1423  *
1424  * RETURNS
1425  *    Success: TRUE
1426  *    Failure: FALSE
1427  */
1428 BOOL32 WINAPI SetConsoleWindowInfo(
1429     HANDLE32 hcon,       /* [in] Handle to console screen buffer */
1430     BOOL32 bAbsolute,    /* [in] Coordinate type flag */
1431     LPSMALL_RECT window) /* [in] Address of new window rectangle */
1432 {
1433     FIXME(console, "(%x,%d,%p): stub\n", hcon, bAbsolute, window);
1434     return TRUE;
1435 }
1436
1437
1438 /******************************************************************************
1439  * SetConsoleTextAttribute32 [KERNEL32.631]  Sets colors for text
1440  *
1441  * Sets the foreground and background color attributes of characters
1442  * written to the screen buffer.
1443  *
1444  * RETURNS
1445  *    Success: TRUE
1446  *    Failure: FALSE
1447  */
1448 BOOL32 WINAPI SetConsoleTextAttribute32(HANDLE32 hConsoleOutput,WORD wAttr)
1449 {
1450     const int colormap[8] = {
1451         0,4,2,6,
1452         1,5,3,7,
1453     };
1454     DWORD xlen;
1455     char buffer[20];
1456
1457     TRACE(console,"(%d,%d)\n",hConsoleOutput,wAttr);
1458     sprintf(buffer,"%c[0;%s3%d;4%dm",
1459         27,
1460         (wAttr & FOREGROUND_INTENSITY)?"1;":"",
1461         colormap[wAttr&7],
1462         colormap[(wAttr&0x70)>>4]
1463     );
1464     WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
1465     return TRUE;
1466 }
1467
1468
1469 /******************************************************************************
1470  * SetConsoleScreenBufferSize [KERNEL32.630]  Changes size of console 
1471  *
1472  * PARAMS
1473  *    hConsoleOutput [I] Handle to console screen buffer
1474  *    dwSize         [I] New size in character rows and cols
1475  *
1476  * RETURNS
1477  *    Success: TRUE
1478  *    Failure: FALSE
1479  */
1480 BOOL32 WINAPI SetConsoleScreenBufferSize( HANDLE32 hConsoleOutput, 
1481                                           COORD dwSize )
1482 {
1483     FIXME(console, "(%d,%dx%d): stub\n",hConsoleOutput,dwSize.x,dwSize.y);
1484     return TRUE;
1485 }
1486
1487
1488 /******************************************************************************
1489  * FillConsoleOutputCharacterA [KERNEL32.242]
1490  *
1491  * PARAMS
1492  *    hConsoleOutput    [I] Handle to screen buffer
1493  *    cCharacter        [I] Character to write
1494  *    nLength           [I] Number of cells to write to
1495  *    dwCoord           [I] Coords of first cell
1496  *    lpNumCharsWritten [O] Pointer to number of cells written
1497  *
1498  * RETURNS
1499  *    Success: TRUE
1500  *    Failure: FALSE
1501  */
1502 BOOL32 WINAPI FillConsoleOutputCharacterA(
1503     HANDLE32 hConsoleOutput,
1504     BYTE cCharacter,
1505     DWORD nLength,
1506     COORD dwCoord,
1507     LPDWORD lpNumCharsWritten)
1508 {
1509     long        count;
1510     DWORD       xlen;
1511
1512     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1513     for(count=0;count<nLength;count++)
1514         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1515     *lpNumCharsWritten = nLength;
1516     return TRUE;
1517 }
1518
1519
1520 /******************************************************************************
1521  * FillConsoleOutputCharacterW [KERNEL32.243]  Writes characters to console
1522  *
1523  * PARAMS
1524  *    hConsoleOutput    [I] Handle to screen buffer
1525  *    cCharacter        [I] Character to write
1526  *    nLength           [I] Number of cells to write to
1527  *    dwCoord           [I] Coords of first cell
1528  *    lpNumCharsWritten [O] Pointer to number of cells written
1529  *
1530  * RETURNS
1531  *    Success: TRUE
1532  *    Failure: FALSE
1533  */
1534 BOOL32 WINAPI FillConsoleOutputCharacterW(HANDLE32 hConsoleOutput,
1535                                             WCHAR cCharacter,
1536                                             DWORD nLength,
1537                                            COORD dwCoord, 
1538                                             LPDWORD lpNumCharsWritten)
1539 {
1540     long        count;
1541     DWORD       xlen;
1542
1543     SetConsoleCursorPosition(hConsoleOutput,dwCoord);
1544     /* FIXME: not quite correct ... but the lower part of UNICODE char comes
1545      * first 
1546      */
1547     for(count=0;count<nLength;count++)
1548         WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
1549     *lpNumCharsWritten = nLength;
1550     return TRUE;
1551 }
1552
1553
1554 /******************************************************************************
1555  * FillConsoleOutputAttribute [KERNEL32.241]  Sets attributes for console
1556  *
1557  * PARAMS
1558  *    hConsoleOutput    [I] Handle to screen buffer
1559  *    wAttribute        [I] Color attribute to write
1560  *    nLength           [I] Number of cells to write to
1561  *    dwCoord           [I] Coords of first cell
1562  *    lpNumAttrsWritten [O] Pointer to number of cells written
1563  *
1564  * RETURNS
1565  *    Success: TRUE
1566  *    Failure: FALSE
1567  */
1568 BOOL32 WINAPI FillConsoleOutputAttribute( HANDLE32 hConsoleOutput, 
1569               WORD wAttribute, DWORD nLength, COORD dwCoord, 
1570               LPDWORD lpNumAttrsWritten)
1571 {
1572     FIXME(console, "(%d,%d,%ld,%dx%d,%p): stub\n", hConsoleOutput,
1573           wAttribute,nLength,dwCoord.x,dwCoord.y,lpNumAttrsWritten);
1574     *lpNumAttrsWritten = nLength;
1575     return TRUE;
1576 }
1577
1578 /******************************************************************************
1579  * ReadConsoleOutputCharacter32A [KERNEL32.573]
1580  * 
1581  * BUGS
1582  *   Unimplemented
1583  */
1584 BOOL32 WINAPI ReadConsoleOutputCharacter32A(HANDLE32 hConsoleOutput, 
1585               LPSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
1586 {
1587     FIXME(console, "(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
1588           dword,coord.x,coord.y,lpdword);
1589     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1590     return FALSE;
1591 }
1592
1593
1594 /******************************************************************************
1595  * ScrollConsoleScreenBuffer [KERNEL32.612]
1596  * 
1597  * BUGS
1598  *   Unimplemented
1599  */
1600 BOOL32 WINAPI ScrollConsoleScreenBuffer( HANDLE32 hConsoleOutput, 
1601               LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
1602               COORD dwDestOrigin, LPCHAR_INFO lpFill)
1603 {
1604     FIXME(console, "(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
1605           lpClipRect,dwDestOrigin.x,dwDestOrigin.y,lpFill);
1606     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1607     return FALSE;
1608 }