[alt.sources] STDWIN 0.9.5, Part 05/19

guido@cwi.nl (Guido van Rossum) (03/04/91)

Archive-name: stdwin/part05

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 19)."
# Contents:  Appls/klok/klok.c Conf/proto.os.bsd Ports/alfa/menu.c
#   Ports/msdos/ptrm.c
# Wrapped by guido@voorn.cwi.nl on Mon Mar  4 12:37:24 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Appls/klok/klok.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Appls/klok/klok.c'\"
else
echo shar: Extracting \"'Appls/klok/klok.c'\" \(17064 characters\)
sed "s/^X//" >'Appls/klok/klok.c' <<'END_OF_FILE'
X/* Analog clock with alarm.
X   
X   Displays the date at the top, a circular clock in the middle,
X   and the alarm time at the bottom of the window.
X   The clock has two hands.
X   
X   Resizing the window recomputes the items' positions and sizes.
X   
X   When the alarm goes off, the clock window is made current,
X   the clock face is inverted for 5 minutes, and a beep is emitted
X   each minute.  The alarm can be acknowledged explicitly, which
X   silences it until the next time the alarm goes off.
X   
X   Dragging the hands of the clock can be used to set the time
X   (and the date, if you care to drag around several times).
X   The alarm is currently set through a dialog only.
X
X   TO DO:
X   	- make the display prettier (how??? everything I design gets ugly :-( )
X	- display alarm time as tick mark?
X	- improve the alarm setting procedure
X	- add more general 'nag' and 'calendar'-like facilities
X	- add a button to allow/disallow setting the time
X	- add a way to change the date directly
X	- turn it into a subroutine package like VT or editwin
X	- organize the code top-down instead of bottom-up
X*/
X
X#include "tools.h"
X#include "stdwin.h"
X
X#include <ctype.h>
X#include <math.h>
X#include <time.h>
X#include <sys/types.h>		/* For time_t, on some systems */
X
X#ifndef PI
X#define PI 3.14159265359
X#endif
X
X/* Alarm parametrizations */
X
X#ifndef DEF_ALARM
X#define DEF_ALARM	-1	/* Initial setting of alarm */
X#endif
X#ifndef ALARMTIME
X#define ALARMTIME	5	/* Alarm goes for this many minutes */
X#endif
X
X/* Relative hand sizes */
X
X#define LITPERC		60	/* Little hand size (percent of radius) */
X#define BIGPERC		80	/* Big hand size */
X#define SECPERC		100	/* Seconds hand size */
X
X/* Menu items */
X
X#define SETALARM	0
X#define CLEARALARM	1
X#define OKALARM		2
X#define SECONDSHAND	4
X#define QUIT		6
X
X/* Global variables */
X
Xchar *progname = "klok";	/* Program name (for error messages) */
Xchar *title;			/* Menu title (default capitalized progname) */
XWINDOW *win;			/* Clock window */
XMENU *mp;			/* Menu pointer */
Xint centh, centv;		/* Clock center */
Xint radius;			/* Clock radius */
Xstruct tm curtime;		/* Current time/date */
Xint alarm = DEF_ALARM;		/* Alarm time (hh*60 + mm); -1 if off */
Xbool alarmed;			/* Is it alarm time? */
Xbool okayed;			/* Has the current alarm been OK'ed? */
Xbool excited;			/* == (alarmed && !okayed) */
Xbool do_seconds;		/* Set if drawing 'seconds' hand */
X
X/* Force a redraw of the entire window */
X
Xchangeall()
X{
X	wchange(win, 0, 0, 10000, 10000);
X}
X
X/* Compute the sine of an angle given in clock units
X   (zero at 12 o'clock, full circle is 60).
X   We cache the sine values in a table,
X   since calling sin is too slow on some systems. */
X
Xdouble
Xsine(i)
X	int i;
X{
X	static double sines[15+1];
X	static bool inited;
X	
X	if (!inited) {
X		int k;
X		inited = TRUE;
X		for (k = 0; k <= 15; ++k)
X			sines[k] = sin(k * PI/30);
X	}
X	i = i % 60;
X	if (i < 0)
X		i += 60;
X	if (i <= 15)
X		return sines[i];
X	if (i <= 30)
X		return sines[30-i];
X	if (i <= 45)
X		return -sines[i-30];
X	return -sines[60-i];
X}
X
X/* Compute the cosine (from the sine) */
X
Xdouble
Xcosine(i)
X	int i;
X{
X	return sine(i+15);
X}
X
X/* Compute the absolute position of the endpoint of a line drawn at
X   i minutes, whose length is a certain percentage of the radius */
X
Xvoid
Xendpoint(i, perc, ph, pv)
X	int i;		/* Minutes */
X	int perc;	/* Percentage of length */
X	int *ph, *pv;	/* Return values */
X{
X	double s = sine(i), c = cosine(i);
X	
X	*ph = centh + s*perc*radius/100 + 0.5;
X	*pv = centv - c*perc*radius/100 + 0.5;
X}
X
X/* Draw a mark at i minutes.
X   Marks at hour positions are longer, every 3 hours even longer. */
X
Xvoid
Xdrawmark(i)
X	int i;
X{
X	int begh, begv;
X	int endh, endv;
X	int len;
X	
X	endpoint(i, 100, &endh, &endv);
X	if (i % 5 != 0)
X		len = 3;
X	else if (i % 15 != 0)
X		len = 8;
X	else
X		len = 19;
X	endpoint(i, 100-len, &begh, &begv);
X	wdrawline(begh, begv, endh, endv);
X}
X
X/* Draw a hand at i minutes, whose length is a given percentage
X   of the radius */
X
Xvoid
Xdrawhand(i, perc)
X	int i;
X	int perc;
X{
X	int endh, endv;
X	endpoint(i, perc, &endh, &endv);
X	wdrawline(centh, centv, endh, endv);
X}
X
X/* Draw a hand in XOR mode */
X
Xvoid
Xxorhand(i, perc)
X	int i;
X	int perc;
X{
X	int endh, endv;
X	endpoint(i, perc, &endh, &endv);
X	wxorline(centh, centv, endh, endv);
X}
X
X/* Draw the date in the top left corner */
X
Xvoid
Xdrawdate(tp)
X	struct tm *tp;
X{
X	char buf[100];
X	
X	sprintf(buf, "%02d/%02d/%02d", tp->tm_year % 100,
X		tp->tm_mon+1, tp->tm_mday);
X	werase(0, 0, 10000, centv - radius);
X	wdrawtext(0, centv - radius - wlineheight(), buf, -1);
X}
X
X/* Draw the alarm time in the bottom left corner */
X
Xvoid
Xdrawalarm()
X{
X	char buf[100];
X	
X	sprintf(buf, "*%02d:%02d", alarm/60, alarm%60);
X	wdrawtext(0, centv + radius, buf, -1);
X}
X
X/* Compute the AM/MP/Noon/Midnight indicator character */
X
Xint
Xampm(tp)
X	struct tm *tp;
X{
X	if (tp->tm_min == 0 && tp->tm_hour%12 == 0) {
X		if (tp->tm_hour == 12)
X			return 'N';
X		else
X			return 'M';
X	}
X	else if (tp->tm_hour < 12)
X		return 'A';
X	else
X		return 'P';
X}
X
X/* Draw the AM/PM/Noon/Midnight indicator in the top right corner */
X
Xvoid
Xdrawampm(c)
X	int c;
X{
X	int dh = wcharwidth('M');
X	int dv = wlineheight();
X	int h = centh + radius - dh;
X	int v = centv - radius - dv;
X	
X	werase(h, v, h+dh, v+dv);
X	wdrawchar(h, v, c);
X}
X
X#ifdef UGLY
X
X/* Draw a shaded square around the clock */
X
X#define SHOFF 4
X
Xvoid
Xdrawborder()
X{
X	int d = radius * 10/9;
X	int left = centh-d, top = centv-d, right = centh+d, bottom = centv+d;
X	wdrawbox(left, top, right, bottom);
X	wshade(right, top+4, right+4, bottom+4, 50);
X	wshade(left+4, bottom, right, bottom+4, 50);
X}
X
X/* Draw a shaded circle around the clock's face;
X   the shadow is on the top left side, so the face appeares to
X   be slightly *lower* than the surrounding material.
X   Also a thin vertical line to indicate 6 and 12 o'clock. */
X
Xvoid
Xdrawoutline()
X{
X	wdrawcircle(centh-1, centv-1, radius+2);
X	wdrawelarc(centh-1, centv-1, radius+1, radius+1, 45-10, 45+180+10);
X	wdrawelarc(centh-1, centv-1, radius  , radius  , 45+10, 45+180-10);
X	wdrawline(centh, centv-radius, centh, centv+radius);
X}
X
X#endif /*UGLY*/
X
X/* Compute the little hand position from hour, min */
X
Xint
Xlittlehand(hour, min)
X	int hour, min;
X{
X	return (hour*5 + (min+6)/12) % 60;
X}
X
X/* Draw procedure */
X
Xvoid
Xdrawproc(win, left, top, right, bottom)
X	WINDOW *win;
X{
X	int i;
X	
X	/* Draw the fixed elements of the clock */
X#ifdef UGLY
X	drawborder();
X	drawoutline();
X#else
X#ifdef macintosh
X	wdrawcircle(centh+1, centv+1, radius+1);
X#else
X	wdrawcircle(centh, centv, radius);
X#endif
X	for (i = 0; i < 12; ++i)
X		drawmark(i*5);			/* Hour marks */
X#endif
X	
X	/* Draw the hands */
X	drawhand(curtime.tm_min, BIGPERC);
X	i = littlehand(curtime.tm_hour, curtime.tm_min);
X	if (i != curtime.tm_min)
X		xorhand(i, LITPERC);
X	if (do_seconds)
X		xorhand(curtime.tm_sec, SECPERC);
X	
X	/* Draw the other elements */
X	drawdate(&curtime);
X	drawampm(ampm(&curtime));
X	if (alarm >= 0)
X		drawalarm();
X		
X	/* Invert if the alarm is going */
X	if (excited)
X		winvert(0, 0, 10000, 10000);
X}
X
X/* Compute the nearest clock angle corresponding to
X   absolute position (h, v) */
X
Xint
Xwhereis(h, v)
X	int h, v;
X{
X	double dnew;
X	
X	h -= centh;
X	v -= centv;
X	if (h == 0 && v == 0)
X		return 0;
X	dnew = atan2((double)h, (double)(-v)) * 30.0 / PI;
X	if (dnew < 0)
X		dnew += 60.0;
X	return ((int)(dnew + 0.5)) % 60;
X}
X
X/* Show a change in time with minimal redrawing */
X
Xshowchange(old, new)
X	struct tm *old, *new;
X{
X	int litold = littlehand(old->tm_hour, old->tm_min);
X	int litnew = littlehand(new->tm_hour, new->tm_min);
X	int newampm = ampm(new);
X	
X	wbegindrawing(win);
X	
X	if (do_seconds && old->tm_sec != new->tm_sec) {
X		xorhand(old->tm_sec, SECPERC);
X		xorhand(new->tm_sec, SECPERC);
X	}
X	
X	if (old->tm_min != new->tm_min) {
X		xorhand(old->tm_min, BIGPERC);
X		xorhand(new->tm_min, BIGPERC);
X	}
X	
X	if (litold != litnew ||
X		litold == old->tm_min || litnew == new->tm_min) {
X		if (litold != old->tm_min)
X			xorhand(litold, LITPERC);
X		if (litnew != new->tm_min)
X			xorhand(litnew, LITPERC);
X	}
X	
X	if (old->tm_mday != new->tm_mday)
X		drawdate(new);
X	
X	if (newampm != ampm(old))
X		drawampm(newampm);
X	
X	wenddrawing(win);
X
X}
X
X/* Leap year calculation.  Input is year - 1900 (but may be >= 100). */
X
Xint
Xisleap(year)
X	int year;
X{
X	year += 1900;
X	
X	return year%4 == 0 && (year%100 != 0 || year%400 == 0);
X}
X
X/* Increment a time variable in minutes, and show the change */
X
Xvoid
Xincrshowtime(tp, incr)
X	struct tm *tp;
X	int incr;
X{
X	struct tm old;
X	static int mdays[12]=
X		{31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
X	
X	mdays[1] = 28 + isleap(tp->tm_year);
X	
X	old = *tp;
X	
X	tp->tm_min += incr;
X	
X	while (tp->tm_min >= 60) {
X		tp->tm_min -= 60;
X		tp->tm_hour++;
X		if (tp->tm_hour >= 24) {
X			tp->tm_hour -= 24;
X			tp->tm_mday++;
X			tp->tm_wday = (tp->tm_wday + 1) % 7;
X			if (tp->tm_mday > mdays[tp->tm_mon]) {
X				tp->tm_mday = 1;
X				tp->tm_mon++;
X				if (tp->tm_mon >= 12) {
X					tp->tm_mon = 0;
X					tp->tm_year++;
X					mdays[1] = 28 + isleap(tp->tm_year);
X				}
X			}
X		}
X	}
X	
X	while (tp->tm_min < 0) {
X		tp->tm_min += 60;
X		tp->tm_hour--;
X		if (tp->tm_hour < 0) {
X			tp->tm_hour += 24;
X			tp->tm_mday--;
X			tp->tm_wday = (tp->tm_wday + 6) % 7;
X			if (tp->tm_mday < 1) {
X				tp->tm_mon--;
X				if (tp->tm_mon < 0) {
X					tp->tm_mon = 11;
X					tp->tm_year--;
X					mdays[1] = 28 + isleap(tp->tm_year);
X				}
X				tp->tm_mday = mdays[tp->tm_mon];
X			}
X		}
X	}
X	
X	showchange(&old, tp);
X}
X
X/* Drag the little hand */
X
Xvoid
Xdraglittlehand(h, v)
X	int h, v;
X{
X	EVENT e;
X	struct tm newtime;
X	int i;
X	
X	newtime = curtime;
X	wsettimer(win, 0);
X	
X	do {
X		wgetevent(&e);
X		if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
X			showchange(&newtime, &curtime);
X			wungetevent(&e);
X			return;
X		}
X		i = whereis(e.u.where.h, e.u.where.v) / 5;
X		if ((i - newtime.tm_hour) % 12 != 0) {
X			int diff = i - newtime.tm_hour;
X			while (diff > 6)
X				diff -= 12;
X			while (diff < -6)
X				diff += 12;
X			incrshowtime(&newtime, diff*60);
X		}
X	} while (e.type != WE_MOUSE_UP);
X	setdatetime(&newtime, FALSE);
X	curtime = newtime;
X}
X
X/* Drag the big hand */
X
Xvoid
Xdragbighand(h, v)
X	int h, v;
X{
X	EVENT e;
X	struct tm newtime;
X	int i;
X	
X	newtime = curtime;
X	wsettimer(win, 0);
X	
X	do {
X		wgetevent(&e);
X		if (e.type != WE_MOUSE_MOVE && e.type != WE_MOUSE_UP) {
X			showchange(&newtime, &curtime);
X			wungetevent(&e);
X			return;
X		}
X		i = whereis(e.u.where.h, e.u.where.v);
X		if (i != newtime.tm_min) {
X			int diff = i - newtime.tm_min;
X			if (diff > 30)
X				diff -= 60;
X			else if (diff < -30)
X				diff += 60;
X			incrshowtime(&newtime, diff);
X		}
X	} while (e.type != WE_MOUSE_UP);
X	setdatetime(&newtime, TRUE);
X	curtime = newtime;
X}
X
X/* Test whether the given position lies on the hand at the
X   given clock angle with the given length percentage */
X
Xbool
Xtesthand(h, v, pos, perc)
X	int h, v;
X	int pos;
X	int perc;
X{
X	long dist2 = (h-centh)*(h-centh)+ (v-centv)*(v-centv);
X	long length2 = ((long)radius*perc/100) * ((long)radius*perc/100);
X	
X	if (dist2 > length2)
X		return FALSE;
X	if ((whereis(h, v) - pos) % 60 != 0)
X		return FALSE;
X	return TRUE;
X}
X
X/* Recompute the time and the alarm parameters.
X   Called every minute, and when other parameters may have changed. */
X
Xvoid
Xnewtime(flash)
X	bool flash;
X{
X	struct tm oldtime;
X	time_t now;
X	bool wasalarmed;
X	
X	/* Save the old time displayed */
X	oldtime = curtime;
X	
X	/* Get the current time */
X	time(&now);
X	curtime = *localtime(&now);
X	
X	/* Set the window timer to go off at the next tick */
X	if (do_seconds) {
X		wsettimer(win, 10);
X	}
X	else {
X		if (curtime.tm_sec >= 59) {
X			/* When we wake up just at the end of the minute,
X			   (which may happen if STDWIN isn't very precise),
X			   pretend it's a bit later, to avoid waking up
X			   again in a second */
X			curtime.tm_sec -= 60;
X			curtime.tm_min += 1;
X		}
X		wsettimer(win, 10 * (60 - curtime.tm_sec));
X	}
X	
X	/* Check whether the alarm should go off */
X	wasalarmed = alarmed;
X	if (!wasalarmed)
X		okayed = FALSE;
X	if (alarm >= 0) {
X		int a = alarm;
X		int hhmm = curtime.tm_hour*60 + curtime.tm_min;
X		if (hhmm < 60 && a >= 23*60)
X			hhmm += 24*60; /* Correct for wrap-around */
X		alarmed = hhmm >= a && hhmm < a+ALARMTIME;
X	}
X	else {
X		alarmed = okayed = FALSE;
X	}
X	excited = alarmed && !okayed;
X	if (excited) {
X		if (!wasalarmed)
X			wsetactive(win);
X		wfleep();
X	}
X	if (excited || wasalarmed && !okayed)
X		flash = TRUE;
X	wmenuenable(mp, OKALARM, excited);
X	
X	/* Redraw the clock face or schedule a redraw */
X	if (flash) {
X		changeall();
X	}
X	else {
X		showchange(&oldtime, &curtime);
X	}
X}
X
X/* Time-setting procedure by dragging the hands around */
X
Xvoid
Xchangehand(h, v)
X	int h, v;
X{
X	/* Test the little hand first, so that if the hands
X	   overlap, a click near the center implies the little
X	   hand and a click further away implies the big hand */
X	if (testhand(h, v,
X		littlehand(curtime.tm_hour, curtime.tm_min), LITPERC)) {
X		/* Drag the little hand -- minutes stay unchanged */
X		draglittlehand(h, v);
X	}
X	else if (testhand(h, v, curtime.tm_min, BIGPERC)) {
X		/* Drag the big hand -- hours may change, too */
X		dragbighand(h, v);
X	}
X	else {
X		/* No hit -- make some noise */
X		wfleep();
X	}
X	newtime(FALSE);
X}
X
X/* Recompute the clock size and position
X   and the time/alarm information.
X   Called initially and when the window is resized. */
X
Xvoid
Xgetallinfo()
X{
X	int width, height;
X	
X	wgetwinsize(win, &width, &height);
X	centh = width/2;
X	centv = height/2;
X	radius = centv - wlineheight();
X	CLIPMAX(radius, centh);
X	newtime(TRUE);
X}
X
X/* Set the alarm time from a string formatted as hhmm */
X
Xbool
Xsetalarm(str)
X	char *str;
X{
X	int al;
X	
X	if (str[0] == EOS || str[0] == '-' && str[1] == EOS) {
X		alarm = -1;
X		wmenuenable(mp, CLEARALARM, FALSE);
X		return TRUE;
X	}
X	al = atoi(str);
X	if (al < 0 || al > 2400 || al%60 >= 60)
X		return FALSE;
X	if (al == 2400)
X		al = 0;
X	alarm = (al/100)*60 + al%100;
X	wmenuenable(mp, CLEARALARM, TRUE);
X	return TRUE;
X}
X
X/* Set up the menu */
X
Xvoid
Xbuildmenu()
X{
X	wmenusetdeflocal(TRUE);
X	mp = wmenucreate(1, "Klok");
X	
X	wmenuadditem(mp, "Set alarm...", 'S');
X	wmenuadditem(mp, "Clear alarm", 'C');
X	wmenuadditem(mp, "OK alarm", 'O');
X	wmenuadditem(mp, "", -1);
X	wmenuadditem(mp, "Seconds Hand", 'H');
X	wmenuadditem(mp, "", -1);
X	wmenuadditem(mp, "Quit", 'Q');
X	
X	wmenuenable(mp, CLEARALARM, alarm >= 0);
X	wmenucheck(mp, SECONDSHAND, do_seconds);
X}
X
X/* Handle a menu selection */
X
Xvoid
Xdomenu(item)
X	int item;
X{
X	bool flash = FALSE;
X	
X	switch (item) {
X	case SETALARM: {
X		char buf[6];
X		if (alarm < 0)
X			buf[0] = EOS;
X		else
X			sprintf(buf, "%02d%02d", alarm/60, alarm%60);
X		if (!waskstr("Set alarm:", buf, sizeof buf))
X			return;
X		if (!setalarm(buf))
X			wmessage("Invalid alarm (must be hhmm)");
X		okayed = FALSE;
X		flash = TRUE;
X		break;
X		}
X	case CLEARALARM:
X		if (alarm >= 0) {
X			setalarm("");
X			flash = TRUE;
X		}
X		break;
X	case OKALARM:
X		if (excited) {
X			flash = okayed = TRUE;
X		}
X		break;
X	case SECONDSHAND:
X		do_seconds = !do_seconds;
X		wmenucheck(mp, SECONDSHAND, do_seconds);
X		wbegindrawing(win);
X		xorhand(curtime.tm_sec, SECPERC);
X		wenddrawing(win);
X		break;
X	case QUIT:
X		wclose(win);
X		wdone();
X		exit(0);
X		break;
X	}
X	newtime(flash);
X}
X
X#ifndef macintosh
X/* Print usage message and exit; called for command line errors */
X
Xvoid
Xusage()
X{
X	wdone();
X	fprintf(stderr,
X		"usage: %s [-s] [-m] [-a hhmm] [-t title]\n", progname);
X	exit(2);
X}
X#endif
X
X/* Main program */
X
Xmain(argc, argv)
X	int argc;
X	char **argv;
X{
X	/* Initialize */
X	winitargs(&argc, &argv);
X	buildmenu(); /* Must be done before setalarm is called */
X	
X	/* Find out program name */
X	if (argc > 0) {
X		progname = strrchr(argv[0], '/');
X		if (progname == NULL)
X			progname = argv[0];
X		else
X			++progname;
X	}
X	
X#ifndef macintosh
X	/* Parse command line */
X	for (;;) {
X		int c = getopt(argc, argv, "msa:t:");
X		if (c == EOF)
X			break;
X		switch (c) {
X		case 's':
X			do_seconds = TRUE;
X			break;
X		case 'm':
X			do_seconds = FALSE;
X			break;
X		case 'a':
X			if (!setalarm(optarg))
X				usage();
X			break;
X		case 't':
X			title = optarg;
X			break;
X		default:
X			usage();
X			/*NOTREACHED*/
X		}
X	}
X	wmenucheck(mp, SECONDSHAND, do_seconds);
X#endif
X	
X	/* Create the window */
X	wsetdefwinsize(120, 120);
X	win = wopen(title == NULL ? progname : title, drawproc);
X	wmenuattach(win, mp);
X	
X	/* Main loop */
X	getallinfo();
X	for (;;) {
X		EVENT e;
X		wgetevent(&e);
X		
X		switch (e.type) {
X		
X		case WE_MOUSE_DOWN:
X			if (excited)
X				domenu(OKALARM);
X			else
X				changehand(e.u.where.h, e.u.where.v);
X			break;
X		
X		case WE_MENU:
X			if (e.u.m.id == 1)
X				domenu(e.u.m.item);
X			break;
X		
X		case WE_CHAR:
X			if (excited)
X				break;
X			switch (e.u.character) {
X			case 's':
X			case 'S':
X				domenu(SETALARM);
X				break;
X			case 'c':
X			case 'C':
X				domenu(CLEARALARM);
X				break;
X			case 'h':
X			case 'H':
X				domenu(SECONDSHAND);
X				break;
X			case 'q':
X			case 'Q':
X				domenu(QUIT);
X				break;
X			}
X			break;
X		
X		case WE_COMMAND:
X			switch (e.u.command) {
X			case WC_RETURN:
X				newtime(FALSE);
X				break;
X			case WC_CLOSE:
X			case WC_CANCEL:
X				domenu(QUIT);
X				break;
X			}
X			break;
X
X		case WE_CLOSE:
X			domenu(QUIT);
X			break;
X		
X		case WE_SIZE:
X			getallinfo();
X			break;
X		
X		case WE_TIMER:
X			newtime(FALSE);
X			break;
X		
X		}
X	}
X}
END_OF_FILE
if test 17064 -ne `wc -c <'Appls/klok/klok.c'`; then
    echo shar: \"'Appls/klok/klok.c'\" unpacked with wrong size!
