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)