wm - a window manager (part 2 of 4)

sources-request at genrad.UUCP sources-request at genrad.UUCP
Sun Aug 4 00:06:22 AEST 1985


Mod.sources:  Volume 2, Issue 32
Submitted by: Tom Truscott <decvax!mcnc!rti-sel!trt>


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	wm.h
#	cmd.c
#	curses.c
#	getch.c
#	hacks.c
#	help.c
# This archive created: Fri Aug  2 13:13:15 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(2215 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
#
#	Makefile for wm
#

# Flags for the C compiler.
CFLAGS	= -O

# Flags for loader.  You probably do not need any.
LDFLAGS	= 

# Final resting place of wm executable.
BIN	= /usr/local

# Name of owner and group that you want installed wm to have.
OWNER	= bin
GROUP	= bin

# Version of libcurses wm is linked with. This *must* be
# the version that is distributed with wm, since it contains
# several bug fixes necessary to the correct operation of wm.
LIBS	= -lcurses -ltermcap

OBJS = cmd.o curses.o getch.o hacks.o help.o misc.o \
	save.o shell.o vterm.o wlist.o wm.o
XSRCS = cmd.c curses.c getch.c hacks.c help.c misc.c \
	save.c shell.c vterm.c wlist.c wm.c

wm: $(OBJS)
	$(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o wm

$(OBJS): wm.h

lint: 
	lint -hbux $(SRCS)

clean:
	/bin/rm -f *.o wm core *.out

install: wm
	install -o $(OWNER) -g $(GROUP) -s wm $(DESTDIR)/$(BIN)

depend:
	cat </dev/null >x.c
	for i in ${SRCS}; do \
		(echo `basename $$i .c`.o: $$i >>makedep; \
		/bin/grep '^#[ 	]*include' x.c $$i | sed \
			-e 's,<\(.*\)>,"/usr/include/\1",' \
			-e 's/:[^"]*"\([^"]*\)".*/: \1/' \
			-e 's/\.c/.o/' >>makedep); done
	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
	echo '$$r makedep' >>eddep
	echo 'w' >>eddep
	cp Makefile Makefile.bak
	ed - Makefile < eddep
	rm eddep makedep x.c
	echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile
	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
	echo '# see make depend above' >> Makefile

# DO NOT DELETE THIS LINE -- make depend uses it

cmd.o: cmd.c
cmd.o: wm.h
curses.o: curses.c
curses.o: wm.h
getch.o: getch.c
getch.o: wm.h
getch.o: /usr/include/signal.h
getch.o: /usr/include/setjmp.h
getch.o: /usr/include/sys/time.h
hacks.o: hacks.c
hacks.o: wm.h
help.o: help.c
help.o: wm.h
misc.o: misc.c
misc.o: wm.h
save.o: save.c
save.o: wm.h
shell.o: shell.c
shell.o: wm.h
shell.o: /usr/include/signal.h
shell.o: /usr/include/errno.h
vterm.o: vterm.c
vterm.o: wm.h
wlist.o: wlist.c
wlist.o: wm.h
wm.o: wm.c
wm.o: wm.h
wm.o: /usr/include/signal.h
wm.o: /usr/include/sys/wait.h
wm.o: /usr/include/sys/time.h
wm.o: /usr/include/sys/resource.h
# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above
SHAR_EOF
if test 2215 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 2215 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'wm.h'" '(6227 characters)'
if test -f 'wm.h'
then
	echo shar: will not over-write existing file "'wm.h'"
else
sed 's/^X//' << \SHAR_EOF > 'wm.h'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
/*
 * definitions for wm
 */

#include "curses.h"
#include <sys/types.h>
#include <ctype.h>

#define	CURSEASSIST		/* give curses a hand, sigh. */
#define	SET_WINDOW		/* assist all-wonderful scrolling rectangles */
#define	GAGMEKEYPAD		/* gross hack for arrow keys */
/*#define	SNEAKYTERMCAP		/* /tmp termcap kludge */

/* define TERMINFO if we are using a terminfo version of curses */
#ifdef A_STANDOUT
#define	TERMINFO
#endif

#ifdef TERMINFO
/* define FASTTERMINFO if your terminfo has a clever doupdate */
/*#define	FASTTERMINFO	/**/
/* define BUGGYTERMINFO if your terminfo has 'certain bugs' */
#define	BUGGYTERMINFO	/**/
#endif

/*
 * Definitions for curses
 */
#define	wcury(w)	((w)->_cury)	/* current (y,x) in window w */
#define	wcurx(w)	((w)->_curx)
#define	wbegy(w)	((w)->_begy)	/* window offset from origin */
#define	wbegx(w)	((w)->_begx)
#define	wlines(w)	((w)->_maxy)	/* # lines/cols in window w */
#define	wcols(w)	((w)->_maxx)
#define	cursrow()	wcury(curscr)	/* current (y,x) on screen */
#define	curscol()	wcurx(curscr)

/* stuff dependent on the version of curses */
#ifdef TERMINFO
#undef GAGMEKEYPAD
#ifdef FASTTERMINFO
#undef CURSEASSIST
#endif
#undef wlines
#undef wcols
#define	wlines(w)	((w)->_maxy+1)	/* # lines/cols in window w */
#define	wcols(w)	((w)->_maxx+1)
#include <term.h>
/* undefine one of the more annoying definitions in term.h */
#ifdef lines
#undef lines
#endif
extern WINDOW *newscr;
#define	Untouchwin(wp)	untouchwin(wp),untouchwin(newscr)
#ifdef CURSEASSIST
/* curseassist cheats big */
#define	Cmove(y,x)	wmove(curscr,y,x),wmove(newscr,y,x)
#define	Cinsertln()	winsertln(curscr),winsertln(newscr)
#define	Cdeleteln()	wdeleteln(curscr),wdeleteln(newscr)
#endif
#else
extern int *_putchar();
#define	putp			_puts
#define	enter_ca_mode		TI
#define	cursor_address		CM
#define	flash_screen		VB
#define	enter_standout_mode	SO
#define	exit_standout_mode	SE
#define	move_standout_mode	MS
#define	insert_line		AL
#define	delete_line		DL
#define	change_scroll_region	CS
#define	scroll_reverse		SR
#define	save_cursor		SC
#define	restore_cursor		RC
#define	insert_character	IC
#define	insert_null_glitch	IN
#define	enter_insert_mode	IM
#define	exit_insert_mode	EI
#define	delete_character	DC
#define	scroll_forward		NL
#define	cursor_down		DO
#define	cursor_up		UP
#define	Untouchwin(wp)	untouchwin(wp)
#ifdef CURSEASSIST
/* curseassist cheats big */
#define	Cmove(y,x)	wmove(curscr,y,x)
#define	Cinsertln()	winsertln(curscr)
#define	Cdeleteln()	wdeleteln(curscr)
#endif
#endif

/* key pad atrocities follow */
extern char tty_text[], keycap[];
extern int tty_textlen, tty_backcnt;
#ifndef KEY_BACKSPACE
#define	KEY_BACKSPACE	0401
#define	KEY_UP		0402
#define	KEY_DOWN	0403
#define	KEY_LEFT	0404
#define	KEY_RIGHT	0405
#define	KEY_HOME	0406
#endif
#ifndef GAGMEKEYPAD
#define	tty_getch	tty_realgetch
#endif

/*
 * The number of active windows is limited by the number of
 * open files a process (i.e., main) may have,
 * the number of processes a user or the whole system can have,
 * and (on an 11 but not a VAX) the memory for the per-window curses buffers.
 * Also, window names are limited to 0..9, i.e. at most 10 windows.
 */
#define	MAXWINDOWS	10	/* windows #0..#9 */

#define	ESC		'\033'	/* char for virtual terminal functions */
#define	CANCEL1		'\033'	/* char to cancel wm command */
#define	CANCEL2		'\177'	/* char to cancel wm command */

#define	MINWINDOW	1	/* change this to 0 to permit window #0 */
#define	iswindow(w) ((w)>=MINWINDOW && (w)<MAXWINDOWS && (win[w].flags&INUSE))
#define	ctoi(c)		((c)-'0')	/* convert ascii digit to int */
#define	itoc(i)		((i)+'0')	/* convert int to ascii digit */

/*
 * Global data with miscellaneous information about each window
 */
struct win_struct
{
    int flags;			/* window status bits */
#define	INUSE	001	/* window is in use */
#define	XFLEX	002	/* # of columns is COLS (depends on terminal type) */
#define	YFLEX	004	/* # of rows    is ROWS ( ""     ""    ""     "" ) */
#define	FAST	010	/* window can scroll 'quickly' (not redrawn) */
#define	BROWSE	020	/* window is in 'browse' mode */
#define	BLOCKED	040	/* window updates are being delayed */
    int next;			/* next window in list */
    char covers[MAXWINDOWS];	/* TRUE for windows we're on top of */
    WINDOW *wptr;		/* ptr to small curses win to be displayed */
    WINDOW *boxbot, *boxtop;	/* ptrs to curses wins for box, or NULL */
    WINDOW *boxright, *boxleft;	/* ptrs to curses wins for box, or NULL */
    char pend[4];		/* characters in partial escape sequence */
    int pid;			/* pid of this window's shell */
    int pty;			/* fildes of pty to/from this win's shell */
};

/*
 * Handy macros
 */
#define	MAX(a,b)	((a)>=(b)? (a): (b))
#define	MIN(a,b)	((a)<=(b)? (a): (b))

/*
 * External variables.
 */
extern struct win_struct win[];	/* array of windows */
extern int botw, topw, lastw;	/* bottom, top, last window */
extern int prefix;		/* WM command prefix character */
extern char savefile[];		/* name of save/restore file */
extern char shellname[];	/* name of shell */
extern char shellpgm[];		/* pathname of shell */
extern int configflag;		/* true if window config. has changed */
extern time_t msgbirth;		/* time last message was displayed */
#ifndef TERMINFO
extern char *change_scroll_region, *save_cursor, *restore_cursor;
extern char *set_window;
#endif
extern int has_scroll_window, has_scroll_region, has_insdel_line;

/*
 * Functions returning a non-int value
 */
XFILE *fopen();
char *sprintf(), *strcpy(), *strcat(), *rindex(), *getenv();
char *mkprint(), *termcap(), *WPrompt(), *plural();
double *Malloc();	/* if only malloc were declared this way */

#define	alloc(n,type)	((type*)Malloc((unsigned)((n)*sizeof(type))))
SHAR_EOF
if test 6227 -ne "`wc -c < 'wm.h'`"
then
	echo shar: error transmitting "'wm.h'" '(should have been 6227 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'cmd.c'" '(7983 characters)'
if test -f 'cmd.c'
then
	echo shar: will not over-write existing file "'cmd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'cmd.c'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
/*
 * Command interpreter for WM.
 */

#include "wm.h"

/*
 * Command definitions
 */
# define DUMPWINDOW	'd'	/* dump contents of current window to file */
# define FITWINDOW	'f'	/* Find best unobscured place for a window */
# define HELP2		'h'	/* Command summary */
# define HELP1		'?'	/* Command summary */
# define IDENTWINDOW	'i'	/* print name of current window */
# define KILLWINDOW	'k'	/* get rid of this window forever */
# define LASTWINDOW	'l'	/* change to Last-used window */
# define MOVEWINDOW	'm'	/* Move locn and/or change size of window */
# define NEWWINDOW	'n'	/* make New window */
# define PREFIX		'p'	/* change prefix character */
# define QUIT		'q'	/* close up everything and Quit */
# define REDRAW		'r'	/* Redraw all windows */
# define SAVEWINDOWS	's'	/* save current window configuration */
# define TERMCAP	't'	/* Reset $TERM and $TERMCAP of current window */
# define SUSPEND	'z'	/* suspend wm */
# define NOOP1		' '	/* no-op */
# define NOOP2		'\n'	/* no-op */
# define NOOP3		'\r'	/* no-op */


/*
 * Execute a WM command.
 */
docmd(cmd)

int cmd;	/* IN: command code */
{
    register int w, tmpw;
    int begline, begcol, lines, cols;	/* window parameters */
    char *s;
    register WINDOW *wp;


    switch (cmd)
    {
    case CANCEL1:
    case CANCEL2:
	showmsg("Canceled.");
	break;

    case NEWWINDOW:
	tmpw = topw;
	if ((w = GetSlot()) < 0) {
	    showmsg("Sorry, can't create any more windows.");
	    break;
	}
	if (NewWindow(w,LINES-1,COLS,0,0))
	    break;
	WListAdd(w);
	if (getbounds(w, TRUE) != 0)
	    break;	/* getbounds will have freed the window */
	lastw = tmpw;
	showmsg("Created new window #%d.", w);
	winchanged(w);
	break;

    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
	w = ctoi(cmd);
	if ( ! iswindow(w))
	    showmsg("No such window #%d.", w);
	else if (w == topw)
	    showmsg("You're already in window #%d.", w);
	else
	{
	    lastw = topw;
	    WListDelete(w);
	    WListAdd(w);
	    RedrawScreen();
	    showmsg("Changed to window #%d.", w);
	}
	break;

    case LASTWINDOW:
	if (iswindow(lastw) && lastw!=topw)
	{
	    w=lastw;
	    lastw=topw;
	    WListDelete(w);
	    WListAdd(w);
	    RedrawScreen();
	    showmsg("Changed back to window #%d.", w);
	}
	else
	    showmsg("No last window.");
	break;

    case MOVEWINDOW:
	w = topw;
	wp = win[w].wptr;
	lines = wlines(wp); cols = wcols(wp);
	begline = wbegy(wp); begcol = wbegx(wp);
	if (getbounds(w, FALSE) != 0)
	    break;
	wp = win[w].wptr;
	if (lines == wlines(wp) && cols == wcols(wp)) {
	    if (begline == wbegy(wp) && begcol == wbegx(wp)) {
		showmsg("Window unchanged.");
		break;
	    }
	}
	else
	    SetTerm(w, 2);
	showmsg("Moved window #%d.", w);
	winchanged(w);
	break;

    case FITWINDOW:
	showmsg("Fit which window?");
	if ((w = askwindow()) < 0)
	    break;
	if (fitwindow(w, &lines, &cols, &begline, &begcol) < 0) {
	    showmsg("Sorry, cannot find unobscured placement.");
	    break;
	}
	wp = win[w].wptr;
	tmpw = 1;	/* shameless misuse of variable */
	if (lines == wlines(wp) && cols == wcols(wp)) {
	    tmpw = 0;
	    if (begline == wbegy(wp) && begcol == wbegx(wp)) {
		showmsg("Window already has best fit.");
		break;
	    }
	}
	if (NewWindow(w,lines,cols,begline,begcol)) {
	    WListDelete(w);
	    break;
	}
	if (tmpw)
	    SetTerm(w, 2);
	RedrawScreen();
	showmsg("Moved window #%d.", w);
	winchanged(w);
	break;

    case KILLWINDOW:
	showmsg("Kill which window?"); /* enter window name */
	if ((w = askwindow())  < 0)
	    break;
	if (w==topw)
	{
	    showmsg("Can't kill the current window.");
	    break;
	}
	WListDelete(w); KillShell(w); FreeWindow(w);
	RedrawScreen();
	showmsg("Killed window #%d.", w);
	if (w==lastw) lastw = -1;
	configflag = TRUE;
	break;

    case IDENTWINDOW:
	IdentWindows();
	break;

    case DUMPWINDOW:
	if ((s = WPrompt("dump file", "wmdump")) == NULL)
	    break;
	else if (DumpWindow(topw, s) == 0)
	    showmsg("Dumped contents of top window to file '%s'.", s);
	else
	    showmsg("Sorry, can't open dump file '%s'.", s);
	break;

    case REDRAW:
	ClearScreen();
	RedrawScreen();
	break;

    case TERMCAP:
	SetTerm(topw, 3);
	break;

    case HELP1:
    case HELP2:
	ClearScreen();
	helpmsg();
	(void) tty_getch();
	ClearScreen();
	RedrawScreen();
	break;

    case PREFIX:
	showmsg("Enter new WM prefix character.");
	prefix = tty_getch();
	showmsg("New WM prefix character is '%s'.", mkprint(prefix));
	configflag = TRUE;
	break;

    case SUSPEND:
	suspend();
	break;

    case SAVEWINDOWS:
	if ((s = WPrompt("save file", savefile))  == NULL)
	    break;
	(void) strcpy(savefile, s);
	if (Save(savefile) != 0)
	{
	    showmsg("Saved current window configuration in '%s'.", savefile);
	    configflag = FALSE;
	}
	else showmsg("Sorry, can't save current window configuration.");
	break;

    case QUIT:
	return(TRUE);

    case NOOP1:
    case NOOP2:
    case NOOP3:
	break;

    default:
	showmsg("Invalid command '%s': use 'h' command for help.",mkprint(cmd));
	break;
    }

    return(FALSE);
}

/*
 * suspend w/ job control if using csh, otherwise spawn subshell.
 * This could be integrated into curses tstp(),
 * but I wasn't sure that could be done correctly,
 * since it is impossible(?) to determine if the parent shell
 * knows job control.
 */
suspend()
{
    register int rc;
#ifndef TERMINFO
    register int ttyflags;
#endif

    /* If wm's parent is init, then we better not suspend with TSTP!
     * Unfortunately, this heuristic fails if the user used rlogin,
     * since wm's parent would then be rlogind.  We can only hope
     * the user knows what he is doing.
     */
    if (getppid() != 1
     && (rc = strlen(shellname)) >= 3
     && strcmp(shellname+rc-3, "csh") == 0) {
	showmsg("Suspending.");
	tstp();
	showmsg("WM resumed.");
	return;
    }

    showmsg("Spawning a sub-shell ...");
    (void) movecursor(LINES-1, 0);
#ifndef TERMINFO
    ttyflags = _tty.sg_flags;
#endif
    endwin();
    putchar('\n');	/* scroll up, for neatness */
    (void) fflush(stdout);

    rc = system(shellpgm);
#ifdef TERMINFO
#ifdef BUGGYTERMINFO
    /* Alas, buggyterminfo apparently does not re-remember the virgin state
     * or correct for a baud-rate change */
#endif
    fixterm();
#else
    savetty();	/* re-remember the virgin state */
    _tty.sg_flags = ttyflags;
    (void) ioctl(_tty_ch, TIOCSETN, (char *)&_tty);
#endif
    if (enter_ca_mode)
	putp(enter_ca_mode);
    wrefresh(curscr);
    /* we could diagnose things better here */
    if (rc == 127)
	showmsg("Cannot spawn a shell!");
    else
	showmsg("Returning to WM.");
}

/*
 * Set 'configflag' to indicate change affecting wmrc file.
 * If this window is full-width or full-length,
 * set the corresponding 'flex' flag.
 * Warn user if this is a 'slow' window.
 */
winchanged(w)
register int w;
{
    register WINDOW *wp;
    static int full_width_warning = FALSE;

    configflag = TRUE;
    win[w].flags &= ~(XFLEX|YFLEX);
    wp = win[w].wptr;
    if (wcols(wp) == COLS)
	win[w].flags |= XFLEX;
    if (wlines(wp) == LINES-1)
	win[w].flags |= YFLEX;
    WObscure();		/* recompute obscured window info */
    if (!(win[w].flags&FAST)) {
	if (wcols(wp) != COLS) {
	    showmsg("\007Non full-width window #%d will scroll slowly!", w);
	    return;
	}
	if (full_width_warning)
	    return;
	full_width_warning = TRUE;
	showmsg("\007This terminal scrolls split-screen windows slowly.");
    }
}
SHAR_EOF
if test 7983 -ne "`wc -c < 'cmd.c'`"
then
	echo shar: error transmitting "'cmd.c'" '(should have been 7983 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'curses.c'" '(11058 characters)'
if test -f 'curses.c'
then
	echo shar: will not over-write existing file "'curses.c'"
else
sed 's/^X//' << \SHAR_EOF > 'curses.c'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
/*
 * curses.c  R. Jacob
 */

#include "wm.h"

static WINDOW *mw=NULL;		/* message window */
static WINDOW *cmw=NULL;	/* blank message window */
time_t msgbirth = 0;


/*
 * Set up win structure and associated junk for new window w.
 * Returns 0 if sucessful, else -1.
 */
NewWindow(w, lines, cols, begline, begcol)

register int w;
int lines, cols, begline, begcol;
{
    register WINDOW *wp, *owp;


    if ((wp=newwin(lines,cols,begline,begcol)) == NULL) {
	showmsg("\007Cannot %sconstruct window #%d!.",
	    ((win[w].flags&INUSE)? "re": ""), w);
	FreeWindow(w);
	return(-1);
    }
    leaveok(wp, TRUE);

    /* If the window is already in use, copy old window to new one
     * anchored at bottom left of the windows.
     * We move the bottom left of both windows to the bottom left
     * of the screen, overwrite, then move the windows back.
     * (Actually, we do not bother to move the old window back.)
     */
    if (win[w].flags&INUSE) {
	owp = win[w].wptr;
	mvwin(owp, LINES-wlines(owp), 0);
	mvwin(wp, LINES-wlines(wp), 0);
	overwrite(owp, wp);
	mvwin(wp, begline, begcol);
	wmove(wp, wcury(owp) + (wlines(wp)-wlines(owp)), wcurx(owp));
	FreeWindow(w);
    }

    win[w].wptr = wp;

    if (MakeBorders(w) != 0)
    {
	showmsg("\007Cannot construct borders for window #%d!.", w);
	FreeWindow(w);
	return(-1);
    }

    win[w].flags |= INUSE;
    if (has_scroll_window
     || (cols == COLS
      && (has_scroll_region || has_insdel_line || lines == LINES-1)))
	win[w].flags |= FAST;

    return(0);
}

/*
 * Deallocate win structure and associated junk.
 */
XFreeWindow(w)

register int w;
{
    win[w].flags = 0;

    if (win[w].wptr)	 {delwin(win[w].wptr);     win[w].wptr = 0;}
    if (win[w].boxbot)	 {delwin(win[w].boxbot);   win[w].boxbot = 0;}
    if (win[w].boxtop)	 {delwin(win[w].boxtop);   win[w].boxtop = 0;}
    if (win[w].boxright) {delwin(win[w].boxright); win[w].boxright = 0;}
    if (win[w].boxleft)	 {delwin(win[w].boxleft);  win[w].boxleft = 0;}
}

#ifdef notdef
/*
 * Redraw window w.
 */
RedrawWindow(w)

register int w;
{
    register WINDOW *wp;

    if (!iswindow(w))
	return;
    if (wp=win[w].wptr)     { touchwin(wp); wrefresh(wp); }
    if (wp=win[w].boxbot)   { touchwin(wp); wrefresh(wp); }
    if (wp=win[w].boxtop)   { touchwin(wp); wrefresh(wp); }
    if (wp=win[w].boxright) { touchwin(wp); wrefresh(wp); }
    if (wp=win[w].boxleft)  { touchwin(wp); wrefresh(wp); }
}
#endif

/*
 * Redraw the entire screen.
 * Uses Curses' standard screen, stdscr.
 */
RedrawScreen()
{
    register int w, base;
    register WINDOW *wp;

    /* speed hack: start with the topmost full-screen window.
     * (Smarter hacks come to mind, but this one is easy.)
     */
    base = botw;
    for (w=base; w>=0; w=win[w].next)
	if ((wp = win[w].wptr) && wcols(wp) == COLS && wlines(wp) >= LINES-1)
	    base = w;

    werase(stdscr);

     /* Write contents of all windows into stdscr, then refresh.
      */
    for (w=base; w>=0; w=win[w].next)
    {
	if (wp=win[w].wptr)     overwrite(wp, stdscr);
	if (wp=win[w].boxtop)   overwrite(wp, stdscr);
	if (wp=win[w].boxbot)   overwrite(wp, stdscr);
	if (wp=win[w].boxright) overwrite(wp, stdscr);
	if (wp=win[w].boxleft)  overwrite(wp, stdscr);
    }

    if (msgbirth)
	overwrite(mw, stdscr);
    touchwin(stdscr);
    wrefresh(stdscr);
    RestoreCursor();
}

/*
 * Identify windows.
 * Draw each window in turn, from bottom to top.
 * Uses Curses' standard screen, stdscr.
 */
IdentWindows()
{
    register int w;	/* window index */
    register WINDOW *wp;
    register int canceled=FALSE; /* TRUE if user cancels this command */
    register int c;


     /* Erase the screen (and stdscr).
      */
    ClearScreen();

     /* Write contents of each window into stdscr, then refresh.
      */
    for (w=botw; w>=0; w=win[w].next)
    {
	if (wp=win[w].wptr)     overwrite(wp, stdscr);
	if (wp=win[w].boxtop)   overwrite(wp, stdscr);
	if (wp=win[w].boxbot)   overwrite(wp, stdscr);
	if (wp=win[w].boxright) overwrite(wp, stdscr);
	if (wp=win[w].boxleft)  overwrite(wp, stdscr);

	if (canceled)
	    continue;

#ifdef BUGGYTERMINFO
	/* buggyterminfo seems to require this */
	touchwin(stdscr);
#endif
	wrefresh(stdscr);

	if (w != topw)
	{
	    showmsg("Window #%d.  Hit any key to see next window.", w);
	    c = tty_getch();
	    if (c == CANCEL1  ||  c == CANCEL2)
	    {
		showmsg("Canceled.");
		canceled = TRUE;
	    }
	}

	else
	{
	    showmsg("Window #%d (top window).  Hit any key to continue.", w);
	    (void) tty_getch();
	}
    }

    if (canceled)
	wrefresh(stdscr);
    RestoreMsg();
    RestoreCursor();
}

/*
 * Show message s on bottom of screen.
 */
/*VARARGS1*/
showmsg(s, arg1, arg2)

register char *s;
{
    char buf[256];

     /* Initialize message window first time 'round.
      */
    if (mw == NULL) {
	mw=newwin(1, 0, LINES-1, 0);
	cmw=newwin(1, 0, LINES-1, 0);
	if (!mw || !cmw) {
	    fprintf(stderr, "Cannot create message window!\n\r");
	    Shutdown(1);
	}
	leaveok(cmw, TRUE);
	werase(cmw);
	/* (leaveok for mw & cursor positioning for prompts needs thought) */
	wstandout(mw);
    }

#ifdef notdef
    /* pause to let user ponder a previous message */
    if (msgbirth && *s && (t = 2-abs(msgbirth - time((time_t *)0))) > 0)
	sleep((unsigned int)t);
#endif

    /* Format the message */
    (void) sprintf(buf, s, arg1, arg2);
    s = buf;
    s[wcols(mw)-1] = '\0';		/* make sure it fits */

    /* hack to honk but once */
    if (*s == '\007') {
	flash();
	s++;
    }
    werase(mw);
    waddstr(mw, s);
    touchwin(mw);
    wrefresh(mw);

    msgbirth = s[0]? time((time_t *)0): 0;
}

ZapMsgLine()
{
    if (msgbirth) {
	touchwin(cmw);
	wrefresh(cmw);
    }
}

RestoreMsg()
{
    if (msgbirth) {
	touchwin(mw);
	wrefresh(mw);
    }
}

/*
 * Restore cursor in top window.
 */
RestoreCursor()
{
    register WINDOW *wp;	/* pointer to top window */

    wp = win[topw].wptr;
    if (movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp)))
	(void) fflush(stdout);
}

