1 /* This file is properly part of the excellent DJGPP compiler/tools package
2 	put out by DJ Delorie for use under DOS.  Unfortunately, the module
3 	as distributed in many versions of the DJGPP is buggy -- this copy
4 	of gppconio.c fixes many of those bugs.  I understand that these
5 	changes have been sent back to the DJGPP maintainers -- hopefully
6 	vile will not need to include this file in the future.  -pgf 9/95
7 
8    $Id: gppconio.c,v 1.5 2020/01/19 16:04:58 tom Exp $
9 */
10 
11 #if __DJGPP__ < 2
12 
13 /**********************************************************************
14  *
15  *  NAME:           gppconio.c
16  *
17  *  DESCRIPTION:    simulate Borland text video funcs for GNU C++
18  *
19  *  copyright (c) 1991 J. Alan Eldridge
20  *
21  *  M O D I F I C A T I O N   H I S T O R Y
22  *
23  *  when        who                 what
24  *  -------------------------------------------------------------------
25  *  10/27/91    J. Alan Eldridge    created
26  *  01/06/92    D. Buerssner        make it work with extended characters
27  * (buers@dg1.chemie.uni-konstanz.de) speed-up of cputs
28  *                                  some missing brackets in VIDADDR
29  *                                  don't need scrollwindow anymore
30  *  07/15/93    D. Buerssner        take care of cursor tracking
31  *                                    txinfo.curx and txinfo.cury
32  *                                  fill in missing functionality
33  *                                    - textmode
34  *                                    - cscanf
35  *                                    - cgets
36  *                                    - getch and ungetch
37  *                                    - _setcursortype
38  *                                    - kbhit
39  *                                  (hpefully) proper initialization of
40  *                                    txinfo.normattrib and txinfo.attribute
41  *                                  gotoxy(1,1) in clrscr (bug introduced
42  *                                    by my previous patches)
43  *                                  gotoxy(1,1) in window
44  *                                  take care of BELL and BACKSPACE
45  *                                    in putch and cputs
46  *                                  take care of blinking bit in textcolor
47  *                                    and textbackground
48  *                                  declare (and ignore) directvideo
49  *  10/09/93    DJ Delorie          Switch to dosmem*() for DPMI
50  *  05/01/94    DJ Delorie          Add _wscroll
51  *********************************************************************/
52 
53 #include    <stdlib.h>
54 #include    <stdio.h>
55 #include    <stdarg.h>
56 #include    <dos.h>
57 #include    <pc.h>
58 #include    <go32.h>
59 #include    "gppconio.h"
60 
61 int _wscroll = 1;
62 
63 int directvideo = 1;		/* We ignore this */
64 
65 static void setcursor(unsigned int shape);
66 static int getvideomode(void);
67 static void bell(void);
68 static int get_screenattrib(void);
69 static int isEGA(void);
70 static int _scan_getche(FILE *fp);
71 static int _scan_ungetch(int c, FILE *fp);
72 
73 #define DBGGTINFO   0
74 
75 static unsigned ScreenAddress = 0xb8000UL;	/* initialize just in case */
76 static struct text_info txinfo;
77 static int ungot_char;
78 static int char_avail = 0;
79 
80 #define VIDADDR(r,c) (ScreenAddress + 2*(((r) * txinfo.screenwidth) + (c)))
81 
82 int
puttext(int c,int r,int c2,int r2,void * buf)83 puttext(int c, int r, int c2, int r2, void *buf)
84 {
85     short *cbuf = (short *) buf;
86     /* we should check for valid parameters, and maybe return 0 */
87     r--, r2--, c--, c2--;
88     for (; r <= r2; r++) {
89 	dosmemput(cbuf, (c2 - c + 1) * 2, VIDADDR(r, c));
90 	cbuf += c2 - c + 1;
91     }
92     return 1;
93 }
94 
95 int
gettext(int c,int r,int c2,int r2,void * buf)96 gettext(int c, int r, int c2, int r2, void *buf)
97 {
98     short *cbuf = (short *) buf;
99     /* we should check for valid parameters, and maybe return 0 */
100     r--, r2--, c--, c2--;
101     for (; r <= r2; r++) {
102 	dosmemget(VIDADDR(r, c), (c2 - c + 1) * 2, cbuf);
103 	cbuf += c2 - c + 1;
104     }
105     return 1;
106 }
107 
108 void
gotoxy(int col,int row)109 gotoxy(int col, int row)
110 {
111     ScreenSetCursor(row + txinfo.wintop - 2, col + txinfo.winleft - 2);
112     txinfo.curx = col;
113     txinfo.cury = row;
114 }
115 
116 int
wherex(void)117 wherex(void)
118 {
119     int row, col;
120 
121     ScreenGetCursor(&row, &col);
122 
123     return col - txinfo.winleft + 2;
124 }
125 
126 int
wherey(void)127 wherey(void)
128 {
129     int row, col;
130 
131     ScreenGetCursor(&row, &col);
132 
133     return row - txinfo.wintop + 2;
134 }
135 
136 void
textmode(int mode)137 textmode(int mode)
138 {
139     union REGS regs;
140     int mode_to_set = mode;
141     if (mode == LASTMODE)
142 	mode = mode_to_set = txinfo.currmode;
143     if (mode == C4350)
144 	/*
145 	 * just set mode 3 and load 8x8 font, idea taken
146 	 * (and code translated from Assembler to C)
147 	 * form Csaba Biegels stdvga.asm
148 	 */
149 	mode_to_set = 0x03;
150     regs.h.ah = 0x00;		/* set mode */
151     regs.h.al = mode_to_set;
152     int86(0x10, &regs, &regs);
153     if (mode == C80 || mode == BW80 || mode == C4350) {
154 	if (isEGA()) {
155 	    /*
156 	     * enable cursor size emulation, see Ralf Browns
157 	     * interrupt list
158 	     */
159 	    regs.h.ah = 0x12;
160 	    regs.h.bl = 0x34;
161 	    regs.h.al = 0x00;	/* 0: enable (1: disable) */
162 	    int86(0x10, &regs, &regs);
163 	}
164     }
165     if (mode == C4350) {
166 	if (!isEGA())
167 	    return;
168 	/* load 8x8 font */
169 	regs.x.ax = 0x1112;
170 	regs.x.bx = 0;
171 	int86(0x10, &regs, &regs);
172     }
173 /*    _setcursortype(_NORMALCURSOR); */
174     /* reinitialize txinfo structure to take into account new mode */
175     gppconio_init();
176 #if 0
177     /*
178      * For mode C4350 the screen is not cleared on my OAK-VGA.
179      * Should we clear it here? TURBOC doesn't so we don't bother either.
180      */
181     clrscr();
182 #endif
183 }
184 
185 void
textattr(int attr)186 textattr(int attr)
187 {
188     txinfo.attribute = ScreenAttrib = (unsigned char) attr;
189 }
190 
191 void
textcolor(int color)192 textcolor(int color)
193 {
194     /* strip blinking (highest) bit and textcolor */
195     ScreenAttrib &= 0x70;	/* strip blinking (highest) bit and textcolor */
196     txinfo.attribute = (ScreenAttrib |= (color & 0x8f));
197 }
198 
199 void
textbackground(int color)200 textbackground(int color)
201 {
202     /* strip background color, keep blinking bit */
203     ScreenAttrib &= 0x8f;
204     /* high intensity background colors (>7) are not allowed
205        so we strip 0x08 bit (and higher bits) of color */
206     txinfo.attribute = (ScreenAttrib |= ((color & 0x07) << 4));
207 }
208 
209 void
highvideo(void)210 highvideo(void)
211 {
212     txinfo.attribute = (ScreenAttrib |= 0x08);
213 }
214 
215 void
lowvideo(void)216 lowvideo(void)
217 {
218     txinfo.attribute = (ScreenAttrib &= 0x07);
219 }
220 
221 void
normvideo(void)222 normvideo(void)
223 {
224     txinfo.attribute = ScreenAttrib = txinfo.normattr;
225 }
226 
227 void
_setcursortype(int type)228 _setcursortype(int type)
229 {
230     unsigned cursor_shape;
231     switch (type) {
232     case _NOCURSOR:
233 	cursor_shape = 0x0700;
234 	break;
235     case _SOLIDCURSOR:
236 	cursor_shape = 0x0007;
237 	break;
238 /*      case _NORMALCURSOR: */
239     default:
240 	cursor_shape = 0x0607;
241 	break;
242     }
243     setcursor(cursor_shape);
244 }
245 
246 static void
setcursor(unsigned int cursor_shape)247 setcursor(unsigned int cursor_shape)
248 /* Sets the shape of the cursor */
249 {
250     union REGS reg;
251 
252     reg.h.ah = 1;
253     reg.x.cx = cursor_shape;
254     int86(0x10, &reg, &reg);
255 }				/* setcursor */
256 
257 static void
getwincursor(int * row,int * col)258 getwincursor(int *row, int *col)
259 {
260     ScreenGetCursor(row, col);
261 }
262 
263 void
clreol(void)264 clreol(void)
265 {
266     short image[256];
267     short val = ' ' | (ScreenAttrib << 8);
268     int c, row, col, ncols;
269 
270     getwincursor(&row, &col);
271     ncols = txinfo.winright - col;
272 
273     for (c = 0; c < ncols; c++)
274 	image[c] = val;
275 
276     puttext(col + 1, row + 1, txinfo.winright, row + 1, image);
277 }
278 
279 static void
fillrow(int row,int left,int right,int fill)280 fillrow(int row, int left, int right, int fill)
281 {
282     int col;
283     short filler[right - left + 1];
284 
285     for (col = left; col <= right; col++)
286 	filler[col - left] = fill;
287     dosmemput(filler, (right - left + 1) * 2, VIDADDR(row, left));
288 }
289 
290 void
clrscr(void)291 clrscr(void)
292 {
293     short filler[txinfo.winright - txinfo.winleft + 1];
294     int row, col;
295     for (col = 0; col < txinfo.winright - txinfo.winleft + 1; col++)
296 	filler[col] = ' ' | (ScreenAttrib << 8);
297     for (row = txinfo.wintop - 1; row < txinfo.winbottom; row++)
298 	dosmemput(filler, (txinfo.winright - txinfo.winleft + 1) * 2,
299 		  VIDADDR(row, txinfo.winleft - 1));
300     gotoxy(1, 1);
301 }
302 
303 int
putch(int c)304 putch(int c)
305 {
306     int row, col;
307 
308     ScreenGetCursor(&row, &col);
309 
310     /*  first, handle the character */
311     if (c == '\n') {
312 	row++;
313     } else if (c == '\r') {
314 	col = txinfo.winleft - 1;
315     } else if (c == '\b') {
316 	if (col > txinfo.winleft - 1)
317 	    col--;
318 	else if (row > txinfo.wintop - 1) {
319 	    /*
320 	     * Turbo-C ignores this case; we are smarter.
321 	     */
322 	    row--;
323 	    col = txinfo.winright - 1;
324 	}
325     } else if (c == 0x07)
326 	bell();
327     else {
328 	/* short   val = c | (ScreenAttrib << 8); */
329 	/* puttext(col + 1, row + 1, col + 1, row + 1, &val); */
330 	ScreenPutChar(c, ScreenAttrib, col, row);
331 	col++;
332     }
333 
334     /* now, readjust the window     */
335 
336     if (col >= txinfo.winright) {
337 	col = txinfo.winleft - 1;
338 	row++;
339     }
340 
341     if (row >= txinfo.winbottom) {
342 	/* scrollwin(0, txinfo.winbottom - txinfo.wintop, 1); */
343 	if (_wscroll) {
344 	    ScreenSetCursor(txinfo.wintop - 1, 0);
345 	    delline();
346 	}
347 	row--;
348     }
349 
350     ScreenSetCursor(row, col);
351     txinfo.cury = row - txinfo.wintop + 2;
352     txinfo.curx = col - txinfo.winleft + 2;
353     return c;
354 }
355 
356 int
getche(void)357 getche(void)
358 {
359     if (char_avail)
360 	/*
361 	 * We don't know, whether the ungot char was already echoed
362 	 * we assume yes (for example in cscanf, probably the only
363 	 * place where ungetch is ever called.
364 	 * There is no way to check for this really, because
365 	 * ungetch could have been called with a character that
366 	 * hasn't been got by a conio function.
367 	 * We don't echo again.
368 	 */
369 	return (getch());
370     return (putch(getch()));
371 }
372 
373 int
getch(void)374 getch(void)
375 {
376     union REGS regs;
377     int c;
378     if (char_avail) {
379 	c = ungot_char;
380 	char_avail = 0;
381     } else {
382 	regs.x.ax = 0x0700;
383 	int86(0x21, &regs, &regs);
384 	c = regs.h.al;
385     }
386     return (c);
387 }
388 
389 int
ungetch(int c)390 ungetch(int c)
391 {
392     if (char_avail)
393 	return (EOF);
394     ungot_char = c;
395     char_avail = 1;
396     return (c);
397 }
398 
399 /*
400  * kbhit from libc in libsrc/c/dos/kbhit.s doesn't check
401  * for ungotten chars, so we have to provide a new one
402  * Don't call it kbhit, rather use a new name (_conio_kbhit)
403  * and do a #define kbhit _conio_kbhit in gppconio.h.
404  * The old kbhit still can be used if gppconio.h
405  * is not included of after #undef kbhit
406  * If you don't use ungetch (directly or indirectly by cscanf)
407  * both kbhit and _conio_kbhit are the same.
408  * So this shouldn't cause any trouble with previously written
409  * source, because ungetch wasn't available.
410  * The only problem might be, if anybody just included gppconio.h
411  * and has not linked with libpc, (I can't think of a good reason
412  * for this). This will result a link error (undefined symbol _conio_kbhit).
413  */
414 
415 #undef kbhit			/* want to be able to call kbhit from libc */
416 
417 /* The kbhit in libc doesn't work for the second byte of extended chars. */
418 int
kbhit(void)419 kbhit(void)
420 {
421     union REGS regs;
422     regs.h.ah = 0x0b;
423     int86(0x21, &regs, &regs);
424     return regs.h.al ? -1 : 0;
425 }
426 
427 int
_conio_kbhit(void)428 _conio_kbhit(void)
429 {
430     if (char_avail)
431 	return (1);
432     else
433 	return (kbhit());
434 }
435 
436 /*
437  * The next two functions are needed by cscanf
438  */
439 static int
_scan_getche(FILE * fp)440 _scan_getche(FILE *fp)
441 {
442     return (getche());
443 }
444 
445 static int
_scan_ungetch(int c,FILE * fp)446 _scan_ungetch(int c, FILE *fp)
447 {
448     return (ungetch(c));
449 }
450 
451 void
insline(void)452 insline(void)
453 {
454     int row, col, left, right, nbytes, bot, fill;
455     ScreenGetCursor(&row, &col);
456     left = txinfo.winleft - 1;
457     right = txinfo.winright - 1;
458     nbytes = (right - left + 1) * 2;
459     bot = txinfo.winbottom - 1;
460     fill = ' ' | (ScreenAttrib << 8);
461     while (bot > row) {
462 	movedata(_go32_conventional_mem_selector(), VIDADDR(bot - 1, left),
463 		 _go32_conventional_mem_selector(), VIDADDR(bot, left),
464 		 nbytes);
465 	bot--;
466     }
467     if (row <= bot) {
468 	fillrow(row, left, right, fill);
469     }
470 }
471 
472 void
delline(void)473 delline(void)
474 {
475     int row, col, left, right, nbytes, bot, fill;
476     ScreenGetCursor(&row, &col);
477     left = txinfo.winleft - 1;
478     right = txinfo.winright - 1;
479     nbytes = (right - left + 1) * 2;
480     bot = txinfo.winbottom - 1;
481     fill = ' ' | (ScreenAttrib << 8);
482     while (row < bot) {
483 	movedata(_go32_conventional_mem_selector(), VIDADDR(row + 1, left),
484 		 _go32_conventional_mem_selector(), VIDADDR(row, left),
485 		 nbytes);
486 	row++;
487     }
488     fillrow(bot, left, right, fill);
489 }
490 
491 void
window(int left,int top,int right,int bottom)492 window(int left, int top, int right, int bottom)
493 {
494     if (top < 1 || left < 1 || right > txinfo.screenwidth ||
495 	bottom > txinfo.screenheight)
496 	return;
497 
498     txinfo.wintop = top;
499     txinfo.winleft = left;
500     txinfo.winright = right;
501     txinfo.winbottom = bottom;
502     gotoxy(1, 1);
503 }
504 
505 int
cputs(const char * s)506 cputs(const char *s)
507 {
508     int row, col, c;
509     const unsigned char *ss = (const unsigned char *) s;
510     short *viaddr;
511     short sa = ScreenAttrib << 8;
512     ScreenGetCursor(&row, &col);
513     viaddr = (short *) VIDADDR(row, col);
514     /*
515      * Instead of just calling putch; we do everything by hand here,
516      * This is much faster. We don't move the cursor after each character,
517      * only after the whole string is written, because ScreenSetCursor
518      * needs to long because of switching to real mode needed with djgpp.
519      * You won't recognize the difference.
520      */
521     while ((c = *ss++)) {
522 	/*  first, handle the character */
523 	if (c == '\n') {
524 	    row++;
525 	    viaddr += txinfo.screenwidth;
526 	} else if (c == '\r') {
527 	    col = txinfo.winleft - 1;
528 	    viaddr = (short *) VIDADDR(row, col);
529 	} else if (c == '\b') {
530 	    if (col > txinfo.winleft - 1) {
531 		col--;
532 		viaddr--;
533 	    } else if (row > txinfo.wintop - 1) {
534 		/*
535 		 * Turbo-C ignores this case. We want to be able to
536 		 * edit strings with backspace in gets after
537 		 * a linefeed, so we are smarter
538 		 */
539 		row--;
540 		col = txinfo.winright - 1;
541 		viaddr = (short *) VIDADDR(row, col);
542 	    }
543 	} else if (c == 0x07)
544 	    bell();
545 	else {
546 	    short q = c | sa;
547 	    dosmemput(&q, 2, (int) viaddr);
548 	    viaddr++;
549 	    col++;
550 	}
551 
552 	/* now, readjust the window     */
553 
554 	if (col >= txinfo.winright) {
555 	    col = txinfo.winleft - 1;
556 	    row++;
557 	    viaddr = (short *) VIDADDR(row, col);
558 	}
559 
560 	if (row >= txinfo.winbottom) {
561 	    ScreenSetCursor(txinfo.wintop - 1, 0);	/* goto first line in window */
562 	    delline();		/* and delete it */
563 	    row--;
564 	    viaddr -= txinfo.screenwidth;
565 	}
566     }
567 
568     ScreenSetCursor(row, col);
569     txinfo.cury = row - txinfo.wintop + 2;
570     txinfo.curx = col - txinfo.winleft + 2;
571     return (*(--ss));
572 }
573 
574 int
cprintf(const char * fmt,...)575 cprintf(const char *fmt,...)
576 {
577     int cnt;
578     char buf[2048];		/* this is buggy, because buffer might be too small. */
579     va_list ap;
580 
581     va_start(ap, fmt);
582     cnt = vsprintf(buf, fmt, ap);
583     va_end(ap);
584 
585     cputs(buf);
586     return cnt;
587 }
588 
589 char *
cgets(char * string)590 cgets(char *string)
591 {
592     unsigned len = 0;
593     unsigned int maxlen_wanted;
594     char *sp;
595     int c;
596     /*
597      * Be smart and check for NULL pointer.
598      * Don't know whether TURBOC does this.
599      */
600     if (!string)
601 	return (NULL);
602     maxlen_wanted = (unsigned int) ((unsigned char) string[0]);
603     sp = &(string[2]);
604     /*
605      * Should the string be shorter maxlen_wanted including or excluding
606      * the trailing '\0' ? We don't take any risk.
607      */
608     while (len < maxlen_wanted - 1) {
609 	c = getch();
610 	/*
611 	 * should we check for backspace here?
612 	 * TURBOC does (just checked) but doesn't in cscanf (that's harder
613 	 * or even impossible). We do the same.
614 	 */
615 	if (c == '\b') {
616 	    if (len > 0) {
617 		cputs("\b \b");	/* go back, clear char on screen with space
618 				   and go back again */
619 		len--;
620 		sp[len] = '\0';	/* clear the character in the string */
621 	    }
622 	} else if (c == '\r') {
623 	    sp[len] = '\0';
624 	    break;
625 	} else if (c == 0) {
626 	    /* special character ends input */
627 	    sp[len] = '\0';
628 	    ungetch(c);		/* keep the char for later processing */
629 	    break;
630 	} else {
631 	    sp[len] = putch(c);
632 	    len++;
633 	}
634     }
635     sp[maxlen_wanted - 1] = '\0';
636     string[1] = (char) ((unsigned char) len);
637     return (sp);
638 }
639 
640 int
cscanf(const char * fmt,...)641 cscanf(const char *fmt,...)
642 {
643     return (_doscan_low(NULL, _scan_getche, _scan_ungetch,
644 			fmt, (void **) ((&fmt) + 1)));
645 }
646 
647 int
movetext(int left,int top,int right,int bottom,int dleft,int dtop)648 movetext(int left, int top, int right, int bottom, int dleft, int dtop)
649 {
650     char *buf = malloc((right - left + 1) * (bottom - top + 1) * 2);
651 
652     if (!buf)
653 	return 0;
654 
655     gettext(left, top, right, bottom, buf);
656     puttext(dleft, dtop, dleft + right - left, dtop + bottom - top, buf);
657     free(buf);
658     return 1;
659 }
660 
661 static void
_gettextinfo(struct text_info * t)662 _gettextinfo(struct text_info *t)
663 {
664     int row, col;
665 
666     t->winleft = t->wintop = 1;
667     t->winright = t->screenwidth = ScreenCols();
668     t->winbottom = t->screenheight = ScreenRows();
669     ScreenAttrib = t->attribute = t->normattr = get_screenattrib();
670     t->currmode = getvideomode();
671     ScreenGetCursor(&row, &col);
672     t->curx = col + 1;
673     t->cury = row + 1;
674 #if DBGGTINFO
675     printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n", t->winleft,
676 	   t->winright, t->wintop, t->winbottom);
677     printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
678 	   t->screenheight, t->screenwidth, t->normattr, t->currmode,
679 	   t->curx, t->cury);
680 #endif
681 }
682 
683 void
gettextinfo(struct text_info * t)684 gettextinfo(struct text_info *t)
685 {
686     *t = txinfo;
687 #if DBGGTINFO
688     printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n", t->winleft,
689 	   t->winright, t->wintop, t->winbottom);
690     printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
691 	   t->screenheight, t->screenwidth, t->normattr, t->currmode,
692 	   t->curx, t->cury);
693 #endif
694 }
695 
696 static int
getvideomode(void)697 getvideomode(void)
698 {
699     int mode = ScreenMode();
700     /*
701      * in mode C80 we might have loaded a different font
702      */
703     if (mode == C80)
704 	if (ScreenRows() > 25)
705 	    mode = C4350;
706     return (mode);
707 }
708 
709 static void
bell(void)710 bell(void)
711 {
712     union REGS regs;
713 #if 0
714     /* use BIOS */
715     regs.h.ah = 0x0e;		/* write */
716     regs.h.al = 0x07;		/* bell */
717     int86(0x10, &regs, &regs);
718 #else
719     /* use DOS */
720     regs.h.ah = 0x06;		/* write */
721     regs.h.dl = 0x07;		/* bell */
722     int86(0x21, &regs, &regs);
723 #endif
724 }
725 
726 static int
get_screenattrib(void)727 get_screenattrib(void)
728 {
729     union REGS regs;
730     regs.h.ah = 0x08;		/* read character and attribute */
731     regs.h.bh = 0;		/* video page 0 */
732     int86(0x10, &regs, &regs);
733     return (regs.h.ah & 0x7f);	/* strip highest (BLINK) bit */
734 }
735 
736 /* check if we have at least EGA (idea form Ralf Browns interrupt list) */
737 static int
isEGA(void)738 isEGA(void)
739 {
740     union REGS regs;
741     regs.h.ah = 0x12;
742     regs.h.bl = 0x10;
743     regs.h.bh = 0xff;
744     int86(0x10, &regs, &regs);
745     return (regs.h.bh != 0xff);
746 }
747 
748 extern int _gppconio_init;
749 
750 void
gppconio_init(void)751 gppconio_init(void)
752 {
753     static int oldattrib = -1;
754     if (oldattrib == -1)
755 	oldattrib = get_screenattrib();
756     _gettextinfo(&txinfo);
757     if (txinfo.currmode == 7)	/* MONO */
758 	ScreenAddress = 0xb0000UL;
759     else
760 	ScreenAddress = 0xb8000UL;
761     ScreenAttrib = txinfo.normattr = txinfo.attribute = oldattrib;
762     _gppconio_init = 1;
763 }
764 
765 #endif /* __DJGPP__ < 2 */
766