menu(1) part 3 of 14

Paul J. Condie pjc at pcbox.UUCP
Thu Dec 27 07:05:20 AEST 1990


#!/bin/sh
# this is part 3 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file menu.1 continued
#
CurArch=3
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file menu.1"
sed 's/^X//' << 'SHAR_EOF' >> menu.1
X     KEY_CANCEL = 27	# (esc)  Cancel all input from a GETINPUT screen or cancel a pop-up menu selection.
X			           Exit a help screen.
X     KEY_SAVE = 6	# (^f)  Save a GETINPUT screen to a file.
X     KEY_PRINT = 16	# (^p)  Print a GETINPUT screen to lp.
X.fi
X
X.SH EXAMPLE menufile
X.nf
X\fB###\fR     This is a example of a menu script file.
X
X\fB .AUTHORIZE\fR  pjc nortons boink mozart
X
X\fB###\fR	Initialize function keys for TERM=5425
X\fB .UNIX\fR  echo "\\033[1;2;0;0q  HELP          h\\r\\c"
X
X\fB###\fR	Define goto menu names.
X\fB .GNAME\fR  main  main.m
X\fB .GNAME\fR  reports  reports.m
X
X\fB###\fR     Title Lines Section.
X\fB .TITLE\fR
X  Version 3.00...\\RPACIFIC * BELL\\N...$DATE
X\fB .TITLE\fR
X $MAIL...Sample Menu...\\S$TIME\\N
X\fB .TITLE\fR
X ...MAIN MENU...
X\fB .LINE\fR
X
X\fB###\fR     Left column of screen - Options
X\fB .WINDOW\fR 0 23 0 39
X\fB .SYSTEM\fR who
XList who is on the system.
X\fB .SYSTEM\fR ps -ef; \\
X	echo "Press [ Return ] to continue.\\c"; read reply
XPrint process status table.
X
X\fB###\fR     Right column of screen - Options
X\fB .WINDOW\fR 0 23 40 79 \\R SUB MENU \\N
X\fB .MENU\fR reports.m
XGo to report menu.
X
X\fB .TEXT\fP 22 50
XSelection [ ? for help ]
X.fi
X
X.SH GENERALLY ACCEPTED GUIDELINES
X.PD 0.1
X.IP -> 3
XPut a meaningful title on the top of every menu.
X.IP -> 3
XProvide symmetric balance by centering the title and the menu options
Xaround the center axis of the screen.
X.IP -> 3
XChoose an organizing principle for the menu options.
XOrganize menu hierarchies according to the tasks users will perform, rather
Xthan the structure of the software modules.
X.br
XHints in organizing options:
X.RS 6
X.IP * 3
XChronological ordering
X.IP * 3
XAscending or descending numerical ordering
X.IP * 3
XItems grouped by physical properties, (Increasing volume, weight or temperature)
X.IP * 3
XAlphabetic sequence of terms
X.IP * 3
XGrouping of related options with spatial demarcation between groups
X.IP * 3
XMost frequently used options first
X.IP * 3
XMost important options first
X.RE
X.IP -> 3
XTo facilitate scanning, put blank lines between logical groupings of menu
Xoptions and after about every fifth option in a long list.
X.IP -> 3
XLimit the number of menu choices of one screen.
XThe breadth (number of options per menu) should be no more than eight and the
Xdepth (number of levels of menus) should be no more than four.
X.IP -> 3
XUse words for your menu options that clearly and specifically describe 
Xwhat the user is selecting; use simple, active verbs to describe menu options.
XUse common, short English words that clearly describe the action that the 
Xcommand will carry out; choose words that are distinctive from one another.
X.IP -> 3
XDisplay the menu options in mixed, upper and lower case letters.
X.IP -> 3
XBe sure that any function keys that you use will operate correctly on all of
Xthe different types of keyboards the users have.
X.IP -> 3
XBe consistent in the use of menu formats, procedures, and wording; the 
Xmapping of keys to functions; the naming of menu options.
X.IP -> 3
XOptions should suggest or entail closure.  If a menu option calls another
Xmenu (.MENU) the option description should be the title of the called menu
Xto provide continuity.  Likewise, if a menu option calls a program (reports,
Xscreens) the option description should be the title of the report/screen.
X.IP -> 3
XDisplay only information that the user needs to know.
X.IP -> 3
XEvery menu should indicate how to exit from the screen.
X.IP -> 3
XAvoid hyphenation of words between lines.
X.IP -> 3
XUse abbreviation and acronyms only when they are significantly shorter than
Xthe full text and when they will be understood by the user.
X.IP -> 3
XOptions in a multiple column list should be organized in vertical columns
Xwhich are read from left to right on the screen.
X.IP -> 3
XPut a least two spaces between the longest item in a column and the beginning
Xof the next column.
X.IP -> 3
XUse highlighting to emphasize important information only.  Do not overuse
Xit.
X.IP -> 3
XA \fI.POPMENU\fP, if possible, should appear as close to and to the right 
Xof the option that selected it.  Probably a \fI.GETINPUT\fP screen should also.
X.PD
X
X.SS References
XHuman Factors Engineering, User Interface Guidelines, Pacific Bell, Sept (1987)
X.PP
XShore, John, The Sachertorte Algorithm and Other Antidotes to Computer
XAnxiety, Viking Penguid Inc. (1985)
X.IP * 3
XShore's book for the general public which translates into why designing 
Xgood user interfaces are necessary.
X.PP
XBeer, S. and Schoefer, W., Screen Development Guidelines - Draft,
XVersion 1.0, Pacific Bell, April (1987)
X.PP
XRubinstein R., and Hersch H.M., with Ledgard, H.F., The Human Factor:
XDesigning Computer Systems for People.  Digital Press, Digital Equipment
XCorporation, (1984).
X.IP * 3
XRubinstein's work is very interesting and original.  The text is readable
Xand the ideas presented are clear and attractive.  This is not a text book.
X.PP
XFuture Technology Architecture District, Proposed Pacific*Bell Screen 
XStandards For NonProgrammable Terminals,  Pacific Bell, May (1988)
X.PP
XDumas Joseph S., Designing User Interface for Software, Prentice Hall, 1988
X
X.SH CREDITS
XPaul J. Condie	    8/18/86	original author
X.br
X{att,bellcore,sun,ames,pyramid}!pacbell!pcbox!pjc
X.br
X
XIrving Griesman			GetInput(3X).
X.br
XSam S. Lok			popmenu(3) enhancements, runrealid(3).
X
X.SH NOTE
XIf memory size is important modify LoadKeys.c and remove all references
Xto keywords your application does not use then relink.  This will reduce
Xthe size of menu.
X
X.SH FILES
Xmenu.hlp    -  menu help file
X.br
X/usr/local/lib/menus	- some menus you might want to use or look at.
X.br
X/usr/local/lib/menus/sample.m    -  a sample menu file
X.br
X/usr/local/lib/menus/printers.m    -  printers pop-up menu
X.br
X/usr/local/lib/menus/reportsrn.m    -  report option input screen
X.br
X/usr/lib/acct/holidays		- holidays file.
X
XThe library of menus may vary from machine to machine.
X
X.SH SEE ALSO
XMenuAccess(1), curses(3X), system(3), mail(1), getenv(3), 
Xlock(1), unlock(1), GetInput(3X), checkpass(1), runrealid(1), MenuMsg(1),
XMenuPrompt(1).
X
X.SH WARNING
XBecause menu uses the environment to pass and save data you are limited on the
Xvolume of data you can have based upon the size of your environment.  
XThis will vary from machine to machine.  If you see the 
Xmessage "Unable to allocate environment memory..." then you have reached
Xyour limit.  Actually you've surpassed the limit or you wouldn't have
Xgotten the message.  But lets not squabble.
X
XMenu has very little intelligence built in to check if you exceed the bounds
Xof any fields.  If menu core dumps, especially with a bus error, you are
Xprobably trying to load too large a value into a field.
X
X.SH BUGS
XCurses bug - When a attribute is the last character on the line (spaces don't 
Xcount) the attributes do not get turned off until it hits the next character 
Xon the next line.
X
X.PP
XWhen you use the mail notification $MAIL the alarms get buffered up when
Xthe cursor is just sitting there, so, as soon as the user types something
Xat the keyboard all the alarms that were buffered take off, which means, you
Xget a beep...beep...beep...beep.  This doesn't happen on AT&T 3b machines
Xbut I've noticed it on SUNS and ARETE machines.
XYou should take the -DALARM off the CFLAGS in the makefile which tells
Xmenu not to use the alarm(2) to check for mail, but check when a key
Xhas been pressed.
X
X.PP
XMenu has not really been tested on terminals/windows that is not 24x80,
Xok,ok... it hasn't been tested at all.  For the most part it should work
Xfine, EXCEPT (you knew that was coming), when you want to create columns
Xof options using the .WINDOW keyword.  The parameters to .WINDOW are
Xabsolute therefore when you line up your columns for a 24x80 terminal and
Xyour menu is run on say a 34x132 terminal your columns will not be
Xcentered right.  Probably a new keyword should be introduced ".COLUMN"
Xwhich would have some intelligence built in to try to center columns within
Xthe window space.  It might have some problems going from a larger window
Xto a smaller window if the columns won't fit.
X.br
XAnyone volunteer to write this one?
X
X.PP
XTerminal attributes sometimes don't work right.  Especially when putting
Xmultiple attributes on one line.  In all cases I've seen it is a restriction
Xof the terminal (hardware).
X
X.bp
X.SH PROGRAMMING NOTES
XThis section is for those of you who want to or need to add new keywords.
X.PP
XThe keywords that have been provided should accommodate most
Xapplication menus, however, if customization is needed the following
Xmay come in handy.  If you introduce any neat new keywords (say like 
X".IF THEN ELSE") I would
Xappreciate you sending them to me so I can incorporate them.  Send your
XParse, Show, and Run functions along with a copy of \fILoadKeys.c\fP.
X.PP
XMenu is primarily driven from the LoadKeys.c module.  This 
Xmodule describes to menu what keywords it needs to scan for and what
Xaction to take when found.
XThere are four sections in LoadKeys (see LoadKeys example) each of which 
Xneed to be
Xdefined if you are introducing a new keyword.  LoadKkeys provides three areas
Xof control (sections 2,3,4), and it is important that you know what you
Xwant to accomplish at each control point:
X.TP 4
XParse
XWhat do you want menu to do with your keyword once it has found it during
Xthe parsing routine?  Any data you need to store for a later step, etc..
X.TP 4
XShow
XHow do you want your keyword displayed to the screen?  Define as NULL if
Xnot appropriate.
X.TP 4
XRun
XIf the user selects an option that is your keyword, what do you want done?
X
X.PP
XIf you want to put debugging code in your functions then the following
Xformat should be used.
X.nf
Xextern int  debug;
X	if (debug)
X	{
X		fprintf (stderr, "\n[%s] <%s> ...", __FILE__,
X			menu->option[opnumber]->keyword, ...);
X		fflush (stderr);
X	}
X.fi
Xwhere [Function] is the function name and <KeyWord> is the keyword being
Xprocessed.
X
X.SS ADDING A NEW KEYWORD
X.TP 8
XStep 1:
XDecide on the name of the new keyword.  For consistency sake, I suggest, it
Xshould begin with a "." and be all in caps.  Maximum length of keyword is
XMAXKEYLENGTH (15).  Then formulate a syntax for the keyword (what the user
Xneeds to type in the menufile).
X.br
XAlso, get clear in your mind what you want done at each of the three control
Xpoints.
X
X.TP 8
XStep 2:
Xvi LoadKeys.c
X.br
XStrcpy your keyword into the next available slot in KeyWord[], under SECTION 1.
XMake sure MAXKEYS in menu.h is >= the slot you strcpy'ied your keyword into.
XSee KeyWord[] below.
X
X.TP 8
XStep 3:
XIn SECTION 2 of LoadKeys.c assign the Parse function that is going 
Xto parse your keyword.
XIt should be assigned to the same slot as in SECTION 1.  First see if one
Xof the Parse functions already written will do the job.  If so use that one,
Xif not you will have to write one.  For consistency call it Parse????.c or
XPar????.c, and declare it at the beginning of LoadKeys.c.
XAll keywords must have a parse function.
XThis function is called immediately when your keyword is found while parsing
Xthe menufile.
XSee ParseKey[]() below.
X.br
XReturn Values:
X.RS 8
X.TP 9
X0
XContinue to parse next keyword.
X.TP 9
X-1
XQuit/Exit menu program.
X.TP 9
X-2
XReturn to main menu.
X.TP 9
X-4
XNOWAYJOSE - Not authorized to run this menu.
X.TP
Xanything else
XAbort this menu and return to previous menu.
X.RE
X
X.TP 8
XStep 4:
XIn SECTION 3 of LoadKeys.c assign the Show function (if your keyword is a
Xuser selectable option) that will display the
Xoption to the screen.
XIt should be assigned to the same slot as in SECTION 1.  First see if one
Xof the Show functions already written will do the job.  If so use that one,
Xif not you will have to write one.  For consistency call it Show????.c, and
Xdeclare it at the beginning of LoadKeys.c.
XThis function is called when displaying options to the screen.
XIf you don't need a Show function for your keyword assign slot to NULL.
XSee ShowKey[]() below.
X
X.TP 8
XStep 5:
XIn SECTION 4 of LoadKeys.c assign the Run function (if your keyword is a
Xuser selectable option) that will be called when the user selects this option.
XIt should be assigned to the same slot as in SECTION 1.  First see if one
Xof the Run functions already written will do the job.  If so use that one,
Xif not you will have to write one.  For consistency call it Run????.c, and
Xdeclare it at the beginning of LoadKeys.c.
XIf you don't need a Run function for your keyword assign slot to NULL.
X.br
XReturn Values:
X.RS 8
X.TP 9
X0
XAOK, continue with normal menu processing.
X.TP 9
XMAINMENU
XGoto main menu.  This is as if the user had typed an "M".
X.TP
XPREVIOUSMENU
XGoto previous menu.  This is as if the user had typed a "P".
X.TP
XQUIT
XQuit program.  This is as if the user had typed an "E".
X.TP
XSUBMENU
XIf you are introducing
Xa new submenu keyword (like \fI.MENU\fP) the Run??? function must return 
X(SUBMENU), a #define.
XRefer to \fIRunMenu.c\fP for an example.
X.TP
XGNAMEOFFSET + gindex
XGoto a specific (.GNAME) menu.
XWhere gindex = the index into the gnames array (base 0).
XThis is as if the user had typed a goto menu.
X.RE
X
X.TP 6
XStep 6:
XCompile your new functions, LoadKeys.c  and link into menu.  
XYour KeyWord should work.
XThere should be no need to change any of the existing driver routines 
X(other than LoadKeys.c)?
X
X
X.SS char  KeyWord[]
XThis array identifies all the keywords to be scanned for in your
Xmenufile.  Maximum number of keys is "MAXKEYS" defined in menu.h
Xfile.  Increasing MAXKEYS will allow more keys.
X
X.SS "int (*ParseKey[]) (keyword, menufile, menu, KeyWord, ParseKey, gnames, gfiles, gindex, opnumber)"
X.nf
Xchar		keyword[];
XFILE		*menufile;
Xstruct MenuInfo	*menu;
Xchar		KeyWord[][MAXKEYLENGTH];
Xint		(*ParseKey[])();
Xchar		gnames[][15], gfiles[][15];
Xint		*gindex;
Xint		*opnumber;
X.fi
XArray of pointers to functions that will be called to parse the
Xkeyword when found.  Any processing you want done while program
Xis parsing your keyword should be placed in this function.
XIf you have defined a new keyword you must
Xdescribe how that keyword is to be parsed.  Unless you are doing
Xsomething special ParseOption() should do the job.
XYour new function will need to malloc struct OptionInfo if you
Xwant to store some information for the option.  The following describes
Xthe data passed to all parsing functions.
X.RS 6
X.TP 6
Xkeyword
XThe keyword that was found in menufile.
X.TP 6
X*menufile
XA pointer to your menufile.  When function returns you must leave
Xthe pointer set to read in the next keyword.
X.TP 6
X*menu
XA struct holding information about the menufile.  You need to maintain
Xthe information for later processing. The Show and Run functions use the
Xinformation you store here.  See struct MenuInfo and struct OptionInfo.
X.TP 6
Xgnames
XThe goto menu names (.GNAME) presently defined (base 0).
X.TP 6
Xgfiles
XThe menufiles associated with the goto names (base 0) (.GNAME).
X.TP 6
Xgindex
XThe number of goto names (.GNAME) presently defined.
X.TP 6
Xopnumber
XThe last option number.  This is the number that will appear to the left
Xof the option, and the number the user will type in to select the option.
XYou should increment this for the next option if your keyword will
Xcontain a option number.
XThe option number should be set to zero for options you don't want a
Xnumber to appear to the left of the option.
X.nf
X.RE
X
X/*
X**     Menu structure layout
X*/
Xstruct MenuInfo
X{
X	char			name	[15];		/* file name */
X	int			wfrow;			/* window first row */
X	int			wlrow;			/* window last row */
X	int			wfcol;			/* window first col */
X	int			wlcol;			/* window last col */
X	int			row_cursor;		/* row for cursor */
X	int			col_cursor;		/* col for cursor */
X	unsigned		boxtype;		/* 0 = no box */
X	unsigned		linetype;		/* same as box */
X	int			titlecount;
X	int			optioncount;		/* base 0 */
X	struct OptionInfo	*option	[MAXOPTION];
X	struct ScreenInfo	*srn	[MAXSCREENS+1];	/* .DEFINE_SCREEN */
X							/* NULL = EOL */
X};
X
X
Xstruct OptionInfo
X{
X	char	keyword		[MAXKEYLENGTH+1];
X	int	opnumber;				/* option number */
X	char	description	[200];
X	char	command		[MAXLEN];
X	int	row;					/* row to display */
X	int	col;					/* col to display */
X};
X
Xstruct ScreenInfo
X{
X	char			name	[30];		/* screen name */
X	char			title	[100];		/* window title */
X	int			toprow;			/* upper left corner */
X	int			leftcol;
X	int			rows;			/* # rows in win */
X	int			cols;			/* # cols in win */
X	unsigned		boxtype;		/* 0 = no box */
X	int			exitlastfield;		/* after last field */
X	char			helpfile[16];
X	char			*fielddefaults;		/* init field command */
X	struct FieldInfo	*field	[MAXFIELDS+1];
X};
X
X
Xstruct FieldInfo
X{
X	char	name	[30];				/* field name */
X	char	label	[50];				/* field label */
X	int	row;					/* start position */
X	int	col;
X	int	length;
X	int	min_input;
X	char	mask	[100];
X	char	range	[1025];
X	char	type;
X	char	adjust;
X	int	mustenter;
X	char	prompt	[100];
X	char	terminator[3];				/* field terminators */
X	int	noinput;
X};
X.fi
X.RE
X
X.SS "int (*ShowKey[]) (menu, index)"
X.nf
Xstruct MenuInfo   *menu;
Xint               index;
X
X.fi
XThe following describes the data passed to all Show functions.
XArray of pointers to functions that will be called to display
Xthat option to the screen.  Unless you are doing something special
XShowOption() should do the job.
X.RS 6
X.TP 6
X*menu
XSee above for description of menu structure.
X.br
Xmenu.option[index]->description gets displayed to the screen.
X.TP 6
Xindex
XOption number in menu structure that is to be displayed.
X
X.SS "int (*RunKey[]) (menu, opnumber, KeyWord, ParseKey, ShowKey, RunKey, gnames, gfiles, gindex)"
X.nf
Xstruct MenuInfo	*menu;
Xint		opnumber;
Xint		(*ParseKey[MAXKEYS])();
Xint		(*ShowKey[MAXKEYS])();
Xint		(*RunKey[MAXKEYS])();
Xchar		KeyWord[MAXKEYS][MAXKEYLENGTH];
Xchar		gnames[MAXGNAME][15];
Xchar		gfiles[MAXGNAME][15];
Xint		gindex;
X.fi
XThe following describes the data passed to all Run functions.
XArray of pointers to functions that will be called when the
Xuser selects the option on the screen.
X.RS 6
X.TP 6
X*option
XSee above for description of struct OptionInfo.
X.br
Xoption->command is what is to be executed for this option.
X.RE
X
X.SS LoadKeys Example:
X.nf
XLoadKeys (KeyWord, ParseKey, ShowKey, RunKey)
X
X	char	KeyWord[][10];
X	int	(*ParseKey[])(), (*ShowKey[])(), (*RunKey[])();
X{
X	int	ParseTitle(), ParseOption();
X	int	ShowOption();
X	int	RunSystem();
X
X	/*
X	**   Section 1:
X	**   	Identify the new keyword here.
X	*/
X	strcpy (KeyWord[1], ".TITLE");
X	strcpy (KeyWord[2], ".MENU");
X	strcpy (KeyWord[3], ".SYSTEM");
X
X	/*
X	**  Section 2:
X	**	Identify the parse function for the new keyword.
X	**  	Every keyword needs a parse function.
X	*/
X	ParseKey[1] = ParseTitle;
X	ParseKey[2] = ParseOption;
X	ParseKey[3] = ParseOption;
X
X	/*
X	**  Section 3:
X	**	Identify the show function for keywords that are options.
X	**  	If ShowKey is set to NULL the option will not be displayed.
X	*/
X	ShowKey[1] = NULL;	/* Title gets displayed in the parse function */
X	ShowKey[2] = ShowOption;
X	ShowKey[3] = ShowOption;
X
X	/*
X	**  Section 4:
X	**	Identify the run function for keywords that are options.
X	**  	If RunKey is set to NULL the cursor will not stop at 
X	**  	the option.  The user will not be able to select it.
X	*/
X	RunKey[1] = NULL;	/* You can't select a title */
X	RunKey[2] = RunMenu;
X	RunKey[3] = RunSystem;
X}
X.fi
X
X
X
X
X.PP
XTHE END     (whew)
SHAR_EOF
echo "File menu.1 is complete"
chmod 0644 menu.1 || echo "restore of menu.1 fails"
echo "x - extracting Main.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > Main.c &&
Xstatic char Sccsid[] = "%W%   DeltaDate %G%   ExtrDate %H%";
X/*	PROGRAM	   Menu  (generic)
X**	AUTHOR	   Paul J. Condie
X**	DATE	   8/18/86
X*/
X
X#include	<curses.h>
X#include	<signal.h>
X#include	"menu.h"
X
Xint	MAILCALL = FALSE;
Xint	mailrow;
Xint	mailcol;
Xint	debug = FALSE;				/* debug flag */
Xint	trapsigs = 1;				/* flag - trap ignore signals */
X
Xchar		KeyWord[MAXKEYS][MAXKEYLENGTH];	/* the keywords */
Xint		(*ShowKey[MAXKEYS])();
Xstruct MenuInfo	menu;
X
X
Xmain (argc, argv)
X
X	int		argc;
X	char		*argv[];
X{
X	FILE		*fopen(), *menufile;
X	char		*getenv();
X	char		*findfile();
X	int		shutdown();		/* clean up before exit */
X	int		(*ParseKey[MAXKEYS])(), 
X			(*RunKey[MAXKEYS])();
X/*
X**	menuname keeps track of nested submenus.
X**	mptr is the index into menuname 0 = main menu
X**					1 = sub menu 2 = sub sub menu etc.
X**					menuname[mptr--] = previous menu
X*/
X	char		menuname[MAXMENU][15];			/* filenames  */
X	char		filename[80];
X	int		menuoption[MAXMENU];	/* what option to highlight */
X	int		i, exitkey, mptr=0, rc;
X	int		j;			/* loop variable */
X	char		gnames[MAXGNAME][15];	/* goto menu names */
X	char		gfiles[MAXGNAME][15];	/* goto file names */
X	int		gindex = 0;		/* goto index */
X	char		*ws;
X	extern int	optind;
X	extern char	*optarg;
X	int		gotorow = 6;		/* default goto menu row */
X	int		gotocol = 8;		/* default goto menu col */
X	int		keys = 0;		/* show keyboard values */
X	int		parse_rc = 0;		/* parsedriver return code */
X
X
X
X   	while ((rc = getopt (argc, argv, "dp:vk:n:")) != EOF)
X      		switch (rc)
X      		{
X	 	   case 'd':
X			/* Get debug excited */
X			debug++;
X			break;
X
X	 	   case 'p':
X			/* Set row and column for ^g */
X			sscanf (optarg, "%d,%d", &gotorow, &gotocol);
X			break;
X
X         	   case 'v':
X			/* Show Version */
X			fprintf (stderr, "%s   Version %s\n", argv[0], VERSION);
X			exit (0);
X			break;
X		   case 'k':
X			/* Show keyboard key values - for .menuinit */
X			keys++;
X			break;
X		   case 'n':
X			/* don't trap signals */
X			trapsigs = 0;
X			break;
X      		}
X   	if (argc == optind  &&  (!keys))
X   	{
X      		fprintf (stderr, 
X		       "\nUsage: %s [-v] [-p row,col] [ -keyboard ] menufile\n",
X				argv[0]);
X      		exit (1);
X   	}
X	if (!keys)
X   		sscanf (argv[optind], "%s", menuname[0]);
X   	menuoption[0] = 1;
X
X	if (trapsigs)
X	{
X		signal (SIGINT, SIG_IGN);
X		signal (SIGQUIT, SIG_IGN);
X	}
X	else
X	{
X		signal (SIGINT, shutdown);
X		signal (SIGQUIT, shutdown);
X	}
X	signal (SIGHUP, shutdown);
X   	signal (SIGALRM, SIG_IGN);		/* to fix bug in curses */
X
X	/* curses stuff */
X   	initscr ();
X   	cbreak ();
X   	noecho ();
X   	nonl ();
X#ifdef SYS5
X   	keypad (stdscr, TRUE);
X#endif
X
X   	SetTerm ();				/* set terminal keyboard */
X	if (keys)
X	{
X		keyboard ();
X		shutdown ();
X	}
X
X   	LoadKeys (KeyWord, ParseKey, ShowKey, RunKey);
X
X
X	/*
X	**	Parse, Show and Run each menu selected until exit program.
X	*/
X   	do
X   	{
X      		move (0,0);
X      		clrtobot ();				/* clear screen */
X
X		/*
X		**  Check the parse return code from the last parse
X		**  to determine what message to display.
X		*/
X		switch (parse_rc)
X		{
X		   case NOWAYJOSE:
X			BEEP;
X			attrset (A_REVERSE|A_BOLD);
X      			mvprintw (ErrRow, 0, 
X			      "You have not been authorized to run that menu.");
X			attrset (A_NORMAL);
X			break;
X		}
X
X      		initmenu (&menu);			/* init menu defaults */
X
X		/* open menu script file */
X		strcpy (filename, findfile (menuname[mptr], ".",
X			getenv("MENUDIR"), ""));
X      		if ((menufile = fopen (filename, "r")) == NULL)
X		{
X            		BEEP;
X            		mvprintw (20, 0, "Unable to locate (%s) file.", 
X					menuname[mptr]);
X            		shutdown ();
X		}
X
X
X		/*
X		**  Return Codes from parsedriver:
X		**	NOWAYJOSE - not authorized for this menu.
X		*/
X      		parse_rc = parsedriver (menufile, KeyWord, ParseKey, &menu, 
X				gnames, gfiles, &gindex);
X      		fclose (menufile);
X
X		switch (parse_rc)
X		{
X		   case 0:
X			/* success */
X			break;
X
X		   case QUIT:
X			shutdown ();
X			break;
X
X		   case MAINMENU:
X			/* not tested */
X			mptr = 0;
X			break;
X
X		   default:
X	 		if (mptr > 0)
X	 		{
X	    			mptr--;		/* return to previous menu */
X	    			continue;
X	 		}
X	 		else
X			{
X				BEEP;
X				attrset (A_REVERSE|A_BOLD);
X      				mvprintw (ErrRow, 0, 
X			      	"You have not been authorized to run that menu.");
X				attrset (A_NORMAL);
X	    			shutdown ();  /* not authorized for main menu */
X			}
X			break;
X		} /* end switch (parse_rc) */
X
X		/* display menu */
X      		showdriver (KeyWord, ShowKey, &menu);
X
X		/*
X		**  rundriver will return:
X		**	MAINMENU	go directly to main menu
X		**	PREVIOUSMENU	go to previous menu
X		**	REPARSE		reparse & display current menu
X		**	QUIT		quit program.
X		**	0 - 99		option number containing sub menu 
X		**			filename.
X		**	GNAMEOFFSET-199 go directly to menu 
X		**			gnames[exitkey%GNAMEOFFSET]
X		*/
X      		exitkey = rundriver (RunKey, ParseKey,
X				&menuoption[mptr], gnames, gfiles, gindex,
X				gotorow, gotocol);
X		if (menu.after_menu != (char *)NULL)
X			RunAftMenu (&menu);
X
X
X
X      		switch (exitkey)
X      		{
X         	   case MAINMENU:
X			mptr = 0;
X			break;
X         	   case PREVIOUSMENU:
X			if (mptr > 0)   mptr--;
X			break;
X	 	   case REPARSE:
X			break;
X	 	   case QUIT:
X			break;
X
X			/*
X			** A submenu option has been selected or a goto menu.
X			** exitkey is the option # selected (which is a submenu)
X			** The submenu filename is in 
X			** menu.option[exitkey]->command
X			*/
X         	   default:
X			if (exitkey >= GNAMEOFFSET)	/* goto gname menu */
X		   		strcpy (menuname[++mptr], 
X					gfiles[exitkey % GNAMEOFFSET]);
X			else
X		   		sscanf (menu.option[exitkey]->command, "%s", 
X			   		menuname[++mptr]);
X
X			menuoption[mptr] = 1;
X			break;
X      		} /* end switch */
X
X		clean_menu (&menu);		/* free menu space */
X
X   	} while (exitkey != QUIT);
X   	shutdown ();
X}
X
X
X
Xshutdown ()
X{
X   move (LINES-1, 0);
X   refresh ();
X   endwin ();
X   exit (1);
X}
SHAR_EOF
chmod 0644 Main.c || echo "restore of Main.c fails"
echo "x - extracting LoadKeys.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > LoadKeys.c &&
X#ifndef LINT
Xstatic char Sccsid[] = "%W%   DeltaDate %G%   ExtrDate %H%";
X#endif
X
X/*  FUNCTION:	LoadKeys()
X**		Identifies all the recognizable keywords and the
X**		function(s) 2b called to process the keyword.
X**  ARGS:	KeyWord		array to hold keywords
X**		ParseKey	array to hold parse functions
X**		ShowKey		array to hold display functions
X**		RunKey		array to hold run functions
X**  RETURNS:	zilch
X*/
X
X#include		"menu.h"
X
XLoadKeys (KeyWord, ParseKey, ShowKey, RunKey)
X
X	char	KeyWord[][MAXKEYLENGTH];
X	int	(*ParseKey[])(), (*ShowKey[])(), (*RunKey[])();
X{
X	int	ParseTitle(), ParseOption(), ParseBanner(), ParseBox(), 
X		ParseLine(), ParseWindow(), ParseComnt(), ParseUnix(),
X		ParseGname(), ParseAuthr(), ParseText(), ParseCursor(),
X		ParseSpace(), ParseDefineScreen(), ParInclude(), ParAssign(),
X		ParAftMenu();
X	int	ShowOption();
X	int	RunSystem(), RunExit(), RunSetenv(), RunMenu(), RunPopMenu(),
X		RunGetInput();
X
X
X/*
X**	SECTION 1:
X**	Starting with base 1.
X**	Identify keywords to be acted upon when found in your
X**	menu file.
X**	Make sure MAXKEYS is >= the number of entries here.
X*/
X
X   strcpy (KeyWord[1], ".TITLE");	/* title line */
X   strcpy (KeyWord[2], ".MENU");	/* submenu option */
X   strcpy (KeyWord[3], ".SYSTEM");	/* system call option */
X   strcpy (KeyWord[4], ".BOX");  	/* encase menu in a box */
X   strcpy (KeyWord[5], ".BANNER"); 	/* welcome banner screen */
X   strcpy (KeyWord[6], ".LINE"); 	/* line between title & options */
X   strcpy (KeyWord[7], ".WINDOW"); 	/* window area for options */
X   strcpy (KeyWord[8], "###"); 		/* comment line */
X   strcpy (KeyWord[9], ".UNIX"); 	/* unix command line */
X   strcpy (KeyWord[10], ".GNAME"); 	/* menu name (used in goto menu) */
X   strcpy (KeyWord[11], ".AUTHORIZE"); 	/* login's authorized to run menu */
X   strcpy (KeyWord[12], ".TEXT"); 	/* display text at row and column */
X   strcpy (KeyWord[13], ".CURSOR"); 	/* where to put the cursor */
X   strcpy (KeyWord[14], ".EXIT"); 	/* exit menu program */
X   strcpy (KeyWord[15], ".SETENV"); 	/* set enviroment variable */
X   strcpy (KeyWord[16], ".SPACE"); 	/* put a space between options */
X   strcpy (KeyWord[17], ".POPMENU"); 	/* pop menu option */
X   strcpy (KeyWord[18], ".DEFINE_SCREEN");/* define a prompt screen */
X   strcpy (KeyWord[19], ".GETINPUT");	/* prompt screen */
X   strcpy (KeyWord[20], ".INCLUDE");	/* include a menu file */
X   strcpy (KeyWord[21], "*=*");		/* assignment - variable=value */
X   strcpy (KeyWord[22], ".AFTER_MENU");	/* command to run after menu */
X
X   strcpy (KeyWord[23], ""); 		/* END OF LIST */
X
X
X/*
X**	SECTION 2:
X**	Starting with base 1.
X**	Identify function names to correspond with above keywords.
X**	These functions describe what is to be done when above keyword
X**	is found while parsing the "menu file".
X**	Every keyword needs a Parse??? function.
X*/
X
X   ParseKey[1] = ParseTitle;
X   ParseKey[2] = ParseOption;
X   ParseKey[3] = ParseOption;
X   ParseKey[4] = ParseBox;
X   ParseKey[5] = ParseBanner;
X   ParseKey[6] = ParseLine;
X   ParseKey[7] = ParseWindow;
X   ParseKey[8] = ParseComnt;
X   ParseKey[9] = ParseUnix;
X   ParseKey[10] = ParseGname;
X   ParseKey[11] = ParseAuthr;
X   ParseKey[12] = ParseText;
X   ParseKey[13] = ParseCursor;
X   ParseKey[14] = ParseOption;
X   ParseKey[15] = ParseOption;
X   ParseKey[16] = ParseSpace;
X   ParseKey[17] = ParseOption;
X   ParseKey[18] = ParseDefineScreen;
X   ParseKey[19] = ParseOption;
X   ParseKey[20] = ParInclude;
X   ParseKey[21] = ParAssign;
X   ParseKey[22] = ParAftMenu;
X
X
X/*
X**	SECTION 3:
X**	These functions describe what is to be done to display the
X**	option to the screen.  The option you loaded into OptionInfo.
X**	If set to NULL then the option is not displayed.
X*/
X
X   ShowKey[1] = NULL;
X   ShowKey[2] = ShowOption;
X   ShowKey[3] = ShowOption;
X   ShowKey[4] = NULL;
X   ShowKey[5] = NULL;
X   ShowKey[6] = NULL;
X   ShowKey[7] = NULL;
X   ShowKey[8] = NULL;
X   ShowKey[9] = NULL;
X   ShowKey[10] = NULL;
X   ShowKey[11] = NULL;
X   ShowKey[12] = NULL;
X   ShowKey[13] = NULL;
X   ShowKey[14] = ShowOption;
X   ShowKey[15] = ShowOption;
X   ShowKey[16] = NULL;
X   ShowKey[17] = ShowOption;
X   ShowKey[18] = NULL;
X   ShowKey[19] = ShowOption;
X   ShowKey[20] = NULL;
X   ShowKey[21] = NULL;
X   ShowKey[22] = NULL;
X
X
X/*
X**	SECTION 4:
X**	These functions explain what you want done when the user
X**	selects the option on the screen with the corresponding 
X**	keyword.
X**	If set to NULL the keyword becomes unselectable.
X*/
X
X   RunKey[1] = NULL;
X   RunKey[2] = RunMenu;
X   RunKey[3] = RunSystem;
X   RunKey[4] = NULL;
X   RunKey[5] = NULL;
X   RunKey[6] = NULL;
X   RunKey[7] = NULL;
X   RunKey[8] = NULL;
X   RunKey[9] = NULL;
X   RunKey[10] = NULL;
X   RunKey[11] = NULL;
X   RunKey[12] = NULL;
X   RunKey[13] = NULL;
X   RunKey[14] = RunExit;
X   RunKey[15] = RunSetenv;
X   RunKey[16] = NULL;
X   RunKey[17] = RunPopMenu;
X   RunKey[18] = NULL;
X   RunKey[19] = RunGetInput;
X   RunKey[20] = NULL;
X   RunKey[21] = NULL;
X   RunKey[22] = NULL;
X}
SHAR_EOF
chmod 0644 LoadKeys.c || echo "restore of LoadKeys.c fails"
echo "x - extracting parsedrive.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > parsedrive.c &&
Xstatic char Sccsid[] = "@(#)parsedrive.c	1.5   DeltaDate 1/22/90   ExtrDate 1/22/90";
X
X/*  FUNCTION:	parsedriver()
X**		This is the driver routine in parseing the menu
X**		file.  This function calls the appropriate parse
X**		function for that keyword.
X**  ARGS:	keyword		the keyword "AUTHORIZE"
X**		menufile	the unix menu file
X**		menu		menu structure
X**		gnames		holder of goto menu names
X**		gfiles		holder of goto menu names (menu file)
X**		gindex		# of gnames
X**  RETURNS:	0	success
X*/
X
X#include	<curses.h>
X#include	"menu.h"
X
X	int	swin, ewin, longest;
X
Xparsedriver (menufile, KeyWord, ParseKey, menu, gname, gfile, gindex)
X
X	FILE		*menufile;
X	char		KeyWord[][MAXKEYLENGTH];
X	int		(*ParseKey[])();
X	struct MenuInfo	*menu;
X	char		gname[][15], gfile[][15];
X	int		*gindex;
X{
X	char	keyword[80];
X	int	rcde, I, KEYFOUND;
X	int	opnumber = 0;				/* last option number */
X
X
X   	/* Set default .WINDOW area */
X   	menu->wfcol = 0;
X   	menu->wlcol = COLS-1;
X	menu->wfrow = 0;
X   	menu->wlrow = LINES-1;
X   	menu->titlecount = 0;
X   	menu->optioncount = 0;
X   	swin = ewin = longest = 0;
X
X   	/* loop through each keyword */
X   	rcde = fscanf (menufile, "%s", keyword);
X   	while (rcde != EOF)
X   	{
X		if (strlen (keyword) >= 80-2)
X		{
X      			BEEP;
X      			mvprintw (ErrRow-2, 0, 
X				"Your keyword <%s> is toooo looong.  Max = %d",
X				keyword, 80-2);
X      			shutdown ();
X		}
X		/*
X		**  Check if we found a defined keyword
X		*/
X      		KEYFOUND = FALSE;
X      		for (I = 1; I <= MAXKEYS; I++)
X      		{
X			/*
X         		if (strcmp (keyword, KeyWord[I]) == 0)
X			*/
X         		if (strmatch (keyword, KeyWord[I]))
X         		{
X            			KEYFOUND = TRUE;
X	    			if (ParseKey[I] != NULL)
X	    			{
X               				rcde = (*ParseKey[I]) (keyword, 
X						menufile, menu, KeyWord, 
X						ParseKey, gname, gfile, gindex, 
X						&opnumber);
X					/*
X					** The return code from each parse
X					** function must be 0 in order to
X					** continue.
X					*/
X	       				if (rcde != 0)   return (rcde);
X	    			}
X            			break;
X         		}
X      		}
X      		if (!KEYFOUND)
X      		{
X         		BEEP;
X         		mvprintw (ErrRow-2, 0, "ERROR: (%s) Key not found.", 
X					keyword);
X         		shutdown ();
X      		}
X      		rcde = fscanf (menufile, "%s", keyword);
X   	} 
X
X   	EndWindow (menu);
X   	return (0);
X}
SHAR_EOF
chmod 0444 parsedrive.c || echo "restore of parsedrive.c fails"
echo "x - extracting showdriver.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > showdriver.c &&
Xstatic char Sccsid[] = "@(#)showdriver.c	1.2   DeltaDate 10/16/88   ExtrDate 1/22/90";
X
X/*  FUNCTION:	showdriver()
X**		The driver module to initially display the options
X**		to the screen.
X**  ARGS:	keyword		the keyword found
X**		ShowKey		show functions
X**		menu		menu structure
X**  RETURNS:	none
X*/
X
X#include	<curses.h>
X#include	"menu.h"
X
X
Xshowdriver (KeyWord, ShowKey, menu)
X
X	char		KeyWord[][MAXKEYLENGTH];
X	int		(*ShowKey[])();
X	struct MenuInfo	*menu;
X{
X	int		i, j;
X
X
X
X	/*
X	**	Loop through options and call apropriate function.
X	*/
X
X   	for (i = 0; i < menu->optioncount; i++)
X      		for (j = 1; j <= MAXKEYS; j++)
X         		if (strcmp (menu->option[i]->keyword, KeyWord[j]) == 0)
X	 		{
X	    			if (ShowKey[j] != NULL)   
X					(*ShowKey[j]) (menu, i);
X	    			break;
X	 		}
X   	refresh ();
X}
SHAR_EOF
chmod 0444 showdriver.c || echo "restore of showdriver.c fails"
echo "x - extracting rundriver.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rundriver.c &&
Xstatic char Sccsid[] = "%W%   DeltaDate %G%   ExtrDate %H%";
X
X/*  FUNCTION:	rundriver()
X**		The driver module to run each selectable option.
X**		Runmenu will call the appropriate run function
X**		for that keyword.
X**  ARGS:	keyword		the keyword "AUTHORIZE"
X**		menufile	the unix menu file
X**		menu		menu structure
X**		gnames		holder of goto menu names
X**		gfiles		holder of goto menu names (menu file)
X**		gindex		# of gnames
X**  RETURNS:	QUIT		exit pgm
X**		MAIN		go to main menu
X**		PREVIOUS	go to previous menu
X**		index to submenu
X*/
X
X#include	<curses.h>
X#include	<signal.h>
X#include	"menu.h"
X#include	"terminal.h"
X
X#define		INITMENU	0
X#define		GOTOMENU	1
X
Xextern int	MAILCALL;
Xextern int	trapsigs;
Xextern int	debug;
X
Xextern	struct MenuInfo	menu;
Xint		tmpoption;
Xint		ckik;				/* current keyword in KeyWord */
Xextern	int	(*ShowKey[])();
Xextern	char	KeyWord[][MAXKEYLENGTH];
X
X
Xrundriver (RunKey, ParseKey, option, gnames, 
X		gfiles, gindex, gotorow, gotocol)
X
X	int		(*RunKey[])(), *option;
X	int		(*ParseKey[])();
X	char		gnames[][15], gfiles[][15];
X	int		gindex;
X	int		gotorow;
X	int		gotocol;
X{
X	FILE		*fopen(), *fp;
X	char		*findfile();
X	char		*upper();
X	int		shutdown();
X	char		select[78], command[MAXLEN];
X	char		matchstr[60];
X	int		exitkey, index;
X	int		i, j;
X	int		lastopnumber = 0;		/* last option # */
X	int		MATCHED;			/* char match flag */
X	int		ch;
X
X
X
X	/*
X   	**  What is the last option number ?
X   	*/
X	for (i = menu.optioncount-1; i >= 0; i--)
X		if (menu.option[i]->opnumber != 0)
X		{
X			lastopnumber = menu.option[i]->opnumber;
X			break;
X		}
X
X	if (lastopnumber <= 0)   return (QUIT);		/* no options */
X	select[0] = '\0';
X	matchstr[0] = '\0';
X
X	/*
X   	**  Loop through options untill user exits menu or selects
X   	**  another menu.
X   	*/
X	for (;;)
X	{
X#ifndef ALARM
X		if (MAILCALL)
X			checkmail ();
X#endif
X
X		/* highlight current option */
X		for (ckik = 1; ckik <= MAXKEYS  &&  KeyWord[ckik] != NULL;
X		     ckik++)
X			if (strcmp (menu.option[*option-1]->keyword, 
X				    KeyWord[ckik]) == 0)
X			{
X				if (ShowKey[ckik] != NULL)
X				{
X					/* display option */
X					(*ShowKey[ckik]) (&menu, (*option)-1);
X					mvaddch (menu.option[(*option)-1]->row,
X					       menu.option[(*option)-1]->col-1,
X					       ' ');
X					/*
X					** turn on reverse video 
X					** maintaining current attributes
X					*/
X					exitkey =  slength(menu.option[(*option)-1]->description) + menu.option[(*option)-1]->col + 5;
X					for (j = menu.option[(*option)-1]->col-1; j <= exitkey; j++)
X					{
X						ch = mvinch (menu.option[(*option)-1]->row, j);
X						ch |= A_REVERSE;
X						mvaddch (menu.option[(*option)-1]->row, j, ch);
X					}
X
X				}
X				break;
X			}
X
X#ifdef BSD
X		standend ();
X#else
X		attrset (A_NORMAL);
X#endif
X
X		tmpoption = *option;
X		if (RunKey[ckik] != NULL)
X			exitkey = GetOption (menu.row_cursor, menu.col_cursor,
X					     select);
X		else
X			/* so we don't go in a loop */
X			exitkey = (exitkey == KEY_UP || 
X			           exitkey == KeyUp) ? KEY_UP : KEY_DOWN;
X		*option = tmpoption;
X
X		if (exitkey == KeyDown)   	exitkey = KEY_DOWN;
X		if (exitkey == KeyUp)		exitkey = KEY_UP;
X		if (exitkey == KeyTab)		exitkey = KEY_TAB;
X		if (exitkey == KeyBTab)		exitkey = KEY_BTAB;
X		if (exitkey == KeyReturn)	exitkey = KEY_RETURN;
X		if (exitkey == KeyMainMenu)	exitkey = KEY_MAINMENU;
X		if (exitkey == KeyPrevMenu)	exitkey = KEY_PREVMENU;
X		if (exitkey == KeyExitMenu)	exitkey = KEY_EXITMENU;
X		if (exitkey == KeyGname)	exitkey = KEY_GNAME;
X
X		/* unhighlight current option */
X		if (ShowKey[ckik] != NULL)
X		{
X			mvaddch (menu.option[(*option)-1]->row, 
X			    menu.option[(*option)-1]->col-1, ' ');
X			strcat (menu.option[(*option)-1]->description, " ");
X			(*ShowKey[ckik]) (&menu, *option-1);
X			menu.option[(*option)-1]->description[strlen(menu.option[(*option)-1]->description)-1] = '\0';
X		}
X
X
X		switch (exitkey)
X		{
X		case KEY_DOWN:
X		case 'j':
X			*option = (*option) >= menu.optioncount 
X					? 1 : ++(*option);
X			break;
X
X		case KEY_UP:
X		case 'k':
X			*option = (*option) <= 1 
X					? menu.optioncount : --(*option);
X			break;
X
X		case KEY_TAB:
X			/* A tab will hop forward four options at a time. */
X			if (menu.optioncount > 4)
X			{
X				*option += 4;
X				if (*option > menu.optioncount)
X					*option = 1 + *option - 
X						  menu.optioncount - 1;
X			}
X			else
X				*option = *option >= menu.optioncount ? 1 : 
SHAR_EOF
echo "End of part 3"
echo "File rundriver.c is continued in part 4"
echo "4" > s2_seq_.tmp
exit 0



More information about the Alt.sources mailing list