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

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

Archive-name: stdwin/part09

#! /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 9 (of 19)."
# Contents:  Packs/vt/vtansi.c Ports/alfa/stdwin.c Ports/mac/draw.c
#   Ports/x11/menu.c Ports/x11/timer.c
# Wrapped by guido@voorn.cwi.nl on Mon Mar  4 12:37:27 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Packs/vt/vtansi.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Packs/vt/vtansi.c'\"
else
echo shar: Extracting \"'Packs/vt/vtansi.c'\" \(11653 characters\)
sed "s/^X//" >'Packs/vt/vtansi.c' <<'END_OF_FILE'
X/* ANSI escape sequence interpreter */
X
X/* There is some ugly code here, since I assume that code looking
X   at the input a character at a time is very time-critical.
X   Action functions are called with the start of the text to process,
X   and return a pointer to where they left off.
X   When an action function hits the end of the string,
X   it returns NULL and sets the action pointer to the function to
X   call next (often itself), or to NULL for the default.
X   A non-NULL return implies that the default action function must
X   be called next and the action pointer is irrelevant.
X   Remember that the general form of most ANSI escape sequences is
X	ESC [ <n1> ; <n2> ; ... <c>
X   where <c> is the command code and <n1>, <n2> etc. are optional
X   numerical parameters.
X*/
X
X#include "vtimpl.h"
X
X#ifdef DEBUG
X /* Let it be heard that a command was not recognized */
X#define FAIL() wfleep()
X#else
X/* Silently ignore unrecognized commands */
X#define FAIL() 0
X#endif
X
X/* Function prototypes */
X
XSTATIC char *def_action _ARGS((VT *vt, char *text, char *end));
XSTATIC char *esc_action _ARGS((VT *vt, char *text, char *end));
XSTATIC char *ansi_params _ARGS((VT *vt, char *text, char *end));
XSTATIC char *ansi_execute _ARGS((VT *vt, char *text));
XSTATIC void vtsetoptions _ARGS((VT *vt, bool flag));
XSTATIC void vtsetattrlist _ARGS((VT *vt));
X
X/* Output a string, interpreting ANSI escapes */
X
Xvoid
Xvtansiputs(vt, text, len)
X	VT *vt;
X	char *text;
X	int len;
X{
X	char *end;
X
X#ifndef NDEBUG
X	if (vt->scr_top < 0 || vt->scr_top > vt->rows) {
X		fprintf(stderr, "vtansiputs: scr_top = %d\n", vt->scr_top);
X		vtpanic("vtansiputs: bad scr_top");
X	}
X#endif
X
X	if (len < 0)
X		len = strlen(text);
X	end = text + len;
X
X	D( printf("vtansiputs %d chars\n", len) );
X	
X	/* Pick up where the last call left us behind  */
X	if (vt->action != NULL)
X		text = (*vt->action)(vt, text, end);
X
X	/* Start in default state until text exhausted */
X	while (text != NULL)
X		text = def_action(vt, text, end);
X
X	/* Execute delayed scrolling */
X	vtsync(vt);
X	D( printf("vtansiputs returns\n") );
X}
X
X/* Default action function */
X
XSTATIC char *
Xdef_action(vt, text, end)
X	VT *vt;
X	char *text, *end;
X{
Xagain:
X	for (;;) {
X		if (text >= end) {
X			vt->action = NULL;
X			return NULL;
X		}
X		if (PRINTABLE(*text))
X			break;
X		switch (*text++) {
X
X		case ESC:	/* ESC */
X			return esc_action(vt, text, end);
X		
X		case BEL:	/* Bell */
X			if (vt->visualbell) {
X				VTBEGINDRAWING(vt);
X				vtinvert(vt, 0, 0, vt->rows, vt->cols);
X				VTENDDRAWING(vt);
X				VTBEGINDRAWING(vt);
X				vtinvert(vt, 0, 0, vt->rows, vt->cols);
X				VTENDDRAWING(vt);
X			}
X			else {
X				wfleep();
X			}
X			break;
X		
X		case BS:	/* Backspace -- move 1 left */
X			/* Rely on vtsetcursor's clipping */
X			vtsetcursor(vt, vt->cur_row, vt->cur_col - 1);
X			/* Don't erase --
X			   that's part of intelligent echoing */
X			break;
X		
X		case TAB:	/* Tab -- move to next tab stop */
X			/* Rely on vtsetcursor's clipping */
X			/* TO DO: use programmable tab stops! */
X			vtsetcursor(vt, vt->cur_row,
X				(vt->cur_col & ~7) + 8);
X			/* Normalize cursor (may cause scroll!) */
X			vtputstring(vt, "", 0);
X			break;
X		
X		case LF:	/* Linefeed -- move down one line */
X			if (vt->nlcr)	/* First a \r? */
X				vtsetcursor(vt, vt->cur_row, 0);
X			vtlinefeed(vt, 1);
X			break;
X		
X		case FF:	/* Formfeed */
X			/* vtreset(vt); */
X			break;
X		
X		case CR:	/* Return -- to col 0 on same line */
X			vtsetcursor(vt, vt->cur_row, 0);
X			break;
X		
X		case ' ':	/* In case isprint(c) fails for space */
X			vtputstring(vt, " ", 1);
X			break;
X
X		default:
X			D( printf("Unrecognized unprintable character 0x%x\n",
X								text[-1]) );
X			FAIL();
X			break;
X		}
X	}
X
X	/* We fall through the previous loop when we get a printable
X	   character */
X	
X	{
X		char *p = text;
X		
X		while (PRINTABLE(*++p)) {
X			/* At least one character guaranteed! */
X			if (p >= end)
X				break;
X		}
X		vtputstring(vt, text, (int)(p-text));
X		text = p;
X		goto again;
X	}
X}
X
X/* Action function called after ESC seen */
X
XSTATIC char *
Xesc_action(vt, text, end)
X	VT *vt;
X	char *text, *end;
X{
X	if (text >= end) {
X		vt->action = esc_action;
X		return NULL;
X	}
X	switch (*text++) {
X/*
X	case '(':
X	case ')':
X	case '*':
X	case '+':
X		return cset_action(vt, text, end);
X*/
X	case '=':
X		vt->keypadmode = TRUE;
X		break;
X	case '>':
X		vt->keypadmode = FALSE;
X		break;
X	case '7':
X		vtsavecursor(vt);
X		break;
X	case '8':
X		vtrestorecursor(vt);
X		break;
X	case 'D':
X		vtlinefeed(vt, 1);
X		break;
X	case 'E':
X		/* Next Line */
X		break;
X	case 'H':
X		/* Tab set */
X		break;
X	case 'M':
X		vtrevlinefeed(vt, 1);
X		break;
X	case '[':
X		vt->nextarg = vt->args;
X		*vt->nextarg = -1;
X		vt->modarg = '\0';
X		return ansi_params(vt, text, end);
X	case 'c':
X		vtreset(vt);
X		break;
X	default:
X		D( printf("Urecognized: esc-%c (0x%x)\n",
X			    text[-1], text[-1]) );
X		FAIL();
X		break;
X	}
X	return text;
X}
X
X/* Action function called after ESC-[ plus possible parameters seen */
X
XSTATIC char *
Xansi_params(vt, text, end)
X	VT *vt;
X	char *text, *end;
X{
Xagain:
X	if (text >= end) {
X		vt->action = ansi_params;
X		return NULL;
X	}
X	if (isdigit(*text)) {
X		long a = *vt->nextarg;
X		if (a < 0) /* Still unused? */
X			a = 0;
X		do {
X			a = a*10 + (*text - '0');
X			CLIPMAX(a, 0x7fff); /* Avoid overflow */
X		} while (++text < end && isdigit(*text));
X		*vt->nextarg = a; /* Remember arg under construction */
X		if (text >= end)
X			goto again;
X	}
X	switch (*text) {
X
X	case ';': /* Arg no longer under construction */
X		++text;
X		if (vt->nextarg < &vt->args[VTNARGS-1])
X			++vt->nextarg; /* Else: overflow; who cares? */
X		*vt->nextarg = -1; /* Mark unused */
X		goto again;
X
X	case '?':
X		++text;
X		if (vt->nextarg == vt->args && /* No arguments yet */
X			*vt->nextarg < 0 && vt->modarg == '\0') {
X			vt->modarg = '?';
X			goto again;
X		}
X		else { /* Illegal here */
X			D( printf("Wrong argcount in DEC private mode\n") );
X			FAIL();
X			return text;
X		}
X
X	default:
X		return ansi_execute(vt, text);
X	}
X}
X
X/* Called after complete ESC [ ? <number> h is parsed.
X   This is called DEC private mode set. Most stuff is not
X   implemented. The vt is guarantueed to contain the one
X   and only argument allowed here. */
X
XSTATIC void
Xvtprivset(vt)
X	VT *vt;
X{
X	switch (vt->args[0]) {
X	case 1:	/* Application cursor keys */
X		if (!vt->keypadmode) {
X			vt->keypadmode = 1;
X			vt->flagschanged = 1;
X		}
X		break;
X#if 0
X	case 3: /* 132 column mode */
X	case 4: /* Smooth (slow) scroll */
X#endif
X	case 5: /* Reverse video */
X		wfleep();
X		break;
X#if 0
X	case 6: /* Origin mode */
X	case 7: /* Wraparound mode */
X	case 8: /* Autorepeat keys */
X#endif
X	case 9: /* Send MIT mouse row & column on Button Press */
X		if (!vt->mitmouse) { /* If not already so */
X			vt->mitmouse = 1;
X			vt->flagschanged = 1;
X		}
X		break;
X#if 0
X	case 38: /* Enter Tektronix Mode */
X	case 40: /* Allow 80 <-> 132 mode */
X	case 41: /* Curses(5) fix */
X	case 44: /* Turn on margin bell */
X	case 45: /* Reverse wraparound mode */
X	case 46: /* Start logging */
X	case 47: /* Use alternate screen buffer */
X	case 1000: /* Send vt200 mouse row & column on Button Press */
X	case 1003: /* Send vt200 Hilite mouse row & column on Button Press */
X#endif
X	default:
X		D( printf("Unsupported DEC private mode set:") );
X		D( printf("esc [ ? %d h\n", vt->args[0]) );
X		wfleep();
X	}
X}
X
X/* Called after complete ESC [ ? <number> l is parsed.
X   This is called DEC private mode reset. The vt is guarantueed
X   to contain the one and only argument allowed here. */
X
XSTATIC void
Xvtprivreset(vt)
X	VT *vt;
X{
X	switch (vt->args[0]) {
X	case 1: /* Normal cursor keys */
X		if (vt->keypadmode) {
X			vt->keypadmode = 0;
X			vt->flagschanged = 1;
X		}
X		break;
X#if 0	/* These are not supprted: */
X	case 3: /* 80 column mode */
X	case 4: /* Jumpscroll */
X#endif
X	case 5: /* Normal video (i.e. not reverse) */
X		/* XXX Why this beep? */
X		wfleep();
X		break;
X#if 0
X	case 6: /* Normal cursor mode */
X	case 7: /* No wraparound */
X	case 8: /* No autorepeat */
X		break;
X#endif
X	case 9: /* Don't send mouse row & column on button press */
X	case 1000:	/* Same */
X	case 1003:	/* Same */
X		if (vt->mitmouse) { /* If not already so */
X			vt->mitmouse = 0;
X			vt->flagschanged = 1;
X		}
X		break;
X#if 0
X	case 40: /* Disallow 80 <-> 132 mode */
X	case 41: /* No curses(5) fix */
X	case 44: /* Turn off Margin bell */
X	case 45: /* No reverse wraparound */
X	case 46: /* Stop logging */
X	case 47: /* Use normal screen buffer (opposed to alternate buffer) */
X		break;
X#endif
X	default:
X		D( printf("Unsupported DEC private mode reset:") );
X		D( printf("esc [ ? %d l\n", vt->args[0]) );
X		wfleep();
X		break;
X	}
X}
X
X/* Action function called at last char of ANSI sequence.
X   (This is only called when the char is actually seen,
X   so there is no need for an 'end' parameter). */
X
XSTATIC char *
Xansi_execute(vt, text)
X	VT *vt;
X	char *text;
X{
X	int a1 = vt->args[0];
X	int a2 = (vt->nextarg > vt->args) ? vt->args[1] : -1;
X
X	if (vt->modarg == '?') {
X		/* These escape sequences have exactly one numeric parameter */
X		if (a1 < 0 || a2 > 0) {
X			wfleep();
X			return text+1;
X		}
X		switch (*text++) {
X		case 'h':	/* DEC Private mode Set */
X			vtprivset(vt);
X			break;
X		case 'l':	/* DEC Private mode Reset */
X			vtprivreset(vt);
X			break;
X		/* To do: add private mode memory to vt-descriptor? */
X		case 'r':	/* DEC Private mode Restore */
X		case 's':	/* DEC Private mode Save */
X		default:
X			/* Not supported or simply wrong */
X			wfleep();
X		}
X		return text;
X	}
X
X	CLIPMIN(a1, 1);
X	CLIPMIN(a2, 1);
X
X	switch (*text++) {
X	case '@': vtinschars(vt, a1);		break;
X	case 'A': vtarrow(vt, WC_UP, a1);	break;
X	case 'B': vtarrow(vt, WC_DOWN, a1);	break;
X	case 'C': vtarrow(vt, WC_RIGHT, a1);	break;
X	case 'D': vtarrow(vt, WC_LEFT, a1);	break;
X	case 'H':
X	case 'f': if (vt->nextarg > &vt->args[0])
X		    vtsetcursor(vt, vt->topterm + a1 - 1, a2 - 1);
X		  else vtsetcursor(vt, vt->topterm, 0);
X		  break;
X	case 'J':
X		switch (vt->args[0]) {
X		case -1:
X		case 0:
X			vteosclear(vt, vt->topterm, 0);
X			break;
X		case 1:
X			/* clear above cursor */
X			break;
X		case 2:
X			vteosclear(vt, vt->cur_row, vt->cur_col);
X			break;
X		default:
X			FAIL();
X			break;
X		}
X		break;
X	case 'K':
X		switch (vt->args[0]) {
X		case -1:
X		case 0:
X			vteolclear(vt, vt->cur_row, vt->cur_col);
X			break;
X		case 1:
X			/* Clear left of cursor */
X			break;
X		case 2:
X			vteolclear(vt, vt->cur_row, 0);
X			break;
X		default:
X			FAIL();
X			break;
X		}
X		break;
X	case 'L': vtinslines(vt, a1);		break;
X	case 'M': vtdellines(vt, a1);		break;
X	case 'P': vtdelchars(vt, a1);		break;
X	case 'S': vtlinefeed(vt, a1);		break;
X	case 'T': vtrevlinefeed(vt, a1);	break;
X	case 'c': vtsendid(vt); break;
X	case 'g': /* Tab clear */		break;
X		/* 0: current col; 3: all */
X	case 'h': vtsetoptions(vt, TRUE);	break;
X	case 'l': vtsetoptions(vt, FALSE);	break;
X	case 'm': vtsetattrlist(vt);		break;
X	case 'n':
X		if (a1 == 6) vtsendpos(vt);
X		/* 5: echo 'ESC [ 0 n' */
X		break;
X	case 'r':
X		vtsetscroll(vt, vt->topterm+vt->args[0]-1, vt->topterm+a2);
X		break;
X	case 'x': /* Send terminal params */
X		break;
X	default:
X		FAIL();
X		break;
X	}
X
X	return text;
X}
X
X/* Set/reset numbered options given in args array */
X
XSTATIC void
Xvtsetoptions(vt, flag)
X	VT *vt;
X	bool flag; /* Set/reset */
X{
X	short *a;
X	for (a = vt->args; a <= vt->nextarg; ++a) {
X		switch (*a) {
X		case 4:
X			vtsetinsert(vt, flag);
X			break;
X		case -1:
X			/* Empty parameter, don't beep */
X			break;
X		default:
X			FAIL();
X			break;
X		}
X	}
X}
X
X/* Set/reset output mode attributes given in args array */
X
XSTATIC void
Xvtsetattrlist(vt)
X	VT *vt;
X{
X	short *a;
X	for (a = vt->args; a <= vt->nextarg; ++a) {
X		switch (*a) {
X		case -1:
X			if (a == vt->args)
X				vtresetattr(vt);
X			break;
X		case 0:
X			vtresetattr(vt);
X			break;
X		default:
X			vtsetattr(vt, *a);
X			break;
X		}
X	}
X}
END_OF_FILE
if test 11653 -ne `wc -c <'Packs/vt/vtansi.c'`; then
    echo shar: \"'Packs/vt/vtansi.c'\" unpacked with wrong size!
