[comp.unix.xenix] Menu software... Here it is: "lush" version 1.34, part 2/2

shields@yunccn.UUCP (Paul Shields) (01/08/90)

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--   1 bin      staff       1054 Jan  8 01:57 config.h
# -rw-r--r--   1 bin      staff       1498 Jan  7 15:51 defs.h
# -rw-r--r--   1 bin      staff       6473 Jan  5 18:16 edit.c
# -rw-r--r--   1 bin      staff       1509 Jan  8 04:11 edit.h
# -rw-r--r--   1 bin      staff       8605 Jan  8 04:11 envinit.c
# -rw-r--r--   1 bin      staff        809 Mar 11  1988 getin.c
# -rw-r--r--   1 bin      staff        537 Jan  8 04:14 login.c
# -rw-r--r--   1 bin      staff       1586 Jan  7 22:26 lush.c
# -rw-r--r--   1 bin      staff       2156 Jan  7 17:56 lush.h
# -rw-r--r--   1 bin      staff       5062 Jan  8 04:11 menu.c
# -rw-r--r--   1 bin      staff       1580 Jan  8 02:01 menu.h
# -rw-r--r--   1 bin      staff       2411 Jan  8 04:13 mfile.c
# -rw-r--r--   1 bin      staff       1056 Jan  8 00:46 mfile.h
# -rw-r--r--   1 bin      staff       2111 Jan  8 00:54 mlex.c
# -rw-r--r--   1 bin      staff       1082 Jan  8 01:52 mlex.h
# -rw-r--r--   1 bin      staff      10005 Jan  8 04:13 mparse.c
# -rw-r--r--   1 bin      staff        661 Jan  7 23:14 mparse.h
# -rw-r--r--   1 bin      staff         66 Jan  8 03:04 version.h
#
echo 'x - config.h'
if test -f config.h; then echo 'shar: not overwriting config.h'; else
sed 's/^X//' << '________This_Is_The_END________' > config.h
X/* config.h - some definitions you might want to change. */
X
X#define GLOBALFILE	"/usr/lib/lush/lushrc" /* global config file */
X#define MENUFILE  	"/usr/lib/lush/menu"  /* menu file */
X#define ROOTMENU  	"MAIN_MENU"          /* the default root menu */
X
X#ifdef MSDOS
X#define LUSHRC		"~/lushrc"        /* user config file */
X#else
X#define LUSHRC    	"~/.lushrc"
X#endif
X
X#define ILLEGAL   	"|<>;&"      /* disallowed user-input characters */
X#define TERM      	"dumb"      /* terminal type if none in environment */
X
X/* things you probably don't want to change... */
X#define LJ_MAX	20 	/* Max size of setjmp() stack.  This governs how
X			many levels down in the menu hierarchy you can go. */
X
X#define MAX_OPTIONS  20   /*(menu.h) max options per menu */
X#define MAX_RESP     10   /*(menu.h) max number of responses per option */
X#define NAME_SIZE    20   /*(menu.h) Max size of a menu name or option word */
X
X#define MAX_MENUS    50   /*(mparse.c) max number of menus in the system */
X
X#define MAX_TOKENS  200   /*(mlex.c) Max number of lexical tokens. */
________This_Is_The_END________
if test `wc -l < config.h` -ne 26; then
	echo 'shar: config.h was damaged during transit (should have been 26 lines)'
fi
fi		; : end of overwriting check
echo 'x - defs.h'
if test -f defs.h; then echo 'shar: not overwriting defs.h'; else
sed 's/^X//' << '________This_Is_The_END________' > defs.h
X/* File:    defs.h
X   Author:  PAS
X   Date:    Sept 7, 1987
X   Purpose: Contains global definitions for lush and other programs.
X */
X/* -- standard headers -------------------------------------------------- */
X
X#ifdef DEBUG
X#include <stdio.h>
X#endif
X#include <fcntl.h>
X
X#ifdef MSDOS
X#include <stdlib.h>
X#include <dos.h>
X#include <float.h>
X#endif
X
X#include <string.h>
X#include <ctype.h>
X#include <time.h>
X#include <pwd.h>
X#include <grp.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <errno.h>
X
X#ifndef PROTOTYPE	/* function declarations are not done for us. */
Xextern char *malloc();
Xextern int  getopt();
Xextern char *getenv();
Xextern int  putenv();
Xextern char *ttyname();
Xextern char *getlogin();
X#endif
X
X/* -- system dependent defs --------------------------------------------- */
X
X#define HOMEDIR	"/"	/* default home directory if none can be found. */
X
X#ifdef MSDOS
X#define access  laccess      	/* our own access() function. */
X#define GROUP 	"/etc/group" 	/* various group access permissions. */
X#define PASSWD	"/etc/passwd"	/* where to find the passwords. */
X#define TTY   	"nul"        	/* default tty name */
X#else
X#define TTY   	"/dev/null"	
X#endif
X
X/* -- immutable defs ---------------------------------------------------- */
X
X/* function return values... */
X#define OK            0
X#define ERROR	     -1
X#define FALSE         0
X#define TRUE          1
X
X#define MAX_LEN     255         /* maximum line length in a file */
X#define PATH_LEN     64         /* max length of a path. */
________This_Is_The_END________
if test `wc -l < defs.h` -ne 59; then
	echo 'shar: defs.h was damaged during transit (should have been 59 lines)'
