[net.sources] menu.c, menu.1l, and mcheck.c

emigh@ecsvax.UUCP (09/27/83)

: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting mcheck.c'
sed 's/^X//' <<'//go.sysin dd *' >mcheck.c
X/*
 *  MCHECK.C -- Menu File Syntax Checker for MENU.C
 *	by Richard Conn
 *
 *	MCHECK checks the syntax of a menu file (one which is to be
 * processed by MENU.C) for errors and gives complete, informative
 * diagnostics.
 *
 */

#define versmaj	1	/* Major Version Number */
#define	versmin	2	/* Minor Version Number */

X/*  Revision History
 *	Version 1.0 - Richard Conn
 *	Version 1.1 - Richard Conn
 *		The ability to check for menu references out of range
 *		added.
 *	Version 1.2 - Richard Conn
 *		Global references made local.
 */

#define FALSE	0
#define TRUE	~FALSE

#define HASH	'#'
#define DASH	'-'
#define	GOTO	':'
#define LF	'\012'

#include <stdio.h>

main(argc,argv)
int argc;
char *argv[];
{
	int c, menunum, nxtline, locmax;
	FILE *fopen(), *fd;

	/* banner */
	printf("MCHECK Version %d.%d\n", versmaj, versmin);

	/* check for file name */
	if (argc==1) {
		printf("Usage:  mcheck filename\n");
		exit(-1);
	}

	/* try to open menu file for input */
	if ((fd=fopen(argv[1],"r")) == NULL) {
		printf("Menu File %s NOT Found\n", argv[1]);
		exit(-1);
	}

	/* print file name */
	printf("File: %s\n", argv[1]);

	/* process file */
	nxtline = 1;
	if ((c=getc(fd)) == DASH) {
		prglobals(fd,&nxtline);
		c=getc(fd);
	}
	menunum = 1;	/* menu count */
	locmax = 0;	/* max menu referenced by GOTOs */
	while (c != EOF) {
		if (c != HASH) {
			printf("New menu expected but not found at line %d\n",
			nxtline);
			fclose(fd);
			exit(0);
		}
		prglobals(fd,&nxtline);
		if ((c=getc(fd)) == EOF) {
			printf("End of Menu after line %d\n", nxtline-1);
			if (locmax > menunum)
				printf("GOTO Reference Out of Range in File\n");
			printf("MCHECK Complete\n");
			fclose(fd);
			exit(0);
		}
		printf("Menu %d at Line %d\n", menunum++, nxtline-1);
		prdisp(fd,&nxtline);
		c = prtext(fd,&nxtline,&locmax);
	}
}

X/*  process global parameters  */
prglobals(fd,nxtline)
FILE *fd;
int *nxtline;
{
	int c;

	while ((c=getc(fd)) != LF)
		switch (c) {
		case HASH :
		case 'D' :
		case 'd' :
		case 'P' :
		case 'p' :
		case 'X' :
		case 'x' :
			break;  /* OK */
		case EOF :
			premature(nxtline);
			break;
		default  :
			printf("Invalid Global %c at line %d\n",
			c, *nxtline);
			break;
		}
	(*nxtline)++;
}

X/* process text */
prtext(fd,nxtline,locmax)
FILE *fd;
int *nxtline, *locmax;
{
	int c, mynum;

	while ((c=getc(fd)) != HASH) {
		if (c != LF) {
			c = getc(fd);
			if (c == GOTO) {
				mynum = 0;
				while (digit(c=getc(fd)))
					mynum = mynum*10 + (c-'0');
				ungetc(fd,c);
				if (*locmax < mynum) *locmax = mynum;
				if (!mynum)
					printf("GOTO Menu 0 on Line %d\n",
					*nxtline);
			}
		}
		while (c != LF) {
			if (c==EOF) premature(nxtline);
			c = getc(fd);
		}
		(*nxtline)++;
	}
	return(c);
}

X/* process display */
prdisp(fd,nxtline)
FILE *fd;
int *nxtline;
{
	int c;

	while ((c=getc(fd)) != HASH) {
		while (c != LF) {
			if (c==EOF) premature(nxtline);
			c = getc(fd);
		}
		(*nxtline)++;
	}
	return(c);
}