fi
# end of 'Packs/vt/vtansi.c'
fi
if test -f 'Ports/alfa/stdwin.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/alfa/stdwin.c'\"
else
echo shar: Extracting \"'Ports/alfa/stdwin.c'\" \(9984 characters\)
sed "s/^X//" >'Ports/alfa/stdwin.c' <<'END_OF_FILE'
X/* TERMCAP STDWIN -- BASIC ROUTINES. */
X
X#include "alfa.h"
X
X#if defined(unix) || defined(AMOEBA)
X#define DO_SIGNAL
X#define DO_SYSTEM
X#endif
X
X#ifdef DO_SIGNAL
X#include <sys/types.h>
X#include <signal.h>
X#include "sigtype.h"
Xstatic SIGTYPE handler(); /* Forward */
X#endif
X
Xint lines, columns;
X
X/* Initialization call.
X   Should be called only once, before any others.
X   Will exit when the initialization fails. */
X
Xvoid
Xwinit()
X{
X	winitargs((int*)NULL, (char***)NULL);
X}
X
X/*ARGSUSED*/
Xvoid
Xwinitargs(pargc, pargv)
X	int *pargc;
X	char ***pargv;
X{
X	int flags;
X	int err;
X	
X#ifdef DO_SIGNAL
X	(void) signal(SIGINT, handler);
X#ifdef NDEBUG
X	(void) signal(SIGQUIT, handler);
X#endif
X	(void) signal(SIGILL, handler);
X	(void) signal(SIGIOT, handler);
X	(void) signal(SIGEMT, handler);
X	(void) signal(SIGFPE, handler);
X	(void) signal(SIGBUS, handler);
X	(void) signal(SIGSEGV, handler);
X	(void) signal(SIGSYS, handler);
X	(void) signal(SIGTERM, handler);
X#endif /* DO_SIGNAL */
X	
X	getttykeydefs(0);	/* File descriptor 0 */
X	err= trmstart(&lines, &columns, &flags);
X	if (err != 0) {
X		fprintf(stderr, "STDWIN: trmstart error %d\n", err);
X		exit(2);
X	}
X	gettckeydefs();
X	if (lines > MAXLINES)
X		lines= MAXLINES;
X	trmputdata(0, lines-1, 0, "");
X	initsyswin();
X	_winitmenus();
X}
X
X/* Termination call.
X   Should be called before the program exits
X   (else the terminal will be left in almost raw mode). */
X
Xvoid
Xwdone()
X{
X	if (lines > 0) {
X		/* Move cursor to last screen line. */
X		trmputdata(lines-1, lines-1, 0, "");
X		trmsync(lines-1, 0);
X	}
X	lines= 0;
X	trmend();
X}
X
X#ifdef DO_SIGNAL
X
X/* Signal handler.
X   Print a message and exit. */
X
Xstatic SIGTYPE
Xhandler(sig)
X	int sig;
X{
X	wdone();
X	signal(sig, SIG_DFL);
X	kill(0, sig);		/* Kill all others in our process group */
X	kill(getpid(), sig);	/* Commit suicide */
X	/* (On BSD, the signal is delivered to us only after we return.) */
X}
X
X#endif /* DO_SIGNAL */
X
X/* Essential data structures. */
X
XWINDOW winlist[MAXWINDOWS] /* = {FALSE, ...}, ... */;
X
XWINDOW *wasfront;	/* What the application thinks is active */
XWINDOW *front;		/* The window that is really active */
X	/* If these are not equal, an activate or deactivate event
X	   will be generated by wevent before anything else. */
X
Xchar uptodate[MAXLINES] /* = FALSE, ... */;
X
X/* Open a window. */
X
XWINDOW *
Xwopen(title, drawproc)
X	char *title;
X	void (*drawproc)();
X{
X	int id;
X	WINDOW *win;
X	
X	for (win= &winlist[0]; win < &winlist[MAXWINDOWS]; ++win) {
X		if (!win->open)
X			break;
X	}
X	id= win - &winlist[0];
X	if (id >= MAXWINDOWS)
X		return NULL;	/* Too many windows open */
X	win->open= TRUE;
X	_wreshuffle();
X	win->resized = FALSE;	/* Don't begin with a redraw event */
X	win->tag= 0;
X	win->drawproc= drawproc;
X	win->title= strdup(title);
X	win->attr= wattr;
X	
X	win->offset= -win->top;
X	win->curh= win->curv= -1;
X	win->timer= 0;
X	
X	initmenubar(&win->mbar);
X	
X	front= win;
X	return win;
X}
X
X/* Divide the available lines over the available windows.
X   Line 0 is for window 0, the system window, and is different:
X   it has no title, and is always one line high, except when it's
X   the only window. */
X
Xvoid
X_wreshuffle()
X{
X	int nwins= 0;
X	int nlines= lines;
X	int top= 0;
X	WINDOW *win;
X	
X	/* Count open windows. */
X	for (win= winlist; win < &winlist[MAXWINDOWS]; ++win) {
X		if (win->open)
X			++nwins;
X	}
X	/* Assign each open window its share of the screen. */
X	for (win= winlist; win < &winlist[MAXWINDOWS]; ++win) {
X		if (win->open) {
X			int i= nlines/nwins;	/* This window's share */
X			int id= win - winlist;
X#ifdef LM_S_PROB
X			int oldtop= win->top, oldbot= win->bottom;
X			int dv, scrbot;
X#endif
X			/* Cause redraw event for old title position: */
X			if (win->top > 0)
X				uptodate[win->top-1]= FALSE;
X			if (id == 0) {	/* System window */
X				win->top= top;
X				if (nwins > 1)
X					i=1;
X			}
X			else
X				win->top= top+1;
X			win->bottom= top + i;
X			nlines -= i;
X			--nwins;
X#ifndef LM_S_PROB
X			/* This is overkill;
X			   we should try not cause a redraw of all lines! */
X			for (i= top; i < win->bottom; ++i) {
X				uptodate[i]= FALSE;
X			}
X#else
X			/* LM's probeersel */
X			dv= oldtop-win->top;
X			scrbot=win->bottom;
X			if (oldbot-dv < scrbot) scrbot=oldbot-dv;
X			scrollupdate(win->top, scrbot, dv);
X			trmscrollup(win->top, scrbot-1, dv);
X			for (i= top; i < win->bottom; ++i)
X				if (!(win->top <= i && i < scrbot ||
X				      win->top <= i+dv && i+dv < scrbot))
X				uptodate[i]= FALSE;
X#endif
X			top= win->bottom;
X			/* Cause redraw event for new title position: */
X			if (win->top > 0)
X				uptodate[win->top-1]= FALSE;
X			/* Cause resize event: */
X			win->resized= TRUE;
X			/* Scroll back if negative line numbers visible: */
X			if (win->top + win->offset < 0)
X				wshow(win, 0, 0,
X					columns, win->bottom - win->top);
X#if 0 /* We don't really want to for showing the caret... */
X			/* Show caret: */
X			if (win->curv >= 0)
X				wshow(win, win->curh, win->curv,
X					win->curh, win->curv);
X#endif
X		}
X	}
X}
X
X/* Close a window. */
X
Xvoid
Xwclose(win)
X	WINDOW *win;
X{
X	int id= win - winlist;
X	
X	if (id < 0 || id >= MAXWINDOWS || !win->open)
X		return;
X	killmenubar(&win->mbar);
X	if (win == wasfront)
X		wasfront= NULL;
X	if (win == front)
X		front= NULL;
X	win->open= FALSE;
X	if (win->title != NULL) {
X		free(win->title);
X		win->title= NULL;
X	}
X	_wreshuffle();
X	/* Select another window. */
X	if (front == NULL) {
X		/* Search below the window we just closed. */
X		for (; win < &winlist[MAXWINDOWS]; ++win) {
X			if (win->open) {
X				front= win;
X				break; /* First hit is OK */
X			}
X		}
X		if (front == NULL) {
X			/* Try searching above it. */
X			for (win= winlist+1; win < &winlist[MAXWINDOWS];
X								++win) {
X				if (win->open)
X					front= win;
X				/* NO break -- we need the last hit */
X			}
X		}
X		if (front == NULL) {
X			/* Exasperation time. */
X			front= &winlist[0]; /* The system window */
X		}
X		_wnewtitle(front); /* Make sure the title is redrawn */
X	}
X}
X
X/* Dummies for functions not supported by this version. */
X
X/*ARGSUSED*/
Xvoid
Xwsetdefwinpos(h, v)
X	int h, v;
X{
X}
X
X/*ARGSUSED*/
Xvoid
Xwsetdefwinsize(width, height)
X	int width, height;
X{
X}
X
X/*ARGSUSED*/
Xvoid
Xwsetmaxwinsize(width, height)
X	int width, height;
X{
X}
X
X/* Make a window the active window. */
X
Xvoid
Xwsetactive(win)
X	WINDOW *win;
X{
X	int id= win - winlist;
X	
X	if (id < 0 || id >= MAXWINDOWS || !win->open)
X		return;
X	_wnewtitle(front);
X	front= win;
X	_wnewtitle(front);
X}
X
X/* Select next, previous window.
X   Note: these will never select the system window unless it is already
X   selected (which can only occur if there are no other windows open). */
X
Xvoid
X_wselnext()
X{
X	WINDOW *win;
X	
X	for (win= front+1; win < &winlist[MAXWINDOWS]; ++win) {
X		if (win->open) {
X			wsetactive(win);
X			return;
X		}
X	}
X	for (win= winlist+1; win < front; ++win) {
X		if (win->open) {
X			wsetactive(win);
X			return;
X		}
X	}
X}
X
Xvoid
X_wselprev()
X{
X	WINDOW *win;
X	
X	for (win= front-1; win > winlist; --win) {
X		if (win->open) {
X			wsetactive(win);
X			return;
X		}
X	}
X	for (win= &winlist[MAXWINDOWS-1]; win > front; --win) {
X		if (win->open) {
X			wsetactive(win);
X			return;
X		}
X	}
X}
X
X/* Force a redraw of the entire screen.
X   (This routine only sets 'invalid' bits for all lines;
X   the actual redraw is done later in wgetevent or wupdate.) */
X
Xvoid
X_wredraw()
X{
X	int i;
X	
X	for (i= 0; i < lines; ++i)
X		uptodate[i]= FALSE;
X	_wreshuffle();
X	trmundefined();
X	trmputdata(0, lines-1, 0, "");
X}
X
X/* Temporarily restore cooked tty mode. */
X
X_wcooked()
X{
X	trmputdata(lines-1, lines-1, 0, "");
X	trmsync(lines-1, 0);
X	trmend();
X}
X
X/* Back to window mode.
X   If 'wait' flag is set, wait until a character is typed before
X   continuing. clearing the screen. */
X
X_wstdwin(wait)
X	bool wait;
X{
X	int flags;
X	
X	if (wait) {
X		printf("\nCR to continue... ");
X		fflush(stdout);
X	}
X	(void) trmstart(&lines, &columns, &flags);
X	if (wait)
X		(void) trminput();
X	_wredraw();
X	wmessage((char *)NULL); /* Reset menu bar */
X}
X
X/* Suspend the process (BSD Unix only). */
X
Xvoid
X_wsuspend()
X{
X	_wcooked();
X	trmsuspend();
X	_wstdwin(FALSE);
X}
X
X/* Execute a shell command, if possible and necessary outside the window
X   manager.  If the 'wait' parameter is set, the window manager pauses
X   until a character is typed before continuing. */
X
Xint
Xwsystem(cmd, wait)
X	char *cmd;
X	bool wait;
X{
X#ifdef DO_SYSTEM
X	int status;
X	_wcooked();
X	status= system(cmd);
X	_wstdwin(wait);
X	return status;
X#else
X	return -1;
X#endif
X}
X
X/* Return active window. */
X
XWINDOW *
Xwgetactive()
X{
X	return front;
X}
X
X/* Change a window's title. */
X
Xvoid
Xwsettitle(win, title)
X	WINDOW *win;
X	char *title;
X{
X	if (win->title != NULL)
X		free(win->title);
X	win->title= strdup(title);
X	_wnewtitle(win);
X}
X
X/* Change the mouse cursor -- dummy */
X
X/*ARGSUSED*/
Xvoid
Xwsetwincursor(win, cursor)
X	WINDOW *win;
X	CURSOR *cursor;
X{
X}
X
X/* Fetch a mouse cursor -- always return NULL */
X
X/*ARGSUSED*/
XCURSOR *
Xwfetchcursor(name)
X	char *name;
X{
X	return NULL;
X}
X
X/* Set a window's extent (document size). Not implemented here. */
X
X/*ARGSUSED*/
Xvoid
Xwsetdocsize(win, width, height)
X	WINDOW *win;
X	int width, height;
X{
X}
X
X/*ARGSUSED*/
Xvoid
Xwgetdocsize(win, pwidth, pheight)
X	WINDOW *win;
X	int *pwidth, *pheight;
X{
X	*pwidth = *pheight = 0;
X}
X
X/* Get a window's origin with respect to document. */
X
Xvoid
Xwgetorigin(win, ph, pv)
X	WINDOW *win;
X	int *ph, *pv;
X{
X	*ph= 0;
X	*pv= win->top + win->offset;
X}
X
X/* Get a window's origin with respect to screen. */
X
Xvoid
Xwgetwinpos(win, ph, pv)
X	WINDOW *win;
X	int *ph, *pv;
X{
X	*ph= 0;
X	*pv= win->top;
X}
X
X/* Get a window's window size. */
X
Xvoid
Xwgetwinsize(win, pwidth, pheight)
X	WINDOW *win;
X	int *pwidth, *pheight;
X{
X	*pwidth= columns;
X	*pheight= win->bottom - win->top;
X}
X
X/* Get the screen size in pixels. */
X
Xvoid
Xwgetscrsize(ph, pv)
X	int *ph, *pv;
X{
X	*ph= columns;
X	*pv= lines;
X}
X
X/* Get the screen size in mm.
X   Of course we don't know it; we pretend that the average character
X   is 3 mm wide and 6 mm high, which is a reasonable approximation
X   of reality on my terminal (an HP2621). */
X
Xvoid
Xwgetscrmm(ph, pv)
X	int *ph, *pv;
X{
X	*ph= columns * 3;
X	*pv= lines * 6;
X}
X
Xvoid
Xwfleep()
X{
X	trmbell();
X}
END_OF_FILE
if test 9984 -ne `wc -c <'Ports/alfa/stdwin.c'`; then
    echo shar: \"'Ports/alfa/stdwin.c'\" unpacked with wrong size!
