diff --git a/README.md b/README.md index 35d3f63bb..73b36ad9c 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ platforms. Build instructions are in the README.md file for each platform: - [DOS] +- [DOS with full VGA support] - [OS/2] - [SDL 1.x] - [SDL 2.x] @@ -58,6 +59,7 @@ William McBrine [History]: docs/HISTORY.md [docs]: docs/README.md [DOS]: dos/README.md +[DOS with full VGA support]: dosvga/README.md [OS/2]: os2/README.md [SDL 1.x]: sdl1/README.md [SDL 2.x]: sdl2/README.md diff --git a/demos/testcurs.c b/demos/testcurs.c index d41feb049..ddbb5d75c 100644 --- a/demos/testcurs.c +++ b/demos/testcurs.c @@ -25,6 +25,9 @@ #if HAVE_WIDE # include +# ifdef __DJGPP__ +static size_t wcslen(const wchar_t *); +# endif #endif #if defined(PDCURSES) && !defined(XCURSES) @@ -1209,7 +1212,7 @@ void gradient(int tmarg) move(tmarg + 3 + i, (COLS - 69) / 2); for (j = 0; j < len; j++) { - const int oval = j * 1000 / len; + const int oval = (int)(j * 1000L / len); const int reverse = 1000 - oval; if (!i) @@ -1380,3 +1383,13 @@ void display_menu(int old_option, int new_option) "Use Up and Down Arrows to select - Enter to run - Q to quit"); refresh(); } + +#if HAVE_WIDE && defined(__DJGPP__) +/* wide character function missing in DJGPP */ +static size_t wcslen(const wchar_t *str) +{ + size_t i; + for (i = 0; str[i] != L'\0'; ++i) {} + return i; +} +#endif diff --git a/dosvga/Makefile b/dosvga/Makefile new file mode 100644 index 000000000..8f82cbcbc --- /dev/null +++ b/dosvga/Makefile @@ -0,0 +1,89 @@ +# GNU Makefile for PDCurses - DOS +# +# Usage: make [-f path\Makefile] [DEBUG=Y] [WIDE=Y] [target] +# +# where target can be any of: +# [all|libs|demos|pdcurses.a|testcurs.exe...] + +O = o +E = .exe +RM = del + +ifndef PDCURSES_SRCDIR + PDCURSES_SRCDIR = .. +endif + +include $(PDCURSES_SRCDIR)/common/libobjs.mif + +osdir = $(PDCURSES_SRCDIR)/dosvga + +PDCURSES_DOS_H = $(osdir)/pdcdos.h + +CC = gcc + +ifeq ($(DEBUG),Y) + CFLAGS = -g -Wall -DPDCDEBUG + LDFLAGS = -g +else + CFLAGS = -O2 -Wall + LDFLAGS = +endif + +CFLAGS += -I$(PDCURSES_SRCDIR) + +ifeq ($(WIDE),Y) + CFLAGS += -DPDC_WIDE +endif + +LINK = gcc + +LIBEXE = ar +LIBFLAGS = rcv + +LIBCURSES = pdcurses.a + +.PHONY: all libs clean demos dist + +all: libs + +libs: $(LIBCURSES) + +clean: + -$(RM) *.o + -$(RM) *.a + -$(RM) *.exe + +demos: $(DEMOS) +ifneq ($(DEBUG),Y) + strip *.exe +endif + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + $(LIBEXE) $(LIBFLAGS)S $@ addch.o addchstr.o addstr.o attr.o beep.o bkgd.o border.o clear.o color.o debug.o delch.o deleteln.o + $(LIBEXE) $(LIBFLAGS)S $@ getch.o getstr.o getyx.o inch.o inchstr.o initscr.o inopts.o insch.o insstr.o instr.o kernel.o keyname.o + $(LIBEXE) $(LIBFLAGS)S $@ mouse.o move.o outopts.o overlay.o pad.o panel.o pdcclip.o pdcdisp.o pdcgetsc.o pdckbd.o pdcscrn.o pdcsetsc.o + $(LIBEXE) $(LIBFLAGS) $@ pdcutil.o printw.o refresh.o scanw.o scr_dump.o scroll.o slk.o termattr.o touch.o util.o window.o + +$(LIBOBJS) $(PDCOBJS) : $(PDCURSES_HEADERS) +$(PDCOBJS) : $(PDCURSES_DOS_H) +$(DEMOS) : $(PDCURSES_CURSES_H) $(LIBCURSES) +panel.o : $(PANEL_HEADER) + +$(LIBOBJS) : %.o: $(srcdir)/%.c + $(CC) -c $(CFLAGS) $< + +$(PDCOBJS) : %.o: $(osdir)/%.c + $(CC) -c $(CFLAGS) $< + +firework.exe ozdemo.exe rain.exe testcurs.exe worm.exe xmas.exe \ +ptest.exe: %.exe: $(demodir)/%.c + $(CC) $(CFLAGS) -o$@ $< $(LIBCURSES) + +tuidemo.exe: tuidemo.o tui.o + $(LINK) $(LDFLAGS) -o$@ tuidemo.o tui.o $(LIBCURSES) + +tui.o: $(demodir)/tui.c $(demodir)/tui.h $(PDCURSES_CURSES_H) + $(CC) -c $(CFLAGS) -I$(demodir) -o$@ $< + +tuidemo.o: $(demodir)/tuidemo.c $(PDCURSES_CURSES_H) + $(CC) -c $(CFLAGS) -I$(demodir) -o$@ $< diff --git a/dosvga/Makefile.bcc b/dosvga/Makefile.bcc new file mode 100644 index 000000000..4cc3a8ce9 --- /dev/null +++ b/dosvga/Makefile.bcc @@ -0,0 +1,82 @@ +# Borland Makefile for PDCurses - DOS +# +# Usage: make -f [path\]Makefile.bcc [DEBUG=] [WIDE=Y] [MODEL=c|h|l|m|s] [target] +# +# where target can be any of: +# [all|demos|pdcurses.lib|testcurs.exe...] + +!ifndef MODEL +MODEL = l +!endif + +O = obj +E = .exe +RM = del + +!ifndef PDCURSES_SRCDIR +PDCURSES_SRCDIR = .. +!endif + +!include $(PDCURSES_SRCDIR)\common\libobjs.mif + +osdir = $(PDCURSES_SRCDIR)\dosvga + +!ifdef DEBUG +CFLAGS = -N -v -y -DPDCDEBUG +!else +CFLAGS = -O +!endif + +!ifdef WIDE +WIDEOPT = -DPDC_WIDE +!else +WIDEOPT = +!endif + +CPPFLAGS = -I$(PDCURSES_SRCDIR) + +BUILD = $(CC) -1- -G -d -w-par -c -m$(MODEL) $(CFLAGS) $(CPPFLAGS) $(WIDEOPT) + +LIBEXE = tlib /C /E + +LIBCURSES = pdcurses.lib + +all: $(LIBCURSES) + +clean: + -$(RM) *.obj + -$(RM) *.lib + -$(RM) *.map + -$(RM) *.exe + +demos: $(LIBCURSES) $(DEMOS) + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + -$(RM) $@ + $(LIBEXE) $@ @$(PDCURSES_SRCDIR)\common\borland.lrf + +.autodepend + +{$(srcdir)\}.c.obj: + $(BUILD) $< + +{$(osdir)\}.c.obj: + $(BUILD) $< + +{$(demodir)\}.c.obj: + $(BUILD) $< + +.c.obj: + $(BUILD) $< + +.obj.exe: + $(CC) -m$(MODEL) -e$@ $** $(LIBCURSES) + +tuidemo.exe: tuidemo.obj tui.obj $(LIBCURSES) + $(CC) -m$(MODEL) -e$@ $** + +tui.obj: $(demodir)\tui.c $(demodir)\tui.h $(PDCURSES_CURSES_H) + $(BUILD) -I$(demodir) $(demodir)\tui.c + +tuidemo.obj: $(demodir)\tuidemo.c $(PDCURSES_CURSES_H) + $(BUILD) -I$(demodir) $(demodir)\tuidemo.c diff --git a/dosvga/Makefile.wcc b/dosvga/Makefile.wcc new file mode 100644 index 000000000..569d052e5 --- /dev/null +++ b/dosvga/Makefile.wcc @@ -0,0 +1,39 @@ +# Watcom Makefile for PDCurses - DOS +# +# Usage: wmake -f [path\]Makefile.wcc [DEBUG=Y] [WIDE=Y] [MODEL=c|h|l|m|s|f] [target] +# +# where target can be any of: +# [all|demos|pdcurses.lib|testcurs.exe...] + +!ifndef MODEL +MODEL = l +!endif + +!ifdef %PDCURSES_SRCDIR +PDCURSES_SRCDIR = $(%PDCURSES_SRCDIR) +!else +PDCURSES_SRCDIR = .. +!endif + +osdir = $(PDCURSES_SRCDIR)/dosvga + +!ifeq MODEL f +CC = wcc386 +TARGET = dos4g +!else +CC = wcc +TARGET = dos +!endif + +CFLAGS = -bt=$(TARGET) -m$(MODEL) + +!ifeq WIDE Y +CFLAGS += -DPDC_WIDE +!endif + +!include $(PDCURSES_SRCDIR)/common/watcom.mif + +$(LIBCURSES) : $(LIBOBJS) $(PDCOBJS) + %write wccdos.lrf $(LIBOBJS) $(PDCOBJS) + $(LIBEXE) $@ @wccdos.lrf + -$(RM) wccdos.lrf diff --git a/dosvga/README.md b/dosvga/README.md new file mode 100644 index 000000000..582cc62a8 --- /dev/null +++ b/dosvga/README.md @@ -0,0 +1,58 @@ +PDCurses for DOS +================ + +This directory contains PDCurses source code files specific to the +VGA-capable DOS port. + + +Building +-------- + +- Choose the appropriate makefile for your compiler: + + Makefile - DJGPP + Makefile.bcc - Borland C++ + Makefile.wcc - Watcom + +- For 16-bit compilers, you can change the memory MODEL as a command- + line option. (Large model is the default, and recommended.) With + Watcom, specifying "MODEL=f" (flat) will automatically switch to a + 32-bit build. + +- Optionally, you can build in a different directory than the platform + directory by setting PDCURSES_SRCDIR to point to the directory where + you unpacked PDCurses, and changing to your target directory: + + set PDCURSES_SRCDIR=c:\pdcurses + +- Build it: + + make -f makefile + + (For Watcom, use "wmake" instead of "make".) You'll get the library + (pdcurses.lib or .a, depending on your compiler) and a lot of object + files. Add the target "demos" to build the sample programs. + + You can also give the optional parameter "WIDE=Y", to build the + library with wide-character (Unicode) support: + + wmake -f Makefile.wcc WIDE=Y + + (WIDE=Y is untested on the Borland compiler.) + +The font can be set via the environment variable PDC_FONT. The font must +be in the PSF format, version 2. + + +Distribution Status +------------------- + +The files in this directory are released to the public domain. + + +Acknowledgements +---------------- + +Watcom C port was provided by Pieter Kunst + +DJGPP port was provided by David Nugent diff --git a/dosvga/cp437.h b/dosvga/cp437.h new file mode 100644 index 000000000..9e3938c20 --- /dev/null +++ b/dosvga/cp437.h @@ -0,0 +1,184 @@ + +static const unsigned short cp437_to_unicode[256] = { + 0, + 0x263a, /* 1 smiling face */ + 0x263b, /* 2 smiling face inverted */ + 0x2665, /* 3 heart */ + 0x2666, /* 4 diamond */ + 0x2663, /* 5 club */ + 0x2660, /* 6 spade */ + 0x2024, /* 7 small bullet */ + 0x25d8, /* 8 inverted bullet */ + 0x25bc, /* 9 hollow bullet */ + 0x25d9, /* 10 inverted hollow bullet */ + 0x2642, /* 11 male/Mars symbol */ + 0x2640, /* 12 female/Venus symbol */ + 0x266a, /* 13 eighth note */ + 0x266c, /* 14 two sixteenth notes */ + 0x263c, /* 15 splat */ + 0x25b6, /* 16 right-pointing triangle */ + 0x25c0, /* 17 left-pointing triangle */ + 0x2195, /* 18 double up/down arrow */ + 0x203c, /* 19 double exclamation !! */ + 0x00b6, /* 20 pilcrow */ + 0xa7, /* 21 */ + 0x2582, /* 22 lower 1/3 block */ + 0x280d, /* 23 double up/down arrow */ + 0x2191, /* 24 up arrow */ + 0x2193, /* 25 down arrow */ + 0x2192, /* 26 right arrow */ + 0x2190, /* 27 left arrow */ + 0x2319, /* 28 */ + 0x280c, /* 29 left & right arrow */ + 0x25b2, /* 30 up triangle */ + 0x25bc, /* 31 down triangle */ + + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, + + 0x2302, /* 127 */ + 0x00c7, /* 128 */ + 0x00fc, /* 129 */ + 0x00e9, /* 130 */ + 0x00e2, /* 131 */ + 0x00e4, /* 132 */ + 0x00e0, /* 133 */ + 0x00e5, /* 134 */ + 0x00e7, /* 135 */ + 0x00ea, /* 136 */ + 0x00eb, /* 137 */ + 0x00e8, /* 138 */ + 0x00ef, /* 139 */ + 0x00ee, /* 140 */ + 0x00ec, /* 141 */ + 0x00c4, /* 142 */ + 0x00c5, /* 143 */ + + 0x00c9, /* 144 */ + 0x00e6, /* 145 */ + 0x00c6, /* 146 */ + 0x00f4, /* 147 */ + 0x00f5, /* 148 */ + 0x00f2, /* 149 */ + 0x00fb, /* 150 */ + 0x00f9, /* 151 */ + 0x00ff, /* 152 */ + 0x00d6, /* 153 */ + 0x00dc, /* 154 */ + 0x00a2, /* 155 */ + 0x00a3, /* 156 */ + 0x00a5, /* 157 */ + 0x20a7, /* 158 */ + 0x0192, /* 159 */ + + 0x00e1, /* 160 */ + 0x00ed, /* 161 */ + 0x00f3, /* 162 */ + 0x00fa, /* 163 */ + 0x00f1, /* 164 */ + 0x00d1, /* 165 */ + 0x00aa, /* 166 */ + 0x00ba, /* 167 */ + 0x00bf, /* 168 */ + 0x2310, /* 169 */ + 0x00ac, /* 170 */ + 0x00bd, /* 171 */ + 0x00bc, /* 172 */ + 0x00a1, /* 173 */ + 0x00ab, /* 174 */ + 0x00bb, /* 175 */ + + 0x2591, /* 176 */ + 0x2592, /* 177 */ + 0x2593, /* 178 */ + 0x2502, /* 179 */ + 0x2524, /* 180 */ + 0x2561, /* 181 */ + 0x2562, /* 182 */ + 0x2556, /* 183 */ + 0x2555, /* 184 */ + 0x2563, /* 185 */ + 0x2561, /* 186 */ + 0x2557, /* 187 */ + 0x255d, /* 188 */ + 0x255c, /* 189 */ + 0x255b, /* 190 */ + 0x2510, /* 191 */ + + 0x2514, /* 192 */ + 0x2534, /* 193 */ + 0x252c, /* 194 */ + 0x251c, /* 195 */ + 0x2500, /* 196 */ + 0x253c, /* 197 */ + 0x255e, /* 198 */ + 0x255f, /* 199 */ + 0x255a, /* 200 */ + 0x2554, /* 201 */ + 0x2569, /* 202 */ + 0x2568, /* 203 */ + 0x2560, /* 204 */ + 0x2550, /* 205 */ + 0x256c, /* 206 */ + 0x2567, /* 207 */ + + 0x2568, /* 208 */ + 0x2564, /* 209 */ + 0x2565, /* 210 */ + 0x2559, /* 211 */ + 0x2558, /* 212 */ + 0x2552, /* 213 */ + 0x2553, /* 214 */ + 0x256b, /* 215 */ + 0x256a, /* 216 */ + 0x2518, /* 217 */ + 0x250c, /* 218 */ + 0x2588, /* 219 */ + 0x2584, /* 220 */ + 0x258c, /* 221 */ + 0x2590, /* 222 */ + 0x2580, /* 223 */ + + 0x03b1, /* 224 */ + 0x00df, /* 225 */ + 0x0393, /* 226 */ + 0x03c0, /* 227 */ + 0x03a3, /* 228 */ + 0x03c3, /* 229 */ + 0x00b5, /* 230 */ + 0x03c4, /* 231 */ + 0x03a6, /* 232 */ + 0x0398, /* 233 */ + 0x03a9, /* 234 */ + 0x03b4, /* 235 */ + 0x221e, /* 236 */ + 0x036c, /* 237 */ + 0x03b5, /* 238 */ + 0x2229, /* 239 */ + + 0x2261, /* 240 */ + 0x00b1, /* 241 */ + 0x2265, /* 242 */ + 0x2264, /* 243 */ + 0x2320, /* 244 */ + 0x2321, /* 245 */ + 0x00f7, /* 246 */ + 0x2248, /* 247 */ + 0x00b0, /* 248 */ + 0x2219, /* 249 */ + 0x00b7, /* 250 */ + 0x221a, /* 251 */ + 0x207f, /* 252 */ + 0x00b2, /* 253 */ + 0x25a0, /* 254 */ + 0x00a0 }; /* 255 */ diff --git a/dosvga/font.h b/dosvga/font.h new file mode 100644 index 000000000..1a4c2d67b --- /dev/null +++ b/dosvga/font.h @@ -0,0 +1,454 @@ +/* Converted from thin-14 using mk_font.c (q.v.) */ +/* Fonts found in https://hack.org/mc/fonts/vgafonts.tar.gz */ +static const unsigned char font_bytes[3584] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x82, 0xaa, 0x82, 0xaa, 0xba, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x7c, + 0xfe, 0xd6, 0xfe, 0xba, 0xc6, 0x7c, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0xee, 0xee, 0xfe, + 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0xfe, 0x7c, + 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x38, 0x38, 0x10, 0xfe, 0xee, 0x54, 0x10, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x7c, 0xfe, 0xfe, 0xee, 0x54, 0x10, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, + 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x18, 0x24, 0x42, 0x42, 0x42, 0x24, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, + 0xdb, 0xbd, 0xbd, 0xbd, 0xdb, 0xe7, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x0e, 0x06, 0x0a, + 0x70, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x10, + 0x10, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x1c, 0x14, 0x14, 0x10, 0x10, 0x30, 0x70, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x38, + 0x2c, 0x66, 0xe2, 0xc2, 0x06, 0x0e, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x54, 0x38, 0x44, + 0xc6, 0x44, 0x38, 0x54, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xfe, 0xf8, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x3e, 0xfe, 0x3e, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, + 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7e, 0x8a, 0x8a, 0x8a, 0x7a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x40, 0x30, 0x28, 0x18, 0x04, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0x10, + 0x10, 0x7c, 0x38, 0x10, 0x00, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x38, 0x7c, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x38, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x0c, 0xfe, 0x0c, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x60, + 0xfe, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, + 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0xfe, 0x28, + 0x28, 0x28, 0xfe, 0x28, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x7c, 0x92, 0x90, 0x7c, 0x12, + 0x92, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0xa2, 0xa4, 0x48, 0x10, 0x24, 0x4a, 0x8a, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, + 0x48, 0x30, 0x50, 0x8a, 0x84, 0x84, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x10, 0x7c, 0x10, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0xfe, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x8c, 0x94, 0xa4, 0xc4, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, + 0x04, 0x08, 0x30, 0x40, 0x80, 0x80, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, 0x04, 0x04, + 0x38, 0x04, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x18, 0x28, 0x48, 0x88, 0x88, + 0xfe, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x80, 0x80, 0x80, 0xf8, 0x04, 0x04, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x84, + 0x80, 0x80, 0xf8, 0x84, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x04, 0x04, 0x08, + 0x10, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x84, 0x84, 0x78, 0x84, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x84, 0x84, 0x84, 0x7c, 0x04, 0x04, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x00, 0x00, 0x18, 0x18, 0x08, 0x10, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x82, 0x02, + 0x0c, 0x10, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x42, 0x9a, 0xa6, 0xa6, 0x9a, + 0x80, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x28, 0x44, 0x82, 0x82, 0xfe, 0x82, 0x82, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x42, + 0x42, 0x42, 0x7c, 0x42, 0x42, 0x42, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x44, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x80, 0x80, 0x80, 0xf8, 0x80, 0x80, 0x80, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, + 0x80, 0x80, 0xf8, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, + 0x8e, 0x82, 0x82, 0x42, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, 0xfe, 0x82, + 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x84, 0x88, 0x90, + 0xe0, 0x90, 0x88, 0x84, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0xc6, 0xaa, 0x92, 0x92, 0x82, 0x82, 0x82, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, + 0xc2, 0xa2, 0x92, 0x8a, 0x86, 0x82, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x82, 0x82, 0x82, 0xfc, 0x80, + 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x82, 0x82, 0x82, 0x92, 0x8a, 0x44, + 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x82, + 0x82, 0x82, 0xfc, 0x90, 0x88, 0x84, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x82, 0x80, 0x80, + 0x7c, 0x02, 0x02, 0x82, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfe, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, + 0x82, 0x44, 0x44, 0x28, 0x28, 0x10, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x82, 0x82, 0x82, + 0x92, 0x92, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x82, 0x82, 0x44, 0x28, 0x10, 0x28, + 0x44, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x82, 0x44, 0x28, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, + 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0x08, 0x10, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, + 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, + 0x80, 0xb8, 0xc4, 0x84, 0x84, 0xc4, 0xb8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x80, 0x80, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x04, 0x04, 0x74, 0x8c, 0x84, + 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x84, 0xfc, 0x80, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, + 0x20, 0xf8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, + 0x8c, 0x8c, 0x8c, 0x74, 0x04, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x80, 0xb8, 0xc4, 0x84, + 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x88, + 0x70, 0x00, 0x00, 0x00, 0x80, 0x80, 0x84, 0x88, + 0x90, 0xa0, 0xd0, 0x88, 0x84, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xec, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0xc4, 0x84, 0x84, 0x84, 0x84, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0xc4, 0x84, + 0xc4, 0xb8, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x74, 0x8c, 0x84, 0x8c, 0x74, + 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0xc4, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x60, 0x18, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x20, 0xf8, 0x20, 0x20, + 0x20, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, + 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x82, 0x82, 0x44, 0x44, 0x28, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, + 0x82, 0x92, 0x92, 0xaa, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x48, 0x30, + 0x30, 0x48, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x8c, 0x74, + 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x08, 0x10, 0x20, 0x40, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x10, + 0x20, 0x10, 0x10, 0x10, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x08, 0x08, 0x08, 0x04, 0x08, 0x08, 0x08, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x98, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x28, 0x44, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x42, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x42, 0x3c, 0x04, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, + 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x10, + 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x00, 0x78, + 0x04, 0x7c, 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x78, 0x04, 0x7c, + 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x08, 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, + 0x7a, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x10, + 0x00, 0x78, 0x04, 0x7c, 0x84, 0x84, 0x7a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, + 0x84, 0x80, 0x80, 0x84, 0x78, 0x08, 0x70, 0x00, + 0x00, 0x30, 0x48, 0x84, 0x00, 0x78, 0x84, 0xfc, + 0x80, 0x80, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, + 0x00, 0x78, 0x84, 0xfc, 0x80, 0x80, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x30, + 0x10, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x28, 0x44, 0x00, 0x30, 0x10, 0x10, + 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x10, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x10, 0x28, 0x44, 0x82, 0xfe, 0x82, 0x82, 0x00, + 0x00, 0x00, 0x10, 0x28, 0x10, 0x00, 0x10, 0x28, + 0x44, 0x82, 0xfe, 0x82, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x18, 0x20, 0x00, 0xfc, 0x80, 0x80, 0xf0, + 0x80, 0x80, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xec, 0x12, 0x7c, 0x90, 0x90, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, + 0x50, 0x90, 0x9e, 0xf0, 0x90, 0x90, 0x9e, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x48, 0x84, 0x00, 0x78, + 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x78, 0x84, 0x84, + 0x84, 0x84, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x10, 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x30, 0x48, 0x84, + 0x00, 0x84, 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x84, + 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x84, 0x84, 0x84, + 0x8c, 0x74, 0x04, 0x84, 0x78, 0x00, 0x00, 0x00, + 0x44, 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x78, 0x84, + 0x80, 0x80, 0x84, 0x78, 0x10, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x78, 0x84, 0x80, 0x40, 0xf8, 0x20, + 0x20, 0x62, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x44, 0x28, 0x10, 0x7c, 0x10, 0x7c, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x88, + 0x88, 0xf0, 0x88, 0x9c, 0x88, 0x88, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x20, 0x20, + 0x78, 0x20, 0x20, 0x20, 0x20, 0x20, 0xc0, 0x00, + 0x00, 0x00, 0x18, 0x20, 0x00, 0x78, 0x04, 0x7c, + 0x84, 0x84, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x20, 0x00, 0x30, 0x10, 0x10, 0x10, 0x10, + 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, + 0x00, 0x78, 0x84, 0x84, 0x84, 0x84, 0x78, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x84, + 0x84, 0x84, 0x84, 0x8c, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0x98, 0x00, 0xb8, 0xc4, 0x84, + 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x4c, 0x82, 0xc2, 0xa2, 0x92, 0x8a, 0x86, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x08, + 0x38, 0x48, 0x34, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, + 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x10, 0x10, 0x60, 0x80, + 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0x80, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x02, 0x02, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x48, 0x50, + 0x20, 0x5c, 0x04, 0x08, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0xc0, 0x48, 0x50, 0x20, 0x54, + 0x14, 0x1e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, + 0x24, 0x48, 0x90, 0x48, 0x24, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x48, 0x24, + 0x12, 0x24, 0x48, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, + 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0xaa, 0x54, + 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, + 0xaa, 0x54, 0xaa, 0x54, 0x76, 0xdc, 0x76, 0xdc, + 0x76, 0xdc, 0x76, 0xdc, 0x76, 0xdc, 0x76, 0xdc, + 0x76, 0xdc, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0xf8, 0x08, 0xf8, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0xf4, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x08, 0xf8, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x14, 0x14, + 0x14, 0x14, 0x14, 0xf4, 0x04, 0xf4, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x04, 0xf4, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xf4, 0x04, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, + 0x08, 0xf8, 0x08, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x17, 0x10, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x10, 0x17, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xf7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x17, 0x14, 0x17, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xf7, 0x00, 0xf7, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x0f, 0x08, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x08, 0x0f, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1f, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0xff, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x90, 0x90, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x44, 0x84, 0xb8, 0x88, 0x84, 0x84, 0xa4, + 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x82, + 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, + 0xa4, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x42, 0x20, 0x10, 0x08, 0x10, + 0x20, 0x42, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7e, 0x88, 0x88, 0x88, 0x88, + 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, + 0xa0, 0x20, 0x20, 0x28, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x10, 0x7c, 0x92, 0x92, 0x92, + 0x7c, 0x10, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x44, 0x82, 0xfe, 0x82, 0x44, 0x38, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, + 0x82, 0x82, 0x82, 0x44, 0x28, 0xaa, 0xee, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x24, 0x10, 0x78, + 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x92, 0x92, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb8, 0x44, 0xa2, 0x92, 0x8a, 0x44, 0x3a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x40, 0x80, 0xfe, 0x80, 0x40, 0x3e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0xfe, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x10, 0x10, 0xfe, 0x10, 0x10, 0x10, 0x00, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, + 0x08, 0x04, 0x08, 0x10, 0x20, 0x00, 0x7c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40, + 0x20, 0x10, 0x08, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x12, 0x16, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xd0, 0x90, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0xfe, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x98, + 0x00, 0x64, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0x48, 0x48, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, + 0x90, 0x50, 0x30, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x58, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x24, 0x08, 0x10, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, + 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +int PDC_font_height = 14; +int PDC_font_width = 8; diff --git a/dosvga/pdcclip.c b/dosvga/pdcclip.c new file mode 100644 index 000000000..260669510 --- /dev/null +++ b/dosvga/pdcclip.c @@ -0,0 +1,132 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#include + +/*man-start************************************************************** + +clipboard +--------- + +### Synopsis + + int PDC_getclipboard(char **contents, long *length); + int PDC_setclipboard(const char *contents, long length); + int PDC_freeclipboard(char *contents); + int PDC_clearclipboard(void); + +### Description + + PDC_getclipboard() gets the textual contents of the system's + clipboard. This function returns the contents of the clipboard in the + contents argument. It is the responsibility of the caller to free the + memory returned, via PDC_freeclipboard(). The length of the clipboard + contents is returned in the length argument. + + PDC_setclipboard copies the supplied text into the system's + clipboard, emptying the clipboard prior to the copy. + + PDC_clearclipboard() clears the internal clipboard. + +### Return Values + + indicator of success/failure of call. + PDC_CLIP_SUCCESS the call was successful + PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for + the clipboard contents + PDC_CLIP_EMPTY the clipboard contains no text + PDC_CLIP_ACCESS_ERROR no clipboard support + +### Portability + X/Open ncurses NetBSD + PDC_getclipboard - - - + PDC_setclipboard - - - + PDC_freeclipboard - - - + PDC_clearclipboard - - - + +**man-end****************************************************************/ + +/* global clipboard contents, should be NULL if none set */ + +static char *pdc_DOS_clipboard = NULL; + +int PDC_getclipboard(char **contents, long *length) +{ + int len; + + PDC_LOG(("PDC_getclipboard() - called\n")); + + if (!pdc_DOS_clipboard) + return PDC_CLIP_EMPTY; + + len = strlen(pdc_DOS_clipboard); + *contents = malloc(len + 1); + if (!*contents) + return PDC_CLIP_MEMORY_ERROR; + + strcpy(*contents, pdc_DOS_clipboard); + *length = len; + + return PDC_CLIP_SUCCESS; +} + +int PDC_setclipboard(const char *contents, long length) +{ + PDC_LOG(("PDC_setclipboard() - called\n")); + + if (pdc_DOS_clipboard) + { + free(pdc_DOS_clipboard); + pdc_DOS_clipboard = NULL; + } + + if (contents) + { + pdc_DOS_clipboard = malloc(length + 1); + if (!pdc_DOS_clipboard) + return PDC_CLIP_MEMORY_ERROR; + + strcpy(pdc_DOS_clipboard, contents); + } + + return PDC_CLIP_SUCCESS; +} + +int PDC_freeclipboard(char *contents) +{ + PDC_LOG(("PDC_freeclipboard() - called\n")); + + /* should we also free empty the system clipboard? probably not */ + + if (contents) + { + /* NOTE: We free the memory, but we can not set caller's pointer + to NULL, so if caller calls again then will try to access + free'd memory. We 1st overwrite memory with a string so if + caller tries to use free memory they won't get what they + expect & hopefully notice. */ + + /* memset(contents, 0xFD, strlen(contents)); */ + + if (strlen(contents) >= strlen("PDCURSES")) + strcpy(contents, "PDCURSES"); + + free(contents); + } + + return PDC_CLIP_SUCCESS; +} + +int PDC_clearclipboard(void) +{ + PDC_LOG(("PDC_clearclipboard() - called\n")); + + if (pdc_DOS_clipboard) + { + free(pdc_DOS_clipboard); + pdc_DOS_clipboard = NULL; + } + + return PDC_CLIP_SUCCESS; +} diff --git a/dosvga/pdcdisp.c b/dosvga/pdcdisp.c new file mode 100644 index 000000000..bbfea83cb --- /dev/null +++ b/dosvga/pdcdisp.c @@ -0,0 +1,689 @@ +/* PDCurses */ + +#include "pdcdos.h" +#ifdef PDC_WIDE +# include "../common/acsuni.h" +#else +# include "../common/acs437.h" +#endif + +#ifdef __DJGPP__ +#include +#include +#endif + +#ifdef __WATCOMC__ +/* For Watcom, we need conio.h, but the Curses macro for getch fouls it up */ +#undef getch +#include +#define outportb(a, b) outp((a), (b)) +#endif + +/* Maximum run of characters per call to _transform_line_[48] */ +#ifdef PDC_FLAT +# define MAX_PACKET 512 /* optimize for speed */ +#else +# define MAX_PACKET 32 /* keep stack usage reasonable */ +#endif + +static unsigned long _get_colors(chtype glyph); +static unsigned long _address_4(int row, int col); +static unsigned long _address_8(int row, int col); +static void _video_read(void *data, unsigned long addr, size_t size); +static void _video_write(unsigned long addr, const void *data, size_t size); +static unsigned _set_window(unsigned window, unsigned long addr); + +/* position hardware cursor at (y, x) */ + +void PDC_gotoyx(int row, int col) +{ + if (PDC_state.cursor_visible) + PDC_private_cursor_off(); + PDC_private_cursor_on(row, col); +} + +/* Draw a run of characters with the same colors */ +/* Used with 4 bit pixels only */ + +static void _new_packet(unsigned long colors, int lineno, int x, int len, const chtype *srcp) +{ + struct + { + const unsigned char *font_addr; + } glyphs[MAX_PACKET]; + int i; + + /* Colors */ + unsigned fore = colors & 0xF; + unsigned back = (colors >> 16) & 0xF; + + /* Width of a character in bytes */ + unsigned ch_width = (PDC_state.font_width + 7) / 8; + + /* Bit to set for A_RIGHT */ + unsigned char r_mask = 0x80 >> ((PDC_state.font_width - 1) % 8); + + /* Bytes to write in a single pass */ + unsigned char bytes[1024]; + + /* Which plane we're writing */ + unsigned plane; + + /* Compute these just once */ + for (i = 0; i < len; ++i) + { + chtype glyph = srcp[i]; + unsigned ch = glyph & A_CHARTEXT; + if ((glyph & A_ALTCHARSET) != 0 && (ch & 0xff80) == 0) + ch = acs_map[ch]; + glyphs[i].font_addr = PDC_state.font_glyph_data(FALSE, ch); + } + + if (PDC_state.font_width % 8 == 0) + { + /* Faster algorithm for use when we're always writing whole bytes */ + + /* Write data twice: once direct, once inverted */ + for (plane = 0; plane < 2; ++plane) + { + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit; + unsigned char invert; + unsigned line; + + if (plane == 0) + { + plane_bit = fore & ~back & 0xF; + invert = 0x00; + } + else + { + plane_bit = ~fore & back & 0xF; + invert = 0xFF; + } + if (plane_bit == 0) + continue; + + /* Select the planes */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned long cp; + unsigned num_bytes = 0; + int col; + + /* Loop once per column */ + cp = addr; + for (col = 0; col < len; ++col) + { + chtype glyph = srcp[col]; + const unsigned char *font_data; + unsigned ch_byte; + + font_data = glyphs[col].font_addr; + + /* Loop once per byte within the font */ + for (ch_byte = 0; ch_byte < ch_width; ++ch_byte) + { + unsigned index = line * ch_width + ch_byte; + unsigned char byte = font_data[index]; + if ((glyph & A_UNDERLINE) && line == PDC_state.underline) + byte |= 0xFF; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + bytes[num_bytes++] = byte ^ invert; + if (num_bytes >= sizeof(bytes)) + { + /* Flush the bytes array to the frame buffer */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + num_bytes = 0; + } + } + } + /* Write any remaining bytes */ + _video_write(cp, bytes, num_bytes); + + addr += PDC_state.bytes_per_line; + } + } + + /* Write fill bytes: once all zeros, once all ones */ + for (plane = 0; plane < 2; ++plane) + { + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit; + unsigned char fill; + unsigned width; + unsigned line; + + if (plane == 0) + { + plane_bit = ~fore & ~back & 0xF; + fill = 0x00; + } + else + { + plane_bit = fore & back & 0xF; + fill = 0xFF; + } + if (plane_bit == 0) + continue; + + /* Select the planes */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + + /* Fill with bytes to be written */ + width = ch_width * len; + memset(bytes, fill, (width < sizeof(bytes)) ? width : sizeof(bytes)); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned count = width; + unsigned long cp = addr; + /* Fill */ + while (count > sizeof(bytes)) + { + _video_write(cp, bytes, sizeof(bytes)); + cp += sizeof(bytes); + count -= sizeof(bytes); + } + _video_write(cp, bytes, count); + addr += PDC_state.bytes_per_line; + } + } + } + else + { + /* Loop once per plane */ + for (plane = 0; plane < 4; ++plane) + { + unsigned xpix = x * PDC_state.font_width; + unsigned long addr = _address_4(lineno, xpix / 8); + unsigned plane_bit = 1 << plane; + unsigned cbits; + unsigned line; + + /* Select the plane */ + outportb(0x3c4, 2); + outportb(0x3c5, plane_bit); + outportb(0x3ce, 4); + outportb(0x3cf, plane); + + /* Select the mask for the current plane */ + cbits = ((fore & plane_bit) ? 1 : 0) + | ((back & plane_bit) ? 2 : 0); + + /* Loop once per raster line */ + for (line = 0; line < PDC_state.font_height; ++line) + { + unsigned shift = xpix % 8; + unsigned long cp; + unsigned num_bytes = 0; + int col; + unsigned ch_byte; + + if (shift != 0) + { + /* We need the existing data from the frame buffer */ + _video_read(bytes, addr, 1); + bytes[0] &= 0xFF00 >> shift; + } + else + { + bytes[0] = 0; + } + + col = 0; + ch_byte = 0; + cp = addr; + while (col < len) + { + /* Render one byte from the current character */ + chtype glyph = srcp[col]; + const unsigned char *font_data = glyphs[col].font_addr; + unsigned char byte; + unsigned num_bits; + + /* Get one byte of pixel data for the current plane */ + if (cbits == 1 || cbits == 2) + { + unsigned index = line * ch_width + ch_byte; + byte = font_data[index]; + if ((glyph & A_UNDERLINE) && line == PDC_state.underline) + byte |= 0xFF; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + } + else + { + byte = 0x00; + } + if (cbits & 2) + byte ^= 0xFF; + + /* Get the number of bits to render in this pass */ + if (ch_byte + 1 < ch_width) + num_bits = 8; + else + { + num_bits = PDC_state.font_width - ch_byte * 8; + byte &= 0xFF00 >> num_bits; + } + + /* Add the bits to the bytes array */ + bytes[num_bytes] |= byte >> shift; + byte <<= 8 - shift; + shift += num_bits; + if (shift >= 8) + { + ++num_bytes; + shift -= 8; + if (num_bytes >= sizeof(bytes)) + { + /* Flush the bytes array to the frame buffer */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + num_bytes = 0; + } + bytes[num_bytes] = byte; + } + + /* Advance to the next byte of the character */ + ++ch_byte; + if (ch_byte >= ch_width) + { + ch_byte = 0; + ++col; + } + } + if (num_bytes != 0) + { + /* There are bytes remaining in the bytes array */ + _video_write(cp, bytes, num_bytes); + cp += num_bytes; + bytes[0] = bytes[num_bytes]; + } + if (shift != 0) + { + /* There are bits remaining in the bytes array */ + unsigned char b; + _video_read(&b, cp, 1); + bytes[0] |= b & (0xFF >> shift); + _video_write(cp, bytes, 1); + } + + addr += PDC_state.bytes_per_line; + } + } + } +} + +/* PDC_transform_line for 4 bit pixels */ + +static void _transform_line_4(int lineno, int x, int len, const chtype *srcp) +{ + unsigned long old_colors, colors; + int i, j; + + /* Draw runs of characters that have the same colors */ + old_colors = _get_colors(srcp[0]); + + for (i = 1, j = 1; j < len; i++, j++) + { + colors = _get_colors(srcp[i]); + + if (colors != old_colors || i >= MAX_PACKET) + { + _new_packet(old_colors, lineno, x, i, srcp); + old_colors = colors; + srcp += i; + x += i; + i = 0; + } + } + + _new_packet(old_colors, lineno, x, i, srcp); + + /* Reset the VGA plane register to its normal state */ + outportb(0x3c4, 2); + outportb(0x3c5, 0xF); +} + +/* PDC_transform_line for 8, 15, 16, 24 and 32 bit pixels */ + +static void _transform_line_8(int lineno, int x, int len, const chtype *srcp) +{ + unsigned char bytes[1024]; + unsigned long addr = _address_8(lineno, x); + unsigned bytes_per_pixel = (PDC_state.bits_per_pixel + 7) / 8; + + struct + { + const unsigned char *font_addr; + unsigned char ul_mask; + unsigned long fore; + unsigned long back; + } glyphs[MAX_PACKET]; + + /* Width of a character in bytes */ + unsigned ch_width = (PDC_state.font_width + 7) / 8; + + /* Bit to set for A_RIGHT */ + unsigned char r_mask = 0x80 >> ((PDC_state.font_width - 1) % 8); + + int col; + unsigned line; + + /* Compute basic glyph data only once per character */ + for (col = 0; col < len; col++) + { + chtype glyph = srcp[col]; + unsigned ch; + unsigned long colors, fore, back; + + /* Get the index into the font */ + ch = glyph & 0xFFFF; + if ((glyph & A_ALTCHARSET) != 0 && (glyph & 0xff80) == 0) + ch = acs_map[ch & 0x7f]; + + /* Get the address of the font data */ + glyphs[col].font_addr = PDC_state.font_glyph_data(FALSE, ch); + + /* Bit mask for underline */ + glyphs[col].ul_mask = (glyph & A_UNDERLINE) ? 0xFF : 0x00; + + /* Get the colors */ + colors = _get_colors(glyph); + fore = colors & 0xFFFF; + back = (colors >> 16) & 0xFFFF; + if (PDC_state.bits_per_pixel > 8) + { + fore = PDC_state.colors[fore].mapped; + back = PDC_state.colors[back].mapped; + } + /* + * If this is ever run on big endian hardware, we'll need to shift + * fore and back left as follows: + * fore <<= 32 - (bytes_per_pixel * 8); + * back <<= 32 - (bytes_per_pixel * 8); + */ + glyphs[col].fore = fore; + glyphs[col].back = back; + } + + /* Loop by raster line */ + for (line = 0; line < PDC_state.font_height; line++) + { + unsigned long cp = addr; + unsigned bindex; + + /* Loop by column */ + bindex = 0; + for (col = 0; col < len; col++) + { + /* Get glyph data */ + chtype glyph = srcp[col]; + const unsigned char *font_addr = glyphs[col].font_addr; + unsigned index = line * ch_width; + unsigned long fore = glyphs[col].fore; + unsigned long back = glyphs[col].back; + unsigned ch_byte; + unsigned byte; + + /* Loop by byte within the font */ + for (ch_byte = 0; ch_byte < ch_width; ++ch_byte) + { + unsigned bit, num_bits; + + /* Get one byte of the font data */ + byte = font_addr[index + ch_byte]; + if ((glyph & A_LEFT) != 0 && ch_byte == 0) + byte |= 0x80; + if ((glyph & A_RIGHT) != 0 && ch_byte + 1 == ch_width) + byte |= r_mask; + if (line == PDC_state.underline) + byte |= glyphs[col].ul_mask; + if (PDC_state.cursor_visible + && lineno == PDC_state.cursor_row + && col + x == PDC_state.cursor_col + && PDC_state.cursor_start <= line && line <= PDC_state.cursor_end) + byte ^= 0xFF; + + /* Number of pixels to render on this pass */ + if (ch_byte + 1 == ch_width) + num_bits = PDC_state.font_width - ch_byte * 8; + else + num_bits = 8; + + /* Render one byte's worth of pixels of the glyph */ + for (bit = 0; bit < num_bits; ++bit) + { + unsigned long color = (byte & (0x80 >> bit)) ? fore : back; + *(unsigned long *)(bytes + bindex) = color; + bindex += bytes_per_pixel; + if (bindex + sizeof(unsigned long) > sizeof(bytes)) + { + /* Flush bytes to the frame buffer */ + _video_write(cp, bytes, bindex); + cp += bindex; + bindex = 0; + } + } + } + } + _video_write(cp, bytes, bindex); + addr += PDC_state.bytes_per_line; + } +} + +/* update the given physical line to look like the corresponding line in + curscr */ + +void PDC_transform_line(int lineno, int x, int len, const chtype *srcp) +{ + PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno)); + + if (PDC_state.bits_per_pixel == 4) + { + _transform_line_4(lineno, x, len, srcp); + } + else + { + while (len > MAX_PACKET) + { + _transform_line_8(lineno, x, MAX_PACKET, srcp); + x += MAX_PACKET; + len -= MAX_PACKET; + srcp += MAX_PACKET; + } + _transform_line_8(lineno, x, len, srcp); + } +} + +void PDC_doupdate(void) +{ +} + +static unsigned long _get_colors(chtype glyph) +{ + attr_t attr; + short fore, back; + + /* Get the foreground and background colors */ + attr = glyph & (A_ATTRIBUTES ^ A_ALTCHARSET); + pair_content(PAIR_NUMBER(attr), &fore, &back); + + if ((attr & A_BOLD) != 0 && fore < 16) + fore |= 8; + if ((attr & A_BLINK) != 0 && back < 16) + back |= 8; + + if (attr & A_REVERSE) + { + short swap = fore; + fore = back; + back = swap; + } + + /* Return them as a pair */ + return ((unsigned long)back << 16) | fore; +} + +void PDC_private_cursor_off(void) +{ + /* This gets called before atrtab is set up; avoid a null dereference */ + if (!SP || !SP->atrtab) + return; + + PDC_state.cursor_visible = FALSE; + if (PDC_state.cursor_row < (unsigned)LINES + && PDC_state.cursor_col < (unsigned)COLS) + { + static const chtype space = ' '; + + PDC_transform_line(PDC_state.cursor_row, PDC_state.cursor_col, 1, + (curscr && curscr->_y) + ? &curscr->_y[PDC_state.cursor_row][PDC_state.cursor_col] + : &space); + } +} + +void PDC_private_cursor_on(int row, int col) +{ + PDC_state.cursor_visible = TRUE; + PDC_state.cursor_row = row; + PDC_state.cursor_col = col; + if (row < (unsigned)LINES && col < (unsigned)COLS) + { + static const chtype space = ' '; + + PDC_transform_line(PDC_state.cursor_row, PDC_state.cursor_col, 1, + (curscr && curscr->_y) + ? &curscr->_y[PDC_state.cursor_row][PDC_state.cursor_col] + : &space); + } +} + +static unsigned long _address_4(int row, int col) +{ + return (unsigned long)row * PDC_state.bytes_per_line * PDC_state.font_height + col; +} + +static unsigned long _address_8(int row, int col) +{ + return (unsigned long)row * PDC_state.bytes_per_line * PDC_state.font_height + + col * PDC_state.font_width * ((PDC_state.bits_per_pixel + 7)/8); +} + +static void _video_read(void *data, unsigned long addr, size_t size) +{ +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { +#ifdef __DJGPP__ + movedata(PDC_state.linear_sel, addr, + _go32_my_ds(), (unsigned)data, size); +#else /* Watcom */ + _fmemcpy(data, MK_FP(PDC_state.linear_sel, addr), size); +#endif + } + else +#endif + { + unsigned window = PDC_state.window[PDC_state.read_win]; + + while (size != 0) + { + unsigned offset = _set_window(PDC_state.read_win, addr); + unsigned long size2 = PDC_state.window_size - offset; + if (size2 > size) + size2 = size; +#ifdef __DJGPP__ + dosmemget(window * 16L + offset, size2, data); +#elif defined(__WATCOMC__) && defined(__386__) + _fmemcpy(data, (void PDC_FAR *)(window * 16L + offset), size2); +#else + if (size2 >= 65532) + size2 = 65532; + + _fmemcpy(data, MK_FP(window, offset), size2); +#endif + addr += size2; + data = (char *)data + size2; + size -= size2; + } + } +} + +static void _video_write(unsigned long addr, const void *data, size_t size) +{ +#ifdef PDC_FLAT + if (PDC_state.linear_sel) + { +#ifdef __DJGPP__ + movedata(_go32_my_ds(), (unsigned)data, + PDC_state.linear_sel, addr, size); +#else /* Watcom */ + _fmemcpy(MK_FP(PDC_state.linear_sel, addr), data, size); +#endif + } + else +#endif + { + unsigned window = PDC_state.window[PDC_state.write_win]; + + while (size != 0) + { + unsigned offset = _set_window(PDC_state.write_win, addr); + unsigned long size2 = PDC_state.window_size - offset; + if (size2 > size) + size2 = size; +#ifdef __DJGPP__ + dosmemput(data, size2, window * 16L + offset); +#elif defined(__WATCOMC__) && defined(__386__) + _fmemcpy((void PDC_FAR *)(window * 16L + offset), data, size2); +#else + if (size2 >= 65532) + size2 = 65532; + + _fmemcpy(MK_FP(window, offset), data, size2); +#endif + addr += size2; + data = (const char *)data + size2; + size -= size2; + } + } +} + +static unsigned _set_window(unsigned window, unsigned long addr) +{ + unsigned long offset = PDC_state.offset[window]; + if (addr < offset || offset + PDC_state.window_size <= addr) + { + /* Need to move the window */ + PDCREGS regs; + unsigned long gran = PDC_state.window_gran * 1024L; + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F05; + regs.W.bx = window; + regs.W.dx = addr / gran; + offset = regs.W.dx * gran; + PDCINT(0x10, regs); + PDC_state.offset[window] = offset; + } + + return addr - offset; +} diff --git a/dosvga/pdcdos.h b/dosvga/pdcdos.h new file mode 100644 index 000000000..1cf46c9cb --- /dev/null +++ b/dosvga/pdcdos.h @@ -0,0 +1,213 @@ +/* PDCurses */ + +#include +#include + +/*---------------------------------------------------------------------- + * MEMORY MODEL SUPPORT: + * + * MODELS + * TINY cs,ds,ss all in 1 segment (not enough memory!) + * SMALL cs:1 segment, ds:1 segment + * MEDIUM cs:many segments, ds:1 segment + * COMPACT cs:1 segment, ds:many segments + * LARGE cs:many segments, ds:many segments + * HUGE cs:many segments, ds:segments > 64K + */ + +#ifdef __TINY__ +# define SMALL 1 +#endif +#ifdef __SMALL__ +# define SMALL 1 +#endif +#ifdef __MEDIUM__ +# define MEDIUM 1 +#endif +#ifdef __COMPACT__ +# define COMPACT 1 +#endif +#ifdef __LARGE__ +# define LARGE 1 +#endif +#ifdef __HUGE__ +# define HUGE 1 +#endif + +#include + +# if SMALL || MEDIUM +# define PDC_FAR far +# else +# define PDC_FAR +# endif + +/* Information about the current video state */ +struct PDC_color +{ + short r, g, b; + unsigned long mapped; +}; + +struct PDC_video_state +{ + /* Information about the current video mode: */ + unsigned short scrn_mode; + int linear_sel; + unsigned long linear_addr; + unsigned char bits_per_pixel; + unsigned short video_width; /* Width of graphics mode in pixels */ + unsigned short video_height; /* Height of graphics mode in pixels */ + unsigned short bytes_per_line; /* Bytes per raster line */ + /* Location of the frame buffer in memory */ + unsigned short window[2]; + unsigned long offset[2]; + unsigned long window_size; + unsigned window_gran; + /* Window used to read and write */ + unsigned char read_win; + unsigned char write_win; + /* Color mappings */ + unsigned char red_max; + unsigned char red_pos; + unsigned char green_max; + unsigned char green_pos; + unsigned char blue_max; + unsigned char blue_pos; + + /* Font support */ + void (*font_close)(bool bold); + unsigned (*font_char_width)(bool bold); + unsigned (*font_char_height)(bool bold); + const unsigned char *(*font_glyph_data)(bool bold, unsigned long pos); + + bool have_bold_font; + unsigned font_width; /* Width of font in pixels */ + unsigned font_height; /* Height of font in pixels */ + unsigned underline; /* Where to draw the underline */ + + /* Cursor state */ + bool cursor_visible; + int cursor_row; + int cursor_col; + unsigned char cursor_start; + unsigned char cursor_end; + + struct PDC_color colors[PDC_MAXCOL]; +}; +extern struct PDC_video_state PDC_state; + +extern void PDC_private_cursor_off(void); +extern void PDC_private_cursor_on(int row, int col); + +#ifdef __DJGPP__ /* Note: works only in plain DOS... */ +# define PDC_FLAT 1 +# if DJGPP == 2 +# define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) +# else +# define _FAR_POINTER(s,o) (0xe0000000 + (((int)(s)) << 4) + ((int)(o))) +# endif +# define _FP_SEGMENT(p) (unsigned short)((((long)p) >> 4) & 0xffff) +#else +# ifdef __TURBOC__ +# define _FAR_POINTER(s,o) MK_FP(s,o) +# else +# if defined(__WATCOMC__) && defined(__FLAT__) +# define PDC_FLAT 1 +# define _FAR_POINTER(s,o) ((((int)(s)) << 4) + ((int)(o))) +# else +# define _FAR_POINTER(s,o) (((long)s << 16) | (long)o) +# endif +# endif +# define _FP_SEGMENT(p) (unsigned short)(((long)p) >> 4) +#endif +#define _FP_OFFSET(p) ((unsigned short)p & 0x000f) + +#ifdef __DJGPP__ +# include +unsigned char getdosmembyte(int offs); +unsigned short getdosmemword(int offs); +unsigned long getdosmemdword(int offs); +void setdosmembyte(int offs, unsigned char b); +void setdosmemword(int offs, unsigned short w); +void setdosmemdword(int offs, unsigned long d); +#else +# define getdosmembyte(offs) \ + (*((unsigned char PDC_FAR *) (offs))) +# define getdosmemword(offs) \ + (*((unsigned short PDC_FAR *) (offs))) +# define getdosmemdword(offs) \ + (*((unsigned long PDC_FAR *) (offs))) +# define setdosmembyte(offs,x) \ + (*((unsigned char PDC_FAR *) (offs)) = (x)) +# define setdosmemword(offs,x) \ + (*((unsigned short PDC_FAR *) (offs)) = (x)) +# define setdosmemdword(offs,x) \ + (*((unsigned long PDC_FAR *) (offs)) = (x)) +#endif + +#if defined(__WATCOMC__) && defined(__386__) + +typedef union +{ + struct + { + unsigned long edi, esi, ebp, res, ebx, edx, ecx, eax; + } d; + + struct + { + unsigned short di, di_hi, si, si_hi, bp, bp_hi, res, res_hi, + bx, bx_hi, dx, dx_hi, cx, cx_hi, ax, ax_hi, + flags, es, ds, fs, gs, ip, cs, sp, ss; + } w; + + struct + { + unsigned char edi[4], esi[4], ebp[4], res[4], + bl, bh, ebx_b2, ebx_b3, dl, dh, edx_b2, edx_b3, + cl, ch, ecx_b2, ecx_b3, al, ah, eax_b2, eax_b3; + } h; +} pdc_dpmi_regs; + +void PDC_dpmi_int(int, pdc_dpmi_regs *); + +#endif + +#ifdef __DJGPP__ +# include +# define PDCREGS __dpmi_regs +# define PDCINT(vector, regs) __dpmi_int(vector, ®s) +#else +# ifdef __WATCOMC__ +# ifdef __386__ +# define PDCREGS pdc_dpmi_regs +# define PDCINT(vector, regs) PDC_dpmi_int(vector, ®s) +# else +# define PDCREGS union REGPACK +# define PDCINT(vector, regs) intr(vector, ®s) +# endif +# else +# define PDCREGS union REGS +# define PDCINT(vector, regs) int86(vector, ®s, ®s) +# endif +#endif + +/* Wide registers in REGS: w or x? */ + +#ifdef __WATCOMC__ +# define W w +#else +# define W x +#endif + +/* Monitor (terminal) type information */ + +enum +{ + _NONE, _MDA, _CGA, + _EGACOLOR = 0x04, _EGAMONO, + _VGACOLOR = 0x07, _VGAMONO, + _MCGACOLOR = 0x0a, _MCGAMONO, + _MDS_GENIUS = 0x30 +}; diff --git a/dosvga/pdcgetsc.c b/dosvga/pdcgetsc.c new file mode 100644 index 000000000..ef6694857 --- /dev/null +++ b/dosvga/pdcgetsc.c @@ -0,0 +1,47 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#include + +/* return width of screen/viewport */ + +int PDC_get_columns(void) +{ + int cols; + + PDC_LOG(("PDC_get_columns() - called\n")); + + cols = PDC_state.video_width / PDC_state.font_width; + + PDC_LOG(("PDC_get_columns() - returned: cols %d\n", cols)); + + return cols; +} + +/* get the cursor size/shape */ + +int PDC_get_cursor_mode(void) +{ + int start = PDC_state.font_height * 3 / 4; + int end = PDC_state.font_height - 1; + + PDC_LOG(("PDC_get_cursor_mode() - called\n")); + + return (start << 8) | end; +} + +/* return number of screen rows */ + +int PDC_get_rows(void) +{ + int rows; + + PDC_LOG(("PDC_get_rows() - called\n")); + + rows = PDC_state.video_height / PDC_state.font_height; + + PDC_LOG(("PDC_get_rows() - returned: rows %d\n", rows)); + + return rows; +} diff --git a/dosvga/pdckbd.c b/dosvga/pdckbd.c new file mode 100644 index 000000000..40202bc37 --- /dev/null +++ b/dosvga/pdckbd.c @@ -0,0 +1,478 @@ +/* PDCurses */ + +#include "pdcdos.h" + +#ifdef __DJGPP__ +# include +# include +# include +#endif + +/************************************************************************ + * Table for key code translation of function keys in keypad mode * + * These values are for strict IBM keyboard compatibles only * + ************************************************************************/ + +static short key_table[] = +{ + -1, ALT_ESC, -1, 0, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, ALT_BKSP, KEY_BTAB, + ALT_Q, ALT_W, ALT_E, ALT_R, + ALT_T, ALT_Y, ALT_U, ALT_I, + ALT_O, ALT_P, ALT_LBRACKET, ALT_RBRACKET, + ALT_ENTER, -1, ALT_A, ALT_S, + ALT_D, ALT_F, ALT_G, ALT_H, + ALT_J, ALT_K, ALT_L, ALT_SEMICOLON, + ALT_FQUOTE, ALT_BQUOTE, -1, ALT_BSLASH, + ALT_Z, ALT_X, ALT_C, ALT_V, + ALT_B, ALT_N, ALT_M, ALT_COMMA, + ALT_STOP, ALT_FSLASH, -1, ALT_PADSTAR, + -1, -1, -1, KEY_F(1), + KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), + KEY_F(6), KEY_F(7), KEY_F(8), KEY_F(9), + KEY_F(10), -1, -1, KEY_HOME, + KEY_UP, KEY_PPAGE, ALT_PADMINUS, KEY_LEFT, + KEY_B2, KEY_RIGHT, ALT_PADPLUS, KEY_END, + KEY_DOWN, KEY_NPAGE, KEY_IC, KEY_DC, + KEY_F(13), KEY_F(14), KEY_F(15), KEY_F(16), + KEY_F(17), KEY_F(18), KEY_F(19), KEY_F(20), + KEY_F(21), KEY_F(22), KEY_F(25), KEY_F(26), + KEY_F(27), KEY_F(28), KEY_F(29), KEY_F(30), + KEY_F(31), KEY_F(32), KEY_F(33), KEY_F(34), + KEY_F(37), KEY_F(38), KEY_F(39), KEY_F(40), + KEY_F(41), KEY_F(42), KEY_F(43), KEY_F(44), + KEY_F(45), KEY_F(46), -1, CTL_LEFT, + CTL_RIGHT, CTL_END, CTL_PGDN, CTL_HOME, + ALT_1, ALT_2, ALT_3, ALT_4, + ALT_5, ALT_6, ALT_7, ALT_8, + ALT_9, ALT_0, ALT_MINUS, ALT_EQUAL, + CTL_PGUP, KEY_F(11), KEY_F(12), KEY_F(23), + KEY_F(24), KEY_F(35), KEY_F(36), KEY_F(47), + KEY_F(48), CTL_UP, CTL_PADMINUS, CTL_PADCENTER, + CTL_PADPLUS, CTL_DOWN, CTL_INS, CTL_DEL, + CTL_TAB, CTL_PADSLASH, CTL_PADSTAR, ALT_HOME, + ALT_UP, ALT_PGUP, -1, ALT_LEFT, + -1, ALT_RIGHT, -1, ALT_END, + ALT_DOWN, ALT_PGDN, ALT_INS, ALT_DEL, + ALT_PADSLASH, ALT_TAB, ALT_PADENTER, -1 +}; + +static struct {unsigned short pressed, released;} button[3]; + +static bool mouse_avail = FALSE, mouse_vis = FALSE, mouse_moved = FALSE, + mouse_button = FALSE, key_pressed = FALSE; + +static unsigned char mouse_scroll = 0; +static PDCREGS ms_regs, old_ms; +static unsigned short shift_status, old_shift = 0; +static unsigned char keyboard_function = 0xff, shift_function = 0xff, + check_function = 0xff; + +static const unsigned short button_map[3] = {0, 2, 1}; + +void PDC_set_keyboard_binary(bool on) +{ + PDC_LOG(("PDC_set_keyboard_binary() - called\n")); + +#ifdef __DJGPP__ + setmode(fileno(stdin), on ? O_BINARY : O_TEXT); + signal(SIGINT, on ? SIG_IGN : SIG_DFL); +#endif +} + +/* check if a key or mouse event is waiting */ + +bool PDC_check_key(void) +{ + PDCREGS regs; + + if (shift_function == 0xff) + { + int scan; + + /* get shift status for all keyboards */ + + regs.h.ah = 0x02; + PDCINT(0x16, regs); + scan = regs.h.al; + + /* get shift status for enhanced keyboards */ + + regs.h.ah = 0x12; + PDCINT(0x16, regs); + + if (scan == regs.h.al && getdosmembyte(0x496) == 0x10) + { + keyboard_function = 0x10; + check_function = 0x11; + shift_function = 0x12; + } + else + { + keyboard_function = 0; + check_function = 1; + shift_function = 2; + } + } + + regs.h.ah = shift_function; + PDCINT(0x16, regs); + + shift_status = regs.W.ax; + + if (mouse_vis) + { + unsigned short i; + + ms_regs.W.ax = 3; + PDCINT(0x33, ms_regs); + + mouse_button = FALSE; + + for (i = 0; i < 3; i++) + { + regs.W.ax = 6; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + button[i].released = regs.W.bx; + if (regs.W.bx) + { + ms_regs.W.cx = regs.W.cx; + ms_regs.W.dx = regs.W.dx; + mouse_button = TRUE; + } + + regs.W.ax = 5; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + button[i].pressed = regs.W.bx; + if (regs.W.bx) + { + ms_regs.W.cx = regs.W.cx; + ms_regs.W.dx = regs.W.dx; + mouse_button = TRUE; + } + } + + mouse_scroll = ms_regs.h.bh; + + mouse_moved = !mouse_button && ms_regs.h.bl && + ms_regs.h.bl == old_ms.h.bl && + (((ms_regs.W.cx / PDC_state.font_width) ^ (old_ms.W.cx / PDC_state.font_width)) || + ((ms_regs.W.dx / PDC_state.font_height) ^ (old_ms.W.dx / PDC_state.font_height))); + + if (mouse_scroll || mouse_button || mouse_moved) + return TRUE; + } + + if (old_shift && !shift_status) /* modifier released */ + { + if (!key_pressed && SP->return_key_modifiers) + return TRUE; + } + else if (!old_shift && shift_status) /* modifier pressed */ + key_pressed = FALSE; + + old_shift = shift_status; + + regs.h.ah = check_function; + PDCINT(0x16, regs); + + return !(regs.W.flags & 64); +} + +static int _process_mouse_events(void) +{ + int i; + short shift_flags = 0; + + memset(&SP->mouse_status, 0, sizeof(SP->mouse_status)); + + key_pressed = TRUE; + old_shift = shift_status; + SP->key_code = TRUE; + + /* Set shift modifiers */ + + if (shift_status & 3) + shift_flags |= BUTTON_SHIFT; + + if (shift_status & 4) + shift_flags |= BUTTON_CONTROL; + + if (shift_status & 8) + shift_flags |= BUTTON_ALT; + + /* Scroll wheel support for CuteMouse */ + + if (mouse_scroll) + { + SP->mouse_status.changes = mouse_scroll & 0x80 ? + PDC_MOUSE_WHEEL_UP : PDC_MOUSE_WHEEL_DOWN; + + SP->mouse_status.x = -1; + SP->mouse_status.y = -1; + + return KEY_MOUSE; + } + + if (mouse_moved) + { + SP->mouse_status.changes = PDC_MOUSE_MOVED; + + for (i = 0; i < 3; i++) + { + if (ms_regs.h.bl & (1 << button_map[i])) + { + SP->mouse_status.button[i] = BUTTON_MOVED | shift_flags; + SP->mouse_status.changes |= (1 << i); + } + } + } + else /* button event */ + { + for (i = 0; i < 3; i++) + { + if (button[i].pressed) + { + /* Check for a click -- a PRESS followed + immediately by a release */ + + if (!button[i].released) + { + if (SP->mouse_wait) + { + PDCREGS regs; + + napms(SP->mouse_wait); + + regs.W.ax = 6; + regs.W.bx = button_map[i]; + PDCINT(0x33, regs); + + SP->mouse_status.button[i] = regs.W.bx ? + BUTTON_CLICKED : BUTTON_PRESSED; + } + else + SP->mouse_status.button[i] = BUTTON_PRESSED; + } + else + SP->mouse_status.button[i] = BUTTON_CLICKED; + } + + if (button[i].pressed || button[i].released) + { + SP->mouse_status.button[i] |= shift_flags; + SP->mouse_status.changes |= (1 << i); + } + } + } + + SP->mouse_status.x = ms_regs.W.cx / PDC_state.font_width; + SP->mouse_status.y = ms_regs.W.dx / PDC_state.font_height; + + old_ms = ms_regs; + + return KEY_MOUSE; +} + +/* return the next available key or mouse event */ + +int PDC_get_key(void) +{ + PDCREGS regs; + int key, scan; + + SP->key_modifiers = 0; + + if (mouse_vis && (mouse_scroll || mouse_button || mouse_moved)) + return _process_mouse_events(); + + /* Return modifiers as keys? */ + + if (old_shift && !shift_status) + { + key = -1; + + if (old_shift & 1) + key = KEY_SHIFT_R; + + if (old_shift & 2) + key = KEY_SHIFT_L; + + if (shift_function == 0x12) + { + if (old_shift & 0x400) + key = KEY_CONTROL_R; + + if (old_shift & 0x100) + key = KEY_CONTROL_L; + + if (old_shift & 0x800) + key = KEY_ALT_R; + + if (old_shift & 0x200) + key = KEY_ALT_L; + } + else + { + if (old_shift & 4) + key = KEY_CONTROL_R; + + if (old_shift & 8) + key = KEY_ALT_R; + } + + key_pressed = FALSE; + old_shift = shift_status; + + SP->key_code = TRUE; + return key; + } + + regs.h.ah = keyboard_function; + PDCINT(0x16, regs); + key = regs.h.al; + scan = regs.h.ah; + + if (shift_status & 3) + SP->key_modifiers |= PDC_KEY_MODIFIER_SHIFT; + + if (shift_status & 4) + SP->key_modifiers |= PDC_KEY_MODIFIER_CONTROL; + + if (shift_status & 8) + SP->key_modifiers |= PDC_KEY_MODIFIER_ALT; + + if (shift_status & 0x20) + SP->key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK; + + if (scan == 0x1c && key == 0x0a) /* ^Enter */ + key = CTL_ENTER; + else if (scan == 0xe0 && key == 0x0d) /* PadEnter */ + key = PADENTER; + else if (scan == 0xe0 && key == 0x0a) /* ^PadEnter */ + key = CTL_PADENTER; + else if (scan == 0x37 && key == 0x2a) /* Star */ + key = PADSTAR; + else if (scan == 0x4a && key == 0x2d) /* Minus */ + key = PADMINUS; + else if (scan == 0x4e && key == 0x2b) /* Plus */ + key = PADPLUS; + else if (scan == 0xe0 && key == 0x2f) /* Slash */ + key = PADSLASH; + else if (key == 0x00 || (key == 0xe0 && scan > 53 && scan != 86)) + key = (scan > 0xa7) ? -1 : key_table[scan]; + + if (shift_status & 3) + { + switch (key) + { + case KEY_HOME: /* Shift Home */ + key = KEY_SHOME; + break; + case KEY_UP: /* Shift Up */ + key = KEY_SUP; + break; + case KEY_PPAGE: /* Shift PgUp */ + key = KEY_SPREVIOUS; + break; + case KEY_LEFT: /* Shift Left */ + key = KEY_SLEFT; + break; + case KEY_RIGHT: /* Shift Right */ + key = KEY_SRIGHT; + break; + case KEY_END: /* Shift End */ + key = KEY_SEND; + break; + case KEY_DOWN: /* Shift Down */ + key = KEY_SDOWN; + break; + case KEY_NPAGE: /* Shift PgDn */ + key = KEY_SNEXT; + break; + case KEY_IC: /* Shift Ins */ + key = KEY_SIC; + break; + case KEY_DC: /* Shift Del */ + key = KEY_SDC; + } + } + + key_pressed = TRUE; + SP->key_code = ((unsigned)key >= 256); + + return key; +} + +/* discard any pending keyboard or mouse input -- this is the core + routine for flushinp() */ + +void PDC_flushinp(void) +{ + PDC_LOG(("PDC_flushinp() - called\n")); + + /* Force the BIOS keyboard buffer head and tail pointers to be + the same... Real nasty trick... */ + + setdosmemword(0x41a, getdosmemword(0x41c)); +} + +bool PDC_has_mouse(void) +{ + PDCREGS regs; + + if (!mouse_avail) + { + regs.W.ax = 0; + PDCINT(0x33, regs); + + mouse_avail = !!(regs.W.ax); + } + + return mouse_avail; +} + +int PDC_mouse_set(void) +{ + PDCREGS regs; + unsigned long mbe = SP->_trap_mbe; + + if (mbe && !mouse_avail) + mouse_avail = PDC_has_mouse(); + + if (mbe) + { + if (mouse_avail && !mouse_vis) + { + memset(&old_ms, 0, sizeof(old_ms)); + + regs.W.ax = 1; + PDCINT(0x33, regs); + + mouse_vis = TRUE; + } + } + else + { + if (mouse_avail && mouse_vis) + { + regs.W.ax = 2; + PDCINT(0x33, regs); + + mouse_vis = FALSE; + } + } + + return (mouse_avail || !mbe) ? OK : ERR; +} + +int PDC_modifiers_set(void) +{ + key_pressed = FALSE; + + return OK; +} diff --git a/dosvga/pdcscrn.c b/dosvga/pdcscrn.c new file mode 100644 index 000000000..e4de24d6e --- /dev/null +++ b/dosvga/pdcscrn.c @@ -0,0 +1,1721 @@ +/* PDCurses */ + +#include "pdcdos.h" +#include "pdcvesa.h" +#include "font.h" + +#include +#include + +struct PDC_video_state PDC_state; + +static int saved_scrnmode[3]; + +static void _init_palette(void); +static void _load_palette(void); +static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info); +static unsigned _find_video_mode(int rows, int cols); +static unsigned _find_mode( + struct ModeInfoBlock *mode_info, + unsigned long mode_addr, + int rows, int cols); +#ifdef PDC_FLAT +static unsigned long _map_frame_buffer(unsigned long phys_addr, + unsigned long size); +static void _unmap_frame_buffer(unsigned long phys_addr); +#endif +#if defined(__WATCOMC__) && defined(__386__) +static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max); +static int __dpmi_free_dos_memory(int sel); +static int __dpmi_allocate_ldt_descriptors(int count); +static int __dpmi_free_ldt_descriptor(int sel); +static int __dpmi_set_segment_base_address(int sel, unsigned long addr); +static int __dpmi_set_segment_limit(int sel, unsigned long limit); +static void dosmemget(unsigned long addr, size_t size, void *buf); +static void dosmemput(const void *buf, size_t size, unsigned long addr); +#endif +static int _psf_font_open(const char *name, bool bold); +static int _vgafont_open(void); + +/* _get_scrn_mode() - Return the current BIOS video mode */ + +static int _get_scrn_mode(void) +{ + PDCREGS regs; + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F03; + PDCINT(0x10, regs); + if (regs.h.ah == 0) { + return (int)regs.W.bx; + } + + regs.h.ah = 0x0f; + PDCINT(0x10, regs); + + return (int)regs.h.al; +} + +/* _set_scrn_mode() - Sets the BIOS Video Mode Number */ + +static void _set_scrn_mode(int new_mode) +{ + PDCREGS regs; + + memset(®s, 0, sizeof(regs)); + if (new_mode >= 0x100) { + regs.W.ax = 0x4F02; + regs.W.bx = new_mode; + } else { + regs.h.ah = 0; + regs.h.al = (unsigned char) new_mode; + } + PDCINT(0x10, regs); + PDC_state.scrn_mode = new_mode; + + LINES = PDC_get_rows(); + COLS = PDC_get_columns(); +} + +/* close the physical screen -- may restore the screen to its state + before PDC_scr_open(); miscellaneous cleanup */ + +void PDC_scr_close(void) +{ +#ifdef PDC_FLAT + _unmap_frame_buffer(PDC_state.linear_addr); + __dpmi_free_ldt_descriptor(PDC_state.linear_sel); +#endif + + _set_scrn_mode(0x03); +} + +void PDC_scr_free(void) +{ + if (PDC_state.font_close != NULL) + { + PDC_state.font_close(FALSE); + PDC_state.font_close(TRUE); + } +} + +/* Set the location of the underline */ +static void _set_underline(void) +{ + unsigned width = (PDC_state.font_width + 7) / 8; + unsigned height = PDC_state.font_height; + unsigned size = width * height; + unsigned i; + const unsigned char *underscore = PDC_state.font_glyph_data(FALSE, 0x5F); + + /* Set underscore at first line of U+005F that is not blank */ + for (i = 0; i < size; ++i) + { + if (underscore[i] != 0) + { + PDC_state.underline = i / width; + return; + } + } + + /* How peculiar; U+005F is blank. Make a guess. */ + PDC_state.underline = PDC_state.font_height * 3 / 4; +} + +/* open the physical screen -- miscellaneous initialization, may save + the existing screen for later restoration */ + +int PDC_scr_open(void) +{ + const char *normal_font, *bold_font; + PDCREGS regs; + + PDC_LOG(("PDC_scr_open() - called\n")); + + /* Check for VGA and bail out if we don't find one */ + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x1A00; + PDCINT(0x10, regs); + if (regs.h.bl != 8) + return ERR; + + SP = calloc(1, sizeof(SCREEN)); + + if (!SP) + return ERR; + + _init_palette(); + + /* Set up fonts: + * * first try PDC_FONT and PDC_FONT_BOLD + * * Fall back to the ROM font if PDC_FONT is not specified + * * Width must be 8; height must be not greater than 16; the bold font, if + * specified, must have the same size as the normal font + */ + normal_font = getenv("PDC_FONT"); + bold_font = getenv("PDC_FONT_BOLD"); + if (normal_font != NULL && normal_font[0] != '\0') + { + if (_psf_font_open(normal_font, FALSE) == 0) + { + /* Opened the normal font; try the bold font */ + if (_psf_font_open(bold_font, TRUE) == 0 + && PDC_state.font_char_width(FALSE) == PDC_state.font_char_width(TRUE) + && PDC_state.font_char_height(FALSE) == PDC_state.font_char_height(TRUE)) + PDC_state.have_bold_font = TRUE; + } + } + if (PDC_state.font_glyph_data == NULL) + { + if (_vgafont_open() < 0) + return ERR; + PDC_state.have_bold_font = FALSE; + } + PDC_state.font_width = PDC_state.font_char_width(FALSE); + PDC_state.font_height = PDC_state.font_char_height(FALSE); + _set_underline(); + + PDC_resize_screen(25, 80); + + SP->orig_attr = FALSE; + + SP->mouse_wait = PDC_CLICK_PERIOD; + SP->audible = TRUE; + + SP->mono = FALSE; + SP->termattrs = A_COLOR | A_REVERSE | A_UNDERLINE; + + SP->_preserve = FALSE; + + return OK; +} + +/* the core of resize_term() */ + +int PDC_resize_screen(int nlines, int ncols) +{ + PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n", + nlines, ncols)); + + _set_scrn_mode(_find_video_mode(nlines, ncols)); + _load_palette(); + SP->orig_cursor = PDC_get_cursor_mode(); + PDC_curs_set(SP->visibility); + if (PDC_state.bits_per_pixel <= 8) + COLORS = 1 << PDC_state.bits_per_pixel; + else + COLORS = PDC_MAXCOL; + + return OK; +} + +void PDC_reset_prog_mode(void) +{ + PDC_LOG(("PDC_reset_prog_mode() - called.\n")); + _load_palette(); +} + +void PDC_reset_shell_mode(void) +{ + PDC_LOG(("PDC_reset_shell_mode() - called.\n")); +} + +void PDC_restore_screen_mode(int i) +{ + if (i >= 0 && i <= 2) + { + _set_scrn_mode(saved_scrnmode[i]); + } +} + +void PDC_save_screen_mode(int i) +{ + if (i >= 0 && i <= 2) + { + saved_scrnmode[i] = _get_scrn_mode(); + } +} + +/* _init_palette -- set up the initial palette */ + +static void _init_palette(void) +{ + unsigned i, r, g, b; + + /* The basic eight colors and their bold forms */ + for (i = 0; i < 8; i++) + { + PDC_state.colors[i+0].r = (i & COLOR_RED) ? 750 : 0; + PDC_state.colors[i+0].g = (i & COLOR_GREEN) ? 750 : 0; + PDC_state.colors[i+0].b = (i & COLOR_BLUE) ? 750 : 0; + PDC_state.colors[i+8].r = (i & COLOR_RED) ? 1000 : 250; + PDC_state.colors[i+8].g = (i & COLOR_GREEN) ? 1000 : 250; + PDC_state.colors[i+8].b = (i & COLOR_BLUE) ? 1000 : 250; + } + + /* 6x6x6 color cube */ + i = 16; + for (r = 0; r < 6; r++) + { + for (g = 0; g < 6; g++) + { + for (b = 0; b < 6; b++) + { + PDC_state.colors[i].r = (r ? r * 157 + 215 : 0); + PDC_state.colors[i].g = (g ? g * 157 + 215 : 0); + PDC_state.colors[i].b = (b ? b * 157 + 215 : 0); + i++; + } + } + } + + /* 24 shades of gray */ + for (i = 232; i < 256; i++) + { + r = (i - 232) * 40 + 30; + PDC_state.colors[i].r = r; + PDC_state.colors[i].g = r; + PDC_state.colors[i].b = r; + } +} + +/* _load_palette -- load the current palette into the DAC */ + +static void _load_palette(void) +{ + if (PDC_state.bits_per_pixel <= 8) + { + PDCREGS regs; + unsigned i; + + /* Load EGA palette registers as an identity map */ + for (i = 0; i < 16; i++) + { + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x1000; + regs.W.bx = i * 0x0101; + PDCINT(0x10, regs); + } + + /* Set 8 bit DACs if available */ + /* This doesn't seem to work with 4 bit color */ + if (PDC_state.bits_per_pixel == 8) + { + unsigned dacmax; + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F08; + regs.W.bx = 0x0800; + PDCINT(0x10, regs); + dacmax = (regs.W.ax == 0x004F) ? (1 << regs.h.bh) - 1 : 63; + PDC_state.red_max = dacmax; + PDC_state.green_max = dacmax; + PDC_state.blue_max = dacmax; + } + + /* Load the DAC registers from the current palette */ + for (i = 0; i < 1 << PDC_state.bits_per_pixel; i++) + PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, + PDC_state.colors[i].b); + } + else + { + unsigned i; + + /* Set up mappings from color index to RGB */ + for (i = 0; i < PDC_MAXCOL; i++) + PDC_init_color(i, PDC_state.colors[i].r, PDC_state.colors[i].g, + PDC_state.colors[i].b); + } +} + +bool PDC_can_change_color(void) +{ + return TRUE; +} + +int PDC_color_content(short color, short *red, short *green, short *blue) +{ + *red = PDC_state.colors[color].r; + *green = PDC_state.colors[color].g; + *blue = PDC_state.colors[color].b; + + return OK; +} + +int PDC_init_color(short color, short red, short green, short blue) +{ + /* Scale */ + unsigned r = DIVROUND((unsigned long)red * PDC_state.red_max, 1000); + unsigned g = DIVROUND((unsigned long)green * PDC_state.green_max, 1000); + unsigned b = DIVROUND((unsigned long)blue * PDC_state.blue_max, 1000); + + PDC_state.colors[color].r = red; + PDC_state.colors[color].g = green; + PDC_state.colors[color].b = blue; + + if (PDC_state.bits_per_pixel <= 8) + { + PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif + + if (PDC_state.scrn_mode >= 0x100) + { + /* VESA mode in use; first try the VESA function */ +#ifdef PDC_FLAT + int seg, sel; +#endif + unsigned long table; + + table = ((unsigned long)b << 0) + | ((unsigned long)g << 8) + | ((unsigned long)r << 16); +#ifdef PDC_FLAT + seg = __dpmi_allocate_dos_memory(1, &sel); + if (seg < 0) + return ERR; + setdosmemdword(seg * 16L, table); +#endif + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F09; + regs.h.bl = 0; + regs.W.cx = 1; + regs.W.dx = color; +#ifdef PDC_FLAT + regs.W.di = 0; + regs.W.es = seg; + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) + regs.W.di = FP_OFF(&table); + regs.W.es = FP_SEG(&table); + PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(&table); + segread(&sregs); + sregs.es = FP_SEG(&table); + int86x(0x10, ®s, ®s, &sregs); +#endif +#ifdef PDC_FLAT + __dpmi_free_dos_memory(sel); +#endif + if (regs.W.ax == 0x004F) + return OK; + } + + regs.h.dh = r; + regs.h.ch = g; + regs.h.cl = b; + + /* Set single DAC register */ + + regs.W.ax = 0x1010; + regs.W.bx = color; + + PDCINT(0x10, regs); + } + else + { + PDC_state.colors[color].mapped = + ((unsigned long)r << PDC_state.red_pos) + | ((unsigned long)g << PDC_state.green_pos) + | ((unsigned long)b << PDC_state.blue_pos); + } + + return OK; +} + +static unsigned _find_video_mode(int rows, int cols) +{ +#ifdef PDC_FLAT + int vbe_info_sel = -1; /* custodial */ + int vbe_info_seg; +#endif + struct VbeInfoBlock vbe_info; + PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif + unsigned long mode_addr; + struct ModeInfoBlock mode_info; + unsigned vesa_mode; + + /* Request VESA BIOS information */ + memset(&vbe_info, 0, sizeof(vbe_info)); + memcpy(vbe_info.VbeSignature, "VBE2", 4); + +#ifdef PDC_FLAT + vbe_info_seg = __dpmi_allocate_dos_memory( + (sizeof(vbe_info) + 15) / 16, + &vbe_info_sel); + if (vbe_info_seg < 0) + goto error; + dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L); +#endif + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F00; +#ifdef PDC_FLAT + regs.W.di = 0; + regs.W.es = vbe_info_seg; + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) + regs.W.di = FP_OFF(&vbe_info); + regs.W.es = FP_SEG(&vbe_info); + PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(&vbe_info); + segread(&sregs); + sregs.es = FP_SEG(&vbe_info); + int86x(0x10, ®s, ®s, &sregs); +#endif + + /* Check for successful completion of function: is VESA BIOS present? */ + if (regs.W.ax != 0x004F) + goto error; +#ifdef PDC_FLAT + dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info); +#endif + if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) + goto error; + + /* Get the address of the mode list */ + /* The mode list may be within the DOS memory area allocated above. + That area must remain allocated and must not be rewritten until + we're done here. */ +#ifdef PDC_FLAT + mode_addr = _FAR_POINTER(vbe_info.VideoModePtr >> 16, + vbe_info.VideoModePtr & 0xFFFF); +#else + mode_addr = vbe_info.VideoModePtr; +#endif + + /* Look for the best-fitting mode available */ + vesa_mode = _find_mode(&mode_info, mode_addr, rows, cols); + if (vesa_mode == 0xFFFF) + vesa_mode = _find_mode(&mode_info, mode_addr, 0, 0); + if (vesa_mode == 0xFFFF) + goto error; + + /* Set up frame buffer window */ + if ((mode_info.WinAAttributes & 0x2) != 0) + PDC_state.read_win = 0; /* Read through Window A */ + else if ((mode_info.WinBAttributes & 0x2) != 0) + PDC_state.read_win = 1; /* Read through Window B */ + else + goto error; /* shouldn't happen */ + if ((mode_info.WinAAttributes & 0x1) != 0) + PDC_state.write_win = 0; /* Write through Window A */ + else if ((mode_info.WinBAttributes & 0x1) != 0) + PDC_state.write_win = 1; /* Write through Window B */ + else + goto error; /* shouldn't happen */ + PDC_state.window[0] = mode_info.WinASegment; + PDC_state.window[1] = mode_info.WinBSegment; + if (vesa_mode == 0x12) + { + PDC_state.offset[0] = 0; + PDC_state.offset[1] = 0; + } + else + { + PDC_state.offset[0] = 0xFFFFFFFF; /* offset is unknown */ + PDC_state.offset[1] = 0xFFFFFFFF; + } + PDC_state.window_size = mode_info.WinSize * 1024L; + PDC_state.window_gran = mode_info.WinGranularity; + PDC_state.bytes_per_line = mode_info.BytesPerScanLine; + PDC_state.video_width = mode_info.XResolution; + PDC_state.video_height = mode_info.YResolution; + PDC_state.bits_per_pixel = mode_info.BitsPerPixel; + +#ifdef PDC_FLAT + /* Enable the linear frame buffer if available */ + if ((mode_info.ModeAttributes & 0x80) != 0) + { + do { /* while (FALSE) */ + unsigned win_size; + unsigned width; + + width = (vbe_info.VbeVersion >= 0x300) + ? mode_info.LinBytesPerScanLine + : mode_info.BytesPerScanLine; + + PDC_state.linear_sel = __dpmi_allocate_ldt_descriptors(1); + if (PDC_state.linear_sel < 0) + break; + win_size = width * mode_info.YResolution; + PDC_state.linear_addr = _map_frame_buffer(mode_info.PhysBasePtr, win_size); + if (PDC_state.linear_addr == 0) + { + __dpmi_free_ldt_descriptor(PDC_state.linear_sel); + PDC_state.linear_sel = 0; + break; + } + __dpmi_set_segment_base_address(PDC_state.linear_sel, PDC_state.linear_addr); + __dpmi_set_segment_limit(PDC_state.linear_sel, (win_size - 1) | 0xFFF); + vesa_mode |= 0x4000; + PDC_state.bytes_per_line = width; + } while (FALSE); + } +#else + PDC_state.linear_sel = 0; +#endif + + if (PDC_state.bits_per_pixel <= 8) + { + PDC_state.red_max = 63; + PDC_state.green_max = 63; + PDC_state.blue_max = 63; + } + else + { +#ifdef PDC_FLAT + if (PDC_state.linear_sel && vbe_info.VbeVersion >= 0x300) + { + PDC_state.red_max = (1 << mode_info.LinRedMaskSize) - 1; + PDC_state.red_pos = mode_info.LinRedFieldPosition; + PDC_state.green_max = (1 << mode_info.LinGreenMaskSize) - 1; + PDC_state.green_pos = mode_info.LinGreenFieldPosition; + PDC_state.blue_max = (1 << mode_info.LinBlueMaskSize) - 1; + PDC_state.blue_pos = mode_info.LinBlueFieldPosition; + } + else +#endif + if (mode_info.ModeAttributes & 0x2) + { + PDC_state.red_max = (1 << mode_info.RedMaskSize) - 1; + PDC_state.red_pos = mode_info.RedFieldPosition; + PDC_state.green_max = (1 << mode_info.GreenMaskSize) - 1; + PDC_state.green_pos = mode_info.GreenFieldPosition; + PDC_state.blue_max = (1 << mode_info.BlueMaskSize) - 1; + PDC_state.blue_pos = mode_info.BlueFieldPosition; + } + else + { + switch (PDC_state.bits_per_pixel) + { + case 15: + PDC_state.red_max = 31; + PDC_state.red_pos = 10; + PDC_state.green_max = 31; + PDC_state.green_pos = 5; + PDC_state.blue_max = 31; + PDC_state.blue_pos = 0; + break; + + case 16: + PDC_state.red_max = 31; + PDC_state.red_pos = 11; + PDC_state.green_max = 63; + PDC_state.green_pos = 5; + PDC_state.blue_max = 31; + PDC_state.blue_pos = 0; + break; + + case 24: + case 32: + PDC_state.red_max = 255; + PDC_state.red_pos = 16; + PDC_state.green_max = 255; + PDC_state.green_pos = 8; + PDC_state.blue_max = 255; + PDC_state.blue_pos = 0; + break; + } + } + } + +#ifdef PDC_FLAT + __dpmi_free_dos_memory(vbe_info_sel); +#endif + return vesa_mode; + +error: + /* If we can't access the VESA BIOS Extensions for any reason, return the + 640x480 VGA mode */ +#ifdef PDC_FLAT + if (vbe_info_sel != -1) + __dpmi_free_dos_memory(vbe_info_sel); +#endif + + PDC_state.bits_per_pixel = 4; + PDC_state.video_width = 640; + PDC_state.video_height = 480; + PDC_state.bytes_per_line = 80; + PDC_state.read_win = 0; + PDC_state.write_win = 0; + PDC_state.window[0] = 0xA000; + PDC_state.window[1] = 0xA000; + PDC_state.offset[0] = 0; + PDC_state.offset[1] = 0; + PDC_state.window_size = (640/8) * 480; + PDC_state.window_gran = 1; + PDC_state.red_max = 63; + PDC_state.green_max = 63; + PDC_state.blue_max = 63; + + return 0x12; +} + +static unsigned _find_mode( + struct ModeInfoBlock *mode_info, + unsigned long mode_addr, + int rows, int cols) +{ + unsigned selected_mode; + unsigned long selected_size; + unsigned selected_bits; + + selected_mode = 0xFFFF; + selected_size = (rows == 0 && cols == 0) ? 0 : 0xFFFFFFFF; + selected_bits = 0; + + if (rows * PDC_state.font_height <= 480 && cols * PDC_state.font_width <= 640) + { + /* Set up a ModeInfoBlock for mode 0x0012 */ + unsigned new_rows = 480 / PDC_state.font_height; + unsigned new_cols = 640 / PDC_state.font_width; + selected_mode = 0x0012; + selected_size = new_rows * new_cols; + selected_bits = 4; + memset(mode_info, 0, sizeof(*mode_info)); + mode_info->ModeAttributes = 0x1F; + mode_info->WinAAttributes = 0x07; + mode_info->WinBAttributes = 0x00; + mode_info->WinGranularity = 1; + mode_info->WinSize = 38; + mode_info->WinASegment = 0xA000; + mode_info->WinBSegment = 0; + mode_info->WinFuncPtr = 0; + mode_info->BytesPerScanLine = 80; + mode_info->XResolution = 640; + mode_info->YResolution = 480; + mode_info->NumberOfPlanes = 4; + mode_info->BitsPerPixel = 4; + mode_info->NumberOfBanks = 1; + mode_info->MemoryModel = 3; + } + + while (1) + { + unsigned mode; + struct ModeInfoBlock mode_info0; + unsigned new_rows, new_cols; + unsigned long new_size; + + mode = getdosmemword(mode_addr); + if (mode == 0xFFFF) + break; + mode_addr += 2; + + /* Query the mode info; skip if not supported */ + if (_get_mode_info(mode, &mode_info0) < 0) + continue; + + /* Check that the mode is acceptable: */ + /* Supported, graphics mode, color, VGA compatible */ + if ((mode_info0.ModeAttributes & 0x79) != 0x19) + continue; + /* Bits per pixel and memory model are acceptable */ + switch (mode_info0.BitsPerPixel) + { + case 4: + if (mode_info0.MemoryModel != 3) /* Planar */ + continue; + if (mode_info0.NumberOfPlanes != 4) + continue; + break; + + case 8: + if (mode_info0.MemoryModel != 4) /* Packed pixel */ + continue; + if (mode_info0.NumberOfPlanes != 1) + continue; + break; + + case 15: + case 16: + case 24: + case 32: + if (mode_info0.MemoryModel != 6) /* Direct color */ + continue; + if (mode_info0.NumberOfPlanes != 1) + continue; + break; + + default: + continue; + } + + /* At least as many rows and columns as requested */ + new_cols = mode_info0.XResolution / PDC_state.font_width; + new_rows = mode_info0.YResolution / PDC_state.font_height; + if (new_cols < cols || new_rows < rows) + continue; + + /* Among modes that are large enough for rows and cols, choose one + with the most bits per pixel. Among modes with the same pixel depth, + if rows == 0 and cols == 0, select the largest available size; + otherwise, select the smallest that can hold that many rows and + columns. */ + if (mode_info0.BitsPerPixel < selected_bits) + continue; + new_size = (unsigned long)new_rows * new_cols; + if (mode_info0.BitsPerPixel == selected_bits) + { + if (rows == 0 && cols == 0) + { + if (new_size <= selected_size) + continue; + } + else + { + if (new_size >= selected_size) + continue; + } + } + + /* Select this mode, pending discovery of a better one */ + selected_mode = mode; + selected_size = new_size; + selected_bits = mode_info0.BitsPerPixel; + *mode_info = mode_info0; + } + + return selected_mode; +} + +static int _get_mode_info(unsigned mode, struct ModeInfoBlock *mode_info) +{ + struct OldModeInfo + { + unsigned mode; + + unsigned short XResolution; /* horizontal resolution in pixels or characters */ + unsigned short YResolution; /* vertical resolution in pixels or characters */ + unsigned char BitsPerPixel; /* bits per pixel */ + }; + static const struct OldModeInfo old_mode_table[] = + { + { 0x0100, 640, 480, 4 }, + { 0x0101, 640, 480, 8 }, + { 0x0102, 800, 600, 4 }, + { 0x0103, 800, 600, 8 }, + { 0x0104, 1024, 768, 4 }, + { 0x0105, 1024, 768, 8 }, + { 0x0106, 1280, 1024, 4 }, + { 0x0107, 1280, 1024, 8 }, + { 0x010D, 320, 200, 15 }, + { 0x010E, 320, 200, 16 }, + { 0x010F, 320, 200, 24 }, + { 0x0110, 640, 480, 15 }, + { 0x0111, 640, 480, 16 }, + { 0x0112, 640, 480, 24 }, + { 0x0113, 800, 600, 15 }, + { 0x0114, 800, 600, 16 }, + { 0x0115, 800, 600, 24 }, + { 0x0116, 1024, 768, 15 }, + { 0x0117, 1024, 768, 16 }, + { 0x0118, 1024, 768, 24 }, + { 0x0119, 1280, 1024, 15 }, + { 0x011A, 1280, 1024, 16 }, + { 0x011B, 1280, 1024, 24 }, + /* sentinel */ + { 0, 0, 0, 0 } + }; + +#ifdef PDC_FLAT + int mode_info_sel = -1; /* custodial */ + int mode_info_seg; +#endif + PDCREGS regs; +#if !defined(PDC_FLAT) && !defined(__WATCOMC__) + struct SREGS sregs; +#endif + + memset(mode_info, 0, sizeof(*mode_info)); +#ifdef PDC_FLAT + mode_info_seg = __dpmi_allocate_dos_memory( + (sizeof(*mode_info) + 15) / 16, + &mode_info_sel); + if (mode_info_seg < 0) + goto error; + dosmemput(mode_info, sizeof(*mode_info), mode_info_seg * 16L); +#endif + + memset(®s, 0, sizeof(regs)); + regs.W.ax = 0x4F01; + regs.W.cx = mode; +#ifdef PDC_FLAT + regs.W.di = 0; + regs.W.es = mode_info_seg; + PDCINT(0x10, regs); +#elif defined(__WATCOMC__) + regs.W.di = FP_OFF(mode_info); + regs.W.es = FP_SEG(mode_info); + PDCINT(0x10, regs); +#else + regs.W.di = FP_OFF(mode_info); + segread(&sregs); + sregs.es = FP_SEG(mode_info); + int86x(0x10, ®s, ®s, &sregs); +#endif + + if (regs.W.ax != 0x004F) + goto error; +#ifdef PDC_FLAT + dosmemget(mode_info_seg * 16L, sizeof(*mode_info), mode_info); +#endif + if (!(mode_info->ModeAttributes & 0x0001)) + goto error; + + if (!(mode_info->ModeAttributes & 0x0002)) + { + /* Older VESA BIOS that did not return certain mode properties, but + that has fixed mode numbers; search the table to find the right + mode properties */ + + unsigned i; + + for (i = 0; old_mode_table[i].mode != 0; ++i) + { + if (mode == old_mode_table[i].mode) + break; + } + if (old_mode_table[i].mode == 0) + goto error; + + mode_info->XResolution = old_mode_table[i].XResolution; + mode_info->YResolution = old_mode_table[i].YResolution; + mode_info->BitsPerPixel = old_mode_table[i].BitsPerPixel; + mode_info->NumberOfBanks = 1; + switch (mode_info->BitsPerPixel) + { + case 4: + mode_info->NumberOfPlanes = 4; + mode_info->MemoryModel = 3; + break; + + case 8: + mode_info->NumberOfPlanes = 1; + mode_info->MemoryModel = 4; + break; + + default: + mode_info->NumberOfPlanes = 1; + mode_info->MemoryModel = 6; + break; + } + } + +#ifdef PDC_FLAT + __dpmi_free_dos_memory(mode_info_sel); +#endif + return TRUE; + +error: +#ifdef PDC_FLAT + if (mode_info_sel != -1) + __dpmi_free_dos_memory(mode_info_sel); +#endif + return FALSE; +} + +/* Make a physical address mapping, to support the linear frame buffer */ +#ifdef __DJGPP__ +static unsigned long +_map_frame_buffer(unsigned long phys_addr, unsigned long size) +{ + __dpmi_meminfo info; + int rc; + + info.handle = 0; + info.address = phys_addr; + info.size = size; + rc = __dpmi_physical_address_mapping(&info); + + return rc == 0 ? info.address : 0; +} + +static void +_unmap_frame_buffer(unsigned long phys_addr) +{ + __dpmi_meminfo info; + + info.handle = 0; + info.address = phys_addr; + info.size = 0; + __dpmi_free_physical_address_mapping(&info); +} +#elif defined(__WATCOMC__) && defined(__386__) +static unsigned long +_map_frame_buffer(unsigned long phys_addr, unsigned long size) +{ + unsigned flags = 0; + unsigned long r_bxcx = 0; + + _asm { + mov ecx, phys_addr; + mov ebx, ecx; + shr ebx, 16; + mov edi, size; + mov esi, edi; + shr esi, 16; + mov eax, 0x0800; + int 0x31; + pushfd; + pop flags; + shl ebx, 16; + mov bx, cx; + mov r_bxcx, ebx; + } + + return (flags & 1) ? 0 : r_bxcx; +} + +static void +_unmap_frame_buffer(unsigned long phys_addr) +{ + _asm { + mov ecx, phys_addr; + mov ebx, ecx; + shr ebx, 16; + mov eax, 0x0801; + int 0x31; + } +} +#endif + +/* DOS memory allocation routines as defined by DJGPP, for use by Watcom */ +#if defined(__WATCOMC__) && defined(__386__) +static int __dpmi_allocate_dos_memory(int paras, int *sel_or_max) +{ + int flags = 0, r_ax = 0, r_bx = 0, r_dx = 0; + + _asm { + mov ebx, paras; + mov eax, 0x0100; + int 0x31; + pushfd; + pop flags; + mov r_ax, eax; + mov r_bx, ebx; + mov r_dx, edx; + } + if (flags & 0x01) + { + /* carry set */ + *sel_or_max = r_bx; + return -1; + } + else + { + /* carry clear */ + *sel_or_max = r_dx; + return r_ax; + } +} + +static int __dpmi_free_dos_memory(int sel) +{ + int flags = 0; + + _asm { + mov edx, sel; + mov eax, 0x0101; + int 0x31; + pushfd; + pop flags; + } + return (flags & 0x01) ? -1 : 0; +} + +static int __dpmi_allocate_ldt_descriptors(int count) +{ + int flags = 0; + int r_eax = 0; + + _asm { + mov ecx, count; + mov eax, 0x0000; + int 0x31; + pushfd; + pop flags; + mov r_eax, eax; + } + + return (flags & 0x01) ? -1 : r_eax; +} + +static int __dpmi_free_ldt_descriptor(int sel) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov eax, 0x0001; + int 0x31; + pushfd; + pop flags; + } + return (flags & 0x01) ? -1 : 0; +} + +static int __dpmi_set_segment_base_address(int sel, unsigned long addr) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov edx, addr; + mov ecx, edx; + shr ecx, 16; + mov eax, 0x0007; + int 0x31; + pushfd; + pop flags; + } + + return (flags & 0x01) ? -1 : 0; +} + +static int __dpmi_set_segment_limit(int sel, unsigned long limit) +{ + int flags = 0; + + _asm { + mov ebx, sel; + mov edx, limit; + mov ecx, edx; + shr ecx, 16; + mov eax, 0x0008; + int 0x31; + pushfd; + pop flags; + } + + return (flags & 0x01) ? -1 : 0; +} + +static void dosmemget(unsigned long addr, size_t size, void *buf) +{ + memcpy(buf, (const void *)addr, size); +} + +static void dosmemput(const void *buf, size_t size, unsigned long addr) +{ + memcpy((void *)addr, buf, size); +} +#endif + +/***************************************************************************** +* Support for a built-in 16 line font * +*****************************************************************************/ + +static void _vgafont_close(bool bold); +static unsigned _vgafont_char_width(bool bold); +static unsigned _vgafont_char_height(bool bold); +static const unsigned char *_vgafont_glyph_data(bool bold, unsigned long pos); + +#ifdef PDC_WIDE +/* This maps Unicode to CP437 */ + +static const struct +{ + unsigned short uni; + unsigned char pos; +} cp437_map[] = +{ + /* Regular mappings */ + { 0x0000, 0x00 }, + { 0x263A, 0x01 }, + { 0x263B, 0x02 }, + { 0x2665, 0x03 }, + { 0x2666, 0x04 }, + { 0x2663, 0x05 }, + { 0x2660, 0x06 }, + { 0x2022, 0x07 }, + { 0x25D8, 0x08 }, + { 0x25CB, 0x09 }, + { 0x25D9, 0x0A }, + { 0x2642, 0x0B }, + { 0x2640, 0x0C }, + { 0x266A, 0x0D }, + { 0x266B, 0x0E }, + { 0x263C, 0x0F }, + { 0x25BA, 0x10 }, + { 0x25C4, 0x11 }, + { 0x2195, 0x12 }, + { 0x203C, 0x13 }, + { 0x00B6, 0x14 }, + { 0x00A7, 0x15 }, + { 0x25AC, 0x16 }, + { 0x21A8, 0x17 }, + { 0x2191, 0x18 }, + { 0x2193, 0x19 }, + { 0x2192, 0x1A }, + { 0x2190, 0x1B }, + { 0x221F, 0x1C }, + { 0x2194, 0x1D }, + { 0x25B2, 0x1E }, + { 0x25BC, 0x1F }, + { 0x2302, 0x7F }, + { 0x00C7, 0x80 }, + { 0x00FC, 0x81 }, + { 0x00E9, 0x82 }, + { 0x00E2, 0x83 }, + { 0x00E4, 0x84 }, + { 0x00E0, 0x85 }, + { 0x00E5, 0x86 }, + { 0x00E7, 0x87 }, + { 0x00EA, 0x88 }, + { 0x00EB, 0x89 }, + { 0x00E8, 0x8A }, + { 0x00EF, 0x8B }, + { 0x00EE, 0x8C }, + { 0x00EC, 0x8D }, + { 0x00C4, 0x8E }, + { 0x00C5, 0x8F }, + { 0x00C9, 0x90 }, + { 0x00E6, 0x91 }, + { 0x00C6, 0x92 }, + { 0x00F4, 0x93 }, + { 0x00F6, 0x94 }, + { 0x00F2, 0x95 }, + { 0x00FB, 0x96 }, + { 0x00F9, 0x97 }, + { 0x00FF, 0x98 }, + { 0x00D6, 0x99 }, + { 0x00DC, 0x9A }, + { 0x00A2, 0x9B }, + { 0x00A3, 0x9C }, + { 0x00A5, 0x9D }, + { 0x20A7, 0x9E }, + { 0x0192, 0x9F }, + { 0x00E1, 0xA0 }, + { 0x00ED, 0xA1 }, + { 0x00F3, 0xA2 }, + { 0x00FA, 0xA3 }, + { 0x00F1, 0xA4 }, + { 0x00D1, 0xA5 }, + { 0x00AA, 0xA6 }, + { 0x00BA, 0xA7 }, + { 0x00BF, 0xA8 }, + { 0x2310, 0xA9 }, + { 0x00AC, 0xAA }, + { 0x00BD, 0xAB }, + { 0x00BC, 0xAC }, + { 0x00A1, 0xAD }, + { 0x00AB, 0xAE }, + { 0x00BB, 0xAF }, + { 0x2591, 0xB0 }, + { 0x2592, 0xB1 }, + { 0x2593, 0xB2 }, + { 0x2502, 0xB3 }, + { 0x2524, 0xB4 }, + { 0x2561, 0xB5 }, + { 0x2562, 0xB6 }, + { 0x2556, 0xB7 }, + { 0x2555, 0xB8 }, + { 0x2563, 0xB9 }, + { 0x2551, 0xBA }, + { 0x2557, 0xBB }, + { 0x255D, 0xBC }, + { 0x255C, 0xBD }, + { 0x255B, 0xBE }, + { 0x2510, 0xBF }, + { 0x2514, 0xC0 }, + { 0x2534, 0xC1 }, + { 0x252C, 0xC2 }, + { 0x251C, 0xC3 }, + { 0x2500, 0xC4 }, + { 0x253C, 0xC5 }, + { 0x255E, 0xC6 }, + { 0x255F, 0xC7 }, + { 0x255A, 0xC8 }, + { 0x2554, 0xC9 }, + { 0x2569, 0xCA }, + { 0x2566, 0xCB }, + { 0x2560, 0xCC }, + { 0x2550, 0xCD }, + { 0x256C, 0xCE }, + { 0x2567, 0xCF }, + { 0x2568, 0xD0 }, + { 0x2564, 0xD1 }, + { 0x2565, 0xD2 }, + { 0x2559, 0xD3 }, + { 0x2558, 0xD4 }, + { 0x2552, 0xD5 }, + { 0x2553, 0xD6 }, + { 0x256B, 0xD7 }, + { 0x256A, 0xD8 }, + { 0x2518, 0xD9 }, + { 0x250C, 0xDA }, + { 0x2588, 0xDB }, + { 0x2584, 0xDC }, + { 0x258C, 0xDD }, + { 0x2590, 0xDE }, + { 0x2580, 0xDF }, + { 0x03B1, 0xE0 }, + { 0x00DF, 0xE1 }, + { 0x0393, 0xE2 }, + { 0x03C0, 0xE3 }, + { 0x03A3, 0xE4 }, + { 0x03C3, 0xE5 }, + { 0x00B5, 0xE6 }, + { 0x03C4, 0xE7 }, + { 0x03A6, 0xE8 }, + { 0x0398, 0xE9 }, + { 0x03A9, 0xEA }, + { 0x03B4, 0xEB }, + { 0x221E, 0xEC }, + { 0x03C6, 0xED }, + { 0x03B5, 0xEE }, + { 0x2229, 0xEF }, + { 0x2261, 0xF0 }, + { 0x00B1, 0xF1 }, + { 0x2265, 0xF2 }, + { 0x2264, 0xF3 }, + { 0x2320, 0xF4 }, + { 0x2321, 0xF5 }, + { 0x00F7, 0xF6 }, + { 0x2248, 0xF7 }, + { 0x00B0, 0xF8 }, + { 0x2219, 0xF9 }, + { 0x00B7, 0xFA }, + { 0x221A, 0xFB }, + { 0x207F, 0xFC }, + { 0x00B2, 0xFD }, + { 0x25A0, 0xFE }, + { 0x00A0, 0xFF }, + /* Extra mappings so ACS_* will work */ + { 0x00A4, 0x0F }, + { 0x2260, 0xD8 }, + { 0x23BA, 0x2D }, + { 0x23BB, 0x2D }, + { 0x23BC, 0x2D }, + { 0x23BD, 0x5F } +}; + +#define NO_CHAR 0xFE +static unsigned char pages[10][256]; +static unsigned char *map[256]; + +static void _build_rom_map(void) +{ + unsigned page = 0; + unsigned i; + + memset(pages, NO_CHAR, sizeof(pages)); + for (i = 0; i < 256; ++i) + map[i] = NULL; + /* Map ASCII as identity */ + map[0] = pages[page++]; + for (i = 0x20; i <= 0x7E; ++i) + map[0][i] = i; + /* Map according to the list */ + for (i = 0; i < sizeof(cp437_map)/sizeof(cp437_map[0]); ++i) + { + unsigned cp = cp437_map[i].uni; + unsigned t1 = cp >> 8; + unsigned t2 = cp & 0xFF; + if (map[t1] == NULL) + { + if (page >= sizeof(pages)/sizeof(pages[0])) + { + fprintf(stderr, "Need to adjust size of pages array\n)"); + abort(); + } + map[t1] = pages[page++]; + } + map[t1][t2] = cp437_map[i].pos; + } +} + +static unsigned char _unicode_to_cp437(unsigned long cp) +{ + unsigned t1, t2; + + if (cp > 0xFFFF) + return NO_CHAR; + t1 = cp >> 8; + t2 = cp & 0xFF; + if (map[t1] == NULL) + return NO_CHAR; + return map[t1][t2]; +} +#endif + +static int _vgafont_open(void) +{ +#ifdef PDC_WIDE + _build_rom_map(); +#endif + PDC_state.font_close = _vgafont_close; + PDC_state.font_char_width = _vgafont_char_width; + PDC_state.font_char_height = _vgafont_char_height; + PDC_state.font_glyph_data = _vgafont_glyph_data; + return 0; +} + +static void _vgafont_close(bool bold) +{ + /* no operation */ +} + +static unsigned _vgafont_char_width(bool bold) +{ + return 8; +} + +static unsigned _vgafont_char_height(bool bold) +{ + return 14; +} + +static const unsigned char *_vgafont_glyph_data(bool bold, unsigned long pos) +{ + unsigned pos437; +#ifdef PDC_WIDE + pos437 = _unicode_to_cp437(pos); +#else + pos437 = pos & 0xFF; +#endif + return font_bytes + pos437*14; +} + +/***************************************************************************** +* Support for PSF fonts * +*****************************************************************************/ + +/* PSF specification from: + https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html + Only PSF version 2 is supported. */ + +#define PSF2_MAGIC "\x72\xb5\x4A\x86" + +/* bits used in flags */ +#define PSF2_HAS_UNICODE_TABLE 0x01 + +/* max version recognized so far */ +#define PSF2_MAXVERSION 0 + +/* UTF8 separators */ +#define PSF2_SEPARATOR 0xFF +#define PSF2_STARTSEQ 0xFE + +struct psf2_header +{ + unsigned char magic[4]; + unsigned long version; + unsigned long headersize; /* offset of bitmaps in file */ + unsigned long flags; + unsigned long length; /* number of glyphs */ + unsigned long charsize; /* number of bytes for each character */ + unsigned long height, width; /* max dimensions of glyphs */ + /* charsize = height * ((width + 7) / 8) */ +}; + +/* Information about a single font */ +struct font_data +{ + struct psf2_header header; + unsigned char **glyphs; /* Bits from the font */ + size_t **map[17]; /* Map code points to font positions */ + unsigned char *blank; /* Default glyph */ +}; + +static struct font_data psf_fonts[2]; /* normal and bold */ + +static void _psf_font_close(bool bold); +static unsigned _psf_font_char_width(bool bold); +static unsigned _psf_font_char_height(bool bold); +static const unsigned char *_psf_font_glyph_data( + bool bold, unsigned long codepoint); +static void _psf_font_do_close(struct font_data *fdata); +static long _psf_font_read_utf8(FILE *fp); +static int _psf_font_map_char(struct font_data *fdata, long codepoint, + size_t pos); +static const unsigned char *_psf_font_do_glyph_data( + struct font_data *fdata, long codepoint); + +/* Open the font with the given file name, as the normal or the bold font. + * Return 0 if OK, -1 on any error. */ +static int _psf_font_open(const char *name, bool bold) +{ + struct font_data *fdata = &psf_fonts[bold != 0]; + FILE *fp; + size_t size; + size_t pos; + + memset(fdata, 0, sizeof(*fdata)); + + fp = fopen(name, "rb"); + if (fp == NULL) + goto error; + + /* Read and check the header */ + size = fread(&fdata->header, sizeof(fdata->header), 1, fp); + if (size != 1) + goto error; + if (memcmp(fdata->header.magic, PSF2_MAGIC, 4) != 0) + goto error; + if (fdata->header.charsize < fdata->header.height * ((fdata->header.width + 7) / 8)) + goto error; + + /* Read the bitmap data */ + if (fdata->header.length != (size_t)fdata->header.length) + goto error; /* only possible if size_t has less than four bytes */ + fdata->glyphs = calloc(fdata->header.length, sizeof(fdata->glyphs[0])); + if (fdata->glyphs == NULL) + goto error; + for (pos = 0; pos < fdata->header.length; ++pos) + { + fdata->glyphs[pos] = malloc(fdata->header.charsize); + if (fdata->glyphs[pos] == NULL) + goto error; + size = fread(fdata->glyphs[pos], 1, fdata->header.charsize, fp); + if (size != fdata->header.charsize) + goto error; + } + + /* Read the Unicode mapping if one is indicated */ + if (fdata->header.flags & PSF2_HAS_UNICODE_TABLE) + { + pos = 0; + while (1) + { + long codepoint = _psf_font_read_utf8(fp); + if (codepoint == -PSF2_STARTSEQ) + { + /* Introduces a sequence of combining characters; these are + * not supported */ + do + { + codepoint = _psf_font_read_utf8(fp); + } while (codepoint != -1 && codepoint != -PSF2_SEPARATOR); + } + if (codepoint == -PSF2_SEPARATOR) + { + ++pos; /* next glyph position */ + } + else if (codepoint < 0) + { + break; /* end of file or error */ + } + else + { + /* single code point mapped to the current position */ + if (pos >= fdata->header.length) + goto error; + if (_psf_font_map_char(fdata, codepoint, pos) < 0) + goto error; + } + } + } + + /* Provide a blank glyph for nonexistent mappings */ + if (_psf_font_do_glyph_data(fdata, 0xFFFD) == NULL) + { + fdata->blank = calloc(1, fdata->header.charsize); + if (fdata->blank == NULL) + goto error; + } + else + { + fdata->blank = NULL; + } + + fclose(fp); + PDC_state.font_close = _psf_font_close; + PDC_state.font_char_width = _psf_font_char_width; + PDC_state.font_char_height = _psf_font_char_height; + PDC_state.font_glyph_data = _psf_font_glyph_data; + return 0; + +error: + if (fp != NULL) + fclose(fp); + _psf_font_do_close(fdata); + return -1; +} + +/* Close the normal or the bold font */ +static void _psf_font_close(bool bold) +{ + _psf_font_do_close(&psf_fonts[bold != 0]); +} + +/* Free memory associated with a font */ +static void _psf_font_do_close(struct font_data *fdata) +{ + size_t pos; + unsigned i, j; + + /* Free the glyph data */ + if (fdata->glyphs != NULL) + { + for (pos = 0; pos < fdata->header.length; ++pos) + free(fdata->glyphs[pos]); + free(fdata->glyphs); + fdata->glyphs = NULL; + } + free(fdata->blank); + fdata->blank = NULL; + + /* Free the Unicode mapping */ + for (i = 0; i < 17; ++i) + { + if (fdata->map[i] != NULL) + { + for (j = 0; j < 256; ++j) + free(fdata->map[i][j]); + free(fdata->map[i]); + fdata->map[i] = NULL; + } + } +} + +/* Local function to read a UTF-8 sequence or a separator from the font file */ +static long _psf_font_read_utf8(FILE *fp) +{ + int byte; + long codepoint; + long min; + unsigned count; + + /* Read first byte */ + byte = fgetc(fp); + if (byte == EOF) + return -1; + if (byte == PSF2_STARTSEQ || byte == PSF2_SEPARATOR) + return -byte; /* markers meaningful to the font format */ + if (byte < 0x80) + { + return byte; /* ASCII */ + } + else if (byte < 0xC2) + { + return -1; /* Not valid as first byte */ + } + else if (byte < 0xE0) + { + /* Two byte character */ + codepoint = byte & 0x1F; + min = 0x80; + count = 1; + } + else if (byte < 0xF0) + { + /* Three byte character */ + codepoint = byte & 0x0F; + min = 0x800; + count = 2; + } + else if (byte < 0xF5) + { + /* Four byte character */ + codepoint = byte & 0x07; + min = 0x10000; + count = 3; + } + else + { + return -1; /* Not valid as first byte */ + } + + /* Read continuation bytes */ + while (count != 0) + { + byte = fgetc(fp); + if (byte < 0x80 || 0xBF < byte) + return -1; + codepoint = (codepoint << 6) | (byte & 0x3F); + --count; + } + + /* Check for overlong, surrogate, out of range */ + if (codepoint < min || codepoint > 0x10FFFF + || (0xD800 <= codepoint && codepoint <= 0xDFFF)) + return -1; + + return codepoint; +} + +/* Local function to establish a mapping from a codepoint to a font position */ +static int _psf_font_map_char(struct font_data *fdata, long codepoint, size_t pos) +{ + unsigned t1 = codepoint >> 16; + unsigned t2 = (codepoint >> 8) & 0xFF; + unsigned t3 = codepoint & 0xFF; + unsigned i; + + if (fdata->map[t1] == NULL) + { + fdata->map[t1] = calloc(256, sizeof(fdata->map[0][0])); + if (fdata->map[t1] == NULL) + return -1; + } + if (fdata->map[t1][t2] == NULL) + { + fdata->map[t1][t2] = malloc(256 * sizeof(fdata->map[0][0][0])); + if (fdata->map[t1][t2] == NULL) + return -1; + for (i = 0; i < 256; ++i) + fdata->map[t1][t2][i] = (size_t)-1; + } + fdata->map[t1][t2][t3] = pos; + return 0; +} + +/* Return the character width in pixels */ +static unsigned _psf_font_char_width(bool bold) +{ + return psf_fonts[bold != 0].header.width; +} + +/* Return the character height in pixels */ +static unsigned _psf_font_char_height(bool bold) +{ + return psf_fonts[bold != 0].header.height; +} + +/* Return the glyph data as read from the file */ +/* Never returns NULL. If the codepoint is not mapped, returns the mapping + * for U+FFFD if that exists, or the blank glyph otherwise */ +static const unsigned char *_psf_font_glyph_data( + bool bold, unsigned long codepoint) +{ + struct font_data *fdata = &psf_fonts[bold != 0]; + const unsigned char *bitmap; + + bitmap = _psf_font_do_glyph_data(fdata, codepoint); + if (bitmap == NULL) + bitmap = _psf_font_do_glyph_data(fdata, 0xFFFD); + if (bitmap == NULL) + bitmap = fdata->blank; + + return bitmap; +} + +/* Return the glyph data as read from the file */ +/* Local function used by PDC_psf_glyph_data; can return NULL */ +static const unsigned char *_psf_font_do_glyph_data( + struct font_data *fdata, long codepoint) +{ + unsigned t1 = codepoint >> 16; + unsigned t2 = (codepoint >> 8) & 0xFF; + unsigned t3 = codepoint & 0xFF; + const unsigned char *bitmap = NULL; + size_t pos; + + if (t1 <= 17 && fdata->map[t1] != NULL && fdata->map[t1][t2] != NULL) + { + pos = fdata->map[t1][t2][t3]; + if (pos != (size_t)-1) + bitmap = fdata->glyphs[pos]; + } + return bitmap; +} diff --git a/dosvga/pdcsetsc.c b/dosvga/pdcsetsc.c new file mode 100644 index 000000000..12b3811e5 --- /dev/null +++ b/dosvga/pdcsetsc.c @@ -0,0 +1,88 @@ +/* PDCurses */ + +#include "pdcdos.h" + +/*man-start************************************************************** + +pdcsetsc +-------- + +### Synopsis + + int PDC_set_blink(bool blinkon); + int PDC_set_bold(bool boldon); + void PDC_set_title(const char *title); + +### Description + + PDC_set_blink() toggles whether the A_BLINK attribute sets an actual + blink mode (TRUE), or sets the background color to high intensity + (FALSE). The default is platform-dependent (FALSE in most cases). It + returns OK if it could set the state to match the given parameter, + ERR otherwise. On DOS, this function also adjusts the value of COLORS + -- 16 for FALSE, and 8 for TRUE. + + PDC_set_bold() toggles whether the A_BOLD attribute selects an actual + bold font (TRUE), or sets the foreground color to high intensity + (FALSE). It returns OK if it could set the state to match the given + parameter, ERR otherwise. + + PDC_set_title() sets the title of the window in which the curses + program is running. This function may not do anything on some + platforms. + +### Portability + X/Open ncurses NetBSD + PDC_set_blink - - - + PDC_set_title - - - + +**man-end****************************************************************/ + +int PDC_curs_set(int visibility) +{ + int ret_vis, start, end; + + PDC_LOG(("PDC_curs_set() - called: visibility=%d\n", visibility)); + + ret_vis = SP->visibility; + SP->visibility = visibility; + + switch (visibility) + { + case 0: /* invisible */ + start = 1; + end = 0; + break; + case 2: /* highly visible */ + start = 0; /* full-height block */ + end = PDC_state.font_height - 1; + break; + default: /* normal visibility */ + start = SP->orig_cursor >> 8; + end = SP->orig_cursor & 0xFF; + } + + PDC_private_cursor_off(); + PDC_state.cursor_start = start; + PDC_state.cursor_end = end; + if (visibility != 0) + PDC_private_cursor_on(PDC_state.cursor_row, PDC_state.cursor_col); + + return ret_vis; +} + +void PDC_set_title(const char *title) +{ + PDC_LOG(("PDC_set_title() - called: <%s>\n", title)); +} + +int PDC_set_blink(bool blinkon) +{ + return blinkon ? ERR : OK; +} + +int PDC_set_bold(bool boldon) +{ + /* TODO: support this */ + return boldon ? ERR : OK; +} diff --git a/dosvga/pdcutil.c b/dosvga/pdcutil.c new file mode 100644 index 000000000..67b12833d --- /dev/null +++ b/dosvga/pdcutil.c @@ -0,0 +1,108 @@ +/* PDCurses */ + +#include "pdcdos.h" + +void PDC_beep(void) +{ + PDCREGS regs; + + PDC_LOG(("PDC_beep() - called\n")); + + regs.W.ax = 0x0e07; /* Write ^G in TTY fashion */ + regs.W.bx = 0; + PDCINT(0x10, regs); +} + +void PDC_napms(int ms) +{ + PDCREGS regs; + long goal, start, current; + + PDC_LOG(("PDC_napms() - called: ms=%d\n", ms)); + + goal = DIVROUND((long)ms, 50); + if (!goal) + goal++; + + start = getdosmemdword(0x46c); + + goal += start; + + while (goal > (current = getdosmemdword(0x46c))) + { + if (current < start) /* in case of midnight reset */ + return; + + regs.W.ax = 0x1680; + PDCINT(0x2f, regs); + PDCINT(0x28, regs); + } +} + +const char *PDC_sysname(void) +{ + return "DOSVGA"; +} + +#ifdef __DJGPP__ + +unsigned char getdosmembyte(int offset) +{ + unsigned char b; + + dosmemget(offset, sizeof(unsigned char), &b); + return b; +} + +unsigned short getdosmemword(int offset) +{ + unsigned short w; + + dosmemget(offset, sizeof(unsigned short), &w); + return w; +} + +unsigned long getdosmemdword(int offset) +{ + unsigned long dw; + + dosmemget(offset, sizeof(unsigned long), &dw); + return dw; +} + +void setdosmembyte(int offset, unsigned char b) +{ + dosmemput(&b, sizeof(unsigned char), offset); +} + +void setdosmemword(int offset, unsigned short w) +{ + dosmemput(&w, sizeof(unsigned short), offset); +} + +void setdosmemdword(int offset, unsigned long d) +{ + dosmemput(&d, sizeof(unsigned long), offset); +} + +#endif + +#if defined(__WATCOMC__) && defined(__386__) + +void PDC_dpmi_int(int vector, pdc_dpmi_regs *rmregs) +{ + union REGPACK regs = {0}; + + rmregs->w.ss = 0; + rmregs->w.sp = 0; + rmregs->w.flags = 0; + + regs.w.ax = 0x300; + regs.h.bl = vector; + regs.x.edi = FP_OFF(rmregs); + regs.x.es = FP_SEG(rmregs); + + intr(0x31, ®s); +} + +#endif diff --git a/dosvga/pdcvesa.h b/dosvga/pdcvesa.h new file mode 100644 index 000000000..0bfc1fd0e --- /dev/null +++ b/dosvga/pdcvesa.h @@ -0,0 +1,88 @@ +/* VESA structures from the VESA BIOS Specification, retrieved 15 Jan 2016 + * from http://flint.cs.yale.edu/cs422/readings/hardware/vbe3.pdf */ + +#ifndef PDCVESA_H +#define PDCVESA_H + +#ifdef __GNUC__ +#pragma pack(push, 1) +#endif +#ifdef __WATCOMC__ +#pragma pack(__push, 1) +#endif +struct VbeInfoBlock { + unsigned char VbeSignature[4]; /* VBE Signature */ + unsigned short VbeVersion; /* VBE Version */ + unsigned long OemStringPtr; /* VbeFarPtr to OEM String */ + unsigned long Capabilities; /* Capabilities of graphics controller */ + unsigned long VideoModePtr; /* VbeFarPtr to VideoModeList */ + unsigned short TotalMemory; /* Number of 64kb memory blocks */ + /* Added for VBE 2.0+ */ + unsigned short OemSoftwareRev; /* VBE implementation Software revision */ + unsigned long OemVendorNamePtr; /* VbeFarPtr to Vendor Name String */ + unsigned long OemProductNamePtr; /* VbeFarPtr to Product Name String */ + unsigned long OemProductRevPtr; /* VbeFarPtr to Product Revision String */ + unsigned char Reserved[222]; /* Reserved for VBE implementation scratch area */ + unsigned char OemData[256]; /* Data Area for OEM Strings */ +}; + +struct ModeInfoBlock { + /* Mandatory information for all VBE revisions */ + unsigned short ModeAttributes; /* mode attributes */ + unsigned char WinAAttributes; /* window A attributes */ + unsigned char WinBAttributes; /* window B attributes */ + unsigned short WinGranularity; /* window granularity */ + unsigned short WinSize; /* window size */ + unsigned short WinASegment; /* window A start segment */ + unsigned short WinBSegment; /* window B start segment */ + unsigned long WinFuncPtr; /* real mode pointer to window function */ + unsigned short BytesPerScanLine; /* bytes per scan line */ + /* Mandatory information for VBE 1.2 and above */ + unsigned short XResolution; /* horizontal resolution in pixels or characters */ + unsigned short YResolution; /* vertical resolution in pixels or characters */ + unsigned char XCharSize; /* character cell width in pixels */ + unsigned char YCharSize; /* character cell height in pixels */ + unsigned char NumberOfPlanes; /* number of memory planes */ + unsigned char BitsPerPixel; /* bits per pixel */ + unsigned char NumberOfBanks; /* number of banks */ + unsigned char MemoryModel; /* memory model type */ + unsigned char BankSize; /* bank size in KB */ + unsigned char NumberOfImagePages; /* number of images */ + unsigned char Reserved1; /* reserved for page function */ + /* Direct Color fields (required for direct/6 and YUV/7 memory models) */ + unsigned char RedMaskSize; /* size of direct color red mask in bits */ + unsigned char RedFieldPosition; /* bit position of lsb of red mask */ + unsigned char GreenMaskSize; /* size of direct color green mask in bits */ + unsigned char GreenFieldPosition; /* bit position of lsb of green mask */ + unsigned char BlueMaskSize; /* size of direct color blue mask in bits */ + unsigned char BlueFieldPosition; /* bit position of lsb of blue mask */ + unsigned char RsvdMaskSize; /* size of direct color reserved mask in bits */ + unsigned char RsvdFieldPosition; /* bit position of lsb of reserved mask */ + unsigned char DirectColorModeInfo; /* direct color mode attributes */ + /* Mandatory information for VBE 2.0 and above */ + unsigned long PhysBasePtr; /* physical address for flat memory frame buffer */ + unsigned long Reserved2; /* Reserved - always set to 0 */ + unsigned short Reserved3; /* Reserved - always set to 0 */ + /* Mandatory information for VBE 3.0 and above */ + unsigned short LinBytesPerScanLine; /* bytes per scan line for linear modes */ + unsigned char BnkNumberOfImagePages; /* number of images for banked modes */ + unsigned char LinNumberOfImagePages; /* number of images for linear modes */ + unsigned char LinRedMaskSize; /* size of direct color red mask (linear modes) */ + unsigned char LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */ + unsigned char LinGreenMaskSize; /* size of direct color green mask (linear modes) */ + unsigned char LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */ + unsigned char LinBlueMaskSize; /* size of direct color blue mask (linear modes) */ + unsigned char LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes) */ + unsigned char LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */ + unsigned char LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */ + unsigned long MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */ + unsigned char Reserved4[190]; /* remainder of ModeInfoBlock */ +}; +#ifdef __GNUC__ +#pragma pack(pop) +#endif +#ifdef __WATCOMC__ +#pragma pack(__pop) +#endif + +#endif