fi
fi		; : end of overwriting check
echo 'x - edit.c'
if test -f edit.c; then echo 'shar: not overwriting edit.c'; else
sed 's/^X//' << '________This_Is_The_END________' > edit.c
X/*  File:    edit.c 
X	Author:  PAS
X	Date:    May 15, 1987
X	Purpose: this is where the real work is done.
X */
X
X#include "lush.h"
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
X#include "edit.h"
X#ifdef PROTOTYPE
Xextern	char *getpass(char *);
X#else
Xextern  char *getpass();
X#endif
X
X#ifdef PROTOTYPE
Xint	(*funcs[])(char *) =   /* array of pointers to functions taking char* and returning int. */
X#else
Xint	(*funcs[])() =
X#endif
X{	     ChgDir,                /* 00 change directory */
X	     ChkPort,               /* 01 check port access */
X	     ChkTerm,               /* 02 check terminal type */
X	     Pause,                 /* 03 pause with "Press enter: " message */
X	     ChkRdAcc,              /* 04 check read access to a file list */
X	     CallCmd,               /* 05 system() to a command with parameters */
X	     SecurChk,              /* 06 perform a security check */
X	     ChkWrAcc,              /* 07 check write access to a file list */
X	     Expert,                /* 08 toggle novice/expert mode */
X	     P1name,                /* 09 write prompt, get parameter. */
X	     P2name,                /* 10 write prompt, get second parameter. */
X	     ChkAccess,             /* 11 check read/write access to a file list */
X	     SetEnvt,		    /* 12 set environment variable */
X	     SaveStr,		    /* 13 save string in (global) recall-buffer */
X	     P1Recall,		    /* 14 put recall-buffer in parameter 1 */
X	     P2Recall		    /* 15 put recall-buffer in parameter 2 */
X};
X
Xstatic char param1[MAX_LEN];     /* parameter for CallCmd. */
Xstatic char param2[MAX_LEN];    /* parameter for CallCmd. */
Xstatic char recall[MAX_LEN];	/* global recall-buffer. */
X
Xint	ChgDir(dn)                  /* change to a directory. */
Xchar	*dn;
X{
X	char  *buf, pbuf[MAX_LEN];
X
X	sprintf(pbuf, dn, param1, param2);  /* add the parameter(s) to the command. */
X    buf = envsubst(pbuf);               /* substitute environment variables if nec. */
X
X    if(chdir(buf) != 0) {
X        perror(buf);
X        return ERROR;
X    }
X	return OK;
X}
X
Xint lookupfile(nam, str)            /* find a string in a file. */
Xchar *nam, *str;
X{
X    FILE *fp;
X    char line[MAX_LEN+1];
X    int  i = strlen(str);
X
X    line[MAX_LEN] = '\0';
X    if((fp = fopen(nam, "r")) != NULL) {
X        while(fgets(line, MAX_LEN, fp) != NULL)
X            if(strncmp(str, line, i) == 0) {
X                fclose(fp);
X                return OK;
X            }
X        fclose(fp);
X    } else
X    	perror(nam);
X
X    return ERROR;
X}
X
Xint   ChkPort(c)                    /* check for local mode */
Xchar  *c;
X{  
X    if(lookupfile(c, tty) == OK)
X        return OK;
X
X	printf("\nThis command is unavailable from TTY %s\n", tty);
X	return ERROR;
X}
X
Xint   ChkTerm(c)                  /* check for remote mode */
Xchar  *c;
X{  
X    if(lookupfile(c, term) == OK)
X        return OK;
X
X	printf("\nThis command is unavailable on terminals of type %s\n", term);
X    return ERROR;
X}
X
Xint   Pause(c)                      /* wait for user */
Xchar  *c;
X{
X	getin("Press enter: ");
X	return OK;
X}
X
Xint ChkRdAcc(list)              /* 04 */
Xchar    *list;
X{
X	printf("\nFile Access Check failed\n");
X    return ERROR;
X}
X
Xint ChkWrAcc(list)              /* 07 */
Xchar    *list;
X{
X	printf("\nFile Access Check failed\n");
X    return ERROR;
X}
X
Xint ChkAccess(list)             /* 11 */
Xchar    *list;
X{
X	printf("\nFile Access Check failed\n");
X    return ERROR;
X}
X
Xint   P1name(prompt)
Xchar  *prompt;
X{
X	int   i;
X	char  *p;
X
X	p = getin(prompt);
X
X	if(strlen(p) > 0) {
X	   /* none of that funny stuff... */
X	   i = strcspn(p, ILLEGAL);
X	}
X	else i=0;
X
X	strncpy(param1, p, i);
X	param1[i] = '\0';
X
X	return OK;                    /* null is ok. */
X}
X
Xint   P2name(prompt)
Xchar  *prompt;
X{
X	int   i;
X	char  *p;
X
X	p = getin(prompt);
X
X	if(strlen(p) > 0) {
X	   /* none of that funny stuff... */
X	   i = strcspn(p, ILLEGAL);
X	}
X	else i=0;
X
X	strncpy(param2, p, i);
X	param2[i] = '\0';
X
X	return OK;                    /* null is ok. */
X}
X
Xint   CallCmd(cmd)               /* use the system function to execute a command. */
Xchar  *cmd;                      /* name of command to call. */
X{
X	int   ret;
X	char  *buf, pbuf[MAX_LEN];
X
X	sprintf(pbuf, cmd, param1, param2);  /* add the parameter(s) to the command. */
X    buf = envsubst(pbuf);               /* substitute environment variables if nec. */
X
X#ifdef DEBUG
X    if(debuglevel & 1)
X        fprintf(stderr,"CallCmd(%s)= system(\"%s\")\n", cmd, buf);
X#endif
X	if((ret = system(buf)) == 0) 
X        return OK;
X
X#ifdef DEBUG
X	fprintf(stderr,"--returned error %d--\n", errno);
X	perror(buf);
X#endif
X	return ERROR;
X}
X
X/* Return TRUE if user is a member of the group, ow FALSE.
X */
Xstatic int member(gr)
Xchar *gr;
X{
X	struct group *grp;
X	char **n;
X	
X	if((grp = getgrnam(gr)) != NULL) {
X	for(n = grp->gr_mem; *n != NULL && strcmp(user, *n) != 0; n++)
X#ifdef DEBUG
X	     if(debuglevel & 1)
X	         fprintf(stderr, "%s ",*n)
X#endif
X	    ;
X	return (*n != NULL);
X	}
X	/* else invalid group. */
X	printf("\nSystem error verifying group %s. Please consult system administrator\n",gr);
X	return FALSE;
X}
X
Xint   SecurChk(gr)	/* check to see that the user is a member of the */
Xchar  *gr;		/* permitted groups... */
X{
X#ifdef DEBUG
X	if(debuglevel & 1)
X	   fprintf(stderr,"SecurChk(%s) ",gr);
X#endif     
X	if(getuid() == 0)
X        return OK;
X
X	if(*gr == '!') {		/* user must not be member of this group. */
X	   if(!member(++gr)) return OK;
X	} else
X	   if(member(gr)) return OK;
X	   
X	printf("\nYou are not allowed to use this command.\n");
X	return ERROR;
X}
X
Xint   Expert(w)                 /* toggle novice/expert mode */
Xchar  *w;
X{
X	novice ^= TRUE;               /* xor */
X	return OK;
X}
X
Xint   SetEnvt(w)	/* set environment variable. allocates memory for it, */
Xchar  *w;		/* and substitutes parameters, etc. */
X{
X	char  *buf, pbuf[MAX_LEN];
X
X	sprintf(pbuf, w, param1, param2);  /* add the parameter(s) to the command. */
X	buf = envsubst(pbuf);           /* substitute environment variables if nec. */
X
X	if((w = malloc(strlen(buf)+1)) == NULL)	/* allocate in static storage */
X	  return ERROR;
X	strcpy(w, buf);
X
X	if(putenv(w) != 0) {
X	  free(w);
X	  return ERROR;
X	} 
X	return OK;
X}
X
Xint   SaveStr(w)	/* save string in global recall buffer. */
Xchar  *w;
X{
X	strncpy(w, recall, MAX_LEN-1);
X	recall[MAX_LEN] = 0;
X	return OK;
X}
X
Xint   P1Recall(w)	/* save string in global recall buffer. */
Xchar  *w;
X{
X	strcpy(recall, param1);
X	return OK;
X}
Xint   P2Recall(w)	/* save string in global recall buffer. */
Xchar  *w;
X{
X	strcpy(recall, param2);
X	return OK;
X}
________This_Is_The_END________
if test `wc -l < edit.c` -ne 279; then
	echo 'shar: edit.c was damaged during transit (should have been 279 lines)'
fi
fi		; : end of overwriting check
echo 'x - edit.h'
if test -f edit.h; then echo 'shar: not overwriting edit.h'; else
sed 's/^X//' << '________This_Is_The_END________' > edit.h
X/* File:    edit.h 
X   Author:  PAS
X   Date:    May 19, 1987
X   Purpose: private definitions for edit.c.
X */
X
X/* prototype statements... */
X#ifdef PROTOTYPE
Xint   ChgDir(char *);            /* 00 change directory */
Xint   ChkPort(char *);           /* 01 check port access */
Xint   ChkTerm(char *);           /* 02 check terminal access */
Xint   Pause(char *);             /* 03 pause with "Press enter: " message */
Xint   ChkRdAcc(char *);          /* 04 check read access to a file list */
Xint   CallCmd(char *);           /* 05 system() to a command with parameter */
Xint   SecurChk(char *);          /* 06 perform a security check */
Xint   ChkWrAcc(char *);          /* 07 check write access to a file list */
Xint   Expert(char *);            /* 08 toggle expert mode */
Xint   P1name(char *);             /* 09 write prompt, get parameter 1 */
Xint   P2name(char *);            /* 10 write prompt, get parameter 2 */
Xint   ChkAccess(char *);         /* 11 check read/write access to a file list */
Xint   SetEnvt(char *);		 /* 12 set environment variable */
Xint   SaveStr(char *);		 /* 13 save string in global recall buffer */
Xint   P1Recall(char *);		 /* 14 put recall-buffer in parameter 1 */
Xint   P2Recall(char *);		 /* 15 put recall-buffer in parameter 2 */
X
XFILE  *popen(char *,char *);
X#else
Xint   ChgDir(),ChkPort(),ChkTerm(),Pause(),ChkRdAcc(),CallCmd(),SecurChk();
Xint   ChkWrAcc(),Expert(),P1name(),P2name(),ChkAccess(), SetEnvt();
Xint   SaveStr(),P1Recall(),P2Recall();
X
XFILE  *popen();
X#endif
________This_Is_The_END________
if test `wc -l < edit.h` -ne 33; then
	echo 'shar: edit.h was damaged during transit (should have been 33 lines)'
