[comp.sources.misc] v16i099: pscmenu - tty based menus, Part01/01

ted@oz.plymouth.edu (Ted Wisniewski) (02/11/91)

Submitted-by: Ted Wisniewski <ted@oz.plymouth.edu>
Posting-number: Volume 16, Issue 99
Archive-name: pscmenu/part01

PSCMenu is a menu system that is capable of doing any unix command 
from the "menu".  The individual menus are read from menu files that
are located in a "menu" directory.  The menu files are simple text files
that may be edited with any editor.  The "menu" is flexable, the only
command line argument that is accepted is the name of a directory in which
the menu files are located.  A default directory is specified in the
menu header file. Developed and tested on Ultrix based systems. 

Ted
----------
#! /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:
#	MENU
# This archive created: Mon Dec 17 14:49:00 1990
# By:	The Wiz ()
export PATH; PATH=/bin:/usr/bin:$PATH
if test ! -d 'MENU'
then
	mkdir 'MENU'
fi
cd 'MENU'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'

CC     = /bin/cc
CFLAGS = -O
LIBS   = -ltermcap
DEFS   =
TARGET = menu
 
HDRS  = menu.h utils.h 
SRCS  = menu.c appl.c utils.c files.c signals.c
OBJS  = menu.o appl.o utils.o files.o signals.o

$(TARGET): $(OBJS) $(SRCS) $(HDRS)
	$(CC) $(CFLAGS) $(DEFS) $(OBJS) -o $(TARGET) $(LIBS)
	strip $(TARGET)
	chmod 711 $(TARGET)

menu.o  : menu.c menu.h
	$(CC) $(CFLAGS) $(DEFS) -c menu.c

appl.o  : appl.c 
	$(CC) $(CFLAGS) $(DEFS) -c appl.c

utils.o : utils.c utils.h
	$(CC) $(CFLAGS) $(DEFS) -c utils.c

files.o : files.c menu.h
	$(CC) $(CFLAGS) $(DEFS) -c files.c

signals.o : signals.c 
	$(CC) $(CFLAGS) $(DEFS) -c signals.c

install:
	/bin/cp  $(TARGET) /usr/local/bin
	chmod 711 /usr/local/bin/$(TARGET)
clean:
	rm -f $(OBJS)

lint:
	lint $(SRCS) > LINT.OUT
SHAR_EOF
fi
if test -f 'appl.c'
then
	echo shar: "will not over-write existing file 'appl.c'"
else
cat << \SHAR_EOF > 'appl.c'
# include <ctype.h>
# include "menu.h"
# include "utils.h"

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

box_screen()
/*
	Draw a box around the screen.
*/
{
	int i;
	char buf[256];

	(void) sprintf(buf,"%80s"," ");
	start_rev();
	move_csr(0,FIRST_LINE);
	print_str(buf);
	move_csr(0,STATUS_LINE);
	print_str(buf);
	for(i=1;i<22;i++){
	   move_csr(0,i);
	   outc(' ');
	   move_csr(79,i);
	   outc(' ');
	}
	end_rev();
}

disp_menu(menu,n_ent)
menu_ent *menu;
int n_ent;
/*
	Display the menu.
*/
{
	int ind = 0;
	char tmp[5];
	
	while(ind < n_ent){
	   if(ind == 0){
	     move_csr((CENTER-(strlen(menu[0].desc)/2)),(ind*2) + 3);
	   }else{
	     if(ind > 0){
	       move_csr(NUMCOL,(ind*2) + 4);
	       (void) sprintf(tmp,"%d",ind);
	       print_str(tmp);
	     }
	     move_csr(DESCOL,(ind*2) + 4);
	   }
	   hi_lite(menu[ind].desc);
	   ind++;
	}
}

