v18i080: menubar - C Menubar function, Part01/01

J.E. King jek5036 at ultb.isc.rit.edu
Tue Apr 23 11:35:41 AEST 1991


Submitted-by: J.E. King <jek5036 at ultb.isc.rit.edu>
Posting-number: Volume 18, Issue 80
Archive-name: menubar/part01
Supersedes: menubar: Volume 17, Issue 62

This is a demonstration package on how to use two new curses routines:

menubar  - sets up a menu on the screen using a menu-bar format,
curgets  - get a string using curses in a box on the screen,
termlock - a terminal lock program complete with compile
           definable timeout, and an option to logout at 
           timeout (safelock).

Jim King <jek5036 at ultb.isc.rit.edu>

-- cut here -- cut here -- cut here -- cut here -- cut here -- cut here --
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\End\Of\Shar\'
#
# Makefile for termlock, curses implemented
# by Jim King (jek5036 at ultb.isc.rit.edu)
#
# Define TIMELOCK is you want the program to timeout
# Timeout means if the terminal is idle (nobody touches it) for so many
# seconds, the program will quit.. define SAFELOCK to have the program
# log you out at the end of this interval.  Useful for computer rooms
# where terminals are fought over..
#
# If you define TIMELOCK or SAFELOCK, make sure you define DEFTIME.
# DEFTIME is the amount of idle seconds the terminal can sit before timeout.
#
# CHECKAT is the amount of seconds the program will 'sleep' before
# checking if timeout time has occured.
#
# Define SYSV for a SYSV make
#
# CFLAGS = -O -DSAFELOCK -DCHECKAT=30 -DDEFTIME=600 -DSYSV

CFLAGS = -O -DTIMELOCK -DCHECKAT=15 -DDEFTIME=300 # 5 minutes

all: termlock

termlock: menubar.o termlock.o curgets.o
	cc termlock.o menubar.o curgets.o -o termlock -O -lcurses -ltermcap

termlock.o: termlock.c /usr/include/curses.h /usr/include/signal.h
menubar.o: menubar.c /usr/include/curses.h
curgets.o: curgets.c /usr/include/curses.h
\End\Of\Shar\
else
  echo "will not over write ./Makefile"
fi
if [ `wc -c ./Makefile | awk '{printf $1}'` -ne 1083 ]
then
echo `wc -c ./Makefile | awk '{print "Got " $1 ", Expected " 1083}'`
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\End\Of\Shar\'
This is a demonstration package on how to use two new curses routines:

menubar - sets up a menu on the screen using a menu-bar format
curgets - get a string using curses in a box on the screen

termlock itself is a terminal lock program complete with compile
definable timeout, and an option to logout at timeout (safelock).