fi
fi		; : end of overwriting check
echo 'x - envinit.c'
if test -f envinit.c; then echo 'shar: not overwriting envinit.c'; else
sed 's/^X//' << '________This_Is_The_END________' > envinit.c
X/* File:    envinit.c
X   Author:  Paul Shields
X   Date:    May 13, 1987
X   Purpose: sets up variables for the environment.
X */
X
X#include "lush.h"
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
X/* We logged into the console, a local tty, or a remote tty. Certain things
X  are unavailable from a remote tty, so we'll need to compare the environment
X  variable TTY with a list of permitted devices when the need calls for it.
X */
Xchar *root_menu = NULL,	/* default main menu name. */
X     *menufile = NULL,  /* name of menu file. */
X     *globalrc = NULL,  /* name of global rc file. */
X     *userrc = NULL,    /* name of user rc file. */
X     *user, 		/* name of the user. */
X     *tty,              /* TTY environment variable. */
X     *term = NULL;      /* TERM environment variable. */
X
Xchar *CL, *SO, *SE;     /* termcap Clear-screen, Stand-out, Unstand-out */
Xint  LI, CO;		/* lines, columns */
X
X
Xchar *
Xgethome(u)		/* allocate and return user home dir or null. */
Xchar *u;
X{
X	struct passwd *pw;
X
X
X	/* if u is null, use default of current user. */
X	if(u == NULL || strlen(u) == 0)
X	  u = user;
X	if((pw = getpwnam(u)) == NULL)
X	    return NULL;
X
X	if((u = malloc(strlen(pw->pw_dir)+1)) == NULL)
X	    return NULL;
X	strcpy(u,pw->pw_dir);
X	return u;
X}
X
X/* allocate and store an environment variable. */
Xchar *mputenv(var,def)
Xchar *var,*def;
X{
X	char *ut;
X	if((ut = malloc(strlen(var)+1+strlen(def)+1)) == NULL)
X	   return NULL;
X	sprintf(ut, "%s=%s",var,def);
X	putenv(ut);
X	return ut;
X}
X
X#define trim(s)	 {char *tl; while(*s && isspace(*s)) s++; \
X	for(tl=s; *tl; tl++) ; for(tl--; tl > s; tl--) \
X	 { if(isspace(*tl)) *tl = '\0'; else break; } }
X
X/* Process a line in the global rc.
X	Allow environment definitions.
X	Do translation of $VAR and ~user strings. 
X	*** Yet to add: System() out to commands enclosed in ``.
X
X	Side-effects: writes junk into the line. 
X */
Xstatic int proc_global(line)
Xchar *line;
X{
X	char *tl, *var, *def;
X
X#ifdef DEBUG
X	if(debuglevel & 1)
X	   fprintf(stderr,"line: |%s|\n",line);
X#endif
X
X/***/ /* this won't do. need to convert to use the scanner in mparse.c */
X	if((tl = strpbrk(line,"#")) != NULL)	/* strip comments */
X	   *tl = '\0';
X
X	/* look for = and break into two: "A=B" => "A","B" */
X	if((def = strpbrk(line, "=")) != NULL) {
X	   var = strtok(line, "=");
X	   def++;
X	   trim(var);		/* zap leading/trailing white space */
X	   trim(def);
X	   tl = envsubst(def);	/* do $ and ~ substitutions */
X	   mputenv(var, tl);
X	} else {
X	   trim(line);
X	   if(strlen(line) > 0)
X	      return ERROR;
X	}
X	return OK;
X}
X
X/* Process a line in the user rc.
X     Only environment definitions allowed. 
X     Restrict to ones already defined.
X */
Xstatic int proc_user(line)
Xchar *line;
X{
X	return proc_global(line);	/***/ /* for now, do the same. */
X}
X
X/* Get and process the global rc file */
Xstatic int getrc_global(name)
Xchar *name;
X{
X	FILE *fp;
X	char line[MAX_LEN+1];
X	int  ln;
X
X	if((fp=fopen(name, "r")) == NULL) {
X	   perror(name);
X	   return ERROR;
X	}
X	for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++)
X	   if(proc_global(line) == ERROR)
X	      fprintf(stderr,"%s: syntax error: line %d\n",name,ln);
X	fclose(fp);
X	return OK;
X}
X
X/* Get and process the user rc file */
Xstatic int getrc_user(name)
Xchar *name;
X{
X	FILE *fp;
X	char line[MAX_LEN+1];
X	int  ln;
X
X	if((fp=fopen(name, "r")) == NULL) {
X	   perror(name);
X	   return ERROR;
X	}
X	for(ln=1; fgets(line, MAX_LEN, fp) != NULL; ln++)
X	   if(proc_user(line) == ERROR)
X	      fprintf(stderr,"%s: syntax error: line %d\n",name,ln);
X	fclose(fp);
X	return OK;
X}
X
Xint envinit(argc,argv)
Xint  argc;
Xchar *argv[];
X{
X	register char *h;
X	char *ut;		/* temporary */
X	int err = 0, c;
X	extern char *optarg;
X
X#ifndef MSDOS
X	if(getenv("SHELL") != argv[0]) 		/* security. */
X	    mputenv("SHELL",argv[0]);
X#endif
X
X	/* find out who we are. */
X	if((user = getlogin()) == NULL) {
X	    struct passwd *pw;
X	    if((pw = getpwuid(getuid())) == NULL) {
X		fprintf(stderr,"Can't find your username anywhere.\n");
X		return ERROR;
X	    }
X	    ut = pw->pw_name;
X	    if((user = malloc(strlen(ut)+1)) == NULL)
X		{ perror("envinit()"); return ERROR; }
X	    strcpy(user,ut);
X	}
X	mputenv("USER",user);
X#ifdef DEBUG
X    if(debuglevel & 1)
X	fprintf(stderr,"USER=<%s> ",user);
X#endif
X
X	if((ut = getenv("HOME")) == NULL) {
X	  if((ut = gethome(user)) == NULL)
X	    ut = HOMEDIR;
X	  mputenv("HOME",ut);
X	}
X#ifdef DEBUG
X    if(debuglevel & 1)
X	fprintf(stderr,"HOME=<%s> ",ut);
X#endif
X
X	/* process the command line options... */
X	while ((c = getopt(argc, argv, "f:R:M:G:U:")) != EOF)
X	  switch((char)c) {
X	    case 'f':
X	    case 'M': 
X		if((menufile=malloc(strlen(optarg)+1)) == NULL)
X		  { perror("envinit()"); return ERROR; }
X		strcpy(menufile,optarg);
X		break;
X	    case 'R':
X		if((root_menu=malloc(strlen(optarg)+1)) == NULL)
X		  { perror("envinit()"); return ERROR; }
X		strcpy(root_menu,optarg);
X		break;
X	    case 'G': 
X		if((globalrc=malloc(strlen(optarg)+1)) == NULL)
X		  { perror("envinit()"); return ERROR; }
X		strcpy(globalrc,optarg);
X		break;
X	    case 'U':
X		if((userrc=malloc(strlen(optarg)+1)) == NULL)
X		  { perror("envinit()"); return ERROR; }
X		strcpy(userrc,optarg);
X		break;
X	    case '?':
X		err = TRUE;
X	  }
X	if(err) {
X	  fprintf(stderr, "Usage:  %s [-G global-config-file] [-M menufile]\n",argv[0]);
X	  fprintf(stderr, "            [-R rootmenu] [-U user-config-file]\n");
X	  return ERROR;
X	}
X
X	if(globalrc == NULL)		/* default global rc file location */
X	  globalrc = GLOBALFILE;
X
X#ifdef DEBUG
X    if(debuglevel & 1)
X	fprintf(stderr,"global rc=<%s>\n",globalrc);
X#endif
X	/* Now process global rc file... must always exist. */
X	getrc_global(globalrc);
X
X	if(menufile == NULL)		/* default menu file location */
X	  if((menufile = getenv("MENUFILE")) == NULL)
X	    menufile = MENUFILE;
X
X	if(root_menu == NULL) 		/* default root menu name */
X	  if((root_menu = getenv("ROOTMENU")) == NULL)
X	    root_menu = ROOTMENU;
X
X	if(userrc == NULL)
X	  if((userrc = getenv("LUSHRC")) == NULL)
X	    userrc = LUSHRC;
X
X#ifdef DEBUG
X    if(debuglevel & 1)
X	printf("userrc: <%s>, menufile: <%s>, root_menu: <%s>\n",
X	    userrc, menufile, root_menu);
X#endif
X	/***/ /* note: may need to subst ~ in userrc here. */
X
X	/* now process the user rc file... */
X	getrc_user(userrc);
X
X	if((tty = getenv("TTY")) == NULL) {     /* default terminal */
X	   if((ut = ttyname(fileno(stdin))) == NULL)
X	      tty = TTY;
X	   else {
X		tty = malloc(strlen(ut)+1);
X		strcpy(tty, ut);
X	   }
X	   mputenv("TTY",tty);
X	}
X
X	if((term = getenv("TERM")) == NULL) {   /* default to "dumb" terminal */
X	   term = TERM;
X	   mputenv("TERM",term);
X	}
X
X	return OK;
X}
X
X/* Initialize the termcap variables. Some of this code is from MicroEMACS 
X   by Daniel M. Lawrence (and others.) */
Xint
Xtcapinit()                  /* important. call envinit() before this. */
X{
X    char *tgetstr();
X    int  tgetnum();
X    char tcbuf[1024];
X    static char strbuf[128];
X    char *str = strbuf;
X
X    if (term == NULL) {
X        fprintf(stderr,"Environment variable TERM not defined!\n");
X        return ERROR;
X    }
X
X    if ((tgetent(tcbuf, term)) <= 0) {
X        fprintf(stderr, "Unknown terminal type %s!\n", term);
X        return ERROR;
X    }
X
X    LI = tgetnum("li");			/* lines & columns */
X    CO = tgetnum("co");
X
X    if((CL = tgetstr("cl",&str)) == NULL)	/* clear screen */
X	CL = "\n------------------------------------------------------------------------------\n";
X
X    if((SO =  tgetstr("so",&str)) == NULL)	/* stand-out enter */
X	SO = "";
X
X    if((SE = tgetstr("se", &str)) == NULL)	/* stand-out end */
X	SE = "";
X
X    /* caution: we lose access to tcbuf now. don't call any more termcap
X       functions. CL, SO, and SE are in static memory. */
X
X    return OK;
X}
X
Xstatic char retbuf[BUFSIZ];
X#define scanword(s, var)    {char *tmp; \
X	  tmp = ++(s);  while(isalnum(*(s))) (s)++; \
X	  strncpy(var, tmp, (s)-tmp); \
X	  (var)[(s)-tmp] = '\0'; }
X
Xchar *      /* substitute environment values in "$VAR" strings for s. */
Xenvsubst(s) /* returns with static data which is overwritten by the next call. */
Xchar *s;
X{
X    char *r = retbuf, *tmp;
X    static char var[MAX_LEN];
X
X    while(*r = *s) {
X	if(*s == '\\')		/* escape with \$ or \~. */
X	  *++r = *++s;
X	if(*s == '$') {		/* substitute */
X	  scanword(s, var);
X	  if((tmp = getenv(var)) == NULL)     /* look it up.. */
X	    tmp = "";		/* Nothing there */
X	  while(*r = *tmp++)	/* copy */
X	    r++;
X          continue;
X        }
X	if(*s == '~') {		/* look for ~user */
X	  scanword(s, var);
X
X	  if((tmp = gethome(var)) == NULL)
X	    tmp = "";		/* no translation */
X
X	  while(*r = *tmp++)	/* copy */
X	    r++;
X          continue;
X	}
X        s++;
X        r++;
X    }
X
X    return retbuf;
X}
________This_Is_The_END________
if test `wc -l < envinit.c` -ne 351; then
	echo 'shar: envinit.c was damaged during transit (should have been 351 lines)'
