Source to jet/console.c


Enter a symbol's name here to quickly find it.

#include <Events.h>
#include <Memory.h>
#include <OSUtils.h>
#include <Quickdraw.h>
#include <Resources.h>
#include <Windows.h>
#include <Script.h>

#include "jet.h"

#if 0
#define NEWKEY /* use the new key press method (doesn't quite work) */
#endif

#define MAXUNFRESH 10

#define DEF_FLAGS CURS_ON

#define KBDSIZE 0x80

#define ASIZE 1024

#define LEFT 4

#define INVERSE 1

typedef void (*Vfunc)(int);

#define paint cpaint

INLINE static void flash(void);
INLINE static void paint(int);
INLINE static void gotoxy(int, int);
INLINE static void clrline(int);
INLINE static void clear(void);
INLINE static void clrchar(int, int);
INLINE static void clrfrom(int, int, int, int);
INLINE static void delete_line(int);
INLINE static void insert_line(int);
INLINE static void markinvers(int, int);
INLINE static void smooth(void);

static void setbgcol(int);
static void setfgcol(int);
static void putesc(int);
static void escy1_putch(int);
static void escy_putch(int);
static void normal_putch(int);
INLINE static void put_ch(int);

static void kbdvec1(void);
static void kbdvec2(void *p);
static long kbdvec3(void);
static long ikbd(void);

unsigned char kbshft;
_KBDVECS kbd;
long keymsg;
short keymod;

static char keytbl[256];

short maxx, maxy;
static short flags;

static Vfunc state;
static Rect crect;
static short cx, cy;
static short escy1;
static short linelen;
static short savex, savey;
static short sincerefresh = 0;

static char scrbuf[(long)TOTROWS*TOTCOLS];
static char xtrabuf[(long)TOTROWS*(TOTCOLS+1)];
char *base[TOTROWS];
char *xbase[TOTROWS];
static char **screen;
static char **extras;

static RgnHandle rgn;

static _IOREC keyrec;
static char kbdbuf[KBDSIZE];

static char alinevars[ASIZE];

void init_console(void)
{
	int r;
	
	__aline = (__LINEA *)(alinevars + ASIZE);

	memset(scrbuf, ' ', (long)TOTROWS * TOTCOLS);
	memset(xtrabuf, '\0', (long)TOTROWS * (TOTCOLS + 1));
	for (r = 0; r < TOTROWS; r++) {
		base[r] = scrbuf + r * (long)TOTCOLS;
		xbase[r] = xtrabuf + r * ((long)TOTCOLS + 1);
	}
	flags = DEF_FLAGS;
	V_CEL_MX = maxx = pref.maxx;
	V_CEL_MY = maxy = pref.maxy;
	linelen = maxx + 1;	
	screen = base + (TOTROWS - maxy - 1);
	extras = xbase + (TOTROWS - maxy - 1);
	state = normal_putch;

	kbd.midivec = kbdvec1;
	kbd.vkbderr = kbdvec1;
	kbd.vmiderr = kbdvec1;
	kbd.statvec = kbdvec2;
	kbd.mousevec = kbdvec2;
	kbd.clockvec = kbdvec2;
	kbd.joyvec = kbdvec2;
	kbd.midisys = kbdvec3;
	kbd.ikbdsys = ikbd;
	keyrec.ibuf = kbdbuf;
	keyrec.ibufsiz = KBDSIZE;
	keyrec.ibufhd = 0;
	keyrec.ibuftl = 0;
	keyrec.ibuflow = 0x20;
	keyrec.ibufhi = 0x20;
	
	rgn = NewRgn();
}