fi
# end of 'Ports/alfa/stdwin.c'
fi
if test -f 'Ports/mac/draw.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/mac/draw.c'\"
else
echo shar: Extracting \"'Ports/mac/draw.c'\" \(10989 characters\)
sed "s/^X//" >'Ports/mac/draw.c' <<'END_OF_FILE'
X/* MAC STDWIN -- DOCUMENT DRAWING. */
X
X/* Contents of this file:
X   
X   wchange, wscroll;
X   wbegindrawing, wenddrawing, _wupdate, wupdate;
X   text attribute manipulation (internal and external);
X   text measuring;
X   text drawing;
X   coordinate conversion tools;
X   ordinary drawing.
X   
X   XXX Should be split, only things used between w{begin,end}drawing
X   belong here.
X
X   BEWARE OF COORDINATE SYSTEMS!
X   
X   The window's origin is not always the same.
X   When the aplication isn't drawing (i.e., outside w{begin,end}drawing),
X   the origin is (0, 0); this is necessary because the control mgr
X   doesn't like it otherwise.
X   When the application is drawing, the origin is set to win->(orgh, orgv)
X   so the drawing primitives don't need to do their own coordinate
X   transformation.
X   Routines called while not drawing must do their own transformations.
X   
X   XXX Routines that may be called any time are in trouble!
X   (There shouldn't be any.)
X*/
X
X#include "macwin.h"
X#ifdef MPW
X#include <Fonts.h>
X#endif
X
Xstatic WINDOW *drawing;
Xstatic TEXTATTR drawsaveattr;
Xstatic int baseline;
Xstatic int lineheight;
X
X/* Function prototypes */
X
XSTATIC void getwattr _ARGS((GrafPtr port, TEXTATTR *attr));
XSTATIC void setwattr _ARGS((TEXTATTR *attr));
XSTATIC void getfinfo _ARGS((void));
X
Xvoid
Xwchange(win, left, top, right, bottom)
X	WINDOW *win;
X	int left, top, right, bottom;
X{
X	Rect r;
X	
X	SetPort(win->w);
X	
X	if (drawing) dprintf("warning: wchange called while drawing");
X	makerect(win, &r, left, top, right, bottom);
X	InvalRect(&r);
X}
X
Xvoid
Xwscroll(win, left, top, right, bottom, dh, dv)
X	WINDOW *win;
X	int left, top, right, bottom;
X	int dh, dv;
X{
X	Rect r;
X	
X	if (drawing) dprintf("warning: wchange called while drawing");
X	makerect(win, &r, left, top, right, bottom);
X	scrollby(win, &r, dh, dv);
X}
X
X/* Scroll a rectangle (given in window coordinates) by dh, dv.
X   Also used from scroll.c. */
X/* XXX need less visible name */
X
Xvoid
Xscrollby(win, pr, dh, dv)
X	WINDOW *win;
X	Rect *pr;
X	int dh, dv;
X{
X	RgnHandle rgn= NewRgn();
X	
X	SetPort(win->w);
X	
X	rmcaret(win);
X	
X	if (!EmptyRgn(( (WindowPeek)win->w )->updateRgn)) {
X		RgnHandle ur= NewRgn();
X		int left, top;
X		Rect r;
X		
X		/* Scroll the part of the update region that intersects
X		   the scrolling area. */
X		CopyRgn(( (WindowPeek)win->w )->updateRgn, ur);
X		/* portBits.bounds is the screen in local coordinates! */
X		left= win->w->portBits.bounds.left;
X		top= win->w->portBits.bounds.top;
X		OffsetRgn(ur, left, top); /* Global to Local */
X		RectRgn(rgn, pr);
X		SectRgn(rgn, ur, ur);
X		if (!EmptyRgn(ur)) {
X			ValidRgn(ur);
X			OffsetRgn(ur, dh, dv);
X			SectRgn(rgn, ur, ur);
X			InvalRgn(ur);
X		}
X		DisposeRgn(ur);
X	}
X	
X	ScrollRect(pr, dh, dv, rgn);
X	InvalRgn(rgn);
X	
X	DisposeRgn(rgn);
X}
X
X
X/* Internal version of wupdate -- also used from event.c */
X
Xvoid
X_wupdate(win, pr)
X	WINDOW *win;
X	Rect *pr;
X{
X	RgnHandle rgn= NewRgn();
X	
X	SetPort(win->w);
X	
X	rmcaret(win);
X	BeginUpdate(win->w);
X	EraseRect(&win->w->portRect);
X	DrawGrowIcon(win->w);
X	DrawControls(win->w);
X	getwinrect(win, pr);
X	RectRgn(rgn, pr);
X	SectRgn(rgn, win->w->visRgn, rgn);
X	*pr= (*rgn)->rgnBBox;
X	OffsetRect(pr, win->orgh, win->orgv);
X	if (win->drawproc != NULL && !EmptyRect(pr)) {
X		wbegindrawing(win);
X		(*win->drawproc)(win, pr->left, pr->top, pr->right, pr->bottom);
X		wenddrawing(win);
X	}
X	EndUpdate(win->w);
X	DisposeRgn(rgn);
X}
X
X/* Process an update event -- call the window's draw procedure. */
X/* XXX This function shouldn't be in the stdwin spec (why was it ever?) */
X
Xvoid
Xwupdate(win)
X	WINDOW *win;
X{
X	if (win->drawproc != NULL) {
X		Rect r;
X		_wupdate(win, &r);
X	}
X}
X
Xvoid
Xwbegindrawing(win)
X	WINDOW *win;
X{
X	Rect r;
X	
X	if (drawing != NULL) {
X		dprintf("warning: recursive call to wbegindrawing");
X		/* Fix it */
X		wenddrawing(drawing);
X	}
X	if (win == NULL) {
X		dprintf("warning: wbegindrawing(NULL) ignored");
X		return;
X	}
X	drawing= win;
X	SetPort(win->w);
X	SetOrigin(win->orgh, win->orgv);
X	rmcaret(win);
X	getwinrect(win, &r);
X	ClipRect(&r);
X	PenNormal();
X	wgettextattr(&drawsaveattr);
X	wsettextattr(&win->attr);
X}
X
Xvoid
Xwenddrawing(win)
X	WINDOW *win;
X{
X	Rect r;
X	
X	if (drawing == NULL) {
X		dprintf("warning: wenddrawing ignored while not drawing");
X		return;
X	}
X	if (drawing != win) {
X		dprintf("warning: wenddrawing ignored for wrong window");
X		return;
X	}
X	SetOrigin(0, 0);
X	SetRect(&r, -32000, -32000, 32000, 32000);
X	ClipRect(&r);
X	wsettextattr(&drawsaveattr);
X	drawing= NULL;
X}
X
X/* Get the current text attributes of a GrafPort. */
X
Xstatic void
Xgetwattr(port, attr)
X	GrafPtr port;
X	TEXTATTR *attr;
X{
X	SetPort(port); /* XXX Is this necessary to validate txFont etc.? */
X	
X	attr->font= port->txFont;
X	attr->style= port->txFace;
X	attr->size= port->txSize;
X}
X
X/* Start using the given text attributes in the current grafport. */
X
Xstatic void
Xsetwattr(attr)
X	TEXTATTR *attr;
X{
X	TextFont(attr->font);
X	TextFace(attr->style & ~TX_INVERSE);
X	TextSize(attr->size);
X}
X
X/* Get font info and baseline from current GrafPort */
X
Xstatic void
Xgetfinfo()
X{
X	FontInfo finfo;
X	GetFontInfo(&finfo);
X	baseline= finfo.ascent + finfo.leading;
X	lineheight= baseline + finfo.descent;
X}
X
X/* Initialize 'wattr'.  Uses the screen's grafport. */
X
Xint _w_font= applFont;
Xint _w_size= 9;
X
Xvoid
Xinitwattr()
X{
X	TEXTATTR saveattr;
X	
X	SetPort(screen);
X	
X	getwattr(screen, &saveattr);
X	TextFont(_w_font);
X	TextSize(_w_size);
X	getwattr(screen, &wattr);
X	getfinfo();
X	setwattr(&saveattr);
X}
X
X/* TEXT ATTRIBUTES. */
X
Xvoid
Xwgettextattr(attr)
X	TEXTATTR *attr;
X{
X	*attr= wattr;
X}
X
Xvoid
Xwsettextattr(attr)
X	TEXTATTR *attr;
X{
X	wattr= *attr;
X	if (drawing != NULL) {
X		setwattr(attr);
X		getfinfo();
X	}
X}
X
Xvoid
Xwgetwintextattr(win, attr)
X	WINDOW *win;
X	TEXTATTR *attr;
X{
X	*attr= win->attr;
X}
X
Xvoid
Xwsetwintextattr(win, attr)
X	WINDOW *win;
X	TEXTATTR *attr;
X{
X	win->attr= *attr;
X	if (drawing != NULL)
X		dprintf("warning: wsetwintextattr called while drawing");
X}
X
Xvoid
Xwsetfont(fontname)
X	char *fontname;
X{
X	if (fontname == NULL || *fontname == EOS)
X		wattr.font= _w_font;
X	else {
X		short fnum= 0;
X		GetFNum(PSTRING(fontname), &fnum);
X		if (fnum == 0)
X			dprintf("can't find font %s", fontname);
X		wattr.font= fnum;
X	}
X	if (drawing != NULL) {
X		TextFont(wattr.font);
X		getfinfo();
X	}
X	
X}
X
Xvoid
Xwsetsize(size)
X	int size;
X{
X	wattr.size= size;
X	if (drawing != NULL) {
X		TextSize(size);
X		getfinfo();
X	}
X}
X
Xvoid
Xwsetstyle(face)
X	Style face;
X{
X	wattr.style= face;
X	if (drawing != NULL) {
X		TextFace(face & ~TX_INVERSE);
X		getfinfo();
X	}
X}
X
Xvoid
Xwsetplain()
X{
X	wsetstyle(0);
X}
X
Xvoid
Xwsetinverse()
X{
X	wattr.style |= TX_INVERSE;
X}
X
Xvoid
Xwsetbold()
X{
X	wsetstyle(bold);
X}
X
Xvoid
Xwsetitalic()
X{
X	wsetstyle(italic);
X}
X
Xvoid
Xwsetbolditalic()
X{
X	wsetstyle(bold|italic);
X}
X
Xvoid
Xwsetunderline()
X{
X	wsetstyle(underline);
X}
X
Xvoid
Xwsethilite()
X{
X	wsetstyle(TX_INVERSE);
X}
X
X/* TEXT MEASURING. */
X
Xint
Xwlineheight()
X{
X	if (drawing == NULL) {
X		TEXTATTR saveattr;
X		getwattr(screen, &saveattr);
X		setwattr(&wattr);
X		getfinfo();
X		setwattr(&saveattr);
X	}
X	return lineheight;
X}
X
Xint
Xwbaseline()
X{
X	if (drawing == NULL)
X		(void) wlineheight();
X	return baseline;
X}
X
Xint
Xwtextwidth(str, len)
X	char *str;
X	int len;
X{
X	TEXTATTR saveattr;
X	int width;
X	
X	if (drawing == NULL) {
X		getwattr(screen, &saveattr);
X		setwattr(&wattr);
X	}
X	if (len < 0)
X		len= strlen(str);
X	width= TextWidth(str, 0, len);
X	if (drawing == NULL)
X		setwattr(&saveattr);
X	return width;
X}
X
Xint
Xwcharwidth(c)
X	int c;
X{
X	char cbuf[1];
X	cbuf[0]= c;
X	return wtextwidth(cbuf, 1);
X}
X
X/* TEXT DRAWING. */
X
Xvoid
Xwdrawtext(h, v, str, len)
X	int h, v;
X	char *str;
X	int len;
X{
X	Point pen;
X	
X	if (len < 0)
X		len= strlen(str);
X	MoveTo(h, v + baseline);
X	DrawText(str, 0, len);
X	GetPen(&pen);
X	if (wattr.style & TX_INVERSE) {
X		Rect r;
X		SetRect(&r, h, v, pen.h, v + lineheight);
X		InvertRect(&r);
X	}
X}
X
Xvoid
Xwdrawchar(h, v, c)
X	int h, v;
X	int c;
X{
X	if ((wattr.style & TX_INVERSE) == 0) {
X		/* Attempt to optimize for appls. like dpv */
X		MoveTo(h, v + baseline);
X		DrawChar(c);
X	}
X	else {
X		char cbuf[1];
X		cbuf[0]= c;
X		wdrawtext(h, v, cbuf, 1);
X	}
X}
X
X/* COORDINATE CONVERSIONS ETC. */
X
X/* Create a rect in current window coordinates (as for getwinrect)
X   from a rectangle given in document coordinates.
X   This works both while drawing and while not drawing.
X   The resulting rectangle is clipped to the winrect. */
X
Xvoid
Xmakerect(win, pr, left, top, right, bottom)
X	WINDOW *win;
X	Rect *pr;
X	int left, top, right, bottom;
X{
X	Rect r;
X	SetRect(pr, left, top, right, bottom);
X	if (!drawing)
X		OffsetRect(pr, - win->orgh, - win->orgv);
X	getwinrect(win, &r);
X	(void) SectRect(&r, pr, pr);
X}
X
X/* Retrieve the 'winrect', i.e., the contents area exclusive
X   of the scroll bars and grow icon.
X   Coordinates are in window coordinates, i.e.,
X   the origin is (0, 0) outside w{begin,end}drawing,
X   but (win->orgh, win->orgv) between calls to these routines. */
X
Xvoid
Xgetwinrect(win, pr)
X	WINDOW *win;
X	Rect *pr;
X{
X	*pr= win->w->portRect;
X	pr->right -= BAR;
X	pr->bottom -= BAR;
X}
X
X/* ACTUAL DRAW ROUTINES. */
X
Xvoid
Xwdrawline(h1, v1, h2, v2)
X{
X	MoveTo(h1, v1);
X	Line(h2-h1, v2-v1);
X}
X
Xvoid
Xwxorline(h1, v1, h2, v2)
X{
X	MoveTo(h1, v1);
X	PenMode(patXor);
X	Line(h2-h1, v2-v1);
X	PenNormal();
X}
X
Xvoid
Xwdrawbox(left, top, right, bottom)
X	int left, top, right, bottom;
X{
X	Rect r;
X	
X	SetRect(&r, left, top, right, bottom);
X	FrameRect(&r);
X}
X
Xvoid
Xwerase(left, top, right, bottom)
X	int left, top, right, bottom;
X{
X	Rect r;
X	
X	SetRect(&r, left, top, right, bottom);
X	EraseRect(&r);
X}
X
Xvoid
Xwinvert(left, top, right, bottom)
X	int left, top, right, bottom;
X{
X	Rect r;
X	
X	SetRect(&r, left, top, right, bottom);
X	InvertRect(&r);
X}
X
Xvoid
Xwpaint(left, top, right, bottom)
X	int left, top, right, bottom;
X{
X	Rect r;
X	
X	SetRect(&r, left, top, right, bottom);
X	FillRect(&r, QD(black));
X}
X
Xvoid
Xwshade(left, top, right, bottom, perc)
X	int left, top, right, bottom;
X	int perc;
X{
X	Rect r;
X	unsigned char *p; /* really Pattern * or PatPtr */
X	
X	perc= (perc + 12)/25;
X	CLIPMIN(perc, 0);
X	
X	switch (perc) {
X	case 0:	p= &QD(white)[0];	break;
X	case 1: p= &QD(ltGray)[0];	break;
X	case 2: p= &QD(gray)[0]; 	break;
X	case 3: p= &QD(dkGray)[0];	break;
X	default: p= &QD(black)[0];	break;
X	}
X	
X	SetRect(&r, left, top, right, bottom);
X
X	FillRect(&r, p);
X}
X
Xvoid
Xwdrawcircle(h, v, radius)
X	int h, v;
X	int radius;
X{
X	Rect r;
X	
X	/* XXX Isn't there an off-by-one error here? */
X	SetRect(&r, h-radius, v-radius, h+radius, v+radius);
X	FrameOval(&r);
X}
X
X/* Draw counterclockwise elliptical arc.
X   h, v are center; hrad, vrad are half axes; ang1 and ang2 are start
X   and stop angles in degrees, with respect to 3 o'clock. */
X
Xvoid
Xwdrawelarc(h, v, hrad, vrad, ang1, ang2)
X{
X	Rect r;
X	/* XXX Does this work? No off-by-one errors? */
X	SetRect(&r, h-hrad, v-vrad, h+hrad, v+vrad);
X	FrameArc(&r, 90-ang1, ang1-ang2); /* ??? */
X}
X
X/* CLIPPING */
X
Xvoid
Xwcliprect(left, top, right, bottom)
X	int left, top, right, bottom;
X{
X	Rect r1, r2;
X	SetRect(&r1, left, top, right, bottom);
X	getwinrect(drawing, &r2);
X	SectRect(&r1, &r2, /*dst:*/ &r2);
X	ClipRect(&r2);
X
X}
X
Xvoid
Xwnoclip()
X{
X	Rect r;
X	getwinrect(drawing, &r);
X	ClipRect(&r);
X}
END_OF_FILE
if test 10989 -ne `wc -c <'Ports/mac/draw.c'`; then
    echo shar: \"'Ports/mac/draw.c'\" unpacked with wrong size!