fi
fi		; : end of overwriting check
echo 'x - getin.c'
if test -f getin.c; then echo 'shar: not overwriting getin.c'; else
sed 's/^X//' << '________This_Is_The_END________' > getin.c
X/* File:    getin.c 
X	Author:  PAS
X	Date:    May 13, 1987
X	Purpose: Miscellaneous esoteric system-dependent functions
X */
X
X#include "defs.h"
X
Xstatic char  istr[MAX_LEN+1];    /* for returned strings. */
X
X/* p = getin(prompt);
X	Get a string from stdin with prompting on stderr. 
X
X	If it's a terminal, avoids that yucky mess that happens if ^Z is pressed 
X	in gets() or scanf().
X */
Xchar *
Xgetin(prompt)
Xchar *prompt;
X{
X	int   i;
X	
X    write(2, prompt, strlen(prompt));
X
X	/* Get an input-string. Don't allow ^Z characters to force EOF on 
X	   subsequent reads when tty's are used.
X	 */
X	i = read(0, istr, MAX_LEN);
X	istr[i] = '\0';                 /* make null-terminated */
X
X	i = strcspn(istr,"\n\r");       /* span to end of line. */
X	istr[i] = '\0';                 /* strip off the junk. */
X	return istr;
X}
________This_Is_The_END________
if test `wc -l < getin.c` -ne 34; then
	echo 'shar: getin.c was damaged during transit (should have been 34 lines)'
fi
fi		; : end of overwriting check
echo 'x - login.c'
if test -f login.c; then echo 'shar: not overwriting login.c'; else
sed 's/^X//' << '________This_Is_The_END________' > login.c
X/*  File:    login.c 
X	Author:  PAS
X	Date:    May 13, 1987
X	Purpose: Miscellaneous esoteric system-dependent functions
X */
X
X#include "defs.h"
X#ifndef NULL
X#define NULL (char *)0
X#endif
X
Xvoid	login(p)					/* log in operator. */
Xchar	*p;							/* oper name */
X{
X	struct passwd *pwd = getpwuid(getuid());
X
X    if((char *)pwd != NULL)
X    	strcpy(p,pwd->pw_name);		   /* set operator name */
X
X	/***/ /* remember login time. */
X}
X
X/***/
Xvoid	logout(p)					   /* log out operator */
Xchar	*p;							   /* oper name */
X{  /* log system use */
X}
________This_Is_The_END________
if test `wc -l < login.c` -ne 27; then
	echo 'shar: login.c was damaged during transit (should have been 27 lines)'
fi
fi		; : end of overwriting check
echo 'x - lush.c'
if test -f lush.c; then echo 'shar: not overwriting lush.c'; else
sed 's/^X//' << '________This_Is_The_END________' > lush.c
X/* File:    lush.c
X   Author:  Paul A. Shields
X   Date:    Sept 6, 1987
X   Purpose: NCCN luser shell -- main program.
X */
X
X#include "lush.h"
X
X#ifndef UNAMELEN
X#define UNAMELEN	8
X#endif
X
Xchar	version[] = VERSION;
Xint	novice = TRUE;					/* novice mode */
X#ifdef DEBUG
Xint     debuglevel = 1;
X#else
X#include <stdio.h>
X#endif
X
X#ifdef PROTOTYPE
Xextern void	menu(char *);			/* display main menu */
Xextern int	menuinit(void);
X#else
Xextern void	menu();
Xextern int	menuinit();
X#endif
X
Xint     num_lj = 0;                 /* stack of (jmp_buf *) for longjmp() */
Xjmp_buf ljstack[LJ_MAX];            /* MAX of 10 levels deep. */
X
Xcatch_intr()
X{
X    (void) signal(SIGINT, catch_intr);
X    longjmp(ljstack[num_lj-1], SIGINT);
X}
X
Xmain(argc,argv)
Xint  argc;
Xchar *argv[];
X{
X    int   (*ofun)();
X
X    /* initialize setjmp stack. */
X    if(setjmp(ljstack[num_lj++]) != 0)
X        exit(1);
X    ofun = signal(SIGINT, catch_intr);  /* ^C trapping */
X#ifdef SIGQUIT
X    ofun = signal(SIGQUIT, SIG_IGN);
X#endif
X#ifdef SIGTSTP
X    ofun = signal(SIGTSTP, SIG_IGN);
X#endif
X
X	if(envinit(argc,argv) == ERROR) { /* environment initialization */
X		fprintf(stderr, "can't initialize environment\n");
X		exit(1);
X	}
X	if(tcapinit() == ERROR) { /* retrieve terminal capabilities */
X		fprintf(stderr, "can't initialize terminal capabilities\n");
X		exit(1);
X	}
X	if(menuinit() == ERROR) {		/* initialize menu data structures */
X		fprintf(stderr, "can't initialize menus\n");
X		exit(1);
X	}
X
X	login(user);		/* log in operator. */
X	menu(root_menu);		/* display & process main menu */
X	logout(user);		/* log out operator. */
X}
________This_Is_The_END________
if test `wc -l < lush.c` -ne 71; then
	echo 'shar: lush.c was damaged during transit (should have been 71 lines)'
fi
fi		; : end of overwriting check
echo 'x - lush.h'
if test -f lush.h; then echo 'shar: not overwriting lush.h'; else
sed 's/^X//' << '________This_Is_The_END________' > lush.h
X/* File:    lush.h
X   Author:  Paul Shields
X   Date:    Feb 2, 1988
X   Purpose: Contains global definitions for lush.
X */
X/* -- standard headers -------------------------------------------------- */
X
X/* global variables... */
X
X#include "version.h"
X#include "defs.h"
X#include "config.h"
X
X/* valid function handles begin at 0. here are some special ones... */
X#define QUIT	     -3		/* PAS - 89/03/01: go back to main menu. */
X#define RETURN       -2		/* return to calling menu. */
X#define NONE         -1		/* don't change menus. */
X
Xextern char *user;		 /* name of user */
Xextern int  novice;              /* Boolean: novice mode (lush.c) */
Xextern char *globalrc;           /* global run-time configuration */
Xextern char *userrc;             /* user run-time configuration */
Xextern char *menufile;           /* defines the menus */
Xextern char *root_menu;		 /* root menu title */
Xextern char *tty;       	 /* the port the user is on. */
Xextern char *term;       	 /* the user's terminal type. */
X#ifdef PROTOTYPE
Xextern int  (*funcs[])(char *);  /* array of pointers to functions taking char* and returning int. */
X#else
Xextern int (*funcs[])();
X#endif
Xextern int  intr;                /* TRUE if interrupt caught */
Xextern int  num_lj;              /* for setjmp()/longjmp() */
Xextern jmp_buf ljstack[];        /* ... */
Xextern char *CL, *SO, *SE;       /* variables for termcap */
Xextern int LI, CO;		 /* ... */
X
X#ifdef DEBUG
Xextern int  debuglevel;
X#endif
X
X/* prototype statements for nccn library: */
X#ifdef PROTOTYPE
Xint 	chkfree(int);      	/* returns boolean true if enuf space. */
Xint  	envinit(int, char **);  /* initialize global variables. */
Xchar    *envsubst(char *);      /* substitute in environment variable values */
Xchar  	*getin(char *);         /* read from stdin with prompt. */
Xvoid	login(char *);  	/* log in operator. */
Xvoid	logout(char *); 	/* log out operator */
Xint     catch_intr(void);       /* interrupt signal catcher */
Xint     tcapinit(void);         /* termcap initialization. */
X#else
Xint 	chkfree();
Xint 	envinit();
Xchar    *envsubst(),*getin();
Xvoid	login(),logout();
Xint     catch_intr();
Xint     tcapinit();
X#endif
________This_Is_The_END________
if test `wc -l < lush.h` -ne 59; then
	echo 'shar: lush.h was damaged during transit (should have been 59 lines)'