fi
# end of 'Appls/klok/klok.c'
fi
if test -f 'Conf/proto.os.bsd' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Conf/proto.os.bsd'\"
else
echo shar: Extracting \"'Conf/proto.os.bsd'\" \(143 characters\)
sed "s/^X//" >'Conf/proto.os.bsd' <<'END_OF_FILE'
X
X#
X# Definitions pertaining to BSD (4.3)
X#
X
XOS=		bsd
XRANLIB=		ranlib
X
X# MKDEP is defined in proto.arch.*
X
XLIBTERMCAP=	-ltermcap
XLIBX11=		-lX11
END_OF_FILE
if test 143 -ne `wc -c <'Conf/proto.os.bsd'`; then
    echo shar: \"'Conf/proto.os.bsd'\" unpacked with wrong size!
fi
# end of 'Conf/proto.os.bsd'
fi
if test -f 'Ports/alfa/menu.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/alfa/menu.c'\"
else
echo shar: Extracting \"'Ports/alfa/menu.c'\" \(10366 characters\)
sed "s/^X//" >'Ports/alfa/menu.c' <<'END_OF_FILE'
X/* TERMCAP STDWIN -- MENUS. */
X
X#include "alfa.h"
X
Xstatic bool deflocal= FALSE;	/* Default menu state */
X
Xstatic struct menubar gmenus;	/* All global menus */
Xstatic struct menubar lmenus;	/* All local menus */
X
Xstatic MENU *sysmenu;		/* Window selection commands */
Xstatic MENU *curmenu;
X
Xstatic void
Xaddtobar(mbp, mp)
X	struct menubar *mbp;
X	MENU *mp;
X{
X	int i;
X	
X	for (i= 0; i < mbp->nmenus; ++i) {
X		if (mp == mbp->menulist[i])
X			return; /* Already attached */
X	}
X	L_APPEND(mbp->nmenus, mbp->menulist, MENU *, mp);
X}
X
Xstatic void
Xdelfrombar(mbp, mp)
X	struct menubar *mbp;
X	MENU *mp;
X{
X	int i;
X	
X	for (i= 0; i < mbp->nmenus; ++i) {
X		if (mp == mbp->menulist[i]) {
X			L_REMOVE(mbp->nmenus, mbp->menulist,
X				MENU *, i);
X			break;
X		}
X	}
X}
X
X_winitmenus()
X{
X	sysmenu= wmenucreate(0, "Windows");
X	wmenuadditem(sysmenu, "Previous Window", -1);
X	wmenuadditem(sysmenu, "Next Window", -1);
X#ifndef EM
X	/* Somehow, Euromath doesn't like this?!? */
X	wmenuadditem(sysmenu, "Close Window", -1);
X	wmenuadditem(sysmenu, "(left)", -1);
X	wmenuadditem(sysmenu, "(right)", -1);
X	wmenuadditem(sysmenu, "(up)", -1);
X	wmenuadditem(sysmenu, "(down)", -1);
X	wmenuadditem(sysmenu, "(cancel)", -1);
X	wmenuadditem(sysmenu, "(backspace)", -1);
X	wmenuadditem(sysmenu, "(tab)", -1);
X	wmenuadditem(sysmenu, "(return)", -1);
X#endif
X	/* Shortcuts are compiled in the key map! */
X}
X
XMENU *
Xwmenucreate(id, title)
X	int id;
X	char *title;
X{
X	MENU *mp= ALLOC(MENU);
X	
X	if (mp == NULL)
X		return NULL;
X	mp->id= id;
X	mp->title= strdup(title);
X	mp->local= deflocal;
X	mp->dirty= TRUE;
X	mp->left= mp->right= 0;
X	L_INIT(mp->nitems, mp->itemlist);
X	addtobar(mp->local ? &lmenus : &gmenus, mp);
X	if (!mp->local)
X		menubarchanged();
X	return mp;
X}
X
Xvoid
Xwmenudelete(mp)
X	MENU *mp;
X{
X	int i;
X	
X	if (mp->local) {
X		for (i= 0; i < MAXWINDOWS; ++i) {
X			if (winlist[i].open)
X				delfrombar(&winlist[i].mbar, mp);
X		}
X	}
X	delfrombar(mp->local ? &lmenus : &gmenus, mp);
X	for (i= 0; i < mp->nitems; ++i) {
X		FREE(mp->itemlist[i].text);
X		FREE(mp->itemlist[i].shortcut);
X	}
X	L_DEALLOC(mp->nitems, mp->itemlist);
X	FREE(mp);
X	menubarchanged();
X}
X
Xint
Xwmenuadditem(mp, text, shortcut)
X	MENU *mp;
X	char *text;
X	int shortcut;
X{
X	struct item it;
X	
X	mp->dirty= TRUE;
X	it.text= strdup(text);
X#ifdef EM
X/* need to add the shortcut now, otherwise it will be taken from
X   the keymap whenever the menu is displayed, which might be after
X   opening another window and overwriting the keymap entry.
X   In the AddMenuEntry code I overwrite the shortcut anyway. */
X/* I don't understand this --Guido */
X	if(shortcut >= 32) {
X		it.shortcut=(char *)malloc(8);	
X		sprintf(it.shortcut,"ESC %c", shortcut);
X	} else 
X#endif
X	it.shortcut= NULL;
X	it.enabled= (text != NULL && *text != EOS);
X	it.checked= FALSE;
X	L_APPEND(mp->nitems, mp->itemlist, struct item, it);
X	if (shortcut >= 0)
X		wsetmetakey(mp->id, mp->nitems-1, shortcut);
X	return mp->nitems-1;
X}
X
Xvoid
Xwmenusetitem(mp, item, text)
X	MENU *mp;
X	int item;
X	char *text;
X{
X	if (item < 0 || item >= mp->nitems)
X		return;
X	mp->dirty= TRUE;
X	FREE(mp->itemlist[item].text);
X	mp->itemlist[item].text= strdup(text);
X	mp->itemlist[item].enabled= (text != NULL && *text != EOS);
X}
X
Xvoid
Xwmenuenable(mp, item, flag)
X	MENU *mp;
X	int item;
X	int flag;
X{
X	if (item < 0 || item >= mp->nitems)
X		return;
X	mp->itemlist[item].enabled= flag;
X}
X
Xvoid
Xwmenucheck(mp, item, flag)
X	MENU *mp;
X	int item;
X	int flag;
X{
X	if (item < 0 || item >= mp->nitems)
X		return;
X	mp->itemlist[item].checked= flag;
X}
X
Xvoid
Xwmenuattach(win, mp)
X	WINDOW *win;
X	MENU *mp;
X{
X	if (!mp->local)
X		return;
X	addtobar(&win->mbar, mp);
X	if (win == front)
X		menubarchanged();
X}
X
Xvoid
Xwmenudetach(win, mp)
X	WINDOW *win;
X	MENU *mp;
X{
X	if (!mp->local)
X		return;
X	delfrombar(&win->mbar, mp);
X	if (win == front)
X		menubarchanged();
X}
X
Xvoid
Xwmenusetdeflocal(local)
X	bool local;
X{
X	deflocal= local;
X}
X
X/* Interface routines for the rest of the library. */
X
Xvoid
Xinitmenubar(mb)
X	struct menubar *mb;
X{
X	L_INIT(mb->nmenus, mb->menulist);
X}
X
Xvoid
Xkillmenubar(mb)
X	struct menubar *mb;
X{
X	L_DEALLOC(mb->nmenus, mb->menulist);
X}
X
Xvoid
Xdrawmenubar() /* This is part of the syswin draw procedure! */
X{
X	WINDOW *win= front;
X	char buf[256];
X	int k= 0;
X	int i;
X	
X	buf[0]= EOS;
X	for (i= 0; i < gmenus.nmenus; ++i)
X		k= bufappend(buf, k, gmenus.menulist[i]);
X	if (win != NULL) {
X		for (i= 0; i < win->mbar.nmenus; ++i)
X			k= bufappend(buf, k, win->mbar.menulist[i]);
X	}
X	wdrawtext(0, 0, buf, -1);
X}
X
Xstatic int
Xbufappend(buf, pos, mp)
X	char *buf;
X	int pos;
X	MENU *mp;
X{
X	if (pos > 0) {
X		buf[pos++]= ' ';
X		buf[pos++]= ' ';
X	}
X	mp->left= pos;
X	strcpy(buf+pos, mp->title);
X	pos += strlen(buf+pos);
X	mp->right= pos;
X	return pos;
X}
X
X/* TO DO:
X   - highlight current menu title, current menu item
X   - remember last menu and item
X   - Allow GOTO to select menus or menu items
X     (m-down on mbar opens the menu; m-up on item selects the item)
X*/
X
Xstatic void menudraw(), menuitemdraw(), menucalcwidth();
Xstatic bool handleevt(), handlecmd(), handlemenu();
Xstatic int calcleft();
X
Xstatic leftblank;
X
Xstatic bool		curlocal;
Xstatic struct menubar *	curmbar;
Xstatic int		curimenu;
Xstatic int		curitem;
Xstatic int		lowest;
X
Xstatic bool
Xfirstmenu()
X{
X	curlocal= FALSE;
X	curmbar= &gmenus;
X	curimenu= 0;
X	
X	if (curmbar->nmenus == 0) {
X		curmbar= &lmenus;
X		curlocal= TRUE;
X		if (curmbar->nmenus == 0) {
X			wmessage("No menus defined");
X			return FALSE;
X		}
X	}
X	curmenu= curmbar->menulist[curimenu];
X	curitem= 0;
X	menudraw();
X	return TRUE;
X}
X
Xstatic void
Xnextmenu()
X{
X	WINDOW *win=front; /* added mcv */
X/* the menus are now taken from the window's menubar, instead
X   of the menubar for *all* local menus */
X
X	++curimenu;
X	while (curimenu >= curmbar->nmenus) {
X		curlocal= !curlocal;
X		curmbar= curlocal ? 
X				 &win->mbar /* changed mcv, was: &lmenus*/ : 
X				 &gmenus;
X		curimenu= 0;
X	}
X	curmenu= curmbar->menulist[curimenu];
X	curitem= 0;
X	menudraw();
X}
X
Xstatic void
Xprevmenu()
X{
X	WINDOW *win=front;  /* added mcv */
X/* the menus are now taken from the window's menubar, instead
X   of the menubar for *all* local menus */
X
X	--curimenu;
X	while (curimenu < 0) {
X		curlocal= !curlocal;
X		curmbar= curlocal ? 
X				 &win->mbar /* changed mcv, was: &lmenus*/ : 
X				 &gmenus;
X		curimenu= curmbar->nmenus - 1;
X	}
X	curmenu= curmbar->menulist[curimenu];
X	curitem= 0;
X	menudraw();
X}
X
Xstatic void
Xnextitem()
X{
X	++curitem;
X	if (curitem >= curmenu->nitems)
X		curitem= 0;
X	trmsync(curitem+1, curmenu->left);
X}
X
Xstatic void
Xprevitem()
X{
X	--curitem;
X	if (curitem < 0)
X		curitem= curmenu->nitems - 1;
X	trmsync(curitem+1, curmenu->left);
X}
X
Xstatic void
Xselectitem(ep)
X	EVENT *ep;
X{
X	ep->type= WE_NULL;
X	if (curitem >= curmenu->nitems || !curmenu->itemlist[curitem].enabled)
X		return;
X	ep->type= WE_MENU;
X	ep->u.m.id= curmenu->id;
X	ep->u.m.item= curitem;
X}
X
Xvoid
Xmenuselect(ep)
X	EVENT *ep;
X{
X	leftblank= columns;
X	lowest= 0;
X	wmessage((char *)NULL);
X	if (!firstmenu())
X		return;
X	for (;;) {
X		wsysevent(ep, 1);
X		if (handleevt(ep))
X			break;
X	}
X}
X
Xstatic bool
Xhandleevt(ep)
X	EVENT *ep;
X{
X	switch (ep->type) {
X	
X	case WE_MENU:
X		return handlemenu(ep);
X	
X	case WE_COMMAND:
X		return handlecmd(ep);
X	
X	default:
X		trmbell();
X		return FALSE;
X	
X	}
X}
X
Xstatic bool
Xhandlecmd(ep)
X	EVENT *ep;
X{
X	switch (ep->u.command) {
X	
X	default:
X		trmbell();
X		return FALSE;
X	
X	case WC_RETURN:
X		selectitem(ep);
X		if (curmenu == sysmenu)
X			wsyscommand(ep);
X		return TRUE;
X	
X	case WC_LEFT:
X		prevmenu();
X		break;
X	
X	case WC_RIGHT:
X		nextmenu();
X		break;
X	
X	case WC_UP:
X		previtem();
X		break;
X	
X	case WC_DOWN:
X		nextitem();
X		break;
X	
X	case WC_CANCEL:
X		ep->type= WE_NULL;
X		return TRUE;
X	
X	}
X	return FALSE;
X}
X
Xstatic bool
Xhandlemenu(ep)
X	EVENT *ep;
X{
X	if (ep->u.m.id != 0)
X		return TRUE;
X	switch (ep->u.m.item) {
X	
X	case SUSPEND_PROC:
X		_wsuspend();
X		menudraw();
X		break;
X	
X	case REDRAW_SCREEN:
X		_wredraw();
X		menudraw();
X		break;
X	
X	case MENU_CALL:
X		ep->type= WE_NULL;
X		return TRUE;
X
X	default:
X		if (ep->u.m.item <= LAST_CMD) {
X			wsyscommand(ep);
X			if (ep->type == WE_COMMAND)
X				return handlecmd(ep);
X			else
X				return TRUE;
X		}
X		else {
X			trmbell();
X			return FALSE;
X		}
X	
X	}
X	return FALSE;
X}
X
Xstatic void
Xmenudraw()
X{
X	MENU *mp= curmenu;
X	int left;
X	int width;
X	int i;
X	
X	wupdate(syswin);
X	if (mp->dirty)
X		menucalcwidth(mp);
X	left= calcleft(mp);
X	width= mp->maxwidth;
X	if (left + width > columns)
X		width= columns - left;
X	for (i= 0; i < mp->nitems; ++i)
X		menuitemdraw(i+1, left, &mp->itemlist[i], width);
X	if (i+1 > lowest) {
X		lowest= i+1;
X		if (lowest < lines)
X			uptodate[lowest]= FALSE;
X	}
X	trmputdata(i+1, lowest, 0, "");
X	leftblank= left;
X	trmsync(curitem+1, mp->left);
X}
X
Xstatic int
Xcalcleft(mp)
X	MENU *mp;
X{
X	int left= columns - mp->maxwidth;
X	
X	if (left > mp->left)
X		left= mp->left;
X	if (left < 0)
X		left= 0;
X	if (left-3 < leftblank) {
X		leftblank= left-3;
X		if (leftblank < 4)
X			leftblank= 0;
X	}
X	return left;
X}
X
Xstatic void
Xmenuitemdraw(line, left, ip, width)
X	int line, left;
X	struct item *ip;
X	int width;
X{
X	char buf[256];
X	int margin= left-leftblank;
X	
X	buf[0]= EOS;
X	if (ip->text != NULL && *ip->text != EOS) {
X		int space;
X		char *p= buf;
X		for (space= margin; space-- > 0; )
X			*p++ = ' ';
X		if (ip->checked && margin >= 2)
X			p[-2]= '*';
X		strcpy(p, ip->text);
X		p += strlen(p);
X		if (!ip->enabled && margin >= 1 &&
X			ip->text != NULL && ip->text[0] != EOS) {
X			buf[margin-1]= '(';
X			*p++= ')';
X			*p= '\0';
X		}
X		if (ip->shortcut != NULL && *ip->shortcut != EOS) {
X			space= width - (p - buf - margin)
X				- strlen(ip->shortcut);
X			if (space <= 0)
X				space= 2;
X			while (--space >= 0)
X				*p++ = ' ';
X			strcpy(p, ip->shortcut);
X		}
X	}
X	/* This was added because brackets and stars from disabled/marked
X	   items on the first menu (after the sysmenu) weren't removed
X	   from the screen.  I haven't tried to fix this in a more
X	   efficient manner. */
X	trmputdata(line, line, 0, "");
X	trmputdata(line, line, leftblank, buf);
X	uptodate[line]= FALSE;
X}
X
Xstatic void
Xmenucalcwidth(mp)
X	MENU *mp;
X{
X	int i;
X	int width= 0;
X	
X	for (i= 0; i < mp->nitems; ++i) {
X		struct item *ip= &mp->itemlist[i];
X		char *text= ip->text;
X		if (text != NULL && *text != EOS) {
X			int w= strlen(text);
X			if (ip->shortcut == NULL) {
X				char buf[256];
X				getbindings(buf, mp->id, i);
X				ip->shortcut= strdup(buf);
X			}
X			if (ip->shortcut != NULL && *ip->shortcut != EOS)
X				w += 2 + strlen(ip->shortcut);
X			if (w > width)
X				width= w;
X		}
X	}
X	mp->maxwidth= width;
X	mp->dirty= FALSE;
X}
END_OF_FILE
if test 10366 -ne `wc -c <'Ports/alfa/menu.c'`; then
    echo shar: \"'Ports/alfa/menu.c'\" unpacked with wrong size!