do_menu(menu,n_ent)
menu_ent *menu;
int n_ent;
{
	char inp = NULL,save = NULL;
	int tmp;

	move_csr(4,20);
	while(inp != 'q') {
	   switch (inp) {
	        case 'c':
		  erase_menu(n_ent);
	          change();
	          disp_menu(menu,n_ent);
	    	break;
		case 'x':
		  erase_menu(n_ent);
		  exec_it();
	          disp_menu(menu,n_ent);
		break;
		case 'd':
		  erase_menu(n_ent);
	          exec_cshell("ls");
	          disp_menu(menu,n_ent);
	        break;
		case 'l':
		  erase_menu(n_ent);
	          exec_pipe("ls -l");
	          disp_menu(menu,n_ent);
		break;
		case RE_DRAW:
	  	  clr_scr();
		  setup_screen();
		  disp_menu(menu,n_ent);
		  (void) fflush(stdin);
		break;
		case LF:
		case CR:
		   if(m_flag != TRUE)
		      inp = n_ent-1 + '0';
		default:
	          tmp = inp - '0';
	          if((tmp >= 1) && (tmp < n_ent)){
	            switch(menu[tmp].key){
	               case '+':
			  erase_menu(n_ent);
	  		  exec_pipe(menu[tmp].cmd);
	  		  disp_menu(menu,n_ent);
	               break;
	               case '*':
			  exec_cshell(menu[tmp].cmd);
	  		  disp_menu(menu,n_ent);
	               break;
		       case '@': menu->key = '@';
	               case '&':
			  erase_menu(n_ent);
	  		  (void) read_menu(menu,menu[tmp].cmd,&n_ent);
	  		  disp_menu(menu,n_ent);
	               break;
	               case '1':
			  erase_menu(n_ent);
			  One_fname(buffer,2);
			  (void) sprintf(string,"%s %s",menu[tmp].cmd,buffer);
			  exec_cshell(string);
			  clear_array(string);
	  		  disp_menu(menu,n_ent);
	               break;
	               case '2':
			  erase_menu(n_ent);
			  One_fname(buffer,2);
			  (void) sprintf(string,"%s %s ",menu[tmp].cmd,buffer);
			  Two_fname(buffer,3);
			  if(!isprint(buffer[strlen(buffer)]))
			     rm_lf(buffer);
			  (void) strcat(string,buffer);
			  exec_cshell(string);
			  clear_array(string);
	  		  disp_menu(menu,n_ent);
	               break;
	               case '3':
			  erase_menu(n_ent);
			  ask_who(buffer,2);
			  (void) sprintf(string,"%s %s",menu[tmp].cmd,buffer);
			  exec_cshell(string);
			  clear_array(buffer);
			  clear_array(string);
	  		  disp_menu(menu,n_ent);
	               break;
	               case '4':
			  erase_menu(n_ent);
			  ask_what(buffer,2);
			  (void) sprintf(string,"%s %s",menu[tmp].cmd,buffer);
			  exec_cshell(string);
			  clear_array(buffer);
			  clear_array(string);
	  		  disp_menu(menu,n_ent);
	               break;
	               default:
		       break;
	     }
	   }
	  }
	  move_csr(0,23);
	  inp = getchar();
	  if(inp == 'h'){
	     inp = disp_help(n_ent);
	     if(inp != 'x' && inp!= 'd' && inp != 'c' && inp!=RE_DRAW)
	       disp_menu(menu,n_ent);
	  }
	}
	quit();
}

erase_menu(num)
int num;
{
	int ind = 0;
	char buffer[50];
	
	(void) sprintf(buffer,"%40s"," ");
	move_csr(20,3);
	print_str(buffer);
	for(ind=0;ind<num;ind++){
	   move_csr(NUMCOL,(ind*2) + 4);
	   print_str(buffer);
	}
}

disp_help(num)
int num;
{
	char buffer[40];
	int i;
	char Key;
	
	(void) sprintf(buffer,"%30s"," ");
	move_csr(25,7);
	print_str(buffer);
	move_csr(25,7);
	hi_lite(buffer);
	for(i=8;i<=18;i++){
	   move_csr(25,i);
	   print_str(buffer);
	   start_rev();
	   move_csr(25,i);
	   outc(' ');
	   move_csr(54,i);
	   outc(' ');
	   end_rev();
	}
	move_csr(25,18);
	print_str(buffer);
	move_csr(25,18);
	hi_lite(buffer);
	move_csr(27,9);
	print_str("Command Summary:");
	move_csr(27,11);
	print_str("(q)       Quit Menu");
	move_csr(27,12);
	print_str("(x)       Execute Command");
	move_csr(27,13);
	print_str("(c)       Change Directory");
	move_csr(27,14);
	print_str("(d)       Show Directory");
	move_csr(27,15);
	print_str("(l)       Long Directory");
	move_csr(27,16);
	print_str("(ctrl-R)  Redraw Screen.");
	move_csr(27,17);
	Key = getchar();
	erase_help();
	return(Key);
}

erase_help()
{
	char buffer[40];
	int i;

	(void) sprintf(buffer,"%30s"," ");
	for(i=7;i<=18;i++){
	   move_csr(25,i);
	   print_str(buffer);
	}
}

One_fname(name,y)
char *name;
int y;
{
	move_csr(2,y);
	clear_array(name);
	print_str("Filename: ");
	read_str(name);
}

Two_fname(name,y)
char *name;
int y;
{
	move_csr(2,y);
	clear_array(name);
	print_str("New File: ");
	read_str(name);
}

change()
{
	move_csr(2,2);
	clear_array(buffer);
	print_str("Directory: ");
	read_str(buffer);
	rm_lf(buffer);
	chdir(buffer);
	erase_line(2,2,60);
	prt_curdir();
	clear_array(buffer);
}

exec_it()
{
	move_csr(2,2);
	print_str("Command: ");
	clear_array(buffer);
	read_str(buffer);
	exec_cshell(buffer);
}

ask_who(name,y)
char *name;
int y;
{
	move_csr(2,y);
	clear_array(name);
	print_str("To Whom: ");
	read_str(name);
	move_csr(2,3);
	(void) fflush(stdout);
}

ask_what(name,y)
char *name;
int y;
{
	move_csr(2,y);
	clear_array(name);
	print_str("Topic: ");
	read_str(name);
}
SHAR_EOF
fi
if test -f '.v'
then
	echo shar: "will not over-write existing file '.v'"
else
cat << \SHAR_EOF > '.v'
game.c
shell.c
appl.c
SHAR_EOF
fi
if test -f 'files.c'
then
	echo shar: "will not over-write existing file 'files.c'"
else
cat << \SHAR_EOF > 'files.c'
# include <stdio.h>
# include <unistd.h>
# include "menu.h"

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