fi
fi		; : end of overwriting check
echo 'x - menu.c'
if test -f menu.c; then echo 'shar: not overwriting menu.c'; else
sed 's/^X//' << '________This_Is_The_END________' > menu.c
X/* File:    menu.c
X   Author:  PAS
X   Date:    May 13, 1987
X   Purpose: menu display and selection.
X */
X
X#include "lush.h"
X#include "menu.h"
X
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
Xstatic int                      /* match characters, case insensitive. */
Xmatch(inp, word)                /* return TRUE if inp is a prefix of word. */
Xchar    *inp, *word;
X{
X#ifdef SUN
X#define toupper(c) (isupper(c) ? (c) : (c) - 'a' + 'A')
X#endif
X
X    while(*inp && toupper(*inp) == toupper(*word)) {
X        inp++;
X        word++;
X    }
X    return (*inp == '\0');
X}
X
Xstatic int GetMenu(name)        /* search for menu and return its handle, or ERROR */
Xchar    *name;
X{
X    int    i;
X    for(i=0; i<NumMenus; i++) {
X        if(strncmp(MenuTree[i].name, name, NAME_SIZE)==0)
X            return i;
X#ifdef DEBUG
X        else if(debuglevel & 1)
X            fprintf(stderr, "node %d=<%s>\n", i, MenuTree[i].name);
X#endif
X    }
X    return ERROR;
X}
X
Xstatic int			/* output function for tputs */
Xoutc(c)
Xchar c;
X{
X	return putchar(c);
X}
X
Xstatic void Display(mh)             /* display a menu */
Xint    mh;                          /* menu handle */
X{
X    int        i;
X    MENUPTR    mp;
X
X    tputs(CL,LI,outc);               /* clear terminal screen. */
X    printf("%s Commands...\n\n", MenuTree[mh].prompt);        /* title. */
X    printf("%-20s %s\n", "Command", "Purpose");
X    printf("%-20s %s\n", "-------", "-------");
X
X    for(i=0, mp=MenuTree[mh].m; i< mp->numop; i++)
X      switch(mp->opt[i].flag) {
X	case '-':
X	    break;
X	default:
X	    printf("%-20s %s\n", mp->opt[i].word, mp->opt[i].purpose);
X	    break;
X      }
X}
X
Xstatic int Select(mh)           /* select an option and return the option number */
Xint mh;                         /* menu handle */
X{
X    char     *p,
X            line[MAX_LEN+1],
X            prompt[MAX_LEN+1];  /* input line */
X    int     i;
X    MENUPTR mp;
X
X    (void)setjmp(ljstack[num_lj++]);    /* signal-return-stack */
X
X    while(TRUE) {
X        sprintf(prompt, "\n%s> ", MenuTree[mh].prompt);
X
X        while(strlen(p = getin(prompt)) == NULL)  /* get the line. */
X            ;
X        if((p = strtok(p, "\t ")) == NULL)      /* rip off the token. */
X            continue;
X        strncpy(line, p, MAX_LEN);
X        line[MAX_LEN] = '\0';
X
X        /* call Display if "?" is pressed. if blank, retype the prompt and
X           try again. otherwise scan for the option. if option not found,
X           display a message and try again. */
X#ifdef DEBUG
X        if(debuglevel & 1)
X             fprintf(stderr,"selected <%s>\n",line);
X#endif
X        if(strcmp(line, "?") == 0) Display(mh);
X        else {
X            int j, n;
X
X            for(i=0, n=0, mp=MenuTree[mh].m; i< mp->numop; i++)
X                if(match(line, mp->opt[i].word)) {
X                    j = i;
X                    n++;
X                }
X            switch(n) {
X                case 0:             /* not found. */
X                    printf("Unrecognised command. Check spelling or press '?' for command list.\n");
X                    break;
X                case 1: 
X                    --num_lj;
X                    return j;
X                default: 
X                    printf("Ambiguous command. Use more letters.\n");
X                    break;
X            }
X        }
X    }
X}
X
Xstatic int Process(mh)         /* process menu display & selection by handle */
Xint    mh;                      /* menu handle */
X{
X    int n,                      /* option number */
X        i,                      /* for loop counter */
X        err;                    /* error tag */
X    struct option *op;          /* */
X
X    (void)setjmp(ljstack[num_lj++]);    /* signal-return-stack */
X
X    if(novice) Display(mh);
X
X    while((n = Select(mh)) != ERROR) {
X        op = &MenuTree[mh].m->opt[n];
X
X        /* Call the functions first. Don't go to the next menu if any of them
X            returns ERROR, or if the user interrupts. */
X        for(i=0, err=0; i < op->numresp && !err; i++) {
X#ifdef DEBUG
X            if(debuglevel & 1)
X                fprintf(stderr,"calling %d ",i);
X#endif	
X           err = (*(op->rsp[i].func))(op->rsp[i].param) == ERROR;
X        }
X        
X        if(err)
X            getin("Press enter: ");
X        else if(op->nextmenu == RETURN || op->nextmenu == QUIT) {
X            --num_lj;
X            return op->nextmenu;
X        }
X        else if(op->nextmenu != NONE) {
X            switch (Process(op->nextmenu)) {	/* QUIT returns to root menu. */
X		case QUIT:
X		    if(GetMenu(root_menu) != mh) {
X			--num_lj;
X			return QUIT;
X		    }
X		case NONE:
X		case RETURN:		/* drop thru */
X		default: 
X		    break;
X	    }
X        }
X        if(novice) Display(mh);
X    }
X    --num_lj;		/* should never reach here. */
X    return 0;
X}
X
Xvoid    menu(name)                    /* display menu and select. */
Xchar    *name;                        /* menu name */
X{
X    int    mh;                        /* menu handle */
X    
X    if((mh = GetMenu(name)) == ERROR)   /* search for the menu */
X        fprintf(stderr, "%s: Menu not found\n", name);
X    else
X        Process(mh);
X}
________This_Is_The_END________
if test `wc -l < menu.c` -ne 183; then
	echo 'shar: menu.c was damaged during transit (should have been 183 lines)'
fi
fi		; : end of overwriting check
echo 'x - menu.h'
if test -f menu.h; then echo 'shar: not overwriting menu.h'; else
sed 's/^X//' << '________This_Is_The_END________' > menu.h
X/* File:    menu.h 
X * Author:  PAS
X * Date:    May 13, 1987
X * Purpose: defines private data structures for menu.c
X */
X
X/* resplist -- for building lists of functions to call upon selection of 
X *             an option.
X */
Xstruct resplist {
X#ifdef PROTOTYPE
X   int   (*func)(char *);     /* function to be called */
X#else
X   int   (*func)();
X#endif
X   char  *param;              /* parameter to give it */
X};
X
X/* option -- contains the option word, its purpose, and a list of pointers
X *           to procedures to call.  The procedure returns a command:
X *				 0 to return, or 1 to select another option.
X */
Xstruct option {
X    int nextmenu,		/* handle of the next menu in the tree */
X	numresp;		/* number of responses */
X    struct resplist 
X	rsp[MAX_RESP];		/* list of routines to activate */
X    char flag,			/* display flag */
X	word[NAME_SIZE+1],
X        *purpose;
X};
X
X/* MENU -- an array of options. these will be dynamically allocated, and 
X *	      initialized by MenuInit.
X */
Xtypedef struct menu {
X	int 	numop;
X	struct option opt[MAX_OPTIONS];
X} *MENUPTR;
X
X/* 
X * How to calculate the size of a menu with n options:
X */
X#define mnusize(n)   (sizeof(int) + (sizeof(struct option))*(n))
X
X/* treenode -- holds the menu name and a pointer to it 
X */
Xstruct treenode {
X    char        name[NAME_SIZE+1],	/* menu name */
X                *prompt;		/* prompt text */
X    MENUPTR	m;                      /* point to menu */
X};
X
X/* tree -- an array (indexed by menu handle) of treenodes.
X */
Xtypedef struct treenode TREE[MAX_MENUS];
X
Xextern int NumMenus;
Xextern TREE MenuTree;
________This_Is_The_END________
if test `wc -l < menu.h` -ne 59; then
	echo 'shar: menu.h was damaged during transit (should have been 59 lines)'