long c_conws(const char *buf)
{
	const char *s = buf;
	const char *string;
	int count = 0;
	Rect r;
  
	if (flags & CURS_FSTATE)
		curs_off();
	scrollBottom();
	string = s;
	while (*s) {
		if ((*s >= ' ') && (cx < maxx) && (state == normal_putch)) {
			count++;
			*(screen[cy] + cx++) = *s++;
			markinvers(cx, cy);
		} else {
			if (count) {
				r.left = crect.left;
				crect.left += count * fwidth;
				crect.right = crect.left + fwidth;
				r.top = cy * fheight;
				r.bottom = r.top + ftotal;
				r.right = crect.left;
				InvalRect(&r);
				count = 0;
			}
			if (!emptySelection())
				if (((cy == selectedChars.top) && (cx >= selectedChars.left)) ||
				    ((cy == selectedChars.bottom) && (cx <= selectedChars.right)) ||
				    ((cy > selectedChars.top) && (cy < selectedChars.bottom)))
					clearSelection();
			put_ch(*s++);
#if 0
			/* put_ch might turn the cursor on ? */
			if (flags & CURS_FSTATE)
				curs_off();
#endif
			string = s;
		}
	}
	if (count) {
		r.left = crect.left;
		crect.left += count * fwidth;
		crect.right = crect.left + fwidth;
		r.top = cy * fheight;
		r.bottom = r.top + ftotal;
		r.right = crect.left;
		InvalRect(&r);
		if (!emptySelection())
			if (((cy == selectedChars.top) && (cx >= selectedChars.left)) ||
			    ((cy == selectedChars.bottom) && (cx <= selectedChars.right)) ||
			    ((cy > selectedChars.top) && (cy < selectedChars.bottom)))
				clearSelection();
	}
	return 0;
}

/*
 * this routine is called very often from the mint kernel. this allows
 * the event loop to keep up with events.
 */
long b_constat(short dev)
{
	eventloop();
	if (dev != 2)
		return 0;
	return (keyrec.ibufhd != keyrec.ibuftl) ? -1 : 0;
}

long b_costat(short dev)
{
	if (dev != 2)
		return 0;
	return -1;
}

long b_conin(short dev)
{
	short h;
	long r;

	if (dev != 2)
		return 0;
	while (keyrec.ibufhd == keyrec.ibuftl)
		eventloop();
	h = keyrec.ibufhd + 4;
	if (h >= keyrec.ibufsiz)
		h = 0;
	r = *((long *)(keyrec.ibuf + h));
	keyrec.ibufhd = h;
	return r;
}

long b_conout(short dev, short c)
{
	if (dev != 2)
		return 0;
	if (flags & CURS_FSTATE)
		curs_off();
	scrollBottom();
	put_ch(c);
	return 1;
}

long b_kbshift(short mode)
{
	return kbshft;
}

static void kbdvec1(void)
{
	DebugStr("\pkbdvec1 called");
}

static void kbdvec2(void *p)
{
	DebugStr("\pkbdvec2 called");
}

static long kbdvec3(void)
{
	DebugStr("\pkbdvec3 called");
	return 0;
}

static short mac2keys(long message, short modifiers, unsigned long *keys)
{
	short nkeys;
	unsigned long code, scan;
#if 0
	static Ptr transData;
	static long transState;
#endif
	
	kbshft = 0;
	nkeys = 1;
	scan = ((unsigned long)message >> 8) & 0xff;
	if (modifiers & optionKey) {
		if (((modifiers & controlKey) && !pref.swap_control) ||
			((modifiers & shiftKey) && pref.swap_control))
			kbshft = 0x0c;
#if 0
		else {
			if (transData == 0) {
#if 0
				transData = GetScriptManagerMVariable(smKCHRCache);
#else
				Handle h = GetResource(KCHR, 0);
				long size = GetHandleSize(h);
				transData = NewPtr(size);
				BlockMove(*h, transData, size);
#endif
				transState = 0;
			}

			/* translate the code into pure ASCII. */
			code = KeyTrans(transData, scan, &transState);

			/* pre-insert an escape so emacs thinks we typed meta-key. */
			keys[0] = 033;
			keys[1] = code | (scan << 16);
			return 2;
		}
#endif
	}
	switch (scan) {
#ifdef NEWKEY
	case 0x7e: /* up arrow */
		code = 0;
		scan = 0x48;
		break;
	case 0x7d: /* down arrow */
		code = 0;
		scan = 0x50;
		break;
	case 0x7c: /* right arrow */
		code = 0;
		scan = 0x4d;
		break;
	case 0x7b: /* left arrow */
		code = 0;
		scan = 0x4b;
		break;
#else
	case 0x7e: /* up arrow */
		code = 033;
		scan = 0;
		nkeys = 2;
		keys[1] = 'A';
		break;
	case 0x7d: /* down arrow */
		code = 033;
		scan = 0;
		nkeys = 2;
		keys[1] = 'B';
		break;
	case 0x7c: /* right arrow */
		code = 033;
		scan = 0;
		nkeys = 2;
		keys[1] = 'C';
		break;
	case 0x7b: /* left arrow */
		code = 033;
		scan = 0;
		nkeys = 2;
		keys[1] = 'D';
		break;
#endif
	case 0x7a: /* F1 */
		code = 0;
		scan = 0x3b;
		break;
	case 0x78: /* F2 */
		code = 0;
		scan = 0x3c;
		break;
	case 0x60: /* F5 */
		code = 0;
		scan = 0x3f;
		break;
	case 0x61: /* F6 */
		code = 0;
		scan = 0x40;
		break;
	default:
		code = (unsigned long)message & 0xff;
		if (kbshft == 0x0c) {
			switch (code) {
			case '1': /* F1 */
				code = 0;
				scan = 0x3b;
				break;
			case '2': /* F2 */
				code = 0;
				scan = 0x3c;
				break;
			case '5': /* F5 */
				code = 0;
				scan = 0x3f;
				break;
			case '6': /* F6 */
				code = 0;
				scan = 0x40;
				break;
			default:
				break;
			}
		}
		if (pref.swap_delete)
			if (scan == 0x75)
				code = 0x08;
			else if (scan == 0x33)
				code = 0x7f;
		if ((code == ' ') &&
				(((modifiers & controlKey) && !pref.swap_control) ||
					((modifiers & optionKey) && pref.swap_control))) {
			code = 0;
			scan = 0;
		}
		break;
	}
	keys[0] = code | (scan << 16);
	return nkeys;
}