fi
# end of 'Ports/mac/draw.c'
fi
if test -f 'Ports/x11/menu.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/x11/menu.c'\"
else
echo shar: Extracting \"'Ports/x11/menu.c'\" \(11775 characters\)
sed "s/^X//" >'Ports/x11/menu.c' <<'END_OF_FILE'
X/* X11 STDWIN -- Menu handling */
X
X#include "x11.h"
X#include "llevent.h" /* For _w_dirty */
X
Xstatic bool local; /* When zero, menus are created global */
X
Xstatic int nmenus;
Xstatic MENU **menulist; /* Only global menus */
X
Xstatic MENU *sysmenu; /* System menu, included in each window's mbar */
X
Xstatic
Xmbardirty(win)
X	WINDOW *win;
X{
X	_w_dirty= win->mbar.dirty= TRUE;
X}
X
Xvoid
Xwmenusetdeflocal(flag)
X	bool flag;
X{
X	local= flag;
X}
X
Xvoid
Xwmenuattach(win, mp)
X	WINDOW *win;
X	MENU *mp;
X{
X	int i;
X	
X	for (i= 0; i < win->nmenus; ++i) {
X		if (win->menulist[i] == mp)
X			return; /* Already attached */
X	}
X	L_APPEND(win->nmenus, win->menulist, MENU *, mp);
X	mbardirty(win);
X}
X
Xvoid
Xwmenudetach(win, mp)
X	WINDOW *win;
X	MENU *mp;
X{
X	int i;
X	
X	for (i= 0; i < win->nmenus; ++i) {
X		if (win->menulist[i] == mp) {
X			L_REMOVE(win->nmenus, win->menulist, MENU *, i);
X			mbardirty(win);
X			break;
X		}
X	}
X}
X
X_waddmenus(win)
X	WINDOW *win;
X{
X	int i;
X	
X	/* Create system menu if first time here */
X	if (sysmenu == NULL) {
X		bool savelocal= local;
X		wmenusetdeflocal(TRUE);
X		sysmenu= wmenucreate(0, "X");
X		if (sysmenu != NULL)
X			wmenuadditem(sysmenu, "Close", -1);
X		wmenusetdeflocal(savelocal);
X	}
X	
X	/* Initialize the nonzero variables used by the menu module */
X	win->curmenu= win->curitem= -1;
X	
X	/* Add system menu and all global menus to the menu list */
X	if (sysmenu != NULL) {
X		L_APPEND(win->nmenus, win->menulist, MENU *, sysmenu);
X	}
X	for (i= 0; i < nmenus; ++i) {
X		L_APPEND(win->nmenus, win->menulist, MENU *, menulist[i]);
X	}
X	if (nmenus > 0)
X		mbardirty(win);
X}
X
X_w_delmenus(win)
X	WINDOW *win;
X{
X	/* Delete the menu list before closing a window */
X	L_DEALLOC(win->nmenus, win->menulist);
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->nitems= 0;
X	mp->itemlist= NULL;
X	if (!local) {
X		L_APPEND(nmenus, menulist, MENU *, mp);
X		_waddtoall(mp);
X	}
X	return mp;
X}
X
Xvoid
Xwmenudelete(mp)
X	MENU *mp;
X{
X	int i;
X	
X	for (i= 0; i < nmenus; ++i) {
X		if (menulist[i] == mp) {
X			L_REMOVE(nmenus, menulist, MENU *, i);
X			break;
X		}
X	}
X	_wdelfromall(mp);
X	
X	for (i= 0; i < mp->nitems; ++i)
X		FREE(mp->itemlist[i].text);
X	FREE(mp->itemlist);
X	FREE(mp);
X}
X
Xint
Xwmenuadditem(mp, text, shortcut)
X	MENU *mp;
X	char *text;
X	int shortcut;
X{
X	struct item it;
X	
X	it.text= strdup(text);
X	if (shortcut < 0)
X		it.sctext= NULL;
X	else {
X		char buf[50];
X		sprintf(buf, "M-%c", shortcut);
X		it.sctext= strdup(buf);
X	}
X	it.shortcut= shortcut;
X	it.enabled=  it.text != NULL && it.text[0] != EOS;
X	it.checked= FALSE;
X	L_APPEND(mp->nitems, mp->itemlist, struct item, it);
X	return mp->nitems - 1;
X}
X
Xvoid
Xwmenusetitem(mp, i, text)
X	MENU *mp;
X	int i;
X	char *text;
X{
X	if (i < 0 || i >= mp->nitems)
X		return;
X	FREE(mp->itemlist[i].text);
X	mp->itemlist[i].text= strdup(text);
X}
X
Xvoid
Xwmenuenable(mp, i, flag)
X	MENU *mp;
X	int i;
X	bool flag;
X{
X	if (i < 0 || i >= mp->nitems)
X		return;
X	mp->itemlist[i].enabled= flag;
X}
X
Xvoid
Xwmenucheck(mp, i, flag)
X	MENU *mp;
X	int i;
X	bool flag;
X{
X	if (i < 0 || i >= mp->nitems)
X		return;
X	mp->itemlist[i].checked= flag;
X}
X
X/* --- system-dependent code starts here --- */
X
X/*
XXXX Stuff recomputed more than I like:
X	- length of menu titles and menu item texts
X	- menu item text widths
X*/
X
X#define NOITEM (-1)
X#define NOMENU (-1)
X
X/* Precomputed values (assume _wdrawmbar is always called first) */
Xstatic int baseline;
Xstatic int lineheight;
Xstatic int halftitledist;
X#define titledist (2*halftitledist)
Xstatic int shortcutdist;
X
Xstatic
X_wmenusetup()
X{
X	shortcutdist= XTextWidth(_wmf, "    ", 4);
X	halftitledist= XTextWidth(_wmf, "0", 1);
X	baseline= _wmf->ascent;
X	lineheight= _wmf->ascent + _wmf->descent;
X}
X
X/* Draw the menu bar.
X   Called via the normal exposure event mechanism. */
X
X_wdrawmbar(win)
X	WINDOW *win;
X{
X	int i;
X	int x;
X	int y;
X	
X	_wmenusetup();
X	x= titledist;
X	y= baseline - 1 + (win->mbar.height - lineheight) / 2;
X	
X	XClearWindow(_wd, win->mbar.wid);
X	for (i= 0; i < win->nmenus; ++i) {
X		char *title= win->menulist[i]->title;
X		int len= strlen(title);
X		XDrawString(_wd, win->mbar.wid, win->gc, x, y, title, len);
X		x += XTextWidth(_wmf, title, len) + titledist;
X	}
X}
X
Xstatic
Xinverttitle(win, it)
X	WINDOW *win;
X	int it;
X{
X	int x= leftedge(win, it);
X	MENU *mp= win->menulist[it];
X	char *title= mp->title;
X	int len= strlen(title);
X	int width= XTextWidth(_wmf, title, len);
X	
X	_winvert(win->mbar.wid, win->gc,
X		x-halftitledist, 0, width+titledist, win->mbar.height);
X}
X
Xstatic int
Xleftedge(win, it)
X	WINDOW *win;
X	int it;
X{
X	int i;
X	int x= titledist;
X	
X	for (i= 0; i < it; ++i) {
X		char *title= win->menulist[i]->title;
X		int len= strlen(title);
X		int width= XTextWidth(_wmf, title, len);
X		x += width + titledist;
X	}
X	
X	return x;
X}
X
X/* Draw the current menu */
X
Xstatic
Xdrawmenu(win)
X	WINDOW *win;
X{
X	int i;
X	int x= halftitledist;
X	int y= baseline;
X	MENU *mp= win->menulist[win->curmenu];
X	
X	for (i= 0; i < mp->nitems; ++i) {
X		char *text= mp->itemlist[i].text;
X		int len= strlen(text);
X		char *marker= NULL;
X		if (!mp->itemlist[i].enabled) {
X			if (len > 0)
X				marker= "-";
X		}
X		else if (mp->itemlist[i].checked)
X			marker= "*";
X		if (marker != NULL) {
X			int width= XTextWidth(_wmf, marker, 1);
X			XDrawString(_wd, win->mwin.wid, win->gc,
X				(x-width)/2, y, marker, 1);
X		}
X		XDrawString(_wd, win->mwin.wid, win->gc, x, y, text, len);
X		text= mp->itemlist[i].sctext;
X		if (text != NULL) {
X			int width;
X			len= strlen(text);
X			width= XTextWidth(_wmf, text, len);
X			XDrawString(_wd, win->mwin.wid, win->gc,
X				win->mwin.width - width - halftitledist, y,
X				text, len);
X		}
X		y += lineheight;
X	}
X}
X
X/* Create the window for the menu.
X   It is a direct child of the outer window, but aligned with the
X   top of the inner window */
X
Xstatic
Xmakemenu(win)
X	WINDOW *win;
X{
X	int i;
X	int maxwidth= 0;
X	MENU *mp= win->menulist[win->curmenu];
X	Window child_dummy;
X	
X	/* Compute the maximum item width.
X	   Item width is the sum of:
X	   - 1/2 title width (left margin, also used for tick marks)
X	   - text width of item text
X	   - if there is a shortcut:
X	   	- shortcutdist (some space between text and shortcut)
X	   	- text width of shortcut text
X	   - 1/2 title width (right margin)
X	*/
X
X	for (i= 0; i < mp->nitems; ++i) {
X		char *text= mp->itemlist[i].text;
X		int len= strlen(text);
X		int width= XTextWidth(_wmf, text, len);
X		text= mp->itemlist[i].sctext;
X		if (text != NULL) {
X			len= strlen(text);
X			width += XTextWidth(_wmf, text, len) + shortcutdist;
X		}
X		if (width > maxwidth)
X			maxwidth= width;
X	}
X	
X	win->mwin.width= maxwidth + titledist;
X	win->mwin.height= mp->nitems * lineheight + 1;
X	CLIPMAX(win->mwin.width, WidthOfScreen(_ws));
X	CLIPMAX(win->mwin.height, HeightOfScreen(_ws));
X	
X	if (!XTranslateCoordinates(_wd, win->wo.wid,
X		RootWindowOfScreen(_ws),
X		leftedge(win, win->curmenu) -halftitledist + win->mbar.x,
X		win->wi.y,
X		&win->mwin.x,
X		&win->mwin.y,
X		&child_dummy)) {
X		
X		_wwarning("makemenu: XTranslateCoordinates failed");
X		win->mwin.x = win->mwin.y = 0;
X	}
X	
X	CLIPMAX(win->mwin.x, WidthOfScreen(_ws) - win->mwin.width);
X	CLIPMAX(win->mwin.y, HeightOfScreen(_ws) - win->mwin.height);
X	CLIPMIN(win->mwin.x, 0);
X	CLIPMIN(win->mwin.y, 0);
X	
X	win->mwin.dirty= TRUE;
X	win->mwin.border= IBORDER;
X	
X	(void) _wcreate1(&win->mwin, RootWindowOfScreen(_ws), XC_arrow, FALSE,
X		win->fgo, win->bgo, 1);
X	_wsaveunder(&win->mwin, True);
X	XMapWindow(_wd, win->mwin.wid);
X	i = XGrabPointer(_wd,		/* display */
X		win->mwin.wid,		/* grab_window */
X		False,			/* owner_events */
X		ButtonMotionMask | ButtonReleaseMask,
X					/* event_masks */
X		GrabModeAsync,		/* pointer_mode */
X		GrabModeAsync,		/* keyboard_mode */
X		None,			/* confine_to */
X		None,			/* cursor */
X		_w_lasttime		/* timestamp */
X		);
X	if (i != GrabSuccess) {
X		_wwarning("makemenu: XGrabPointer failed (err %d)", i);
X		/* Didn't get the grab -- forget about it */
X	}
X}
X
X/* Handle mouse state change in menu bar */
X
X_whitmbar(bsp, ep)
X	struct button_state *bsp;
X	EVENT *ep;
X{
X	WINDOW *win= bsp->win;
X
X	if (win->curmenu >= 0) {
X		/* We already created a menu.
X		   This is probably an event that was queued before
X		   the menu window was created. */
X		_wdebug(1, "_whitmbar: mouse in mwin");
X	}
X	
X	if (!bsp->down)
X		hidemenu(win);
X	else if (bsp->y >= 0 && bsp->y <= win->mbar.height &&
X			bsp->x >= 0 && bsp->x <= win->mbar.width)
X		showmenu(win, whichmenu(win, bsp->x));
X}
X
X/* Handle mouse state change in menu.
X   (This is called with a fake button state from _whitmbar,
X   since the menu bar has grabbed the pointer) */
X
X/*static*/ /* Now called from event.c */
X_whitmwin(bsp, ep)
X	struct button_state *bsp;
X	EVENT *ep;
X{
X	WINDOW *win= bsp->win;
X	MENU *mp= win->menulist[win->curmenu];
X	int it;
X	
X	if (bsp->x >= 0 && bsp->x <= win->mwin.width)
X		it= whichitem(mp, bsp->y);
X	else
X		it= NOITEM;
X	_wdebug(5, "_whitmwin: hit item %d", it);
X	hiliteitem(win, it);
X	
X	if (!bsp->down) {
X		hidemenu(win);
X		XFlush(_wd); /* Show it right now */
X		if (it >= 0) {
X			if (mp->id == 0) {
X				ep->type= WE_COMMAND;
X				ep->u.command= WC_CLOSE;
X				ep->window= win;
X			}
X			else {
X				ep->type= WE_MENU;
X				ep->u.m.id= mp->id;
X				ep->u.m.item= it;
X				ep->window= win;
X			}
X		}
X	}
X}
X
X/* Show and hide menus */
X
Xstatic
Xshowmenu(win, newmenu)
X	WINDOW *win;
X	int newmenu;
X{
X	if (newmenu != win->curmenu) {
X		hidemenu(win);
X		if (newmenu >= 0) {
X			win->curmenu= newmenu;
X			win->curitem= NOITEM;
X			inverttitle(win, win->curmenu);
X			makemenu(win);
X			drawmenu(win);
X		}
X	}
X}
X
Xstatic
Xhidemenu(win)
X	WINDOW *win;
X{
X	if (win->curmenu >= 0) {
X		hiliteitem(win, NOITEM);
X		XDestroyWindow(_wd, win->mwin.wid);
X		win->mwin.wid= 0;
X		inverttitle(win, win->curmenu);
X		win->curmenu= NOMENU;
X	}
X}
X
X/* Compute which menu was hit */
X
Xstatic int
Xwhichmenu(win, xhit)
X	WINDOW *win;
X	int xhit;
X{
X	int i;
X	int x= halftitledist;
X	
X	if (xhit < x)
X		return NOMENU;
X	
X	for (i= 0; i < win->nmenus; ++i) {
X		char *title= win->menulist[i]->title;
X		int len= strlen(title);
X		x += XTextWidth(_wmf, title, len) + titledist;
X		if (xhit < x)
X			return i;
X	}
X	
X	return NOMENU;
X}
X
X/* (Un)hilite the given menu item */
X
Xstatic
Xhiliteitem(win, it)
X	WINDOW *win;
X	int it;
X{
X	if (it != win->curitem) {
X		if (win->curitem >= 0)
X			invertitem(win, win->curitem);
X		if (it >= 0)
X			invertitem(win, it);
X		win->curitem= it;
X	}
X}
X
Xstatic
Xinvertitem(win, it)
X	WINDOW *win;
X	int it;
X{
X	int top, size;
X	
X	size= lineheight;
X	top= it*size;
X	_winvert(win->mwin.wid, win->gc, 0, top, win->mwin.width, size);
X}
X
X/* Compute which item was hit */
X
Xstatic int
Xwhichitem(mp, yhit)
X	MENU *mp;
X	int yhit;
X{
X	int it= yhit < 0 ? NOITEM : yhit / lineheight;
X	
X	_wdebug(4, "whichitem: yhit=%d, it=%d", yhit, it);
X	if (it >= 0 && it < mp->nitems && mp->itemlist[it].enabled)
X		return it;
X	else
X		return NOITEM;
X}
X
X/* Generate a menu selection event from a meta-key press.
X   *ep has the window already filled in. */
X
Xbool
X_w_menukey(c, ep)
X	int c;
X	EVENT *ep;
X{
X	WINDOW *win= ep->window;
X	int i;
X	int altc;
X	bool althit= FALSE;
X	
X	c &= 0xff;
X	
X	if (islower(c))
X		altc= toupper(c);
X	else if (isupper(c))
X		altc= tolower(c);
X	else
X		altc= 0;
X	
X	for (i= 0; i < win->nmenus; ++i) {
X		MENU *mp= win->menulist[i];
X		int j;
X		for (j= 0; j < mp->nitems; ++j) {
X			if (mp->itemlist[j].shortcut == c) {
X				ep->type= WE_MENU;
X				ep->u.m.id= mp->id;
X				ep->u.m.item= j;
X				return TRUE;
X			}
X			else if (altc != 0 && !althit &&
X				mp->itemlist[j].shortcut == altc) {
X				ep->u.m.id= mp->id;
X				ep->u.m.item= j;
X				althit= TRUE;
X			}
X		}
X	}
X	if (althit)
X		ep->type= WE_MENU;
X	return althit;
X}
X
X/* Delete all menus -- called by wdone().
X   (In fact local menus aren't deleted since they aren't in the menu list). */
X
X_wkillmenus()
X{
X	while (nmenus > 0)
X		wmenudelete(menulist[nmenus-1]);
X	if (sysmenu != NULL) {
X		wmenudelete(sysmenu);
X		sysmenu= NULL;
X	}
X}
END_OF_FILE
if test 11775 -ne `wc -c <'Ports/x11/menu.c'`; then
    echo shar: \"'Ports/x11/menu.c'\" unpacked with wrong size!