fi
fi		; : end of overwriting check
echo 'x - mfile.c'
if test -f mfile.c; then echo 'shar: not overwriting mfile.c'; else
sed 's/^X//' << '________This_Is_The_END________' > mfile.c
X/*  File:    mfile.c
X    Author:  PAS
X    Date:    Jan 7, 1990
X    Purpose: A few file utilities capable of counting line numbers.
X	     This code was part of mparse.c in earlier encarnations and is
X	     needed by the lexical analysis and parsing code. 
X */
X#include "lush.h"
X
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
X#include "mfile.h"
X
X/* ---------------------- Utility Procedures --------------------- */
X
XMFILE *Mfopen(name, mode)
Xchar *name;
Xchar *mode;
X{
X	MFILE *mfp; 
X	FILE *fp;
X
X	if((fp = fopen(name, mode)) == NULL)
X	    return NULL;
X	if(((char *)mfp = malloc(sizeof(MFILE))) == NULL) {
X	    fclose(fp);
X	    return NULL;
X	}
X	mfp->fp = fp;
X	mfp->name = name;
X	mfp->curline = 1;
X
X#ifdef DEBUG
X	fprintf(stderr,"Mfopen(%s,%s)\n", name, mode);
X#endif
X	return mfp;
X}
X
Xint Mfclose(mfp)
XMFILE *mfp;
X{
X	FILE *fp = mfp->fp;
X	free(mfp);
X
X#ifdef DEBUG
X	fprintf(stderr,"Mfclose()\n");
X#endif
X	return fclose(mfp->fp);
X}
X
Xvoid MnextCh(mfp)		/* advance file pointer  to next char. */
XMFILE *mfp;
X{
X	mfp->curchar = fgetc(mfp->fp);
X	if(mfp->curchar == '\n')
X		mfp->curline++;
X#ifdef DEBUG
X	if(debuglevel & 4)
X	fprintf(stderr,"MnextCh()=%c ",Mcurchar(mfp));
X#endif
X}
X
Xvoid MwNextCh(mfp)  /* get a character. ignore white space & comments. */
XMFILE  *mfp;
X{
X	do {
X		MnextCh(mfp);
X		while(isspace(mfp->curchar))	/* skip white space. */
X			MnextCh(mfp);
X		if(mfp->curchar == '#') {	/* skip to eoln. */
X		    MnextCh(mfp);
X		    while((mfp->curchar) != '\n' && mfp->curchar != EOF)
X			MnextCh(mfp);
X		}
X	} while(isspace(mfp->curchar) && mfp->curchar != EOF);
X
X#ifdef DEBUG
X	if(debuglevel & 4)
X	fprintf(stderr,"MwNextCh()=%c ",c);
X#endif
X}
X
X/*
X Read delimited text, creating buffer space as necessary.  The delimiter
X is the current character. 
X */
Xchar *ReadText(mfp)
XMFILE  *mfp;               /* file pointer */
X{
X	char  buf[MAX_LEN];	   /* temporary buffer. */
X	char  *t = buf;
X	int   i = 1;
X	char  d = Mcurchar(mfp);   /* delimiter */
X
X#ifdef DEBUG
X	if(debuglevel & 1)
X		fprintf(stderr, "ReadText() ");
X#endif
X	MnextCh(mfp);
X	while((*t = Mcurchar(mfp)) != d && i < MAX_LEN) {
X		t++; i++;
X		MnextCh(mfp);
X	}
X	*t = '\0';
X
X#ifdef DEBUG
X	if(debuglevel & 1)
X	fprintf(stderr, "size=%d, value=<%s>\n", i, buf);
X#endif
X
X	/* allocate just enough space. */
X	if((t = malloc(i)) == NULL) {
X	    perror("ReadText()");
X	    fprintf(stderr, "%s line %d\n", mfp->name, mfp->curline);
X	    return NULL;
X	}
X	strcpy(t, buf);
X	return t;
X}
________This_Is_The_END________
if test `wc -l < mfile.c` -ne 121; then
	echo 'shar: mfile.c was damaged during transit (should have been 121 lines)'
fi
fi		; : end of overwriting check
echo 'x - mfile.h'
if test -f mfile.h; then echo 'shar: not overwriting mfile.h'; else
sed 's/^X//' << '________This_Is_The_END________' > mfile.h
X/* File:    mfile.h 
X   Author:  Paul Shields
X   Date:    Jan 7, 1990
X   Purpose: defines private data structures for mfile.c
X */
X
Xtypedef struct mfile {
X	char	curchar;	/* the current character. */
X	int	curline;	/* the current line. */
X	char	*name;		/* the file name. */
X	FILE	*fp;		/* UNIX file pointer. */
X} MFILE;
X
X/* prototype statements... */
X#ifdef PROTOTYPE
X
Xvoid MwNextCh(MFILE *);		/* get a character, remove white space. */
Xvoid MnextCh(MFILE *);		/* get a character. */
XMFILE *Mfopen(char *, char *);	/* open an MFILE. */
Xint Mfclose(MFILE *);		/* close an MFILE. */
Xchar *ReadText(MFILE *);	/* read a delimited string of text. */
X
X#else
X
Xvoid MwNextCh(), MnextCh();
XMFILE *Mfopen();
Xint Mfclose();
Xchar *ReadText();
X
X#endif
X
X/* some more defines... */
X
X/* the current line number. */
X#define Mcurline(mfp)      ((mfp) == NULL ? ERROR : (mfp)->curline)
X
X/* the current file name. */
X#define Mfilename(mfp)     ((mfp) == NULL ? NULL : (mfp)->name)
X
X/* the current character. */
X#define Mcurchar(mfp)      ((mfp) == NULL ? ERROR : (mfp)->curchar)
________This_Is_The_END________
if test `wc -l < mfile.h` -ne 41; then
	echo 'shar: mfile.h was damaged during transit (should have been 41 lines)'
fi
fi		; : end of overwriting check
echo 'x - mlex.c'
if test -f mlex.c; then echo 'shar: not overwriting mlex.c'; else
sed 's/^X//' << '________This_Is_The_END________' > mlex.c
X/* File:    mlex.c
X   Author:  Paul Shields
X   Date:    June 1, 1987
X   Purpose: lexical analysis. 
X */
X
X#include "lush.h"
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
X#include "mfile.h"
X#include "mlex.h"
X
Xint NumTokens = 0;        /* (lexical) number of tokens */
XTOKENS SymTable;          /* (lexical) symbol table */
X
X/* ----------------------- Lexical Analysis ---------------------- */
X
X/*
X GetToken: get a token, which must be a word or an integer.
X  Will allocate space as necessary, and return token "handle"
X  if successful, o/w ERROR.
X */
Xint  GetToken(fp)
XMFILE  *fp;
X{
X	char  s[MAX_LEN], *t;         /* string buffers */
X	int   ttype,                  /* token type */
X	      i;                      /* counter */
X
X	if(isalpha(Mcurchar(fp))) {                   /* a word */
X	    t = s; *t++ = Mcurchar(fp);
X	    MnextCh(fp);
X	    while(isalnum(*t = Mcurchar(fp)) || *t == '_') {
X	        t++;
X	        MnextCh(fp);
X	    }
X	    *t = '\0';
X	    if(isspace(Mcurchar(fp)))	/* gobble white space */
X	    	MwNextCh(fp);
X
X	    ttype = (strcmp(s,"RETURN")==0) ? M_RETURN :
X			((strcmp(s,"NONE")==0) ? M_NONE :
X					M_WORD);
X	}
X	else if(isdigit(Mcurchar(fp)) || Mcurchar(fp)=='-') /* a number */
X	{
X	    t = s; *t++ = Mcurchar(fp);
X	    MnextCh(fp);
X	    while(isdigit(*t = Mcurchar(fp))) {
X	        t++;
X	        MnextCh(fp);
X	    }
X	    *t = '\0';
X	    if(isspace(Mcurchar(fp)))	/* gobble white space */
X	        MwNextCh(fp);
X	    ttype = M_INTEGER;
X	}
X	else return ERROR;
X
X	/* look up token in symbol table. */
X
X	for(i=0; i<NumTokens; i++)
X		if(strcmp(SymTable[i].val, s) == 0) return i;
X
X	/* not found. allocate new space. */
X	if(NumTokens < MAX_TOKENS) {
X		if((SymTable[NumTokens].val = malloc(strlen(s)+1)) == NULL) {
X			perror("GetToken()");
X			fprintf(stderr, "%s line %d\n", Mfilename(fp), Mcurline(fp));
X			return ERROR;
X		}
X		strcpy(SymTable[NumTokens].val, s);
X		SymTable[NumTokens].typ = ttype;
X		SymTable[NumTokens].mh = -1;           /* set later, if necessary */
X		return NumTokens++;
X	}
X	fprintf(stderr,"Out of space for Tokens. Recompile with larger MAX_TOKENS (mlex.h)\n");
X	return ERROR;
X}
________This_Is_The_END________
if test `wc -l < mlex.c` -ne 81; then
	echo 'shar: mlex.c was damaged during transit (should have been 81 lines)'