static long ikbd(void)
{
	short t;
	short nkeys;
	unsigned long keys[2], *kp;

	nkeys = mac2keys(keymsg, keymod, keys);
	kp = keys;
	while (nkeys--) {
		t = keyrec.ibuftl + 4;
		if (t >= keyrec.ibufsiz)
			t = 0;
		*((unsigned long *)(keyrec.ibuf + t)) = *kp++;
		keyrec.ibuftl = t;
	}
	return 0;
}

_KBDVECS *x_kbdvbase(void)
{
	return &kbd;
}

/* this needs to be modified to return the correct value for
   the modem device too. see biosfs_init in biosfs.c (1.10) */
_IOREC *x_iorec(short dev)
{
	if (dev == 1) {
		return &keyrec;
	}
	return (_IOREC *)-EINVAL;
}

/* return some very large address for the screen base so that
 * mint doesn't try to move it.
 */
long x_physbase(void)
{
	return 0x7fffffff;
}

long x_logbase(void)
{
	return -EINVAL;
}

long x_bconmap(short dev)
{
	return -EINVAL;
}

long x_keytbl(void *nrml, void *shft, void *caps)
{
	return (long)keytbl;
}

/* routines for flashing the cursor */

INLINE static void
markinvers(int x, int y)
{
	if (flags & FINVERSE) {
		*(extras[y]) = '\255';
		*(extras[y] + x) |= INVERSE;
	} else
		*(extras[y] + x) &= ~INVERSE;
}

INLINE static void
smooth(void)
{
	if (sincerefresh >= MAXUNFRESH) {
		BeginUpdate(myWindow);
		refresh();
		EndUpdate(myWindow);
/*		eventloop(); */
	}
}

/* flash(): invert the character currently under the cursor */

INLINE static void
flash(void)
{
	GetClip(rgn);
	ClipRect(&crect);
	InvertRect(&crect);
	SetClip(rgn);
}

/* make sure the cursor is off */

void curs_off(void)
{
	if (flags & CURS_ON) {
		if (flags & CURS_FSTATE) {
			flash();
			flags &= ~CURS_FSTATE;
		}
	}
}

/* OK, show the cursor again (if appropriate) */

void curs_on(void)
{
	if (flags & CURS_ON) {
	/* if the cursor is flashing, we cheat a little and leave it off
	 * to be turned on again (if necessary) by the VBL routine
	 */
		if (pref.curs_flash) {
			return;
		}
		if (!(flags & CURS_FSTATE)) {
			flags |= CURS_FSTATE;
			flash();
		}
	}
}

/* enable/disable the cursor. */

void curs_enable()
{
	flags |= CURS_ON;
}

void curs_disable()
{
	flags &= ~CURS_ON;
}

/*
 * paint(c): put character 'c' at current position.
 */

INLINE static void
paint(int c)
{
	*(screen[cy] + cx) = c;
	markinvers(cx + 1, cy);
	InvalRect(&crect);
	flags &= ~CURS_FSTATE;
}

/*
 * gotoxy (x, y): move current cursor address to (x, y)
 * makes sure that (x, y) will be legal
 */

