/*
	hlib.C

	Version 1.1

	Hercules Library

	Copyright (C) 1993, Geoff Friesen B.Sc.
	All rights reserved.

	Developed with: Borland C++ 3.1
*/

/* =================================================================

One of the earliest video adaptors available to PC computers was the
Hercules video adaptor.  This adaptor consisted of an 80 column x 25
line text mode and a 720 column x 348 line graphics mode.  Color was
not an issue as the Hercules adaptor was a monochrome only device.

The Hercules video adaptor is not commonly used today.  A VGA or EGA
(also disappearing) video adaptor can emulate Hercules.

How does the Hercules video adaptor work?  The rest of this document
provides the answer.

The adaptor can be thought of as two separate units: a text unit and
a graphics unit.  The text unit is capable of displaying 80 columns
by 25 lines for a total of 2000 characters.  However, 4000 bytes are
required - two per character.  The first byte holds the character's
ASCII code and the second holds an attribute byte used in displaying
this character (for information on how this attribute byte is organ-
ized, consult the documentation in BMNU.ZIP - my menu program).

Hercules video memory begins at segment b000h (hexadecimal) and con-
sists of 32,768 bytes or 32 kilobytes.  Memory is divided into four
8192-byte regions.  Region one begins at address b000:0000h.  Region
two begins at b000:2000h.  The third regions begins at b000:4000h.
The final region begins at b000:6000h.  Screen rows are interlaced
throughout these regions.  The first row begins in region one.  The
second begins in region two and is followed by the third row in the
third region.  The fourth row begins in region four.  The fifth row
follows the first row in the first region.  The following expression
computes the address of graphics location (x, y) where x ranges from
0-719 and y ranges from 0-347.  The resulting address is the address
of a byte containing the bit represented by (x,y).  A mask is needed
to get at the bit.

address = 8192*(y%4)+90*y/4+x/8;

This expression assumes that x and y are integers and C is the lang-
uage being used.

Like other video adaptors, a variety of I/O ports are used which are
accessed via the IN and OUT 80x86 instructions.  Most ports can only
be written to (which explains why memory resident programs are often
unable to popup correctly when Hercules graphics is active).  Port
addresses include:

03b4h - address register

A value from 0-17 is written to this register to select an internal
6845 CRT controller register.  Access is controlled by the following
register.

03b5h - data register

Once a 6845 internal register is selected, a value can be passed to
this value by using an OUT instruction and port 3b5h as the destina-
tion port.

03b8h - mode select register

This register selects the display mode (text or graphics).

03bah - status register

The status register is used in determining the existance of a Herc-
ules video adaptor.  If the least significant bit toggles between 0
and 1 then a Hercules adaptor might be present.  However, this could
also indicate a pure monochrome card with only 80 x 25 text display.

03bfh - config register

The video RAM configuration is controlled by this register.  Graphic
and text RAM is different.

I cannot go into further detail about using these registers because
improper use could result in hardware damage to the monitor.

==================================================================== */

#if !defined(__LARGE__)
#error Large Memory Model Expected
#endif

#pragma inline

#include <dir.H>
#include <dos.H>
#include <io.H>
#include <math.H>
#include <stdio.H>
#include <string.H>

#include "hlib.H"

/* -------------------------------- */
/* MDA Adaptor Video Port Constants */
/* -------------------------------- */

#define	ADDRESS_PORT	0x3b4
#define	DATA_PORT	0x3b5
#define	MODE_PORT	0x3b8
#define	STATUS_PORT	0x3ba
#define	CONFIG_PORT	0x3bf

/* ------------------ */
/* Internal Variables */
/* ------------------ */

/*
   (curx, cury) defines the current position used by
   hline (), hlineto (), hmoveto (), hputc (), hputs (),
   hwherex (), and hwherey ().  The default position is
   the center of the screen.
*/

static int curx = 360;
static int cury = 174;
static int state = WHITE_ON_BLACK;
static int xaspect = 0;
static int yaspect = 0;