/*
 * Clear the whole screen
 */
ClearScreen()
{
    wclear(stdscr);
    wrefresh(stdscr);
}

/*
 * Creates windows containing
 * a border to surround window w
 * and puts pointer to the new windows
 * into proper places in global win[].
 * Borders appear in standout mode if
 * terminal has that capability.
 * Returns 0 if sucessful, else -1.
 */
MakeBorders(w)

register int w;		/* make borders for this window */
{
    int left, right, top, bottom;	/* border flags */
    int begx, begy, cols, lines;	/* window dimensions */
    register WINDOW *wp;		/* window pointer */
    register int i;			/* index */


     /* Get window dimensions.
      */
    wp = win[w].wptr;
    begx =  wbegx(wp);
    begy =  wbegy(wp);
    cols =  wcols(wp);
    lines = wlines(wp);


     /* Determine which sides of the window need borders.
      */
    left   = (begx > 0);
    right  = (begx+cols < COLS);
    top    = (begy > 0);
    bottom = (begy+lines < LINES-1); /* bottom line for msgs */

    if (top)
	--begy, ++lines;
    if (bottom)
	lines++;
    

     /* Make left border using '>'.
      */
    if (left)
    {
	if ((win[w].boxleft = wp = newwin(lines,1,begy,begx-1))  == NULL)
	    return(-1);
	leaveok(wp, TRUE);
	wstandout(wp);
	for (i=0; i<lines; i++)
	    waddch(wp, '>');
    }
    

     /* Make right border using '<'.
      */
    if (right)
    {
	if ((win[w].boxright = wp = newwin(lines,1,begy,begx+cols))  == NULL)
	    return(-1);
	leaveok(wp, TRUE);
	wstandout(wp);
	for (i=0; i<lines; i++)
	    waddch(wp, '<');
    }


     /* Make top border using window number.
      */
    if (top)
    {
	if ((win[w].boxtop = wp = newwin(1,cols,begy,begx))  == NULL)
	    return(-1);
	leaveok(wp, TRUE);
	wstandout(wp);
	for (i=0; i<cols; i++)
	    waddch(wp, itoc(w));
    }


     /* Make bottom border using window number.
      */
    if (bottom)
    {
	if ((win[w].boxbot = wp = newwin(1,cols,begy+lines-1,begx))  == NULL)
	    return(-1);
	leaveok(wp, TRUE);
	wstandout(wp);
	for (i=0; i<cols; i++)
	    waddch(wp, itoc(w));
    }

    return(0);
}