read_menu(menu,file_name,num)
menu_ent *menu;
char *file_name;
int *num;
{
	FILE *fp;
	int index = 0;
	char buffer[256];
	
	if(menu->key == '@')
	   m_flag = TRUE;
	else
	   m_flag = FALSE;
	(void) sprintf(buffer,"%s%s",menu_dir,file_name);
	if((access(buffer,R_OK|F_OK)) == -1){
	   move_csr(26,11);
	   hi_lite("Menu file cannot be accessed.");
	   continue_it(20);
	   erase_line(26,11,30);
	}else{
	   fp = fopen(buffer,"r");
	   while(!feof(fp)){
	      (void) fgets(buffer,256,fp);
	      rm_lf(buffer);
	      if(!feof(fp) && (index <= 7)){
		switch (buffer[0]){
		  case '$':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].desc,buffer+2);
			index++;
		  break;
		  case '?': 
			(void) strcpy(menu[index].desc,buffer+2);
			index++;
		  break;
		  case '+':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '*':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '@':
		  case '&':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '1':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '2':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '3':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		  case '4':
			menu[index].key = buffer[0];
			(void) strcpy(menu[index].cmd,buffer+2);
		  break;
		}
	      }
	    }
	fclose(fp);
	*num = index;
	}
}
SHAR_EOF
fi
if test -f 'menu.c'
then
	echo shar: "will not over-write existing file 'menu.c'"
else
cat << \SHAR_EOF > 'menu.c'
# include <stdio.h>
# include <sys/file.h>
# include <sys/ioctl.h>
# include "menu.h"

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

/*****************************************************************************
	Execute a process and have the output read into a buffer and then
	print it to the screen.
 *****************************************************************************/

exec_pipe(comline)
char *comline;
{
	char inbuf[LINESZ], list[FOURK][80];
	FILE *f, *popen(), *pclose();
	int num = 1, len = 0;

	if((f = popen(comline,"r")) == NULL){
	   strcpy(list[0],"command not found");
	   (void) fprintf(fprintf,"Command not Found.\n");
	}else
	   while(fgets(inbuf,LINESZ,f) != NULL){
	      rm_lf(inbuf);
	      (void) strcpy(list[num],inbuf);
	      if(strlen(inbuf) > len)
		len = strlen(inbuf);
	      num++;
	   }
	   print_output(list,num,len);
	pclose(f);
}

/**************************************************************************
 Print output to the Menu Window,  when done clear the Window.
 **************************************************************************/

print_output(output,number,len)
char output[FOURK][80];
int number, len;
{
	int i, k = 4;

	for(i=1;i<number;++i){
	   move_csr(5,k);
	   print_str(output[i]);
	   k++;
	   if(i%15 == 14){
	     if(cont_it() == 1){
	        clr_area(5,4,(k-4),len+2);
	        return;
	     }
	     clr_area(5,4,(k-4),len+2);
	     move_csr(5,4);
	     k = 4;
	   }
	   (void) fflush(stdout);
	}
	continue_it(CONT_LINE);
	clr_area(5,4,(k-4),len+2);
}

/**************************************************************************
 Request input from the user as to whether he/she wishes to continue.
 This routine gives the option to stop seeing output.
 **************************************************************************/

cont_it()
{
	char c;

	move_csr(20,CONT_LINE);
	hi_lite("Press space to continue or \'q\' to stop.");
	c = getchar();
	while(c != 'q' && c != ' ')
	   c = getchar();
	erase_line(20,CONT_LINE,45);
	if(c == 'q')
	   return 1;
	else
	   return 0;
}

/**************************************************************************
 Request input from the user as to whether he/she wishes to continue.
 **************************************************************************/

continue_it(line)
int line;
{
	move_csr(27,line);
	hi_lite("Press a space to Continue.");
	while(getchar() != SPACE);
	erase_line(27,line,45);
}

/*****************************************************************************
 Print The current working directory at the bottom of the screen.
 *****************************************************************************/

prt_curdir()
{
	char direct[BUF_SIZ];
	int i;

	move_csr(0,STATUS_LINE);
	hi_lite("Directory:");
	getwd(direct);
	if(strlen(direct) < 40)
	   for(i=strlen(direct);i<=40;i++)
	      (void) strcat(direct," ");
	else
	   for(i=40;i<=80;i++)
   	      direct[i] = NULL;
	move_csr(12,STATUS_LINE);
	hi_lite(direct);
}

/*****************************************************************************
 Clear an Area in the Menu Window.
 *****************************************************************************/

clr_area(st_y,st_x,n_line,len)
int st_y,st_x,n_line,len;
{
	int i;

	for(i=0;i<=len;i++)
	  line[i] = ' ';
	line[i+1] = NULL;
	for(i=(st_y-1);i<(n_line+st_y);i++){
	   move_csr(st_x,i);
	   print_str(line);
	}
}

/*****************************************************************************
 Erase a line within the Menu Window.
 *****************************************************************************/

erase_line(x,y,length)
int x,y,length;
{
	int i;

	for(i=0;i<=length;i++)
	    line[i] = ' ';
	line[i+1] = NULL;
	move_csr(x,y);
	print_str(line);
}

/*****************************************************************************
 Execute a shell command.  Output does not come to back to the window.
 *****************************************************************************/