fi
# end of 'Ports/x11/menu.c'
fi
if test -f 'Ports/x11/timer.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Ports/x11/timer.c'\"
else
echo shar: Extracting \"'Ports/x11/timer.c'\" \(5523 characters\)
sed "s/^X//" >'Ports/x11/timer.c' <<'END_OF_FILE'
X/* X11 STDWIN -- Alarm timers (BSD-specific) */
X
X#ifdef AMOEBA
X#include "amtimer.c"
X#else /* !AMOEBA */
X
X#include "x11.h"
X
X#include <errno.h>
X
X/* Alarm timer values must be stored as absolute times,
X   but since they are in tenths of a second and stored in a long,
X   there isn't enough space to store the true absolute time.
X   Therefore, they are stored relative to the second when the
X   first call to wsettimer was made, which is saved in torigin */
X
Xstatic long torigin;		/* Seconds */
Xstatic long nexttimer;		/* Deciseconds */
X
X/* Compute a new value for nexttimer.
X   Return the relevant window as a convenience */
X
Xstatic WINDOW *
Xsetnexttimer()
X{
X	WINDOW *win= _wnexttimer();
X	
X	if (win == NULL)
X		nexttimer= 0;
X	else
X		nexttimer= win->timer;
X	_wdebug(3, "setnexttimer: nexttimer at %d for %x", nexttimer, win);
X	return win;
X}
X
X/* Set the alarm timer for a given window */
X
Xvoid wsettimer(win, deciseconds)
X	WINDOW *win;
X	int deciseconds;
X{
X	_wdebug(3, "wsettimer: deciseconds=%d", deciseconds);
X	win->timer= 0;
X	if (deciseconds > 0) {
X		struct timeval tv;
X		struct timezone tz;
X		
X		if (gettimeofday(&tv, &tz) < 0) {
X			_wwarning("wsettimer: can't get time of day");
X		}
X		else {
X			if (torigin == 0) {
X				torigin= tv.tv_sec;
X				_wdebug(3, "wsettimer: torigin %d", torigin);
X			}
X			win->timer= deciseconds + 10 * (tv.tv_sec - torigin) +
X				tv.tv_usec/100000;
X			_wdebug(4, "wsettimer(%d): timer set to %d",
X				deciseconds, win->timer);
X		}
X	}
X	(void) setnexttimer();
X}
X
X/* Return a pointer suitable as timeout parameter for BSD select(2).
X   If no alarms are currently set, return a NULL pointer */
X
Xstatic struct timeval *
Xtimeout()
X{
X	if (nexttimer == 0) {
X		_wdebug(4, "timeout: no timers set");
X		return NULL;
X	}
X	else {
X		static struct timeval tv;
X		struct timezone tz;
X		
X		if (gettimeofday(&tv, &tz) < 0) {
X			_wwarning("timeout: can't get time of day");
X			return NULL;
X		}
X		else {
X			long tout;
X			tout= nexttimer
X				- (tv.tv_sec - torigin) * 10
X				- tv.tv_usec / 100000;
X			if (tout <= 0)
X				tv.tv_sec= tv.tv_usec= 0;
X			else {
X				tv.tv_sec= tout / 10; 
X				tv.tv_usec= (tout % 10) * 100000;
X			}
X			_wdebug(4, "timeout: delay %d sec %d usec",
X				tv.tv_sec, tv.tv_usec);
X			return &tv;
X		}
X	}
X}
X
X/* Check if an alarm has gone off, and if so, generate an appropriate event.
X   This can be called at any time, but for efficiency reasons it should
X   only be called when an alarm has actually gone of (i.e., select has
X   timed out).  If an alarm has gone off, it will always be found by
X   this function */
X
Xstatic bool
Xdotimer(ep)
X	EVENT *ep;
X{
X	WINDOW *win= setnexttimer();
X	struct timeval *tp;
X	
X	if (win == NULL) {
X		_wdebug(1, "dotimer: no event found (spurious call)");
X		return FALSE;
X	}
X	tp= timeout();
X	if (tp == NULL) {
X		_wdebug(1, "dotimer: unexpected NULL timeout()");
X		return FALSE;
X	}
X	if (tp->tv_sec == 0 && tp->tv_usec == 0) {
X		_wdebug(3, "dotimer: reporting timer event");
X		ep->type= WE_TIMER;
X		ep->window= win;
X		win->timer= 0;
X		(void) setnexttimer();
X		return TRUE;
X	}
X	else {
X		_wdebug(1, "dotimer: it is not yet time");
X		return FALSE;
X	}
X}
X
X/* Check for timer events.
X   Call this after XPending returns 0, just before calling XNextEvent */
X
Xbool
X_w_checktimer(ep, mayblock)
X	EVENT *ep;
X	bool mayblock;
X{
X	for (;;) {
X		struct timeval *tp= timeout();
X		/* This is naive.  BSD 4.3 really uses an array of longs
X		   as arguments to select.  Hope there aren't >32 fds, or
X		   the socket and pipe are among the first 32 files opened */
X		unsigned long rd, wd, xd;
X		int fd, nfd;
X		int nfound;
X		if (tp != NULL)
X			_wdebug(4, "_wchecktimer: sec=%d, usec=%d",
X				tp->tv_sec, tp->tv_usec);
X		if (!mayblock) {
X			if (tp != NULL)
X				_wdebug(4, "_wchecktimer: !mayblock");
X			return tp != NULL &&
X				tp->tv_sec == 0 && tp->tv_usec == 0 &&
X				dotimer(ep);
X		}
X		fd= _wd->fd;
X		rd= 1 << fd;
X		nfd= fd+1;
X#ifdef PIPEHACK
X		if (_wpipe[0] >= 0) {
X			rd |= (1 << _wpipe[0]);
X			if (_wpipe[0]+1 > nfd)
X				nfd= _wpipe[0]+1;
X		}
X#endif
X		wd= xd= 0;
X		if (tp == NULL)
X			_wdebug(4, "wchecktimer: select w/o timeout");
X		else
X			_wdebug(4,
X				"_wchecktimer: select call, sec=%d, usec=%d",
X				tp->tv_sec, tp->tv_usec);
X#ifdef AMOEBA
X		/* Amoeba is far superior to unix:
X		   we don't need something as silly as select... */
X		nfound= EIO;
X#else
X		nfound= select(nfd, &rd, &wd, &xd, tp);
X#endif
X		_wdebug(4, "_wchecktimer: select returned %d", nfound);
X		/* Note: if select returns negative, we also break
X		   out of the loop -- better drop a timer event than
X		   loop forever on a select error.
X		   The only exception is EINTR, which may have been caused
X		   by an application's signal handler */
X		if (nfound < 0) {
X			if (errno == EINTR) {
X				_wdebug(4, "_wchecktimer: select interrupted");
X				continue;
X			}
X			else {
X#ifdef AMOEBA
X				if (errno != EIO)
X#endif
X				_wwarning(
X				    "_wchecktimer: select failed, errno=%d",
X				    errno);
X			}
X		}
X		if (nfound != 0)
X			break;
X		if (dotimer(ep))
X			return TRUE;
X	}
X	_wdebug(4, "_wchecktimer: returning FALSE");
X	return FALSE;
X}
X
X/* P.S.: It is not necessary to recompute nextalarm when windows are
X   deleted.  This can at most cause a spurious time-out, after which
X   dotimeout() is called again which recomputes nextalarm as a side
X   effect (twice, even).  Applications incur a slight overhead if they
X   delete a window with a timer set and no other windows have timers
X   set; in this case a larger part of the timeout code is called until
X   the alarm goes off (which is then ignored!). */
X
X#endif /* !AMOEBA */
END_OF_FILE
if test 5523 -ne `wc -c <'Ports/x11/timer.c'`; then
    echo shar: \"'Ports/x11/timer.c'\" unpacked with wrong size!
fi
# end of 'Ports/x11/timer.c'
fi
echo shar: End of archive 9 \(of 19\).
cp /dev/null ark9isdone
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