1/*$Header: /p/tcsh/cvsroot/tcsh/win32/console.c,v 1.9 2006/08/27 01:13:28 amold Exp $*/ 2/*- 3 * Copyright (c) 1980, 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * console.c: hacks to do various cursor movement/attribute things 33 * -amol 34 */ 35#define WIN32_LEAN_AND_MEAN 36#include <windows.h> 37#include <wincon.h> 38#include <stdio.h> 39#include "ntport.h" 40 41 42// int to SHORT. caused by all the stupid functions that take WORDs 43#pragma warning(disable:4244) 44 45void ScrollBuf(HANDLE,CONSOLE_SCREEN_BUFFER_INFO*,int); 46void NT_MoveToLineOrChar(int ,int ) ; 47WORD get_attributes(); 48 49 50#define FSHIN 16 /* Preferred desc for shell input */ 51#define FSHOUT 17 /* Preferred desc for shell input */ 52 53#define FOREGROUND_BLACK (FOREGROUND_RED |FOREGROUND_GREEN | FOREGROUND_BLUE) 54#define FOREGROUND_WHITE 0 55#define BACKGROUND_BLACK (BACKGROUND_RED |BACKGROUND_GREEN | BACKGROUND_BLUE) 56#define BACKGROUND_WHITE 0 57 58static WORD wNormalAttributes; 59 60 61static int nt_is_raw; 62// 63// The following are used to optimize some console routines. It avoids having 64// to call GetConsoleScreenBufferInfo. 65// Seems to have helped the speed a bit. -amol 66// 67HANDLE ghstdout; 68HANDLE ghReverse; 69 70// 71// This function is called to set the values for above variables. 72// 73void redo_console(void) { 74 75 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 76 HANDLE hTemp= GetStdHandle(STD_OUTPUT_HANDLE); 77 WORD dbga; 78 DWORD wrote; 79 COORD origin = {0,0}; 80 81 if (!DuplicateHandle(GetCurrentProcess(),hTemp,GetCurrentProcess(), 82 &ghstdout,0,TRUE,DUPLICATE_SAME_ACCESS) ) { 83 ; 84 } 85 86 if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) { 87 wNormalAttributes = FOREGROUND_BLACK | BACKGROUND_WHITE; 88 } 89 else 90 wNormalAttributes = scrbuf.wAttributes; 91 92 ghReverse = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, 93 FILE_SHARE_READ | FILE_SHARE_WRITE, 94 NULL, 95 CONSOLE_TEXTMODE_BUFFER, 96 NULL); 97 98 dbga = ((wNormalAttributes & 0x00f0) >> 4) | 99 ((wNormalAttributes & 0x000f) << 4) ; 100 101 FillConsoleOutputAttribute(ghReverse,dbga, 102 scrbuf.dwSize.X*scrbuf.dwSize.Y, 103 origin, 104 &wrote); 105} 106void nt_term_cleanup(void) { 107 CloseHandle(ghstdout); 108} 109void nt_term_init() { 110 111 DWORD dwmode; 112 HANDLE hinput =GetStdHandle(STD_INPUT_HANDLE); 113 114 if (!GetConsoleMode(hinput,&dwmode) ){ 115 ; 116 } 117 if(!SetConsoleMode(hinput,dwmode | ENABLE_WINDOW_INPUT) ){ 118 return; 119 } 120 121 redo_console(); 122 123 return; 124} 125int do_nt_check_cooked_mode(void) { 126 127 return !nt_is_raw; 128} 129void do_nt_raw_mode() { 130 131 DWORD dwmode; 132 HANDLE hinput =(HANDLE)_get_osfhandle(FSHIN); 133 134 if (hinput == INVALID_HANDLE_VALUE) 135 return; 136 if (!GetConsoleMode(hinput,&dwmode) ){ 137 ; 138 } 139 if(!SetConsoleMode(hinput,dwmode & (~( 140 ENABLE_LINE_INPUT |ENABLE_ECHO_INPUT 141 | ENABLE_PROCESSED_INPUT)| ENABLE_WINDOW_INPUT ) 142 ) ){ 143 return; 144 } 145 nt_is_raw = 1; 146 return; 147} 148void do_nt_cooked_mode() { 149 150 DWORD dwmode; 151 HANDLE hinput =(HANDLE)_get_osfhandle(FSHIN); 152 153 if (hinput == INVALID_HANDLE_VALUE) 154 return; 155 if (!GetConsoleMode(hinput,&dwmode) ){ 156 ; 157 } 158 if(!SetConsoleMode(hinput,dwmode | ( ( 159 ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT | 160 ENABLE_PROCESSED_INPUT) ) 161 ) ){ 162 } 163 nt_is_raw = 0; 164 return; 165} 166// 167// this function is a bit ugly, but I don't know how to do it better 168// -amol 169// 170int nt_ClearEOL( void) { 171 172 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 173 HANDLE hStdout =ghstdout ; 174 DWORD numwrote; 175 char errbuf[128];/*FIXME: uninitialized*/ 176 int num=0; 177 COORD savepos; 178 179 180 if (hStdout == INVALID_HANDLE_VALUE){ 181 ExitProcess(0xFFFF); 182 } 183 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 184 return 0 ; 185 } 186 num =2048; 187 188 savepos = scrbuf.dwCursorPosition; 189 if (!FillConsoleOutputCharacter(hStdout,' ',num,scrbuf.dwCursorPosition, 190 &numwrote) ){ 191 dprintf("error from FillCons %s",errbuf); 192 } 193 else if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, num, 194 scrbuf.dwCursorPosition,&numwrote)) { 195 dprintf("error from FillConsAttr %s",errbuf); 196 } 197 return 0; 198} 199void nt_move_next_tab(void) { 200 201 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 202 HANDLE hStdout = ghstdout; 203 int where; 204 205 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 206 ; 207 } 208 where = 8 - (scrbuf.dwCursorPosition.X+1)%8; 209 scrbuf.dwCursorPosition.X += where; 210 if (!SetConsoleCursorPosition(hStdout, scrbuf.dwCursorPosition) ) { 211 ; 212 } 213 214} 215void NT_VisibleBell(void) { 216 217 if(ghReverse != INVALID_HANDLE_VALUE) { 218 SetConsoleActiveScreenBuffer(ghReverse); 219 Sleep(100); 220 SetConsoleActiveScreenBuffer(ghstdout); 221 222 } 223 224} 225void NT_WrapHorizontal(void) { 226 SMALL_RECT wnd; 227 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 228 229 230 if (ghstdout == INVALID_HANDLE_VALUE){ 231 return; 232 } 233 if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) { 234 return; 235 } 236 //absolute movement 237 wnd.Left = 0;//scrbuf.srWindow.Left ; 238 wnd.Right = scrbuf.srWindow.Right- scrbuf.srWindow.Left + 1; 239 wnd.Top = scrbuf.srWindow.Top; 240 wnd.Bottom = scrbuf.srWindow.Bottom; 241 242 SetConsoleWindowInfo(ghstdout,TRUE,&wnd); 243} 244void ScrollBufHorizontal(HANDLE hOut, CONSOLE_SCREEN_BUFFER_INFO *scrbuf, 245 int where) { 246 SMALL_RECT wnd; 247 int diff; 248 CHAR_INFO chr; 249 250 251 //absolute movement 252 wnd.Left = (where - scrbuf->srWindow.Right) + scrbuf->srWindow.Left ; 253 wnd.Right = where; 254 wnd.Top = scrbuf->srWindow.Top; 255 wnd.Bottom = scrbuf->srWindow.Bottom; 256 257 //diff = scrbuf->srWindow.Right - where; 258 //dprintf("\tdiff1 %d\n",diff); 259 260 diff = scrbuf->dwSize.X - where -1; 261 262 if (diff < 0) { //would scroll past console buffer 263 264 chr.Char.AsciiChar = ' '; 265 chr.Attributes = scrbuf->wAttributes; 266 267 scrbuf->dwCursorPosition.Y = scrbuf->srWindow.Top ; 268 scrbuf->dwCursorPosition.X = scrbuf->srWindow.Right+ diff; 269 270 dprintf("scroll diff %d\n",diff); 271 if (!ScrollConsoleScreenBuffer(hOut,&(scrbuf->srWindow), 272 NULL, 273 scrbuf->dwCursorPosition,&chr)) 274 ; 275 276 return; 277 } 278 279 SetConsoleWindowInfo(hOut,TRUE,&wnd); 280} 281// relative movement of "where". line is 1 if we want to move to a line, 282// or 0 if the movement is horizontal 283void NT_MoveToLineOrChar(int where,int line) { 284 285 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 286 HANDLE hStdout = ghstdout; 287 288 289 if (hStdout == INVALID_HANDLE_VALUE){ 290 return; 291 } 292 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 293 return; 294 } 295 296 if (line){ 297 if ( ((scrbuf.dwCursorPosition.Y+where)> (scrbuf.srWindow.Bottom-1)) 298 &&( where >0)){ 299 ScrollBuf(hStdout,&scrbuf,where); 300 scrbuf.dwCursorPosition.Y += where; 301 } 302 else 303 scrbuf.dwCursorPosition.Y += where; 304 } 305 else{ 306 if ( (where> (scrbuf.srWindow.Right)) &&( where >0)){ 307 ScrollBufHorizontal(hStdout,&scrbuf,where); 308 } 309 scrbuf.dwCursorPosition.X = where; 310 } 311 if (scrbuf.dwCursorPosition.X < 0 || scrbuf.dwCursorPosition.Y <0) 312 return; 313 if (!SetConsoleCursorPosition(hStdout, scrbuf.dwCursorPosition) ) { 314 return; 315 } 316 317} 318void ScrollBuf(HANDLE hOut, CONSOLE_SCREEN_BUFFER_INFO *scrbuf,int where) { 319 SMALL_RECT wnd; 320 int diff; 321 CHAR_INFO chr; 322 COORD newpos; 323 324 325 wnd.Left = 0; 326 wnd.Right = 0; 327 wnd.Top = where; 328 wnd.Bottom = where; 329 330 //dwSize is not 0-based, so add 1 to proposed location 331 diff = scrbuf->srWindow.Bottom + where + 1; 332 333 diff = scrbuf->dwSize.Y - diff; 334 335 if (diff < 0) { //would scroll past console buffer 336 337 chr.Char.AsciiChar = ' '; 338 chr.Attributes = scrbuf->wAttributes; 339 340 newpos.Y = scrbuf->srWindow.Top + diff; 341 newpos.X = scrbuf->srWindow.Left; 342 343 dprintf("scroll diff %d\n",diff); 344 if (!ScrollConsoleScreenBuffer(hOut,&(scrbuf->srWindow), 345 NULL, 346 newpos,&chr)) 347 ; 348 349 // need this to be in sync with tcsh 350 scrbuf->dwCursorPosition.Y += diff; 351 return; 352 } 353 354 SetConsoleWindowInfo(hOut,FALSE,&wnd); 355} 356BOOL ConsolePageUpOrDown(BOOL Up) { 357 358 HANDLE hStdout = ghstdout; 359 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 360 SMALL_RECT srect; 361 short diff; 362 363 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 364 return FALSE; 365 } 366 diff = scrbuf.srWindow.Bottom -scrbuf.srWindow.Top+1 ; 367 368 369 if (Up) 370 diff = -diff; 371 372 if ((scrbuf.srWindow.Top + diff > 0) && 373 (scrbuf.srWindow.Bottom + diff < scrbuf.dwSize.Y)) { 374 srect.Top = diff; 375 srect.Bottom = diff; 376 srect.Left = 0; 377 srect.Right = 0; 378 379 if (! SetConsoleWindowInfo( hStdout, FALSE, &srect)) { 380 return FALSE; 381 } 382 } 383 384 return TRUE; 385} 386int nt_getsize(int * lins, int * cols, int *visiblecols) { 387 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 388 HANDLE hStdout = ghstdout; 389 390 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 391 ; 392 } 393 *lins = scrbuf.srWindow.Bottom -scrbuf.srWindow.Top+1 ; 394 395 if(visiblecols) 396 *visiblecols = scrbuf.srWindow.Right -scrbuf.srWindow.Left +1; 397 398 *cols = scrbuf.dwSize.X; 399 return 1; 400} 401void nt_set_size(int lins, int cols) { 402 SMALL_RECT srect; 403 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 404 int expand; 405 406 /* The screen buffer visible window is specified as co-ordinates 407 * not size. Therefore, it must be zero-based 408 */ 409 cols--; 410 lins--; 411 412 srect.Left = srect.Top = 0; 413 srect.Right = cols; 414 srect.Bottom = lins; 415 416 if(!GetConsoleScreenBufferInfo(ghstdout, &scrbuf) ) 417 return; 418 419 expand = 0; 420 if (scrbuf.dwSize.X < cols){ 421 expand = 1; 422 scrbuf.dwSize.X = cols+1; 423 } 424 if (scrbuf.dwSize.Y < lins){ 425 expand = 1; 426 scrbuf.dwSize.Y = lins+1; 427 } 428 429 if (expand && !SetConsoleScreenBufferSize(ghstdout,scrbuf.dwSize)) 430 return; 431 432 if(!SetConsoleWindowInfo(ghstdout,TRUE,&srect)){ 433 int err; 434 err=GetLastError(); 435 dprintf("error %d\n",err); 436 } 437} 438void NT_ClearEOD(void) { 439 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 440 DWORD numwrote; 441 COORD origin; 442 int ht,wt; 443 HANDLE hStdout = ghstdout;//GetStdHandle(STD_OUTPUT_HANDLE); 444 445 if (hStdout == INVALID_HANDLE_VALUE){ 446 return ; 447 } 448 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 449 return ; 450 } 451 origin = scrbuf.dwCursorPosition; 452 ht = scrbuf.dwSize.Y - origin.Y; 453 wt = scrbuf.dwSize.X - origin.X; 454 if(!FillConsoleOutputCharacter(hStdout,' ',ht*wt,origin,&numwrote) ) { 455 return ; 456 } 457 if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, ht*wt, 458 scrbuf.dwCursorPosition,&numwrote)) { 459 return; 460 } 461 return; 462} 463void NT_ClearScreen(void) { 464 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 465 DWORD numwrote; 466 COORD origin={0,0}; 467 HANDLE hStdout = ghstdout;//GetStdHandle(STD_OUTPUT_HANDLE); 468 469 if (hStdout == INVALID_HANDLE_VALUE){ 470 ; 471 } 472 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 473 ; 474 } 475 origin.X = scrbuf.srWindow.Left; 476 origin.Y = scrbuf.srWindow.Top; 477 if(!FillConsoleOutputCharacter(hStdout,' ',scrbuf.dwSize.X*scrbuf.dwSize.Y, 478 origin,&numwrote) ) { 479 ; 480 } 481 if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, 482 scrbuf.dwSize.X*scrbuf.dwSize.Y,origin,&numwrote)) { 483 ; 484 } 485 if (!SetConsoleCursorPosition(hStdout, origin) ) { // home cursor 486 ; 487 } 488 return; 489} 490void NT_ClearScreen_WholeBuffer(void) { 491 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 492 DWORD numwrote; 493 COORD origin={0,0}; 494 HANDLE hStdout = ghstdout; 495 496 if (hStdout == INVALID_HANDLE_VALUE){ 497 ; 498 } 499 if(!GetConsoleScreenBufferInfo(hStdout, &scrbuf) ) { 500 ; 501 } 502 if(!FillConsoleOutputCharacter(hStdout,' ',scrbuf.dwSize.X*scrbuf.dwSize.Y, 503 origin,&numwrote) ) { 504 ; 505 } 506 if (!FillConsoleOutputAttribute(hStdout,scrbuf.wAttributes, 507 scrbuf.dwSize.X*scrbuf.dwSize.Y,origin,&numwrote)) { 508 ; 509 } 510 if (!SetConsoleCursorPosition(hStdout, origin) ) { // home cursor 511 ; 512 } 513 return; 514} 515 516#ifndef COLOR_LS_F 517void set_cons_attr(char *attr2) { 518 char cp[3]; 519 USHORT attr; 520 HANDLE outhandle = (HANDLE)_get_osfhandle(FSHOUT); 521 static WORD old_attribs; 522 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 523 524 if (!old_attribs) { 525 if(!GetConsoleScreenBufferInfo(outhandle, &scrbuf) ) { 526 return; 527 } 528 old_attribs = scrbuf.wAttributes; 529 } 530 cp[0] = (unsigned char)(attr2[0]); 531 cp[1] = (unsigned char)(attr2[1]); 532 cp[2] = 0; 533 if (cp[0] != 'g' || cp[1] != 'g') 534 attr = (USHORT)strtol(cp,NULL,16); 535 else{ 536 attr = old_attribs; 537 old_attribs=0; 538 } 539 540 SetConsoleTextAttribute(outhandle, attr ); 541} 542#endif /* !COLOR_LS_F */ 543 544 545/* 546 color escape sequences (ISO 6429, aixterm) 547 - nayuta 548 */ 549 550 551WORD get_attributes() { 552 CONSOLE_SCREEN_BUFFER_INFO scrbuf; 553 if (!GetConsoleScreenBufferInfo(ghstdout, &scrbuf)) 554 return 0x70; // ERROR: return white background, black text 555 return scrbuf.wAttributes; 556} 557 558 559#ifndef COMMON_LVB_REVERSE_VIDEO 560#define COMMON_LVB_REVERSE_VIDEO 0x4000 561#define COMMON_LVB_UNDERSCORE 0x8000 562#endif 563 564 565void set_attributes(const unsigned char *color) { 566 567 static const int colors[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; 568 WORD wAttributes; 569 const char *t; 570 571 if (color[0] == '\x1b' && color[1] == '[') 572 color += 2; 573 574 if (!('0' <= color[0] && color[0] <= '9')) { 575 SetConsoleTextAttribute(ghstdout, wNormalAttributes); 576 return; 577 } 578 579 wAttributes = get_attributes(); 580 t = (char*)color; 581 582 while (t) { 583 int n = atoi(t); 584 585 if ((t = strchr(t, ';')) != NULL) 586 t++; 587 588 if (n == 0) // Normal (default) 589 wAttributes = wNormalAttributes; 590 else if (n == 1) // Bold 591 wAttributes |= FOREGROUND_INTENSITY; 592 else if (n == 4) // Underlined 593 wAttributes |= COMMON_LVB_UNDERSCORE; 594 else if (n == 5) // Blink (appears as BACKGROUND_INTENSITY) 595 wAttributes |= BACKGROUND_INTENSITY; 596 else if (n == 7) // Inverse 597 wAttributes |= COMMON_LVB_REVERSE_VIDEO; 598 else if (n == 21) // Not bold 599 wAttributes &= ~FOREGROUND_INTENSITY; 600 else if (n == 24) // Not underlined 601 wAttributes &= ~COMMON_LVB_UNDERSCORE; 602 else if (n == 25) // Steady (not blinking) 603 wAttributes &= ~BACKGROUND_INTENSITY; 604 else if (n == 27) // Positive (not inverse) 605 wAttributes &= ~COMMON_LVB_REVERSE_VIDEO; 606 else if (30 <= n && n <= 37) // Set foreground color 607 wAttributes = (wAttributes & ~0x0007) | colors[n - 30]; 608 else if (n == 39) // Set foreground color to default 609 wAttributes = (wAttributes & ~0x0007) | (wNormalAttributes & 0x0007); 610 else if (40 <= n && n <= 47) // Set background color 611 wAttributes = (wAttributes & ~0x0070) | (colors[n - 40] << 4); 612 else if (n == 49) // Set background color to default 613 wAttributes = (wAttributes & ~0x0070) | (wNormalAttributes & 0x0070); 614 else if (90 <= n && n <= 97) // Set foreground color (bright) 615 wAttributes = (wAttributes & ~0x0007) | colors[n - 90] 616 | FOREGROUND_INTENSITY; 617 else if (100 <= n && n <= 107) // Set background color (bright) 618 wAttributes = (wAttributes & ~0x0070) | (colors[n - 100] << 4) 619 | BACKGROUND_INTENSITY; 620 else // (default) 621 wAttributes = wNormalAttributes; 622 } 623 624 // Though Windows' console supports COMMON_LVB_REVERSE_VIDEO, 625 // it seems to be buggy. So we must simulate it. 626 if (wAttributes & COMMON_LVB_REVERSE_VIDEO) 627 wAttributes = (wAttributes & COMMON_LVB_UNDERSCORE) 628 | ((wAttributes & 0x00f0) >> 4) | ((wAttributes & 0x000f) << 4); 629 SetConsoleTextAttribute(ghstdout, wAttributes); 630} 631void StartHighlight(void) 632{ 633} 634void StopHighlight(void) 635{ 636} 637