exec_cshell(command)
char *command;
{
	clr_scr();
	(void) fflush(stdout);
	reset_tty();
	if(fork() == 0)
	  execl("/bin/csh","csh","-c",command,0);
	else
	  wait((int *)0);
	setup_tty();
	continue_it(LAST_LINE);
	setup_screen();
}

/*****************************************************************************
 Draw borders and print Header on the screen.
 *****************************************************************************/

setup_screen()
{
	clr_scr();			/* Clear screen routine		     */
	box_screen();
	move_csr((CENTER-strlen(HEADER)/2),FIRST_LINE);
	hi_lite(HEADER);
	move_csr(68,STATUS_LINE);
	hi_lite(CMD_LIN);
	prt_curdir();
}

/*****************************************************************************
 Make sure The user does not try to run menu in the background.
 *****************************************************************************/

check_run()
{
        int     tpgrp;  /* terminal control process group */

        if (ioctl(2, TIOCGPGRP, &tpgrp) != 0) { /* hope stderr open */
                exit(1);
        }
	if(getpgrp(0) != tpgrp){
	  (void) fprintf(stderr,"\nSorry, Cannot run in background.\n");
	  exit(0);
	}
}

/*****************************************************************************
 Make sure Output goes to the screen and terminal is capable of running
 menu.
 *****************************************************************************/

initialize()
{
	int term;

	if(!isatty(1)){
	   (void) fprintf(stderr,"Sorry, Cannot output to the screen (exiting).\n");
	   exit(4);
	}
	if((term = get_term()) == -1){
	   (void) fprintf(stderr,"Sorry, Bad termcap entry (exiting).\n");
	   exit(4);
	}
	save_tty();			/* Save tty states		     */
	setup_tty();
}

/*****************************************************************************
 Prepare for Quit Menu, and exit (restore original settings).
 *****************************************************************************/

quit()
/*
	Reset the terminal to the same as before it was run.
*/
{
	clr_scr();			/* Clear screen routine		     */
	move_csr(0,LAST_LINE);
	reset_tty();
	exit(0);
}

/*****************************************************************************
 Set proper terminal settings for use while within menu.
 *****************************************************************************/

setup_tty()
{
	no_echo();
	cbreak();
	crmode();
}

main(argc,argv)
int argc;
char *argv[];
{
	int *num;

	    /************************************************************
		If More than two arguments are supplied print the
		Usage statement.
	     ************************************************************/
	if(argc > 2){
	  (void) fprintf(stderr,"Usage: menu\n");
	  (void) fprintf(stderr,"Usage: menu [menu_directory]\n");
	  exit(0);
	}else{
	    /************************************************************
		If there are no additional arguments Use the default
		Menu directory.
	     ************************************************************/
	  if(argc == 1)
	     (void) strcpy(menu_dir,MENU_DIR);
	  else
	    /************************************************************
		See if the directory name ends in a '/' if not add
		one.
	     ************************************************************/
	    if(argc == 2){
	       (void) strcpy(menu_dir,argv[1]);
	       if(menu_dir[strlen(menu_dir)-1] != '/')
	          (void) strcat(menu_dir,"/");
	    }
	    (void) sprintf(buffer,"%s%s",menu_dir,"menu.1");
	    /************************************************************
	        Check to make sure the menu directory is Read-able and
		executeable
	     ************************************************************/
	    if(access(menu_dir,R_OK|X_OK)){
	       (void) fprintf(stderr,"Directory :%s: is not accessable ",menu_dir);
	       (void) fprintf(stderr,"or does not exist.\n");
	       exit(1);
	    }
	    /************************************************************
	        Check to see if the main menu file exists, if it does 
	        not exist, exit the program.
	     ************************************************************/
	    if(access(buffer,F_OK)){
	       (void) fprintf(stderr,"Menu files do not exist in %s.\n",menu_dir);
	       exit(2);
	    }
	}
	check_run();
	initialize();		
	setup_screen();
	setup_sigs();
	main_menu->key = '@';			/* We start in main menu */
	(void) read_menu(main_menu,MAIN_MENU,&num);
	disp_menu(main_menu,num);
	(void) fflush(stdin);
	do_menu(main_menu,num);
}
SHAR_EOF
fi
if test -f 'menu.h'
then
	echo shar: "will not over-write existing file 'menu.h'"
else
cat << \SHAR_EOF > 'menu.h'
/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

# define 	FOURK		4096
# define 	ONEK		1024
# define	BUF_SIZ		256
# define	LINESZ		80
# define 	FIRST_LINE	0
# define	STATUS_LINE	22
# define	NUMCOL		22
# define	DESCOL		25
# define 	LAST_LINE	23
# define 	CONT_LINE	21
# define 	N_ENTRIES	9
# define 	RE_DRAW		('r' & 037)
# define 	MAIN_MENU	"menu.1"
# define	MENU_DIR	"/usr/local/lib/menus/"
# define	CR		0x0d
# define	LF		0x0a
# define	SPACE		0x20
# define	TRUE		1
# define	FALSE		0
# define 	CENTER		40
# define 	HEADER		"Plymouth State College Menu System"
# define	CMD_LIN		"h)elp q)uit"


int catch();

typedef struct
{
	char key;
	char desc[LINESZ];	/* description of cmd 	*/
	char cmd[LINESZ];  	/* The Command		*/
/*      char help_fil[LINESZ];  Name of the Help file for option. */
}menu_ent;

