2 * $Source: x:/prj/tech/libsrc/mprintf/RCS/mprintf.c $
5 * $Date: 1997/07/28 19:25:35 $
10 /* things to do - logon/logoff w/o destroying fname */
27 #define MONO_BASE 0xb0000
28 #define CGA_BASE 0xb8000
29 #define MONO_PAGE_SZ 0x01000
34 /* video bios constants. */
35 #define VBIOS_INT 0x10
36 #define VB_GET_COMBO 0x1a00
37 #define VB_SET_XY 0x0200
39 /* monochrome register ports. */
40 #define M_CNTRL 0x3b8 /* mono controller register */
41 #define M_SRX_ADR 0x3b4 /* mono sequencer address port */
42 #define M_SRX_DATA 0x3b5 /* mono sequencer data port */
43 #define SR_CTP 0x0a /* cursor top and bottom */
45 #define SR_AHI 0x0c /* page address hi and low */
47 #define SR_CLH 0x0e /* seq cursor location high */
48 #define SR_CLL 0x0f /* low */
50 #define C_SRX_ADR 0x3d4 /* cga sequencer address port */
51 #define C_SRX_DATA 0x3d5 /* cga sequencer data port */
56 #define MONO_ROW (2*MONO_WID)
60 #define MONO_FILE "mprintf.log"
61 #define MONO_DUMP "mono.dmp"
68 const char * lpOutputString
70 #define OutputDebugString(s) OutputDebugStringA(s)
73 bool mono_to_debugger
= FALSE
;
75 /* have we yet called mono_init()? */
76 static bool mono_done_init
= FALSE
;
78 /* TRUE if there's a monochrome screen present. */
79 static bool mono_screen
= FALSE
;
81 /* MONO_ON when monochrome printing enabled. */
82 static uchar mono_mode
= MONO_OFF
;
84 /* cursor position on the mono screen. - abs cursor pos */
85 static uchar mono_x
= 0;
86 static uchar mono_y
= 0;
94 uchar lcoor
[MONO_WIN_MAX
][2];
101 static page_parms _mono_screens
[MONO_MAX_PAGES
];
102 /* last is for flip/unflip - init to 1 so setpage 0 at start does stuff */
103 static char _cur_mono_page
=1, _last_mono_page
=-1, _cur_mono_focus
=0;
104 static uint _inited_mpages
=0; /* bitfielded list of which pages are inited */
105 static uchar _cur_card
=0; /* MDA */
107 static char *def_wrap_msg
=MONO_WRAP_MESSAGE
;
109 static int srx_adr
[2]={M_SRX_ADR
,C_SRX_ADR
};
110 static int srx_data
[2]={M_SRX_DATA
,C_SRX_DATA
};
112 #define cur_stru (_mono_screens[_cur_mono_page])
113 #define split_axis ((cur_stru).axis)
114 #define split_coord ((cur_stru).coord)
115 #define split_win ((cur_stru).win)
116 #define split_w ((cur_stru).w)
117 #define split_h ((cur_stru).h)
118 #define split_x ((cur_stru).x)
119 #define split_y ((cur_stru).y)
120 #define split_base ((cur_stru).base)
121 #define page_addr ((cur_stru).addr)
122 #define split_lcoor ((cur_stru).lcoor)
123 #define split_lfocus ((cur_stru).lfocus)
124 #define split_flags ((cur_stru).flags)
125 #define split_msg ((cur_stru).msg)
128 /* static split screen stuff */
129 static uchar split_axis
= MONO_AXIS_X
;
130 static char split_coord
= -1;
131 static char split_win
= -1; /* which window is active, -1 for no windows, else 1 or 2 */
132 static uchar split_w
=MONO_WID
, split_h
=MONO_HGT
;
133 static uchar split_x
=0, split_y
=0;
134 static uchar
*split_base
=MONO_BASE
;
135 static uchar split_lcoor
[MONO_WIN_MAX
][2]={{0xff,0xff},{0xff,0xff}};
136 static char split_lfocus
=-1;
139 /* current drawing attribute */
140 static uchar mono_attr
= 7; /* MA_NORMAL */
142 /* handle of the log file or -1 if no log file. */
143 static int mono_file
= -1;
144 static uchar mlog
=0; /* last/cur log file parms, mostly for which windows to log */
145 /* name of last log file */
146 static char last_lf
[_MAX_PATH
]=MONO_FILE
; /* pretend default was last */
148 int _mprint(const char *s
, int n
);
150 // just extern this and set it if you want to see things go...
151 void (*mono_spc_func
)(char *,int)=NULL
;
153 #define _mono_spc_check(s,n) \
154 if (mono_spc_func!=NULL) \
155 (*mono_spc_func)(s,n)
157 /* memset that sets n shorts starting a s to c. */
159 void *smemset (void *s
, short c
, int n
);
160 #pragma aux smemset= \
164 parm [edi] [eax] [ecx] \
165 modify [edi eax ecx];
167 __inline
void *smemset(void *s
, short c
, int n
)
169 #pragma warning(disable : 4035) // disables no return value warning
182 #define out_mda(reg,val) outp(M_SRX_ADR,reg); outp(M_SRX_DATA,val)
185 #define out_set(card,reg,val)\
186 outp(srx_adr[card],reg);\
187 outp(srx_data[card],val)
189 #define out_set(card,reg,val)\
190 outp((ushort) srx_adr[card],reg);\
191 outp((ushort) srx_data[card],val)
194 #ifdef USE_OLD_MONO_DETECT
195 bool mono_detect(void)
199 r
.w
.ax
= VB_GET_COMBO
;
200 int386 (VBIOS_INT
, &r
, &r
);
201 return ((r
.h
.bh
==COMBO_MONO
)||(r
.h
.bl
==COMBO_MONO
));
203 #endif /* USE_OLD_MONO_DETECT */
206 /* video bios call */
207 int vbio_call (int parm_ax
)
212 int386 (VBIOS_INT
, &r
, &r
);
215 #endif /* USE_VBIO_CALL */
218 int mono_get_combo(void);
219 #pragma aux mono_get_combo=\
226 __inline
int mono_get_combo(void)
228 #pragma warning(disable : 4035) // disables no return value warning
238 /* returns TRUE if the secondary display is monochrome. */
239 bool mono_detect(void)
244 // Fake this out under Windows 95, for now assume there is a monochrome
245 // board at 0xB000 and monitor present and hope for the best. The more
246 // this crashes on other setups, the sooner we'll have to come up with
247 // something else. Under Windows NT, monochrome output is not supported.
249 if (pStr
= getenv ("OS"))
250 if (! stricmp (pStr
, "Windows_NT"))
253 // Must be Windows 95
258 combo
=mono_get_combo();
259 // note the 5 is for Jaemz's machine which bites.
260 return (combo
&0xff)==COMBO_MONO
|| (combo
>>8)==COMBO_MONO
|| (combo
>>8)==5;
264 /* sets the monochrome printing mode to the mode passed in. it can be one of
265 MONO_ON, MONO_OFF, or MONO_TOG. returns new mono mode. */
266 int mono_setmode (int mode
)
269 { /* lets do this only if we have a mono screen */
270 if (mode
== MONO_TOG
)
272 if (mono_mode
== MONO_ON
)
273 mono_mode
= MONO_OFF
;
280 // it really already should be this
281 // else mono_mode=MONO_OFF;
286 /* setup for wrapping on mono as opposed to scrolling */
287 void mono_set_flags(int flags
, char *msg
)
290 if ((flags
&MONO_FLG_MSG
)&&(msg
!=NULL
))
294 /* fire up the monochrome screen printer. returns TRUE if there is a
295 monochrome screen present. */
302 mono_screen
=mono_detect();
303 r
=mono_setmode(mono_screen
);
304 if (r
) mono_setpage(0,TRUE
); /* put cursor at upper left, get to page 0 */
308 /* fire up the monochrome screen printer. returns TRUE if there is a
309 monochrome screen present. */
310 bool mono_win_init(bool have_screen
)
316 mono_screen
=have_screen
?MONO_ON
:MONO_OFF
;
317 r
=mono_setmode(mono_screen
);
318 if (r
) mono_setpage(0,TRUE
); /* put cursor at upper left, get to page 0 */
323 /* Mono Logging functions, logon, logoff, logdel */
325 /* turn on logging of monochrome activities.
326 * if how&MONO_LOG_CON use the last file logged to
327 * if how&MONO_LOG_DEF always use default log
328 * if how&MONO_LOG_NEW erase existing log file
329 * if CON and DEF, CON overrides, so there
330 * which uses the MONO_LOG_ALLWIN, or FULLSC defines, or | together MONO_WIN_ONE,TWO,etc
332 int mono_logon (char *fn
, int how
, int which
)
334 int open_flags
=O_WRONLY
|O_CREAT
;
337 if (how
&MONO_LOG_CON
)
338 fn
= last_lf
; /* continue with last */
339 else if ((fn
== NULL
)||(how
&MONO_LOG_DEF
))
341 if (how
&MONO_LOG_NEW
)
344 open_flags
|=O_APPEND
;
347 mono_file
= open (fn
, open_flags
, S_IWRITE
);
352 /* turn off logging of monochrome screen. */
353 void mono_logoff (void)
363 * kill_last is last log/default log
364 * always is even if open delete
366 * this is bizarrely broken, what to return re:kill_last
368 bool mono_logdel (bool kill_last
, bool always
)
381 return remove(last_lf
);
383 return remove(MONO_FILE
);
386 /* internal routines for memory access, screen parameter setting */
388 /* this is called for a page we have never visited before */
389 void _mono_init_page(int pageid
)
391 split_axis
=MONO_AXIS_X
; split_coord
=split_win
=split_lfocus
-1;
392 split_x
=split_y
=0; split_w
=MONO_WID
; split_h
=MONO_HGT
;
393 memset(split_lcoor
,0xff,4);
394 split_base
=page_addr
=(uchar
*)(MONO_BASE
+(pageid
*MONO_PAGE_SZ
));
395 split_flags
=0; split_msg
=def_wrap_msg
;
396 _inited_mpages
|=(1<<pageid
);
399 /* get memory address of x,y in current window */
400 uchar
*_maddr(int x
, int y
)
402 if ((x
<split_w
)&&(y
<split_h
))
403 return (uchar
*)split_base
+MONO_ROW
*y
+x
*2;
408 /* returns whether the gotten coordinates are or are not on the screen */
409 static bool _mget(int *x
, int *y
, bool always
)
411 if (always
||(*x
==-1)) *x
=mono_x
-split_x
;
412 if (always
||(*y
==-1)) *y
=mono_y
-split_y
;
413 return (!(((*x
)<0)||((*x
)>=MONO_WID
)||((*y
)<0)||((*y
)>=MONO_HGT
)));
416 static bool _mset(int x
, int y
)
418 if ((x
<0)||(x
>=split_w
)||(y
<0)||(y
>split_h
)) return FALSE
;
419 mono_x
=split_x
+x
; mono_y
=split_y
+y
; return TRUE
;
422 static bool _out_of_win(int x
, int y
)
424 return (((x
!=-1)&&((x
<0)||(x
>=split_w
)))||((y
!=-1)&&((y
<0)||(y
>=split_h
))));
427 /* the beginning of all mono_ external calls - returns true to really do it */
428 static bool _mono_top(void)
430 if (!mono_done_init
) mono_init ();
431 return (mono_mode
!= MONO_OFF
);
434 #define _mono_focused() (_cur_mono_focus==_cur_mono_page)
436 /* routines to get and put single characters */
437 /* returns -1 if out of range or no mono screen */
438 int mget(uchar
*s
, int x
, int y
) /* get current character (at x,y specified w/o moving cursor ) */
440 if ((_mono_top())&&(!_out_of_win(x
,y
))&&(_mget(&x
,&y
,FALSE
)))
441 return (int)(*s
=*_maddr(x
,y
));
446 int mput(uchar s
, int x
, int y
) /* put single character ( or a -1 for x means at current loc) */
448 if ((_mono_top())&&(!_out_of_win(x
,y
))&&(_mget(&x
,&y
,FALSE
)))
449 return (int)(*_maddr(x
,y
)=s
);
454 /* split screen stuff */
455 /* internal get/set correct window parameters */
456 static bool _mwin_set(int pick
,int axe
,int loc
)
458 int save_focus
=split_win
;
460 split_win
=pick
; split_base
=(uchar
*)page_addr
;
461 split_w
=MONO_WID
; split_h
=MONO_HGT
; split_x
=split_y
=0;
462 if (pick
==-1) goto no_split
;
463 if (axe
==MONO_AXIS_X
)
466 if (loc
>=MONO_WID
) goto no_split
;
468 if (pick
==1) split_w
=loc
;
469 else { split_w
=MONO_WID
-loc
; split_base
+=2*loc
; split_x
=loc
; }
474 if (loc
>=MONO_HGT
) goto no_split
;
476 if (pick
==1) split_h
=loc
;
477 else { split_h
=MONO_HGT
-loc
; split_base
+=MONO_ROW
*loc
; split_y
=loc
; }
479 split_axis
=axe
; split_coord
=loc
;
480 if (split_lfocus
==-1) /* brand new split */
481 memset(split_lcoor
,0,(MONO_WIN_MAX
*2));
482 mono_setxy(split_lcoor
[split_win
-1][0],split_lcoor
[split_win
-1][1]); /* go to correct position */
483 split_lfocus
=split_win
;
486 split_lfocus
=save_focus
;
491 /* split returns number of windows, or -1 if there are already windows */
492 int mono_split (int axe
, int loc
)
494 int save_focus
=split_lfocus
, focus
=1;
495 if (split_win
!=-1) return -1; /* already an open window */
496 if (axe
==MONO_AXIS_R
) { axe
=split_axis
; loc
=split_coord
; focus
=split_lfocus
; } else split_lfocus
=-1;
497 if (_mwin_set(focus
,axe
,loc
)) return MONO_WIN_MAX
; /* there are 2 windows */
498 else { split_lfocus
=save_focus
; return -1; }
501 /* returns false if it cannot unsplit the window */
502 bool mono_unsplit (void)
504 return (split_win
!=-1)&&(_mwin_set(-1,-1,-1));
507 /* returns whether the pickwin was succesful, ie. whether you passed legal in */
508 bool mono_setwin (int which
)
511 if ((split_win
==-1)||(which
<0)||(which
>MONO_WIN_NXT
)) return FALSE
;
513 if (which
==split_win
) return TRUE
; /* already focused on this window */
514 if (which
==MONO_WIN_NXT
)
515 if ((which
=split_win
+1)==MONO_WIN_MAX
+1) which
=1;
516 _mwin_set(which
,split_axis
,split_coord
);
520 int mono_getwin(void)
522 // printf("Axe %d, loc %d, cur %d, last %d scr %d %d %d %d\n",split_axis,split_coord,split_win,split_lfocus,split_x,split_y,split_w,split_h);
526 /* direct page set/get */
527 bool mono_setpage(int pageid
, bool focus
)
529 if (!_mono_top()) return FALSE
;
530 if (_cur_mono_page
==pageid
) return FALSE
;
531 if (pageid
>=MONO_MAX_PAGES
) return FALSE
;
532 _cur_mono_page
=pageid
;
533 if ((_inited_mpages
&(1<<pageid
))==0)
535 _mono_init_page(pageid
);
539 mono_setfocus(pageid
);
543 int mono_getpage(void)
545 return _cur_mono_page
;
548 int mono_setfocus(int pageid
)
551 if (!_mono_top()) return FALSE
;
552 if (_cur_mono_focus
==pageid
) return FALSE
;
553 if (pageid
<MONO_NUM_PAGES
)
554 { _cur_card
=MONO_CARD
; page_offs
=(int)(page_addr
-MONO_BASE
); }
556 { _cur_card
=CGA_CARD
; page_offs
=(int)(page_addr
-CGA_BASE
)>>1; }
557 // printf("Trying to set to %x on card %d\n",page_offs,_cur_card);
558 out_set(_cur_card
,SR_AHI
,(page_offs
)>>8);
559 out_set(_cur_card
,SR_ALO
,(page_offs
)&0xff);
560 // vbio_call(0x0500+pageid-(_cur_card==CGA_CARD?8:0));
564 int mono_getfocus(void)
566 return _cur_mono_focus
;
569 /* goofy turn off screen thing */
570 void mono_scr_disable(void)
572 int ostate
=inp (M_CNTRL
);
574 outp(M_CNTRL
,ostate
);
577 void mono_scr_enable(void)
579 int ostate
=inp (M_CNTRL
);
581 outp(M_CNTRL
,ostate
);
584 /* warning, bizarrly broken on some mono cards */
585 void mono_cursor(bool cur_mon
, int start
, int stop
)
588 if (start
>stop
) {int tmp
=start
; start
=stop
; stop
=tmp
; }
589 if (cur_mon
) card
=_cur_card
;
590 out_set(card
,SR_CTP
,start
);
591 out_set(card
,SR_CBT
,stop
);
594 /* screen flip stuff */
595 bool mono_flip(int pageid
)
597 int old_page
=_cur_mono_page
;
598 bool retv
=mono_setpage(pageid
,TRUE
);
599 if (retv
) _last_mono_page
=old_page
;
603 bool mono_unflip(void)
606 if (_last_mono_page
==-1) return FALSE
;
607 if ((retv
=mono_setpage(_last_mono_page
,TRUE
)) != 0)
608 _last_mono_page
=-1; /* so it wont be able to double unflip */
612 /* set the current text attributes. */
613 void mono_setattr (uchar attrib
)
618 /* set the (x,y) location of the cursor. - window relative */
619 bool mono_setxy (int x
, int y
)
621 if (!_mset(x
,y
)) return FALSE
; /* set even if screen disabled */
622 if (!_mono_top()) return FALSE
;
625 int c_offset
= MONO_WID
*mono_y
+ mono_x
;
626 out_set(_cur_card
,SR_CLH
,(c_offset
)>>8);
627 out_set(_cur_card
,SR_CLL
,(c_offset
)&0xff);
632 /* return the current x,y coordinates */
633 void mono_getxy(int *x
, int *y
)
638 /* clear the monochrome screen and reset cursor. */
639 void mono_clear (void)
642 if (!_mono_top()) return;
643 if ((split_win
!=-1)&&(split_axis
==MONO_AXIS_X
))
644 for (i
=0; i
<MONO_HGT
; i
++)
645 smemset(split_base
+i
*MONO_ROW
,mono_attr
<<8,split_w
);
647 smemset(split_base
,mono_attr
<<8,MONO_WID
*split_h
);
651 /* scroll the monochrome screen by n lines, blanking bottom n lines. */
652 void mono_scroll (int n
)
655 uchar
*src
, *dst
, *bot
;
657 if (!_mono_top()) return;
659 if ((split_flags
==0)||((split_flags
&MONO_FLG_WRAPCLEAR
)==MONO_FLG_WRAPCLEAR
))
660 { mono_clear (); return; }
662 if (split_flags
&MONO_FLG_WRAP
)
668 if (split_flags
&MONO_FLG_CLEAR
)
669 smemset(split_base
+y
*MONO_ROW
,mono_attr
<<8,(split_h
-y
-1)*MONO_WID
);
672 } /* now at top of window */
675 if (split_flags
&MONO_FLG_CLEAR
)
676 smemset(split_base
,mono_attr
<<8,n
*MONO_WID
);
684 src
= split_base
+n
*MONO_ROW
;
686 bot
= split_base
+(split_h
-n
)*MONO_ROW
;
687 if ((split_win
!=-1)&&(split_axis
==MONO_AXIS_X
))
689 for (i
=0; i
<(split_h
-n
); i
++)
690 memmove(dst
+i
*MONO_ROW
,src
+i
*MONO_ROW
,2*split_w
);
692 smemset(bot
+i
*MONO_ROW
,mono_attr
<<8,split_w
);
696 memmove (dst
, src
, (split_h
-n
)*MONO_ROW
);
697 smemset (bot
, mono_attr
<<8, n
*MONO_WID
);
704 // return ((mono_spc_func!=NULL)||((mono_file!=-1)&&(!mono_screen||(mlog&split_win))));
705 return (mono_spc_func
!=NULL
) ||
707 (!mono_screen
||((mlog
==0)||(mlog
&split_win
))));
710 // doesnt correctly support split width stuff....
711 int _mscroll_msg(int *x
, int *y
)
713 if (split_flags
&MONO_FLG_CLEAR
)
714 smemset(split_base
+(*y
)*MONO_ROW
,mono_attr
<<8,split_w
);
715 if ((split_flags
&MONO_FLG_MSG
)&&(split_msg
!=NULL
))
717 int old_y
=*y
, chars_in_msg
=strlen(split_msg
);
720 if ((chars_in_msg
>0)&&(split_msg
[chars_in_msg
-1]=='\n'))
721 { smemset(split_base
+(*y
)*MONO_ROW
,mono_attr
<<8,split_w
); chars_in_msg
--; }
722 _mprint(split_msg
,chars_in_msg
);
729 int _mscroll_us(int n
, int *x
, int *y
)
743 /* internal print a buffer a length n to the mono screen */
744 int _mprint(const char *s
, int n
)
747 uchar
*p
; /* pointer to current line. */
750 write (mono_file
, s
, n
); /* write even if no screen */
752 if (mono_to_debugger
)
753 OutputDebugString (s
);
756 _mono_spc_check((char *)s
,n
);
758 if (mono_mode
==MONO_OFF
|| !mono_screen
) return n
;/* no screen, so dont print */
760 _mget(&cur_x
,&cur_y
,TRUE
);
763 p
= _maddr(cur_x
,cur_y
);
768 _mscroll_us(1,&cur_x
,&cur_y
);
786 if (cur_x
< split_w
-1)
789 _mscroll_us(1,&cur_x
,&cur_y
);
793 mono_setxy (cur_x
, cur_y
);
797 /* printf to the monochrome screen. has the same arguments and return value
798 as printf (returns number of items printed). uses vsprintf to print into
799 a 1k buffer which is then transferred to the mono screen char by char. */
800 int mprintf(const char *fmt
, ...)
816 n
=lg_vsprintf(buf
, fmt
, ap
);
819 /* punt if there was an error. */
826 /* write this string if we're logging. */
833 /* print s with no formating, it's just text folks, just text, nothing to be seen here */
834 int mprint(const char *s
)
844 ret
= _mprint(s
,strlen(s
));
849 /* dump screen to fn, erase if set */
850 bool mono_dump(char *fn
, bool erase_it
, bool readable
)
852 int open_flags
=O_WRONLY
|O_CREAT
|O_BINARY
, mono_hnd
;
853 int x
,y
,write_wid
=MONO_WID
;
855 char on_line
[MONO_WID
+2];
857 if (!_mono_top()) return FALSE
;
858 if (erase_it
) open_flags
|=O_TRUNC
; else open_flags
|=O_APPEND
;
859 if (fn
==NULL
) fn
=MONO_DUMP
;
860 if ((mono_hnd
= open (fn
, open_flags
, S_IWRITE
))==-1) return FALSE
;
861 if (readable
) { on_line
[MONO_WID
]=0x0D; on_line
[MONO_WID
+1]=0x0A; write_wid
+=2; }
862 for (y
=0; y
<MONO_HGT
; y
++)
864 cur_char
=(uchar
*)page_addr
+MONO_ROW
*y
;
865 for (x
=0; x
<MONO_WID
; x
++)
866 on_line
[x
]=*(cur_char
+2*x
);
867 write(mono_hnd
,on_line
,write_wid
);