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