STDWIN 0.9.5, Part 05/19
Guido van Rossum
guido at cwi.nl
Mon Mar 4 21:57:45 AEST 1991
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 at 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, ®s, ®s))
X#define nbios10(code) (regs.h.ah = (code), int86(0x10, ®s, &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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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(®s, ®s);
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
More information about the Alt.sources
mailing list