Menu software... Here it is: "lush" version 1.34, part 2/2
Paul Shields
shields at yunccn.UUCP
Mon Jan 8 20:51:16 AEST 1990
#--------------------------------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 at nccn.yorku.ca (..!uunet!yunccn!shields)
More information about the Alt.sources
mailing list