/*
 * Dump.
 * Dump the contents of the current window to file 'wmdump'
 * in the current directory.
 * Returns 0 on sucessful completion, -1 otherwise.
 */
DumpWindow(w, dumpfile)

int w;		/* number of window we're to dump */
char *dumpfile;	/* file we're dumping to */
{
    register WINDOW *wp;	/* top window */
    register FILE *dfp;		/* dump file pointer */
    register int line, col;	/* current line, column of window */
    register int lastcol;	/* column of rightmost non-blank */
    int oldy, oldx;		/* saved cursor position */

    if ((dfp = fopen(dumpfile, "w"))  == NULL)
	return(-1);

    wp = win[w].wptr;
    getyx(wp, oldy, oldx);
    for (line = 0; line < wlines(wp); line++)
    {
	lastcol = wcols(wp);
	while (--lastcol >= 0)
	    if (toascii(mvwinch(wp, line, lastcol)) != ' ')
		break;
	for (col = 0; col <= lastcol; col++)
	    putc(toascii(mvwinch(wp, line, col)),  dfp);
	putc('\n', dfp);
    }
    (void) fclose(dfp);
    wmove(wp, oldy, oldx);
    return(0);
}

#define BUFLEN		80

/* Prompt user for a string.
 */
char *
WPrompt(prompt, dflt)

