[alt.sources] simple_menu program - part1/2

how@milhow1.UU.NET (Mike Howard) (03/26/91)

Submitted-by: Mike Howard <how%milhow1@uunet.uu.net>
Archive-name: simple_menu/part01

I'm looking for suckers to test this - please reply by e-mail to
  how%milhow1@uunet.uu.net

  Currently compiles and appears to work on Sun SparcStation 4.1.1,
  SCO Xenix 2.3.3 and SCO UNIX 3.2.  This is the third version I've
  done so I have some expectation that it should not foul up too badly.

  simple_menu - executes a simple menus

  This is a new version of my 'simple/dumb' menu program.  The goal of
this project is to write a simple menu shell which handles the user
response loop and simplifies writing and maintaining user menus.  Only
rudimentary pick-one-of-N menus are supported with optional parameters.

  For those people (if there are any) who have actually mucked with
my two previous attempts: the changes in this version are:
 o  menu-environment variables to allow dynamic customization of menus
    on the basis of users and system administration changes
 o  assignable command processor path and variable assignment format
 o  some bug fixes - in particular, hitting return at the menu prompt
    does not cause the program to exit.
 o  restructuring the code so that display and user interaction is more
    modular.  This is in anticipation of creating an X version of this
    thing.  Currently, only character based terminals which can be
    controlled by termcap or terminfo character control are supported.

  Menu actions are either to call a sub-menu or to run a shell script.

  Shell scripts are run by writing variable definitions to a temp file
followed by copying a supplied shell script and then feeding this to
a command interpreter.  The command interpreter and assignment format
default to Bourne shell - but can be changed on either the command line
(dumb) or in the menu itself [what do you think? should I chuck the
command line option? - does it have *any* real use or is it dangerous?].

  Some dynamic customization of menus is supported by 'menu-environment'
variables.  These are variables which take their values from either the
user's environment [from-env type] or from a specified file [from-file type].
In both cases, default values can be supplied in the menu.  Also, in both
cases, all menu-environment variables are defined in the shell script
fed to the command interpreter.

  Take a look at 'menu.def' to see an example of a menu definition.

  The Makefile should be pretty straightforward to modify.  In general,
you will not need more than one entry in MENUPATH - but it does take colon
separated path names.

  After building, try './simple_menu -M .' in the build-directory in