#define	DRVSIZ	5000

static char driver [DRVSIZ+16] = { 0 };

/*
   font contains the character data used by
   hputc () & hputs () in drawing characters
*/

static unsigned char font [] =
{
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
   0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
   0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
   0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
   0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
   0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
   0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
   0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
   0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
   0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
   0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
   0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
   0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
   0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
   0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
   0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
   0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
   0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
   0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
   0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
   0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
   0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
   0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
   0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
   0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
   0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
   0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
   0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
   0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
   0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
   0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
   0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
   0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
   0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
   0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
   0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
   0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
   0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
   0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
   0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
   0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
   0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
   0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
   0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
   0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
   0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
   0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
   0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
   0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
   0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
   0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
   0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
   0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
   0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
   0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
   0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
   0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
   0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
   0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
   0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
   0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
   0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
   0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
   0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
   0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
   0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
   0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
   0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
   0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
   0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
   0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
   0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
   0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
   0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
   0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
   0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
   0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
   0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
   0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
   0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
   0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
   0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
   0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
   0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
   0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
   0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
   0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
   0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
   0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
   0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
   0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
   0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
   0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
   0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
   0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
   0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
   0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
   0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
   0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
   0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
   0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
   0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
   0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
   0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
   0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
   0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
   0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
   0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
   0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
   0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
   0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
   0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
   0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
   0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
   0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
   0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
   0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78,
   0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
   0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
   0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
   0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
   0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
   0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
   0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
   0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
   0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
   0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
   0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
   0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
   0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
   0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
   0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
   0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
   0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
   0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
   0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
   0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
   0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
   0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
   0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
   0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
   0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
   0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
   0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
   0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
   0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
   0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
   0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
   0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
   0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
   0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
   0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
   0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
   0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
   0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
   0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
   0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
   0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
   0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
   0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
   0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
   0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
   0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
   0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
   0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
   0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
   0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
   0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
   0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
   0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
   0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
   0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
   0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
   0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
   0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
   0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
   0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
   0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
   0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
   0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
   0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
   0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
   0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
   0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
   0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
   0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
   0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
   0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
   0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
   0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
   0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
   0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
   0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
   0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
   0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
   0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
   0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
   0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
   0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
   0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
   0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
   0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
   0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
   0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
   0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
   0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
   0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
   0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
   0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
   0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
   0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
   0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
   0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
   0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
   0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
   0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
   0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
   0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
   0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
   0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
   0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
   0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
   0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
   0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
   0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
   0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* ------------------------- */
/* Local Function Prototypes */
/* ------------------------- */

void plot (int cx, int cy, int x, int y);

/* --------------------------------------------- */
/* void haspect (double aspect);                 */
/*                                               */
/* Define horizontal and vertical aspect ratios. */
/* These ratios define the shape of resulting    */
/* circles.  A value of 1.0 defines a perfectly  */
/* round circle.  Larger values define ellipses  */
/* that are short and fat.  Smaller values spec- */
/* ify elipses that are tall and skinny.         */
/* --------------------------------------------- */

void haspect (double aspect)
{
   xaspect = 0;
   yaspect = 0;

   aspect = fabs (aspect);
   if (aspect != 1.0)
      if (aspect > 1.0)
	  yaspect = 65536.0 / aspect;
      else
	  xaspect = 65536.0 * aspect;
}

/* -------------------------------------------------------------- */
/* void hbezier1 (int x1, int y1, int x2, int y2, int x3, int y3, */
/*		  double ss);                                     */
/*                                                                */
/* Plot a first order Bezier curve.  The three control points are */
/* located at (x1, y1), (x2, y2), and (x3, y3).  The step size is */
/* contained in ss.                                               */
/* -------------------------------------------------------------- */

void hbezier1 (int x1, int y1, int x2, int y2, int x3, int y3, double ss)
{
   double one_minus_u, u = 0.0, u2, usquared;

   do
   {
      one_minus_u = 1-u;
      u2 = 2*u;
      usquared = u*u;

      hplot ((x1*one_minus_u+x2*u2)*one_minus_u+x3*usquared,
	     (y1*one_minus_u+y2*u2)*one_minus_u+y3*usquared);

      if ((u += ss) > 1.0)
	  return;
   }
   while (1);
}

/* ------------------------------------------------------ */
/* void hcenter (const char *s, int *cx, int *cy);        */
/*                                                        */
/* Return the centered (x, y) coordinates via *cx and *cy */
/* of the upper-left corner of the left-most character of */
/* a string pointed to by s.                              */
/* ------------------------------------------------------ */

void hcenter (const char *s, int *cx, int *cy)
{
   *cx = (720-strlen (s)*8) >> 1;
   *cy = (VSIZE-8) >> 1;
}

/* ---------------------------------------------- */
/* void hcircle (int cx, int cy, int radius);     */
/*                                                */
/* Draw a circle centered at (cx, cy) and having  */
/* a radius specified by radius.  See haspect for */
/* information regarding the circle's shape.      */
/* ---------------------------------------------- */

void hcircle (int cx, int cy, int radius)
{
   int x, _x, y, _y, sum;

   x = 0;
   y = radius << 1;
   sum = 0;

   while (x <= y)
   {
      if (!(x & 1))   /* plot if x is even */
      {
	  _x = x >> 1;
	  _y = (y+1) >> 1;

	  plot (cx, cy, _x, _y);
	  plot (cx, cy, -_x, _y);
	  plot (cx, cy, _x, -_y);
	  plot (cx, cy, -_x, -_y);
	  plot (cx, cy, _y, _x);
	  plot (cx, cy, -_y, _x);
	  plot (cx, cy, _y, -_x);
	  plot (cx, cy, -_y, -_x);
      }
      if ((sum += ((x++ << 1) + 1)) > 0)
	  sum -= ((y-- << 1) - 1);
   }
}

/* ------------------------------------------------- */
/* void hcls (void);                                 */
/*                                                   */
/* Clear graphics memory.  Memory is either cleared  */
/* to BLACK or WHITE depending on the drawing state. */
/* ------------------------------------------------- */

void hcls (void)
{
   asm mov cx, 4000h
   asm mov ax, 0b000h
   asm mov es, ax
   asm mov di, 0

   asm mov ax, 0
   asm cmp state, BLACK_ON_WHITE
   asm jnz hcls1
   asm not ax

hcls1:

   asm cld
   asm rep stosw
}

/* ----------------------------------------------------- */
/* int hdriver (const char *filespec);                   */
/*                                                       */
/* Attempt to load Hercules Dump Driver.  The driver is  */
/* indicated by filespec.  A -1 is returned if the file  */
/* cannot be opened.  A -2 is returned if the file size  */
/* exceeds DRVSIZ bytes.  A -3 is returned if it cannot  */
/* be read into memory.  If the latter occurs, the mem-  */
/* ory where the driver is loaded could become corrupt.  */
/* To prevent problems the next time hdump () is called, */
/* the first byte of this space would be set to zero.    */
/* If no file extension is specified the HDD is assumed. */
/* ----------------------------------------------------- */

int hdriver (const char *filespec)
{
   FILE *fp;
   int (*_driver) (void);
   char _filespec [MAXPATH];
   char drive [MAXDRIVE];
   char dir [MAXDIR];
   char file [MAXFILE];
   char ext [MAXEXT];
   long address = (((long) FP_SEG(driver) << 4)+FP_OFF(driver)) >> 4, l;

   _driver = (int (*) ()) ((address+1) << 16);

   strcpy (_filespec, filespec);

   if (!(fnsplit (_filespec, drive, dir, file, ext) & EXTENSION))
   {
       strcpy (ext, ".HDD");
       fnmerge (_filespec, drive, dir, file, ext);
   }

   if ((fp = fopen (_filespec, "rb")) == NULL)
       return -1;

   if ((l = filelength (fileno(fp))) > DRVSIZ)
       return -2;

   if (fread (_driver, l, 1, fp) != 1)
   {
       (void) fclose (fp);
       *(char *) _driver = 0;
       return -3;
   }

   (void) fclose (fp);

   return 0;
}

/* -------------------------------------------------------- */
/* int hdump (void);                                        */
/*                                                          */
/* Execute HDD driver.  A -1 value is returned if no driver */
/* is loaded.  The driver should return 0 on success or any */
/* other value except -1 on failure.                        */
/* -------------------------------------------------------- */

int hdump (void)
{
   int (*_driver) (void);

   long address = (((long) FP_SEG(driver) << 4)+FP_OFF(driver)) >> 4;

   _driver = (int (*) ()) ((address+1) << 16);

   if (!(char *) _driver)
       return -1;

   return (*_driver) ();
}

/* ---------------------------------------------------- */
/* int hexist (void);                                   */
/*                                                      */
/* Return a nonzero value if a Hercules adaptor exists. */
/* Two checks are made.  A Hercules adaptor is part of  */
/* an MDA card.  Therefore, the horizontal retrace bit  */
/* in the status port should alternate between 1 and 0. */
/* Furthermore, memory locations b000:7ffe & b000:7fff  */
/* should exist.                                        */
/* ---------------------------------------------------- */

int hexist (void)
{
   struct time nt, ot;
   int diff, exist = 0, word;
   unsigned char newbyte, oldbyte;

   gettime (&ot);
   oldbyte = inportb(STATUS_PORT)&0x80;

   do
   {
      if ((newbyte = inportb(STATUS_PORT)&0x80) != oldbyte)
	  break;

      gettime (&nt);

      if ((diff = nt.ti_sec-ot.ti_sec) < 0)
	  diff = -diff;
   }
   while (diff != 2);

   if (oldbyte == newbyte)
       return 0;

   word = peek(0xb000, 0x7ffe);
   poke(0xb000, 0x7ffe, 0xaa55);
   if ((unsigned) peek(0xb000, 0x7ffe) == 0xaa55)
       exist = 1;
   else
   {
       outportb(CONFIG_PORT, 1);
       poke(0xb000, 0x7ffe, 0xaa55);
       if ((unsigned) peek(0xb000, 0x7ffe) == 0xaa55)
	   exist = 1;
   }
   poke(0xb000, 0x7ffe, word);

   return exist;
}

/* --------------------------------------------------- */
/* int hgetstate (void);                               */
/*                                                     */
/* Return the drawing state.  The two states are black */
/* pixels on a white background and white pixels on a  */
/* black background.  See the constants defined in the */
/* header file (BLACK_ON_WHITE and WHITE_ON_BLACK).    */
/* --------------------------------------------------- */

int hgetstate (void)
{
   return state;
}

/* --------------------------------------------- */
/* void hline (int x1, int y1, int x2, int y2);  */
/*                                               */
/* Draw a line from (x1, y1) to (x2, y2) and set */
/* the current position to (x2, y2).  The coord- */
/* inates should be in appropriate ranges (see   */
/* hreset () and hset ()).                       */
/* --------------------------------------------- */

void hline (int x1, int y1, int x2, int y2)
{
   int a, b, d, diag_inc, dx_diag, dy_diag;
   int dx_nondiag, dy_nondiag, i, nondiag_inc, xchg, x, y;

   x = x1;
   y = y1;
   a = x2-x1;
   b = y2-y1;

   if (a < 0)
   {
       a = -a;
       dx_diag = -1;
   }
   else
       dx_diag = 1;

   if (b < 0)
   {
       b = -b;
       dy_diag = -1;
   }
   else
       dy_diag = 1;

   if (a < b)
   {
       xchg = a;
       a = b;
       b = xchg;
       dx_nondiag = 0;
       dy_nondiag = dy_diag;
   }
   else
   {
       dx_nondiag = dx_diag;
       dy_nondiag = 0;
   }

   d = b+b-a;
   nondiag_inc = b+b;
   diag_inc = b+b-a-a;

   for (i = 0; i <= a; i++)
   {
	hplot (x, y);

	if (d < 0)
	{
	    x += dx_nondiag;
	    y += dy_nondiag;
	    d += nondiag_inc;
	}
	else
	{
	    x += dx_diag;
	    y += dy_diag;
	    d += diag_inc;
	}
   }

   curx = x2;
   cury = y2;
}

/* ------------------------------------------------------- */
/* void hlineto (int x, int y);                            */
/*                                                         */
/* Draw a line from the current position to (x, y) and set */
/* the current position to (x, y).  The (x, y) coordinates */
/* should be in appropriate ranges (see hreset () and      */
/* hset ()).                                               */
/* ------------------------------------------------------- */

void hlineto (int x, int y)
{
   hline (curx, cury, x, y);
   curx = x;
   cury = y;
}

/* ------------------------------------------------------------ */
/* void hmoveto (int x, int y);                                 */
/*                                                              */
/* Set the current position to (x, y).  The (x, y) coordinates  */
/* should be in appropriate ranges (see hreset () and hset ()). */
/* ------------------------------------------------------------ */

void hmoveto (int x, int y)
{
   curx = x;
   cury = y;
}

/* --------------------------------------- */
/* void hoff (void);                       */
/*                                         */
/* Disable graphics mode and clear screen. */
/* --------------------------------------- */

void hoff (void)
{
   int i;
   unsigned char monoparms [] =
   {
      97, 80, 82, 15, 25, 6, 25, 25, 2, 13, 11, 12, -1
   };

   outportb(MODE_PORT, 32);

   for (i = 0; i < 12; i++)
   {
	outportb(ADDRESS_PORT, (unsigned char) i);
	outportb(DATA_PORT, monoparms [i]);
   }

   asm mov cx, 07d0h
   asm mov ax, 0b000h
   asm mov es, ax
   asm mov di, 0
   asm mov ax, 0720h
   asm cld
   asm rep stosw

   outportb(MODE_PORT, 40);
}

/* -------------------------------------- */
/* void hon (void);                       */
/*                                        */
/* Enable graphics mode and clear screen. */
/* -------------------------------------- */

void hon (void)
{
   int i;
   unsigned char grafparms [] =
   {
      53, 45, 46, 7, 91, 2, 88, 88, 2, 3, 0, 0, -1
   };

   outportb(CONFIG_PORT, 1);
   outportb(MODE_PORT, 2);

   for (i = 0; i < 12; i++)
   {
	outportb(ADDRESS_PORT, (unsigned char) i);
	outportb(DATA_PORT, grafparms [i]);
   }

   hcls ();

   outportb(MODE_PORT, 10);
}

/* ---------------------------------------------------------- */
/* void hplot (int x, int y);                                 */
/*                                                            */
/* Set the pixel located at (x, y) to the appropriate state.  */
/* This state is the inverse of the state used by hunplot (). */
/* ---------------------------------------------------------- */

void hplot (int x, int y)
{
   if (state == WHITE_ON_BLACK)
       hset (x, y);
   else
       hreset (x, y);
}

/* --------------------------------------------------------- */
/* int hpoint (int x, int y);                                */
/*                                                           */
/* Return the current status of the pixel located at (x, y). */
/* The status is zero if the pixel is in the BLACK state or  */
/* nonzero if the pixel is in the WHITE state.  An undefined */
/* result is returned if the coordinates are not in range    */
/* (see hreset () and hset () for more information).         */
/* --------------------------------------------------------- */

int hpoint (int x, int y)
{
   asm mov ax, y
   asm cmp ax, VSIZE-1
   asm ja hpoint1

   asm mov bx, x
   asm cmp bx, 719
   asm ja hpoint1

   asm mov dx, ax
   asm shr ax, 1
   asm shr ax, 1
   asm mov cl, 90
   asm mul cl
   asm and dl, 3
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm add ah, dl
   asm mov dx, bx
   asm shr dx, 1
   asm shr dx, 1
   asm shr dx, 1
   asm add dx, ax
   asm and bx, 7
   asm mov cl, 7
   asm sub cl, bl
   asm mov al, 1
   asm shl al, cl
   asm mov bx, dx
   asm mov dx, 0b000h
   asm mov es, dx
   asm mov cl, es:[bx]
   asm and cl, al
   asm mov al, cl
   asm xor ah, ah

   asm or al, al
   asm jz hpoint1

   asm mov al, 1

hpoint1:

}

/* ----------------------------------------------------------------- */
/* void hputc (int c);                                               */
/*                                                                   */
/* Put a character on the screen.  The character is written with its */
/* upper-left corner appearing at the latest coordinates specified   */
/* by hmoveto ().  Coordinates are not updated.                      */
/* ----------------------------------------------------------------- */

void hputc (int c)
{
   int index = c << 3, mask, x = curx, y;

   for (y = cury; y < cury+8; y++)
   {
	for (mask = 128; mask; mask >>= 1, x++)
	     if (font [index] & mask)
		 hplot (x, y);
	     else
		 hunplot (x, y);

	x -= 8;
	index++;
   }
}

/* ---------------------------------------------------------------- */
/* void hputs (const char *s);                                      */
/*                                                                  */
/* Put a string of characters on the screen.  The string is written */
/* with the upper-most corner of the left-most character appearing  */
/* at the latest coordinates specified by hmoveto ().  The coordi-  */
/* nates are not updated.                                           */
/* ---------------------------------------------------------------- */

void hputs (const char *s)
{
   int i = 0, temp;

   temp = curx;

   while (*(s+i))
   {
      hputc ((unsigned) *(s+i++));
      curx += 8;
   }

   curx = temp;
}

/* ------------------------------------------------------- */
/* void hrectangle (int x1, int y1, int x2, int y2);       */
/*                                                         */
/* Draw a rectangle with upper-left corner at (x1, y1) and */
/* lower-right corner at (x2, y2).  Coordinates must be in */
/* valid ranges (see hreset () and hset ()).               */
/* ------------------------------------------------------- */

void hrectangle (int x1, int y1, int x2, int y2)
{
   hmoveto (x1, y1);
   hlineto (x2, y1);
   hlineto (x2, y2);
   hlineto (x1, y2);
   hlineto (x1, y1);
}

/* --------------------------------------------------- */
/* void hreset (int x, int y);                         */
/*                                                     */
/* Set the pixel located at (x, y) to the BLACK state. */
/* The pixel is not set if the coordinates are out of  */
/* range.  The x coordinate must lie in the range 0 to */
/* 719 and y must range from 0 to VSIZE-1 (VSIZE spec- */
/* ifies the maximum number of vertical pixels).       */
/* --------------------------------------------------- */

void hreset (int x, int y)
{
   asm mov ax, y
   asm cmp ax, VSIZE-1
   asm ja hreset1

   asm mov bx, x
   asm cmp bx, 719
   asm ja hreset1

   asm mov dx, ax
   asm shr ax, 1
   asm shr ax, 1
   asm mov cl, 90
   asm mul cl
   asm and dl, 3
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm add ah, dl
   asm mov dx, bx
   asm shr dx, 1
   asm shr dx, 1
   asm shr dx, 1
   asm add dx, ax
   asm and bx, 7
   asm mov cl, 7
   asm sub cl, bl
   asm mov al, 1
   asm shl al, cl
   asm not al
   asm mov bx, dx
   asm mov dx, 0b000h
   asm mov es, dx
   asm and es:[bx], al

hreset1:

}

/* --------------------------------------------------- */
/* void hset (int x, int y);                           */
/*                                                     */
/* Set the pixel located at (x, y) to the WHITE state. */
/* The pixel is not set if the coordinates are out of  */
/* range.  The x coordinate must lie in the range 0 to */
/* 719 and y must range from 0 to VSIZE-1 (VSIZE spec- */
/* ifies the maximum number of vertical pixels).       */
/* --------------------------------------------------- */

void hset (int x, int y)
{
   asm mov ax, y
   asm cmp ax, VSIZE-1
   asm ja hset1

   asm mov bx, x
   asm cmp bx, 719
   asm ja hset1

   asm mov dx, ax
   asm shr ax, 1
   asm shr ax, 1
   asm mov cl, 90
   asm mul cl
   asm and dl, 3
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm shl dl, 1
   asm add ah, dl
   asm mov dx, bx
   asm shr dx, 1
   asm shr dx, 1
   asm shr dx, 1
   asm add dx, ax
   asm and bx, 7
   asm mov cl, 7
   asm sub cl, bl
   asm mov al, 1
   asm shl al, cl
   asm mov bx, dx
   asm mov dx, 0b000h
   asm mov es, dx
   asm or es:[bx], al

hset1:

}

/* ------------------------------------------------------- */
/* void hsetstate (int _state);                            */
/*                                                         */
/* Set the drawing state.  The two states are black pixels */
/* on a white background or white pixels on a black back-  */
/* ground.  The screen is redrawn to the appropriate state */
/* (if the state changes).                                 */
/* ------------------------------------------------------- */

void hsetstate (int _state)
{
   if (state == _state)
       return;

   state = _state;

   asm push ds

   asm mov cx, 4000h
   asm mov ax, 0b000h
   asm mov ds, ax
   asm mov es, ax
   asm mov si, 0
   asm mov di, 0

hsetstate1:

   asm lodsw
   asm not ax
   asm stosw

   asm loop hsetstate1

   asm pop ds
}

/* ------------------------------------------------------- */
/* void _hsetstate (int _state);                           */
/*                                                         */
/* Set the drawing state.  The two states are black pixels */
/* on a white background or white pixels on a black back-  */
/* ground.                                                 */
/* ------------------------------------------------------- */

void _hsetstate (int _state)
{
   if (state == _state)
       return;

   state = _state;
}

/* --------------------------------------------------------- */
/* void hunplot (int x, int y);                              */
/*                                                           */
/* Set the pixel located at (x, y) to the appropriate state. */
/* This state is the inverse of the state used by hplot ().  */
/* --------------------------------------------------------- */

void hunplot (int x, int y)
{
   if (state == BLACK_ON_WHITE)
       hset (x, y);
   else
       hreset (x, y);
}

/* -------------------------------------------------------------- */
/* int hversion (void);                                           */
/*                                                                */
/* Return the library version number.  The least significant byte */
/* of the result holds the version number (the most significant 4 */
/* bits hold the major portion, the least significant 4 bits hold */
/* the minor portion).                                            */
/* -------------------------------------------------------------- */

int hversion (void)
{
   return 0x0011;	/* version 1.1 */
}

/* -------------------------------------------------------- */
/* int hwherex (void);                                      */
/*                                                          */
/* Return the current x position (specified by hmoveto ()). */
/* -------------------------------------------------------- */

int hwherex (void)
{
   return curx;
}

/* -------------------------------------------------------- */
/* int hwherey (void);                                      */
/*                                                          */
/* Return the current y position (specified by hmoveto ()). */
/* -------------------------------------------------------- */

int hwherey (void)
{
   return cury;
}

/* --------------- */
/* Local Functions */
/* --------------- */

/* -------------------------------------------------------------- */
/* void plot (int cx, int cy, int x, int y);                      */
/*                                                                */
/* Plot a point on the circle circumference centered at (cx, cy). */
/* The point is specified by (x, y).  The current aspect ratio is */
/* taken into account allowing us to generate ellipses.           */
/* -------------------------------------------------------------- */

static void plot (int cx, int cy, int x, int y)
{
   if (!xaspect)
       if (!yaspect)
	   hplot (x+cx, y+cy);
       else
	   hplot (x+cx, cy+(((long) y * (long) yaspect) >> 16));
   else
       hplot (cx+(((long) x * (long) xaspect) >> 16), y+cy);
}