char *prompt;	/* prompt */
char *dflt;	/* default response */
{
    register int c;		/* character in string */
    static char buf[BUFLEN+1];	/* string buffer */
    register int i=0;		/* buffer index */
    int maxlen, x;		/* how long can string be? */

     /* Print prompt and default response
      * on bottom line of screen.
      */
    showmsg("%s? [%s] ", prompt, dflt);

     /* Determine length of longest string
      * that will fit in window.
      */
    x = wcurx(mw);
    maxlen = (BUFLEN < wcols(mw)-2-x  ?  BUFLEN  :  wcols(mw)-2-x);


     /* Read string. Process line kill & backspace chars.
      */
    while ((c = tty_getch()) != EOF && c != '\n' && c != '\r')
    {
	if (c==CANCEL1 || c==CANCEL2)	/* cancel */
	{
	    showmsg("Canceled.");
	    return(NULL);
	}
	if (c==erasechar() || c == KEY_BACKSPACE || c == KEY_LEFT)
	{
	    if (i > 0)
	    {
		i--;
		waddstr(mw, "\b \b");
	    }
	}
	else if (c == killchar())
	{
	    i = 0;
	    wmove(mw, 0, x);
	    wclrtoeol(mw);
	}
	else if (i > maxlen)		/* is string too long? */
	    flash();
	else if (isspace(c) || !isprint(c)) /* is character inappropriate? */
	    flash();
	else				/* regular char: add to string */
	{
	    waddch(mw, c);
	    buf[i++] = c;
	}

	wrefresh(mw);
    }


     /* If user didn't respond, just return default response.
      */
    if (i == 0)
	strcpy(buf, dflt);
    else
	buf[i] = '\0';


    return(buf);
}
SHAR_EOF
if test 11058 -ne "`wc -c < 'curses.c'`"
then
	echo shar: error transmitting "'curses.c'" '(should have been 11058 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getch.c'" '(6283 characters)'