menu_ent main_menu[N_ENTRIES];

typedef int FLAG;

FLAG m_flag;

char line[BUF_SIZ], buffer[BUF_SIZ], string[BUF_SIZ];
char menu_dir[BUF_SIZ];
int len;

int get_term();
SHAR_EOF
fi
if test -f 'menu.man'
then
	echo shar: "will not over-write existing file 'menu.man'"
else
cat << \SHAR_EOF > 'menu.man'
.TH MENU 1 "June 1990" "Newwords+ Manual"
\.@(#)menu.1 1.1 90/06/31 SMI;
.SH NAME
menu \- Runs the PSC Menu System.
.SH SYNOPSIS
menu [ menu_directory ]
.SH DESCRIPTION
Menu is a menu system that is capable of doing any unix command 
from the "menu".  The individual menus are read from menu files that
are located in a "menu" directory.  The menu files are simple text files
that may be edited with any editor.  The "menu" is flexable, the only
command line argument that is accepted is the name of a directory in which
the menu files are located.  A default directory is specified in the
menu header file.
.SH SELECTING ITEMS & USING BUILTIN COMMANDS
An item is selected from the menu simply by entering the corresponding
number that is displayed for the item.  It is important to know that
you should not enter the selection and then press return.  The return key
has a special function.  The return key tells the menu to back up one
menu unless you are in the main menu, where it haas no effect.  The PSC
menu system contains built in commands that allow you to: change directory,
execute a shell command, do directory listings, quit menu, help and re-draw
the screen. See the section on the "Built in Menu" for more details.
.SH BUILT IN MENU
The Built in menu is a pop-up window that displays a list of builtin commands
accessable.  This menu is accessed by entering the letter 'h' from any
menu accept the builtin menu.  Options in this menu are: 'q','d','l','x','c'
and <ctrl-R>.  These characters cause the following affects:
.PP
\'h' - Use the builtin help menu.
.PP
\'d' - Get a short directory listing of the current directory.
.PP
\'l' - Get a long directory listing of the current directory.
.PP
\'x' - Execute a shell command.
.PP
\'c' - Change to a new working directory.
.PP
\'q' - Quit the Menu.
.PP
\<ctrl-R> Re-draw the screen in cases where you get garbled. (control
key and 'R' are pressed at the same time).

.SH MENU FILES
The Menu files have a specific format that must be followed.  The first
character in each line must be '$', '+', '*', '&', '?', '1', '2', '3', '4'.
These are "key" characters that tell "menu" what kind of operation is to
be performed.
.PP
\'$'     This character means that this line is the menu header for this
menu, this must be the first character in the line.
This must always be the first line in the "menu" file.  The second
character in this line is skipped anything after the second column is
interpreted as the menu heading.
.PP
\'+'     This character means that output from the name program be 
output to the "menu" window.  It is best if the output is 70 columns
wide or less.  Some good examples are ls and ls -l.  Any program which
actually does screen manipulation cannot use the '+' option (It Will really
get messed up).
.PP
\'@'	 This character specifies that the menu to be loaded is to
be considered the main menu so that pressing return will not do anything.
.PP
\'&'	 This character specifies a menu to be loaded.  The path to the menu
file is the default or the specified one given in the command argument.
.PP
\'*'	 This character means that the invoked program will interfere with
the "menu" window.  Such programs include more, less and any games.
.PP
\'1'	 This character specifies that one file name is expected as an argument
for the program to be run.  A good example would be: vi <filename>.
.PP
\'2'	 This character specifies that two file names are expected as
arguments for the program to be run.  A good exmample would be:       
cp <file1> <file2>.
.PP
\'3'	 This character specifies that a user name is expected as an argument
for the program to be run.  A good exapmple would be:	mail <user>.
.PP
\'4'	 This character specifies a topic to be used as an argument to the 
program to be run.  A good example would be:	man <topic>.

.SH DEFAULTS
	The menu program looks for a file called "menu.1" in the default
or specified directory.  If the Directory does not exist or is not accessable
the program will tell you of the condition and quietly exit.  If the file
"menu.1" does not exist in the named directory the program will notify you
that it could not find any menu files and quietly exits.  The return key
if pressed will do the last thing in the menu, unless that menu is defined
to be the main menu (this is done to make it easy to back out of menus
assuming of course that return to previous menu is that last option in that
menu).
.SH EXAMPLE MENU FILE
.nf
$ File Management Menu
2 /bin/mv -i
? Rename a file.
2 /bin/cp -i
? Copy a file.
1 rm -i
? Remove a single file.
* rm -i *
? Cleanup your files.
+ /bin/ls
? List your Files.
& menu.1
? Return to main Menu.
.fi

.SH CAUTIONS
If you use the '+' menu command that tells the menu program to send
output to the menu window with a command that uses cursor addressing
or requires user input you may get some rather interesting results.
SHAR_EOF
fi
if test -f 'signals.c'
then
	echo shar: "will not over-write existing file 'signals.c'"
else
cat << \SHAR_EOF > 'signals.c'
# include <signal.h>
# include "menu.h"

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

setup_sigs()
{
	(void) signal(SIGSEGV,catch);
	(void) signal(SIGBUS,catch);
	(void) signal(SIGINT,SIG_IGN);
	(void) signal(SIGTSTP,SIG_IGN);
	(void) signal(SIGQUIT,SIG_IGN);
}

catch(signo)
int signo;
{
	switch (signo){
	   case SIGSEGV:
	   case SIGBUS:
		clr_scr();  
	        reset_tty();
	        end_rev();
		perror(" ");
		exit(1);
	   break;
	}
}
SHAR_EOF
fi
if test -f 'utils.c'
then
	echo shar: "will not over-write existing file 'utils.c'"
else
cat << \SHAR_EOF > 'utils.c'
# include "utils.h"
# include <ctype.h>
# include <sys/ioctl.h>

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

/*
	This file contains basic low level utilities.
*/

int get_term()
/*
   	This routine gets the terminal specific escape sequences
   	and saves them in the appropriate variable for use by
   	tputs() and tgoto()
*/
{
	char bp[1024], termtype[MAXL];
	static char buf[100];
	char *buf_ptr = buf;

	if(getenv("TERM") != NULL)
	   (void) strcpy(termtype, getenv("TERM"));
	if(tgetent(bp,termtype) != 1)
	   return(-1);
	if((CL = tgetstr("cl",&buf_ptr)) == (char *)NULL)
	   return(-1);
	if((CM = tgetstr("cm",&buf_ptr)) == (char *)NULL)
	   return(-1);
	if((CE = tgetstr("ce",&buf_ptr)) == (char *)NULL)
	   return(-1);
	if((SO = tgetstr("so",&buf_ptr)) == (char *)NULL)
	   return(-1);
	if((SE = tgetstr("se",&buf_ptr)) == (char *)NULL)
	   return(-1);
}

outc(c)
int c;
/*
	This routine puts a single character out to the screen
	at the current location.
*/
{
	(void) fputc(c,stdout);
}

move_csr(x,y)
int x,y;
/*
   	This routine is used to move the cursor to a new position
   	on the screen.
*/
{
	tputs(tgoto(CM,x,y),1,outc);
}

clr_scr()
/*
	This routine clears the screen and leaves the cursor in the
	upper left corner of the screen.
*/
{
	tputs(CL,1,outc);
}

clr_line()
/*
	This routine clears from the current cursor position to
	the end of the line.
*/
{
	tputs(CE,1,outc);
}

start_rev()
/*
	Start the reverse video mode.
*/
{
	tputs(SO,1,outc);
}

end_rev()
/*
	End the reverse video mode.
*/
{
	tputs(SE,1,outc);
}

print_str(string)
char *string;
/*
	Print an entire string to the screen.
*/
{
	(void) fputs(string,stdout);
}

hi_lite(string)
char *string;
/*
	Hi-lite a string that will be printed.
*/
{
	start_rev();
	print_str(string);
	end_rev();
}

save_tty() 
/*
	Save Terminal characteristics Reset by call to reset_tty().
*/
{
  	(void) ioctl(0, TCGETA, &ter_old);
}

reset_tty() 
/*
	This routine returns the terminal to the same state it
	had before this program was invoked.
*/
{
  (void) ioctl(0, TCSETA, &ter_old) ;
}

crmode()
/*
	Turn on CRmode.
*/
{
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag |= CRMOD;
	(void) ioctl(0,TCSETA,&ter_des);
}

no_crmode()
/*
	Turn off CRmode.
*/
{
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag &= ~CRMOD;
	(void) ioctl(0,TCSETA,&ter_des);
}

echo()
/*
	Turn echo back on.
*/
{
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag |= ECHO;
	(void) ioctl(0,TCSETA,&ter_des);
}

no_echo()
/*
	Turn off echo.
*/
{
	struct termio ter_des;
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag &= ~ECHO;
	(void) ioctl(0,TCSETA,&ter_des);
}

no_cbreak()
/*
	Take the terminal out of cbreak mode.
*/
{
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag |= CBREAK;
	(void) ioctl(0,TCSETA,&ter_des);
}

cbreak()
/*
	Place the Terminal in Cbreak mode.
*/
{
	(void) ioctl(0,TCGETA,&ter_des);
	ter_des.c_lflag &= ~CBREAK;
	(void) ioctl(0,TCSETA,&ter_des);
}
	
rm_lf(array)
char *array;
/*	
	Remove Trailing line feed from a line.
*/
{
	array[strlen(array)-1] = NULL;
}

read_str(string)
char *string;
{
	char *str;

	str = string;
	while((*str = getchar()) != LF && *str != CR){
	   if(*str ==  DEL  || *str == BS)
	      if(*str != *string){
		 outc(DEL);
		 outc(SPACE);
		 outc(DEL);
		 *str--;
	      }else
		 continue;
	   else{
	      outc(*str);
	      *str++;
	   }
	}
	*str = LF;
}

clear_array(array)
char *array;
{
	for(;*array != NULL;*array++)
		*array = NULL;
}

	
SHAR_EOF
fi
if test -f 'utils.h'
then
	echo shar: "will not over-write existing file 'utils.h'"
else
cat << \SHAR_EOF > 'utils.h'
# include <stdio.h>
# include <termio.h>

/*	PSC MENU COPYRIGHT NOTICE

	Part of PSCMenu

	This software is to be considered to be public domain, it
may be copied, modified and parts of it may be used in other programs
as long as this copyright notice remains intact.

	Copyright()   PSC - Plymouth State College
	Written by:   Ted Wisniewski 12-9-1990
 
*/

# define 		MAXL		80
# define  		THIS_TTY	0
# define		DEL		0x08
# define		BS		0x7f
# define		SPACE		0x20
# define		LF		0x0a
# define 		CR		0x0d

char *SO, *SE, *CE, *CM, *CL;

char *getenv(), *tgetstr(), *tgoto();

int outc();

struct termio ter_old, ter_des;

SHAR_EOF
fi
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
Install Notes for Menu1.1

	This Menu system should compile on just about any machine.  Since
I have only one type to work with I cannot be absolutely sure of this.
I have successfully compiled and run it in and Ultrix environment (the
compiler is really picky).

To compile:

	unshar the shell archive via: % sh menu.shar
	
	then edit the header file "menu.h" and the Makefile to set 
	appropriate paths for your system.
	
	then
	
	do: % make

To Test:

	do: % ./menu ./demos

	This should show you a working example of how this menu
	works, the demo is set up for what this site is using so
	the applications called may not be on your system.


To install:

	do: % make install 

Problems or Questions:

	Send E-Mail to: ted@oz.plymouth.edu
		    or  uunet!unhd!oz!ted

	Please do not post questions directed to me to the net, we
	have some problems with our news feed.  Generally we somtimes
	get the news 2 weeks late or not at all due to something down
	the line from us.


Present & Future:

	At the present time menu has proved to be bug free, but there
is a possibility there are bugs.  Menu has been Beta-tested for 4 months
and has been used by hundreds of users successfully.  In the future I
plan to implement a help file to be associated with each menu option.  
The help file will allow the "menu" administrator to specify help files
for the menu options within the menu definition file to aid users
unfamiliar with the specific application.
SHAR_EOF
fi
if test ! -d 'demos'
then
	mkdir 'demos'
fi
cd 'demos'
if test -f 'menu.1'
then
	echo shar: "will not over-write existing file 'menu.1'"
else
cat << \SHAR_EOF > 'menu.1'
$ PSC Menu Executive
& menu.4
? Use the Help Menu.
& menu.5
? Word processing & editing.
& menu.7
? File Management Menu.
& menu.8
? Misc Menu.
& menu.3
? Communications Menu.
& menu.2
? The Math Menu.
& games/menu.1
? Recreation Menu.
SHAR_EOF
fi
if test -f 'menu.2'
then
	echo shar: "will not over-write existing file 'menu.2'"
else
cat << \SHAR_EOF > 'menu.2'
$ Math Menu
* /usr/psc/min
? Minitab statisical program.
* /usr/psc/finite
? Use the finite math menu.
* /usr/psc/amortf
? Amort: full report.
* /usr/psc/amort
? Amort: short report.
* /usr/psc/calc
? Desk Calculator.
@ menu.1
? Return to Main Menu.
SHAR_EOF
fi
if test -f 'menu.4'
then
	echo shar: "will not over-write existing file 'menu.4'"
else
cat << \SHAR_EOF > 'menu.4'
$ Help Menu
* cat /usr/tmp/menus/help
? Get help on this menu System.
* /usr/psc/help 
? Use the online help facility.
* /usr/psc/tutorial
? Use the unix tutorial.
4 apropos
? Lookup system commands.
4 /usr/ucb/man
? Read the manual.
@ menu.1
? Return to main Menu.
SHAR_EOF
fi
if test -f 'menu.5'
then
	echo shar: "will not over-write existing file 'menu.5'"
else
cat << \SHAR_EOF > 'menu.5'
$ Wordprocessing Menu
* /usr/psc/uniplex
? Uniplex office automation.
1 /usr/psc/pfs
? Use the "pfs" look-alike.
1 /usr/psc/nws
? Use the Word Star look-alike.
1 /usr/ucb/vi
? Use the "vi" Editor.
1 /usr/psc/gemacs
? Use The Gemacs Editor.
+ /bin/ls
? List your files.
@ menu.1
? Return to main menu.
SHAR_EOF
fi
if test -f 'menu.6'
then
	echo shar: "will not over-write existing file 'menu.6'"
else
cat << \SHAR_EOF > 'menu.6'
$ File & disk Information.
+ /bin/ls
? A short listing of your files.
+ /bin/ls -l
? A long listing of your files.
* /usr/ucb/quota -v
? Check your disk quota.
& menu.7
? Return to main menu.
SHAR_EOF
fi
if test -f 'menu.7'
then
	echo shar: "will not over-write existing file 'menu.7'"
else
cat << \SHAR_EOF > 'menu.7'
$ File Management Menu
2 /bin/mv -i
? Rename a file.
2 /bin/cp -i
? Copy a file.
1 rm -i
? Remove a single file.
* rm -i *
? Cleanup your files.
+ /bin/ls
? List your Files.
& menu.6
? File & Disk Infromation.
@ menu.1
? Return to main Menu.
SHAR_EOF
fi
if test -f 'menu.8'
then
	echo shar: "will not over-write existing file 'menu.8'"
else
cat << \SHAR_EOF > 'menu.8'
$ Miscellaneous Menu
+ /bin/who
? Who is logged on.
+ /usr/ucb/w -s
? What's up?
3 /usr/ucb/last
? Checks last log on's.
@ menu.1
? Return to main Menu.
SHAR_EOF
fi
if test -f 'help'
then
	echo shar: "will not over-write existing file 'help'"
else
cat << \SHAR_EOF > 'help'
Menu Help:

To select an item:

	Just enter the apropriate number for your request no <Return> needed.
	
To change Directory:

	Enter the letter 'c' from any menu.
	You will be prompted for the new directory.

To execute a Unix Command:

	Enter the letter 'x' from any menu.
	You will be prompted to enter a Unix Command.

To Quit:

	Enter the letter 'q' from any menu.
	
To Re-Draw the screen:

	Hit The <ctrl> and 'r' keys at the same time.
SHAR_EOF
fi
if test ! -d 'games'
then
	mkdir 'games'
fi
cd 'games'
if test -f 'menu.1'
then
	echo shar: "will not over-write existing file 'menu.1'"
else
cat << \SHAR_EOF > 'menu.1'
$ PSC Recreation Menu
+ cat /usr/tmp/games/info
? Get some Information.
& games/menu.3
? Arcade Games
& games/menu.5
? Casino
& games/menu.2
? Dungeon Games
& games/menu.4
? Other Games
@ menu.1
? Return Original Menu
SHAR_EOF
fi
if test -f 'menu.2'
then
	echo shar: "will not over-write existing file 'menu.2'"
else
cat << \SHAR_EOF > 'menu.2'
$ Role Playing & Adventure
* /usr/games/moria
? Moria:  2-D Dungeon Game.
* /usr/games/castle
? Castle: 3-D Dungeon Game.
* /usr/games/Ularn
? Ularn:  2-D Dungeon Game.
* /usr/games/rogue
? Rogue:  2-D Dungeon Game.
& games/menu.1
? Return to the Main Menu.
SHAR_EOF
fi
if test -f 'menu.3'
then
	echo shar: "will not over-write existing file 'menu.3'"
else
cat << \SHAR_EOF > 'menu.3'
$ Arcade Games
* /usr/games/tt
? Play Tetris.
* /usr/games/snake
? Snake: Avoid the Snake.
* /usr/tmp/wanderer
? Wanderer: Solve a puzzle.
* usr/games/worm
? Worm: 
& games/menu.1
? Return to the Main Menu.
SHAR_EOF
fi
if test -f 'info'
then
	echo shar: "will not over-write existing file 'info'"
else
cat << \SHAR_EOF > 'info'
Games Information:

	Many of the games have restricted hours during the 
	semester.
SHAR_EOF
fi
if test -f 'menu.4'
then
	echo shar: "will not over-write existing file 'menu.4'"
else
cat << \SHAR_EOF > 'menu.4'
$ Other Games.
* /usr/games/fish
? Fish:     Card Game.
* /usr/games/ttt
? ttt:      Tic-Tac-Toe.
* /usr/tmp/othello
? Othello
* /usr/games/hangman
? Hangman
& games/menu.1
? Return to Main Menu.
SHAR_EOF
fi
if test -f 'Idea'
then
	echo shar: "will not over-write existing file 'Idea'"
else
cat << \SHAR_EOF > 'Idea'
>From pyr203 Tue Jun  5 15:08:56 1990
Received: by psc90.UUCP (5.51/smail2.5/06-02-89)
	id AA13720; Tue, 5 Jun 90 15:08:52 EDT
Date: Tue, 5 Jun 90 15:08:52 EDT
>From: pyr203 (Dragonsbane)
Message-Id: <9006051908.AA13720@psc90.UUCP>
To: ted
Status: O

Okay, here's my suggestion for a Games menu:
	Main menu:
		Arcade
		Casino
		Dungeon
		Other

	Arcade:
		Snake
		Tetris
		Wanderer
		Worm

	Casino:
		Blackjack
		Craps
		Yahtzee

	Dungeon:
		Castle
		Moria
		Rogue
		Ularn

	Other:
		Fish
		Hangman
		Othello
		Tic-Tac-Toe

Also, I was thinking that you might consider putting the random maze
generator under Dungeon games, but you would have to include the commands
to redirect it to another file. Otherwise, you don't get the entire maze.
Besides that, all you do get is a maze printout to "solve at home", rather
than try to solve it on the computer. Although that wuldn't be a bad idea...

								JEV

SHAR_EOF
fi
if test -f 'menu.5'
then
	echo shar: "will not over-write existing file 'menu.5'"
else
cat << \SHAR_EOF > 'menu.5'
$ Casino Games
* /usr/games/blackjack
? Blackjack.
* /usr/games/craps
? Craps.
* /usr/games/yahtzee
? Yahtzee.
& games/menu.1
? Return to Main Menu.
SHAR_EOF
fi
cd ..
if test -f 'menu.3.bup'
then
	echo shar: "will not over-write existing file 'menu.3.bup'"
else
cat << \SHAR_EOF > 'menu.3.bup'
$ Communications Menu
* /usr/psc/elm 
? Use the "elm" mailer.
3 /usr/ucb/mail 
? Send mail to another user.
3 /usr/ucb/talk
? Talk to another user.
* /usr/psc/rn
? Read News.
* /usr/psc/kermit 
? Use Kermit
@ menu.1
? Return to main Menu.
SHAR_EOF
fi
cd ..
cd ..
exit 0
#	End of shell archive

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@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@uunet.uu.net.