INLINE static void
gotoxy(int x, int y)
{
	if (x > maxx) x = maxx;
	else if (x < 0) x = 0;
	if (y > maxy) y = maxy;
	else if (y < 0) y = 0;
	if (flags & CURS_FSTATE)
		curs_off();

	cx = x;
	cy = y;
	crect.left = LEFT;
	if (x != 0)
		crect.left += cx * fwidth;
	crect.top = cy * fheight;
	crect.right = crect.left + fwidth;
	crect.bottom = crect.top + ftotal;
}

/*
 * clrline(n): clear line n
 */

INLINE static void
clrline(int n)
{
	Rect r;

	if (!emptySelection() &&
	    ((n >= selectedChars.top) && (n <= selectedChars.bottom)))
		clearSelection();
	
	r = conRect;
	if (n != maxy)
		r.bottom = (n + 1) * fheight;
	r.top = r.bottom - fheight;
	memset(screen[n], ' ', TOTCOLS);
	memset(extras[n], '\0', TOTCOLS + 1);
	InvalRect(&r);
}

/*
 * clear(): clear the whole screen
 */

INLINE static void
clear(void)
{
	int r;

	clearSelection();

	for (r = 0; r <= maxy; r++) {
		memset(screen[r], ' ', TOTCOLS);
		memset(extras[r], '\0', TOTCOLS + 1);
	}
	InvalRect(&conRect);
}

/*
 * clrchar(x, y): clear the (x,y) position on screen v
 */

INLINE static void
clrchar(int x, int y)
{
	Rect r;

	if (!emptySelection())
		if (((y == selectedChars.top) && (x >= selectedChars.left)) ||
		    ((y == selectedChars.bottom) && (x <= selectedChars.right)) ||
		    ((y > selectedChars.top) && (y < selectedChars.bottom)))
			clearSelection();
	
	*(screen[y] + x) = ' ';
	markinvers(x + 1, y);
	r.left = LEFT + x * fwidth;
	r.top = y * fheight;
	r.right = r.left + fwidth;
	r.bottom = r.top + ftotal;
	InvalRect(&r);
}

/*
 * clrfrom(x1, y1, x2, y2): clear from position (x1,y1) to
 * position (x2, y2) inclusive. It is assumed that y2 >= y1.
 */

INLINE static void
clrfrom(int x1, int y1, int x2, int y2)
{
	int i;
	Rect r;

	if (!emptySelection())
		if (((y1 == selectedChars.top) && (x1 <= selectedChars.left)) ||
		    ((y2 == selectedChars.top) && (x2 >= selectedChars.right)) ||
		    ((y1 == selectedChars.bottom) && (x1 <= selectedChars.right)) ||
		    ((y2 == selectedChars.bottom) && (x2 >= selectedChars.right)) ||
		    ((y1 < selectedChars.top) && (y2 > selectedChars.bottom)) ||
		    ((y1 > selectedChars.top) && (y2 < selectedChars.bottom)))
			clearSelection();

	/* clear from x1 on first line */
	if (y2 > y1) {
		for (i = x1; i <= maxx; i++) {
			*(screen[y1] + i) = ' ';
			markinvers(i + 1, y1);
		}
		r.left = LEFT + x1 * fwidth;
		r.top = y1 * fheight;
		r.right = LEFT + (maxx + 1) * fwidth;
		r.bottom = r.top + ftotal;
		InvalRect(&r);

		/* clear to x2 of last line */
		for (i = 0; i <= x2; i++) {
			*(screen[y2] + i) = ' ';
			markinvers(i + 1, y2);
		}
		r.left = LEFT;
		r.top = y2 * fheight;
		r.right = LEFT + (x2 + 1) * fwidth;
		r.bottom = r.top + ftotal;
		InvalRect(&r);
	} else {
		for (i = x1; i <= x2; i++) {
			*(screen[y1] + i) = ' ';
			markinvers(i + 1, y1);
		}
		r.left = LEFT + x1 * fwidth;
		r.top = y1 * fheight;
		r.right = LEFT + (x2 + 1) * fwidth;
		r.bottom = r.top + ftotal;
		InvalRect(&r);
	}
	
	/* clear intermediate lines if any */
	for (i = y1+1; i < y2; i++)
		clrline(i);
	sincerefresh += y2 - y1 + 1;
	smooth();
}

/*
 * delete_line(n): delete line n. The screen below this
 * line is scrolled up, and the bottom line is cleared.
 */

#define scroll() delete_line(0)