if test -f 'getch.c'
then
	echo shar: will not over-write existing file "'getch.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getch.c'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
#include "wm.h"
#include <signal.h>

char keycap[200];	/* termcap entries for keypad functions */

int tty_backcnt;	/* number of pre-read terminal chars */
char tty_backbuf[10];	/* stack of pre-read chars */
char tty_text[10];	/* actual text corresponding to tty_getch code */
int tty_textlen;	/* strlen(tty_text) */

/*
 * Returns true iff a call to tty_realgetch would not block.
 */
tty_inputpending()
{
    long n;

    if (tty_backcnt > 0)
	return(TRUE);
    if (ioctl(0, (int)FIONREAD, (char *)&n) == 0 && n > 0)
	return(TRUE);
    return(FALSE);
}

/*
 * Read the next character from the terminal (or the backbuf),
 * return EOF if end of file, else (int)the_char, sans parity
 */
int
tty_realgetch()
{
    char c;

    if (tty_backcnt > 0)
	c = tty_backbuf[--tty_backcnt];
    else if (read(0, &c, 1) <= 0) {
	tty_text[0] = '\0';
	tty_textlen = 0;
	return(EOF);
    }
    c = toascii(c);
    tty_text[0] = c;
    tty_text[1] = '\0';
    tty_textlen = 1;
    return(c);
}

