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