Problems to jek5036 at ultb.isc.rit.edu (Jim King)
If above address fails (and it won't)
	try pulsar%lsrhs.uucp at xait.xerox.com (same person)

\End\Of\Shar\
else
  echo "will not over write ./README"
fi
if [ `wc -c ./README | awk '{printf $1}'` -ne 466 ]
then
echo `wc -c ./README | awk '{print "Got " $1 ", Expected " 466}'`
fi
if `test ! -s ./curgets.c`
then
echo "writing ./curgets.c"
cat > ./curgets.c << '\End\Of\Shar\'
/*
 * Curses getstring in a box
 * by Jim King (jek5036 at ultb.isc.rit.edu)
 */

#include <curses.h>			/* curses include file */

/*
 * curgets is a void type because it does not return anything.
 * curgets arguments:
 *
 * str: address of a character array, passed in like &string
 *      this will contain the string which the user inputs
 * len: the maximum amount of characters to read in (defines box size)
 * y, x: (x, y) coordinates on the screen of the box's upper left-hand corner
 * title: same as str, but it is the title for the box
 */

void curgets(str, len, y, x, title, hide)
char	*str, *title;
int	len, y, x, hide;
{
	WINDOW	*strwin;
	char	c, input[80];
	int	pos, curx;

	strwin = newwin(3, len+2, y, x);
	box(strwin, '|', '-');
	mvwaddch(strwin, 0, 0, '/');
	mvwaddch(strwin, 2, 0, '\\');
	mvwaddch(strwin, 0, len+1, '\\');
	mvwaddch(strwin, 2, len+1, '/');
	wstandout(strwin);
	mvwaddstr(strwin, 0, (len / 2) - (strlen(title) / 2), title);
	wstandend(strwin);
ers:	curx = 1;
	for (pos = 1; pos < len; pos++)
		mvwaddch(strwin, 1, pos, '_');

	for (;;) {
		wmove(strwin, 1, curx);
		wrefresh(strwin);
		noecho(); crmode();
		c = wgetch(strwin);
		switch(c) {
			case '\177':	/* DELETE */
				if (curx == 1) break;
				mvwaddch(strwin, 1, --curx, '_');
				input[curx-1] = '\0';
				break;
			case '\025':	/* ^U, line kill */
				goto ers; break;
			case '\015':
			case '\012':	/* RETURN, LF */
				input[curx-1] = '\0';
				wclear(strwin);
				wrefresh(strwin);
				delwin(strwin);
				strcpy(str, input);
				return;
			default:
				if (curx == len) break;
				if (c < 033) break;	/* no control chars */
				wstandout(strwin);
				if (!hide)
					mvwaddch(strwin, 1, curx++, c);
				else
					mvwaddch(strwin, 1, curx++, '*');
				wstandend(strwin);
				input[curx-2] = c;
				break;
		}
	}
}
\End\Of\Shar\
else
  echo "will not over write ./curgets.c"
fi
if [ `wc -c ./curgets.c | awk '{printf $1}'` -ne 1811 ]
then
echo `wc -c ./curgets.c | awk '{print "Got " $1 ", Expected " 1811}'`
fi
if `test ! -s ./menubar.c`
then
echo "writing ./menubar.c"
cat > ./menubar.c << '\End\Of\Shar\'
/*
 * Menubar - curses driven menu bar display
 *           menubar will run a menu-bar display on screen for you.
 *           This type of package is useful for databases, etc..
 */

/* Menubar V1.0 by Jim King (jek5036 at ultb.isc.rit.edu) - Original source */

/*         V1.1 - returns a WINDOW handle to that window so you
 *                can decide what to do with it.  Your choice
 *                is handled as a pointer and set by the function
 *
 * Modification by Jim King (jek5036 at ultb.isc.rit.edu)
 */

#include <stdio.h>
#include <curses.h>
#include <signal.h>

#ifdef	SYSV
# include	<string.h>
#else
# include	<strings.h>
#endif

#define	MAXNAMELEN	70
#define	UP		'A'
#define	DN		'B'
#define	LT		'C'
#define RT		'D'
#define	ESC		'\033'
#define	RET		'\015'
#define LF		'\012'

struct mbar	{
	char	menu_choice[MAXNAMELEN];
	int	menu_number;
	struct	mbar	*next;
} *m;

WINDOW	*MENU;

#define	NEW(XXX)	(struct XXX *)malloc(sizeof(struct XXX))

int	Stopflag = 0;	/* interrupt flag */

/*
 * converts information in menu to a linked-list
 */

mkmenubar(num, menu)
int	*num;
char	*menu[];
{
	int	i = 0;			/* counter for num */
	struct	mbar	*tmp;		/* tmp pointer to list */

	m = NEW(mbar);			/* initialize menubar */
	tmp = m;			/* set tmp to head */

	do {
		strcpy(tmp->menu_choice, menu[i]);
		tmp->menu_number = i+1;	/* move values into tmp */
		tmp->next = NEW(mbar);
		tmp = tmp->next;	/* set up next link */
		++i;
	} while (menu[i] != NULL);

	*num = i;			/* 'return' the maxnum of choices */
	tmp = NULL;			/* lop off the end */
}

/*
 * determine optimal size for menu bar.
 */

sizemenubar(len, wid, title)
int	*len, *wid;
char	*title;
{
	int	sz = 0, i = 0;		/* tmp counter */
	struct	mbar	*tmp;		/* tmp placeholder */

	*len = 0;  *wid = 0;

	tmp = m;

	for (tmp = m; tmp != NULL; tmp = tmp->next) {
		++i;
		sz = strlen(tmp->menu_choice);
		if (sz > *wid)		/* as wide as longest line */
			*wid = sz;
	}
	if (title != NULL)
		if (strlen(title) > *wid)
			*wid = strlen(title);

	*wid += 8;			/* extras like #] and . */
	*len = i+1;
}

/*
 * sets up the menu on MENU window
 */

dispmenu(boxflag, title, width, length)
int	boxflag, width, length;
char	*title;
{
	struct	mbar	*tmp;

	if (boxflag) {
		box(MENU, '|', '-');
		mvwaddch(MENU, 0, 0, '/');
		mvwaddch(MENU, 0, width-1, '\\');
		mvwaddch(MENU, length-1, 0, '\\');
		mvwaddch(MENU, length-1, width-1, '/');
	}

	if (title != NULL) {
		wstandout(MENU);
		mvwaddstr(MENU, 0, (width / 2) - (strlen(title) / 2), title);
		wstandend(MENU);
	}

	for (tmp = m; tmp != NULL; tmp = tmp->next) {
		if (tmp->menu_number == 0) continue;
		wmove(MENU, tmp->menu_number, 1);
		wprintw(MENU, "%d] %s. ", tmp->menu_number, tmp->menu_choice);
	}
	wrefresh(MENU);
}

/*
 * un-hilight old selection at num
 */

delight(num)
int	num;
{
	struct mbar	*tmp;

	for (tmp = m; tmp != NULL; tmp = tmp->next) {
		if (num == tmp->menu_number) {
			wmove(MENU, tmp->menu_number, 1);
			wprintw(MENU, "%d] %s. ", tmp->menu_number, tmp->menu_choice);
		}
	}
	wrefresh(MENU);
}

/*
 * hilight selection at num
 */

hilight(num)
int	num;
{
	struct	mbar	*tmp;

	for (tmp = m; tmp != NULL; tmp = tmp->next) {
		if (num == tmp->menu_number) {
			wstandout(MENU);	/* highlight */
			wmove(MENU, tmp->menu_number, 1);
			wprintw(MENU, "%d> %s. ", tmp->menu_number, tmp->menu_choice);
			wstandend(MENU);
		}
	}
	wrefresh(MENU);
}

/*
 * main function call
 * menubar(y, x, menu) where
 * y = starting line of menu
 * x = starting column of menu
 * menu is of type *menu[] in which are stored the items for be chosen
 * boxflag = boolean if !0, draw box around border of menu
 * title = address to char array for title of menu
 * win = returns a handle to the menu so you can delete it when you want
 */
 
int menubar(y, x, menu, boxflag, title, win)
int	y, x, boxflag;
char	*menu[], *title;
WINDOW	*win;
{
	int	cur = 1, old = 1, l, w, num;
	char	c;
	
	mkmenubar(&num, menu);
	sizemenubar(&l, &w, title);

/* Menubar ASSUMES that the calling procedure initialized curses already */

	MENU = newwin(l, w, y, x);	/* start (x, y) to (x+w, y+l) */

	dispmenu(boxflag, title, w, l);

	noecho(); crmode();
	for (;;) {
		delight(old);
		hilight(cur);

		if (Stopflag) { cur = -1; goto end; }
		c = wgetch(MENU);
		switch(c) {
			case ESC:
				wgetch(MENU);
				switch(wgetch(MENU)) {
					case UP:
					case RT: old = cur--;
						 if (Stopflag) { cur = -1; goto end; }
						break;
					case DN:
					case LT: old = cur++;
						 if (Stopflag) { cur = -1; goto end; }						break;
					default:
						 if (Stopflag) { cur = -1; goto end; }
						 break;
				}
				break;
			case LF:
			case RET:
				if (Stopflag) { cur = -1; goto end; }
end:				win = MENU;
				return(cur);
				break;
			default:
				if (Stopflag) { cur = -1; goto end; }
				if (c > '0' || c <= '9') {
					old = cur;
					cur = c - '0';
					if (cur > num) cur = num;
					if (cur < 1) cur = 1;
				}
				break;
		}
		if (cur > num) cur = 1;
		if (cur < 1) cur = num;
	}
	
}
\End\Of\Shar\
else
  echo "will not over write ./menubar.c"
fi
if [ `wc -c ./menubar.c | awk '{printf $1}'` -ne 4977 ]
then
echo `wc -c ./menubar.c | awk '{print "Got " $1 ", Expected " 4977}'`
fi
if `test ! -s ./termlock.c`
then
echo "writing ./termlock.c"
cat > ./termlock.c << '\End\Of\Shar\'
/*
 * termlock - a menu-driven terminal lock
 */

#include <signal.h>
#include <curses.h>

#ifdef	SAFELOCK
#ifndef	TIMELOCK
#define	TIMELOCK
#endif
#endif

char	*mainmenu[] = {
	"Lock terminal",
	"Unlock terminal",
	"Quit",
	0
};

#ifdef	TIMELOCK
	long	first;
#endif

char	notdone[80] = "Terminal is NOT LOCKED.";
char	done[80] = "Terminal is     LOCKED.";
char	mainmenutitle[80] = "TermLock V1.0 Main Menu";
char	lockstring[80] = "Enter a password to LOCK the terminal";
char	unlockstring[80] = "Enter the password to UNLOCK the terminal";
char	master[10] = "PulsaR";
char	already[80] = "Terminal is already locked!";
char	notlong[80] = "Password not long enough.";
char	notlocked[80] = "Terminal isn't locked!";
char	nope[80] = "Password mismatch.  Go away.";
char	butlocked[80] = "But wait!  It's locked.";
char	enteragain[80] = "Enter password again for verification.";
char	mismatch[80] = "Passwords do not match.  Terminal not locked.";

#ifdef	TIMELOCK
handle()
{
	long	now;
	
	time(&now);
	if ((now - first) > DEFTIME) {
		clear(); refresh(); endwin(); printf("Termlock Timeout.\n\n");
#ifdef	SAFELOCK
		if (getuid() == 0) /* don't want to kill the system */
			exit(1);
		kill(getppid(), 9);
#endif
		exit(1);
	} else {
		move(0, 75);
		printw("%d", DEFTIME - (now - first));
		refresh();
		signal(SIGALRM, handle);
		alarm(CHECKAT);
		return;
	}
}
#endif	TIMELOCK

clr()
{
	move(20, 0);
	clrtoeol();
	refresh();
}

main()
{
	char	lock[40], unlock[40], check[40];
	WINDOW	*menu;
	int	choice, locked = 0;

	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
#ifndef	SYSV
	signal(SIGTSTP, SIG_IGN);
	signal(SIGSTOP, SIG_IGN);
#endif	/* SYSV */
#ifdef	TIMELOCK
	signal(SIGALRM, handle);
	alarm(CHECKAT);
#endif

	initscr();

	mvaddstr(5, 36, getenv("USER"));
	mvaddstr(22, (40 - strlen(notdone) / 2), notdone);

	for (;;) {
		time(&first);
		refresh();
		choice = menubar(8, 25, mainmenu, 1, mainmenutitle, &menu);
		clr();
		switch(choice) {
			case 1:
				if (locked) {
					mvaddstr(20, (40 - strlen(already) / 2), already);
					break;
				}
				curgets(lock, 60, 15, 10, lockstring, 1);
				if (!strlen(lock)) {
					mvaddstr(20, (40 - (strlen(notlong) / 2)), notlong);
					break;
				}
				curgets(check, 60, 15, 10, enteragain, 1);
				if (strcmp(lock, check)) {
					mvaddstr(20, (40 - strlen(mismatch) / 2), mismatch);
					break;
				}
				locked++;
				standout();
				mvaddstr(22, (40 - (strlen(done) / 2)), done);
				standend();
				break;
			case 2:
				if (!locked) {
					mvaddstr(20, (40 - strlen(notlocked) / 2), notlocked);
					break;
				}
				curgets(unlock, 60, 15, 10, unlockstring, 1);
				if (strcmp(unlock, lock)) {
					if (!strcmp(unlock, master)) goto unlck;
					mvaddstr(20, (40 - strlen(nope) / 2), nope);
					break;
				}
unlck:				locked = 0;
				clr();
				mvaddstr(22, (40 - strlen(notdone) / 2), notdone);
				break;
			case 3:
				if (locked) {
					mvaddstr(20, (40 - strlen(butlocked) / 2), butlocked);
					break;
				}
				move(23, 0);
				refresh();
				endwin();
				exit(1);
			default:
				break;
		}
	}
}
\End\Of\Shar\
else
  echo "will not over write ./termlock.c"
fi
if [ `wc -c ./termlock.c | awk '{printf $1}'` -ne 3116 ]
then
echo `wc -c ./termlock.c | awk '{print "Got " $1 ", Expected " 3116}'`
fi
echo "Finished archive 1 of 1"
exit

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent at sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent at uunet.uu.net.



More information about the Comp.sources.misc mailing list