#ifdef GAGMEKEYPAD
init_keypad()
{
	register int i;
	register char *p;
	char buf1[10];

	if (p = getcap("ks"))
		putp(p);
	for (i=1,p = "kbkukdklkrkhk0k1k2k3k4k5k6k7k8k9"; *p; i++,p+= 2) {
	    (void) sprintf(buf1, "%2.2s", p);
	    add_to_try(buf1, i+0400);
	}
}

/*
**      add_to_try() (Copyright Pavel Curtis, see notice in hacks.c)
**
**      Construct the try for the current terminal's keypad keys.
**
*/
struct try
{
	struct try      *child;     /* ptr to child.  NULL if none          */
	struct try      *sibling;   /* ptr to sibling.  NULL if none        */
	char            ch;         /* character at this node               */
	short           value;      /* code of string so far.  NULL if none */
};

static struct  try *newtry;

add_to_try(capname, code)
char    *capname;
int code;
{
	register struct try *ptr, *savedptr;
	register char *str, *s;
	static bool     out_of_memory = FALSE;

	str = getcap(capname);
	if (! str  ||  out_of_memory)
	    return;
	strcat(keycap, capname); strcat(keycap, "=");
	for (s = str; *s; s++) {
	    strcat(keycap, mkprint(*s));
	}
	strcat(keycap, ":");
	
	if (newtry != NULL)    
	{
	    ptr = newtry;
	    
	    for (;;)
	    {
		while (ptr->ch != *str  &&  ptr->sibling != NULL)
		    ptr = ptr->sibling;
	    
		if (ptr->ch == *str)
		{
		    if (*(++str))
		    {
			if (ptr->child != NULL)
			    ptr = ptr->child;
			else
			    break;
		    }
		    else
		    {
			ptr->value = code;
			return;
		    }
		}
		else
		{
		    if ((ptr->sibling = alloc(1, struct try)) == NULL)
		    {
			out_of_memory = TRUE;
			return;
		    }
		    
		    savedptr = ptr = ptr->sibling;
		    ptr->child = ptr->sibling = NULL;
		    ptr->ch = *str++;
		    ptr->value = NULL;
		    
		    break;
		}
	    } /* end for (;;) */  
	}
	else    /* newtry == NULL :: First sequence to be added */
	{
	    savedptr = ptr = newtry = alloc(1, struct try);
	    
	    if (ptr == NULL)
	    {
		out_of_memory = TRUE;
		return;
	    }
	    
	    ptr->child = ptr->sibling = NULL;
	    ptr->ch = *(str++);
	    ptr->value = NULL;
	}
	
	    /* at this point, we are adding to the try.  ptr->child == NULL */
	    
	while (*str)
	{
	    ptr->child = alloc(1, struct try);
	    
	    ptr = ptr->child;
	    
	    if (ptr == NULL)
	    {
		out_of_memory = TRUE;
		
		ptr = savedptr;
		while (ptr != NULL) 
		{
		    savedptr = ptr->child;
		    free((char *)ptr);
		    ptr = savedptr;
		}
		
		return;
	    }
	    
	    ptr->child = ptr->sibling = NULL;
	    ptr->ch = *(str++);
	    ptr->value = NULL;
	}
	
	ptr->value = code;
	return;
}

#include <setjmp.h>
static jmp_buf jmpbuf;

/*
**      tty_getch() (Copyright Pavel Curtis, see notice in hacks.c)
**
**      Get an input character, but take care of keypad sequences, returning
**      an appropriate code when one matches the input.  After each character
**      is received, set an alarm call.  If no more of the sequence
**      is received by the time the alarm goes off, pass through the sequence
**      gotten so far.
**
*/
tty_getch()
{
	/* longjmp alert!  beware of register variables */
	register struct try  *ptr;
	int        ch;
	char        buffer[10];     /* Assume no sequences longer than 10 */
	char *bufp = buffer;
	int         (*oldsigalrm)();
	int         sigalrm();
	bool    alarmset;

	ptr = newtry;
	alarmset = FALSE;
	oldsigalrm = SIG_DFL;	/* to quiet lint */
	
	do
	{
	    if (setjmp(jmpbuf))
		break;
	    ch = tty_realgetch();
	    if (ch != EOF)              /* returns EOF on error, too */
		*(bufp++) = ch;
	    
	    while (ptr != NULL  &&  ptr->ch != ch)
		ptr = ptr->sibling;
	    
	    if (ptr != NULL)
	    {
		if (ptr->value != NULL)
		{
		    if (alarmset) {
			(void) ualarm(0L);
			(void) signal(SIGALRM, oldsigalrm);
		    }
		    tty_textlen = bufp-buffer;
		    bcopy(buffer, tty_text, tty_textlen);
		    return(ptr->value);
		}
		else
		{
		    ptr = ptr->child;
		    if (!alarmset) {
			alarmset = TRUE;
			oldsigalrm = signal(SIGALRM, sigalrm);
		    }
		    (void) ualarm(200000L);
		}
	    }
	    
	} while (ptr != NULL);
	
	if (alarmset) {
	    (void) ualarm(0L);
	    (void) signal(SIGALRM, oldsigalrm);
	}
	
	if (bufp <= buffer)
	    return(EOF);
	while (--bufp > buffer)
	    tty_backbuf[tty_backcnt++] = *bufp;
	return(*bufp);
}

static
sigalrm()
{
	longjmp(jmpbuf, 1);
}

/*
 * ualarm(usec).  If this doesn't compile, just use alarm(0) and alarm(1).
 */
#include <sys/time.h>

#define	MILLION	1000000L

ualarm(usecs)
	long usecs;
{
	struct itimerval it, oitv;
	register struct itimerval *itp = ⁢

	timerclear(&itp->it_interval);
	itp->it_value.tv_sec = usecs/MILLION;
	itp->it_value.tv_usec = usecs%MILLION;
	if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
		return (-1);
	return (oitv.it_value.tv_sec*MILLION+oitv.it_value.tv_usec);
}
#endif
SHAR_EOF
if test 6283 -ne "`wc -c < 'getch.c'`"
then
	echo shar: error transmitting "'getch.c'" '(should have been 6283 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hacks.c'" '(11742 characters)'
if test -f 'hacks.c'
then
	echo shar: will not over-write existing file "'hacks.c'"
else
sed 's/^X//' << \SHAR_EOF > 'hacks.c'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
/*
 * hacks.c
 * curses-package routines missing in one version or another,
 * or corrections for routines in one version or another,
 * or whatever.
 */
#include "wm.h"

/*
 * Special redefinitions.  We get right into the dirt here.
 */
#ifndef TERMINFO
#define	_line		_y
#define	chtype		char
#define	_firstchar	_firstch
#define	_lastchar	_lastch
#endif

/*
 * Move physical cursor to (y,x).
 * If y is past the end of the screen, scroll the screen up.
 * This is an ugly routine in either version of curses,
 * perhaps because no one worried about this sort of thing.
 * (It would be nice to be able to request 'anywhere on line y',
 * or 'anywhere in column x', since more optimizations are then possible.)
 */
