1 //  This may look like C code, but it is really -*- C++ -*-
2 
3 //  ------------------------------------------------------------------
4 //  The Goldware Library
5 //  Copyright (C) 1990-1999 Odinn Sorensen
6 //  Copyright (C) 1999-2000 Alexander S. Aganichev
7 //  Copyright (C) 2000 Jacobo Tarrio
8 //  ------------------------------------------------------------------
9 //  This library is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU Library General Public
11 //  License as published by the Free Software Foundation; either
12 //  version 2 of the License, or (at your option) any later version.
13 //
14 //  This library is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 //  Library General Public License for more details.
18 //
19 //  You should have received a copy of the GNU Library General Public
20 //  License along with this program; if not, write to the Free
21 //  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 //  MA 02111-1307, USA
23 //  ------------------------------------------------------------------
24 //  $Id: gvidbase.cpp,v 1.1 2011/02/18 19:46:02 stas_degteff Exp $
25 //  ------------------------------------------------------------------
26 //  GCUI: Golded+ Character-oriented User Interface.
27 //  Device-independent video functions.
28 //  ------------------------------------------------------------------
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstdarg>
33 #include <gmemall.h>
34 #include <gmemdbg.h>
35 #include <gstrall.h>
36 #include <gvidall.h>
37 
38 #if defined(__OS2__)
39 #define INCL_BASE
40 #include <os2.h>
41 #ifndef __EMX__
42 #define PCCH CHAR*
43 #endif
44 #endif
45 
46 #ifdef __WIN32__
47 #include <windows.h>
48 #endif
49 
50 #ifdef __GNUC__
51 #include <unistd.h>
52 #endif
53 
54 #if defined(__DJGPP__)
55 #include <sys/farptr.h>
56 #endif
57 
58 
59 //  ------------------------------------------------------------------
60 //  Check if Borland C++ for OS/2 1.0 header has been fixed
61 
62 #if defined(__OS2__) && defined(__BORLANDC__)
63   #if __BORLANDC__ <= 0x400
64     #ifndef BCOS2_BSESUB_FIXED
65     #error There is a bug in the BSESUB.H header. Please fix it.
66     //
67     // Add/change the following in BSESUB.H:
68     //
69     // #define BCOS2_BSESUB_FIXED
70     // APIRET16  APIENTRY16    VioGetState (PVOID16 pState, HVIO hvio);
71     // APIRET16  APIENTRY16    VioSetState (PVOID16 pState, HVIO hvio);
72     //
73     // Borland forgot this (was only PVOID)      ^^
74     //
75     #endif
76   #endif
77 #endif
78 
79 
80 //  ------------------------------------------------------------------
81 
82 static bool __vcurhidden = false;
83 #if defined(__UNIX__) || defined(__USE_NCURSES__)
84 static uint32_t gvid_boxcvtc(char);
85 #endif
86 
87 #if !defined(__USE_NCURSES__)
88 
89 //  ------------------------------------------------------------------
90 
91 #ifdef __WIN32__
92 extern HANDLE gvid_hout;
93 extern OSVERSIONINFO WinVer; // defined in gutlwin.cpp
94 extern WCHAR oem2unicode[]; // defined in gutlwin.cpp
95 
96 //  ------------------------------------------------------------------
97 //  Transform character < 32 into printable Unicode equivalent
98 
99 
gvid_tcpr(vchar chr)100 inline WCHAR gvid_tcpr(vchar chr) {
101 
102   return oem2unicode[chr & 0xff];
103 }
104 
105 #endif
106 
107 
108 //  ------------------------------------------------------------------
109 
110 #if defined(__MSDOS__) || defined(__UNIX__)
111 
112 #if defined(__MSDOS__)
113 extern int __gdvdetected;
114 #endif
115 
116 #ifndef __DJGPP__
117 const uint16_t _dos_ds = 0;
118 
_my_ds(void)119 inline uint16_t _my_ds(void) {
120 
121   return 0;
122 }
123 
_farpokew(uint16_t s,gdma ptr,word chat)124 inline void _farpokew(uint16_t s, gdma ptr, word chat) {
125 
126   NW(s);
127   *ptr = chat;
128 }
129 
_farnspokew(gdma ptr,word chat)130 inline void _farnspokew(gdma ptr, word chat) {
131 
132   *ptr = chat;
133 }
134 
_farpeekw(uint16_t s,gdma ptr)135 inline word _farpeekw(uint16_t s, gdma ptr) {
136 
137   NW(s);
138   return *ptr;
139 }
140 
_farnspokeb(byte * ptr,byte chr)141 inline void _farnspokeb(byte *ptr, byte chr) {
142 
143   *ptr = chr;
144 }
145 
_farsetsel(uint16_t s)146 inline void _farsetsel(uint16_t s) {
147 
148   NW(s);
149 }
150 #endif
151 
152 #ifdef __DJGPP__
153 const int ATTRSIZE = sizeof(word);
154 #else
155 const int ATTRSIZE = 1;
156 #endif
157 
gdmacpy(uint16_t seg_d,gdma sel_d,uint16_t seg_s,gdma sel_s,int len)158 inline void gdmacpy(uint16_t seg_d, gdma sel_d, uint16_t seg_s, gdma sel_s, int len) {
159 
160   #ifdef __DJGPP__
161   movedata(seg_s, sel_s, seg_d, sel_d, len);
162   #else
163   NW(seg_d);
164   NW(seg_s);
165   memcpy(sel_d, sel_s, len);
166   #endif
167 }
168 
gdmaptr(int col,int row)169 inline gdma gdmaptr(int col, int row) {
170 
171   return gvid->dmaptr+ATTRSIZE*((row*gvid->numcols)+col);
172 }
173 #endif
174 
175 
176 //  ------------------------------------------------------------------
177 
178 #if defined(__UNIX__)
179 
180 
181 //  ------------------------------------------------------------------
182 
183 extern int gvid_stdout;
184 extern const char* gvid_acs_enable;
185 extern const char* gvid_acs_disable;
186 int gvid_last_attr = 0;
187 
188 
189 //  ------------------------------------------------------------------
190 
gvid_printf(const char * fmt,...)191 void gvid_printf(const char* fmt, ...) {
192 
193   char buf[1024];
194   va_list argptr;
195   va_start(argptr, fmt);
196   int n = vsprintf(buf, fmt, argptr);
197   va_end(argptr);
198 
199   write(gvid_stdout, buf, n);
200 }
201 
202 
203 //  ------------------------------------------------------------------
204 //  Control chars      01234567890123456789012345678901
205 
206 const char* gvid_x0 = "x@xxxxxxxxxxxxxx><xxxxxx^vxxxx^v";
207 
208 
209 //  ------------------------------------------------------------------
210 
gvid_cvtchr(char & ch)211 inline void gvid_cvtchr(char& ch) {
212 
213   register const char* x0 = gvid_x0;
214 
215   if(ch < ' ')
216     ch = x0[ch];
217 }
218 
219 
220 //  ------------------------------------------------------------------
221 
gvid_cvtstr(char * s,int len)222 void gvid_cvtstr(char* s, int len) {
223 
224   register char* p = s;
225 
226   for(int n=0; n<len; n++,p++)
227     gvid_cvtchr(*p);
228 }
229 
230 
231 //  ------------------------------------------------------------------
232 
gvid_cvtstr(word * ws,int len)233 void gvid_cvtstr(word* ws, int len) {
234 
235   register word* wp = ws;
236 
237   for(int n=0; n<len; n++,wp++)
238     gvid_cvtchr(*(char*)wp);
239 }
240 
241 
242 //  ------------------------------------------------------------------
243 
244 static int _atr_to_ans[8] = {
245   0,  // BLACK    0
246   4,  // BLUE     1
247   2,  // GREEN    2
248   6,  // CYAN     3
249   1,  // RED      4
250   5,  // MAGENTA  5
251   3,  // BROWN    6
252   7   // WHITE    7
253 };
254 
255 
256 //  ------------------------------------------------------------------
257 
vatr2ansin(int x)258 inline int vatr2ansin(int x) {
259 
260   return (x & 8) ? 1 : 0;
261 }
262 
263 
264 //  ------------------------------------------------------------------
265 
vatr2ansfg(int x)266 inline int vatr2ansfg(int x) {
267 
268   return _atr_to_ans[x & 7];
269 }
270 
271 
272 //  ------------------------------------------------------------------
273 
vatr2ansbg(int x)274 inline int vatr2ansbg(int x) {
275 
276   return _atr_to_ans[(x>>4) & 7];
277 }
278 
279 
280 //  ------------------------------------------------------------------
281 
vputansi(int row,int col,word * buf,int len)282 void vputansi(int row, int col, word* buf, int len) {
283 
284   char ch;
285   int in, fg, bg, acs;
286   int atr = gvid_last_attr;
287   int in0 = vatr2ansin(atr);
288   int fg0 = vatr2ansfg(atr);
289   int bg0 = vatr2ansbg(atr);
290   int acs0 = atr & ACSET;
291 
292   // Get pointer to ANSI line buffer
293   char* ptr = gvid->bufansi;
294 
295   // Get pointer to video memory image
296   byte* p = (byte*)buf;
297 
298   for(int n=0; n<len; n++,p+=2) {    // For each screen element
299 
300     if(p[1] != atr) {                 // If attribute is different
301 
302       atr = p[1];                     // Store new attribute
303       gvid_last_attr = atr;
304 
305       in = vatr2ansin(atr);           // Get intensity
306       fg = vatr2ansfg(atr);           // Get foreground color
307       bg = vatr2ansbg(atr);           // Get background color
308       acs = atr & ACSET;              // Get Alt Color Set
309 
310       if(acs != acs0) {
311         ptr = stpcpy(ptr, acs ? gvid_acs_enable : gvid_acs_disable);
312         acs0 = acs;
313       }
314 
315       *ptr++ = 0x1B;                  // Start ANSI color sequence
316       *ptr++ = '[';
317 
318       if(in != in0) {                 // Set intensity if different
319         if(in)
320           *ptr++ = '1';               // Intense
321         else {
322           *ptr++ = '0';               // Reset
323           fg0 = bg0 = -1;
324         }
325         in0 = in;
326         if((fg != fg0) or (bg != bg0))
327           *ptr++ = ';';
328       }
329 
330       if(fg != fg0) {                 // Set foreground if different
331         *ptr++ = '3';
332         *ptr++ = (char)('0' + fg);
333         fg0 = fg;
334         if(bg != bg0)
335           *ptr++ = ';';
336       }
337 
338       if(bg != bg0) {                 // Set background if different
339         *ptr++ = '4';
340         *ptr++ = (char)('0' + bg);
341         bg0 = bg;
342       }
343 
344       *ptr++ = 'm';                   // End ANSI color sequence
345     }
346 
347     ch = p[0];
348     gvid_cvtchr(ch);
349     *ptr++ = ch;                    // Output the character
350   }
351 
352   *ptr = NUL;                         // Terminate string
353 
354   // Print complete ANSI string at the specified position
355   gvid_printf("\x1B[%u;%uH%s", row+1, col+1, gvid->bufansi);
356 }
357 
358 
359 //  ------------------------------------------------------------------
360 
361 #endif
362 
363 #endif // !defined(__USE_NCURSES__)
364 
365 
366 //  ------------------------------------------------------------------
367 //  Converts an attribute to monochrome equivalent
368 
mapattr(vattr attr)369 vattr mapattr(vattr attr)
370 {
371   switch(attr&112) {      // test for a light background
372 
373     case _LGREY:
374     case _GREEN:
375     case _CYAN:
376     case _BROWN:
377       attr &= 240;        // foreground = black
378       attr |= 112;        // background = light grey
379       break;
380 
381     default:
382       if((attr&15)==8)    // if foreground = dark grey
383         attr &= 247;      // clear intensity bit
384       attr |= 7;          // foreground = light grey
385       attr &= 143;        // background = black
386   }
387 
388   return attr;              // return converted attribute
389 }
390 
391 
392 //  ------------------------------------------------------------------
393 //  Reverses the attribute given
394 
revsattr(vattr attr)395 vattr revsattr(vattr attr)
396 {
397   return (vattr)(((attr>>4)&0x07)|((attr<<4)&0x70)|(attr&0x80)|(attr&0x08));
398 }
399 
400 #if !defined(__USE_NCURSES__)
401 
402 
403 //  ------------------------------------------------------------------
404 
405 #if defined(__UNIX__)
gvid_newattr(int & attr)406 char* gvid_newattr(int& attr) {
407 
408   // 12345678901234567890
409   // E[1;33;44mE[11m
410   static char newattr[20];
411   *newattr = NUL;
412   if(attr != gvid_last_attr) {
413     if((attr & ~ACSET) != (gvid_last_attr & ~ACSET)) {
414       sprintf(newattr, "\033[%c;3%u;4%um",
415         vatr2ansin(attr) ? '1' : '0',
416         vatr2ansfg(attr),
417         vatr2ansbg(attr)
418       );
419     }
420     if((attr & ACSET) != (gvid_last_attr & ACSET))
421       strcat(newattr, (attr & ACSET) ? gvid_acs_enable : gvid_acs_disable);
422     gvid_last_attr = attr;
423   }
424 
425   return newattr;
426 }
427 #endif
428 
429 
430 //  ------------------------------------------------------------------
431 //  OS/2 Vio* wrappers for prevent 16-bit segment overrun
432 
433 #if defined(__OS2__)
434 
435 #ifndef _THUNK_PTR_SIZE_OK
436 #define _THUNK_PTR_SIZE_OK(ptr,size) (((ULONG)(ptr) & ~0xffff) == (((ULONG)(ptr) + (size) - 1) & ~0xffff))
437 #endif
438 
VioReadCellStr_(PCH str,PUSHORT pcb,USHORT row,USHORT col,HVIO hvio)439 static USHORT VioReadCellStr_(PCH str, PUSHORT pcb, USHORT row, USHORT col, HVIO hvio) {
440   USHORT rc, cb = *pcb;
441 
442   if(_THUNK_PTR_SIZE_OK(str, cb))
443     return VioReadCellStr(str, pcb, row, col, hvio);
444   PCH newstr = (PCH)throw_xmalloc(cb * 2);
445   if(_THUNK_PTR_SIZE_OK(newstr, cb)) {
446     rc = VioReadCellStr(newstr, pcb, row, col, hvio);
447     if(rc == 0)
448       memcpy(str, newstr, *pcb);
449   }
450   else {
451     rc = VioReadCellStr(newstr + cb, pcb, row, col, hvio);
452     if(rc == 0)
453       memcpy(str, newstr + cb, *pcb);
454   }
455   throw_xfree(newstr);
456   return rc;
457 }
458 
459 
VioWrtCellStr_(PCCH str,USHORT cb,USHORT row,USHORT col,HVIO hvio)460 static USHORT VioWrtCellStr_(PCCH str, USHORT cb, USHORT row, USHORT col, HVIO hvio) {
461   USHORT rc;
462 
463   if(_THUNK_PTR_SIZE_OK(str, cb ))
464     return VioWrtCellStr(str, cb, row, col, hvio);
465   PCH newstr = (PCH)throw_xmalloc(cb * 2);
466   if(_THUNK_PTR_SIZE_OK(newstr, cb)) {
467     memcpy(newstr, str, cb);
468     rc = VioWrtCellStr(newstr, cb, row, col, hvio);
469   }
470   else {
471     memcpy(newstr + cb, str, cb);
472     rc = VioWrtCellStr(newstr + cb, cb, row, col, hvio);
473   }
474   throw_xfree(newstr);
475   return rc;
476 }
477 
478 
VioWrtCharStrAtt_(PCCH str,USHORT cb,USHORT row,USHORT col,PBYTE attr,HVIO hvio)479 static USHORT VioWrtCharStrAtt_(PCCH str, USHORT cb, USHORT row, USHORT col, PBYTE attr, HVIO hvio) {
480   USHORT rc;
481 
482   if(_THUNK_PTR_SIZE_OK(str, cb))
483     return VioWrtCharStrAtt(str, cb, row, col, attr, hvio);
484   PCH newstr = (PCH)throw_xmalloc(cb * 2);
485   if(_THUNK_PTR_SIZE_OK(newstr, cb)) {
486     memcpy(newstr, str, cb);
487     rc = VioWrtCharStrAtt(newstr, cb, row, col, attr, hvio);
488   }
489   else {
490     memcpy(newstr + cb, str, cb);
491     rc = VioWrtCharStrAtt(newstr + cb, cb, row, col, attr, hvio);
492   }
493   throw_xfree(newstr);
494   return rc;
495 }
496 
497 #define VioReadCellStr         VioReadCellStr_
498 #define VioWrtCellStr          VioWrtCellStr_
499 #define VioWrtCharStrAtt       VioWrtCharStrAtt_
500 
501 #endif
502 
503 //  ------------------------------------------------------------------
504 //  ncurses support functions
505 
506 #else // defined(__USE_NCURSES__)
507 
508 //  ------------------------------------------------------------------
509 //  Compute our attributes from DOS attributes
510 
gvid_attrcalc(int dosattr)511 int gvid_attrcalc(int dosattr) {
512 
513   // DOS attrs: XRGBxrgb
514   // color pair definition: 00RGBrgb, with last 3 bits negated
515   int attr;
516   attr = COLOR_PAIR(((dosattr & 0x70) >> 1) | ((~dosattr) & 0x07));
517   if(dosattr & 0x08)
518     attr |= A_BOLD;
519 //  if(dosattr & 0x80)
520 //    attr |= A_BLINK;
521 
522   return attr;
523 }
524 
525 //  ------------------------------------------------------------------
526 //  Compute DOS attributes from our attributes
527 
gvid_dosattrcalc(int ourattr)528 int gvid_dosattrcalc(int ourattr) {
529 
530   int attr = 0;
531   attr = PAIR_NUMBER(ourattr);
532   attr = ((attr & 0x38) << 1) | ((~attr) & 0x07);
533   if(ourattr & A_BLINK)
534     attr |= 0x80;
535   if(ourattr & A_BOLD)
536     attr |= 0x08;
537 
538   return attr;
539 }
540 
541 //  ------------------------------------------------------------------
542 //  Transform character < 32 into printable equivalent
543 
544 
gvid_tcpr(vchar chr)545 chtype gvid_tcpr(vchar chr) {
546 
547   const chtype gvid_cpr[] = {
548     (chtype)' ', (chtype)'@', (chtype)'@', (chtype)'x',
549     (chtype) ACS_DIAMOND, (chtype)'x', (chtype)'x', ACS_BULLET,
550     ACS_BULLET, ACS_BULLET, ACS_BULLET, (chtype)'x',
551     (chtype)'x', (chtype)'x', (chtype)'x', ACS_LANTERN,
552     (chtype)ACS_RARROW, ACS_LARROW, (chtype)'x', (chtype)'!',
553     (chtype)'x', (chtype)'x', ACS_S1, (chtype)'x',
554     ACS_UARROW, ACS_DARROW, ACS_LARROW, (chtype)ACS_RARROW,
555     (chtype)'x', (chtype)'x', ACS_UARROW, ACS_DARROW
556   };
557 
558   chtype ch = chr & A_CHARTEXT;
559   chtype at = chr & (~A_CHARTEXT);
560 
561   if(ch<' ')
562     return gvid_cpr[ch] | at;
563   else
564     return ch | at;
565 }
566 
567 
568 //  ------------------------------------------------------------------
569 
570 #endif // defined(__USE_NCURSES__)
571 
572 
573 //  ------------------------------------------------------------------
574 //  Print character and attribute at specfied location
575 
576 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vputw(int row,int col,word chat)577 inline void _vputw(int row, int col, word chat) {
578 
579   _farpokew(_dos_ds, gdmaptr(col, row), chat);
580 }
581 #endif
582 
583 
vputw(int row,int col,vatch chat)584 void vputw(int row, int col, vatch chat) {
585 
586   #if defined(__USE_NCURSES__)
587 
588   mvaddch(row, col, chat);
589   refresh();
590 
591   #elif defined(__MSDOS__)
592 
593   if(gvid->isdma()) {
594     _vputw(row, col, chat);
595   }
596   else if(gvid->isbios() or gvid->iscga()) {
597     i86 cpu;
598     cpu.ah(2);
599     cpu.bh(0);
600     cpu.dh((byte)row);
601     cpu.dl((byte)col);
602     cpu.genint(0x10);
603     cpu.ah(9);
604     cpu.al(vgchar(chat));
605     cpu.bh(0);
606     cpu.bl(vgattr(chat));
607     cpu.cx(1);
608     cpu.genint(0x10);
609   }
610 
611   #elif defined(__OS2__)
612 
613   VioWrtNCell((BYTE *)&chat, 1, (USHORT)row, (USHORT)col, 0);
614 
615   #elif defined(__WIN32__)
616 
617   const COORD coord = {0, 0};
618   const COORD size = {1, 1};
619   SMALL_RECT rect;
620 
621   rect.Top = row;
622   rect.Left = col;
623   rect.Bottom = row+size.Y-1;
624   rect.Right = col+size.X-1;
625   if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) {
626     chat.Char.UnicodeChar = gvid_tcpr(vgchar(chat));
627     WriteConsoleOutputW(gvid_hout, &chat, size, coord, &rect);
628   }
629   else
630     WriteConsoleOutputA(gvid_hout, &chat, size, coord, &rect);
631 
632   #elif defined(__UNIX__)
633 
634   char chr = vgchar(chat);
635   int atr = vgattr(chat);
636   char* color = gvid_newattr(atr);
637 
638   gvid_cvtstr(&chat, 1);
639   _vputw(row, col, chat);
640 
641   gvid_printf("\033[%u;%uH%s%c", row+1, col+1, color, chr);
642 
643   #endif
644 }
645 
646 
647 //  ------------------------------------------------------------------
648 //  Print attrib/char buffer at specfied location
649 
vputws(int row,int col,vatch * buf,uint len)650 void vputws(int row, int col, vatch* buf, uint len) {
651 
652   #if defined(__USE_NCURSES__)
653 
654   move(row, col);
655   for(int counter = 0; counter < len; counter++)
656     addch(buf[counter]);
657   refresh();
658 
659   #elif defined(__MSDOS__)
660 
661   if(gvid->isdma()) {
662     gdmacpy(_dos_ds, (gdma)gdmaptr(col, row), _my_ds(), (gdma)buf, len*sizeof(word));
663   }
664   else if(gvid->isbios() or gvid->iscga()) {
665     i86 cpu;
666     byte* p = (byte*)buf;
667     for(uint n=0; n<len; n++) {
668       cpu.ah(2);
669       cpu.bh(0);
670       cpu.dh((byte)row);
671       cpu.dl((byte)col++);
672       cpu.genint(0x10);
673       cpu.ah(9);
674       cpu.al(*p++);
675       cpu.bh(0);
676       cpu.bl(*p++);
677       cpu.cx(1);
678       cpu.genint(0x10);
679     }
680   }
681 
682   #elif defined(__OS2__)
683 
684   VioWrtCellStr((PCCH)buf, (USHORT)(len*2), (USHORT)row, (USHORT)col, 0);
685 
686   #elif defined(__WIN32__)
687 
688   const COORD coord = {0, 0};
689   COORD size = {len, 1};
690   SMALL_RECT rect;
691 
692   rect.Top = row;
693   rect.Left = col;
694   rect.Bottom = row+size.Y-1;
695   rect.Right = col+size.X-1;
696   if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT) {
697     for(int i = 0; i < len; i++) {
698       buf[i].Char.UnicodeChar = gvid_tcpr(vgchar(buf[i]));
699     }
700     WriteConsoleOutputW(gvid_hout, buf, size, coord, &rect);
701   }
702   else
703     WriteConsoleOutputA(gvid_hout, buf, size, coord, &rect);
704 
705   #elif defined(__UNIX__)
706 
707   gvid_cvtstr(buf, len);
708   gdmacpy(_dos_ds, (gdma)gdmaptr(col, row), _my_ds(), (gdma)buf, len*sizeof(word));
709   vputansi(row, col, buf, len);
710 
711   #endif
712 }
713 
714 
715 //  ------------------------------------------------------------------
716 //  Print character and attribute at specfied location
717 
vputc(int row,int col,vattr atr,vchar chr)718 void vputc(int row, int col, vattr atr, vchar chr) {
719 
720   #if defined(__USE_NCURSES__)
721 
722   mvaddch(row, col, vcatch(gvid_tcpr(chr), atr));
723   refresh();
724 
725   #elif defined(__MSDOS__)
726 
727   if(gvid->isdma()) {
728     _vputw(row, col, vcatch(chr, atr));
729   }
730   else if(gvid->isbios() or gvid->iscga()) {
731     i86 cpu;
732     cpu.ah(2);
733     cpu.bh(0);
734     cpu.dh((byte)row);
735     cpu.dl((byte)col);
736     cpu.genint(0x10);
737     cpu.ah(9);
738     cpu.al(chr);
739     cpu.bh(0);
740     cpu.bl((byte)atr);
741     cpu.cx(1);
742     cpu.genint(0x10);
743   }
744 
745   #elif defined(__OS2__) || defined(__WIN32__)
746 
747   vputw(row, col, vcatch(chr, atr));
748 
749   #elif defined(__UNIX__)
750 
751   char* color = gvid_newattr(atr);
752   gvid_cvtstr(&chr, 1);
753   _vputw(row, col, vcatch(chr, atr));
754 
755   gvid_printf("\033[%u;%uH%s%c", row+1, col+1, color, chr);
756 
757   #endif
758 }
759 
760 
761 //  ------------------------------------------------------------------
762 //  Print string with attribute at specfied location
763 
vputvs(int row,int col,vattr atr,const vchar * str)764 void vputvs(int row, int col, vattr atr, const vchar* str) {
765 
766   #if defined(__USE_NCURSES__)
767 
768   uint counter;
769   int attr = gvid_attrcalc(atr);
770   move(row, col);
771   for(counter = 0; str[counter] != 0; counter++)
772     addch(gvid_tcpr(str[counter]) | attr);
773   refresh();
774 
775   #else
776 
777   vputs(row, col, atr, str);
778 
779   #endif
780 }
781 
782 
783 //  ------------------------------------------------------------------
784 //  Print string with attribute at specfied location
785 
vputs_box(int row,int col,vattr atr,const char * str)786 void vputs_box(int row, int col, vattr atr, const char* str) {
787 #if defined(__USE_NCURSES__)
788   uint counter;
789   int len = strlen(str);
790   int attr = gvid_attrcalc(atr);
791   move(row, col);
792   for(counter = 0; counter < len; counter++)
793     addch(gvid_tcpr(gvid_boxcvtc(str[counter])) | attr);
794   refresh();
795 #else
796   vputs(row, col, atr, str);
797 #endif
798 }
799 
vputs(int row,int col,vattr atr,const char * str)800 void vputs(int row, int col, vattr atr, const char* str) {
801 
802   #if defined(__USE_NCURSES__)
803 
804   uint counter;
805   int len = strlen(str);
806   int attr = gvid_attrcalc(atr);
807   move(row, col);
808   for(counter = 0; counter < len; counter++)
809     addch(gvid_tcpr(str[counter]) | attr);
810   refresh();
811 
812   #elif defined(__MSDOS__)
813 
814   if(gvid->isdma()) {
815     gdma p = gdmaptr(col, row);
816     _farsetsel(_dos_ds);
817     while(*str) {
818       _farnspokew(p, vcatch(*str++, atr));
819       p += ATTRSIZE;
820     }
821   }
822   else if(gvid->isbios() or gvid->iscga()) {
823     i86 cpu;
824     for(const char* q=str; *q; q++) {
825       // Write as fast as possible on XT bios...
826       cpu.ah(2);
827       cpu.bh(0);
828       cpu.dh((byte)row);
829       cpu.dl((byte)(col++));
830       cpu.genint(0x10);
831       cpu.ah(9);
832       cpu.al(*q);
833       cpu.bh(0);
834       cpu.bl((byte)atr);
835       cpu.cx(1);
836       cpu.genint(0x10);
837     }
838   }
839 
840   #elif defined(__OS2__)
841 
842   VioWrtCharStrAtt((PCCH)str, (USHORT)strlen(str), (USHORT)row, (USHORT)col, (PBYTE)&atr, 0);
843 
844   #elif defined(__WIN32__)
845 
846   int i;
847 
848   for(i = 0; *str && (i < gvid->numcols); i++)
849     gvid->bufwrd[i] = vcatch(*str++, atr);
850   if(i)
851     vputws(row, col, gvid->bufwrd, i);
852 
853   #elif defined(__UNIX__)
854 
855   char buf[1024];
856   strcpy(buf, str);
857   char* color = gvid_newattr(atr);
858   gvid_cvtstr(buf, strlen(buf));
859   gdma p = gdmaptr(col, row);
860   _farsetsel(_dos_ds);
861   while(*str) {
862     _farnspokew(p, vcatch(*str++, atr));
863     p += ATTRSIZE;
864   }
865 
866   gvid_printf("\033[%u;%uH%s%s", row+1, col+1, color, buf);
867 
868   #endif
869 }
870 
871 
872 //  ------------------------------------------------------------------
873 //  Print string with attribute at specfied location
874 
875 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vputns(int row,int col,int atr,const char * str,uint width)876 static void _vputns(int row, int col, int atr, const char* str, uint width) {
877 
878   char fillchar = ' ';
879 
880   gdma p = gdmaptr(col, row);
881   _farsetsel(_dos_ds);
882   while(width--) {
883     _farnspokew(p, (atr << 8) | (*str ? *str++ : fillchar));
884     p += ATTRSIZE;
885   }
886 }
887 #endif
888 
889 
890 //  ------------------------------------------------------------------
891 //  Print string with attribute at specfied location
892 
vputns(int row,int col,vattr atr,const char * str,uint width)893 void vputns(int row, int col, vattr atr, const char* str, uint width) {
894 
895   char fillchar = ' ';
896 
897   #if defined(__USE_NCURSES__)
898 
899   uint counter;
900   int len = strlen(str);
901   int attr = gvid_attrcalc(atr);
902   move(row, col);
903   for(counter = 0; counter < width; counter++) {
904     if(counter<len)
905       addch(gvid_tcpr(str[counter]) | attr);
906     else
907       addch(gvid_tcpr(fillchar) | attr);
908   }
909   refresh();
910 
911   #elif defined(__MSDOS__)
912 
913   if(gvid->isdma()) {
914     _vputns(row, col, atr, str, width);
915   }
916   else if(gvid->isbios() or gvid->iscga()) {
917     i86 cpu;
918     while(width--) {
919       // Write as fast as possible on XT bios...
920       cpu.ah(2);
921       cpu.bh(0);
922       cpu.dh((byte)row);
923       cpu.dl((byte)(col++));
924       cpu.genint(0x10);
925       cpu.ah(9);
926       cpu.al(*str ? *str++ : fillchar);
927       cpu.bh(0);
928       cpu.bl((byte)atr);
929       cpu.cx(1);
930       cpu.genint(0x10);
931     }
932   }
933 
934   #elif defined(__OS2__)
935 
936   uint len = strlen(str);
937 
938   VioWrtCharStrAtt((PCCH)str, (USHORT)minimum_of_two(len,width), (USHORT)row, (USHORT)col, (PBYTE)&atr, 0);
939 
940   if(width > len) {
941     vatch filler = vcatch(fillchar, atr);
942     VioWrtNCell((BYTE *)&filler, (USHORT)(width-len), (USHORT)row, (USHORT)(col+len), 0);
943   }
944 
945   #elif defined(__WIN32__)
946 
947   int i;
948 
949   if (width > gvid->numcols)
950     width = gvid->numcols;
951 
952   for(i = 0; (i < width) and *str; i++)
953     gvid->bufwrd[i] = vcatch(*str++, atr);
954   vatch filler = vcatch(fillchar, atr);
955   for(; i < width; i++)
956     gvid->bufwrd[i] = filler;
957   vputws(row, col, gvid->bufwrd, width);
958 
959   #elif defined(__UNIX__)
960 
961   char* color = gvid_newattr(atr);
962 
963   uint len = strlen(str);
964   uint min_len = minimum_of_two(len, width);
965   char buf[1024];
966   strcpy(buf, str);
967   gvid_cvtstr(buf, len);
968 
969   _vputns(row, col, atr, buf, width);
970 
971   char fillbuf[256];
972   if(width > len) {
973     memset(fillbuf, fillchar, width-len);
974     fillbuf[width-len] = NUL;
975   }
976   else {
977     *fillbuf = NUL;
978   }
979 
980   gvid_printf("\033[%u;%uH%s%*.*s%s", row+1, col+1, color,
981     min_len, min_len, buf, fillbuf
982   );
983 
984   #endif
985 }
986 
987 
988 //  ------------------------------------------------------------------
989 //  Print horizontal line of character and attribute
990 
991 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vputx(int row,int col,int atr,char chr,uint len)992 void _vputx(int row, int col, int atr, char chr, uint len) {
993 
994   gdma p = gdmaptr(col, row);
995   word tmp = vcatch(chr, atr);
996   _farsetsel(_dos_ds);
997   for(uint n=0; n<len; n++) {
998     _farnspokew(p, tmp);
999     p += ATTRSIZE;
1000   }
1001 }
1002 #endif
1003 
1004 
1005 //  ------------------------------------------------------------------
1006 //  Print horizontal line of character and attribute
1007 
vputx(int row,int col,vattr atr,vchar chr,uint len)1008 void vputx(int row, int col, vattr atr, vchar chr, uint len) {
1009 
1010   #if defined(__USE_NCURSES__)
1011 
1012   mvhline(row, col, vcatch(gvid_tcpr(chr), atr), len);
1013   refresh();
1014 
1015   #elif defined(__MSDOS__)
1016 
1017   if(gvid->isdma()) {
1018     _vputx(row, col, atr, chr, len);
1019   }
1020   else if(gvid->isbios() or gvid->iscga()) {
1021     i86 cpu;
1022     cpu.ah(2);
1023     cpu.bh(0);
1024     cpu.dh((byte)row);
1025     cpu.dl((byte)col);
1026     cpu.genint(0x10);
1027     cpu.ah(9);
1028     cpu.al(chr);
1029     cpu.bh(0);
1030     cpu.bl((byte)atr);
1031     cpu.cx((word)len);
1032     cpu.genint(0x10);
1033   }
1034 
1035   #elif defined(__OS2__)
1036 
1037   vatch filler = vcatch(chr, atr);
1038   VioWrtNCell((BYTE *)&filler, (USHORT)len, (USHORT)row, (USHORT)col, 0);
1039 
1040   #elif defined(__WIN32__)
1041 
1042   if (len > gvid->numcols)
1043     len = gvid->numcols;
1044 
1045   vatch filler = vcatch(chr, atr);
1046   for(int i = 0; i < len; i++)
1047     gvid->bufwrd[i] = filler;
1048   vputws(row, col, gvid->bufwrd, len);
1049 
1050   #elif defined(__UNIX__)
1051 
1052   char buf[256];
1053   char* color = gvid_newattr(atr);
1054   gvid_cvtchr(chr);
1055   _vputx(row, col, atr, chr, len);
1056   memset(buf, chr, len);
1057   buf[len] = NUL;
1058   gvid_printf("\033[%u;%uH%s%s", row+1, col+1, color, buf);
1059 
1060   #endif
1061 }
1062 
1063 
1064 //  ------------------------------------------------------------------
1065 //  Print vertical line of character and attribute
1066 
1067 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vputy(int row,int col,int atr,char chr,uint len)1068 inline void _vputy(int row, int col, int atr, char chr, uint len) {
1069 
1070   gdma p = gdmaptr(col, row);
1071   word tmp = vcatch(chr, atr);
1072   _farsetsel(_dos_ds);
1073   for(uint n=0; n<len; n++) {
1074     _farnspokew(p, tmp);
1075     p += ATTRSIZE*gvid->numcols;
1076   }
1077 }
1078 #endif
1079 
1080 
1081 //  ------------------------------------------------------------------
1082 //  Print vertical line of character and attribute
1083 
vputy(int row,int col,vattr atr,vchar chr,uint len)1084 void vputy(int row, int col, vattr atr, vchar chr, uint len) {
1085 
1086   #if defined(__USE_NCURSES__)
1087 
1088   mvvline(row, col, vcatch(gvid_tcpr(chr), atr), len);
1089   refresh();
1090 
1091   #elif defined(__MSDOS__)
1092 
1093   if(gvid->isdma()) {
1094     _vputy(row, col, atr, chr, len);
1095   }
1096   else if(gvid->isbios() or gvid->iscga()) {
1097     for(uint n=0; n<len; n++) {
1098       i86 cpu;
1099       cpu.ah(2);
1100       cpu.bh(0);
1101       cpu.dh((byte)row++);
1102       cpu.dl((byte)col);
1103       cpu.genint(0x10);
1104       cpu.ah(9);
1105       cpu.al(chr);
1106       cpu.bh(0);
1107       cpu.bl((byte)atr);
1108       cpu.cx(1);
1109       cpu.genint(0x10);
1110     }
1111   }
1112 
1113   #elif defined(__OS2__)
1114 
1115   vatch filler = vcatch(chr, atr);
1116   for(int n=0; n<len; n++)
1117     VioWrtNCell((BYTE *)&filler, 1, (USHORT)row++, (USHORT)col, 0);
1118 
1119   #elif defined(__WIN32__)
1120 
1121   vatch filler = vcatch(chr, atr);
1122   for(int i=0; i < len; i++)
1123     vputw(row++, col, filler);
1124 
1125   #elif defined(__UNIX__)
1126 
1127   char* color = gvid_newattr(atr);
1128   gvid_cvtchr(chr);
1129   _vputy(row, col, atr, chr, len);
1130 
1131   char buf[2048];
1132   sprintf(buf, "\033[%u;%uH%s", row+1, col+1, color);
1133 
1134   char* p = buf + strlen(buf);
1135   for(uint n=0; n<(len-1); n++) {
1136     *p++ = chr;
1137     if(col == gvid->numcols-1) {
1138       sprintf(p, "\033[%u;%uH", row+n+2, col+1);
1139       p += strlen(p);
1140     }
1141     else {
1142       strcpy(p, "\033[D\033[B");
1143       p += 6;
1144     }
1145   }
1146   *p++ = chr;
1147   *p = NUL;
1148   gvid_printf("%s", buf);
1149 
1150   #endif
1151 }
1152 
1153 
1154 //  ------------------------------------------------------------------
1155 //  Get character and attribute at cursor position
1156 
1157 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vgetw(int row,int col)1158 inline word _vgetw(int row, int col) {
1159 
1160   return _farpeekw(_dos_ds, gdmaptr(col, row));
1161 }
1162 #endif
1163 
1164 
1165 //  ------------------------------------------------------------------
1166 //  Get character and attribute at cursor position
1167 
vgetw(int row,int col)1168 vatch vgetw(int row, int col) {
1169 
1170   #if defined(__USE_NCURSES__)
1171 
1172   return mvinch(row, col);
1173 
1174   #elif defined(__MSDOS__)
1175 
1176   if(gvid->isdma()) {
1177     return _vgetw(row, col);
1178   }
1179   else if(gvid->isbios() or gvid->iscga()) {
1180     i86 cpu;
1181     cpu.ah(2);
1182     cpu.bh(0);
1183     cpu.dh((byte)row);
1184     cpu.dl((byte)col);
1185     cpu.genint(0x10);
1186     cpu.ah(8);
1187     cpu.bh(0);
1188     cpu.genint(0x10);
1189     return cpu.ax();
1190   }
1191   return 0;
1192 
1193   #elif defined(__OS2__)
1194 
1195   vatch chat;
1196   USHORT len=sizeof(chat);
1197 
1198   VioReadCellStr((BYTE *)&chat, &len, (USHORT)row, (USHORT)col, 0);
1199 
1200   return chat;
1201 
1202   #elif defined(__WIN32__)
1203 
1204   vatch chat;
1205   const COORD coord = {0, 0};
1206   const COORD size = {1, 1};
1207   SMALL_RECT rect;
1208 
1209   rect.Top = row;
1210   rect.Left = col;
1211   rect.Bottom = row+size.Y-1;
1212   rect.Right = col+size.X-1;
1213   ReadConsoleOutput(gvid_hout, &chat, size, coord, &rect);
1214 
1215   return chat;
1216 
1217   #elif defined(__UNIX__)
1218 
1219   return _vgetw(row, col);
1220 
1221   #endif
1222 }
1223 
1224 
1225 //  ------------------------------------------------------------------
1226 //  Get character and attribute at cursor position
1227 
vgetc(int row,int col,vattr * atr,vchar * chr)1228 void vgetc(int row, int col, vattr* atr, vchar* chr) {
1229 
1230   if((row < 0) or (row > gvid->numrows-1) or (col < 0) or (col > gvid->numcols-1)) {
1231     *chr = ' ';
1232     *atr = BLACK_|_BLACK;
1233   }
1234   else {
1235     vatch tmp = vgetw(row, col);
1236 
1237     *chr = vgchar(tmp);
1238     *atr = vgattr(tmp);
1239   }
1240 }
1241 
1242 
1243 //  ------------------------------------------------------------------
1244 //  Scroll screen area
1245 
1246 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vscroll(int srow,int scol,int erow,int ecol,int atr,int lines)1247 static void _vscroll(int srow, int scol, int erow, int ecol, int atr, int lines) {
1248 
1249   word empty = (atr << 8) | ' ';
1250   if(lines > 0) {
1251     while(lines--) {
1252       int nrow = srow;
1253       int l = ((ecol - scol) + 1);
1254       gdma scrptr = gdmaptr(scol, srow);
1255       while(nrow++ < erow) {
1256         gdmacpy(_dos_ds, (gdma)scrptr, _dos_ds, (gdma)(scrptr+ATTRSIZE*gvid->numcols), l*sizeof(word));
1257         scrptr += ATTRSIZE*gvid->numcols;
1258       }
1259       _farsetsel(_dos_ds);
1260       for(l *= ATTRSIZE; l>0;) {
1261         l -= ATTRSIZE;
1262         _farnspokew(scrptr+l, empty);
1263       }
1264     }
1265   }
1266   else {
1267     while(lines++) {
1268       int nrow = erow;
1269       int l = ((ecol - scol) + 1);
1270       gdma scrptr = gdmaptr(scol, erow);
1271       while(nrow-- >= (srow + 1)) {
1272         gdmacpy(_dos_ds, (gdma)scrptr, _dos_ds, (gdma)(scrptr-ATTRSIZE*gvid->numcols), l*sizeof(word));
1273         scrptr -= ATTRSIZE*gvid->numcols;
1274       }
1275       _farsetsel(_dos_ds);
1276       for(l *= ATTRSIZE; l>0;) {
1277         l -= ATTRSIZE;
1278         _farnspokew(scrptr+l, empty);
1279       }
1280     }
1281   }
1282 }
1283 #endif
1284 
1285 
1286 //  ------------------------------------------------------------------
1287 //  Scroll screen area
1288 
vscroll(int srow,int scol,int erow,int ecol,vattr atr,int lines)1289 void vscroll(int srow, int scol, int erow, int ecol, vattr atr, int lines) {
1290 
1291   #if defined(__USE_NCURSES__)
1292 
1293   vatch filler = vcatch(' ', atr);
1294 
1295   // Currently implemented with vsave/vrestore
1296   // Does anyone know a better solution?
1297 
1298   if(lines >= 0) {
1299     if(lines <= 1 + erow - srow) {
1300       vsavebuf *buf = vsave(srow + lines, scol, erow, ecol);
1301       vrestore(buf, srow, scol, erow - lines, ecol);
1302       throw_xfree(buf);
1303     }
1304     else
1305       lines = 1 + erow - srow;
1306 
1307     for(int counter = 0; counter < lines; counter++)
1308       mvhline(1 + erow + counter - lines, scol, filler, 1 + ecol - scol);
1309     refresh();
1310   }
1311   else {
1312     lines*=-1;
1313     if(lines <= 1 + erow - srow) {
1314       vsavebuf *buf = vsave(srow, scol, erow - lines, ecol);
1315       vrestore(buf, srow + lines, scol, erow, ecol);
1316       throw_xfree(buf);
1317     }
1318     else
1319       lines = 1 + erow - srow;
1320 
1321     for(int counter = 0; counter < lines; counter++)
1322       mvhline(srow + counter, scol, filler, 1 + ecol - scol);
1323     refresh();
1324   }
1325 
1326   #elif defined(__MSDOS__)
1327 
1328   if(gvid->isdma()) {
1329     _vscroll(srow, scol, erow, ecol, atr, lines);
1330   }
1331   else if(gvid->isbios() or gvid->iscga()) {
1332     i86 cpu;
1333     cpu.ah((byte)(lines > 0 ? 6 : 7));
1334     cpu.al((byte)absolute(lines));
1335     cpu.bh((byte)atr);
1336     cpu.ch((byte)srow);
1337     cpu.cl((byte)scol);
1338     cpu.dh((byte)erow);
1339     cpu.dl((byte)ecol);
1340     cpu.genint(0x10);
1341   }
1342 
1343   #elif defined(__OS2__)
1344 
1345   vatch filler = vcatch(' ', atr);
1346 
1347   if(lines > 0)
1348     VioScrollUp((USHORT)srow, (USHORT)scol, (USHORT)erow, (USHORT)ecol, (USHORT)lines, (BYTE *)&filler, 0);
1349   else
1350     VioScrollDn((USHORT)srow, (USHORT)scol, (USHORT)erow, (USHORT)ecol, (USHORT)-lines, (BYTE *)&filler, 0);
1351 
1352   #elif defined(__WIN32__)
1353 
1354   SMALL_RECT r;
1355   COORD c = {scol, srow - lines};
1356   vatch filler = vcatch(' ', atr);
1357 
1358   r.Left   = (SHORT)scol;
1359   r.Top    = (SHORT)srow;
1360   r.Right  = (SHORT)ecol;
1361   r.Bottom = (SHORT)erow;
1362 
1363   ScrollConsoleScreenBuffer(gvid_hout, &r, &r, c, &filler);
1364 
1365   #elif defined(__UNIX__)
1366 
1367   _vscroll(srow, scol, erow, ecol, atr, lines);
1368 
1369   gdma ptr = gdmaptr(scol, srow);
1370   int len = ecol-scol+1;
1371   for(int nrow=srow; nrow<=erow; nrow++) {
1372     vputansi(nrow, scol, ptr, len);
1373     ptr += ATTRSIZE*gvid->numcols;
1374   }
1375 
1376   #endif
1377 }
1378 
1379 
1380 //  ------------------------------------------------------------------
1381 //  Returns true if cursor invisible
1382 
vcurhidden()1383 bool vcurhidden() {
1384 
1385   return __vcurhidden;
1386 }
1387 
1388 //  ------------------------------------------------------------------
1389 //  Get cursor position
1390 
vposget(int * row,int * col)1391 void vposget(int* row, int* col) {
1392 
1393   #if defined(__USE_NCURSES__)
1394 
1395   getyx(stdscr, gvid->currow, gvid->curcol);
1396 
1397   #elif defined(__MSDOS__)
1398 
1399   i86 cpu;
1400   cpu.ah(3);
1401   cpu.bh(0);
1402   cpu.genint(0x10);
1403   gvid->currow = cpu.dh();
1404   gvid->curcol = cpu.dl();
1405 
1406   #elif defined(__OS2__)
1407 
1408   USHORT _getrow, _getcol;
1409   VioGetCurPos(&_getrow, &_getcol, 0);
1410   gvid->currow = _getrow;
1411   gvid->curcol = _getcol;
1412 
1413   #elif defined(__WIN32__)
1414 
1415   CONSOLE_SCREEN_BUFFER_INFO i;
1416   GetConsoleScreenBufferInfo(gvid_hout, &i);
1417   gvid->currow = i.dwCursorPosition.Y;
1418   gvid->curcol = i.dwCursorPosition.X;
1419 
1420   #elif defined(__UNIX__)
1421 
1422   // Not available
1423 
1424   #endif
1425 
1426   *row = gvid->currow;
1427   *col = gvid->curcol;
1428 }
1429 
1430 
1431 //  ------------------------------------------------------------------
1432 //  Set cursor position
1433 
vposset(int row,int col)1434 void vposset(int row, int col) {
1435 
1436   gvid->currow = row;
1437   gvid->curcol = col;
1438 
1439   #if defined(__USE_NCURSES__)
1440 
1441   move(row, col);
1442   refresh();
1443 
1444   #elif defined(__MSDOS__)
1445 
1446   i86 cpu;
1447   cpu.ah(2);
1448   cpu.bh(0);
1449   cpu.dh((byte)row);
1450   cpu.dl((byte)col);
1451   cpu.genint(0x10);
1452 
1453   #elif defined(__OS2__)
1454 
1455   VioSetCurPos((USHORT)row, (USHORT)col, 0);
1456 
1457   #elif defined(__WIN32__)
1458 
1459   // No need to set the cursor position if its not visible
1460   // Strangely, this is a major speedup to screen-output
1461 
1462   if(__vcurhidden)
1463     return;
1464 
1465   COORD c = {col, row};
1466   SetConsoleCursorPosition(gvid_hout, c);
1467 
1468   #elif defined(__UNIX__)
1469 
1470   gvid_printf("\x1B[%u;%uH", row+1, col+1);
1471 
1472   #endif
1473 }
1474 
1475 
1476 //  ------------------------------------------------------------------
1477 //  Clears the screen and homes the cursor
1478 
vclrscr()1479 void vclrscr() {
1480 
1481   vclrscr(vgattr(vgetw(gvid->currow, gvid->curcol)));
1482 }
1483 
1484 
1485 //  ------------------------------------------------------------------
1486 //  Clears the screen using given attribute and homes the cursor
1487 
1488 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vclrscr(vattr atr)1489 static void _vclrscr(vattr atr) {
1490 
1491   int len = gvid->numrows * gvid->numcols;
1492 
1493   _vputx(0, 0, atr, ' ', len);
1494 }
1495 #endif
1496 
1497 
1498 
1499 //  ------------------------------------------------------------------
1500 //  Clears the screen using given attribute and homes the cursor
1501 
vclrscr(vattr atr)1502 void vclrscr(vattr atr) {
1503 
1504   #if defined(__USE_NCURSES__)
1505 
1506   clearok(stdscr, TRUE);
1507   vatch filler = vcatch(' ', atr);
1508   for(int row = 0; row < LINES; row++)
1509     mvhline(row, 0, filler, COLS);
1510   move(0, 0);
1511   refresh();
1512 
1513   #elif defined(__MSDOS__)
1514 
1515   if(gvid->isdma()) {
1516     _vclrscr(atr);
1517   }
1518   else if(gvid->isbios() or gvid->iscga()) {
1519     i86 cpu;
1520     cpu.ax(0x0600);           // clear screen by scrolling it
1521     cpu.bh((byte)atr);
1522     cpu.cx(0);
1523     cpu.dh((byte)(gvid->numrows - 1));
1524     cpu.dl((byte)(gvid->numcols - 1));
1525     cpu.genint(0x10);
1526   }
1527 
1528   #elif defined(__OS2__)
1529 
1530   vatch filler = vcatch(' ', atr);
1531   VioScrollUp(0, 0, 0xFFFF, 0xFFFF, 0xFFFF, (BYTE *)&filler, 0);
1532 
1533   #elif defined(__WIN32__)
1534 
1535   COORD c = {0, 0};
1536   DWORD wr, len = gvid->numrows * gvid->numcols;
1537   // Filling with space seems to work for both Unicode and regular functions
1538   FillConsoleOutputCharacter(gvid_hout,       ' ', len, c, &wr);
1539   FillConsoleOutputAttribute(gvid_hout, (WORD)atr, len, c, &wr);
1540 
1541   #elif defined(__UNIX__)
1542 
1543   _vclrscr(atr);
1544 
1545   gvid_printf("%s\x1B[2J", gvid_newattr(atr));
1546 
1547   #endif
1548 
1549   vposset(0,0);
1550 }
1551 
1552 
1553 //  ------------------------------------------------------------------
1554 //  Saves the current screen and returns pointer to buffer
1555 
1556 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vsave(word * buf,int len1,int srow,int scol,int erow)1557 static void _vsave(word* buf, int len1, int srow, int scol, int erow) {
1558 
1559   const int len2 = len1*sizeof(word);
1560   gdma p = gdmaptr(scol, srow);
1561   for(int nrow=srow; nrow<=erow; nrow++) {
1562     gdmacpy(_my_ds(), (gdma)buf, _dos_ds, (gdma)p, len2);
1563     p += ATTRSIZE*gvid->numcols;
1564     buf += len1;
1565   }
1566 }
1567 #endif
1568 
1569 
1570 //  ------------------------------------------------------------------
1571 //  Saves the current screen and returns pointer to buffer
1572 
vsave(int srow,int scol,int erow,int ecol)1573 vsavebuf* vsave(int srow, int scol, int erow, int ecol) {
1574 
1575   if(srow == -1)  srow = 0;
1576   if(scol == -1)  scol = 0;
1577   if(erow == -1)  erow = gvid->numrows-1;
1578   if(ecol == -1)  ecol = gvid->numcols-1;
1579 
1580   vsavebuf* sbuf = (vsavebuf*)throw_xmalloc(sizeof(vsavebuf) + (erow - srow + 1) * (ecol - scol + 1) * sizeof(vatch));
1581 
1582   if(sbuf) {
1583 
1584     vatch* buf = sbuf->data;
1585 
1586     sbuf->top = srow;
1587     sbuf->left = scol;
1588     sbuf->bottom = erow;
1589     sbuf->right = ecol;
1590 
1591     #if defined(__USE_NCURSES__)
1592 
1593     for(int row=srow; row<=erow; row++)
1594       for(int col=scol; col<=ecol; col++)
1595         *buf++ = mvinch(row, col);
1596 
1597     #elif defined(__MSDOS__)
1598 
1599     int len1 = ecol-scol+1;
1600 
1601     if(gvid->isdma()) {
1602       _vsave(buf, len1, srow, scol, erow);
1603     }
1604     else if(gvid->isbios() or gvid->iscga()) {
1605       i86 cpu;
1606       byte* p = (byte*)buf;
1607       for(byte row=(byte)srow; row<=erow; row++) {
1608         for(byte col=(byte)scol; col<=ecol; col++) {
1609           cpu.ah(2);
1610           cpu.bh(0);
1611           cpu.dh(row);
1612           cpu.dl(col);
1613           cpu.genint(0x10);
1614           cpu.ah(8);
1615           cpu.bh(0);
1616           cpu.genint(0x10);
1617           *p++ = cpu.al();
1618           *p++ = cpu.ah();
1619         }
1620       }
1621     }
1622 
1623     #elif defined(__OS2__)
1624 
1625     int len1 = (int)(ecol-scol+1);
1626 
1627     #if defined(__BORLANDC__)
1628     PCHAR16 ptr = (PCHAR16)buf;
1629     #else
1630     PCH ptr = (PCH)buf;
1631     #endif
1632 
1633     USHORT len2 = (USHORT)(len1*sizeof(word));
1634     for(int nrow=srow; nrow<=erow; nrow++) {
1635       VioReadCellStr(ptr, &len2, nrow, scol, 0);
1636       ptr += len2;
1637     }
1638 
1639     #elif defined(__WIN32__)
1640 
1641     const COORD coord = {0, 0};
1642     COORD size = {ecol-scol+1, erow-srow+1};
1643     SMALL_RECT r;
1644 
1645     // Set the source rectangle.
1646     r.Top = srow;
1647     r.Left = scol;
1648     r.Bottom = erow;
1649     r.Right = ecol;
1650 
1651     if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
1652       ReadConsoleOutputW(gvid_hout, buf, size, coord, &r);
1653     else
1654       ReadConsoleOutputA(gvid_hout, buf, size, coord, &r);
1655 
1656     #elif defined(__UNIX__)
1657 
1658     int len1 = ecol-scol+1;
1659 
1660     _vsave(buf, len1, srow, scol, erow);
1661 
1662     #endif
1663   }
1664 
1665   return sbuf;
1666 }
1667 
1668 
1669 //  ------------------------------------------------------------------
1670 //  Redraws a previously saved screen
1671 
1672 #if (defined(__MSDOS__) || defined(__UNIX__)) && !defined(__USE_NCURSES__)
_vredraw(word * buf,int len1,int srow,int scol,int erow)1673 static void _vredraw(word* buf, int len1, int srow, int scol, int erow) {
1674 
1675   const int len2 = len1*sizeof(word);
1676   gdma p = gdmaptr(scol, srow);
1677   for(int nrow=srow; nrow<=erow; nrow++) {
1678     gdmacpy(_dos_ds, (gdma)p, _my_ds(), (gdma)buf, len2);
1679     p += ATTRSIZE*gvid->numcols;
1680     buf += len1;
1681   }
1682 }
1683 #endif
1684 
1685 
1686 //  ------------------------------------------------------------------
1687 //  Redraws a previously saved screen
1688 
vrestore(vsavebuf * sbuf,int srow,int scol,int erow,int ecol)1689 void vrestore(vsavebuf* sbuf, int srow, int scol, int erow, int ecol) {
1690 
1691   if(srow != -1)  sbuf->top = srow;
1692   if(scol != -1)  sbuf->left = scol;
1693   if(erow != -1)  sbuf->bottom = erow;
1694   if(ecol != -1)  sbuf->right = ecol;
1695 
1696   srow = sbuf->top;
1697   scol = sbuf->left;
1698   erow = sbuf->bottom;
1699   ecol = sbuf->right;
1700 
1701   vatch *buf = sbuf->data;
1702 
1703   #if defined(__USE_NCURSES__)
1704 
1705   for(int row=srow; row<=erow; row++)
1706     for(int col=scol; col<=ecol; col++)
1707       mvaddch(row, col, *buf++);
1708 
1709   refresh();
1710 
1711   #elif defined(__MSDOS__)
1712 
1713   int len1 = ecol-scol+1;
1714 
1715   if(gvid->isdma()) {
1716     _vredraw(buf, len1, srow, scol, erow);
1717   }
1718   else if(gvid->isbios() or gvid->iscga()) {
1719     i86 cpu;
1720     byte* p = (byte*)buf;
1721     for(byte row=(byte)srow; row<=erow; row++) {
1722       for(byte col=(byte)scol; col<=ecol; col++) {
1723         cpu.ah(2);
1724         cpu.bh(0);
1725         cpu.dh(row);
1726         cpu.dl(col);
1727         cpu.genint(0x10);
1728         cpu.ah(9);
1729         cpu.al(*p++);
1730         cpu.bh(0);
1731         cpu.bl(*p++);
1732         cpu.cx(1);
1733         cpu.genint(0x10);
1734       }
1735     }
1736   }
1737 
1738   #elif defined(__OS2__)
1739 
1740   USHORT len1 = (USHORT)(ecol-scol+1);
1741   USHORT len2 = (USHORT)(len1*sizeof(word));
1742 
1743   #if defined(__BORLANDC__)
1744   PCHAR16 ptr = (PCHAR16)buf;
1745   #else
1746   PCH ptr = (PCH)buf;
1747   #endif
1748 
1749   for(USHORT nrow=srow; nrow<=erow; nrow++) {
1750     VioWrtCellStr(ptr, len2, nrow, scol, 0);
1751     ptr += len2;
1752   }
1753 
1754   #elif defined(__WIN32__)
1755 
1756   const COORD coord = {0, 0};
1757   COORD size = {ecol-scol+1, erow-srow+1};
1758   SMALL_RECT r;
1759 
1760   // Set the source rectangle.
1761   r.Top = srow;
1762   r.Left = scol;
1763   r.Bottom = erow;
1764   r.Right = ecol;
1765 
1766   if(WinVer.dwPlatformId == VER_PLATFORM_WIN32_NT)
1767     WriteConsoleOutputW(gvid_hout, buf, size, coord, &r);
1768   else
1769     WriteConsoleOutputA(gvid_hout, buf, size, coord, &r);
1770 
1771   #elif defined(__UNIX__)
1772 
1773   int len1 = ecol-scol+1;
1774 
1775   _vredraw(buf, len1, srow, scol, erow);
1776 
1777   int atr = vgattr(*buf);
1778   char* color = gvid_newattr(atr);
1779   gvid_printf("%s", color);
1780 
1781   for(int nrow=srow; nrow<=erow; nrow++) {
1782     vputansi(nrow, scol, buf, len1);
1783     buf += len1;
1784   }
1785 
1786   #endif
1787 }
1788 
1789 
1790 //  ------------------------------------------------------------------
1791 //  Sets the cursor shape/size
1792 
vcurset(int sline,int eline)1793 void vcurset(int sline, int eline) {
1794 
1795   if(eline) {
1796     gvid->curr.cursor.start = sline;
1797     gvid->curr.cursor.end = eline;
1798     __vcurhidden = false;
1799   }
1800 
1801   #if defined(__USE_NCURSES__)
1802 
1803   if((sline == 0) and (eline == 0))
1804     curs_set(0);
1805   else if((eline - sline) <= 4)
1806     curs_set(1);
1807   else
1808     curs_set(2);
1809 
1810   #elif defined(__MSDOS__)
1811 
1812   if(eline == 0) {
1813     int _dvhide = __gdvdetected ? 0x01 : 0x30;
1814     sline = ((gvid->adapter>=V_HGC) and (gvid->adapter<=V_INCOLOR)) ? 0x3F : _dvhide;
1815   }
1816 
1817   i86 cpu;
1818   cpu.ah(1);
1819   cpu.ch((byte)sline);
1820   cpu.cl((byte)eline);
1821   cpu.genint(0x10);
1822 
1823   #elif defined(__OS2__)
1824 
1825   VIOCURSORINFO vioci;
1826   VioGetCurType(&vioci, 0);
1827   vioci.yStart = (USHORT)sline;
1828   vioci.cEnd   = (USHORT)eline;
1829   vioci.attr   = (USHORT)((eline == 0) ? 0xFFFF : gvid->curr.color.textattr);
1830   VioSetCurType(&vioci, 0);
1831 
1832   #elif defined(__WIN32__)
1833 
1834   CONSOLE_CURSOR_INFO cci;
1835 
1836   if(eline)
1837     vposset(gvid->currow, gvid->curcol);
1838   else  /* Move cursor to bottom right corner (workaround of the win9x console bug) */
1839     vposset(gvid->numrows-1, gvid->numcols-1);
1840 
1841   cci.dwSize = (eline and sline) ? sline : 100;
1842   cci.bVisible = make_bool(eline);
1843 
1844 // To hide cursor in w98 needs change byte sequnce in compiled gedcyg.exe:
1845 //   0F 95 C0 89 45 FC
1846 //   B0 01 90 -- -- --
1847 
1848   SetConsoleCursorInfo(gvid_hout, &cci);
1849 
1850   #elif defined(__UNIX__)
1851 
1852   gvid_printf("\033[?25%c", eline ? 'h' : 'l');
1853 
1854   #endif
1855 }
1856 
1857 
1858 //  ------------------------------------------------------------------
1859 //  Hides the cursor
1860 
vcurhide()1861 void vcurhide() {
1862 
1863   if(not __vcurhidden) {
1864     #if defined(__USE_NCURSES__)
1865     curs_set(0);
1866     #else
1867     vcurset(0,0);
1868     #endif
1869     __vcurhidden = true;
1870   }
1871 }
1872 
1873 
1874 //  ------------------------------------------------------------------
1875 //  Reveals the cursor
1876 
vcurshow()1877 void vcurshow() {
1878 
1879   if(__vcurhidden) {
1880     vcurset(gvid->curr.cursor.start, gvid->curr.cursor.end);
1881     __vcurhidden = false;
1882   }
1883 }
1884 
1885 
1886 //  ------------------------------------------------------------------
1887 //  Sets a large cursor
1888 
vcurlarge()1889 void vcurlarge() {
1890 
1891   #if defined(__USE_NCURSES__)
1892   curs_set(2);
1893   #else
1894   vcurshow();
1895 
1896   #if defined(__MSDOS__)
1897 
1898   switch(gvid->adapter) {
1899     case V_CGA:
1900       vcurset(1,7);
1901       break;
1902     case V_EGA:
1903       if(gvid->numrows == 25) {
1904         vcurset(1,7);
1905       }
1906       else {
1907         word* p = (word*)0x0463;  // video BIOS data area
1908         outpw(*p,0x000A);         // update cursor start register
1909         outpw(*p,0x0A0B);         // update cursor end register
1910       }
1911       break;
1912     case V_VGA:
1913       vcurset(1,7);
1914       break;
1915     default:    // one of the monochrome cards
1916       vcurset(1,12);
1917   }
1918 
1919   #elif defined(__OS2__)
1920 
1921   vcurset(1, gvid->curr.screen.cheight-1);
1922 
1923   #elif defined(__WIN32__)
1924 
1925   vcurset(90, true);
1926 
1927   #endif
1928   #endif
1929 }
1930 
1931 
1932 //  ------------------------------------------------------------------
1933 //  Sets a small cursor
1934 
vcursmall()1935 void vcursmall() {
1936 
1937   #if defined(__USE_NCURSES__)
1938   curs_set(1);
1939   #else
1940   vcurshow();
1941 
1942   #if defined(__MSDOS__)
1943 
1944   switch(gvid->adapter) {
1945     case V_CGA:
1946       vcurset(6,7);
1947       break;
1948     case V_EGA:
1949       if(gvid->numrows == 25) {
1950         vcurset(6,7);
1951       }
1952       else {
1953         word* p = (word*)0x0463;    // video BIOS data area
1954         outpw(*p,0x060A);           // update cursor start register
1955         outpw(*p,0x000B);           // update cursor end register
1956       }
1957       break;
1958     case V_VGA:
1959       vcurset(6,7);
1960       break;
1961     default:    // one of the monochrome cards
1962       vcurset(11,12);
1963   }
1964 
1965   #elif defined(__OS2__)
1966 
1967   vcurset(gvid->curr.screen.cheight-2, gvid->curr.screen.cheight-1);
1968 
1969   #elif defined(__WIN32__)
1970 
1971   vcurset(13, true);
1972 
1973   #endif
1974   #endif
1975 }
1976 
1977 
1978 //  ------------------------------------------------------------------
1979 //  Table of characters used to display boxes
1980 //
1981 //  Access box table characters via:
1982 //      _box_table(boxtype, x)
1983 //
1984 //  where:
1985 //      boxtype is the number of the box type you want to use (0 - 5)
1986 //
1987 //      x will be one of the following:
1988 //           0 - upper left corner
1989 //           1 - upper horizontal line
1990 //           2 - upper right corner
1991 //           3 - left vertical line
1992 //           4 - right vertical line
1993 //           5 - lower left corner
1994 //           6 - lower horizontal line
1995 //           7 - lower right corner
1996 //           8 - middle junction
1997 //           9 - left vertical junction
1998 //          10 - right vertical junction
1999 //          11 - upper horizontal junction
2000 //          12 - lower horizontal junction
2001 //          13 - checkerboard
2002 //          14 - solid block
2003 //  ------------------------------------------------------------------
2004 
2005 #if !defined(__USE_NCURSES__)
2006 
2007 char* __box_table[] = {
2008 
2009   #if defined(__UNIX__) // This table will be actually patched at startup...
2010 
2011   ".-.||`-'+||-- #",    // box type 0     Single border
2012   ".-.||`-'+||-- #",    // box type 1     Double border
2013   ".-.||`-'+||-- #",    // box type 2     Single top
2014   ".-.||`-'+||-- #",    // box type 3     Double top
2015   "              #",    // box type 4     With empty border
2016   ".-.||`-'+||-- #",    // box type 5     No border at all
2017   ".-.||`-'+||-- #",    // box type 6     Blocky border
2018   ".-.||`-'+||-- #",    // box type 7     ASCII border
2019   "lqkxxmqjntuwvaa",    // box type 8     xterm single border
2020 
2021   #else
2022 
2023   "�Ŀ������ô����",    // box type 0     Single border
2024   "�ͻ���ͼ�̹�ʰ�",    // box type 1     Double border
2025   "�ķ���Ľ�Ƕ�а�",    // box type 2     Single top
2026   "�͸���;�Ƶ�ϰ�",    // box type 3     Double top
2027   "             ��",    // box type 4     With empty border
2028   "�Ŀ������ô����",    // box type 5     No border at all
2029   "������������ݰ�",    // box type 6     Blocky border
2030   ".-.||`-'+||--##",    // box type 7     ASCII border
2031   "lqkxxmqjntuwvaa",    // box type 8     xterm single border
2032 
2033   #endif
2034 };
2035 #else
2036 
2037 // ncurses ACS_nnn characters are usually computed at runtime, so
2038 // we cannot use a static array
2039 
_box_table(int type,int c)2040 chtype _box_table(int type, int c) {
2041 
2042   char asciiborder[] = ".-.||-'+||--##";
2043 
2044   switch(type) {
2045     case 4:
2046       switch(c) {
2047         case 13:
2048           return ACS_BOARD;
2049         case 14:
2050           return ACS_BLOCK;
2051         default:
2052           return (chtype) ' ';
2053       }
2054     case 6:
2055       switch(c) {
2056         case 13:
2057           return ACS_BOARD;
2058         default:
2059           return ACS_BLOCK;
2060       }
2061     case 7:
2062       return (chtype) (asciiborder[c]);
2063     default:
2064       switch (c) {
2065         case 0:
2066           return ACS_ULCORNER;
2067         case 1:
2068         case 6:
2069           return ACS_HLINE;
2070         case 2:
2071           return ACS_URCORNER;
2072         case 3:
2073         case 4:
2074           return ACS_VLINE;
2075         case 5:
2076           return ACS_LLCORNER;
2077         case 7:
2078           return ACS_LRCORNER;
2079         case 8:
2080           return ACS_PLUS;
2081         case 9:
2082           return ACS_LTEE;
2083         case 10:
2084           return ACS_RTEE;
2085         case 11:
2086           return ACS_TTEE;
2087         case 12:
2088           return ACS_BTEE;
2089         case 13:
2090           return ACS_BOARD;
2091         default:
2092           return ACS_BLOCK;
2093       }
2094   }
2095 }
2096 
2097 #endif
2098 
2099 
2100 //  ------------------------------------------------------------------
2101 
2102 #if defined(__UNIX__)
gvid_boxcvt(char * s)2103 void gvid_boxcvt(char* s) {
2104   while(*s)
2105     *s++ = (char)gvid_boxcvtc(*s);
2106 }
2107 
gvid_boxcvtc(char c)2108 static uint32_t gvid_boxcvtc(char c) {
2109     switch(c) {
2110 #if 0
2111       case '�': return _box_table(8, 0);
2112       case '�': return _box_table(8, 1);
2113       case '�': return _box_table(8, 2);
2114       case '�': return _box_table(8, 4);
2115       case '�': return _box_table(8, 5);
2116       case '�': return _box_table(8, 7);
2117       case '�': return _box_table(8, 8);
2118       case '�': return _box_table(8, 9);
2119       case '�': return _box_table(8, 10);
2120       case '�': return _box_table(8, 11);
2121       case '�': return _box_table(8, 12);
2122 #else
2123       case '�': return _box_table(0, 0);
2124       case '�': return _box_table(0, 1);
2125       case '�': return _box_table(0, 2);
2126       case '�': return _box_table(0, 4);
2127       case '�': return _box_table(0, 5);
2128       case '�': return _box_table(0, 7);
2129       case '�': return _box_table(0, 8);
2130       case '�': return _box_table(0, 9);
2131       case '�': return _box_table(0, 10);
2132       case '�': return _box_table(0, 11);
2133       case '�': return _box_table(0, 12);
2134       case '�': return _box_table(1, 0);
2135       case '�': return _box_table(1, 1);
2136       case '�': return _box_table(1, 2);
2137       case '�': return _box_table(1, 4);
2138       case '�': return _box_table(1, 5);
2139       case '�': return _box_table(1, 7);
2140       case '�': return _box_table(1, 8);
2141       case '�': return _box_table(1, 9);
2142       case '�': return _box_table(1, 10);
2143       case '�': return _box_table(1, 11);
2144       case '�': return _box_table(1, 12);
2145 #endif
2146     }
2147     return c;
2148 }
2149 #endif
2150 
2151 
2152 //  ------------------------------------------------------------------
2153 //  Draws a text box on the screen
2154 
vbox(int srow,int scol,int erow,int ecol,int box,vattr hiattr,vattr loattr)2155 void vbox(int srow, int scol, int erow, int ecol, int box, vattr hiattr, vattr loattr)
2156 {
2157   if (loattr == DEFATTR)
2158     loattr = hiattr;
2159   else if(loattr == -2)
2160     loattr = (int)((hiattr & 0x08) ? (hiattr & 0xF7) : (hiattr | 0x08));
2161 
2162   #if defined(__UNIX__)
2163   hiattr |= ACSET;
2164   loattr |= ACSET;
2165   #endif
2166 
2167   vputc(srow,   scol,   hiattr, _box_table(box, 0));               // Top left corner
2168   vputx(srow,   scol+1, hiattr, _box_table(box, 1), ecol-scol-1);  // Top border
2169   vputc(srow,   ecol,   loattr, _box_table(box, 2));               // Top right corner
2170   vputy(srow+1, scol,   hiattr, _box_table(box, 3), erow-srow-1);  // Left border
2171   vputy(srow+1, ecol,   loattr, _box_table(box, 4), erow-srow-1);  // Right border
2172   vputc(erow,   scol,   hiattr, _box_table(box, 5));               // Bottom left corner
2173   vputx(erow,   scol+1, loattr, _box_table(box, 6), ecol-scol-1);  // Bottom border
2174   vputc(erow,   ecol,   loattr, _box_table(box, 7));               // Bottom right corner
2175 }
2176 
2177 
2178 //  ------------------------------------------------------------------
2179 //  Fills an area of screen with a character & attribute
2180 
vfill(int srow,int scol,int erow,int ecol,vchar chr,vattr atr)2181 void vfill(int srow, int scol, int erow, int ecol, vchar chr, vattr atr) {
2182 
2183   int width = ecol-scol+1;
2184   for(int crow=srow; crow<=erow; crow++)
2185     vputx(crow, scol, atr, chr, width);
2186 }
2187 
2188 
2189 //  ------------------------------------------------------------------
2190