INLINE static void
delete_line(int n)
{
	Rect sRect;
	short r, nrows;
	char **tbase, **xtbase, *save, *xsave;
	
	sRect = conRect;
	if (n == 0) {
		nrows = TOTROWS - 1;
		tbase = base;
		xtbase = xbase;
	} else {
		sRect.top = n * fheight;
		nrows = maxy - n;
		tbase = screen;
		xtbase = extras;
	}
	save = tbase[n];
	xsave = xtbase[n];
	for (r = n; nrows--; r++) {
		tbase[r] = tbase[r+1];
		xtbase[r] = xtbase[r+1];
	}
	tbase[r] = save;
	xtbase[r] = xsave;
	sRect.bottom -= fheight;
	InvalRect(&sRect);
	
	selectedChars.top -= 1;
	selectedChars.bottom -= 1;
	
	/* clear the last line */
	clrline(maxy);
	sincerefresh++;
	smooth();
}

/*
 * insert_line(n): scroll all of the screen starting at line n down,
 * and then clear line n.
 */

INLINE static void
insert_line(int n)
{
	Rect sRect;
	short r;
	char *save, *xsave;
	
	save = screen[maxy];
	xsave = extras[maxy];
	for (r = maxy - 1; r >= n ; --r) {
		screen[r+1] = screen[r];
		extras[r+1] = extras[r];
	}
	screen[r+1] = save;
	extras[r+1] = xsave;
	sRect = conRect;
	sRect.top = n * fheight;
	InvalRect(&sRect);
	
	/* clear line n */
	clrline(n);
}

/*
 * special states for handling ESC b x and ESC c x. Note that for now,
 * color is ignored.
 */

static void
setbgcol(int c)
{
	state = normal_putch;
}

static void
setfgcol(int c)
{
	state = normal_putch;
}

/*
 * putesc(c): handle the control sequence ESC c
 */

static void
putesc(int c)
{
	int cx1, cy1;

	cx1 = cx; cy1 = cy;

	switch (c) {
	case 'A':		/* cursor up */
		gotoxy(cx1, cy1-1);
		break;
	case 'B':		/* cursor down */
		gotoxy(cx1, cy1+1);
		break;
	case 'C':		/* cursor right */
		gotoxy(cx1+1, cy1);
		break;
	case 'D':		/* cursor left */
		gotoxy(cx1-1, cy1);
		break;
	case 'E':		/* clear home */
		if (flags & CURS_FSTATE)
			curs_off();
		clear();
		/* fall through... */
	case 'H':		/* cursor home */
		gotoxy(0, 0);
		break;
	case 'I':		/* cursor up, insert line */
		if (cy1 == 0) {
			if (flags & CURS_FSTATE)
				curs_off();
			insert_line(0);
		}
		else
			gotoxy(cx1, cy1-1);
		break;
	case 'J':		/* clear below cursor */
		if (flags & CURS_FSTATE)
			curs_off();
		clrfrom(cx1, cy1, maxx, maxy);
		break;
	case 'K':		/* clear remainder of line */
		if (flags & CURS_FSTATE)
			curs_off();
		clrfrom(cx1, cy1, maxx, cy1);
		break;
	case 'L':		/* insert a line */
		gotoxy(0, cy1);
		insert_line(cy1);
		break;
	case 'M':		/* delete line */
		gotoxy(0, cy1);
		delete_line(cy1);
		break;
	case 'Y':
		state = escy_putch;
		return;		/* YES, this should be 'return' */

	case 'b':
		state = setfgcol;
		return;
	case 'c':
		state = setbgcol;
		return;
	case 'd':		/* clear to cursor position */
		if (flags & CURS_FSTATE)
			curs_off();
		clrfrom(0, 0, cx1, cy1);
		break;
	case 'e':		/* enable cursor */
		if (flags & CURS_FSTATE)
			curs_off();
		flags |= CURS_ON;
		break;
	case 'f':		/* disable cursor */
		if (flags & CURS_FSTATE)
			curs_off();
		flags &= ~CURS_ON;
		break;
	case 'j':		/* save cursor position */
		savex = cx;
		savey = cy;
		break;
	case 'k':		/* restore saved position */
		gotoxy(savex, savey);
		break;
	case 'l':		/* clear line */
		gotoxy(0, cy1);
		clrline(cy1);
		break;
	case 'o':		/* clear from start of line to cursor */
		if (flags & CURS_FSTATE)
			curs_off();
		clrfrom(0, cy1, cx1, cy1);
		break;
	case 'p':		/* reverse video on */
		flags |= FINVERSE;
		break;
	case 'q':		/* reverse video off */
		flags &= ~FINVERSE;
		break;
	case 'v':		/* wrap on */
		pref.fwrap = true;
		break;
	case 'w':
		pref.fwrap = false;
		break;
	}
	state = normal_putch;
}