movecursor(y,x)
register int y, x;
{
    if (cursrow() == y && curscol() == x)
	return(0);
#ifdef TERMINFO
    if (y >= LINES) {
	(void) movecursor(y-1,x);
	vidattr(A_NORMAL);
	putp(scroll_forward);
	return(1);
    }
    Untouchwin(stdscr);
    leaveok(stdscr, FALSE);
    wmove(stdscr, y, x);
    wrefresh(stdscr);
    leaveok(stdscr, TRUE);
#else
    /* Couldn't mvcur handle the move_standout_mode problem? */
    if ((curscr->_flags&_STANDOUT) && !move_standout_mode) {
	putp(exit_standout_mode);
	curscr->_flags &= ~_STANDOUT;
    }
    /* speed hack: short circuit mvcur for simple scrolling */
    if (y == LINES && curscol() == x && cursrow()+2 == y && cursor_down) {
	putp(cursor_down);
	putp(scroll_forward);
    }
    else
	mvcur(cursrow(), curscol(), y, x);
    /* Couldn't mvcur update curscr's current (y,x) coordinate? */
    if (y >= LINES)
	y = LINES-1;
    cursrow() = y; curscol() = x;
#endif
    return(1);
}

/*
 * Make it appear that every location on the window is unchanged.
 */
untouchwin(wp)
register WINDOW *wp;
{
    register int i;

    for (i=0; i<wlines(wp); i++) {
	wp->_firstchar[i] = _NOCHANGE;
#ifdef TERMINFO
	wp->_lastchar[i] = _NOCHANGE;
	wp->_numchngd[i] = 0;
#endif
    }
}

/*
 * This is a replacement overwrite() routine for both curses versions.
 * The termcap version is slow and has some minor bugs.
 * The terminfo version aligns the two windows at their origins,
 * rather than on the virtual screen, making it less useful
 * as one cannot use 'mvwin' &etc to paint one window at an
 * arbitrary place on another.
 * Neither version documents what is done with 'standout' information.
 * This version copies the standout information for each character
 * so that a truly identical copy is made, which is handy for painting.
 */
/*********************************************************************
*                         COPYRIGHT NOTICE                           *
**********************************************************************
*        This software is copyright (C) 1982 by Pavel Curtis         *
*                                                                    *
*        Permission is granted to reproduce and distribute           *
*        this file by any means so long as no fee is charged         *
*        above a nominal handling fee and so long as this            *
*        notice is always included in the copies.                    *
*                                                                    *
*        Other rights are reserved except as explicitly granted      *
*        by written permission of the author.                        *
*                Pavel Curtis                                        *
*                Computer Science Dept.                              *
*                405 Upson Hall                                      *
*                Cornell University                                  *
*                Ithaca, NY 14853                                    *
*                                                                    *
*                Ph- (607) 256-4934                                  *
*                                                                    *
*                Pavel.Cornell at Udel-Relay   (ARPAnet)                *
*                decvax!cornell!pavel       (UUCPnet)                *
*********************************************************************/

/*
**
**	overwrite(win1, win2)
**
**
**	overwrite() writes win1 on win2 destructively.
**
**/

overwrite(win1, win2)
WINDOW	*win1, *win2;
{
	register chtype	*w1ptr, *w2ptr;
	register int col, end_col;
	int line, offset_line, offset_col, start_line, start_col, end_line;
	short   *firstchar, *lastchar;

#ifdef TRACE
	if (_tracing)
	    _tracef("overwrite(%o, %o) called", win1, win2);
#endif
	
	offset_line = wbegy(win1) - wbegy(win2);
	offset_col = wbegx(win1) - wbegx(win2);
	start_line = MAX(offset_line, 0);
	start_col = MAX(offset_col, 0);
	end_line = offset_line + wlines(win1) - wlines(win2);
	end_line = wlines(win2) + MIN(end_line, 0);
	end_col = offset_col + wcols(win1) - wcols(win2);
	end_col = wcols(win2) + MIN(end_col, 0);
	firstchar = &win2->_firstchar[start_line];
	lastchar = &win2->_lastchar[start_line];

	for(line = start_line;  line < end_line;  line++)
	{
	    short   fc, lc;
	    
	    w1ptr = &win1->_line[line-offset_line][start_col-offset_col];
	    w2ptr = &win2->_line[line][start_col];
	    fc = lc = _NOCHANGE;

	    for(col = start_col;  col < end_col;  col++)
	    {
		if (*w1ptr != *w2ptr)
		{
		    *w2ptr = *w1ptr;
		    if (fc == _NOCHANGE)
			fc = col;
		    lc = col;
		}

		w1ptr++;
		w2ptr++;
	    }

	    if (*firstchar == _NOCHANGE)
	    {
		*firstchar = fc;
		*lastchar = lc;
	    }
	    else if (fc != _NOCHANGE)
	    {
		if (fc < *firstchar)
		    *firstchar = fc;

		if (lc > *lastchar)
		    *lastchar = lc;
	    }
	    
	    firstchar++;
	    lastchar++;
	}
}

#ifndef TERMINFO
/*
 * Emulators for terminfo curses procedures.
 */

#ifdef SET_WINDOW
/*
 *	tparm.c (Copyright Pavel Curtis, copyright notice above applies)
 */
/*
 *	char *
 *	tparm(string, parms)
 *
 *	Substitute the given parameters into the given string.
 */

#define STACKSIZE	20

#define npush(x)    if (stack_ptr < STACKSIZE) {stack[stack_ptr].num = x;\
                                                stack_ptr++;\
                                               }
#define npop()	   (stack_ptr > 0  ?  stack[--stack_ptr].num  :  0)
#define spop()	   (stack_ptr > 0  ?  stack[--stack_ptr].str  :  (char *) 0)

typedef union
{
	unsigned int	num;
	char		*str;
}		stack_frame;

stack_frame	stack[STACKSIZE];
static	int	stack_ptr;
static	char	buffer[256];
static	int	*param;
static	char	*bufptr;
static	int	variable[26];