fi
fi		; : end of overwriting check
echo 'x - mlex.h'
if test -f mlex.h; then echo 'shar: not overwriting mlex.h'; else
sed 's/^X//' << '________This_Is_The_END________' > mlex.h
X/* File:    mlex.h 
X   Author:  Paul Shields
X   Date:    June 1, 1987
X   Purpose: defines private data structures for mlex.c
X */
X
X/* lexical elements... */
X#define M_DOT      1
X#define M_COMMA    2
X#define M_SEMI     3
X#define M_COLON    4
X#define M_ARROW    5
X#define M_QUOTE    6
X#define M_NONE     7
X#define M_RETURN   8
X#define M_TEXT     9
X#define M_WORD    10
X#define M_INTEGER 11
X
Xstruct tokens {
X	char	*val;			/* value */
X	int	typ,			/* symbol type M_whatever. */
X		mh;			/* menu handle, if menu type. */
X};
X
Xtypedef struct tokens TOKENS[MAX_TOKENS];
X
Xextern int NumTokens;        /* (lexical) number of tokens */
Xextern TOKENS SymTable;          /* (lexical) symbol table */
X
X#ifdef PROTOTYPE
Xint  GetToken(MFILE *);     /* get next token from input stream. */
X#else
Xint  GetToken();
X#endif
X
X#define GetValue(h)  ((h) < NumTokens ? SymTable[h].val : NULL)
X#define GetType(h)   ((h) < NumTokens ? SymTable[h].typ : ERROR)
X#define GetMnuH(h)   ((h) < NumTokens ? SymTable[h].mh : ERROR)
X#define SetMnuH(h,i) {if((h) < NumTokens) \
X		SymTable[h].mh = (i); else return ERROR;}
________This_Is_The_END________
if test `wc -l < mlex.h` -ne 41; then
	echo 'shar: mlex.h was damaged during transit (should have been 41 lines)'