order to test it.  That will fire it up using the sample menu.def file.
This exercises all the options I normally (and some I don't) use.  If you
find some cases which make it die, please document and mail them to me
for update.

Mike Howard
how@milhow1.uunet.uu.net
--------------------------------cut here--------------------------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  MANIFEST Makefile README directory ev-values grammar.y
#   login.menu menu.def patchlevel.h prototypes.h scanner.c
#   simple_menu.h sub.menu tty_display.c
# Wrapped by mike@milhow4 on Mon Mar 25 16:45:32 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(610 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	This shipping list
X Makefile                   1	
X README                     1	
X directory                  1	
X ev-values                  1	
X grammar.y                  1	
X login.menu                 1	
X menu.def                   1	
X patchlevel.h               1	
X prototypes.h               1	
X scanner.c                  1	
X simple_menu.1              2	
X simple_menu.c              2	
X simple_menu.h              1	
X sub.menu                   1	
X tty_display.c              1	
END_OF_FILE
if test 610 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(3176 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# installation info
XBINDIR	=	/usr/local/bin
XMENUPATH	=	/usr/local/lib/simple_menu:/usr/local/lib/dumb_menu
XLIBDIR	=	/usr/local/lib/simple_menu
XMANDIR	=	/usr/local/man/man1
XMANEXT	=	1
XINSTALL	=	install
XINSTALL_BIN_OPT	=	-c -m 755
XINSTALL_MAN_OPT	=	-c -m 644
X# INSTALL	=	cp
X# INSTALL_BIN_OPT	=
X# INSTALL_MAN_OPT	=
X
X# pick one which works
XVOID_FLAG	=	-DVOID=void
X# VOID_FLAG	=	-DVOID=void -DPROTOTYPES_OK
X# VOID_FLAG	=	-DVOID=int
X# VOID_FLAG	=	-DVOID=int -DPROTOTYPES_OK
X
X# os independant compiler flag(s)
XCIND_FLAGS	=	-g $(VOID_FLAG) -DDEFAULT_MENU_PATH=\"$(MENUPATH)\"
X# CIND_FLAGS	=	-O $(VOID_FLAG) -DDEFAULT_MENU_PATH=\"$(MENUPATH)\"
X
X# sun4 sys V compatability
XCC	=	/usr/5bin/cc
X# CC	=	cc
X
X# SYS V
XCFLAGS	=	$(CIND_FLAGS) -DTERMINFO
XLDFLAGS	=	-lcurses
X
X# BSD with termcap & BSD style tty inteface
X# CFLAGS	=	$(CIND_FLAGS) -DBSDTTY -DTERMCAP
X# LDFLAGS	=	-ltermcap
X
X# BSD or SCO Xenix with termcap & termio style tty inteface
X# CFLAGS	=	$(CIND_FLAGS) -DTERMIO -DTERMCAP
X# LDFLAGS	=	-ltermcap
X
X# SCO Xenix small model with termcap & termio style tty inteface
X# CFLAGS	=	$(CIND_FLAGS) -DTERMIO -DTERMCAP -M0s
X# LDFLAGS	=	-ltermcap
X
X#  shouldn't have to change below here
X
X# C source files
X# Yacc source files
XYSRC	=	grammar.y
XYCCC	=	grammar.c
XYOBJ	=	grammar.o
XOBJS	=	simple_menu.o disp.o $(YOBJ) scanner.o
XDISP_OBJ	=	tty_display.o
X
XHDRS	=	patchlevel.h simple_menu.h prototypes.h
XSRC	=	simple_menu.c $(YSRC) scanner.c $(HDRS)
XCSRC	=	simple_menu.c $(YCCC) scanner.c tty_display.c
X
XMISC_SRC	=	simple_menu.1 menu.def sub.menu login.menu \
X			directory README ev-values
XDISP_SRC	=	tty_display.c
X
Xsimple_menu :  $(OBJS)
X	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) -o simple_menu
X
X$(YCCC) : $(YSRC)
X	$(YACC) -d $(YSRC)
X	mv y.tab.c $(YCCC)
X
Xscanner.o : scanner.c y.tab.h $(HDRS)
X$(YOBJ) : $(YCCC) $(HDRS)
Xdisp.o : $(DISP_OBJ)
X	cp $(DISP_OBJ) disp.o
X$(DISP_OBJ) simple_menu.o scanner.o : $(HDRS)
X
Xprt : $(SRC) $(DISP_SRC)
X	for x in $? ; do \
X	/usr/5bin/pr -f -l60 -e8 -o2 $$x | rsh milhow1 -l how 'lp -dlaser' ;\
X	done
X	touch prt
X
X# uses an automatic prototype generator
Xprototypes.h :
X	echo "#ifdef PROTOTYPES_OK" >p-tmp.h
X	cproto $(CFLAGS) -p2 $(CSRC) >>p-tmp.h
X	echo "" >>p-tmp.h
X	echo "#else /* PROTOTYPES_OK */" >>p-tmp.h
X	cproto $(CFLAGS) -p1 $(CSRC) >>p-tmp.h
X	echo "#endif /* PROTOTYPES_OK */" >>p-tmp.h
X	mv p-tmp.h prototypes.h
X
Xtar :
X	format /dev/rfd096ds9
X	tar cvf /dev/fd096ds9 $(SRC) $(DISP_SRC) \
X		Makefile $(MISC_SRC) \
X		simple_menu simple_menu.0s
X
Xtar.kit :
X	rm -f tar.file.z
X	tar cvf tar.file $(SRC) $(DISP_SRC) \
X		Makefile \
X		$(MISC_SRC) \
X		simple_menu simple_menu.0s
X	pack tar.file
X
Xclean :
X	rm -f $(OBJS) $(YCCC) y.tab.h
X
Xvery.clean :
X	make clean
X	rm -f simple_menu
X
Xinstall : simple_menu simple_menu.1
X	$(INSTALL) $(INSTALL_BIN_OPT) simple_menu $(BINDIR)
X	$(INSTALL) $(INSTALL_MAN_OPT) simple_menu.1 \
X		$(MANDIR)/simple_menu.$(MANEXT)
X	[ ! -s $(LIBDIR) ] || mkdir $(LIBDIR)
X
Xkit : $(SRC) $(DISP_SRC) Makefile $(MISC_SRC)
X	makekit -m $(SRC) $(DISP_SRC) Makefile $(MISC_SRC)
X	touch kit
X
Xmake-patches :
X	rm -f patches
X	for x in MANIFEST \
X		$(SRC) $(DISP_SRC) Makefile \
X		$(MISC_SRC) ; do \
X		echo "\nIndex: $$x" >>patches ;\
X 		cdiff RLSDIR/$$x ./$$x >>patches ;\
X	done
END_OF_FILE
if test 3176 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(2514 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X  simple_menu - executes a simple menus
X
X  This is a new version of my 'simple/dumb' menu program.  The goal of
Xthis project is to write a simple menu shell which handles the user
Xresponse loop and simplifies writing and maintaining user menus.  Only
Xrudimentary pick-one-of-N menus are supported with optional parameters.
X
X  For those people (if there are any) who have actually mucked with
Xmy two previous attempts: the changes in this version are:
X o  menu-environment variables to allow dynamic customization of menus
X    on the basis of users and system administration changes
X o  assignable command processor path and variable assignment format
X o  some bug fixes - in particular, hitting return at the menu prompt
X    does not cause the program to exit.
X o  restructuring the code so that display and user interaction is more
X    modular.  This is in anticipation of creating an X version of this
X    thing.  Currently, only character based terminals which can be
X    controlled by termcap or terminfo character control are supported.
X
X  Menu actions are either to call a sub-menu or to run a shell script.
X
X  Shell scripts are run by writing variable definitions to a temp file
Xfollowed by copying a supplied shell script and then feeding this to
Xa command interpreter.  The command interpreter and assignment format
Xdefault to Bourne shell - but can be changed on either the command line
X(dumb) or in the menu itself [what do you think? should I chuck the
Xcommand line option? - does it have *any* real use or is it dangerous?].
X
X  Some dynamic customization of menus is supported by 'menu-environment'
Xvariables.  These are variables which take their values from either the
Xuser's environment [from-env type] or from a specified file [from-file type].
XIn both cases, default values can be supplied in the menu.  Also, in both
Xcases, all menu-environment variables are defined in the shell script
Xfed to the command interpreter.
X
X  Take a look at 'menu.def' to see an example of a menu definition.
X
X  The Makefile should be pretty straightforward to modify.  In general,
Xyou will not need more than one entry in MENUPATH - but it does take colon
Xseparated path names.
X
X  After building, try './simple_menu -M .' in the build-directory in
Xorder to test it.  That will fire it up using the sample menu.def file.
XThis exercises all the options I normally (and some I don't) use.  If you
Xfind some cases which make it die, please document and mail them to me
Xfor update.
X
XMike Howard
Xhow@milhow1.uunet.uu.net
END_OF_FILE
if test 2514 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'directory' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'directory'\"
else
echo shar: Extracting \"'directory'\" \(227 characters\)
sed "s/^X//" >'directory' <<'END_OF_FILE'
Xsimple_menu.1:The Manual Page
Xscanner.c:The Lexical Analyzer
Xsimple_menu.c:Main Program
Xgrammary.y:The Parser
Xtty_display.c:A tty display handler
Xsimple_menu.h:Function definition header file
Xprototypes.h:Prototype definitions
END_OF_FILE
if test 227 -ne `wc -c <'directory'`; then
    echo shar: \"'directory'\" unpacked with wrong size!
fi
# end of 'directory'
fi
if test -f 'ev-values' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ev-values'\"
else
echo shar: Extracting \"'ev-values'\" \(111 characters\)
sed "s/^X//" >'ev-values' <<'END_OF_FILE'
X# environment file definitions
X
XEV_FROMFILE_NO_INIT = a new value
X
XEV_FROMFILE_DEFINED = the non-default value
END_OF_FILE
if test 111 -ne `wc -c <'ev-values'`; then
    echo shar: \"'ev-values'\" unpacked with wrong size!
fi
# end of 'ev-values'
fi
if test -f 'grammar.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'grammar.y'\"
else
echo shar: Extracting \"'grammar.y'\" \(9787 characters\)
sed "s/^X//" >'grammar.y' <<'END_OF_FILE'
X%{
X/* %W% %D% */
X
Xstatic char *cpy_str =
X  "Copyright (c), Mike Howard, 1990,1991 all rights reserved";
X
X/* Conditions of use:
X
X   This software is not for sale and is not to be sold by or
X   to anyone.
X
X   You may use this software and may distribute it to anyone
X   you wish to provided you distribute the entire distribution
X   package w/o any deletions (i.e. include all the source code).
X
X   I do not warrent this software to do anything at all and
X   am not responsible for anything which happens as a result of
X   its use.
X*/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <string.h>
X#include <signal.h>
X#include <ctype.h>
X#include "simple_menu.h"
X#include "patchlevel.h"
X
X
X/* Menu definition files begin with an optional environment definition
X   section followed by a manditory menu definition section.
X
X   The environment definition section consists of one or more environment
X   variable declarations of the forms:
X
X   shell-path = 'path' ;
X
X   asg-fmt = 'format' ; # default is asg-fmt = '"%s=\"%s\"\n"' ;
X
X   from-env "NAME" ;
X
X   from-env "NAME" = 'default value' ;
X
X   from-file 'file-path' "NAME" ;
X
X   from-file 'file-path' "NAME" = 'default value' ;
X
X   from-env variables are initialized from the environment.  from-file
X   variables are initialized from the first value in the file named
X   file-path which is of the form:
X
X      NAME = string
X
X   In either case, default values of the Null string or a specified string
X   can be defined.
X
X   Environment variables are evalutated after the menu file is parsed and
X   before the top level menu is displayed.
X
X   Environment variables are defined in the environment shell items
X   execute in.  Their definition precedes local parameter definitions,
X   so local parameters can be used to over-ride their value.
X
X
X   Menu definitions begin with a main menu definition, optionally
X   followed by submenu definitions.  The main menu is automatically
X   given the name MAIN, so it may begin with a title directive.
X   
X   title 'text for the title'
X   
X   This is followed by zero or more of the following parameters, which
X   do the `obvious' things:
X   
X   bold clear always-show once wait alpha
X   
X   This is followed by one or more menu-item definitions of the form:
X   
X   prelude 'prompt' %( shell command %)
X   parm "name" 'prompt'
X   parm "name" = 'initializer' 'prompt'
X   parm "name" = "name" 'prompt'
X   ;
X   
X   epilogue 'prompt' %( shell command %)
X   parm "name" 'prompt'
X   parm "name" = 'initializer' 'prompt'
X   parm "name" = "name" 'prompt'
X   ;
X   
X   SHELL 'prompt' %( shell command %)
X   parm "name" 'prompt'
X   parm "name" = 'initializer' 'prompt'
X   parm "name" = "name" 'prompt'
X   ;
X   
X   do-menu "menu-name" 'prompt'
X   ;
X   
X   skip ;
X
X   Only one prelude and epilogue are allowed per menu.
X
X   Parameters default values may be set in one of three ways:
X    parm "name" 'prompt' - default is ""
X    parm "name" = 'string' 'prompt' - default is "string"
X    parm "name" = "ev-name" 'prompt' - default is the value of the
X               environment variable ev-name
X
X   Shell scripts are run by creating a command file and feeding it to
X   a shell.  The sequence is:
X    1. user interactively fills in values for local parameters
X    2. copy all global variables definition strings to temp file
X    3. copy all local parameter definitions to temp file
X    4. copy shell script to temp file
X    5. fork a shell and feed it the temp file - wait for completion
X    6. delete the temp file.
X   
X   text can be written in one of three ways:
X   1. bound by curly braces { & }
X     in which case } and \ are written as by escaping with a backslash
X     character
X   2. bound by %( & %), in which case %( and and %) are written
X     by doubling (trippling, ...) the percent sign.
X   3. bound by single quote marks ', in which case a single quote
X     mark is written by doubling - 'foo''s dog' -> foo's dog
X   
X   The text in between the double quotes may ONLY contain letters, digits,
X   and underscores;
X   
X   Sub-menus begin with the sequence:
X   
X   menu "menu-name"
X   
X   followed by definitions as for the main menu.
X   
X   comments are delimited on the left by a '#' sign and on the
X   right by the end of line.  In-line comments are allowed.
X   
X   Sub-menus can also be formed by running simple_menu as the shell process,
X   pointed to an appropriate sub-menu definition file.
X   
X   There is no provision for menus which require more than one screen 
X   to display.
X   */
X
X%}
X
X%union {
X  int ival;
X  char *txt;
X  char chr;
X  double dbl;
X  struct item *itm;
X  struct parm *prm;
X  struct ev_var *ev;
X  struct menu *mnu;
X}
X
X%token <ival> NUMBER
X%token <dbl> FLOAT
X%token <txt> TEXT NAME
X%token MENU
X%token SHELL_PATH ASG_FMT
X%token FROM_ENV FROM_FILE
X%token PARM SHELL TITLE ERROR SKIP DO_MENU PRELUDE EPILOGUE
X%token CLEAR BOLD ALWAYS_SHOW ONCE ALPHA WAIT
X
X%type <ival> menu_flags menu_flag
X%type <itm> item
X%type <prm> parm
X%type <ev> ev_list ev_var
X%type <mnu> menu title
X
X%%
X
Xmenu_def_file : ev_list menu_list
X	| menu_list
X	;
X
Xev_list : ev_var
X	| ev_list ev_var
X	;
X
Xev_var : SHELL_PATH '=' TEXT ';'
X	{
X	  cmd_path = $3;
X	}
X	| ASG_FMT '=' TEXT ';'
X	{
X	  asg_fmt = $3;
X	}
X	| FROM_ENV NAME ';'
X	{
X	  $$ = make_new_ev_var(EV_FROM_ENV, $2, (char *)0, (char *)0);
X	  $$->next = environment_list;
X	  environment_list = $$;
X	  DEBUG1("env variable %s from environment - no default\n", $2);
X	}
X	| FROM_ENV NAME '=' TEXT ';'
X	{
X	  $$ = make_new_ev_var(EV_FROM_ENV, $2, $4, (char *)0);
X	  $$->next = environment_list;
X	  environment_list = $$;
X	  DEBUG2("env variable %s from environment - defaults to %s\n", $2, $4);
X	}
X	| FROM_FILE TEXT NAME ';'
X	{
X	  $$ = make_new_ev_var(EV_FROM_FILE, $3, (char *)0, $2);
X	  $$->next = environment_list;
X	  environment_list = $$;
X	  DEBUG2("env variable %s from file %s - no default\n", $3, $2);
X	}
X	| FROM_FILE TEXT NAME '=' TEXT ';'
X	{
X	  $$ = make_new_ev_var(EV_FROM_FILE, $3, $5, $2);
X	  $$->next = environment_list;
X	  environment_list = $$;
X	  DEBUG3("env variable %s from file %s - default: %s\n", $3, $2, $5);
X	}
X	;
X  
Xmenu_list : menu
X	{
X	  menu_list_head =
X	    menu_list_tail = $1;
X	}
X	| menu_list menu
X	{
X	  menu_list_tail->next =  $2;
X	  menu_list_tail = menu_list_tail->next;
X	}
X	;
X
Xmenu : title menu_flags item
X	{
X	  $1->flags = $2;
X	  switch ($3->action) {
X	  case ITEM_PRELUDE:
X	    $1->prelude = $3;
X	    break;
X	  case ITEM_EPILOGUE:
X	    $1->epilogue = $3;
X	    break;
X	  default:
X	    $1->item_head =
X	      $1->item_tail = $3;
X	    break;
X	  }
X	}
X	| menu item
X	{
X	  switch ($2->action) {
X	  case ITEM_PRELUDE:
X	    if ($1->prelude) {
X	      yacc_errors++;
X	      fprintf(stderr, "multiple prelude detected -line %d\n",
X		      line_number);
X	    }
X	    else
X	      $1->prelude = $2;
X	    break;
X	  case ITEM_EPILOGUE:
X	    if ($1->epilogue) {
X	      yacc_errors++;
X	      fprintf(stderr, "multiple epilogue detected -line %d\n",
X		      line_number);
X	    }
X	    else
X	      $1->epilogue = $2;
X	    break;
X	  default:
X	    if ($1->item_head) {
X	      $1->item_tail->next = $2;
X	      $1->item_tail = $2;
X	    }
X	    else
X	      $1->item_head =
X		$1->item_tail = $2;
X	    break;
X	  }
X	}
X	;
X
Xtitle : TITLE TEXT
X	{
X	  struct menu *menu_ptr;
X
X	  menu_ptr = make_new_menu();
X	  menu_ptr->menu_title = $2;
X	  if (menu_list_head) {
X	    fprintf(stderr, "untitled sub menu detected near line %d\n",
X		    line_number);
X	    yacc_errors++;
X	    menu_ptr->menu_name = "NOT NAMED";
X	  }
X	  DEBUG2("\nMenu %s Title '%s'\n", menu_ptr->menu_name, $2);
X	  $$ = menu_ptr;
X	}
X	| MENU NAME TITLE TEXT
X	{
X	  struct menu *menu_ptr;
X
X	  menu_ptr = make_new_menu();
X	  menu_ptr->menu_name = $2;
X	  menu_ptr->menu_title = $4;
X	  DEBUG2("\nMenu %s Title '%s'\n", $2, $4);
X	  $$ = menu_ptr;
X	}
X	;
X
Xmenu_flags :
X	{
X	  $$ = 0;
X	}
X	| menu_flags menu_flag
X	{  
X	  $$ = $1 | $2;
X	}
X	;
X
Xmenu_flag : CLEAR
X	{
X	  $$ = CLEAR_FLAG;
X	}
X	| BOLD
X	{
X  	  $$ = BOLD_FLAG;
X	}
X	| ALWAYS_SHOW
X	{
X  	  $$ = ALWAYS_DISPLAY_FLAG;
X	}
X	| ONCE
X	{
X	  $$ = ONCE_FLAG;
X	}
X	| ALPHA
X	{
X	  $$ = ALPHA_FLAG;
X	}
X	| WAIT
X	{
X	  $$ = WAIT_FLAG;
X	}
X	;
X
Xitem : SHELL TEXT  TEXT  parms ';'
X	{
X	  $$ = make_new_item($2, $3, parm_list, ITEM_SHELL);
X	  parm_list = (struct parm *)0;
X	  DEBUG3("shell item: line %d '%s'\n%%(\n%s\n%%)\n",
X                 line_number, $2, $3);
X	}
X	| PRELUDE  TEXT  TEXT  parms ';'
X	{
X	  $$ = make_new_item($2, $3, parm_list, ITEM_PRELUDE);
X	  parm_list = (struct parm *)0;
X	  DEBUG3("prelude item: line %d '%s'\n%%(\n%s\n%%)\n",
X                 line_number, $2, $3);
X	}
X	| EPILOGUE  TEXT  TEXT  parms ';'
X	{
X	  $$ = make_new_item($2, $3, parm_list, ITEM_EPILOGUE);
X	  parm_list = (struct parm *)0;
X	  DEBUG3("epilogue item: line %d '%s 'n%%(\n%s\n%%)\n",
X                 line_number, $2, $3);
X	}
X	| DO_MENU NAME TEXT ';'
X	{
X	  $$ = make_new_item($3, $2, (struct parm *)0, ITEM_MENU);
X	  DEBUG3("menu item: line %d \"%s\"\n'%s'\n",
X                 line_number, $2, $3);
X	}
X	| SKIP ';'
X	{
X	  $$ = make_new_item("SKIP", (char *)0, (struct parm *)0,
X			     ITEM_SKIP);
X	  DEBUG1("skip item: line %d\n", line_number);
X	}
X	;
X
Xparms : /* empty */
X	| parms parm
X	;
X
Xparm : PARM NAME TEXT
X	{
X	  $$ = make_new_parm(PARM_NO_DEFAULT, $2, $3, (char *)0);
X	  $$->next = parm_list;
X	  parm_list = $$;
X	  DEBUG2("parm: %s\n'%s'\n", $2, $3);
X	}
X	| PARM NAME '=' TEXT TEXT
X	{
X	  $$ = make_new_parm(PARM_STATIC_DEFAULT, $2, $5, $4);
X	  $$->next = parm_list;
X	  parm_list = $$;
X	  DEBUG3("parm: %s = %s\n'%s'\n", $2, $4, $5);
X	}
X	;
X	| PARM NAME '=' NAME TEXT
X	{
X	  $$ = make_new_parm(PARM_ENV_DEFAULT, $2, $5, $4);
X	  $$->next = parm_list;
X	  parm_list = $$;
X	  DEBUG3("parm: %s = \"%s\"\n'%s'\n", $2, $4, $5);
X	  if (!find_ev_var_by_name($4)) {
X	    yacc_errors++;
X	    fprintf(stderr, "parm initialized to non-existant environmental variable - line %s\n",
X		    line_number);
X	  }
X	}
X	;
X
X%%
END_OF_FILE
if test 9787 -ne `wc -c <'grammar.y'`; then
    echo shar: \"'grammar.y'\" unpacked with wrong size!
fi
# end of 'grammar.y'
fi
if test -f 'login.menu' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'login.menu'\"
else
echo shar: Extracting \"'login.menu'\" \(495 characters\)
sed "s/^X//" >'login.menu' <<'END_OF_FILE'
X#	a sample login menu
X
Xfrom-env "EDITOR" = 'vi' ;
Xfrom-env "PAGER"  = 'more' ;
X
Xtitle 'Login Menu'
X
Xclear always-show
X
Xprelude 'checking for mail ...'
X%( mail %)
X;
X
Xepilogue 'checking for mail'
X%( mail %)
X;
X
Xshell 'Edit a File'
X%( ${EDITOR} $FILE %)
Xparm "FILE"='work.doc' 'Name of File to Edit'
X;
X
Xshell 'Browse a File'
X%( ${PAGER} $FILE %)
Xparm "FILE"='work.doc' 'Name of File to View'
X;
X
Xshell 'Mail to a User'
X%( mail -s "$SUBJECT" $TO_WHOM %)
Xparm "SUBJECT" 'Subject'
Xparm "TO_WHOM" 'To'
X;
END_OF_FILE
if test 495 -ne `wc -c <'login.menu'`; then
    echo shar: \"'login.menu'\" unpacked with wrong size!
fi
# end of 'login.menu'
fi
if test -f 'menu.def' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'menu.def'\"
else
echo shar: Extracting \"'menu.def'\" \(2442 characters\)
sed "s/^X//" >'menu.def' <<'END_OF_FILE'
X# environment definitions
X
Xfrom-file './ev-values' "EV_FROMFILE_NO_INIT" ;
X
Xfrom-file './ev-values' "EV_FROMFILE_DEFINED" = 'value of file value' ;
X
Xfrom-file './ev-values' "EV_FROMEFILE_NOT_THERE" ;
X
Xfrom-env "EV_DEFINED" = 'value of EV_DEFINED' ;
X
Xfrom-env "EV_UNDEFINED" ;
X
X
X#This is the beginning of the main menu
X# since it is not named, the name will default to MAIN
X
Xtitle 'Test Menu'
X
X# clear will cause the screen to be cleared prior to each
X#  redisplay.
X# bold will cause the text 'Test Menu' to be displayed in
X#  standout mode - if the terminal type is defined and supports
X#  it
X# always-show will cause the choices to always displayed
X
Xclear bold always-show
X
X# this is a simple example
X
Xshell 'First Item'
X%( echo $PARM1 %)  # this is the shell script which will be executed
Xparm "PARM1" 'Input Parm 1'  # this paramter is set by the user
X;
X
Xshell 'Second Item'
X%( echo "This is $PARM and $FOO and $BARF" %)
Xparm "PARM" 'input value for PARM'
Xparm "FOO"='foo value' 'input value for FOO'
Xparm "BARF" = "EV_DEFINED" 'environment variable EV_DEFINED default'
X;
X
Xshell 'Display all Menu-Environment Variables and values'
X%(
X  echo "EV_FROMFILE_NO_INIT: $EV_FROMFILE_NO_INIT"
X  echo "EV_FROMFILE_DEFINED: $EV_FROMFILE_DEFINED"
X  echo "EV_FROMEFILE_NOT_THERE: $EV_FROMEFILE_NOT_THERE"
X  echo "EV_DEFINED: $EV_DEFINED"
X  echo "EV_UNDEFINED: $EV_UNDEFINED"
X%)
X;
X
X# this will cause a line to be skipped so as to block the first
X#  two items together
X
Xskip ;
X
Xshell 'Execute a Command'
X%(
X $CMD
X%)
Xparm "CMD" 'Command Line'
X;
X
Xskip ;
X
X#  three types of sub-menus folow.  The first is an internal
X#   sub menu defined later in this file
X
Xdo-menu "SUB_MENU" 'An Internal Submenu'
X;
X
X# this is a sub menu defined in a second file
X
Xshell 'Another Submenu in a Separate File'
X%(  ./simple_menu ./sub.menu %)
X;
X
X#  this sub menu is constructed dynamically by building a
X#  menu and feeding it to simple_menu
X
Xshell 'A Dynamically constructed Submenu'
X%( awk -F: '
XBEGIN {
X  print "title %( A dynamically constructed submenu %%)"
X  print "clear bold"
X}
X{
X  print "shell %( Browse " $2 " %%) %( " pager " " $1 " %%) ;"
X}
X' pager=$PAGER directory | ./simple_menu  -
X%)
Xparm "PAGER" = 'more' 'name of your pager'
X;
X
X# ============================================================
X
X# sub menu definition
X
Xmenu "SUB_MENU"
X
Xtitle 'a sub menu'
X
Xbold alpha once
X
Xshell 'spawn a shell'
X%( /bin/sh -i %)
X;
X
Xshell 'do nothing'
X%( echo "did nothing" %)
X;
END_OF_FILE
if test 2442 -ne `wc -c <'menu.def'`; then
    echo shar: \"'menu.def'\" unpacked with wrong size!
fi
# end of 'menu.def'
fi
if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'patchlevel.h'\"
else
echo shar: Extracting \"'patchlevel.h'\" \(21 characters\)
sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
X#define PATCHLEVEL 3
END_OF_FILE
if test 21 -ne `wc -c <'patchlevel.h'`; then
    echo shar: \"'patchlevel.h'\" unpacked with wrong size!
fi
# end of 'patchlevel.h'
fi
if test -f 'prototypes.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'prototypes.h'\"
else
echo shar: Extracting \"'prototypes.h'\" \(4212 characters\)
sed "s/^X//" >'prototypes.h' <<'END_OF_FILE'
X#ifdef PROTOTYPES_OK
X
X/* simple_menu.c */
X
Xint main(int /*argc*/, char ** /*argv*/);
Xvoid display_parsed_menus(void);
Xvoid init(int /*argc*/, char ** /*argv*/);
Xstruct parm *make_new_parm(int /*flag*/, char * /*identifier*/, char * /*prompt*/, char * /*def_or_evname*/);
Xstruct ev_var *make_new_ev_var(int /*flag*/, char * /*identifier*/, char * /*deflt*/, char * /*fname*/);
Xstruct item *make_new_item(char * /*prompt*/, char * /*command*/, struct parm * /*parms*/, int /*action*/);
Xstruct menu *make_new_menu(void);
Xvoid init_environment(void);
Xstruct ev_var *find_ev_var_by_name(char * /*name*/);
Xvoid init_parm_defaults(void);
Xvoid init_item_parm_defaults(struct item * /*i_ptr*/);
Xvoid push_menu(struct menu * /*menu_ptr*/);
Xint pop_menu(void);
Xstruct menu *find_menu(char * /*name*/);
Xint check_menu(void);
Xvoid do_menu(void);
Xvoid do_shell_script(struct item * /*selected_item*/);
Xvoid do_prelude(void);
Xvoid do_epilogue(void);
Xvoid fatal(char * /*s*/);
Xvoid trapoid(int /*sig*/);
Xvoid do_longjmp(int /*sig*/);
Xvoid wait_for_child(int /*pid*/);
Xvoid set_signals(int /*flag*/);
Xvoid reset_signals(void);
Xint open_menu_file(void);
Xint search_menu_path(char * /*path*/, char * /*fname*/);
Xchar *Malloc(unsigned /*size*/);
Xchar *Realloc(char * /*ptr*/, unsigned /*size*/);
Xvoid yyerror(char * /*s*/);
Xvoid prt_item(struct item * /*item_ptr*/);
Xvoid simple_menu_exit(int /*code*/);
X
X/* grammar.c */
X
Xint yyparse(void);
X
X/* scanner.c */
X
Xint match_token(char * /*s*/);
Xint make_lower(char /*c*/);
Xint yylex(void);
Xint scan_in_token_state(void);
Xint scan_in_name_state(void);
Xint scan_in_string_state(void);
Xint scan_in_text_state(void);
Xint scan_in_old_text_state(void);
Xvoid unget_char(char /*c*/);
Xint next_char(int /*fd*/);
Xvoid flush_char_input(void);
Xvoid add_char(char /*c*/);
Xvoid strip_white_space(void);
Xchar *take_saved_text(void);
X
X/* tty_display.c */
X
Xint outc(int /*c*/);
Xvoid init_terminal(void);
Xvoid close_terminal(void);
Xvoid display_menu(void);
Xchar *get_variable_value(char * /*prompt*/, char * /*deflt*/);
Xint get_user_rsp(void);
Xvoid do_pause(int /*flag*/);
X
X#else /* PROTOTYPES_OK */
X
X/* simple_menu.c */
X
Xint main(/*int argc, char **argv*/);
Xvoid display_parsed_menus(/*void*/);
Xvoid init(/*int argc, char **argv*/);
Xstruct parm *make_new_parm(/*int flag, char *identifier, char *prompt, char *def_or_evname*/);
Xstruct ev_var *make_new_ev_var(/*int flag, char *identifier, char *deflt, char *fname*/);
Xstruct item *make_new_item(/*char *prompt, char *command, struct parm *parms, int action*/);
Xstruct menu *make_new_menu(/*void*/);
Xvoid init_environment(/*void*/);
Xstruct ev_var *find_ev_var_by_name(/*char *name*/);
Xvoid init_parm_defaults(/*void*/);
Xvoid init_item_parm_defaults(/*struct item *i_ptr*/);
Xvoid push_menu(/*struct menu *menu_ptr*/);
Xint pop_menu(/*void*/);
Xstruct menu *find_menu(/*char *name*/);
Xint check_menu(/*void*/);
Xvoid do_menu(/*void*/);
Xvoid do_shell_script(/*struct item *selected_item*/);
Xvoid do_prelude(/*void*/);
Xvoid do_epilogue(/*void*/);
Xvoid fatal(/*char *s*/);
Xvoid trapoid(/*int sig*/);
Xvoid do_longjmp(/*int sig*/);
Xvoid wait_for_child(/*int pid*/);
Xvoid set_signals(/*int flag*/);
Xvoid reset_signals(/*void*/);
Xint open_menu_file(/*void*/);
Xint search_menu_path(/*char *path, char *fname*/);
Xchar *Malloc(/*unsigned size*/);
Xchar *Realloc(/*char *ptr, unsigned size*/);
Xvoid yyerror(/*char *s*/);
Xvoid prt_item(/*struct item *item_ptr*/);
Xvoid simple_menu_exit(/*int code*/);
X
X/* grammar.c */
X
Xint yyparse(/*void*/);
X
X/* scanner.c */
X
Xint match_token(/*char *s*/);
Xint make_lower(/*char c*/);
Xint yylex(/*void*/);
Xint scan_in_token_state(/*void*/);
Xint scan_in_name_state(/*void*/);
Xint scan_in_string_state(/*void*/);
Xint scan_in_text_state(/*void*/);
Xint scan_in_old_text_state(/*void*/);
Xvoid unget_char(/*char c*/);
Xint next_char(/*int fd*/);
Xvoid flush_char_input(/*void*/);
Xvoid add_char(/*char c*/);
Xvoid strip_white_space(/*void*/);
Xchar *take_saved_text(/*void*/);
X
X/* tty_display.c */
X
Xint outc(/*int c*/);
Xvoid init_terminal(/*void*/);
Xvoid close_terminal(/*void*/);
Xvoid display_menu(/*void*/);
Xchar *get_variable_value(/*char *prompt, char *deflt*/);
Xint get_user_rsp(/*void*/);
Xvoid do_pause(/*int flag*/);
X#endif /* PROTOTYPES_OK */
END_OF_FILE
if test 4212 -ne `wc -c <'prototypes.h'`; then
    echo shar: \"'prototypes.h'\" unpacked with wrong size!
fi
# end of 'prototypes.h'
fi
if test -f 'scanner.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'scanner.c'\"
else
echo shar: Extracting \"'scanner.c'\" \(6770 characters\)
sed "s/^X//" >'scanner.c' <<'END_OF_FILE'
X/* %W% %D% */
X/* copyrite (c) Mike Howard, 1990, 1991 */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "y.tab.h"
X#include "simple_menu.h"
X
Xextern int debug_mode;
Xextern int lex_errors;
Xextern int line_number;
X
Xchar *saved_text;
Xchar *Malloc();
Xchar *Realloc();
X
Xstruct word_cell {
X  char *name;
X  int value;
X};
X
Xstruct word_cell word_list[] =  {
X"ERROR", ERROR,
X"item", SHELL,       /* left over dinosaur */
X"shell", SHELL,
X"parm", PARM,
X"title", TITLE,
X"clear", CLEAR,
X"bold", BOLD,
X"always-show", ALWAYS_SHOW,
X"once", ONCE,
X"prelude", PRELUDE,
X"epilogue", EPILOGUE,
X"menu", MENU,
X"do-menu", DO_MENU,
X"skip", SKIP,
X"alpha", ALPHA,
X"wait", WAIT,
X"shell-path", SHELL_PATH,
X"asg-fmt", ASG_FMT,
X"from-env", FROM_ENV,
X"from-file", FROM_FILE,
X(char *)0, -1 };
X
Xint
Xmatch_token(s)
X     char *s;
X{
X  int i;
X
X  for (i=1;word_list[i].name;i++) {
X    if (*s == word_list[i].name[0] && !strcmp(s, word_list[i].name))
X      return i;
X  }
X
X  lex_errors++;
X  return 0;
X}
X
Xint
Xmake_lower(c)
X     char c;
X{
X  return isupper(c) ? tolower(c) : c;
X}
X
X/* this thing is a state machine - of sorts.  */
X
Xint
Xyylex()
X{
X  char c;
X
X  while (1) {
X    while (isspace(c = next_char(0)))
X      ;
X    switch (c) {
X    case '"':
X      return scan_in_name_state();
X    case '{':
X      return scan_in_old_text_state();
X    case '\0':
X      return 0;
X    case '%':
X      if ((c = next_char(0)) == '(')
X	return scan_in_text_state();
X      unget_char(c);
X      unget_char('%');
X      return scan_in_token_state();
X    case '\'':
X      return scan_in_string_state();
X    case '#':
X      while (c && c != '\n')
X	c = next_char(0);
X      break;
X    case ';':
X    case '=':
X      VDEBUG2("scanner: line %d - returning %c\n", line_number, c);
X      return c;
X    default:
X      unget_char(c);
X      return scan_in_token_state();
X    }
X  }
X}
X
Xint
Xscan_in_token_state()
X{
X  char c;
X  int ret;
X
X  while (isalpha(c = make_lower(next_char(0))) || c == '-')
X    add_char(c);
X
X  unget_char(c);
X  ret = match_token(saved_text);
X  VDEBUG3("scanner: line %d: token: %s matches %s\n", line_number,
X	 saved_text, word_list[ret].name);
X  free(saved_text);
X  saved_text = (char *)0;
X
X  return word_list[ret].value;
X}
X
Xint
Xscan_in_name_state()
X{
X  char c;
X
X  while (1) {
X    c = next_char(0);
X    if (isalnum(c) || c == '_')
X      add_char(c);
X    else if (c == '"') {
X      strip_white_space();
X      yylval.txt = take_saved_text();
X      VDEBUG2("scanner: line %d - found Name: \"%s\"\n", line_number,
X	     yylval.txt);
X      return NAME;
X    }
X    else {
X      printf("error in line %d - bad character (%c) in name\n",
X	     line_number, c);
X      while (c && !isspace(c))
X	c = next_char(0);
X      unget_char(c);
X      lex_errors++;
X      return ERROR;
X    }
X  }
X}
X
X/* scans for ' delimited plain text - translates '' into ' */
X
Xint scan_in_string_state()
X{
X  char c;
X
X  while (1) {
X    switch (c = next_char(0)) {
X    case 0:
X      printf("error in line %d - premature end of text\n", line_number);
X      lex_errors++;
X      return ERROR;
X    case '\'':
X      if ((c = next_char(0)) != '\'') {
X	strip_white_space();
X	yylval.txt = take_saved_text();
X	VDEBUG2("scanner: line %d - found Text-String\n'%s'\n",
X	       line_number, yylval.txt);
X	return TEXT;
X      }
X      add_char('\'');
X      break;
X    default:
X      add_char(c);
X      break;
X    }
X  }
X}
X
X/* scans for %( %) delimited text - a %) may be embedded if written %%) */
X
Xint scan_in_text_state()
X{
X  char c;
X
X  while (1) {
X    switch (c = next_char(0)) {
X    case 0:
X      printf("error in line %d - premature end of text\n", line_number);
X      lex_errors++;
X      return ERROR;
X    case '%':
X      if ((c = next_char(0)) == ')') {
X	strip_white_space();
X	yylval.txt = take_saved_text();
X	VDEBUG2("scanner: line %d - found Text-String\n%(\n%s\n%)\n",
X		line_number, yylval.txt);
X	return TEXT;
X      }
X      if (c == '%') {
X	if ((c = next_char(0)) == ')' || c == '(') {
X	  add_char('%');
X	  add_char(c);
X	  break;
X	}
X	/* back up two characters and restart */
X	unget_char(c);
X	c = '%';
X	break;
X      }
X      unget_char(c);
X      add_char('%');
X      break;
X    default:
X      add_char(c);
X      break;
X    }
X  }
X}
X
Xint
Xscan_in_old_text_state()
X{
X  char c;
X
X  while (1) {
X    switch (c = next_char(0)) {
X    case 0:
X      printf("error in line %d - premature end of text\n", line_number);
X      lex_errors++;
X      return ERROR;
X    case '\\':
X      switch(c = next_char(0)) {
X      case '\\':
X      case '}':
X	add_char(c);
X	break;
X      default:
X	add_char('\\');
X	add_char(c);
X	break;
X      }
X      break;
X    case '}':
X      strip_white_space();
X      yylval.txt = take_saved_text();
X      VDEBUG2("scanner: line %d - found old style Text-String\n{\n%s\n}\n",
X	      line_number, yylval.txt);
X      return TEXT;
X    default:
X      add_char(c);
X      break;
X    }
X  }
X}
X
X#define CHAR_BUFSIZE  1024
Xunsigned char char_buf[CHAR_BUFSIZE];
Xint chars_left;
Xunsigned char *nxt_char;
X#define UNGET_BUFSIZE 128
Xchar unget_buf[UNGET_BUFSIZE];
Xint unget_len;
X
XVOID
Xunget_char(c)
X     char c;
X{
X  if ((unget_buf[unget_len++] = c) == '\n')
X    line_number--;
X}
X
Xint
Xnext_char(fd)
Xint fd;
X{
X  int c;
X
X  if (unget_len > 0) {
X    c = unget_buf[--unget_len];
X  }
X  else {
X    if (chars_left <= 0) {
X      if ((chars_left = read(fd, char_buf, CHAR_BUFSIZE)) <= 0)
X	return 0;
X      nxt_char = char_buf;
X    }
X
X    c = *nxt_char++;
X    chars_left--;
X  }
X
X  if (c == '\n')
X    line_number++;
X
X  return c;
X}
X
XVOID flush_char_input()
X{
X  chars_left =
X    unget_len = 0;
X}
X
X#define INIT_SIZE	256
X#define INC_SIZE	64
X
X
XVOID
Xadd_char(c)
X     char c;
X{
X  static int saved_length;
X  static int room_left;
X  static int saved_size;
X
X  if (!saved_text) {
X    memset(saved_text = Malloc(INIT_SIZE), '\0', INIT_SIZE);
X    room_left = INIT_SIZE;
X    saved_size = INIT_SIZE;
X    saved_length = 0;
X  }
X
X  if (room_left < 2) {
X    saved_text = Realloc(saved_text, saved_size += INC_SIZE);
X    room_left += INC_SIZE;
X  }
X
X  saved_text[saved_length++] = c;
X  saved_text[saved_length] = '\0';
X  room_left--;
X}
X
X
XVOID
Xstrip_white_space()
X{
X  char *cp;
X  char *sp;
X
X  if (!saved_text)
X    return;
X
X  for (cp = saved_text + strlen(saved_text) - 1;cp > saved_text;cp--) {
X    if (!isspace(*cp))
X      break;
X  }
X  *++cp = '\0';
X
X  for (cp=saved_text;*cp && isspace(*cp);cp++)
X    ;
X
X  /* is it all white? */
X  if (!*cp && cp > saved_text) {
X    saved_text = Realloc(saved_text, 1);
X    *saved_text = '\0';
X    return;
X  }
X
X  /* is there any leading white space? */
X  if (cp > saved_text) {
X    char *tmp;
X    int len;
X
X    tmp = Malloc(len = strlen(cp) + 1);
X    memcpy(tmp, cp, len);
X    free(saved_text);
X    saved_text = tmp;
X
X    return;
X  }
X
X  saved_text = Realloc(saved_text, strlen(saved_text) + 1);
X}
X
Xchar *
Xtake_saved_text()
X{
X  char *cp = saved_text;
X
X  saved_text = (char *)0;
X
X  return cp;
X}
END_OF_FILE
if test 6770 -ne `wc -c <'scanner.c'`; then
    echo shar: \"'scanner.c'\" unpacked with wrong size!
fi
# end of 'scanner.c'
fi
if test -f 'simple_menu.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'simple_menu.h'\"
else
echo shar: Extracting \"'simple_menu.h'\" \(3804 characters\)
sed "s/^X//" >'simple_menu.h' <<'END_OF_FILE'
X/* %W% %D% */
X/* copyrite (c) Mike Howard, 1990, 1991 */
X
X/* #define VOID  void or int is expected to occur in the compilation line */
X#ifndef VOID
X# define VOID void
X#endif
X
X/* include some common stuff */
X#ifndef FILE
X# include <stdio.h>
X#endif
X#include <setjmp.h>
X
X#define EV_FROM_FILE 1
X#define EV_FROM_ENV  2
X
Xstruct ev_var {
X  struct ev_var *next;
X  char *identifier;
X  char *value;
X  char *deflt;
X  char *file_name;
X  int   flag;
X};
X
X#define PARM_NO_DEFAULT       0
X#define PARM_STATIC_DEFAULT   1
X#define PARM_ENV_DEFAULT      2
X
Xstruct parm {
X  struct parm *next;
X  char *prompt;
X  char *identifier;
X  char *value;
X  char *def_or_evname;
X  int   flag;
X};
X
X#define ITEM_SHELL       1
X#define ITEM_MENU        2
X#define ITEM_SKIP        3
X#define ITEM_PRELUDE     4
X#define ITEM_EPILOGUE    5
X
X
Xstruct item {
X  struct item *next;
X  int action;
X  int item_idx;
X  char *prompt;
X  char *command;
X  struct parm *parms;
X};
X
X#define CLEAR_FLAG                1
X#define BOLD_FLAG                 2
X#define ALWAYS_DISPLAY_FLAG       4
X#define ONCE_FLAG                 8
X#define ALPHA_FLAG               16
X#define WAIT_FLAG                32
X#define Clear_Flag	(clear_flag&&(active_menu->flags&CLEAR_FLAG))
X#define Bold_Flag	(bold_flag&&(active_menu->flags&BOLD_FLAG))
X#define Always_Display_Flag	(active_menu->flags&ALWAYS_DISPLAY_FLAG)
X#define Once_Flag       (active_menu->flags&ONCE_FLAG)
X#define Alpha_Flag      (active_menu->flags&ALPHA_FLAG)
X#define Wait_Flag       (active_menu->flags&WAIT_FLAG)
X
Xstruct menu {
X  struct menu *next;
X  struct menu *menu_stack_ptr;
X  struct item *item_head;
X  struct item *item_tail;
X  struct item *prelude;
X  struct item *epilogue;
X  char *menu_name;
X  char *menu_title;
X  char *short_title;
X  int max_item;
X  int flags;
X};
X
X#define DEBUG0(fmt)	if(debug_mode>1)printf(fmt);
X#define DEBUG1(fmt,aa)	if(debug_mode>1)printf(fmt,aa);
X#define DEBUG2(fmt,aa,bb)	if(debug_mode>1)printf(fmt,aa,bb);
X#define DEBUG3(fmt,aa,bb,cc)	if(debug_mode>1)printf(fmt,aa,bb,cc);
X
X#define VDEBUG0(fmt)	if(debug_mode>2)printf(fmt);
X#define VDEBUG1(fmt,aa)	if(debug_mode>2)printf(fmt,aa);
X#define VDEBUG2(fmt,aa,bb)	if(debug_mode>2)printf(fmt,aa,bb);
X#define VDEBUG3(fmt,aa,bb,cc)	if(debug_mode>2)printf(fmt,aa,bb,cc);
X
X/* data declarations and initializations */
X#ifdef MAIN
X# define EXTERN
X#else
X# define EXTERN extern
X#endif
X
X/* capability flags - set by init_terminal */
XEXTERN int clear_flag;
XEXTERN int bold_flag;
X
XEXTERN struct menu *menu_list_head;
XEXTERN struct menu *menu_list_tail;
XEXTERN struct menu *active_menu;
X
XEXTERN struct parm *parm_list;
XEXTERN struct ev_var *environment_list;
X
XEXTERN char *user_rsp;
XEXTERN int default_timeout;
X
XEXTERN int lex_errors;
XEXTERN int yacc_errors;
XEXTERN int line_number;
X
X
X
Xextern char *optarg;
Xextern int optind, opterr;
XEXTERN int tty_in;
XEXTERN char *tty_fname;
XEXTERN char *ttyname();
XEXTERN int argcc;
XEXTERN char **argvv;
XEXTERN char *progname;
XEXTERN char *in_fname;
XEXTERN char *menu_fname;
X#define MENU_FNAME "menu.def"
XEXTERN char *menu_path;
X#ifndef DEFAULT_MENU_PATH
X# define DEFAULT_MENU_PATH \
X   "/usr/local/lib/simple_menu:/usr/local/lib/dumb_menu"
X#endif /* DEFAULT_MENU_PATH */
XEXTERN char *cmd_path;
XEXTERN char *asg_fmt;
XEXTERN char *cmd_name;
X
XEXTERN struct item *selected_item;
XEXTERN struct parm *selected_parms;
XEXTERN FILE *tmp_file;
XEXTERN char *tmp_fname;
X
X/* flags */
XEXTERN int verbose;
XEXTERN int debug_mode;
X
XEXTERN int display_menu_flag;
XEXTERN jmp_buf env;
X#define SIGS_FOR_JMP   1
X#define SIGS_FOR_CHILD 2
X
X#ifdef MAIN
X
Xchar *use_msg = "usage: %s (patchlevel %d) [-h | option(s)] [menu-file | -]\n";
Xchar *item_types[] = {
X"none",
X"Shell Item",
X"Menu Item",
X"Skip Item",
X"Prelude Item",
X"Epilogue Item",
X(char *)0 };
X#else
Xextern char *use_msg;
Xextern char *item_types[];
X#endif
X
X#include "prototypes.h"
END_OF_FILE
if test 3804 -ne `wc -c <'simple_menu.h'`; then
    echo shar: \"'simple_menu.h'\" unpacked with wrong size!
fi
# end of 'simple_menu.h'
fi
if test -f 'sub.menu' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sub.menu'\"
else
echo shar: Extracting \"'sub.menu'\" \(226 characters\)
sed "s/^X//" >'sub.menu' <<'END_OF_FILE'
X
Xtitle 'A non-descript submenu
XWith a multi-line
X   title'
X
Xclear wait
X
Xshell 'Sub-Item 1
X     long prompt'
X%( echo "Sub-Item 1" %)
X;
X
Xshell 'Sub-Item 2'
X%( echo "Sub-Item 2" %)
X;
X
Xshell 'Sub-Item 3'
X%( echo "Sub-Item 3" %)
X;
END_OF_FILE
if test 226 -ne `wc -c <'sub.menu'`; then
    echo shar: \"'sub.menu'\" unpacked with wrong size!
fi
# end of 'sub.menu'
fi
if test -f 'tty_display.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tty_display.c'\"
else
echo shar: Extracting \"'tty_display.c'\" \(8253 characters\)
sed "s/^X//" >'tty_display.c' <<'END_OF_FILE'
X/* %W% %D% */
X
Xstatic char *cpy_str =
X  "Copyright (c), Mike Howard, 1990,1991 all rights reserved";
X
X/* Conditions of use:
X
X   This software is not for sale and is not to be sold by or
X   to anyone.
X
X   You may use this software and may distribute it to anyone
X   you wish to provided you distribute the entire distribution
X   package w/o any deletions (i.e. include all the source code).
X
X   I do not warrent this software to do anything at all and
X   am not responsible for anything which happens as a result of
X   its use.
X*/
X
X/* this is the display dependant part which knows how to talk to character
X   terminals
X
X   must define 4 functions:
X   init_terminal() - initializes the display - a tty for tty based stuff
X   display_menu() - draws the menu on the display
X   prepare_for_subshell() - this and the companion routine do whatever
X   return_from_subshell() -  is required to the display to run a subshell
X   close_terminal() - does whatever closedown is required for terminal
X   get_user_rsp() - returns single character user choice.
X   get_variable_value(prompt, def) - returns Malloc'ed value of parameter
X                                 after talking to user
X   do_pause(flag) - implements a timed pause.  It should return after a user
X                    action or default_timeout seconds have passed.  The
X		    flag is 0 for an illegal menu choice and 1 if exiting
X		    a menu
X*/
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <string.h>
X#include <signal.h>
X#include <ctype.h>
X
X#include "simple_menu.h"
X#include "patchlevel.h"
X
X#ifdef TERMCAP
Xchar tty_bp[1024];
Xchar tty_caps[1024];
Xchar *term_cm;
Xchar *term_so;
Xchar *term_se;
Xint term_sg;
Xchar *term_cl;
Xint term_lines;
Xchar PC;
Xchar *BC;
Xchar *UP;
Xshort ospeed;
X
Xint
Xoutc(c)
X     int c;
X{
X  putc(c, stdout);
X}
X
XVOID
Xinit_terminal()
X{
X  char *getenv();
X  char *tty_type = getenv("TERM");
X  char *cp = tty_caps;
X  char *tgetstr();
X
X  /* assumes fd's 0, 1, & 2 are closed */
X  tty_fname = ttyname(1);
X  if (!isatty(1) || (tty_in = open(tty_fname, O_RDWR)) < 0)
X    fatal("cannot open tty - must be run interactively");
X  close(0);
X  close(1);
X  close(2);
X  dup(tty_in);
X  dup(tty_in);
X  close(tty_in);
X
X  if (!tty_type || tgetent(tty_bp, tty_type) <= 0) {
X    clear_flag =
X      bold_flag = 0;
X    return;
X  }
X
X  PC = (BC = tgetstr("pc", &cp)) ? *BC : '\0';
X  BC = tgetstr("bc", &cp);
X  UP = tgetstr("up", &cp);
X#ifdef TERMIO
X  {
X#include <termio.h>
X
X    struct termio termio;
X
X    ioctl(0, TCGETA, &termio);
X    ospeed = termio.c_cflag & CBAUD;
X  }
X#undef ECHO /* conflicts with lex code */
X#endif /* TERMIO */
X#ifdef BSDTTY
X  {
X#include <sgtty.h>
X    struct sgttyb sgttyb;
X
X    ioctl(0, TIOCGETP, &sgttyb);
X    ospeed = sgttyb.sg_ospeed;
X  }
X#endif /* BSDTTY */
X
X  term_cm = tgetstr("cm", &cp);
X  term_so = tgetstr("so", &cp);
X  term_se = tgetstr("se", &cp);
X  term_sg = tgetnum("sg");
X  bold_flag = term_so ? 1 : 0;
X
X  term_cl = tgetstr("cl", &cp);
X  term_lines = tgetnum("li");
X  clear_flag = term_cl ? 1 : 0;
X
X  flush_char_input();
X}
X
XVOID
Xclose_terminal()
X{
X}
X
XVOID
Xprepare_for_subshell()
X{
X}
X
XVOID
Xreturn_from_subshell()
X{
X}
X
XVOID
Xdisplay_menu()
X{
X  struct item *ptr;
X  int i;
X
X  /* if we clear the screen, then do it, otherwise skip a line */
X  if (Clear_Flag)
X    tputs(term_cl, term_lines, outc);
X  else
X    putc('\n', stdout);
X
X  /* this is not correct for magic cookie tubes - solving that problem
X     requires counting lines in menu_title, maintaining line counts in the
X     case we don't clear-screen-before-displaying, cursor positioning
X     sequences, ... AND having a known tube environment - i.e. no one
X     has reprogrammed something for their own purposes.  So, if you
X     have any such tube, it will probably flash if you set the
X     bold flag     */
X  if (Bold_Flag) {
X    tputs(term_so, 1, outc);
X    printf("%s", active_menu->menu_title);
X    tputs(term_se, 1, outc);
X    putc('\n', stdout);
X  }
X  else
X    printf("%s\n", active_menu->menu_title);
X
X  if (display_menu_flag) {
X    for (ptr=active_menu->item_head;ptr;ptr = ptr->next) {
X      switch (ptr->action) {
X      case ITEM_SKIP:
X	putchar('\n');
X	break;
X      default:
X	if (Alpha_Flag)
X	  printf("%c. %s\n", 'A' + ptr->item_idx - 1, ptr->prompt);
X	else
X	  printf("%2d. %s\n", ptr->item_idx, ptr->prompt);
X	break;
X      }
X    }
X  }
X
X  if (Once_Flag)
X    printf("Choice? ");
X  else if (Always_Display_Flag)
X    printf("Q) to End - choice? ");
X  else
X    printf("Q) to End, ?) for Menu - choice? ");
X  fflush(stdout);
X
X  display_menu_flag = Always_Display_Flag;
X}
X#endif /* TERMCAP */
X
X#ifdef TERMINFO
X
Xint havecalled_setupterm;
X#include <curses.h>
X#include <term.h>
X
XVOID
Xinit_terminal()
X{
X
X  /* assumes fd's 0, 1, & 2 are closed */
X  tty_fname = ttyname(1);
X  if (!isatty(1) || (tty_in = open(tty_fname, O_RDWR)) < 0)
X    fatal("cannot open tty - must be run interactively");
X  close(0);
X  close(1);
X  close(2);
X  dup(tty_in);
X  dup(tty_in);
X  close(tty_in);
X
X
X  setupterm((char *)0, 1, &havecalled_setupterm);
X  if (havecalled_setupterm != 1) {
X    clear_flag =
X      bold_flag = 0;
X    return;
X  }
X
X  if (clear_screen)
X    clear_flag++;
X  if (enter_standout_mode)
X    bold_flag++;
X
X  flush_char_input();
X}
X
XVOID
Xclose_terminal()
X{
X  if (havecalled_setupterm)
X    resetterm();
X}
X
XVOID
Xprepare_for_subshell()
X{
X  if (havecalled_setupterm)
X    resetterm();
X}
X
XVOID
Xreturn_from_subshell()
X{
X  if (havecalled_setupterm)
X    fixterm();
X}
X
XVOID
Xdisplay_menu()
X{
X  struct item *ptr;
X  int i;
X
X  /* if we clear the screen, then do it, otherwise skip a line */
X  if (Clear_Flag)
X    putp(clear_screen);
X  else
X    putc('\n', stdout);
X
X  /* this is not correct for magic cookie tubes - solving that problem
X     requires counting lines in menu_title, maintaining line counts in the
X     case we don't clear-screen-before-displaying, cursor positioning
X     sequences, ... AND having a known tube environment - i.e. no one
X     has reprogrammed something for their own purposes.  So, if you
X     have any such tube, it will probably flash if you set the
X     bold flag     */
X  if (Bold_Flag) {
X    putp(enter_standout_mode);
X    printf("%s", active_menu->menu_title);
X    putp(exit_standout_mode);
X    putc('\n', stdout);
X  }
X  else
X    printf("%s\n", active_menu->menu_title);
X
X  if (display_menu_flag) {
X    for (ptr=active_menu->item_head;ptr;ptr = ptr->next) {
X      switch (ptr->action) {
X      case ITEM_SKIP:
X	putchar('\n');
X	break;
X      default:
X	if (Alpha_Flag)
X	  printf("%c. %s\n", 'A' + ptr->item_idx - 1, ptr->prompt);
X	else
X	  printf("%2d. %s\n", ptr->item_idx, ptr->prompt);
X	break;
X      }
X    }
X  }
X
X  if (Once_Flag)
X    printf("Choice? ");
X  else if (Always_Display_Flag)
X    printf("Q) to End - choice? ");
X  else
X    printf("Q) to End, ?) for Menu - choice? ");
X  fflush(stdout);
X
X  display_menu_flag = Always_Display_Flag;
X}
X#endif /* TERMINFO */
X
Xchar *
Xget_variable_value(prompt, deflt)
Xchar *prompt;
Xchar *deflt;
X{
X  char *cp;
X  int c;
X
X  printf("%s[%s]: ", prompt, deflt);
X  fflush(stdout);
X  while ((c = next_char(0)) && c != '\n')
X    add_char(c);
X
X  if ((cp = take_saved_text()) && strlen(cp)) {
X    return cp;
X  }
X  else if (deflt) {
X    strcpy(cp = Malloc(strlen(deflt) + 1), deflt);
X  }
X  else {
X    cp = Malloc(1);
X    cp[0] = '\0';
X  }
X
X  return cp;
X}
X
X
Xint
Xget_user_rsp()
X{
X  char c;
X
X  while ((c = next_char(0)) && c != '\n')
X    add_char(c);
X  strip_white_space();
X
X  if (user_rsp)
X    free(user_rsp);
X  if (!(user_rsp = take_saved_text()))
X    return c == '\n' ? '\n' : 0;
X
X  switch (user_rsp[0]) {
X  case 'q':
X  case 'Q':
X    return 'q';
X  case '?':
X    return '?';
X  case '\0':
X    return c == '\n' ? '\n' : 0;
X  default:
X    if (Alpha_Flag) {
X      if (isalpha(user_rsp[0]))
X	return toupper(user_rsp[0]) - 'A' + 1;
X      return 0;
X    }
X    else
X      return atoi(user_rsp);
X  }
X}
X
Xstatic VOID
Xalarm_trap()
X{
X  return;
X}
X
XVOID
Xdo_pause(flag)
X     int flag;
X{
X  char c;
X
X  if (Clear_Flag) {
X    if (flag)
X      printf("Returning to '%s' [Press Return to Continue]",
X	     active_menu->short_title);
X    else
X      printf("[Press Return to Continue]");
X    fflush(stdout);
X    if (!Wait_Flag) {
X      alarm(default_timeout);
X      signal(SIGALRM, alarm_trap);
X    }
X    while ((c = next_char(0)) && c != '\n')
X      ;
X    alarm(0);
X    signal(SIGALRM, SIG_IGN);
X  }
X}
END_OF_FILE
if test 8253 -ne `wc -c <'tty_display.c'`; then
    echo shar: \"'tty_display.c'\" unpacked with wrong size!
fi
# end of 'tty_display.c'
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
--------------------------------cut here--------------------------------------
-- 
Mike Howard
uunet!milhow1!how or how%milhow1@uunet.uu.net