fi
# end of 'Ports/alfa/menu.c'
fi
if test -f 'Ports/msdos/ptrm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/msdos/ptrm.c'\"
else
echo shar: Extracting \"'Ports/msdos/ptrm.c'\" \(23047 characters\)
sed "s/^X//" >'Ports/msdos/ptrm.c' <<'END_OF_FILE'
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
X
X/*
X * ibm Pc virtual TeRMinal package.
X *
X * (Under reconstruction by Guido!)
X *
X * An implementation of the VTRM interface for MS-DOS machines.
X *
X * This code supports two modes of accessing the screen.
X * The first one (BIOS) will be used, unless the user overwrites this
X * by setting the SCREEN environment variable.
X * This variable can also be used to convey a screen size that differs
X * from the default 25 lines and 80 columns. See below.
X *
X * The two modes are:
X *
X * 1) IBM BIOS interrupt 10 hex, video io.
X *    (See IBM PC XT Technical Reference 6936833, May 1983,
X *     Appendix A, pages A46-A47).
X *    This is what you really want to use, since it's the only one that
X *    can decently scroll. It cannot insert or delete characters, so
X *    most optimisations from vtrm.c are useless and taken out.
X *    Unfortunately, not every PC-compatible machine supports this BIOS
X *    interrupt, so for these unlucky souls there is the following escape:
X *
X * 2) The ANSI.SYS driver.
X *    (See IBM MS-DOS 6936839, Jan 1983, Version 2.00, Chapter 13.)
X *    (Some compatibles don't have a separate ANSI.SYS driver but do the
X *    same escape interpretation by default.)
X *    This works reasonably, apart from scrolling downward, or part of
X *    the screen, which is clumsy.
X *    (The ANSI standard provides an escape sequence for scrolling
X *    but ANSI.SYS does not support it, nor any other way of scrolling.)
X *
X * The rest of the interface is the same as described in vtrm.c,
X * with the following exceptions:
X *    - to ease coding for ansi scrolls, the terminal is supposed to
X *	contain blanks at positions that were not written yet;
X *	the unknown rubbish that is initially on the screen can
X *	only be cleared by the caller by scrolling the whole screen up
X *	by one or more lines;
X *    - the number of lines on the terminal is assumed to be 25;
X *	the number of columns is (1) determined by a BIOS function, or
X *	(2) assumed to be 80 for ANSI;
X *	the user can overwrite this by setting the environment variable:
X *
X *		SET SCREEN=BIOS y x
X *	or
X *		SET SCREEN=ANSI y x
X *
X *	where x and y are the number of lines and columns respectively.
X *
X * The lines and columns of our virtual terminal are numbered
X *	y = {0...lines-1} from top to bottom, and
X *	x = {0...cols-1} from left to right,
X * respectively.
X *
X * The Visible Procedures in this package are as described in vtrm.c.
X *
X */
X
X/*
X * Includes and data definitions.
X */
X
X#include <stdio.h>
X#include <signal.h>
X#include <ctype.h>
X#include <dos.h>
X#include <fcntl.h>
X#include <io.h>
X
Xchar *malloc();
X
X#define STDIN_HANDLE 0
X
X#include "vtrm.h"
X
X#ifdef lint
X#define VOID (void)
X#else
X#define VOID
X#endif
X
X#define Forward
X#define Visible
X#define Hidden static
X#define Procedure
X
Xtypedef short intlet;
Xtypedef char *string;
Xtypedef char bool;
X#define Yes '\1'
X#define No  '\0'
X#define Undefined (-1)
X
X#define Min(a,b) ((a) <= (b) ? (a) : (b))
X
X#define MESS(number, text) text
X
X#ifdef GFX
X#include "gfx.h"
X#endif
X
X/* terminal status */
X
XHidden int started = No;
X
XHidden int scr_mode = 0;
X#define ANSI 'A'
X#define BIOS 'B'
X
X#define Nlines	25
X#define Ncols	80
XHidden int lines = Nlines;
XHidden int cols = Ncols;
XHidden int flags = 0;
X
X/* current standout mode */
X#define Off	0
X#define On	0200
XHidden int so_mode = Off;
X
X/* masks for char's and intlet's */
X#define NULCHAR '\000'
X#define CHAR	0177
X#define SOBIT	On
X#define SOCHAR	0377
X
X/* current cursor position */
XHidden intlet cur_y = Undefined, cur_x = Undefined;
X
X/* "line[y][x]" holds the char on the terminal, with the SOBIT.
X * the SOBIT tells whether the character is standing out.
X * "lenline[y]" holds the length of the line.
X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
X * Unknown chars will be ' ', so the scrolling routines for ANSI
X * can use "unwritten" chars (with indent > 0 in trmputdata).
X * To make the optimising compare in putline fail, lenline[y] is initially 0.
X * The latter implies that if a line is first addressed with trmputdata,
X * any rubbish that is on the screen beyond the data that gets put, will
X * remain there.
X */
X
XHidden char **line = 0;
XHidden intlet *lenline = 0;
X
X/* Make the cursor invisible when trmsync() tries to move outside the screen */
XHidden bool no_cursor = No;
X
X/*
X * Starting, Ending and (fatal) Error.
X */
X
Xbool wasbreak;
X
X/*
X * Initialization call.
X * Determine terminal mode.
X * Start up terminal and internal administration.
X * Return Yes if succeeded, No if trouble (which doesn't apply here).
X */
X
XVisible int
Xtrmstart(plines, pcols, pflags)
Xint *plines;
Xint *pcols;
Xint *pflags;
X{
X	static char setup = No;
X	int err;
X
X#ifdef TRACE
Xif (!setup) freopen("TRACE.DAT", "a", stderr);
Xfprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
X#endif
X
X	if (started)
X		return TE_TWICE;
X
X#ifdef GFX
X	if (gfx_mode != TEXT_MODE)
X		gfx_mode= SPLIT_MODE;
X#endif
X
X	if (!setup) {
X		err= set_screen_up();
X		if (err != TE_OK)
X			return err;
X		setup = Yes;
X	}
X
X	err= start_trm();		/* internal administration */
X	if (err != TE_OK)
X		return err;
X
X	*plines = lines;
X	*pcols = cols;
X	*pflags = flags;
X
X	setmode(STDIN_HANDLE, O_BINARY); /* Don't translate CRLF to LF */
X	setraw(STDIN_HANDLE, Yes);
X	wasbreak= getbreak(); /* Save BREAK status; restore when done */
X	setbreak(No);
X
X	set_handler();
X	started = Yes;
X	return TE_OK;
X}
X
XHidden int
Xset_screen_up()
X{
X	int height;
X	int width;
X	int get_screen_env();
X	int get_cols();
X
X	height = width = 0;
X	scr_mode = get_screen_env(&height, &width);
X
X	switch (scr_mode) {
X	case BIOS:
X	case TE_OK:
X		cols = get_cols();
X		flags = HAS_STANDOUT|CAN_SCROLL;
X		break;
X	case ANSI:
X		flags = HAS_STANDOUT;
X		break;
X	default:
X		return scr_mode; /* Error flag */
X	}
X
X	/* allow x and y in environment variable SCREEN to override */
X	if (height > 0)
X		lines = height;
X	if (width > 0)
X		cols = width;
X	return TE_OK;
X}
X
XHidden int
Xget_screen_env(pheight, pwidth)
X	int *pheight, *pwidth;
X{
X	string s;
X	int mode;
X	char screrr;
X	string getenv();
X	string strip();
X	string skip();
X
X	screrr = No;
X	s = getenv("SCREEN");
X	if (s == NULL)
X		return BIOS;
X
X	s = strip(s);
X	switch (*s) {
X	case '\0':
X		return BIOS;
X	case 'a':
X		mode = ANSI;
X		s = skip(s, "ansi");
X		break;
X	case 'A':
X		mode = ANSI;
X		s = skip(s, "ANSI");
X		break;
X	case 'b':
X		mode = BIOS;
X		s = skip(s, "bios");
X		break;
X	case 'B':
X		mode = BIOS;
X		s = skip(s, "BIOS");
X		break;
X	default:
X		mode = BIOS;
X		screrr = Yes;
X	}
X
X	/* *pheight and *pwidth were set to 0 above */
X	s = strip(s);
X	while (isdigit(*s)) {
X		*pheight = *pheight * 10 + (*s++ - '0');
X	}
X	s = strip(s);
X	while (isdigit(*s)) {
X		*pwidth = *pwidth * 10 + (*s++ -'0');
X	}
X	s = strip(s);
X	if (screrr || *s != '\0')
X		return TE_BADTERM;
X
X	return mode;
X}
X
XHidden string strip(s)
Xstring s;
X{
X	while (*s == ' ' || *s == '\t')
X		++s;
X	return s;
X}
X
XHidden string skip(s, pat)
Xstring s, pat;
X{
X	while (*s == *pat)
X		++s, ++pat;
X	return s;
X}
X
XHidden int		/* initialise internal administration */
Xstart_trm()
X{
X	register int y;
X
X	if (line == 0) {
X		if ((line = (char**) malloc(lines * sizeof(char*))) == NULL)
X			return TE_NOMEM;
X		for (y = 0; y < lines; y++) {
X			if ((line[y] = malloc(cols * sizeof(char))) == NULL)
X				return TE_NOMEM;
X		}
X	}
X	if (lenline == 0) {
X		if ((lenline = (intlet *)
X				malloc(lines * sizeof(intlet))) == NULL)
X			return TE_NOMEM;
X	}
X
X	trmundefined();
X	return TE_OK;
X}
X
X/*
X * Termination call.
X * Beware that it might be called by a catched interrupt even in the middle
X * of trmstart()!
X */
X
XVisible Procedure
Xtrmend()
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmend();\n");
X#endif
X	if (started && so_mode != Off)
X		standend();
X	if (scr_mode == ANSI) {
X		VOID fflush(stdout);
X	}
X	/* Always turn off RAW mode -- it is unlikely that anybody
X	   would want to interface to COMMAND.COM in raw mode.
X	   This way, if you were accidentally left in RAW mode
X	   because of a crash, it will go away if you re-enter. */
X	setraw(STDIN_HANDLE, No);
X	setbreak(wasbreak);
X
X	started = No;
X}
X
X/*
X * Set all internal statuses to undefined, especially the contents of
X * the screen, so a hard redraw will not be optimised to heaven.
X */
X
XVisible Procedure
Xtrmundefined()
X{
X	register int y, x;
X#ifdef TRACE
Xfprintf(stderr, "\ttrmundefined();\n");
X#endif
X
X	cur_y = cur_x = Undefined;
X	so_mode = Undefined;
X
X	for (y = 0; y < lines; y++) {
X		for (x = 0; x < cols; x++)
X			line[y][x] = ' ';
X			/* they may get printed in scrolling */
X		lenline[y] = 0;
X	}
X}
X
X#ifdef DEBUG
XHidden Procedure
Xcheck_started(m)
X	char *m;
X{
X	if (!started) {
X		printf("Not started: %s\n", m);
X		exit(TE_TWICE);
X	}
X}
X#else
X#define check_started(m) /*empty*/
X#endif
X
X/*
X * Sensing the cursor.
X * (NOT IMPLEMENTED, since there is no way to locally move the cursor.)
X */
X
X/*
X * Sense the current (y, x) cursor position, after a possible manual
X * change by the user with local cursor motions.
X * If the terminal cannot be asked for the current cursor position,
X * or if the string returned by the terminal is garbled,
X * the position is made Undefined.
X */
XVisible Procedure
Xtrmsense(py, px)
X	int *py;
X	int *px;
X{
X/*	bool getpos(); */
X#ifdef TRACE
Xfprintf(stderr, "\ttrmsense(&yy, &xx);\n");
X#endif
X	check_started(MESS(7904, "trmsense called outside trmstart/trmend"));
X
X	*py = *px = Undefined;
X
X/*
X *	if (flags&CAN_SENSE && getpos(py, px)) {
X *		if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
X *			*py = *px = Undefined;
X *	}
X */
X	cur_y = *py;
X	cur_x = *px;
X}
X
X/*
X * Putting data on the screen.
X */
X
X/*
X * Fill screen area with given data.
X * Characters with the SO-bit (0200) set are put in standout mode.
X * (Unfortunately this makes it impossible to display accented characters.
X * The interface should change.)
X */
XVisible Procedure
Xtrmputdata(yfirst, ylast, indent, data)
Xint yfirst;
Xint ylast;
Xregister int indent;
Xregister string data;
X{
X	register int y;
X	int x, len, lendata, space;
X
X#ifdef TRACE
Xfprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
X#endif
X	check_started(MESS(7905, "trmputdata called outside trmstart/trmend"));
X
X	if (yfirst < 0)
X		yfirst = 0;
X	if (ylast >= lines)
X		ylast = lines-1;
X	space = cols*(ylast-yfirst+1) - indent;
X	if (space <= 0)
X		return;
X	yfirst += indent/cols;
X	indent %= cols;
X	y = yfirst;
X	if (data) {
X		x = indent;
X		lendata = strlen(data);
X		if (ylast == lines-1 && lendata >= space)
X			lendata = space - 1;
X		len = Min(lendata, cols-x);
X		while (len > 0 && y <= ylast) {
X			put_line(y, x, data, len);
X			y++;
X			lendata -= len;
X			if (lendata > 0) {
X				x = 0;
X				data += len;
X				len = Min(lendata, cols);
X			}
X			else
X				break;
X		}
X	}
X	if (y <= ylast)
X		clear_lines(y, ylast);
X}
X
X/*
X * We will try to get the picture:
X *
X *		    op>>>>>>>>>>>op				       oq
X *		    ^		 ^				       ^
X *	     <xskip><-----m1----><---------------od-------------------->
X *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
X *   NEW:	   "in a maze of little twisting pieces of code, all alike"
X *		    <-----m1----><----------------nd--------------------->
X *		    ^		 ^					 ^
X *		    np>>>>>>>>>>>np					 nq
X * where
X *	op, oq, np, nq are pointers to start and end of Old and New data,
X * and
X *	xskip = length of indent to be skipped,
X *	m1 = length of Matching part at start,
X *	od = length of Differing end on screen,
X *	nd = length of Differing end in data to be put.
X */
XHidden int
Xput_line(y, xskip, data, len)
Xint y, xskip;
Xstring data;
Xint len;
X{
X	register char *op, *oq, *np, *nq;
X	int m1, od, nd, delta;
X
X	/* calculate the magic parameters */
X	op = &line[y][xskip];
X	oq = &line[y][lenline[y]-1];
X	np = data;
X	nq = data + len - 1;
X	m1 = 0;
X	while ((*op&SOCHAR) == (*np&SOCHAR) && op <= oq && np <= nq)
X		op++, np++, m1++;
X	od = oq - op + 1;
X	nd = nq - np + 1;
X	/* now we have the picture above */
X
X	if (od==0 && nd==0)
X		return;
X
X	delta = nd - od;
X	move(y, xskip + m1);
X	if (nd > 0) {
X		put_str(np, nd);
X	}
X	if (delta < 0) {
X		clr_to_eol();
X		return;
X	}
X	lenline[y] = xskip + len;
X	if (cur_x == cols) {
X		cur_y++;
X		cur_x = 0;
X	}
X}
X
X/*
X * Scrolling (part of) the screen up (or down, dy<0).
X */
X
XVisible Procedure
Xtrmscrollup(yfirst, ylast, by)
Xregister int yfirst;
Xregister int ylast;
Xregister int by;
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
X#endif
X	check_started(MESS(7906, "trmscrollup called outside trmstart/trmend"));
X
X	if (by == 0)
X		return;
X
X	if (yfirst < 0)
X		yfirst = 0;
X	if (ylast >= lines)
X		ylast = lines-1;
X
X	if (yfirst > ylast)
X		return;
X
X	if (so_mode != Off)
X		standend();
X
X	if (by > 0 && yfirst + by > ylast
X	    ||
X	    by < 0 && yfirst - by > ylast)
X	{
X		clear_lines(yfirst, ylast);
X		return;
X	}
X
X	switch (scr_mode) {
X	case BIOS:
X		biosscrollup(yfirst, ylast, by);
X		break;
X	case ANSI:
X		if (by > 0 && yfirst == 0) {
X			lf_scroll(ylast, by);
X		}
X		else if (by > 0) {
X			move_lines(yfirst+by, yfirst, ylast-yfirst+1-by, 1);
X			clear_lines(ylast-by+1, ylast);
X		}
X		else {
X			move_lines(ylast+by, ylast, ylast-yfirst+1+by, -1);
X			clear_lines(yfirst, yfirst-by-1);
X		}
X		break;
X	}
X}
X
X/*
X * Synchronization, move cursor to given position (or previous if < 0).
X */
X
XVisible Procedure
Xtrmsync(y, x)
X	int y;
X	int x;
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
X#endif
X	check_started(MESS(7907, "trmsync called outside trmstart/trmend"));
X
X	if (0 <= y && y < lines && 0 <= x && x < cols) {
X		move(y, x);
X	}
X	VOID fflush(stdout);
X}
X
X/*
X * Send a bell, visible if possible.
X */
X
XVisible Procedure
Xtrmbell()
X{
X#ifdef TRACE
Xfprintf(stderr, "\ttrmbell();\n");
X#endif
X	check_started(MESS(7908, "trmbell called outside trmstart/trmend"));
X	ring_bell();
X}
X
X/*
X * Now for the real work: here are all low level routines that really
X * differ for BIOS or ANSI mode.
X */
X
X/*
X * BIOS video io is called by generating an 8086 software interrupt,
X * using lattice's int86() function.
X * To ease coding, all routines fill in the apropriate parameters in regs,
X * and then call bios10(code), where code is to be placed in ah.
X */
X
XHidden union REGS regs, outregs;
X
X/* A macro for speed  */
X#define bios10(code) (regs.h.ah = (code), int86(0x10, &regs, &regs))
X#define nbios10(code) (regs.h.ah = (code), int86(0x10, &regs, &outregs))
X
X/* Video attributes: (see the BASIC manual) (used for standout mode) */
X
XHidden int video_attr;
X#ifndef GFX
X#define V_NORMAL 7
X#else
X#define V_NORMAL (gfx_mode == TEXT_MODE ? 7 : 0)
X#endif
X#define V_STANDOUT (7<<4)
X
X/* Some BIOS only routines */
X
XHidden get_cols()
X{
X	bios10(15);
X	return regs.h.ah;
X}
X
X/*
X * ANSI escape sequences
X */
X#define A_CUP	"\033[%d;%dH"   /* cursor position */
X#define A_SGR0	"\033[0m"       /* set graphics rendition to normal */
X#define A_SGR7	"\033[7m"       /* set graphics rendition to standout */
X#define A_ED	"\033[2J"       /* erase display (and cursor home) */
X#define A_EL	"\033[K"        /* erase (to end of) line */
X
X/*
X * The following routine is the time bottleneck, I believe!
X */
X
XHidden Procedure
Xput_str(data, n)
Xchar *data;
Xint n;
X{
X	register char c, so;
X
X	so = so_mode;
X	if (scr_mode == BIOS) {
X		regs.x.cx = 1;	/* repition count */
X		regs.h.bh = 0;	/* page number */
X		regs.h.bl = video_attr;
X		while (--n >= 0) {
X			c = (*data++)&SOCHAR;
X			if ((c&SOBIT) != so) {
X				so = c&SOBIT;
X				so ? standout() : standend();
X				regs.h.bl = video_attr;
X			}
X			regs.h.al = c&CHAR;
X			nbios10(9);
X			if (cur_x >= cols-1) {
X				line[cur_y][cols-1] = c;
X				continue;
X			}
X			regs.h.dh = cur_y;
X			regs.h.dl = cur_x + 1;
X			nbios10(2);
X			line[cur_y][cur_x] = c;
X			cur_x++;
X		}
X	}
X	else {
X		while (--n >= 0) {
X			c = (*data++)&SOCHAR;
X			if ((c&SOBIT) != so) {
X				so = c&SOBIT;
X				so ? standout() : standend();
X			}
X			putch(c&CHAR);
X			line[cur_y][cur_x] = c;
X			cur_x++;
X		}
X	}
X}
X
X/*
X * Move to position y,x on the screen
X */
X
XHidden Procedure
Xmove(y, x)
Xint y, x;
X{
X	if (scr_mode != BIOS && cur_y == y && cur_x == x)
X		return;
X	switch (scr_mode) {
X	case BIOS:
X		regs.h.dh = y;
X		regs.h.dl = x;
X		regs.h.bh = 0; /* Page; must be 0 for graphics */
X		bios10(2);
X		break;
X	case ANSI:
X		cprintf(A_CUP, y+1, x+1);
X		break;
X	}
X	cur_y = y;
X	cur_x = x;
X}
X
XHidden Procedure
Xstandout()
X{
X	so_mode = On;
X	switch (scr_mode) {
X	case BIOS:
X		video_attr = V_STANDOUT;
X		break;
X	case ANSI:
X		cputs(A_SGR7);
X		break;
X	}
X}
X
XHidden Procedure
Xstandend()
X{
X	so_mode = Off;
X	switch (scr_mode) {
X	case BIOS:
X		video_attr = V_NORMAL;
X		break;
X	case ANSI:
X		cputs(A_SGR0);
X		break;
X	}
X}
X
X#ifdef UNUSED
XHidden Procedure
Xput_c(c)
Xint c;
X{
X	int ch;
X
X	ch = c&CHAR;
X#ifndef NDEBUG
X	if (!isprint(ch)) {
X		ch = '?';
X		c = (c&SOBIT)|'?';
X	}
X#endif
X	switch (scr_mode) {
X	case BIOS:
X		regs.h.al = ch;
X		regs.h.bl = video_attr;
X		regs.x.cx = 1;	/* repition count */
X		regs.h.bh = 0;	/* page number */
X		bios10(9);
X		if (cur_x >= cols-1) {
X			line[cur_y][cols-1] = c;
X			return;
X		}
X		regs.h.dh = cur_y;
X		regs.h.dl = cur_x + 1;
X		bios10(2);
X		break;
X	case ANSI:
X		putch(ch);
X		break;
X	}
X	line[cur_y][cur_x] = c;
X	cur_x++;
X}
X#endif /* UNUSED */
X
XHidden Procedure
Xclear_lines(yfirst, ylast)
Xint yfirst, ylast ;
X{
X	register int y;
X
X	if (scr_mode == BIOS) {
X		regs.h.al = 0;	/* scroll with al = 0 means blank window */
X		regs.h.ch = yfirst;
X		regs.h.cl = 0;
X		regs.h.dh = ylast;
X		regs.h.dl = cols-1;
X		regs.h.bh = V_NORMAL;
X		bios10(6);
X		for (y = yfirst; y <= ylast; y++)
X			lenline[y] = 0;
X		return;
X	}
X	/* scr_mode == ANSI */
X	if (yfirst == 0 && ylast == lines-1) {
X		if (so_mode == On)
X			standend();
X		move(0, 0);		/* since some ANSI'd don't move */
X		cputs(A_ED);
X		cur_y = cur_x = 0;
X		for (y = yfirst; y < ylast; y++)
X			lenline[y] = 0;
X		return;
X	}
X	for (y = yfirst; y <= ylast; y++) {
X		if (lenline[y] > 0) {
X			move(y, 0);
X			clr_to_eol();
X		}
X	}
X}
X
XHidden Procedure
Xclr_to_eol()
X{
X	if (so_mode == On)
X		standend();
X	switch (scr_mode) {
X	case BIOS:
X		regs.h.bh = 0;	/* page */
X		regs.x.cx = lenline[cur_y] - cur_x;
X		regs.h.al = ' ';
X		regs.h.bl = V_NORMAL;
X		bios10(9);
X		break;
X	case ANSI:
X		cputs(A_EL);
X		break;
X	}
X	lenline[cur_y] = cur_x;
X}
X
XHidden Procedure		/* scrolling for BIOS */
Xbiosscrollup(yfirst, ylast, by)
Xint yfirst;
Xint ylast;
Xint by;
X{
X	regs.h.al = (by < 0 ? -by : by);
X	regs.h.ch = yfirst;
X	regs.h.cl = 0;
X	regs.h.dh = ylast;
X	regs.h.dl = cols-1;
X	regs.h.bh= V_NORMAL;
X	bios10(by < 0 ? 7 : 6);
X	cur_y = cur_x = Undefined;
X	if (by > 0)
X		scr_lines(yfirst, ylast, by, 1);
X	else
X		scr_lines(ylast, yfirst, -by, -1);
X}
X
XHidden Procedure		/* Reset internal administration accordingly */
Xscr_lines(yfrom, yto, n, dy)
Xint yfrom, yto, n, dy;
X{
X	register int y, x;
X	char *saveln;
X
X	while (n-- > 0) {
X		saveln = line[yfrom];
X		for (y = yfrom; y != yto; y += dy) {
X			line[y] = line[y+dy];
X			lenline[y] = lenline[y+dy];
X		}
X		line[yto] = saveln;
X		for (x = 0; x < cols; x++ )
X			line[yto][x] = ' ';
X		lenline[yto] = 0;
X	}
X}
X
XHidden Procedure
Xlf_scroll(yto, by)
Xint yto;
Xint by;
X{
X	register int n = by;
X
X	move(lines-1, 0);
X	while (n-- > 0) {
X		putch('\n');
X	}
X	scr_lines(0, lines-1, by, 1);
X	move_lines(lines-1-by, lines-1, lines-1-yto, -1);
X	clear_lines(yto-by+1, yto);
X}
X
XHidden Procedure		/* for dumb scrolling, uses and updates */
Xmove_lines(yfrom, yto, n, dy)	/* internal administration */
Xint yfrom;
Xint yto;
Xint n;
Xint dy;
X{
X	while (n-- > 0) {
X		put_line(yto, 0, line[yfrom], lenline[yfrom]);
X		yfrom += dy;
X		yto += dy;
X	}
X}
X
XHidden Procedure ring_bell()
X{
X	switch (scr_mode) {
X	case BIOS:
X		regs.h.al = '\007';
X		regs.h.bl = V_NORMAL;
X		bios10(14);
X		break;
X	case ANSI:
X		putch('\007');
X		break;
X	}
X}
X
X/*
X * Show the current internal statuses of the screen on stderr.
X * For debugging only.
X */
X
X#ifdef SHOW
XVisible Procedure
Xtrmshow(s)
Xchar *s;
X{
X	int y, x;
X
X	fprintf(stderr, "<<< %s >>>\n", s);
X	for (y = 0; y < lines; y++) {
X		for (x = 0; x <= lenline[y] /*** && x < cols ***/ ; x++) {
X			fputc(line[y][x]&CHAR, stderr);
X		}
X		fputc('\n', stderr);
X		for (x = 0; x <= lenline[y] && x < cols-1; x++) {
X			if (line[y][x]&SOBIT)
X				fputc('-', stderr);
X			else
X				fputc(' ', stderr);
X		}
X		fputc('\n', stderr);
X	}
X	fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
X	VOID fflush(stderr);
X}
X#endif
X
X/*
X * Interrupt handling.
X *
X * (This has not properly been tested, nor is it clear that
X * this interface is what we want.  Anyway, it's here for you
X * to experiment with.  What does it do, you may ask?
X * Assume an interactive program which reads its characters
X * through trminput.  Assume ^C is the interrupt character.
X * Normally, ^C is treated just like any other character: when
X * typed, it turns up in the input.  The program may understand
X * input ^C as "quit from the current mode".
X * Occasionally, the program goes into a long period of computation.
X * Now it would be uninterruptible, except if it calls trminterrupt
X * at times in its computational loop.  Trminterrupt magically looks
X * ahead in the input queue, and if it sees a ^C, discards all input
X * before that point and returns Yes.  It also sets a flag, so that
X * the interupt "sticks around" until either trminput or trmavail
X * is called.  It is undefined whether typing ^C several times in
X * a row is seen as one interrupt, or an interrupt followed by input
X * of ^C's.  A program should be prepared for either.)
X */
X
Xstatic bool intrflag= No;
X
Xstatic
Xhandler(sig)
X	int sig;
X{
X	signal(sig, handler);
X	intrflag= Yes;
X}
X
Xstatic
Xset_handler()
X{
X	signal(SIGINT, handler);
X}
X
Xbool
Xtrminterrupt()
X{
X	/* Force a check for ^C which will call handler. */
X	/* (This does a ^C check even if stdin is in RAW mode. */
X	(void) kbhit();
X	return intrflag;
X}
X
X
X/* Definitions for DOS function calls. */
X
X#define IOCTL		0x44
X#define IOCTL_GETDATA	0x4400
X#define IOCTL_SETDATA	0x4401
X#define DEVICEBIT	0x80
X#define RAWBIT		0x20
X
X#define BREAKCK		0x33
X#define GET		0x00
X#define SET		0x01
X
X#define IOCTL_GETSTS	0x4406
X
X#define STDIN_HANDLE	0
X
X/*
X * Terminal input without echo.
X */
X
Xint
Xtrminput()
X{
X	char c;
X	
X	intrflag= No;
X	/* Assume stdin is in RAW mode; this turns echo and ^C checks off. */
X	if (read(STDIN_HANDLE, &c, 1) < 1)
X		return -1;
X	else
X		return c;
X}
X
X/*
X * Check for character available.
X *
X */
X
Xtrmavail()
X{
X	intrflag= No;
X	regs.x.ax= IOCTL_GETSTS;
X	regs.x.bx= STDIN_HANDLE;
X	intdos(&regs, &regs);
X	if (regs.x.cflag)
X		return -1; /* Error */
X	return regs.h.al != 0;
X}
X
Xtrmsuspend()
X{
X	/* Not implementable on MS-DOS */
X}
X
X/* Issue an IOCTL to turn RAW for a device on or off. */
X
Xsetraw(handle, raw)
X	int handle;
X	bool raw;
X{
X	regs.x.ax= IOCTL_GETDATA;
X	regs.x.bx= handle;
X	intdos(&regs, &regs);
X	if (regs.x.cflag || !(regs.h.dl & DEVICEBIT))
X		return; /* Error or not a device -- ignore it */
X	regs.h.dh= 0;
X	if (raw)
X		regs.h.dl |= RAWBIT;
X	else
X		regs.h.dl &= ~RAWBIT;
X	regs.x.ax= IOCTL_SETDATA;
X	intdos(&regs, &regs);
X	/* Ignore errors */
X}
X
X/* Get the raw bit of a device. */
X
Xint
Xgetraw(handle)
X	int handle;
X{
X	regs.x.ax= IOCTL_GETDATA;
X	regs.x.bx= handle;
X	intdos(&regs, &regs);
X	return !regs.x.cflag &&
X		(regs.h.dh & (DEVICEBIT|RAWBIT)) == (DEVICEBIT|RAWBIT);
X}
X
X/* Set the break status. */
X
Xsetbreak(on)
X	bool on;
X{
X	bdos(BREAKCK, on, SET);
X}
X
X/* Get the break status. */
X
Xint
Xgetbreak()
X{
X	regs.x.ax= (BREAKCK << 8) | GET;
X	intdos(&regs, &regs);
X	return regs.h.dl;
X}
END_OF_FILE
if test 23047 -ne `wc -c <'Ports/msdos/ptrm.c'`; then
    echo shar: \"'Ports/msdos/ptrm.c'\" unpacked with wrong size!
fi
# end of 'Ports/msdos/ptrm.c'
fi
echo shar: End of archive 5 \(of 19\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 19 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0