X/* check for digit */
digit(c)
int c;
{
	if (c<'0' || c>'9') return(FALSE);
	else return(TRUE);
}

X/* premature EOF */
premature(nxtline)
int *nxtline;
{
	printf("Premature end of file at line %d\n", *nxtline);
	exit(-1);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 mcheck.c
	/bin/echo -n '	'; /bin/ls -ld mcheck.c
fi
/bin/echo 'Extracting menu.1l'
sed 's/^X//' <<'//go.sysin dd *' >menu.1l
X.TH MENU 1
X.SH NAME
MENU -- A Menu Preprocessor for UNIX
X.sp 2
MENU Version 2.0 by Richard Conn
X.SH SYNOPSIS

	MENU is invoked by a command line of the following form:

X.ce
menu [-n] menufile

where the "-n" is optional and is the number of a menu to be invoked in
a menu file which contains more than one menu.

	Hence, MENU command lines may take the following forms:

X.nf
		menu mymenu	<-- invoke on file 'mymenu'
		menu -2 mymenu	<-- invoke menu 2 of file 'mymenu'

X.fi
X.SH DESCRIPTION
	MENU (written in C) is a very simple menu preprocessor for use
under the UNIX operating system.  A user can compose files containing
screen displays and command lines which are invoked in response to
single-character
commands, and MENU will present those screen displays to the user and
accept both single-character and text string (terminated by a RETURN)
input from the user.

X.SH WRITING MENU FILES

	A file which can be processed by MENU can take on the following
general format:

X.nf
-o		<-- set global options (optional line)
#o		<-- define screen display and set local options
<text>		<-- text of screen display
#		<-- end of screen display
<c><text>	<-- command letter followed by text of command line
   ...		<-- additional menus, all of the format
			#o
			<text>
			#
			<c><text>
#o		<-- define screen display and set local options for
			next menu
<text>
#
<c><text>	<-- command letter followed by text of command line
#		<-- marks end of last menu

X.fi
	There are three options recognized by the MENU processor.  These
options are:

X.nf
		d - Display text of menu (screen display)
		p - If 'd' is on, page (fill screen with blank lines)
			when end of menu text (screen display)
			is reached
		x - Allow the user to exit to UNIX

X.fi
	When MENU is first invoked, all three options are OFF.  The text
of the screen displays will not be shown and the user will not be allowed
to exit to UNIX.

	The first line (which is optional) of the menu file
toggles the global options to ON from their initial state of OFF.  The
dash (-) can be followed by any combination of the menu options in any
order (-dpx = -xpd = -pxd).  This global option line sets the options
for all of the menus in the file except for those menus whose option
line toggles selected options.

	Each menu begins with its own option line.  This is the hash (#)
followed by zero or more of the option characters.  For each option character
specified, the state of the global options FOR THIS MENU ONLY is reversed.
Note the following example:

X.ne 20
X.nf
		-dpx		<-- turn on all options
		#x		<-- do not allow the user to exit
					to UNIX for this menu
		<text>
		#
		<c><text>
		#px		<-- do not allow the user to exit
					to UNIX and do not page the
					screen display for this menu
		<text>
		#
		<c><text>
		#		<-- all options are on for this menu
		<text>
		#
		<c><text>
		#

X.fi
	The text of the screen display (that text which follows the
local options line for each menu) can be any text desired with the
one exception that the first character of any line of this text may
not be a hash (#).  The hash, of course, signals the end of the
screen display text and the beginning of the command text.
Example:

X.nf
		#dpx		<-- this menu has no globals set
			Any	<-- text of menu
			Text
			I Want
		#
		<c><text>
		#		<-- only one menu in this file

X.fi
	Finally, the last part of a menu entry is the command
definition itself.  The definition of a menu command is of the
following general form:

X.ce
<char><text>

where <char> is one character which will invoke the text of a
command line.  For example, valid menu command lines include:

X.nf
		dls		<-- run ls if char 'd' is typed
		Dls | pr -4t	<-- run 'ls | pr -4t' if char
					'D' is typed

X.fi
	There are three special characters which may be embedded
into the text of the command line to cause MENU to perform some
additional processing.  These characters are:

X.nf
		:	<-- goto a menu
		!	<-- cause MENU to wait when
				command line completes
		'	<-- prompt user for string input

X.fi
	The first special character is used to transfer control
from one menu in a menu file to another.  If the colon (:) is the
first character of text (right after the single-character command),
then the rest of the line is assumed to be the text of a number,
and control is transferred to that menu (first menu is 1, second is 2, etc)
in the file.  ":2" will transfer to menu 2, ":20" will transfer
to menu 20, etc.  Examples:

X.nf
		2:2	<-- goto menu 2 if char '2' is typed
		h:1	<-- goto menu 1 if char 'h' is typed
		?:100	<-- goto menu 100 if char '?' is typed

X.fi
	The second character is used to cause MENU to wait for user
input after the text of the command line is executed (before displaying
the screen of the menu the user is returning to).  If the exclamation
mark (!) is the first character of text (right after the single-character
command), then MENU will wait after the text of the command line
is executed.  Examples:

X.nf
		d!ls		<-- run 'ls' and then wait
		D!ls | pr -4t	<-- run 'ls | pr -4t' and then wait

X.fi
	Finally, the third character is followed by text to prompt the
user for input, and the user is allowed to enter any text he desires.
This text will be inserted at the point of the prompt.  Unlike the
other two commands, the text input command (') may appear anywhere
in the text of the command line.  This text may be bracketed by the
quote character (like 'Enter Source File'), in which case the user's
input is inserted into the command line at this point and command line
processing from the menu file resumes after the second quote.  Alternatively,
this text may be preceeded by the quote character (like 'Enter File? ),
in which case the end of the line indicates the end of the prompt.  In
both cases, the last character of the prompt is followed by a trailing
blank to improve readability.
Examples:

X.ne 22
X.nf
		u'Enter Command? 	<-- user is prompted with
						'Enter Command? '
						and his text becomes
						the command line
		u!'Command? 		<-- like above, but MENU
						waits when the command
						is completed
		d!ls 'File Spec?' | wc 	<-- the command line
						'ls <user input> | wc' is
						built
		ccp 'Source?' 'Destination?'
					<-- the user is prompted once
						with 'Source? ', allowed
						to enter his input, is
						prompted on the next line
						with 'Destintion? ',
						allowed to enter his input,
						and the command line
						'cp <user 1> <user 2>'
						is built
X.fi
X.SH EXAMPLE

	The following is a sample menu file.
Note that it contains commands which are available
on my UNIX SYSTEM III but may not be available on yours.

X.nf

-dpx
#p
MENU 1 - Basic Operations

        ---- Directory ----     ---- File Transfer ----
        d display directory     1 compress file
        D disp dir with arg     2 uncompress file
                                u uc - transfer file

        ------ Filer ------     -------- Other --------
            c  copy file         C  C Programming Menu
            e  edit file         w  who is on?
            f  format file       z  enter any command
            r  remove file
            t  type file

#
C:2
ccp 'Source File?' 'Destination File or Dir?
d!ls | pr -4t
D!ls 'Enter File Spec?
1xsq 'Enter File Name?
2xusq 'Enter File Name?
uuc z
evi 'Enter File Name?
fnroff >out.roff 'Output is on out.roff -- Enter File Name?
rrm 'Enter File Name?
t!type 'Enter File Name?
w!who
z!'Enter Command Line?
#
MENU 2 -- C Programming

        -------- Filer --------         ---- Compiler ----
          d  display directory            c  compile prog
          e  edit file
          r  remove file                ----- Other ------
          t  type file                    z  run prog
                                          M  Main menu
#
M:1
d!ls | pr -4t
evi 'Enter File Name?
rrm 'Enter File Name?
t!type 'Enter File Name?
c!cc  'Enter File Name?
z!'Enter Command Line?
#
X.fi
X.SH FILES
X.nf
menu.c   -- source code
mcheck.c -- menu file syntax checker
X.fi
X.SH DIAGNOSTICS
	MENU issues very simple error messages when syntax errors are
encountered in the menu file.  I did this to keep MENU as simple as possible,
and it is a good idea to run any new menu file through MCHECK before running
it under MENU.  MCHECK gives complete, self-explanatory error messages on
syntax errors contained in a menu file.

X.SH BUGS

	No known problems exist at this time.  This design is vastly improved
over the original MENU 1.0, and nesting of shell procedures as well as
multiple prompted entries on the same line are now supported.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 menu.1l
	/bin/echo -n '	'; /bin/ls -ld menu.1l
fi
/bin/echo 'Extracting menu.c'
sed 's/^X//' <<'//go.sysin dd *' >menu.c
X/*
 *  MENU -- a menu preprocessor for UNIX
 *		by Richard Conn
 *
 *  MENU allows the user to create menu files, containing screen displays
 *  and command lines which are to be issued in response to single-character
 *  commands presented by the user.  Once a user issues a single-character
 *  command, MENU executes his command line (as a shell procedure) and
 *  then resumes control (in most cases).
 *
 */

#define versmaj	2	/* major version */
#define versmin 0	/* minor version */

X/*  Version History
 *	Version 1.0 - Richard Conn
 *	2.0 - Richard Conn
 *		Rather than creating a shell procedure file and then
 *			executing it via an execl, the program was
 *			redesigned to use the system() library function,
 *			which I feel is a much better, cleaner design.
 *			No intermediate command files are created now.
 *			NOTE:  This redesign caused many problems because
 *			of what I believe to be an undocumented bug with
 *			system() -- if an global variables of type int
 *			are declared, calling system() results in an
 *			error message about an invalid instruction exec
 *			and then a core dump.  The program redesign removed
 *			all global variables.
 */

#define FALSE	0
#define TRUE	~FALSE
#define HASH	'#'	/* menu separator */
#define GOTO	':'	/* goto command in menu text */
#define WAIT	'!'	/* wait command in menu text */
#define QUOTE	'\''	/* quote for user input */
#define	llimit	23	/* number of lines in screen display */
#define EOB	0x7f	/* end of buffer marker */
#define ESC	0x1b	/* user abort (if allowed) */
#define BEL	'\7'
#define LF	'\n'
#define SCRSIZ	4000	/* size of buffer for screen display */
#define CMDSIZ	8000	/* size of buffer for command lines */

#include <stdio.h>
#include <ctype.h>

#ifdef SYS3
#include <sgtty.h>
#endif

#ifdef JHU
#include </usr/includeJHU/stty.h>  /* at BRL */
#endif

X/*  options structure  */
struct opt {
	int disp;  /* display on/off */
	int page;  /* page on/off */
	int exit;  /* exit on/off */
}

main(argc,argv)
int argc;
char *argv[];
{
	char file[50];				/* menu file name */
	char inline[400];			/* menu command line */
	int cmd, ccode;				/* user command, ret code */
	int wait, menunum;			/* wait flag, menu number */
	struct opt globopts, locopts;		/* global and local options */
	char screen[SCRSIZ], text[CMDSIZ];	/* screen and text buffers */

	if (argc==1) { 	/* give user help info if no args */
		help();
		exit(-1);
	}

	/* process options if any */
	menunum = 1;   /* set to first menu */
	if (*argv[1]=='-') menunum = atoi(argv[1]+1);  /* extract options */
	if (!menunum) menunum = 1;  /* set to 1 if error in arg */

	/* extract menu file name */
	file[0] = '\0';  /* set no file name */
	if (argc==2 && *argv[1]!='-') strcat(file, argv[1]);
	else if (argc>2) strcat(file, argv[2]);
	else {
		help();
		exit(-1);
	}

	/* get menu from file */
	getmenu(file,menunum,&globopts,&locopts,screen,text);

	/* process menu */
	while (TRUE) {		/* exit only on ESC from user (if allowed) */
		if (locopts.disp) prdisp(screen,&locopts);  /* print display */
		wait = FALSE;  /* set no wait */
		printf("MENU %d.%d Command%s", versmaj, versmin,
		locopts.exit ? " (ESC to exit)? " : "? ");	/* prompt */
		cmd = getcmd();		/* get command from user */
		if (locopts.exit && cmd==ESC) exit(0);		/* exit */
		ccode = prcmd(cmd,text,inline,&wait);		/* get cmnd */
		switch (ccode) {
		case 0 :	/* command line */
			system(inline);  /* execute command */
			if (wait) {
				printf("Strike any key -- ");
				setraw();
				getchar();
				clrraw();
				printf("\n");
			}
			break;
		case 1 :	/* goto new menu */
			menunum = atoi (inline);  /* get menu number */
			if (!menunum) menunum = 1;
			getmenu(file,menunum,&globopts,&locopts,
			screen,text);  /* get menu */
			break;
		default :	/* invalid command */
			putchar(BEL);
			break;
		}
	}
}

X/*  print display if desired and page if desired  */
prdisp(screen,locops)
char *screen;
struct opt *locops;
{
	int linecnt;

	linecnt = 0;  /* init line counter */
	while (*screen != EOB) {
		putchar(*screen);  /* send char */
		if (*screen++ == LF) linecnt++;  /* increment line count */
	}
	if (locops->page) /* page display */
		while (linecnt++ < llimit) printf("\n");
}

X/*  get raw command from user  */
getcmd()
{
	int c;

	setraw();			/* set no echo and immed input */
	c = getchar() & 0x7f;		/* get command and mask out MSB */
	clrraw();			/* restore normal I/O */
	if (c > ' ') putchar(c);	/* echo if printing char */
	printf("\n");			/* new line */
	return(c);
}

X/*  get and process command from user  */
prcmd(c,text,line,wait)
int c, *wait;
char *text, *line;
{
	char *scmd(), *cline;

	cline = scmd(c,text);		/* cline pts to command from text */
	*line = '\0';			/* init command line */
	if (!(*cline)) return(2);	/* command not found */
	if (*cline==GOTO) {		/* GOTO command */
		++cline;		/* pt to first digit */
		while (isdigit(*cline)) *line++ = *cline++;	/* copy */
		*line = '\0';		/* set end of string */
		return(1);		/* goto return code */
	}
	if (*cline==WAIT) {		/* wait in command line */
		*wait=TRUE;		/* set flag */
		++cline;		/* pt to first valid cmd line char */
	}
	docmnd(cline,line);		/* extract and process command line */
	return(0);			/* command line return code */
}

X/*  scan commands in command buffer for command passed  */
char *scmd(cmd,text)
int cmd;
char *text;
{
	while (*text != EOB) {			/* scan thru buffer */
		if (*text==cmd) return(++text);	/* found command */
		while (*text++ != LF);		/* skip current line */
	}
	return("");				/* null command if not found */
}

X/*  build command line  */
docmnd(cline,line)
char *cline, *line;
{
	char userin[200];		/* buffer for build and user input */

	while (*cline != LF) {		/* advance over line */
		switch (*cline) {
		case QUOTE :
			++cline;	/* pt to after quote */
			while (*cline != LF && *cline != QUOTE)
				putchar(*cline++);	/* print prompt */
			putchar(' ');	/* print extra space */
			gets(userin);	/* get input from user */
			if (*cline == QUOTE) cline++;	/* skip ending quote */
			break;
		default :
			userin[0] = *cline++;	/* set up string */
			userin[1] = '\0';
			break;
		}
		strcat (line, userin);		/* append user input or char */
	}
}

X/* extract menu from menu file */
getmenu(file,menunum,globopts,locopts,screen,text)
int menunum;
struct opt *globopts, *locopts;
char *file, *screen, *text;
{
	FILE *fopen(), *fd;
	int c;

	/* open menu file */
	fd=fopen(file,"r");
	if (fd==NULL) {
		printf("Menu %s NOT Found\n", file);
		exit(0);
	}

	/* set global options */
	globopts->disp = FALSE;
	globopts->page = FALSE;
	globopts->exit = FALSE;
	if ((c=getc(fd)) == '-') setopts(fd,globopts);
	else ungetc(fd,c);

	/* skip to desired menu */
	skip(fd,menunum);

	/* set local options */
	locopts->disp = globopts->disp;
	locopts->page = globopts->page;
	locopts->exit = globopts->exit;
	setopts(fd,locopts);

	/* build buffers */
	build(fd,screen,SCRSIZ);  /* build screen display */
	build(fd,text,CMDSIZ);    /* build command buffer */

	/* close menu file */
	fclose(fd);
}

X/*  set options  */
setopts(fd,opts)
FILE *fd;
struct opt *opts;
{
	int c;

	while ((c=getc(fd)) != LF)
		switch (c) {
		case 'D' :
		case 'd' :
			opts->disp = ~opts->disp;
			break;
		case 'P' :
		case 'p' :
			opts->page = ~opts->page;
			break;
		case 'X' :
		case 'x' :
			opts->exit = ~opts->exit;
			break;
		case EOF :
			premature();
			break;
		default :
			break;  /* skip invalid option */
		}
}

X/*  Skip to desired menu and load buffers  */
skip(fd,menunum)
FILE *fd;
int menunum;
{
	int mctr, c;

	/*  skip required number of menus  */
	if (getc(fd) != HASH) strerror();	/* first char must be a hash */
	for (mctr=menunum-1; mctr; mctr--) skipmenu(fd);	/* skip menus */
}

X/*  Skip over menu  */
skipmenu(fd)
FILE *fd;
{
	int c;

	/*  advance over screen display  */
	while ((c=getc(fd)) != HASH)
		while (c != LF) {
			if (c == EOF) strerror();
			c=getc(fd);
		}

	/*  advance over commands  */
	while ((c=getc(fd)) != HASH)
		while (c != LF) {
			if (c == EOF) strerror();
			c=getc(fd);
		}
}

X/*  Build buffers  */
build(fd,buff,size)
FILE *fd;
char *buff;
int size;
{
	int c;

	while ((c=getc(fd)) != HASH) {		/* loop to end of section */
		while (c != LF) {		/* loop to end of line */
			if (c == EOF) premature();
			*buff++ = c & 0x7f;	/* store char */
			if (!(--size)) overflow();
			c = getc(fd);		/* get next char */
		}
		*buff++ = c;			/* store LF */
		if (!(--size)) overflow();
	}
	*buff = EOB;				/* set end of buffer marker */
}

X/*  premature EOF exit  */
premature()
{
	printf("Premature End of File Encountered\n");
	exit(-1);
}

X/*  menu structure error  */
strerror()
{
	printf("Menu Structure Error\n");
	exit(-1);
}

X/*  Buffer overflow  */
overflow()
{
	printf("Buffer Overflow\n");
	exit(-1);
}

X/*  Print Help Message  */
help()
{
	printf("Usage:  menu [-n] menufile");
	printf("\n\twhere 'n' is the menu number to start at\n");
}

X/*  set byte-oriented I/O  */
setraw()
{
#ifdef SYS3
	struct sgttyb ttys;

	if (gtty(0,&ttys) < 0) {		/* get term characteristics */
		printf("Can't set Byte-Oriented I/O\n");
		exit(-1);
	}
	ttys.sg_flags |= RAW;	/* set RAW */
	ttys.sg_flags &= ~ECHO;	/* set no echo */
	if (stty(0,&ttys) < 0) {		/* set term characteristics */
		printf("Can't set Byte-Oriented I/O\n");
		exit(-1);
	}
#endif
#ifdef JHU
	struct sttybuf ttys;

	if (gtty(0,&ttys) < 0) {		/* get term characteristics */
		printf("Can't set Byte-Oriented I/O\n");
		exit(-1);
	}
	ttys.sg_mode |= RAW;	/* set RAW */
	ttys.sg_mode &= ~ECHO;	/* set no echo */
	if (stty(0,&ttys) < 0) {		/* set term characteristics */
		printf("Can't set Byte-Oriented I/O\n");
		exit(-1);
	}
#endif
}

X/*  restore normal operation for I/O  */
clrraw()
{
#ifdef SYS3
	struct sgttyb ttys;

	if (gtty(0,&ttys) <0) {			/* get term characteristics */
		printf("Can't restore normal I/O\n");
		exit(-1);
	}
	ttys.sg_flags &= ~RAW;	/* clear RAW */
	ttys.sg_flags |= ECHO;	/* enable ECHO */
	if (stty(0,&ttys) < 0) {		/* set term characteristics */
		printf("Can't restore normal I/O\n");
		exit(-1);
	}
#endif
#ifdef JHU
	struct sttybuf ttys;

	if (gtty(0,&ttys) <0) {			/* get term characteristics */
		printf("Can't restore normal I/O\n");
		exit(-1);
	}
	ttys.sg_mode &= ~RAW;	/* clear RAW */
	ttys.sg_mode |= ECHO;	/* enable ECHO */
	if (stty(0,&ttys) < 0) {		/* set term characteristics */
		printf("Can't restore normal I/O\n");
		exit(-1);
	}
#endif
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 menu.c
	/bin/echo -n '	'; /bin/ls -ld menu.c
fi