590 lines
12 KiB
C
590 lines
12 KiB
C
/* Header: /usr/src/games/warp/RCS/intrp.c,v 1.2 87/07/03 00:56:37 games Exp
|
|
*
|
|
* Revision 7.0.1.2 86/12/12 16:59:04 lwall
|
|
* Baseline for net release.
|
|
*
|
|
* Revision 7.0.1.1 86/10/16 10:51:43 lwall
|
|
* Added Damage. Fixed random bugs.
|
|
*
|
|
* Revision 7.0 86/10/08 15:12:19 lwall
|
|
* Split into separate files. Added amoebas and pirates.
|
|
*
|
|
*/
|
|
|
|
#include "EXTERN.h"
|
|
#include "warp.h"
|
|
#include "sig.h"
|
|
#include "util.h"
|
|
#include "term.h"
|
|
#include "INTERN.h"
|
|
#include "intrp.h"
|
|
|
|
/* name of this host */
|
|
char *hostname;
|
|
|
|
#ifdef TILDENAME
|
|
static char *tildename = NULL;
|
|
static char *tildedir = NULL;
|
|
#endif
|
|
|
|
static char *getrealname(uid_t);
|
|
#ifdef CONDSUB
|
|
static char *skipinterp(const char *, const char *);
|
|
#endif
|
|
|
|
__dead static void abort_interp(void);
|
|
|
|
void
|
|
intrp_init(char *tcbuf)
|
|
{
|
|
/* get environmental stuff */
|
|
|
|
/* get home directory */
|
|
|
|
homedir = getenv("HOME");
|
|
if (homedir == NULL)
|
|
homedir = getenv("LOGDIR");
|
|
|
|
dotdir = getval("DOTDIR",homedir);
|
|
|
|
/* get login name */
|
|
|
|
logname = getenv("USER");
|
|
if (logname == NULL)
|
|
logname = getenv("LOGNAME");
|
|
#ifdef GETLOGIN
|
|
if (logname == NULL)
|
|
logname = savestr(getlogin());
|
|
#endif
|
|
|
|
/* get the real name of the person (%N) */
|
|
/* Must be done after logname is read in because BERKNAMES uses that */
|
|
|
|
strcpy(tcbuf,getrealname(getuid()));
|
|
realname = savestr(tcbuf);
|
|
|
|
/* name of this host (%H) */
|
|
|
|
gethostname(buf,sizeof buf);
|
|
hostname = savestr(buf);
|
|
if (strchr(hostname,'.'))
|
|
hostname = savestr(hostname);
|
|
else {
|
|
char hname[128];
|
|
|
|
strcpy(hname,hostname);
|
|
strcat(hname,MYDOMAIN);
|
|
hostname=savestr(hname);
|
|
}
|
|
warplib = savestr(filexp(WARPLIB));
|
|
|
|
if (scorespec) /* that getwd below takes ~1/3 sec. */
|
|
return; /* and we do not need it for -s */
|
|
(void) getcwd(tcbuf, sizeof(tcbuf));/* find working directory name */
|
|
origdir = savestr(tcbuf); /* and remember it */
|
|
}
|
|
|
|
/* expand filename via %, ~, and $ interpretation */
|
|
/* returns pointer to static area */
|
|
/* Note that there is a 1-deep cache of ~name interpretation */
|
|
|
|
char *
|
|
filexp(const char *s)
|
|
{
|
|
static char filename[CBUFLEN];
|
|
char scrbuf[CBUFLEN];
|
|
char *d;
|
|
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("< %s\r\n",s);
|
|
#endif
|
|
interp(filename, (sizeof filename), s); /* interpret any % escapes */
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("%% %s\r\n",filename);
|
|
#endif
|
|
s = filename;
|
|
if (*s == '~') { /* does destination start with ~? */
|
|
if (!*(++s) || *s == '/') {
|
|
snprintf(scrbuf, sizeof(scrbuf), "%s%s",homedir,s);
|
|
/* swap $HOME for it */
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("~ %s\r\n",scrbuf);
|
|
#endif
|
|
strcpy(filename,scrbuf);
|
|
}
|
|
else {
|
|
#ifdef TILDENAME
|
|
for (d=scrbuf; isalnum((unsigned char)*s); s++,d++)
|
|
*d = *s;
|
|
*d = '\0';
|
|
if (tildedir && strEQ(tildename,scrbuf)) {
|
|
strcpy(scrbuf,tildedir);
|
|
strcat(scrbuf, s);
|
|
strcpy(filename, scrbuf);
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("r %s %s\r\n",tildename,tildedir);
|
|
#endif
|
|
}
|
|
else {
|
|
if (tildename) {
|
|
free(tildename);
|
|
free(tildedir);
|
|
}
|
|
tildedir = NULL;
|
|
tildename = savestr(scrbuf);
|
|
{
|
|
struct passwd *pwd = getpwnam(tildename);
|
|
|
|
snprintf(scrbuf, sizeof(scrbuf), "%s%s",pwd->pw_dir,s);
|
|
tildedir = savestr(pwd->pw_dir);
|
|
strcpy(filename,scrbuf);
|
|
endpwent();
|
|
}
|
|
}
|
|
#else /* !TILDENAME */
|
|
#ifdef VERBOSE
|
|
IF(verbose)
|
|
fputs("~loginname not implemented.\r\n",stdout);
|
|
ELSE
|
|
#endif
|
|
#ifdef TERSE
|
|
fputs("~login not impl.\r\n",stdout);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
else if (*s == '$') { /* starts with some env variable? */
|
|
d = scrbuf;
|
|
*d++ = '%';
|
|
if (s[1] == '{')
|
|
strcpy(d,s+2);
|
|
else {
|
|
*d++ = '{';
|
|
for (s++; isalnum((unsigned char)*s); s++) *d++ = *s;
|
|
/* skip over token */
|
|
*d++ = '}';
|
|
strcpy(d,s);
|
|
}
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("$ %s\r\n",scrbuf);
|
|
#endif
|
|
interp(filename, (sizeof filename), scrbuf);
|
|
/* this might do some extra '%'s but */
|
|
/* that is how the Mercedes Benz */
|
|
}
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
printf("> %s\r\n",filename);
|
|
#endif
|
|
return filename;
|
|
}
|
|
|
|
#ifdef CONDSUB
|
|
/* skip interpolations */
|
|
|
|
static char *
|
|
skipinterp(const char *pattern, const char *stoppers)
|
|
{
|
|
|
|
while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) {
|
|
#ifdef DEBUGGING
|
|
if (debug & 8)
|
|
printf("skipinterp till %s at %s\r\n",stoppers?stoppers:"",pattern);
|
|
#endif
|
|
if (*pattern == '%' && pattern[1]) {
|
|
switch (*++pattern) {
|
|
case '{':
|
|
for (pattern++; *pattern && *pattern != '}'; pattern++)
|
|
if (*pattern == '\\')
|
|
pattern++;
|
|
break;
|
|
#ifdef CONDSUB
|
|
case '(': {
|
|
pattern = skipinterp(pattern+1,"!=");
|
|
if (!*pattern)
|
|
goto getout;
|
|
for (pattern++; *pattern && *pattern != '?'; pattern++)
|
|
if (*pattern == '\\')
|
|
pattern++;
|
|
if (!*pattern)
|
|
goto getout;
|
|
pattern = skipinterp(pattern+1,":)");
|
|
if (*pattern == ':')
|
|
pattern = skipinterp(pattern+1,")");
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef BACKTICK
|
|
case '`': {
|
|
pattern = skipinterp(pattern+1,"`");
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef PROMPTTTY
|
|
case '"':
|
|
pattern = skipinterp(pattern+1,"\"");
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
pattern++;
|
|
}
|
|
else {
|
|
if (*pattern == '^' && pattern[1])
|
|
pattern += 2;
|
|
else if (*pattern == '\\' && pattern[1])
|
|
pattern += 2;
|
|
else
|
|
pattern++;
|
|
}
|
|
}
|
|
getout:
|
|
return __UNCONST(pattern); /* where we left off */
|
|
}
|
|
#endif
|
|
|
|
static char *mygets(char *str, size_t n)
|
|
{
|
|
char *ret;
|
|
size_t last;
|
|
|
|
if ((ret = fgets(str, n, stdin)) != NULL) {
|
|
last = strlen(str) - 1;
|
|
|
|
if (str[last] == '\n')
|
|
str[last] = '\0';
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* interpret interpolations */
|
|
|
|
char *
|
|
dointerp(char *dest, size_t destsize, const char *pattern, const char *stoppers)
|
|
{
|
|
char *s;
|
|
int i;
|
|
char scrbuf[512];
|
|
bool upper = false;
|
|
bool lastcomp = false;
|
|
int metabit = 0;
|
|
|
|
while (*pattern && (!stoppers || !strchr(stoppers,*pattern))) {
|
|
#ifdef DEBUGGING
|
|
if (debug & 8)
|
|
printf("dointerp till %s at %s\r\n",stoppers?stoppers:"",pattern);
|
|
#endif
|
|
if (*pattern == '%' && pattern[1]) {
|
|
upper = false;
|
|
lastcomp = false;
|
|
for (s=NULL; !s; ) {
|
|
switch (*++pattern) {
|
|
case '^':
|
|
upper = true;
|
|
break;
|
|
case '_':
|
|
lastcomp = true;
|
|
break;
|
|
case '{':
|
|
pattern = cpytill(scrbuf,pattern+1,'}');
|
|
if ((s = strchr(scrbuf,'-')) != NULL)
|
|
*s++ = '\0';
|
|
else
|
|
s = nullstr;
|
|
s = getval(scrbuf,s);
|
|
break;
|
|
#ifdef CONDSUB
|
|
case '(': {
|
|
char rch;
|
|
bool matched;
|
|
|
|
pattern = dointerp(dest,destsize,pattern+1,"!=");
|
|
rch = *pattern;
|
|
if (rch == '!')
|
|
pattern++;
|
|
if (*pattern != '=')
|
|
goto getout;
|
|
pattern = cpytill(scrbuf,pattern+1,'?');
|
|
if (!*pattern)
|
|
goto getout;
|
|
if (*scrbuf == '^' && scrbuf[strlen(scrbuf)-1] == '$') {
|
|
scrbuf[strlen(scrbuf)-1] = '\0';
|
|
matched = strEQ(scrbuf+1,dest);
|
|
}
|
|
else
|
|
matched = instr(dest,scrbuf) != NULL;
|
|
if (matched==(rch == '=')) {
|
|
pattern = dointerp(dest,destsize,pattern+1,":)");
|
|
if (*pattern == ':')
|
|
pattern = skipinterp(pattern+1,")");
|
|
}
|
|
else {
|
|
pattern = skipinterp(pattern+1,":)");
|
|
if (*pattern == ':')
|
|
pattern++;
|
|
pattern = dointerp(dest,destsize,pattern,")");
|
|
}
|
|
s = dest;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef BACKTICK
|
|
case '`': {
|
|
FILE *pipefp;
|
|
|
|
pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"`");
|
|
pipefp = popen(scrbuf,"r");
|
|
if (pipefp != NULL) {
|
|
int len;
|
|
|
|
len = fread(scrbuf,sizeof(char),(sizeof scrbuf)-1,
|
|
pipefp);
|
|
scrbuf[len] = '\0';
|
|
pclose(pipefp);
|
|
}
|
|
else {
|
|
printf("\r\nCan't run %s\r\n",scrbuf);
|
|
*scrbuf = '\0';
|
|
}
|
|
for (s=scrbuf; *s; s++) {
|
|
if (*s == '\n') {
|
|
if (s[1])
|
|
*s = ' ';
|
|
else
|
|
*s = '\0';
|
|
}
|
|
}
|
|
s = scrbuf;
|
|
break;
|
|
}
|
|
#endif
|
|
#ifdef PROMPTTTY
|
|
case '"':
|
|
pattern = dointerp(scrbuf,(sizeof scrbuf),pattern+1,"\"");
|
|
fputs(scrbuf,stdout);
|
|
resetty();
|
|
mygets(scrbuf, sizeof(scrbuf));
|
|
crmode();
|
|
raw();
|
|
noecho();
|
|
nonl();
|
|
s = scrbuf;
|
|
break;
|
|
#endif
|
|
case '~':
|
|
s = homedir;
|
|
break;
|
|
case '.':
|
|
s = dotdir;
|
|
break;
|
|
case '$':
|
|
s = scrbuf;
|
|
snprintf(scrbuf, sizeof(scrbuf), "%d",getpid());
|
|
break;
|
|
case 'H': /* host name */
|
|
s = hostname;
|
|
break;
|
|
case 'L': /* login id */
|
|
s = logname;
|
|
break;
|
|
case 'N': /* full name */
|
|
s = getval("NAME",realname);
|
|
break;
|
|
case 'O':
|
|
s = origdir;
|
|
break;
|
|
case 'p':
|
|
s = cwd;
|
|
break;
|
|
case 'X': /* warp library */
|
|
s = warplib;
|
|
break;
|
|
default:
|
|
if (--destsize <= 0)
|
|
abort_interp();
|
|
*dest++ = *pattern | metabit;
|
|
s = nullstr;
|
|
break;
|
|
}
|
|
}
|
|
if (!s)
|
|
s = nullstr;
|
|
pattern++;
|
|
if (upper || lastcomp) {
|
|
char *t;
|
|
|
|
if (s != scrbuf) {
|
|
safecpy(scrbuf,s,(sizeof scrbuf));
|
|
s = scrbuf;
|
|
}
|
|
if (upper || !(t=strrchr(s,'/')))
|
|
t = s;
|
|
while (*t && !isalpha((unsigned char)*t)) {
|
|
t++;
|
|
*t = toupper((unsigned char)*t);
|
|
}
|
|
}
|
|
i = metabit; /* maybe get into register */
|
|
if (s == dest) {
|
|
while (*dest) {
|
|
if (--destsize <= 0)
|
|
abort_interp();
|
|
*dest++ |= i;
|
|
}
|
|
}
|
|
else {
|
|
while (*s) {
|
|
if (--destsize <= 0)
|
|
abort_interp();
|
|
*dest++ = *s++ | i;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (--destsize <= 0)
|
|
abort_interp();
|
|
if (*pattern == '^' && pattern[1]) {
|
|
++pattern; /* skip uparrow */
|
|
i = *pattern; /* get char into a register */
|
|
if (i == '?')
|
|
*dest++ = '\177' | metabit;
|
|
else if (i == '(') {
|
|
metabit = 0200;
|
|
destsize++;
|
|
}
|
|
else if (i == ')') {
|
|
metabit = 0;
|
|
destsize++;
|
|
}
|
|
else
|
|
*dest++ = (i & 037) | metabit;
|
|
pattern++;
|
|
}
|
|
else if (*pattern == '\\' && pattern[1]) {
|
|
++pattern; /* skip backslash */
|
|
i = *pattern; /* get char into a register */
|
|
|
|
/* this used to be a switch but the if may save space */
|
|
|
|
if (i >= '0' && i <= '7') {
|
|
i = 1;
|
|
while (i < 01000 && *pattern >= '0' && *pattern <= '7') {
|
|
i <<= 3;
|
|
i += *pattern++ - '0';
|
|
}
|
|
*dest++ = (i & 0377) | metabit;
|
|
--pattern;
|
|
}
|
|
else if (i == 'b')
|
|
*dest++ = '\b' | metabit;
|
|
else if (i == 'f')
|
|
*dest++ = '\f' | metabit;
|
|
else if (i == 'n')
|
|
*dest++ = '\n' | metabit;
|
|
else if (i == 'r')
|
|
*dest++ = '\r' | metabit;
|
|
else if (i == 't')
|
|
*dest++ = '\t' | metabit;
|
|
else
|
|
*dest++ = i | metabit;
|
|
pattern++;
|
|
}
|
|
else
|
|
*dest++ = *pattern++ | metabit;
|
|
}
|
|
}
|
|
*dest = '\0';
|
|
getout:
|
|
return __UNCONST(pattern); /* where we left off */
|
|
}
|
|
|
|
void
|
|
interp(char *dest, size_t destsize, const char *pattern)
|
|
{
|
|
(void) dointerp(dest,destsize,pattern,NULL);
|
|
#ifdef DEBUGGING
|
|
if (debug & DEB_FILEXP)
|
|
fputs(dest,stdout);
|
|
#endif
|
|
}
|
|
|
|
/* get the person's real name from /etc/passwd */
|
|
/* (string is overwritten, so it must be copied) */
|
|
|
|
static char *
|
|
getrealname(uid_t uid)
|
|
{
|
|
char *s, *c;
|
|
|
|
#ifdef PASSNAMES
|
|
struct passwd *pwd = getpwuid(uid);
|
|
|
|
s = pwd->pw_gecos;
|
|
#ifdef BERKNAMES
|
|
#ifdef BERKJUNK
|
|
while (*s && !isalnum(*s) && *s != '&') s++;
|
|
#endif
|
|
if ((c = strchr(s, ',')) != NULL)
|
|
*c = '\0';
|
|
if ((c = strchr(s, ';')) != NULL)
|
|
*c = '\0';
|
|
s = cpytill(buf,s,'&');
|
|
if (*s == '&') { /* whoever thought this one up was */
|
|
c = buf + strlen(buf); /* in the middle of the night */
|
|
strcat(c,logname); /* before the morning after */
|
|
strcat(c,s+1);
|
|
if (islower((unsigned char)*c))
|
|
*c = toupper((unsigned char)*c); /* gack and double gack */
|
|
}
|
|
#else
|
|
if ((c = strchr(s, '(')) != NULL)
|
|
*c = '\0';
|
|
if ((c = strchr(s, '-')) != NULL)
|
|
s = c;
|
|
strcpy(buf,tmpbuf);
|
|
#endif
|
|
endpwent();
|
|
return buf; /* return something static */
|
|
#else
|
|
if ((tmpfp=fopen(filexp(FULLNAMEFILE),"r")) != NULL) {
|
|
fgets(buf,sizeof buf,tmpfp);
|
|
fclose(tmpfp);
|
|
}
|
|
else {
|
|
resetty();
|
|
printf("What is your name? ");
|
|
fgets(buf,(sizeof buf),stdin);
|
|
crmode();
|
|
raw();
|
|
noecho();
|
|
nonl();
|
|
if (fork())
|
|
wait(0);
|
|
else {
|
|
setgid(getgid());
|
|
if ((tmpfp = fopen(filexp(FULLNAMEFILE),"w")) == NULL)
|
|
exit(1);
|
|
fprintf(tmpfp, "%s\n", buf);
|
|
fclose(tmpfp);
|
|
exit(0);
|
|
}
|
|
}
|
|
buf[strlen(buf)-1] = '\0';
|
|
return buf;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
abort_interp(void)
|
|
{
|
|
fputs("\r\n% interp buffer overflow!\r\n",stdout);
|
|
sig_catcher(0);
|
|
}
|