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, ®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