1 /*
2 * $Id: scrnio.c,v 1.7 2005/06/21 19:53:14 andrew_belov Exp $
3 * ---------------------------------------------------------------------------
4 * This module provides basic screen output routines.
5 *
6 */
7
8 #include "arj.h"
9
10 #if CONSOLE_SET==CT_NATIVE||TARGET==OS2
11 #define KNOW_DIMENSIONS
12 #endif
13
14 #include <stdarg.h>
15
16 #if CONSOLE_SET==CT_NATIVE
17 #if TARGET==DOS
18 #include <conio.h>
19 #include <dos.h>
20 #elif TARGET==OS2
21 #endif
22 #endif
23
24 DEBUGHDR(__FILE__) /* Debug information block */
25
26 /* Local variables */
27
28 #ifdef KNOW_DIMENSIONS
29 static unsigned char w_rows=0, w_columns;
30 #endif
31 #if TARGET==WIN32
32 static HANDLE hcons;
33 #endif
34 #if CONSOLE_SET==CT_ANSI||CONSOLE_SET==CT_NATIVE
35 static unsigned char curattr=7;
36 #if CONSOLE_SET==CT_ANSI
37 static char ansicolors[8]={30, 34, 32, 36, 31, 35, 33, 37};
38 static int background_touched=0;
39 #endif
40 #endif
41 int scr_sentry=0;
42
43 /* Queries screen dimensions, excluding window region */
44
45 #ifdef KNOW_DIMENSIONS
get_dimensions()46 static void get_dimensions()
47 {
48 #if TARGET==DOS
49 union REGS r;
50
51 r.h.ah=0x0F;
52 int86(0x10, &r, &r);
53 w_columns=(unsigned int)r.h.ah;
54 w_rows=*(unsigned char FAR *)0x00000484L+1;
55 #elif TARGET==OS2
56 VIOMODEINFO modedata;
57
58 modedata.cb=sizeof(modedata);
59 VioGetMode(&modedata, 0);
60 w_columns=modedata.col;
61 w_rows=modedata.row;
62 #elif TARGET==WIN32
63 CONSOLE_SCREEN_BUFFER_INFO csbi;
64
65 GetConsoleScreenBufferInfo(hcons=GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
66 w_columns=csbi.dwSize.X;
67 w_rows=csbi.dwSize.Y;
68 #endif
69 }
70 #endif
71
72 /* Positions the cursor at row y, column x (top-left screen corner is 1, 1) */
73
74 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_MSGRAPH
gotoxy(int x,int y)75 void gotoxy(int x, int y)
76 {
77 #if CONSOLE_SET==CT_NATIVE
78 #if TARGET==DOS
79 union REGS r;
80
81 r.h.ah=2;
82 r.h.bh=0;
83 r.h.dh=(char)y-1;
84 r.h.dl=(char)x-1;
85 int86(0x10, &r, &r);
86 #elif TARGET==OS2
87 VioSetCurPos((USHORT)y-1, (USHORT)x-1, 0);
88 #elif TARGET==WIN32
89 COORD xy;
90
91 if(w_rows==0)
92 get_dimensions();
93 xy.X=x-1;
94 xy.Y=y-1;
95 SetConsoleCursorPosition(hcons, xy);
96 #endif
97 #elif CONSOLE_SET==CT_ANSI
98 printf("\x1B[%u;%uH", y, x);
99 #endif
100 }
101 #endif
102
103 /* Refreshes the ANSI attributes */
104
105 #if CONSOLE_SET==CT_ANSI
kick_attr()106 static void kick_attr()
107 {
108 if(!background_touched)
109 {
110 if(curattr%8==7)
111 printf("\x1B[0m");
112 else
113 printf("\x1B[0;%um", (unsigned int)ansicolors[curattr%8]);
114 }
115 else
116 {
117 printf("\x1B[0;%u;%um", (unsigned int)ansicolors[curattr%8],
118 (unsigned int)(ansicolors[(curattr>>4)%8])+10);
119 }
120 if(curattr&8)
121 printf("\x1B[1m");
122 }
123 #else
124 #define kick_attr()
125 #endif
126
127 /* Sets the background color to c, color index is the same as on PCs. The
128 colors 8..15 do NOT enable blinking. */
129
130 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_MSGRAPH
textbackground(int c)131 void textbackground(int c)
132 {
133 curattr=(curattr%16+(c<<4))%128;
134 kick_attr();
135 #if CONSOLE_SET==CT_ANSI
136 background_touched=1;
137 #endif
138 }
139 #endif
140
141 /* Sets the foreground color to c, 16...31 enables blinking. */
142
143 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_MSGRAPH
textcolor(int c)144 void textcolor(int c)
145 {
146 curattr=(curattr&112)+((c&16)<<3)+c%16;
147 kick_attr();
148 }
149 #endif
150
151 /* Sets text attributes */
152
153 #if CONSOLE_SET!=CT_BORLAND&&SFX_LEVEL>=ARJSFX
textattr(int c)154 void textattr(int c)
155 {
156 #if CONSOLE_SET==CT_MSGRAPH
157 _settextcolor((short)((c&128)?16:0)+c%16);
158 _setbkcolor((short)(c%128)>>4);
159 #elif CONSOLE_SET==CT_NATIVE||CONSOLE_SET==CT_ANSI
160 curattr=(unsigned char)c;
161 #endif
162 kick_attr();
163 }
164 #endif
165
166 /* Returns current column, 1...<screen width> */
167
168 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_ANSI
wherex()169 int wherex()
170 {
171 #if CONSOLE_SET==CT_MSGRAPH
172 struct rccoord coord;
173
174 coord=_gettextposition();
175 return((int)coord.col);
176 #elif CONSOLE_SET==CT_NATIVE
177 #if TARGET==DOS
178 union REGS r;
179
180 r.h.ah=3;
181 r.h.bh=0;
182 int86(0x10, &r, &r);
183 return((int)r.h.dl+1);
184 #elif TARGET==OS2
185 USHORT x, y;
186
187 VioGetCurPos(&y, &x, 0);
188 return(x+1);
189 #elif TARGET==WIN32
190 CONSOLE_SCREEN_BUFFER_INFO csbi;
191
192 GetConsoleScreenBufferInfo(hcons, &csbi);
193 return(csbi.dwCursorPosition.X+1);
194 #endif
195 #endif
196 }
197 #endif
198
199 /* Returns current row, 1...<screen height> */
200
201 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_ANSI
wherey()202 int wherey()
203 {
204 #if CONSOLE_SET==CT_MSGRAPH
205 struct rccoord coord;
206
207 coord=_gettextposition();
208 return((int)coord.row);
209 #elif CONSOLE_SET==CT_NATIVE
210 #if TARGET==DOS
211 union REGS r;
212
213 r.h.ah=3;
214 r.h.bh=0;
215 int86(0x10, &r, &r);
216 return((int)r.h.dh+1);
217 #elif TARGET==OS2
218 USHORT x, y;
219
220 VioGetCurPos(&y, &x, 0);
221 return(y+1);
222 #elif TARGET==WIN32
223 CONSOLE_SCREEN_BUFFER_INFO csbi;
224
225 GetConsoleScreenBufferInfo(hcons, &csbi);
226 return(csbi.dwCursorPosition.Y+1);
227 #endif
228 #endif
229 }
230 #endif
231
232 /* Returns the current text attribute */
233
234 #if SFX_LEVEL>=ARJSFX
getcurattr()235 unsigned char getcurattr()
236 {
237 #if CONSOLE_SET==CT_BORLAND
238 struct text_info r;
239
240 gettextinfo(&r);
241 return(r.attribute);
242 #elif CONSOLE_SET==CT_MSGRAPH
243 unsigned char textcolor;
244
245 textcolor=(unsigned char)_gettextcolor();
246 return(textcolor%16+((unsigned char)_getbkcolor()<<4)+((textcolor&16)?128:0));
247 #elif CONSOLE_SET==CT_NATIVE||CONSOLE_SET==CT_ANSI
248 return(curattr);
249 #endif
250 }
251 #endif
252
253 /* Clears the entire screen or window */
254
255 #if CONSOLE_SET!=CT_BORLAND&&CONSOLE_SET!=CT_MSGRAPH
clrscr()256 void clrscr()
257 {
258 #if CONSOLE_SET==CT_NATIVE
259 #if TARGET==DOS
260 unsigned int st_x, st_y;
261 union REGS r;
262
263 get_dimensions();
264 r.x.ax=0x600;
265 r.h.bh=(unsigned char)curattr;
266 r.x.cx=0;
267 r.h.dh=w_rows-1;
268 r.h.dl=w_columns-1;
269 int86(0x10, &r, &r);
270 gotoxy(1, 1);
271 #elif TARGET==OS2
272 static BYTE cell[]={' ', 0};
273 int i;
274
275 get_dimensions();
276 cell[1]=(BYTE)curattr;
277 for(i=0; i<w_rows; i++)
278 VioWrtNCell(cell, w_columns, i, 0, 0);
279 gotoxy(1, 1);
280 #elif TARGET==WIN32
281 int i;
282 DWORD dummy;
283 COORD xy;
284
285 get_dimensions();
286 xy.X=0;
287 for(i=0; i<w_rows; i++)
288 {
289 xy.Y=i;
290 FillConsoleOutputCharacter(hcons, 0x20, w_columns, xy, &dummy);
291 FillConsoleOutputAttribute(hcons, (WORD)curattr, w_columns, xy, &dummy);
292 };
293 gotoxy(1, 1);
294 #endif
295 #elif CONSOLE_SET==CT_ANSI
296 printf("\x1B[2J");
297 #endif
298 }
299 #endif
300
301 /* Clears all characters from current position to the end of line */
302
303 #if CONSOLE_SET!=CT_BORLAND
clreol()304 void clreol()
305 {
306 #if CONSOLE_SET==CT_MSGRAPH
307 struct videoconfig vc;
308 struct rccoord st_coord;
309 short x;
310 unsigned char c=' ';
311
312 _getvideoconfig(&vc);
313 st_coord=_gettextposition();
314 for(x=st_coord.col; x<=vc.numtextcols; x++)
315 {
316 _settextposition(st_coord.row, x);
317 _outmem((unsigned char FAR *)&c, 1);
318 }
319 _settextposition(st_coord.row, st_coord.col);
320 #elif CONSOLE_SET==CT_NATIVE
321 unsigned int x, st_x, y;
322 #if TARGET==DOS
323 union REGS r;
324 #elif TARGET==OS2
325 char c[2]={32, 0};
326 #endif
327
328 y=wherey();
329 get_dimensions();
330 for(x=st_x=wherex(); x<=w_columns; x++)
331 {
332 #if TARGET==DOS
333 gotoxy(x, y);
334 r.x.ax=0x920;
335 r.x.bx=curattr;
336 r.x.cx=1;
337 int86(0x10, &r, &r);
338 #elif TARGET==OS2
339 c[1]=curattr;
340 VioWrtCharStrAtt((PCH)&c, 1, y-1, x-1, &curattr, 0);
341 #elif TARGET==WIN32
342 DWORD dummy;
343 COORD xy;
344
345 get_dimensions();
346 xy.X=x-1;
347 xy.Y=y-1;
348 FillConsoleOutputCharacter(hcons, 0x20, w_columns-x, xy, &dummy);
349 FillConsoleOutputAttribute(hcons, (WORD)curattr, w_columns-x, xy, &dummy);
350 #endif
351 }
352 gotoxy(st_x, y);
353 #elif CONSOLE_SET==CT_ANSI
354 printf("\x1B[K");
355 #endif
356 }
357 #endif
358
359 /* Writes a single character to the console, with scrolling */
360
361 #if CONSOLE_SET!=CT_BORLAND
wputch(int c)362 void wputch(int c)
363 {
364 #if CONSOLE_SET==CT_MSGRAPH
365 char p[2];
366
367 p[0]=c;
368 p[1]='\0';
369 _outtext((char FAR *)p);
370 #elif CONSOLE_SET==CT_NATIVE
371 {
372 unsigned int row, column;
373 #if TARGET==DOS
374 union REGS r;
375 #elif TARGET==OS2
376 BYTE cell[2];
377 #elif TARGET==WIN32
378 CHAR_INFO ci;
379 COORD xy, xysp;
380 SMALL_RECT sr;
381 #endif
382
383 if(w_rows==0)
384 get_dimensions();
385 row=wherey();
386 column=wherex();
387 switch(c)
388 {
389 case BEL:
390 fputc(BEL, stdout); /* Not as correct but is expected to do
391 its job - the output goes to screen,
392 the sounds flow to stdout */
393 break;
394 case 8:
395 if(column>1)
396 column--;
397 break;
398 case 9:
399 do
400 {
401 wputch(' ');
402 } while((wherex()-1)%8);
403 return;
404 case 10:
405 row++;
406 column=1;
407 break;
408 case 13:
409 column=1;
410 break;
411 default:
412 #if TARGET==DOS
413 r.h.ah=9;
414 r.h.al=(unsigned char)c;
415 r.x.bx=curattr;
416 r.x.cx=1;
417 int86(0x10, &r, &r);
418 #elif TARGET==OS2
419 VioWrtCharStrAtt((PCH)&c, 1, row-1, column-1, &curattr, 0);
420 #elif TARGET==WIN32
421 ci.Char.UnicodeChar=0;
422 ci.Char.AsciiChar=(CHAR)c;
423 ci.Attributes=curattr;
424 xy.X=xy.Y=1;
425 xysp.X=0;
426 xysp.Y=0;
427 sr.Left=sr.Right=column-1;
428 sr.Top=sr.Bottom=row-1;
429 WriteConsoleOutput(hcons, &ci, xy, xysp, &sr);
430 #endif
431 column++;
432 }
433 if(column>w_columns)
434 {
435 column=1;
436 row++;
437 }
438 while(row>w_rows)
439 {
440 #if TARGET==DOS
441 r.x.ax=0x601;
442 r.h.bh=(unsigned char)curattr;
443 r.x.cx=0x100;
444 r.h.dh=w_rows-1;
445 r.h.dl=w_columns-1;
446 int86(0x10, &r, &r);
447 #elif TARGET==OS2
448 cell[0]=' ';
449 cell[1]=curattr;
450 VioScrollUp(0, 0, w_rows-1, w_columns-1, 1, cell, 0);
451 #elif TARGET==WIN32
452 sr.Top=1;
453 sr.Left=0;
454 sr.Right=w_columns-1;
455 sr.Bottom=w_rows-1;
456 xy.X=0;
457 xy.Y=0;
458 ci.Char.UnicodeChar=0x20;
459 ci.Attributes=curattr;
460 ScrollConsoleScreenBuffer(hcons, &sr, NULL, xy, &ci);
461 #else
462 #error BUG: wputch() routine not implemented
463 #endif
464 row--;
465 }
466 gotoxy(column, row);
467 }
468 #elif CONSOLE_SET==CT_ANSI
469 putchar(c);
470 #endif
471 }
472 #endif
473
474 /* High-level functions, dropped for ANSI */
475
476 #if CONSOLE_SET!=CT_ANSI
477
478 /* Borland calls this cprintf(). We call this scrprintf(). */
479
480 #if CONSOLE_SET!=CT_BORLAND&&defined(ARJDISP)
scrprintf(char * fmt,...)481 void scrprintf(char *fmt, ...)
482 {
483 char text[1024];
484 va_list marker;
485
486 va_start(marker, fmt);
487 vsprintf(text, fmt, marker);
488 va_end(marker);
489 scr_out(text);
490 }
491 #endif
492
493 #endif /* !CT_ANSI */
494
495
496 /* A general routine for outputting unformatted text onto screen */
497
498 #if defined(ARJDISP)||defined(COLOR_OUTPUT)
scr_out(char * str)499 void scr_out(char *str)
500 {
501 #if CONSOLE_SET==CT_BORLAND
502 #ifdef ARJDISP
503 char strform[]="%s";
504 #endif
505
506 kbhit();
507 cprintf(strform, str);
508 #elif CONSOLE_SET==CT_MSGRAPH
509 /* Needs a special hack. Microsoft allows the backspace character to be
510 passed. */
511 char t[128];
512 int i=0;
513 int xpos;
514
515 while(str[0]!='\0')
516 {
517 kbhit(); /* To check for Ctrl+C */
518 while(str[i]!='\0'&&(i<sizeof(t)-1))
519 {
520 if(str[i]==8)
521 {
522 if(i>0)
523 {
524 t[i]='\0';
525 str+=i;
526 i=0;
527 _outtext((char FAR *)t);
528 }
529 str++;
530 xpos=wherex()-1;
531 _settextposition(wherey(), max(xpos, 1));
532 }
533 else
534 {
535 t[i]=str[i];
536 i++;
537 }
538 }
539 t[i]='\0';
540 _outtext((char FAR *)t);
541 str+=i;
542 i=0;
543 }
544 if(i>0)
545 {
546 t[i]='\0';
547 _outtext((char FAR *)t);
548 }
549 #elif CONSOLE_SET==CT_NATIVE||CONSOLE_SET==CT_ANSI
550 char *t_ptr;
551
552 #if TARGET==DOS
553 kbhit(); /* To check for Ctrl+C */
554 #endif
555 for(t_ptr=str; *t_ptr!='\0'; t_ptr++)
556 wputch((int)*t_ptr);
557 #else
558 #error scr_out() not implemented
559 #endif
560 }
561 #endif
562
563 /* For ANSI, we have to reset the terminal. Do it here (on other console
564 types, it's a null macro) */
565
566 #if CONSOLE_SET==CT_ANSI
scrn_reset()567 void scrn_reset()
568 {
569 printf("\x1B[0m\n");
570 }
571 #endif
572
573 /* Helper routine for ARJ to know the screen height */
574
query_screen_height()575 int query_screen_height()
576 {
577 #ifdef KNOW_DIMENSIONS
578 get_dimensions();
579 return(w_rows);
580 #else
581 return(25);
582 #endif
583 }
584
585 /* Prepares for wrapping around the right margin if the given length exceeds
586 it */
587
check_wrap(int i)588 void check_wrap(int i)
589 {
590 #if SFX_LEVEL>=ARJ&&defined(KNOW_DIMENSIONS)&&(defined(ARJDISP)||defined(COLOR_OUTPUT))
591 if(wherex()+i>w_columns)
592 scr_out(lf);
593 #endif
594 }
595