fi
fi		; : end of overwriting check
echo 'x - mparse.c'
if test -f mparse.c; then echo 'shar: not overwriting mparse.c'; else
sed 's/^X//' << '________This_Is_The_END________' > mparse.c
X/*  File:    mparse.c
X    Author:  Paul Shields
X    Date:    May 13, 1987
X    Purpose: parses the menu file to build menu structure during initialization.
X */
X
X#include "lush.h"
X
X#ifndef DEBUG
X#include <stdio.h>
X#endif
X
X#include "menu.h"
X#include "mfile.h"
X#include "mlex.h"
X#include "mparse.h"
X
Xint   NumMenus = 0;              /* number of menus */
XTREE  MenuTree;
X
X/* temporary menu. the syntax is simple enough to allow us to make the
X   following a single global variable. it is a stack in its general form.
X */
Xstatic struct menu tmenu;
X
X/* note the fields:
X	tmenu.numop 
X	tmenu.opt[0..MAX_OPTIONS] {
X				[x].word        command word string.
X				[x].purpose     explanitory text.
X				[x].nextmenu    handle of next menu. how do we get this?
X								assign handles as we add mnu-name to symbol table.
X				[x].rsp         list of functions to call
X	}
X */
X
X/* ---------------------- Utility Procedures --------------------- */
X
X/* look up the name in the menu list. if new, return a new handle.
X */
Xstatic int  Lookup(name, mhp)
Xchar  *name;
Xint   *mhp;                      /* returned menu handle */
X{
X	int   i;
X
X	if((strcmp("NONE", name) == 0 && (*mhp = NONE)) ||
X	   (strcmp("RETURN", name) == 0 && (*mhp = RETURN)) ||
X	   (strcmp("QUIT", name) == 0 && (*mhp = QUIT)) )
X			return OK;
X
X	for(i=0; i<NumMenus; i++)
X		if(strncmp(MenuTree[i].name, name, NAME_SIZE)==0) {
X			*mhp = i;
X			return OK;
X		}
X
X	/* not found.. */
X
X	if(NumMenus < MAX_MENUS) {
X		strncpy(MenuTree[NumMenus].name, name, NAME_SIZE);    /* copy the name.. */
X		MenuTree[NumMenus].name[NAME_SIZE] = '\0';   /* make sure it's null-terminated */
X
X		MenuTree[NumMenus].prompt = NULL;      /* supplimentary initialization */
X		MenuTree[NumMenus].m = NULL;
X
X		*mhp = NumMenus++;
X		return OK;
X	}
X	fprintf(stderr,"Out of space for menus. Recompile with larger MAX_MENUS\n");
X	return ERROR;
X}
X
Xstatic int  NewMenu(mh,n)     /* allocate space for a new menu. */
Xint   mh,                     /* menu handle */
X      n;                      /* number of options */
X{
X	MENUPTR p;
X
X	/* kill it if it's already there. */
X	if(MenuTree[mh].m != NULL) free((char *)MenuTree[mh].m);
X
X	/* allocate just enuf space.. */
X	if (((char *)p = malloc(mnusize(n))) == NULL)
X		return ERROR;
X
X	/* some initialization... */
X	p->numop = n;
X	MenuTree[mh].m = p;
X
X	return OK;
X}
X
Xstatic int  MenuParse(fp)     /* parse the file and build the structure. */
XMFILE  *fp;
X{
X	char  c;
X	int   rc;            /* return code */
X
X#ifdef DEBUG
X	if(debuglevel & 1)
X		fprintf(stderr,"sizeof(struct menu) = %d\n", mnusize(MAX_OPTIONS));
X#endif
X
X	MwNextCh(fp);		/* get the first character. */
X	rc = MnuTree(fp);    /* menu-tree -> menu-list ".". */
X	return rc;
X}
X
Xint   menuinit()       /* initialize data structures */
X{
X	MFILE  *fp;
X
X	if((fp = Mfopen(menufile, "r")) == NULL) {
X		perror(menufile);
X		return ERROR;
X	}
X
X	NumMenus = 0;                 /* initialize the menu structure */
X
X	if(MenuParse(fp) == ERROR) {
X		fprintf(stderr, "%s: Syntax error, line %d\n", Mfilename(fp), Mcurline(fp));
X		Mfclose(fp);
X		return ERROR;
X	}
X	Mfclose(fp);
X	return OK;
X}
X
X/* ----------------- Syntax and Semantic Analysis ----------------- */
X
X/*
X	mnu-tree -> mnu-list ".".
X */
Xstatic int MnuTree(fp)
XMFILE  *fp;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"MnuTree('%c')\n",Mcurchar(fp));
X#endif
X
X	if(MnuList(fp) == ERROR) return ERROR;
X	if(Mcurchar(fp) == '.') {
X		MwNextCh(fp);
X		return OK;
X	}
X	return ERROR;
X}
X
X
X/*
Xmnu-list -> mnu {NewMenu(mh, opt-count, mnu-name), menuinit(mh, tmenu)}
X	mnu-seq.
X */
Xstatic int MnuList(fp)
XMFILE  *fp;
X{
X	int   mh;                     /* menu handle */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"MnuList('%c')\n",Mcurchar(fp));
X#endif
X	if((mh=Mnu(fp)) == ERROR) return ERROR;
X
X	NewMenu(mh, tmenu.numop);
X	memcpy( (char *)(MenuTree[mh].m), (char *)(&tmenu),
X		mnusize(tmenu.numop));
X
X	return MnuSeq(fp);
X}
X
X/* mnu-seq -> ";" mnu-list.
X	mnu-seq -> .
X */
Xstatic int MnuSeq(fp)
XMFILE  *fp;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"MnuSeq('%c')\n",Mcurchar(fp));
X#endif
X	if(Mcurchar(fp) == ';') {
X		MwNextCh(fp);
X		return MnuList(fp);
X	}
X	return OK;
X}
X
X/* mnu -> mnu-name {mh = Lookup(mnu-name)} ":"
X		prompt-text {clear temporary menu}
X		opt-list.
X */
Xstatic int Mnu(fp)
XMFILE  *fp;
X{
X	int   sh,                     /* symbol handle. */
X			mh;                     /* menu handle */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"Mnu('%c')\n",Mcurchar(fp));
X#endif
X	if((sh=MnuName(fp)) == ERROR ||
X		(Lookup(GetValue(sh),&mh)) == ERROR ||
X		Mcurchar(fp) != ':') return ERROR;
X
X	MwNextCh(fp);   /* read prompt-text. recall, delimiters are ", ', or / */
X	if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR;
X
X	MenuTree[mh].prompt = ReadText(fp);    /* allocate and read text (single line) into a buffer */
X	MwNextCh(fp);
X
X	tmenu.numop = 0;                          /* clear temporary menu */
X	if(OptList(fp)==ERROR) return ERROR;     /* build option list */
X	else SetMnuH(sh, mh);        /* store handle for later reference */
X
X	return mh;
X}
X
X/* opt-list -> opt {tmenu.numop++} opt-seq.
X */
Xstatic int OptList(fp)
XMFILE  *fp;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"OptList('%c')\n",Mcurchar(fp));
X#endif
X	if(Opt(fp) == ERROR) return ERROR;
X	tmenu.numop++;
X	return OptSeq(fp);
X}
X
X/* opt-seq -> "," opt-list.
X	opt-seq -> .
X */
Xstatic int OptSeq(fp)
XMFILE  *fp;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"OptSeq('%c')\n",Mcurchar(fp));
X#endif
X	if(Mcurchar(fp) == ',') {
X		MwNextCh(fp);
X		return OptList(fp);
X	}
X	return OK;
X}
X
X/* opt -> {op = &tmenu.opt[opt-count]}
X			cmd {strcpy(op->word, cmd)}
X			mnu-name {op->nextmenu = Lookup(mnu-name)}
X
X			"(" resp-list {op->rsp = response} ")"
X
X			explanitory-text {op->purpose = explanitory-text)}.
X */
Xstatic int Opt(fp)
XMFILE  *fp;
X{
X	struct option *op;
X	int   fl, t1, t2;                 /* token handles */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"Opt('%c')\n",Mcurchar(fp));
X#endif
X	op = &tmenu.opt[tmenu.numop];
X	if((fl=Flag(fp)) == ERROR ||
X	    (t1=Cmd(fp)) == ERROR ||
X	    (t2=MnuName(fp)) == ERROR ||
X	    Mcurchar(fp) != '(')
X	  return ERROR;
X
X	op->flag = (char)fl;
X	op->numresp = 0;              /* initialize */
X	
X	MwNextCh(fp);               /* looking for [resp-list] ")" */
X	if(Mcurchar(fp) != ')')
X		if(RspList(fp,op) == ERROR)
X			return ERROR;
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"numresp = %d\n", op->numresp);
X#endif
X	if(Mcurchar(fp) != ')')
X			return ERROR;
X	MwNextCh(fp);
X
X	strcpy(op->word, GetValue(t1));
X	if(Lookup(GetValue(t2), &(op->nextmenu)) == ERROR) return ERROR;
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"Explanitory text...\n");
X#endif
X
X	/* explanitory text */
X	if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR;
X	op->purpose = ReadText(fp);            /* allocate and read text */
X
X	MwNextCh(fp);
X	return OK;
X}
X
Xstatic int Flag(fp)		/* finds the display-flag. */
XMFILE  *fp;
X{
X	switch(Mcurchar(fp)) {
X	    case '-': 	
X		MwNextCh(fp);
X		return (int)'-';
X	    default: 
X		break;
X	}
X	return (int)' ';
X}
X
Xstatic int Cmd(fp)       /* command -> word. Return token handle or ERROR */
XMFILE  *fp;
X{
X	int   th;               /* token handle */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"Cmd('%c')\n",Mcurchar(fp));
X#endif
X	if((th = GetToken(fp)) == ERROR)
X		return ERROR;
X
X	return (GetType(th) == M_WORD) ? th : ERROR;
X}
X
Xstatic int MnuName(fp)         /* menu-name -> word. */
XMFILE  *fp;                     /* menu-name -> "NONE". */
X                               /* menu-name -> "RETURN". */
X{
X	int   th,              /* token handle */
X	      tt;              /* token type */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"MnuName('%c')\n",Mcurchar(fp));
X#endif
X	if((th=GetToken(fp)) == ERROR) return ERROR;
X	tt = GetType(th);
X
X	return (tt==M_WORD || tt==M_NONE || tt==M_RETURN) ? th : ERROR;
X}
X
X
X/* resp-list -> resp {numresp++} resp-seq .
X */
Xstatic int RspList(fp,op)
XMFILE  *fp;
Xstruct option *op;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"RspList('%c')\n",Mcurchar(fp));
X#endif
X	if(Rsp(fp,&(op->rsp[op->numresp])) == ERROR) return ERROR;
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"numresp == %d, ",op->numresp);
X#endif
X	if(op->numresp < MAX_RESP) {         /* die if too many responses. */
X		(op->numresp)++;
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"numresp++ ");
X#endif
X	} else {
X		fprintf(stderr,"Too many menu options. Edit rc to decrease.\n");
X		return ERROR;
X	}
X
X	return RspSeq(fp,op);
X}
X
X/* resp-seq  -> ";" resp-list .
X	resp-seq  -> .
X */
Xstatic int RspSeq(fp,op)
XMFILE  *fp;
Xstruct option *op;
X{
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"RspSeq('%c')\n",Mcurchar(fp));
X#endif
X	if(Mcurchar(fp) != ';') return OK;
X
X	MwNextCh(fp);
X	return RspList(fp,op);
X}
X
X/* rsp ->
X			proc-id {op->rsp[op->numresp].func = funcs[proc-id]}
X			param-text {op->rsp[op->numresp].param = ReadText(fp,d) }
X */
Xstatic int Rsp(fp,rp)
XMFILE  *fp;
Xstruct resplist *rp;             /* pointer to current response */
X{
X	int th,                     /* token handle */
X		fh;                     /* function handle */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"Rsp('%c') ",Mcurchar(fp));
X#endif
X	if((th = ProcId(fp)) == ERROR)
X		return ERROR;
X	
X	sscanf(GetValue(th),"%d",&fh);
X	rp->func = funcs[fh];
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"fh = %d, ",fh);
X#endif
X
X	/* parameter text */
X	if(Mcurchar(fp) != '"' && Mcurchar(fp) != '\'' && Mcurchar(fp) != '/') return ERROR;
X	rp->param = ReadText(fp);    /* allocate and read text */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"param = %s, ",rp->param);
X#endif
X
X	MwNextCh(fp);
X	return OK;
X}
X
Xstatic int ProcId(fp)    /* routine-ident -> integer. Return token handle or ERROR */
XMFILE  *fp;
X{
X	int   th;               /* token handle */
X
X#ifdef DEBUG
X	if(debuglevel & 2)
X		fprintf(stderr,"ProcId('%c')\n",Mcurchar(fp));
X#endif
X	if((th=GetToken(fp)) == ERROR) return ERROR;
X
X	return (GetType(th) == M_INTEGER) ? th : ERROR;
X}
________This_Is_The_END________
if test `wc -l < mparse.c` -ne 451; then
	echo 'shar: mparse.c was damaged during transit (should have been 451 lines)'
fi
fi		; : end of overwriting check
echo 'x - mparse.h'
if test -f mparse.h; then echo 'shar: not overwriting mparse.h'; else
sed 's/^X//' << '________This_Is_The_END________' > mparse.h
X/* File:    mparse.h 
X   Author:  PAS
X   Date:    June 1, 1987
X   Purpose: defines private data structures for mparse.c
X */
X
X/* prototype statements for parser... */
X#ifdef PROTOTYPE
X
Xint MnuTree(MFILE *);
Xint MnuList(MFILE *);
Xint MnuSeq(MFILE *);
Xint Mnu(MFILE *);
Xint OptList(MFILE *);
Xint OptSeq(MFILE *);
Xint Opt(MFILE *);
Xint RspList(MFILE *, struct option *);
Xint RspSeq(MFILE *, struct option *);
Xint Rsp(MFILE *, struct resplist *);
Xint Cmd(MFILE *);
Xint Flag(MFILE *);
Xint MnuName(MFILE *);
Xint ProcId(MFILE *);
X#else
X
Xint	MnuTree(),MnuList(),MnuSeq(),Mnu(),OptList(),OptSeq(),Opt(),
X	RspList(),RspSeq(),Rsp(),Cmd(),Flag(),MnuName(),ProcId();
X
X#endif
________This_Is_The_END________
if test `wc -l < mparse.h` -ne 29; then
	echo 'shar: mparse.h was damaged during transit (should have been 29 lines)'
fi
fi		; : end of overwriting check
echo 'x - version.h'
if test -f version.h; then echo 'shar: not overwriting version.h'; else
sed 's/^X//' << '________This_Is_The_END________' > version.h
X#define VERSION "LUSH version 1.34, Mon Jan  8 03:04:15 EST 1990"
________This_Is_The_END________
if test `wc -l < version.h` -ne 1; then
	echo 'shar: version.h was damaged during transit (should have been 1 lines)'
fi
fi		; : end of overwriting check
exit 0


-- 
Paul Shields, shields@nccn.yorku.ca  (..!uunet!yunccn!shields)