/*
 * escy1_putch(c): for when an ESC Y + char has been seen
 */
static void
escy1_putch(int c)
{
	gotoxy(c - ' ', escy1 - ' ');
	state = normal_putch;
}

/*
 * escy_putch(c): for when an ESC Y has been seen
 */
static void
escy_putch(int c)
{
	escy1 = c;
	state = escy1_putch;
}

/*
 * normal_putch(c): put character 'c'. This is the default
 * for when no escape, etc. is active
 */

static void
normal_putch(int c)
{
	/* control characters */
	if (c < ' ') {
		switch (c) {
		case '\r':
			gotoxy(0, cy);
			return;
		case '\n':
			if (cy == maxy) {
				if (flags & CURS_FSTATE)
					curs_off();
				scroll();
			}
			else
				gotoxy(cx, cy+1);
			return;
		case '\b':
			gotoxy(cx-1, cy);
			return;
		case '\007':		/* BELL */
			SysBeep(5);
			return;
		case '\033':		/* ESC */
			state = putesc;
			return;
		case '\t':
			gotoxy((cx + 8) & ~7, cy);
			return;
		default:
			return;
		}
	}

	if ((cx > maxx) && pref.fwrap) { /* if we need to wrap */
		if (flags & CURS_FSTATE)
			curs_off();
		cx = 0;
		crect.left = LEFT;
		crect.right = crect.left + fwidth;
		normal_putch('\n');
	}

	if (!emptySelection())
		if (((cy == selectedChars.top) && (cx >= selectedChars.left)) ||
		    ((cy == selectedChars.bottom) && (cx <= selectedChars.right)) ||
		    ((cy > selectedChars.top) && (cy < selectedChars.bottom)))
			clearSelection();
	paint(c);
	cx++;

	/*
	 * Don't move cursor right if at limit
	 * Wrapping will take care of it when it is time.
	 */
	if (cx <= maxx) {
		crect.left = crect.right;
		crect.right += fwidth;
	}
}

INLINE static void
put_ch(int c)
{
	(*state)(c & 0x00ff);
}

void refresh(void)
{
	static Point one1 = { 1, 1 };
	char **p, **e, *x;
	int i, r, r1, r2;
	Rect iRect,sect;
	int none;
	
	sincerefresh = 0;
	iRect = (*myWindow->visRgn)->rgnBBox;
	
	/* <PCB> we need to know if the cursor will get obliterated, and mark it as so. */
	if (RectInRgn(&crect, myWindow->visRgn))
		flags &= ~CURS_FSTATE;
	
	r1 = iRect.top / fheight;
	r2 = (iRect.bottom + fheight - 1) / fheight;
	p = base + curVal + r1;
	e = xbase + curVal + r1;
	for (r = r1; r < r2; r++) {
		MoveTo(LEFT, r*fheight + fascent);
		StdText(maxx+1, (Ptr)*p++, one1, one1);
		if (**e++) {
			x = *(e - 1);
			none = true;
			sect.top = r * fheight;
			sect.bottom = sect.top + ftotal;
			for (i = 1; i <= maxx + 1; i++)
				if (*++x & INVERSE) {
					none = false;
					sect.left = LEFT + (i - 1) * fwidth;
					sect.right = sect.left + fwidth;
					InvertRect(&sect);
				}
			if (none)
				*x = '\0'; /* No longer any attributes on this line */
		}
	}
}

void resize(short rows, short columns)
{
	short v;

	v = (rows - 1) - maxy;
	V_CEL_MX = maxx = columns - 1;
	V_CEL_MY = maxy = rows - 1;
	linelen = maxx + 1;
	screen = base + (TOTROWS - maxy - 1);
	extras = xbase + (TOTROWS - maxy - 1);
	gotoxy(cx, cy + v);
}

/* called to update the cursor */
void swap_curs(void)
{
	static long nextblink = 0;
	long time;
	
	if (!(flags & CURS_ON) || (curVal != maxVal))
		return;
	if (pref.curs_flash) {
		time = TickCount();
		if (time >= nextblink) {
			nextblink = time + GetCaretTime();
			flash();
			flags ^= CURS_FSTATE;
		}
	} else {
		curs_on();
	}
}