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