/*VARARGS1*/
char *
tparm(string, parms)
char	*string;
int	parms;
{
	char	len;
	int	number;
	int	level;
	int	x, y;

	param = &parms;

	stack_ptr = 0;
	bufptr = buffer;

	while (*string)
	{
	    if (*string != '%')
		*(bufptr++) = *string;
	    else
	    {
		string++;
		switch (*string)
		{
		    default:
			break;

		    case '%':
			*(bufptr++) = '%';
			break;

		    case 'd':
			(void) sprintf(bufptr, "%d", npop());
			bufptr += strlen(bufptr);
			break;

		    case '0':
			string++;
			len = *string;
			if ((len == '2'  ||  len == '3')  &&  *++string == 'd')
			{
			    if (len == '2')
				(void) sprintf(bufptr, "%02d", npop());
			    else
				(void) sprintf(bufptr, "%03d", npop());
			    
			    bufptr += strlen(bufptr);
			}
			break;

		    case '2':
			string++;
			if (*string == 'd')
			{
			    (void) sprintf(bufptr, "%2d", npop());
			    bufptr += strlen(bufptr);
			}
			break;

		    case '3':
			string++;
			if (*string == 'd')
			{
			    (void) sprintf(bufptr, "%3d", npop());
			    bufptr += strlen(bufptr);
			}
			break;

		    case 'c':
			*(bufptr++) = (char) npop();
			break;

		    case 's':
			strcpy(bufptr, spop());
			bufptr += strlen(bufptr);
			break;

		    case 'p':
			string++;
			if (*string >= '1'  &&  *string <= '9')
			    npush(param[*string - '1']);
			break;

		    case 'P':
			string++;
			if (*string >= 'a'  &&  *string <= 'z')
			    variable[*string - 'a'] = npop();
			break;

		    case 'g':
			string++;
			if (*string >= 'a'  &&  *string <= 'z')
			    npush(variable[*string - 'a']);
			break;

		    case '\'':
			string++;
			npush(*string);
			string++;
			break;

		    case '{':
			number = 0;
			string++;
			while (*string >= '0'  &&  *string <= '9')
			{
			    number = number * 10 + *string - '0';
			    string++;
			}
			npush(number);
			break;

		    case '+':
			y = npop();
			x = npop();
			npush(x + y);
			break;

		    case '-':
			y = npop();
			x = npop();
			npush(x - y);
			break;

		    case '*':
			y = npop();
			x = npop();
			npush(x * y);
			break;

		    case '/':
			y = npop();
			x = npop();
			npush(x / y);
			break;

		    case 'm':
			y = npop();
			x = npop();
			npush(x % y);
			break;

		    case '&':
			y = npop();
			x = npop();
			npush(x & y);
			break;

		    case '|':
			y = npop();
			x = npop();
			npush(x | y);
			break;

		    case '^':
			y = npop();
			x = npop();
			npush(x ^ y);
			break;

		    case '=':
			y = npop();
			x = npop();
			npush(x == y);
			break;

		    case '<':
			y = npop();
			x = npop();
			npush(x < y);
			break;

		    case '>':
			y = npop();
			x = npop();
			npush(x > y);
			break;

		    case '!':
			x = npop();
			npush(! x);
			break;

		    case '~':
			x = npop();
			npush(~ x);
			break;

		    case 'i':
			param[0]++;
			param[1]++;
			break;

		    case '?':
			break;

		    case 't':
			x = npop();
			if (x)
			{
			    /* do nothing; keep executing */
			}
			else
			{
			    /* scan forward for %e or %; at level zero */
				string++;
				level = 0;
				while (*string)
				{
				    if (*string == '%')
				    {
					string++;
					if (*string == '?')
					    level++;
					else if (*string == ';')
					{
					    if (level > 0)
						level--;
					    else
						break;
					}
					else if (*string == 'e'  && level == 0)
					    break;
				    }

				    if (*string)
					string++;
				}
			}
			break;

		    case 'e':
			/* scan forward for a %; at level zero */
			    string++;
			    level = 0;
			    while (*string)
			    {
				if (*string == '%')
				{
				    string++;
				    if (*string == '?')
					level++;
				    else if (*string == ';')
				    {
					if (level > 0)
					    level--;
					else
					    break;
				    }
				}

				if (*string)
				    string++;
			    }
			break;

		    case ';':
			break;

		} /* endswitch (*string) */
	    } /* endelse (*string == '%') */

	    if (*string == '\0')
		break;
	    
	    string++;
	} /* endwhile (*string) */

	*bufptr = '\0';
	return(buffer);
}
#endif

/*
 * Ring Bell.
 */
beep()
{
    putchar('\007');
}

/*
 * 'Ring' visual bell if available, otherwise audible bell.
 */
flash()
{
    /* If you get a syntax error on this routine,
     * you are not using the new curses.h!  Put
     * it in this directory or in /usr/include (saving the old one).
     * And double check that you are linking with the new libcurses.a
     */
    if (flash_screen)
	putp(flash_screen);
    else
	beep();
}

/*
 * Return the baud rate of the current terminal.
 */
baudrate()
{
#ifdef	B9600
    if (_tty.sg_ospeed >= B9600)
	return(9600);
#endif
#ifdef	B4800
    if (_tty.sg_ospeed >= B4800)
	return(4800);
#endif
    return(1200);
}

erasechar() { return(_tty.sg_erase); }
killchar() { return(_tty.sg_kill); }
#endif
SHAR_EOF
if test 11742 -ne "`wc -c < 'hacks.c'`"
then
	echo shar: error transmitting "'hacks.c'" '(should have been 11742 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'help.c'" '(2137 characters)'
if test -f 'help.c'
then
	echo shar: will not over-write existing file "'help.c'"
else
sed 's/^X//' << \SHAR_EOF > 'help.c'
/*
 *************
 * DISTRIBUTION NOTICE  July 30 1985
 * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
 *		Research Triangle Institute, (919) 541-7005.
 * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
 *		Naval Research Laboratory, (202) 767-3365.
 * No claims or warranties of any sort are made for this distribution.
 * General permission is granted to copy, but not for profit,
 * any of this distribution, provided that this notice
 * is always included in the copies.
 *************
 */
#include "wm.h"


/*
 * print a command summary over the top of the screen, then redraw
 */
helpmsg()
{
printf("Code    Command  Description\r\n");
printf("----    -------  -----------\r\n");
printf("%d..%d    change    Change to the named window\r\n",
	MINWINDOW, MAXWINDOWS-1);
printf("d       dump      dump current window contents to a file\r\n");
printf("h or ?  help      print this help message\r\n");
printf("i       identify  identify windows\r\n");
printf("k       kill      kill a window permanently\r\n");
printf("l       last      change to last-used window\r\n");
printf("m       move      move and/or change size of current window\r\n");
printf("n       new       make a new window\r\n");
printf("p       prefix    change WM prefix character (See EXECUTE below)\r\n");
printf("q       quit      quit WM\r\n");
printf("r       redraw    redraw entire screen\r\n");
printf("s       save      save current window configuration\r\n");
printf("t       termcap   reset $TERM and $TERMCAP of current window\r\n");
printf("z       suspend   suspend WM (or spawn non-window subshell)\r\n");

printf("----------------------------------------------------------\r\n");

printf("To EXECUTE a command, type the WM prefix character (%s) then the command code.\r\n", mkprint(prefix));
printf("To ENTER the prefix character itself, type it twice.\r\n");
printf("To CANCEL a WM command before it executes, type <ESC> or <DEL>.\r\n");
printf("For FUTHER INFORMATION, consult the 'wm' manual entry.\r\n");

printf("------------------------------\r\n");

printf("Now hit any key to return to WM");
(void)fflush(stdout);
}
SHAR_EOF
if test 2137 -ne "`wc -c < 'help.c'`"
then
	echo shar: error transmitting "'help.c'" '(should have been 2137 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Mod.sources mailing list